PHP 8.1 dev (#1282)

This commit is contained in:
Jenny Tam 2021-07-28 15:45:04 -07:00 committed by GitHub
parent 277872619e
commit 5e607a802c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 816 additions and 278 deletions

View file

@ -34,7 +34,7 @@ namespace {
const char LAST_INSERT_ID_QUERY[] = "SELECT @@IDENTITY;";
const size_t LAST_INSERT_ID_BUFF_LEN = 50; // size of the buffer to hold the string value of the last inserted id, which may be an int, bigint, decimal(p,0) or numeric(p,0)
const char SEQUENCE_CURRENT_VALUE_QUERY[] = "SELECT current_value FROM sys.sequences WHERE name=N'%s'";
const char SEQUENCE_CURRENT_VALUE_QUERY[] = "SELECT current_value FROM sys.sequences WHERE name=N'%s'";
const int LAST_INSERT_ID_QUERY_MAX_LEN = sizeof( SEQUENCE_CURRENT_VALUE_QUERY ) + SQL_MAX_SQLSERVERNAME + 2; // include the quotes
// List of PDO supported connection options.
@ -436,36 +436,66 @@ const connection_option PDO_CONN_OPTS[] = {
};
#if PHP_VERSION_ID < 80100
// close the connection
int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh );
int pdo_sqlsrv_dbh_close(_Inout_ pdo_dbh_t *dbh);
// execute queries
int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const char *sql,
_Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options );
zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len );
int pdo_sqlsrv_dbh_prepare(_Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const char *sql,
_Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options);
zend_long pdo_sqlsrv_dbh_do(_Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len);
// quote a string, meaning put quotes around it and escape any quotes within it
int pdo_sqlsrv_dbh_quote(_Inout_ pdo_dbh_t* dbh, _In_reads_(unquotedlen) const char* unquoted, _In_ size_t unquotedlen, _Outptr_result_buffer_(*quotedlen) char **quoted, _Out_ size_t* quotedlen,
enum pdo_param_type paramtype);
// transaction support functions
int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh );
int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh );
int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh );
int pdo_sqlsrv_dbh_commit(_Inout_ pdo_dbh_t *dbh);
int pdo_sqlsrv_dbh_begin(_Inout_ pdo_dbh_t *dbh);
int pdo_sqlsrv_dbh_rollback(_Inout_ pdo_dbh_t *dbh);
// attribute functions
int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val );
int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value );
// return more information
int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt,
_Out_ zval *info);
int pdo_sqlsrv_dbh_set_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val);
int pdo_sqlsrv_dbh_get_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value);
// return the last id generated by an executed SQL statement
char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len );
char * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len);
// return more information
int pdo_sqlsrv_dbh_return_error(_In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, _Out_ zval *info);
#else
// close the connection
void pdo_sqlsrv_dbh_close(_Inout_ pdo_dbh_t *dbh);
// execute queries
bool pdo_sqlsrv_dbh_prepare(_Inout_ pdo_dbh_t *dbh, _In_ zend_string *sql,
_Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options);
zend_long pdo_sqlsrv_dbh_do(_Inout_ pdo_dbh_t *dbh, _In_ const zend_string *sql);
// quote a string, meaning put quotes around it and escape any quotes within it
zend_string* pdo_sqlsrv_dbh_quote(_Inout_ pdo_dbh_t* dbh, _In_ const zend_string *unquoted, _In_ enum pdo_param_type paramtype);
// transaction support functions
bool pdo_sqlsrv_dbh_commit(_Inout_ pdo_dbh_t *dbh);
bool pdo_sqlsrv_dbh_begin(_Inout_ pdo_dbh_t *dbh);
bool pdo_sqlsrv_dbh_rollback(_Inout_ pdo_dbh_t *dbh);
// attribute functions
bool pdo_sqlsrv_dbh_set_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val);
int pdo_sqlsrv_dbh_get_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value);
// return the last id generated by an executed SQL statement
zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_string *name);
// return more information
void pdo_sqlsrv_dbh_return_error(_In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, _Out_ zval *info);
#endif
// additional methods are supported in this function
pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( _Inout_ pdo_dbh_t *dbh, int kind );
// quote a string, meaning put quotes around it and escape any quotes within it
int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquotedlen) const char* unquoted, _In_ size_t unquotedlen, _Outptr_result_buffer_(*quotedlen) char **quoted, _Out_ size_t* quotedlen,
enum pdo_param_type paramtype );
struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = {
@ -632,15 +662,22 @@ int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_
// Parameters:
// dbh - The PDO managed connection object.
// Return:
// Always returns 1 for success.
// Always returns 1 for success. (for PHP_VERSION_ID < 80100)
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh )
#else
void pdo_sqlsrv_dbh_close(_Inout_ pdo_dbh_t *dbh)
#endif
{
LOG( SEV_NOTICE, "pdo_sqlsrv_dbh_close: entering" );
// if the connection didn't complete properly, driver_data isn't initialized.
if( dbh->driver_data == NULL ) {
#if PHP_VERSION_ID < 80100
return 1;
#else
return;
#endif
}
PDO_RESET_DBH_ERROR;
@ -649,8 +686,10 @@ int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh )
core_sqlsrv_close( reinterpret_cast<sqlsrv_conn*>( dbh->driver_data ) );
dbh->driver_data = NULL;
#if PHP_VERSION_ID < 80100
// always return success that the connection is closed
return 1;
#endif
}
// pdo_sqlsrv_dbh_prepare
@ -664,8 +703,12 @@ int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh )
// driver_options - User provided list of statement options.
// Return:
// 0 for failure, 1 for success.
int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const char *sql,
_Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options )
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_prepare(_Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const char *sql,
_Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options)
#else
bool pdo_sqlsrv_dbh_prepare(_Inout_ pdo_dbh_t *dbh, _In_ zend_string *sql_zstr, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -707,27 +750,44 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch
driver_stmt->buffered_query_limit = driver_dbh->client_buffer_max_size;
}
#if PHP_VERSION_ID >= 80100
zend_string* sql_rewrite_zstr = NULL;
const char* sql = ZSTR_VAL(sql_zstr);
size_t sql_len = ZSTR_LEN(sql_zstr);
#endif
// rewrite named parameters in the query to positional parameters if we aren't letting PDO do the
// parameter substitution for us
if( stmt->supports_placeholders != PDO_PLACEHOLDER_NONE ) {
// rewrite the query to map named parameters to positional parameters. We do this rather than use the ODBC named
// parameters for consistency with the PDO MySQL and PDO ODBC drivers.
#if PHP_VERSION_ID < 80100
int zr = pdo_parse_params( stmt, const_cast<char*>( sql ), sql_len, &sql_rewrite, &sql_rewrite_len );
CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE) {
CHECK_ZEND_ERROR(zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE) {
throw core::CoreException();
}
// if parameter substitution happened, use that query instead of the original
if( sql_rewrite != 0) {
if (sql_rewrite != 0) {
sql = sql_rewrite;
sql_len = sql_rewrite_len;
}
#else
int zr = pdo_parse_params(stmt, sql_zstr, &sql_rewrite_zstr);
CHECK_ZEND_ERROR(zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE) {
throw core::CoreException();
}
// if parameter substitution happened, use that query instead of the original
if (sql_rewrite_zstr != NULL) {
sql = ZSTR_VAL(sql_rewrite_zstr);
sql_len = ZSTR_LEN(sql_rewrite_zstr);
}
#endif
}
if( !driver_stmt->direct_query && stmt->supports_placeholders != PDO_PLACEHOLDER_NONE ) {
core_sqlsrv_prepare( driver_stmt, sql, sql_len );
core_sqlsrv_prepare(driver_stmt, sql, sql_len);
}
else if( driver_stmt->direct_query ) {
@ -739,14 +799,26 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch
driver_stmt->direct_query_subst_string = estrdup( sql );
driver_stmt->direct_query_subst_string_len = sql_len;
}
#if PHP_VERSION_ID >= 80100
if (sql_rewrite_zstr != NULL) {
zend_string_release(sql_rewrite_zstr);
}
#endif
// else if stmt->support_placeholders == PDO_PLACEHOLDER_NONE means that stmt->active_query_string will be
// set to the substituted query
if ( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) {
// parse placeholders in the sql query into the placeholders ht
// parse placeholders in the sql query into the placeholders ht
ALLOC_HASHTABLE( placeholders );
core::sqlsrv_zend_hash_init( *driver_dbh, placeholders, 5, ZVAL_PTR_DTOR /* dtor */, 0 /* persistent */ );
sql_parser = new ( sqlsrv_malloc( sizeof( sql_string_parser ))) sql_string_parser( *driver_dbh, stmt->query_string,
static_cast<int>(stmt->query_stringlen), placeholders );
core::sqlsrv_zend_hash_init(*driver_dbh, placeholders, 5, ZVAL_PTR_DTOR /* dtor */, 0 /* persistent */);
#if PHP_VERSION_ID < 80100
sql_parser = new (sqlsrv_malloc(sizeof(sql_string_parser))) sql_string_parser(*driver_dbh, stmt->query_string,
static_cast<int>(stmt->query_stringlen), placeholders);
#else
sql_parser = new (sqlsrv_malloc(sizeof(sql_string_parser))) sql_string_parser(*driver_dbh, ZSTR_VAL(stmt->query_string),
ZSTR_LEN(stmt->query_string), placeholders);
#endif
sql_parser->parse_sql_string();
driver_stmt->placeholders = placeholders;
placeholders.transferred();
@ -772,7 +844,11 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch
reinterpret_cast<const char*>( driver_dbh->last_error()->sqlstate ));
}
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
// catch any errant exception and die
@ -781,7 +857,11 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch
DIE( "pdo_sqlsrv_dbh_prepare: Unknown exception caught." );
}
#if PHP_VERSION_ID < 80100
return 1;
#else
return true;
#endif
}
@ -795,7 +875,11 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch
// sql_len - length of sql query
// Return
// # of rows affected, -1 for an error.
#if PHP_VERSION_ID < 80100
zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len )
#else
zend_long pdo_sqlsrv_dbh_do(_Inout_ pdo_dbh_t *dbh, _In_ const zend_string *sql)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -823,8 +907,11 @@ zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) c
NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt );
driver_stmt->set_func( __FUNCTION__ );
SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt, sql, static_cast<int>( sql_len ) );
#if PHP_VERSION_ID < 80100
SQLRETURN execReturn = core_sqlsrv_execute(driver_stmt, sql, static_cast<int>(sql_len));
#else
SQLRETURN execReturn = core_sqlsrv_execute(driver_stmt, ZSTR_VAL(sql), ZSTR_LEN(sql));
#endif
// since the user can give us a compound statement, we return the row count for the last set, and since the row count
// isn't guaranteed to be valid until all the results have been fetched, we fetch them all first.
@ -883,8 +970,13 @@ zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) c
// Parameters:
// dbh - The PDO managed connection object.
// Return:
// 0 for failure and 1 for success.
int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh )
// 0 for failure and 1 for success. (if PHP_VERSION_ID < 80100)
// Return true if currently inside a transaction, false otherwise
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_begin(_Inout_ pdo_dbh_t *dbh)
#else
bool pdo_sqlsrv_dbh_begin(_Inout_ pdo_dbh_t *dbh)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -902,18 +994,29 @@ int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh )
core_sqlsrv_begin_transaction( driver_conn );
#if PHP_VERSION_ID < 80100
return 1;
#else
return true;
#endif
}
catch( core::CoreException& ) {
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
catch( ... ) {
DIE ("pdo_sqlsrv_dbh_begin: Uncaught exception occurred.");
}
// Should not have reached here but adding this due to compilation warnings
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
@ -927,8 +1030,13 @@ int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh )
// Parameters:
// dbh - The PDO managed connection object.
// Return:
// 0 for failure and 1 for success.
int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh )
// 0 for failure and 1 for success. (if PHP_VERSION_ID < 80100)
// Return true for success and false otherwise
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_commit(_Inout_ pdo_dbh_t *dbh)
#else
bool pdo_sqlsrv_dbh_commit(_Inout_ pdo_dbh_t *dbh)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -946,18 +1054,30 @@ int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh )
core_sqlsrv_commit( driver_conn );
#if PHP_VERSION_ID < 80100
return 1;
#else
return true;
#endif
}
catch( core::CoreException& ) {
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
catch( ... ) {
DIE ("pdo_sqlsrv_dbh_commit: Uncaught exception occurred.");
}
// Should not have reached here but adding this due to compilation warnings
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
// pdo_sqlsrv_dbh_rollback
@ -969,8 +1089,13 @@ int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh )
// Parameters:
// dbh - The PDO managed connection object.
// Return:
// 0 for failure and 1 for success.
int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh )
// 0 for failure and 1 for success. (if PHP_VERSION_ID < 80100)
// Return true for success and false otherwise
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_rollback(_Inout_ pdo_dbh_t *dbh)
#else
bool pdo_sqlsrv_dbh_rollback(_Inout_ pdo_dbh_t *dbh)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -987,18 +1112,30 @@ int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh )
core_sqlsrv_rollback( driver_conn );
#if PHP_VERSION_ID < 80100
return 1;
#else
return true;
#endif
}
catch( core::CoreException& ) {
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
catch( ... ) {
DIE ("pdo_sqlsrv_dbh_rollback: Uncaught exception occurred.");
}
// Should not have reached here but adding this due to compilation warnings
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
// pdo_sqlsrv_dbh_set_attr
@ -1010,8 +1147,13 @@ int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh )
// attr - The attribute to be set.
// val - The value of the attribute to be set.
// Return:
// 0 for failure, 1 for success.
int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val )
// 0 for failure, 1 for success. (if PHP_VERSION_ID < 80100)
// Return true on success and false in case of failure
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_set_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val)
#else
bool pdo_sqlsrv_dbh_set_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -1158,11 +1300,18 @@ int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
}
}
catch( pdo::PDOException& ) {
#if PHP_VERSION_ID < 80100
return 0;
#else
return false;
#endif
}
#if PHP_VERSION_ID < 80100
return 1;
#else
return true;
#endif
}
@ -1173,8 +1322,12 @@ int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
// attr - The attribute to get.
// return_value - zval in which to return the attribute value.
// Return:
// 0 for failure, 1 for success.
int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value )
// 0 for failure, 1 for success. (if PHP_VERSION_ID < 80100)
// There are 3 return states:
// -1 for errors while retrieving a valid attribute
// 0 for attempting to retrieve an attribute which is not supported by the driver
// any other value for success, *return_value must be set to the attribute value
int pdo_sqlsrv_dbh_get_attr(_Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value)
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -1196,8 +1349,12 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
case PDO_ATTR_AUTOCOMMIT:
case PDO_ATTR_TIMEOUT:
{
#if PHP_VERSION_ID < 80100
// PDO does not throw "not supported" error message for these attributes.
THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_UNSUPPORTED_DBH_ATTR );
THROW_PDO_ERROR(driver_dbh, PDO_SQLSRV_ERROR_UNSUPPORTED_DBH_ATTR);
#else
return 0;
#endif
}
// Statement level only
@ -1303,10 +1460,18 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
}
}
#if PHP_VERSION_ID < 80100
return 1;
#else
return 1;
#endif
}
catch( core::CoreException& ) {
#if PHP_VERSION_ID < 80100
return 0;
#else
return -1;
#endif
}
}
@ -1318,8 +1483,11 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
// info - zval in which to return the error info.
// Return:
// 0 for failure, 1 for success.
int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt,
_Out_ zval *info)
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_return_error(_In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, _Out_ zval *info)
#else
void pdo_sqlsrv_dbh_return_error(_In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, _Out_ zval *info)
#endif
{
SQLSRV_ASSERT( dbh != NULL || stmt != NULL, "Either dbh or stmt must not be NULL to dereference the error." );
@ -1333,7 +1501,9 @@ int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt,
pdo_sqlsrv_retrieve_context_error( ctx_error, info );
#if PHP_VERSION_ID < 80100
return 1;
#endif
}
// pdo_sqlsrv_dbh_last_id
@ -1344,8 +1514,13 @@ int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt,
// name - Table name.
// len - Length of the name.
// Return:
// Returns the last insert id as a string.
char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len )
// Returns the last insert id as a string. (if PHP_VERSION_ID < 80100)
// Returning NULL indicates an error condition. The input "name" MIGHT be NULL
#if PHP_VERSION_ID < 80100
char * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len)
#else
zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_string *name)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -1372,7 +1547,12 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, LAST_INSERT_ID_QUERY, sizeof(LAST_INSERT_ID_QUERY), &wsql_len);
} else {
char buffer[LAST_INSERT_ID_QUERY_MAX_LEN] = { '\0' };
#if PHP_VERSION_ID < 80100
snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, name);
#else
const char *name_str = ZSTR_VAL(name);
snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, ZSTR_VAL(name));
#endif
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, buffer, sizeof(buffer), &wsql_len);
}
CHECK_CUSTOM_ERROR(wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, get_last_error_message()) {
@ -1390,7 +1570,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
// execute the last insert id query
core::SQLExecDirectW( driver_stmt, wsql_string );
core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 );
SQLRETURN r = core::SQLGetData(driver_stmt, 1, SQL_C_CHAR, idSTR, LAST_INSERT_ID_BUFF_LEN, &cbID, false);
CHECK_CUSTOM_ERROR((!SQL_SUCCEEDED(r) || cbID == SQL_NULL_DATA || cbID == SQL_NO_TOTAL), driver_stmt,
PDO_SQLSRV_ERROR_LAST_INSERT_ID) {
@ -1408,20 +1588,31 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
if( driver_stmt ) {
driver_stmt->~sqlsrv_stmt();
}
#if PHP_VERSION_ID < 80100
*len = 0;
str = reinterpret_cast<char*>(sqlsrv_malloc(0, sizeof(char), 1)); // return an empty string with a null terminator
str[0] = '\0';
return str;
#else
return NULL;
#endif
}
// restore error handling to its previous mode
dbh->error_mode = prev_err_mode;
// copy the last ID string and return it
*len = static_cast<size_t>(cbID);
// copy the last ID string and return it
str = reinterpret_cast<char*>(sqlsrv_malloc(cbID, sizeof(char), 1)); // include space for null terminator
strcpy_s(str, cbID + 1, idSTR);
#if PHP_VERSION_ID < 80100
*len = static_cast<size_t>(cbID);
return str;
#else
zend_string *zstr = zend_string_init(str, cbID, 0);
sqlsrv_free(str);
return zstr;
#endif
}
// pdo_sqlsrv_dbh_quote
@ -1435,8 +1626,12 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
// quoted_len - Length of the output string.
// Return:
// 0 for failure, 1 for success.
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const char* unquoted, _In_ size_t unquoted_len, _Outptr_result_buffer_(*quoted_len) char **quoted, _Out_ size_t* quoted_len,
enum pdo_param_type paramtype )
#else
zend_string* pdo_sqlsrv_dbh_quote(_Inout_ pdo_dbh_t* dbh, _In_ const zend_string *unquoted, _In_ enum pdo_param_type paramtype)
#endif
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
@ -1513,28 +1708,60 @@ int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const
}
#endif
if ( encoding == SQLSRV_ENCODING_BINARY ) {
*quoted_len = (unquoted_len * 2) + 2; // each character will be converted to 2 hex digits and prepend '0x' to the result
*quoted = reinterpret_cast<char*>(sqlsrv_malloc(*quoted_len, sizeof(char), 1)); // include space for null terminator
memset(*quoted, '\0', *quoted_len + 1);
unsigned int pos = 0;
(*quoted)[pos++] = '0';
(*quoted)[pos++] = 'x';
for (size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index) {
// On success, snprintf returns the total number of characters written
// On failure, a negative number is returned
// The generated string has a length of at most len - 1, so
if (encoding == SQLSRV_ENCODING_BINARY) {
#if PHP_VERSION_ID < 80100
*quoted_len = (unquoted_len * 2) + 2; // each character will be converted to 2 hex digits and prepend '0x' to the result
*quoted = reinterpret_cast<char*>(sqlsrv_malloc(*quoted_len, sizeof(char), 1)); // include space for null terminator
memset(*quoted, '\0', *quoted_len + 1);
unsigned int pos = 0;
(*quoted)[pos++] = '0';
(*quoted)[pos++] = 'x';
for (size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index) {
// On success, snprintf returns the total number of characters written
// On failure, a negative number is returned
// The generated string has a length of at most len - 1, so
// len is 3 (2 hex digits + 1)
int n = snprintf((char*)(*quoted + pos), 3, "%02X", unquoted[index]);
if (n < 0) {
// Something went wrong, simply return 0 (failure)
return 0;
}
pos += 2;
}
return 1;
if (n < 0) {
// Something went wrong, simply return 0 (failure)
return 0;
}
pos += 2;
}
return 1;
#else
size_t unquoted_len = ZSTR_LEN(unquoted);
const char *unquoted_str = ZSTR_VAL(unquoted);
sqlsrv_malloc_auto_ptr<char> quoted;
size_t quoted_len = (unquoted_len * 2) + 2; // each character will be converted to 2 hex digits and prepend '0x' to the result
quoted = reinterpret_cast<char*>(sqlsrv_malloc(quoted_len, sizeof(char), 1)); // include space for null terminator
memset(quoted, '\0', quoted_len + 1);
unsigned int pos = 0;
quoted[pos++] = '0';
quoted[pos++] = 'x';
char *p = quoted;
for (size_t index = 0; index < unquoted_len && unquoted_str[index] != '\0'; ++index) {
// On success, snprintf returns the total number of characters written
// On failure, a negative number is returned
// The generated string has a length of at most len - 1, so
// len is 3 (2 hex digits + 1)
int n = snprintf((char*)(p + pos), 3, "%02X", unquoted_str[index]);
if (n < 0) {
// Something went wrong, simply return NULL (failure)
return NULL;
}
pos += 2;
}
zend_string* zstr = zend_string_init(quoted, quoted_len, 0);
return zstr;
#endif
}
else {
// The minimum number of single quotes needed is 2 -- the initial start and end quotes
@ -1542,18 +1769,35 @@ int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const
int quotes_needed = (use_national_char_set) ? 3 : 2;
char c = '\'';
#if PHP_VERSION_ID < 80100
std::string tmp_str(unquoted, unquoted_len); // Copy all unquoted_len characters from unquoted
#else
size_t unquoted_len = ZSTR_LEN(unquoted);
const char *unquoted_str = ZSTR_VAL(unquoted);
std::string tmp_str(unquoted_str, unquoted_len); // Copy all unquoted_len characters from unquoted
#endif
std::size_t found = tmp_str.find(c); // Find the first single quote
while (found != std::string::npos) {
tmp_str.insert(found + 1, 1, c); // Insert an additional single quote
found = tmp_str.find(c, found + 2); // Find the next single quote
}
size_t len = tmp_str.length();
#if PHP_VERSION_ID < 80100
*quoted_len = quotes_needed + len; // The new length should be number of quotes plus the length of tmp_str
*quoted = reinterpret_cast<char*>(sqlsrv_malloc(*quoted_len, sizeof(char), 1)); // include space for null terminator
memset(*quoted, '\0', *quoted_len + 1);
memset(*quoted, '\0', *quoted_len + 1);
char *p = *quoted;
#else
sqlsrv_malloc_auto_ptr<char> quoted;
size_t quoted_len = quotes_needed + len; // length returned to the caller should not account for null terminator
quoted = reinterpret_cast<char*>(sqlsrv_malloc(quoted_len, sizeof(char), 1)); // include space for null terminator
memset(quoted, '\0', quoted_len + 1);
char *p = quoted;
#endif
size_t pos = 0;
if (use_national_char_set) { // Insert the letter N if the encoding is UTF8
*(p + (pos++)) = 'N';
@ -1562,7 +1806,13 @@ int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const
tmp_str.copy(p + pos, len, 0); // Copy tmp_str to *quoted
pos += len;
*(p + pos) = c; // Add the end quote
#if PHP_VERSION_ID < 80100
return 1;
#else
zend_string* zstr = zend_string_init(quoted, quoted_len, 0);
return zstr;
#endif
}
}

View file

@ -278,8 +278,13 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta
int pdo_sqlsrv_stmt_param_hook( _Inout_ pdo_stmt_t *stmt,
_Inout_ struct pdo_bound_param_data *param, _In_ enum pdo_param_event event_type );
int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno );
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno,
_Out_writes_bytes_opt_(*len) char **ptr, _Inout_ size_t *len, _Out_opt_ int *caller_frees );
#else
int pdo_sqlsrv_stmt_get_col_data(_Inout_ pdo_stmt_t *stmt, _In_ int colno, _Inout_ zval *result, _Inout_ enum pdo_param_type *type);
#endif
int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *val );
int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *return_value );
int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno, _Inout_ zval *return_value );
@ -453,9 +458,10 @@ int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno)
// Set the precision
column_data->precision = core_meta_data->field_scale;
#if PHP_VERSION_ID < 80100
// Set the param_type
column_data->param_type = PDO_PARAM_ZVAL;
#endif
// store the field data for use by pdo_sqlsrv_stmt_get_col_data
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );
SQLSRV_ASSERT( driver_stmt != NULL, "Invalid driver statement in pdo_sqlsrv_stmt_describe_col" );
@ -551,8 +557,13 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt )
zend_hash_internal_pointer_reset(driver_stmt->placeholders);
#if PHP_VERSION_ID < 80100
query = stmt->active_query_string;
query_len = static_cast<unsigned int>(stmt->active_query_stringlen);
#else
query = ZSTR_VAL(stmt->active_query_string);
query_len = ZSTR_LEN(stmt->active_query_string);
#endif
}
// The query timeout setting is inherited from the corresponding connection attribute, but
@ -652,14 +663,23 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta
pdo_bound_param_data* bind_data = NULL;
if( !driver_stmt->bound_column_param_types ) {
driver_stmt->bound_column_param_types =
#if PHP_VERSION_ID < 80100
driver_stmt->bound_column_param_types =
reinterpret_cast<pdo_param_type*>( sqlsrv_malloc( stmt->column_count, sizeof( pdo_param_type ), 0 ));
std::fill( driver_stmt->bound_column_param_types, driver_stmt->bound_column_param_types + stmt->column_count,
PDO_PARAM_ZVAL );
#else
// TODO: possibly no longer need bound_column_param_types?? default to PDO_PARAM_STR???
driver_stmt->bound_column_param_types =
reinterpret_cast<pdo_param_type*>(sqlsrv_malloc(stmt->column_count, sizeof(pdo_param_type), 0));
std::fill(driver_stmt->bound_column_param_types, driver_stmt->bound_column_param_types + stmt->column_count,
PDO_PARAM_STR);
#endif
}
for( long i = 0; i < stmt->column_count; ++i ) {
#if PHP_VERSION_ID < 80100
if (NULL== (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_index_find_ptr(stmt->bound_columns, i))) &&
(NULL == (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_find_ptr(stmt->bound_columns, stmt->columns[i].name))))) {
@ -672,6 +692,15 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta
driver_stmt->bound_column_param_types[i] = bind_data->param_type;
bind_data->param_type = PDO_PARAM_ZVAL;
}
#else
if (NULL == (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_index_find_ptr(stmt->bound_columns, i))) &&
(NULL == (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_find_ptr(stmt->bound_columns, stmt->columns[i].name))))) {
continue;
}
// TODO: possibly no longer need bound_column_param_types??
driver_stmt->bound_column_param_types[i] = bind_data->param_type;
#endif
}
}
@ -730,8 +759,13 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta
// freeing the memory.
// Return:
// 0 for failure, 1 for success.
#if PHP_VERSION_ID < 80100
int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno,
_Out_writes_bytes_opt_(*len) char **ptr, _Inout_ size_t *len, _Out_opt_ int *caller_frees)
#else
int pdo_sqlsrv_stmt_get_col_data(_Inout_ pdo_stmt_t *stmt, _In_ int colno, _Inout_ zval *result_z, _Inout_ enum pdo_param_type *type)
#endif
{
PDO_RESET_STMT_ERROR;
PDO_VALIDATE_STMT;
@ -739,39 +773,44 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno,
try {
SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_get_col_data: pdo_stmt object was null" );
SQLSRV_ASSERT(stmt != NULL, "pdo_sqlsrv_stmt_get_col_data: pdo_stmt object was null");
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );
SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_get_col_data: driver_data object was null" );
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>(stmt->driver_data);
CHECK_CUSTOM_ERROR((colno < 0), driver_stmt, PDO_SQLSRV_ERROR_INVALID_COLUMN_INDEX ) {
SQLSRV_ASSERT(driver_stmt != NULL, "pdo_sqlsrv_stmt_get_col_data: driver_data object was null");
CHECK_CUSTOM_ERROR((colno < 0), driver_stmt, PDO_SQLSRV_ERROR_INVALID_COLUMN_INDEX) {
return 0;
}
#if PHP_VERSION_ID < 80100
// Let PDO free the memory after use.
*caller_frees = 1;
* caller_frees = 1;
#endif
// translate the pdo type to a type the core layer understands
sqlsrv_phptype sqlsrv_php_type;
SQLSRV_ASSERT( colno >= 0 && colno < static_cast<int>( driver_stmt->current_meta_data.size()),
"Invalid column number in pdo_sqlsrv_stmt_get_col_data" );
SQLSRV_ASSERT(colno >= 0 && colno < static_cast<int>(driver_stmt->current_meta_data.size()),
"Invalid column number in pdo_sqlsrv_stmt_get_col_data");
// set the encoding if the user specified one via bindColumn, otherwise use the statement's encoding
// save the php type for next use
sqlsrv_php_type = driver_stmt->sql_type_to_php_type(
static_cast<SQLINTEGER>(driver_stmt->current_meta_data[colno]->field_type),
static_cast<SQLUINTEGER>(driver_stmt->current_meta_data[colno]->field_size),
true);
static_cast<SQLINTEGER>(driver_stmt->current_meta_data[colno]->field_type),
static_cast<SQLUINTEGER>(driver_stmt->current_meta_data[colno]->field_size),
true);
driver_stmt->current_meta_data[colno]->sqlsrv_php_type = sqlsrv_php_type;
// if a column is bound to a type different than the column type, figure out a way to convert it to the
// type they want
if( stmt->bound_columns && driver_stmt->bound_column_param_types[colno] != PDO_PARAM_ZVAL ) {
sqlsrv_php_type.typeinfo.type = pdo_type_to_sqlsrv_php_type( driver_stmt,
driver_stmt->bound_column_param_types[colno]
);
#if PHP_VERSION_ID < 80100
if (stmt->bound_columns && driver_stmt->bound_column_param_types[colno] != PDO_PARAM_ZVAL) {
#else
if (stmt->bound_columns) {
#endif
sqlsrv_php_type.typeinfo.type = pdo_type_to_sqlsrv_php_type(driver_stmt,
driver_stmt->bound_column_param_types[colno]
);
pdo_bound_param_data* bind_data = NULL;
bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_index_find_ptr(stmt->bound_columns, colno));
@ -780,40 +819,41 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno,
bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_find_ptr(stmt->bound_columns, stmt->columns[colno].name));
}
if( bind_data != NULL && !Z_ISUNDEF(bind_data->driver_params) ) {
if (bind_data != NULL && !Z_ISUNDEF(bind_data->driver_params)) {
CHECK_CUSTOM_ERROR( Z_TYPE( bind_data->driver_params ) != IS_LONG, driver_stmt,
PDO_SQLSRV_ERROR_INVALID_COLUMN_DRIVER_DATA, colno + 1 ) {
CHECK_CUSTOM_ERROR(Z_TYPE(bind_data->driver_params) != IS_LONG, driver_stmt,
PDO_SQLSRV_ERROR_INVALID_COLUMN_DRIVER_DATA, colno + 1) {
throw pdo::PDOException();
}
CHECK_CUSTOM_ERROR( driver_stmt->bound_column_param_types[colno] != PDO_PARAM_STR
&& driver_stmt->bound_column_param_types[colno] != PDO_PARAM_LOB, driver_stmt,
PDO_SQLSRV_ERROR_COLUMN_TYPE_DOES_NOT_SUPPORT_ENCODING, colno + 1 ) {
CHECK_CUSTOM_ERROR(driver_stmt->bound_column_param_types[colno] != PDO_PARAM_STR
&& driver_stmt->bound_column_param_types[colno] != PDO_PARAM_LOB, driver_stmt,
PDO_SQLSRV_ERROR_COLUMN_TYPE_DOES_NOT_SUPPORT_ENCODING, colno + 1) {
throw pdo::PDOException();
throw pdo::PDOException();
}
sqlsrv_php_type.typeinfo.encoding = Z_LVAL( bind_data->driver_params );
sqlsrv_php_type.typeinfo.encoding = Z_LVAL(bind_data->driver_params);
switch( sqlsrv_php_type.typeinfo.encoding ) {
case SQLSRV_ENCODING_SYSTEM:
case SQLSRV_ENCODING_BINARY:
case SQLSRV_ENCODING_UTF8:
break;
default:
THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_DRIVER_COLUMN_ENCODING, colno );
break;
switch (sqlsrv_php_type.typeinfo.encoding) {
case SQLSRV_ENCODING_SYSTEM:
case SQLSRV_ENCODING_BINARY:
case SQLSRV_ENCODING_UTF8:
break;
default:
THROW_PDO_ERROR(driver_stmt, PDO_SQLSRV_ERROR_INVALID_DRIVER_COLUMN_ENCODING, colno);
break;
}
}
// save the php type for the bound column
driver_stmt->current_meta_data[colno]->sqlsrv_php_type = sqlsrv_php_type;
}
SQLSRV_PHPTYPE sqlsrv_phptype_out = SQLSRV_PHPTYPE_INVALID;
core_sqlsrv_get_field( driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast<void**>(ptr)),
reinterpret_cast<SQLLEN*>( len ), true, &sqlsrv_phptype_out );
#if PHP_VERSION_ID < 80100
core_sqlsrv_get_field(driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast<void**>(ptr)),
reinterpret_cast<SQLLEN*>(len), true, &sqlsrv_phptype_out);
if (ptr) {
zval* zval_ptr = reinterpret_cast<zval*>(sqlsrv_malloc(sizeof(zval)));
@ -821,7 +861,14 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno,
*ptr = reinterpret_cast<char*>(zval_ptr);
*len = sizeof(zval);
}
#else
SQLLEN len = 0;
void *ptr = NULL;
core_sqlsrv_get_field(driver_stmt, colno, sqlsrv_php_type, false, ptr, &len, true, &sqlsrv_phptype_out);
if (ptr) {
*result_z = convert_to_zval(driver_stmt, sqlsrv_phptype_out, &ptr, len);
}
#endif
return 1;
}
catch ( core::CoreException& ) {
@ -1114,9 +1161,15 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno
&out_buff_len, &field_type_num );
add_assoc_string( return_value, "table", table_name );
#if PHP_VERSION_ID < 80100
if( stmt->columns && stmt->columns[colno].param_type == PDO_PARAM_ZVAL ) {
add_assoc_long( return_value, "pdo_type", pdo_type );
}
#else
if (stmt->columns) {
add_assoc_long(return_value, "pdo_type", pdo_type);
}
#endif
}
catch( core::CoreException& ) {
zval_ptr_dtor(return_value);

View file

@ -23,20 +23,20 @@ $stmt->debugDumpParams();
$stmt=null;
$conn=null;
?>
--EXPECT--
SQL: [52] select * from Person.ContactType where name = :param
--EXPECTREGEX--
SQL: \[52\] select \* from Person.ContactType where name = \:param
Params: 1
Key: Name: [6] :param
Key: Name: \[6\] :param
paramno=0
name=[6] ":param"
name=\[6\] ":param"
is_param=1
param_type=2
param_type=(2|3)
SQL: [47] select * from Person.ContactType where name = ?
SQL: \[47\] select \* from Person.ContactType where name = \?
Params: 1
Key: Position #0:
paramno=0
name=[0] ""
name=\[0\] ""
is_param=1
param_type=2
param_type=(2|3)

View file

@ -19,24 +19,24 @@ print $metadata['name'];
$stmt = null;
$conn = null;
?>
--EXPECT--
array(8) {
["flags"]=>
int(0)
["sqlsrv:decl_type"]=>
string(8) "datetime"
["native_type"]=>
string(6) "string"
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
["name"]=>
string(12) "ModifiedDate"
["len"]=>
int(23)
["precision"]=>
int(3)
--EXPECTREGEX--
array\(8\) {
\["flags"\]=>
int\(0\)
\["sqlsrv:decl_type"\]=>
string\(8\) "datetime"
\["native_type"\]=>
string\(6\) "string"
\["table"\]=>
string\(0\) ""
\["pdo_type"\]=>
int\((2|3)\)
\["name"\]=>
string\(12\) "ModifiedDate"
\["len"\]=>
int\(23\)
\["precision"\]=>
int\(3\)
}
datetime
string

View file

@ -306,7 +306,7 @@ class BindParamOp
}
if ($length >= 0 || is_null($length)) {
$this->length = $length;
$this->length = is_null($length) ? 0 : $length;
} else {
printf("BindParamOp construct: The length provided must be greater or equal to 0.\n");
exit;
@ -531,14 +531,11 @@ function fetchAll($conn, $tbname)
* @param string $fetchStyle : fetch_style argument passed to PDOStatement::fetchAll
* @return array rows in a result set
*/
function selectAll($conn, $tbname, $fetchStyle = null)
function selectAll($conn, $tbname, $fetchStyle = PDO::FETCH_BOTH)
{
try {
$sql = "SELECT * FROM $tbname";
$stmt = $conn->query($sql);
if ($fetchStyle) {
$fetchStyle = constant($fetchStyle);
}
$data = $stmt->fetchAll($fetchStyle);
return $data;
} catch (PDOException $e) {
@ -1806,3 +1803,22 @@ function getTodayDateAsString($conn)
$row = $stmt->fetch(PDO::FETCH_NUM);
return $row[0];
}
function compareResourceToInput($actual, $expected)
{
$size = 8192;
$pos = 0;
$matched = true;
while (!feof($actual)) {
$original = fread($actual, $size);
$str = substr($expected, $pos, $size);
if ($original !== $str) {
$matched = false;
break;
}
$pos += $size;
}
return $matched;
}

View file

@ -65,7 +65,7 @@ function insertNullsTest($bindType)
$stmt2->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_BINARY);
$stmt2->bindValue(":p1", null, $bindType);
} elseif ($bindType == PDO::PARAM_STR) {
$stmt2->bindParam(":p1", $outvar, $bindType, null, PDO::SQLSRV_ENCODING_BINARY);
$stmt2->bindParam(":p1", $outvar, $bindType, 0, PDO::SQLSRV_ENCODING_BINARY);
}
} else {
$stmt2->bindParam(":p1", $outvar);

View file

@ -10,7 +10,7 @@ PHPT_EXEC=true
<?php
include 'MsCommon.inc';
function ReadOnly()
function testReadOnly()
{
include 'MsSetup.inc';
@ -62,7 +62,7 @@ function Repro()
try
{
ReadOnly();
testReadOnly();
}
catch (Exception $e)
{

View file

@ -81,7 +81,7 @@ function Repro()
Repro();
?>
--EXPECT--
--EXPECTF--
array(8) {
["flags"]=>
int(0)
@ -92,7 +92,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(2) "id"
["len"]=>
@ -110,7 +110,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(3) "val"
["len"]=>
@ -128,7 +128,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(4) "val2"
["len"]=>
@ -146,7 +146,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(0) ""
["len"]=>

View file

@ -61,8 +61,14 @@ function fetchLob($offset, $conn, $table, $sqlType, $data1, $data2)
if ($id != $data1) {
logInfo($offset, "ID data corruption: [$id] instead of [$data1]");
}
if ($label != $data2) {
logInfo($offset, "Label data corruption: [$label] instead of [$data2]");
if (PHP_VERSION_ID < 80100) {
if ($label != $data2) {
logInfo($offset, "Label data corruption: [$label] instead of [$data2]");
}
} else {
if (!compareResourceToInput($label, $data2)) {
logInfo($offset, "Label data corruption");
}
}
unset($stmt);
unset($label);

View file

@ -42,7 +42,7 @@ try {
}
// Get data
$row = selectAll($conn, $tableName, "PDO::FETCH_ASSOC");
$row = selectAll($conn, $tableName, PDO::FETCH_ASSOC);
var_dump($row);
// Close connection

View file

@ -28,9 +28,18 @@ try {
$stmt = $conn->prepare("SELECT Value FROM $tableName");
$stmt->bindColumn('Value', $val1, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$stmt->fetch(PDO::FETCH_BOUND);
var_dump($val1 === $value);
$stmt->fetch(PDO::FETCH_BOUND);
if (PHP_VERSION_ID < 80100) {
var_dump($val1 === $value);
} else {
// $val1 is a stream object
if (!feof($val1)) {
$str = fread($val1, 8192);
var_dump($str === $value);
}
}
// Close connection
dropTable($conn, $tableName);
unset($stmt);

View file

@ -148,7 +148,16 @@ try {
$stmt->bindColumn('Value', $val1, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$stmt->fetch(PDO::FETCH_BOUND);
var_dump($val1 === $value);
if (PHP_VERSION_ID < 80100) {
var_dump($val1 === $value);
} else {
// $val1 is a stream object
if (!feof($val1)) {
$str = fread($val1, 8192);
var_dump($str === $value);
}
}
// Close connection
dropTable($conn, $tableName);

View file

@ -57,7 +57,12 @@ try {
// Start testing quote function
$conn->setAttribute(PDO::ATTR_DEFAULT_STR_PARAM, PDO::PARAM_STR_CHAR);
var_dump($conn->quote(null, PDO::PARAM_NULL));
// Deprecated: PDO::quote(): Passing null to parameter #1 ($string) of type string is being deprecated
if (PHP_VERSION_ID < 80100) {
var_dump($conn->quote(null, PDO::PARAM_NULL));
} else {
var_dump($conn->quote('', PDO::PARAM_NULL));
}
var_dump($conn->quote('\'', PDO::PARAM_STR));
var_dump($conn->quote('foo', PDO::PARAM_STR));
var_dump($conn->quote('foo', PDO::PARAM_STR | PDO::PARAM_STR_CHAR));

View file

@ -38,7 +38,7 @@ try {
}
?>
--EXPECT--
--EXPECTF--
array(8) {
["flags"]=>
int(0)
@ -49,7 +49,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(6) "RESULT"
["len"]=>

View file

@ -50,7 +50,23 @@ try {
var_dump($e->errorInfo);
}
//calls various fetch methods
function verifyBinaryResult($result, $input, $len, $message)
{
if (PHP_VERSION_ID < 80100) {
if (strncmp($result, $input, $len) !== 0) {
print_r($message);
}
} else {
if (!feof($result)) {
$str = fread($result, $len);
if (strncmp($str, $input, $len) !== 0) {
print_r($message);
}
}
}
}
//calls various fetch methods
function testFetch($conn, $tableName, $columnName, $input)
{
$len = strlen($input);
@ -60,17 +76,13 @@ function testFetch($conn, $tableName, $columnName, $input)
$stmt->bindColumn(1, $result, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
//binary is fixed size, to evaluate output, compare it using strncmp
if (strncmp($result, $input, $len) !== 0) {
print_r("\nRetrieving using bindColumn failed");
}
verifyBinaryResult($result, $input, $len, "\nRetrieving using bindColumn failed");
$result = "";
$stmt = $conn->query($sql);
$stmt->bindColumn(1, $result, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->fetch(PDO::FETCH_BOUND);
if (strncmp($result, $input, $len) !== 0) {
print_r("\nRetrieving using bindColumn with encoding set failed");
}
verifyBinaryResult($result, $input, $len, "\nRetrieving using bindColumn with encoding set failed");
$result = "";
$stmt = $conn->query($sql);

View file

@ -45,9 +45,23 @@ try {
$stmt->bindColumn(2, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_SYSTEM);
$result = $stmt->fetch(PDO::FETCH_BOUND);
if (!$result || $value !== $input[1]) {
echo "Expected $input[1] but got: ";
var_dump($result);
if (PHP_VERSION_ID < 80100) {
if (!$result || $value !== $input[1]) {
echo "Expected $input[1] but got: ";
var_dump($value);
}
} else {
if (!$result || !is_resource($value)) {
echo "Expected a stream resource but got: ";
var_dump($value);
}
if (!feof($value)) {
$str = fread($value, strlen($input[1]));
if ($str !== $input[1]) {
echo "Expected $input[1] but got: ";
var_dump($str);
}
}
}
$stmt->bindColumn(2, $value, PDO::PARAM_STR);

View file

@ -79,7 +79,7 @@ unset($stmt);
unset($conn);
?>
--EXPECT--
--EXPECTF--
Number of columns after UPDATE: 0
array(8) {
["flags"]=>
@ -91,7 +91,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(2) "id"
["len"]=>
@ -109,7 +109,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(4) "name"
["len"]=>

View file

@ -52,9 +52,15 @@ try {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// check the case when fetching as PDO::PARAM_STR
// with or without AE: should work
} else {
if (PHP_VERSION_ID >= 80100 && $pdoParamType == "PDO::PARAM_LOB") {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$det = fread($det, 8192);
$rand = fread($rand, 8192);
}
if (trim($det) == $inputValues[0] && trim($rand) == $inputValues[1]) {
echo "****Retrieving $typeFull data as $pdoParamType is supported****\n";
} else {

View file

@ -53,6 +53,10 @@ try {
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (PHP_VERSION_ID >= 80100 && is_resource($c1)) {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$c1 = fread($c1, 8192);
}
if (strlen($c1) == $m) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {

View file

@ -47,6 +47,11 @@ try {
// only check if input values are part of fetched values because some input values do not contain any deicmal places, the value retrieved however has 3 decimal places if the type is a datetime
// with or without AE: should work
} else {
if (PHP_VERSION_ID >= 80100 && $pdoParamType == "PDO::PARAM_LOB") {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$det = fread($det, 8192);
$rand = fread($rand, 8192);
}
if (strpos($det, $inputValues[0]) !== false && strpos($rand, $inputValues[1]) !== false) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {

View file

@ -83,6 +83,11 @@ try {
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (PHP_VERSION_ID >= 80100 && $pdoParamType == "PDO::PARAM_LOB") {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$det = fread($det, 8192);
$rand = fread($rand, 8192);
}
if (compareDate($det, $inputValues[0], $dataType) && compareDate($rand, $inputValues[1], $dataType)) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {

View file

@ -114,6 +114,11 @@ try {
$succeeded = compareIntegers($pdoParamType, $det, $rand, $inputValues, $m1, $m2);
}
} else {
if (PHP_VERSION_ID >= 80100 && $pdoParamType == "PDO::PARAM_LOB") {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$det = fread($det, 8192);
$rand = fread($rand, 8192);
}
if (abs($det - $inputValues[0]) < $epsilon &&
abs($rand - $inputValues[1]) < $epsilon) {
$succeeded = true;

View file

@ -57,6 +57,12 @@ try {
echo "Retriving $typeFull data as $pdoParamType should return NULL\n";
}
} else {
if (PHP_VERSION_ID >= 80100 && $pdoParamType == "PDO::PARAM_LOB") {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$det = fread($det, 8192);
$rand = fread($rand, 8192);
}
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {

View file

@ -53,6 +53,10 @@ try {
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (PHP_VERSION_ID >= 80100 && is_resource($c1)) {
// Starting with PHP 8.1 fetching as PDO::PARAM_LOB will return a resource obj
$c1 = fread($c1, 8192);
}
if (strlen($c1) == $m) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {

View file

@ -48,27 +48,41 @@ try {
}
// check the case when fetching as PDO::PARAM_BOOL or PDO::PARAM_INT
// with or without AE: should only not work with bigint
} else if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") {
} elseif ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") {
if ($dataType == "bigint") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
}
} else if ($dataType == "real") {
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
} elseif (PHP_VERSION_ID >= 80100 && $pdoParamType == "PDO::PARAM_BOOL") {
if ($det == boolval($inputValues[0]) && $rand == boolval($inputValues[1])) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
} else {
if ($det == $inputValues[0] && $rand == $inputValues[1]) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
if ($dataType == "real") {
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
if ($det == $inputValues[0] && $rand == $inputValues[1]) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
}
}
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if ($pdoParamType == "PDO::PARAM_LOB") {
if (PHP_VERSION_ID >= 80100) {
$det = fread($det, 8192);
$rand = fread($rand, 8192);
}
}
if ($dataType == "real") {
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";

View file

@ -129,8 +129,14 @@ function fetchBinaryAsBinary($conn, $tableName, $inputs)
$stmt->bindColumn('c1', $binaryValue, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
$row = $stmt->fetch(PDO::FETCH_BOUND);
if ($binaryValue !== $inputs[0]) {
echo "Fetched binary value unexpected: $binaryValue\n";
if (PHP_VERSION_ID < 80100) {
if ($binaryValue !== $inputs[0]) {
echo "Fetched binary value unexpected: $binaryValue\n";
}
} else {
if (!compareResourceToInput($binaryValue, $inputs[0])) {
echo "Fetched binary value unexpected\n";
}
}
} catch (PdoException $e) {
echo "Caught exception in fetchBinaryAsBinary:\n";

View file

@ -50,7 +50,8 @@ function testConnAttrCases()
$conn = new PDO($dsn, $uid, $pwd, $attr);
$conn->getAttribute(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION);
} catch (PDOException $e) {
if (!fnmatch($noSupportErr, $e->getMessage())) {
$expected = (PHP_VERSION_ID < 80100) ? $noSupportErr : $stmtErr;
if (!fnmatch($expected, $e->getMessage())) {
echo "Connection attribute test (3) unexpected\n";
var_dump($e->getMessage());
}

View file

@ -52,7 +52,8 @@ function testConnAttrCases()
$conn = new PDO($dsn, $uid, $pwd, $attr);
$conn->getAttribute(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION);
} catch (PDOException $e) {
if (!fnmatch($noSupportErr, $e->getMessage())) {
$expected = (PHP_VERSION_ID < 80100) ? $noSupportErr : $stmtErr;
if (!fnmatch($expected, $e->getMessage())) {
echo "Connection attribute test (3) unexpected\n";
var_dump($e->getMessage());
}

View file

@ -30,6 +30,9 @@ try {
$stmt->execute();
$stmt->bindColumn('exist', $float_col, PDO::PARAM_LOB);
$value = $stmt->fetch();
if (PHP_VERSION_ID >= 80100) {
$float_col = fread($float_col, 8192);
}
var_dump($float_col);
print "\nno buffered cursor, stringify off, fetch_numeric on\n";
@ -38,6 +41,9 @@ try {
$stmt->execute();
$stmt->bindColumn('exist', $float_col, PDO::PARAM_LOB);
$value = $stmt->fetch();
if (PHP_VERSION_ID >= 80100) {
$float_col = fread($float_col, 8192);
}
var_dump($float_col);
print "\nno buffered cursor, stringify on, fetch_numeric on\n";
@ -63,6 +69,9 @@ try {
$stmt->execute();
$stmt->bindColumn('exist', $float_col, PDO::PARAM_LOB);
$value = $stmt->fetch();
if (PHP_VERSION_ID >= 80100) {
$float_col = fread($float_col, 8192);
}
var_dump($float_col);
print "\nbuffered cursor, stringify off, fetch_numeric on\n";
@ -71,6 +80,9 @@ try {
$stmt->execute();
$stmt->bindColumn('exist', $float_col, PDO::PARAM_LOB);
$value = $stmt->fetch();
if (PHP_VERSION_ID >= 80100) {
$float_col = fread($float_col, 8192);
}
var_dump($float_col);
print "\nbuffered cursor, stringify on, fetch_numeric on\n";

View file

@ -135,7 +135,12 @@ function runTest($conn, $query, $columns, $values, $useBuffer = false)
// Setting it to true only converts numeric values to strings when fetching
// See http://www.php.net/manual/en/pdo.setattribute.php for details
// stringify on, fetch_numeric off, fetch_datetime on
$conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
if (PHP_VERSION_ID < 80100) {
// TODO: starting in PHP 8.1 with ATTR_STRINGIFY_FETCHES set to true
// this fails with this error from PHP:
// Fatal error: Uncaught Error: Object of class DateTime could not be converted to string
$conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
}
$conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, false);
$conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, true);
$stmt = $conn->prepare($query, $options);
@ -253,11 +258,7 @@ try {
$query = "INSERT INTO $tableName VALUES(?, ?, ?, ?, ?, ?)";
$stmt = $conn->prepare($query);
// Bind the first param using the PHP DateTime object
$today = date_create($values[0]);
$stmt->bindParam(1, $today, PDO::PARAM_LOB);
for ($i = 1; $i < count($columns); $i++) {
for ($i = 0; $i < count($columns); $i++) {
$stmt->bindParam($i+1, $values[$i], PDO::PARAM_LOB);
}
$stmt->execute();

View file

@ -23,6 +23,9 @@ $nstrValue = str_repeat("ÃÜðßZZýA©", 200);
function checkData($actual, $expected)
{
if (PHP_VERSION_ID >= 80100 && is_resource($actual)) {
$actual = fread($actual, 8192);
}
trace("Actual:\n$actual\n");
$success = true;

View file

@ -7,12 +7,33 @@ Test getting invalid attributes
require_once("MsCommon_mid-refactor.inc");
// When testing with PHP 8.1-dev, pdo_sqlsrv handles unsupported attribute differently.
// Implement a custom warning handler such that this test works with previous PHP versions as well.
function warningHandler($errno, $errstr)
{
$warning = "Driver does not support this function: driver does not support that attribute";
$str = strstr($errstr, $warning);
if ($str == false) {
echo "Unexpected warning message:";
var_dump($errstr);
}
}
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
set_error_handler("warningHandler", E_WARNING);
@$conn->getAttribute(PDO::ATTR_FETCH_TABLE_NAMES);
print_r(($conn->errorInfo())[2]);
echo "\n";
// Starting with PHP 8.1-dev getting an unsupported attribute pdo_sqlsrv will no longer
// throw an exception. PHP PDO will handle the warning instead.
if (PHP_VERSION_ID < 80100) {
$errmsg = ($conn->errorInfo())[2];
if ($errmsg !== "An unsupported attribute was designated on the PDO object.") {
var_dump($conn->errorInfo());
}
}
restore_error_handler();
@$conn->getAttribute(PDO::ATTR_CURSOR);
print_r(($conn->errorInfo())[2]);
@ -26,6 +47,5 @@ try {
}
?>
--EXPECT--
An unsupported attribute was designated on the PDO object.
The given attribute is only supported on the PDOStatement object.
An invalid attribute was designated on the PDO object.

View file

@ -26,7 +26,7 @@ try {
$insertSql = "INSERT INTO $tableName (c1) VALUES (?)";
$stmt = $conn->prepare($insertSql);
$stmt->bindParam(1, $invalidUTF16, PDO::PARAM_STR, null, PDO::SQLSRV_ENCODING_BINARY);
$stmt->bindParam(1, $invalidUTF16, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
try {

View file

@ -40,7 +40,7 @@ try {
?>
--EXPECT--
string(3) "200"
string(3) "102"
string(0) ""
--EXPECTREGEX--
string\(3\) "200"
string\(3\) "102"
(string\(0\) ""|bool\(false\))

View file

@ -6,7 +6,7 @@ prepare with emulate prepare and binding uft8 characters
<?php
require_once('MsCommon_mid-refactor.inc');
function prepareStmt($conn, $query, $prepareOptions = array(), $dataType = null, $length = null, $driverOptions = null)
function prepareStmt($conn, $query, $prepareOptions = array(), $dataType = PDO::PARAM_STR, $length = 0, $driverOptions = null)
{
$name = "가각";
if (!isColEncrypted()) {

View file

@ -4,12 +4,38 @@ Test warnings on connection and statement levels
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
$counter = 0;
// When testing with PHP 8.1-dev it throws different warning messages. Implement a custom
// warning handler such that when testing with previous PHP versions, the warnings are
// handled and verified differently.
function warningHandler($errno, $errstr)
{
global $counter;
$warnings = array("An unsupported attribute was designated on the PDO object.",
"Driver does not support this function: driver does not support that attribute");
if (PHP_VERSION_ID < 80100) {
$str = strstr($errstr, $warnings[$counter++]);
} else {
$str = strstr($errstr, $warnings[1]);
}
if ($str == false) {
echo "Unexpected warning message ($counter):";
var_dump($errstr);
}
}
try {
require_once("MsCommon_mid-refactor.inc");
set_error_handler("warningHandler", E_WARNING);
$conn = connect("", array(), PDO::ERRMODE_WARNING);
// raise a warning in connection
$conn->getAttribute(PDO::ATTR_TIMEOUT);
restore_error_handler();
$tbname = "table1";
dropTable($conn, $tbname);
@ -22,15 +48,7 @@ try {
unset($conn);
} catch (PDOException $e) {
var_dump($e->errorInfo);
exit;
}
?>
--EXPECTREGEX--
Warning: SQLSTATE: IMSSP
Error Code: -38
Error Message: An unsupported attribute was designated on the PDO object\.
in .+(\/|\\)pdo_warnings\.php on line [0-9]+
Warning: PDO::getAttribute\(\): SQLSTATE\[IM001\]: Driver does not support this function: driver does not support that attribute in .+(\/|\\)pdo_warnings\.php on line [0-9]+
Warning: PDOStatement::execute\(\): SQLSTATE\[42000\]: Syntax error or access violation: 156 \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Incorrect syntax near the keyword 'TABLE'\. in .+(\/|\\)pdo_warnings\.php on line [0-9]+

View file

@ -111,8 +111,10 @@ function bindPARAM_NULL($db, $tbname)
$query = "UPDATE PDO_AllTypes SET [BitCol]=:Name WHERE [VarcharCol]=:value";
$stmt = $db->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
fwrite($noteID, null);
rewind($noteID);
// PHP Deprecated: fwrite(): Passing null to parameter #2 ($data) of type string is deprecated
// Also, it is not necessary for this test
// fwrite($noteID, null);
// rewind($noteID);
$stmt->bindParam(':Name', $noteID, PDO::PARAM_NULL);
$stmt->bindParam(':value', $data);
$stmt->execute();

View file

@ -28,16 +28,16 @@ try {
var_dump($e);
}
?>
--EXPECT--
--EXPECTF--
SQL: [79] SELECT IntCol FROM PDO_AllTypes WHERE BigIntCol = :bigint AND CharCol = :string
Params: 2
Key: Name: [7] :bigint
paramno=0
name=[7] ":bigint"
is_param=1
param_type=1
param_type=%d
Key: Name: [7] :string
paramno=1
name=[7] ":string"
is_param=1
param_type=2
param_type=%d

View file

@ -185,7 +185,7 @@ try {
}
?>
--EXPECT--
--EXPECTF--
SQLSTATE[IMSSP]: The given attribute is only supported on the PDOStatement object.
SQLSTATE[IMSSP]: An invalid attribute was designated on the PDOStatement object.
Start inserting data...
@ -271,7 +271,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(6) "Budget"
["len"]=>

View file

@ -94,7 +94,7 @@ try {
?>
--EXPECT--
--EXPECTF--
array(8) {
["flags"]=>
@ -106,7 +106,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(6) "IntCol"
["len"]=>
@ -124,7 +124,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(7) "CharCol"
["len"]=>
@ -142,7 +142,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(8) "NCharCol"
["len"]=>
@ -160,7 +160,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(11) "DateTimeCol"
["len"]=>
@ -178,7 +178,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(10) "VarcharCol"
["len"]=>
@ -196,7 +196,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(11) "NVarCharCol"
["len"]=>
@ -214,7 +214,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(8) "FloatCol"
["len"]=>
@ -230,7 +230,7 @@ array(7) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(6) "XmlCol"
["len"]=>

View file

@ -133,7 +133,7 @@ try {
exit;
}
?>
--EXPECT--
--EXPECTF--
array(8) {
["flags"]=>
@ -145,7 +145,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(12) "此是後話"
["len"]=>
@ -163,7 +163,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(29) "Κοντάוְאַתָּה第"
["len"]=>
@ -181,7 +181,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(30) "NΚοντάוְאַתָּה第"
["len"]=>
@ -199,7 +199,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(38) "ნომინავიiałopioБун"
["len"]=>
@ -217,7 +217,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(10) "VarcharCol"
["len"]=>
@ -235,7 +235,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(33) "NVarΚοντάוְאַתָּה第"
["len"]=>
@ -253,7 +253,7 @@ array(8) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(8) "FloatCol"
["len"]=>
@ -269,7 +269,7 @@ array(7) {
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
int(%d)
["name"]=>
string(6) "XmlCol"
["len"]=>

View file

@ -74,7 +74,7 @@ class ColumnMeta
$unsupported = array("xml", "timestamp", "image", "ntext", "text", "sql_variant", "hierarchyid", "geography", "geometry", "alias");
if (stripos($this->options, "identity") !== false) {
if (!is_null($this->options) && stripos($this->options, "identity") !== false) {
$this->encryptable = false;
} elseif (in_array(strtolower($this->dataType), $unsupported)) {
$this->encryptable = false;
@ -180,7 +180,7 @@ class BindParamOption
$scal = $prec_scal[1];
$size = null;
}
if (strpos($size, "max") !== false) {
if (!is_null($size) && strpos($size, "max") !== false) {
$size = trim($size, "'");
}
}
@ -794,15 +794,14 @@ function getInsertData($rowIndex, $colIndex)
if (empty($inputArray)) {
fatalError("getInsertData: failed to retrieve data at row $rowIndex.\n");
}
$count = 0;
foreach ($inputArray as $key => $value) {
if (++$count == $colIndex) {
if (is_array($value)) {
return $value[0];
} else {
return $value;
}
break;
$key = getColName($colIndex);
if (!empty($key)) {
$value = $inputArray[$key];
if (is_array($value)) {
return $value[0];
} else {
return $value;
}
}
@ -988,11 +987,7 @@ function isUnicode($k)
function isUpdatable($k)
{
switch ($k) {
case 27: return (false); // timestamp
default: break;
}
return (true);
return ($k != 27); // timestamp
}
function isLiteral($k)

View file

@ -37,7 +37,7 @@ function deleteQuery()
trace("Deleting rows from $tableName ...");
$delRows = 1;
if (strlen($keyValue) == 0) {
if (empty($keyValue)) {
$stmt2 = AE\executeQuery($conn1, "DELETE TOP(1) FROM [$tableName]");
$cond = "(top row)";
} else {

View file

@ -23,7 +23,7 @@ function fetchFields()
AE\createTestTable($conn1, $tableName);
$startRow = 1;
$noRows = 20;
$noRows = 14; // 20;
AE\insertTestRowsByRange($conn1, $tableName, $startRow, $startRow + $noRows - 1);
$query = "SELECT * FROM [$tableName] ORDER BY c27_timestamp";
@ -49,8 +49,12 @@ function fetchFields()
if (isUpdatable($col)) {
// should check data even if $fld is null
$data = AE\getInsertData($startRow + $i, $col);
if (!checkData($col, $fld, $data)) {
echo("\nData error\nExpected:\n$data\nActual:\n$fld\n");
if (!checkData($col, $fld, $data, isBinary($col))) {
// echo("\nData error\nExpected:\n$data\nActual:\n$fld\n");
echo("\nData error\nExpected:\n");
var_dump($data);
echo("\nActual:\n");
var_dump($fld);
setUTF8Data(false);
die("Data corruption on row ".($startRow + $i)." column $col");
@ -66,10 +70,23 @@ function fetchFields()
sqlsrv_close($conn1);
}
function checkData($col, $actual, $expected)
function checkData($col, $actual, $expected, $isBinary)
{
$success = true;
// First check for nulls
if (is_null($expected)) {
$success = ($isBinary) ? empty($actual) : is_null($actual);
if (!$success) {
trace("\nData error\nExpected null but Actual:\n$actual\n");
}
return $success;
} elseif (is_null($actual)) {
trace("\nData error\nExpected:\n$expected\nbut Actual is null\n");
return false;
}
// Neither is null, so keep checking
if (isNumeric($col)) {
if (floatval($actual) != floatval($expected)) {
$success = false;

View file

@ -126,9 +126,17 @@ function checkData($row, $stmt, $index, $mode)
}
} elseif (isBinary($col)) {
$expected = sqlsrv_get_field($stmt, $index, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
$actual = bin2hex($actual);
if (strcasecmp($actual, $expected) != 0) {
$success = false;
if (is_null($expected)) {
$success = is_null($actual);
} else {
if (is_null($actual)) {
$success = false;
} else {
$actual = bin2hex($actual);
if (strcasecmp($actual, $expected) != 0) {
$success = false;
}
}
}
} else { // if (isChar($col))
if (useUTF8Data()) {
@ -136,7 +144,9 @@ function checkData($row, $stmt, $index, $mode)
} else {
$expected = sqlsrv_get_field($stmt, $index, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
}
if (strcmp($actual, $expected) != 0) {
if (is_null($expected)) {
$success = is_null($actual);
} elseif (strcmp($actual, $expected) != 0) {
$success = false;
}
}

View file

@ -86,15 +86,24 @@ function verifyStream($stmt, $row, $colIndex)
function checkData($col, $actual, $expected)
{
if (is_null($expected)) {
return empty($actual);
}
$success = true;
if (isBinary($col)) {
$actual = bin2hex($actual);
if (strncasecmp($actual, $expected, strlen($expected)) != 0) {
if (is_null($actual)) {
$success = false;
} else {
$actual = bin2hex($actual);
if (strncasecmp($actual, $expected, strlen($expected)) != 0) {
$success = false;
}
}
} else {
if (strncasecmp($actual, $expected, strlen($expected)) != 0) {
$len = (empty($expected)) ? 0 : strlen($expected);
if (strncasecmp($actual, $expected, $len) != 0) {
if ($col != 19) { // skip ntext
$pos = strpos($actual, $expected);
if (($pos === false) || ($pos > 1)) {
@ -120,7 +129,8 @@ startTest($testName);
if (isLocaleSupported()) {
try {
setUTF8Data(false);
streamRead(20, 1);
// streamRead(20, 1);
streamRead(14, 1);
} catch (Exception $e) {
echo $e->getMessage();
}
@ -132,7 +142,8 @@ startTest($testName);
try {
setUTF8Data(true);
resetLocaleToDefault();
streamRead(20, 1);
// streamRead(20, 1);
streamRead(14, 1);
} catch (Exception $e) {
echo $e->getMessage();
}

View file

@ -105,15 +105,24 @@ function verifyStream($stmt, $row, $colIndex)
function checkData($col, $actual, $expected)
{
if (is_null($expected)) {
return empty($actual);
}
$success = true;
if (isBinary($col)) {
$actual = bin2hex($actual);
if (strncasecmp($actual, $expected, strlen($expected)) != 0) {
if (is_null($actual)) {
$success = false;
} else {
$actual = bin2hex($actual);
if (strncasecmp($actual, $expected, strlen($expected)) != 0) {
$success = false;
}
}
} else {
if (strncasecmp($actual, $expected, strlen($expected)) != 0) {
$len = (empty($expected)) ? 0 : strlen($expected);
if (strncasecmp($actual, $expected, $len) != 0) {
if ($col != 19) {
// skip ntext
$pos = strpos($actual, $expected);
@ -143,7 +152,8 @@ startTest($testName);
if (isLocaleSupported()) {
try {
setUTF8Data(false);
streamScroll(20, 1);
// streamScroll(20, 1);
streamScroll(14, 1);
} catch (Exception $e) {
echo $e->getMessage();
}
@ -155,7 +165,8 @@ startTest($testName);
try {
setUTF8Data(true);
resetLocaleToDefault();
streamScroll(20, 1);
// streamScroll(20, 1);
streamScroll(14, 1);
} catch (Exception $e) {
echo $e->getMessage();
}

View file

@ -25,13 +25,14 @@ if (!$stmt) {
}
// insert new date time types as strings (this works now)
$d1 = date_create();
$insertSql = "INSERT INTO [$tableName] (id, [c1_date], [c2_time], [c3_datetimeoffset], [c4_datetime2]) VALUES (?, ?, ?, ?, ?)";
$stmt = AE\executeQueryParams(
$conn,
$insertSql,
array(rand(0, 99999),
array(strftime('%Y-%m-%d'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATE),
array(strftime('%H:%M:%S'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_TIME),
array(date_format($d1, 'Y-m-d'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATE),
array(date_format($d1, 'H:i:s'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_TIME),
array(date_format(date_create(), 'Y-m-d H:i:s.u P'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATETIMEOFFSET),
array(date_format(date_create(), 'Y-m-d H:i:s.u'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATETIME2)),
false,
@ -61,10 +62,11 @@ $stmt = AE\executeQueryParams(
);
// insert new date time types as strings with no type information (this works)
$d2 = date_create();
$stmt = AE\executeQueryParams(
$conn,
$insertSql,
array(rand(0, 99999), strftime('%Y-%m-%d'), strftime('%H:%M:%S'), date_format(date_create(), 'Y-m-d H:i:s.u P'), date_format(date_create(), 'Y-m-d H:i:s.u P')),
array(rand(0, 99999), date_format($d2, 'Y-m-d'), date_format($d2, 'H:i:s'), date_format(date_create(), 'Y-m-d H:i:s.u P'), date_format(date_create(), 'Y-m-d H:i:s.u P')),
false,
"Insert 4 failed"
);

View file

@ -60,7 +60,12 @@ function FetchAsStream_Binary()
function CompareValues($actual, $expected)
{
return (strncasecmp($actual, $expected, strlen($expected)) === 0);
if (is_null($expected)) {
return (is_null($actual));
}
$len = (empty($expected)) ? 0 : strlen($expected);
return (strncasecmp($actual, $expected, $len) === 0);
}
function GetQuery($tableName, $index)

View file

@ -218,7 +218,7 @@ function compareDataStream($colType, $rowIndex, $colName, $stream, $expected)
function compareBinaryData($actual, $expected)
{
// this function assumes $actual is a stream of hex
$len = strlen($expected);
$len = (empty($expected)) ? 0 : strlen($expected);
$pos = 0;
$matched = true;