From 5e607a802c5e0376325c6b1e8a5dc62dffa24f95 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Wed, 28 Jul 2021 15:45:04 -0700 Subject: [PATCH] PHP 8.1 dev (#1282) --- source/pdo_sqlsrv/pdo_dbh.cpp | 400 ++++++++++++++---- source/pdo_sqlsrv/pdo_stmt.cpp | 133 ++++-- .../msdn_pdoStatement_debugDumpParams.phpt | 16 +- .../msdn_pdoStatement_getColumnMeta.phpt | 36 +- .../pdo_sqlsrv/MsCommon_mid-refactor.inc | 26 +- .../pdo_sqlsrv/PDO100_InsertNulls.phpt | 2 +- .../pdo_sqlsrv/PDO27_ReadOnlyAttr.phpt | 4 +- .../pdo_sqlsrv/PDO35_ColumnMeta.phpt | 10 +- .../functional/pdo_sqlsrv/PDO51_FetchLOB.phpt | 10 +- .../pdo_sqlsrv/pdo_022_xml_bind_value.phpt | 2 +- ...5_binary_encoding_error_bound_by_name.phpt | 15 +- ...y_encoding_error_bound_by_name_errors.phpt | 11 +- .../pdo_1018_quote_param_str_natl_char.phpt | 7 +- ...pdo_1079_sql_variant_buffered_queries.phpt | 4 +- .../pdo_sqlsrv/pdo_270_fetch_binary.phpt | 26 +- .../pdo_569_query_varcharmax_ae.phpt | 20 +- .../pdo_sqlsrv/pdo_937_metadata.phpt | 6 +- ...do_ae_bindColumn_pdoparam_binary_size.phpt | 8 +- .../pdo_ae_bindColumn_pdoparam_char_size.phpt | 4 + .../pdo_ae_bindColumn_pdoparam_datetime.phpt | 5 + ...indColumn_pdoparam_datetime_precision.phpt | 5 + ...bindColumn_pdoparam_decimal_precision.phpt | 5 + ...pdo_ae_bindColumn_pdoparam_float_bits.phpt | 6 + ...pdo_ae_bindColumn_pdoparam_nchar_size.phpt | 4 + .../pdo_ae_bindColumn_pdoparam_numeric.phpt | 26 +- .../pdo_sqlsrv/pdo_buffered_fetch_types.phpt | 10 +- .../pdo_sqlsrv/pdo_data_classification.phpt | 3 +- .../pdo_data_classification_ranks.phpt | 3 +- ...h_cursorBuffered_float_bindColumn_lob.phpt | 12 + .../pdo_fetch_datetime_time_as_objects.phpt | 13 +- .../pdo_sqlsrv/pdo_fetch_large_stream.phpt | 3 + .../pdo_sqlsrv/pdo_get_attr_invalid.phpt | 26 +- .../pdo_insert_fetch_invalid_utf16.phpt | 2 +- .../pdo_sqlsrv/pdo_lastInsertId.phpt | 8 +- .../pdo_prepare_emulatePrepare_unicode.phpt | 2 +- test/functional/pdo_sqlsrv/pdo_warnings.phpt | 34 +- .../pdo_sqlsrv/pdostatement_Buffqry.phpt | 6 +- .../pdostatement_debugDumpParams.phpt | 6 +- ...dostatement_fetchmode_emulate_prepare.phpt | 4 +- .../pdostatement_getColumnMeta.phpt | 18 +- ...tement_getColumnMeta_unicode_col_name.phpt | 18 +- test/functional/sqlsrv/MsHelper.inc | 27 +- test/functional/sqlsrv/TC32_DeleteQuery.phpt | 2 +- test/functional/sqlsrv/TC43_FetchData.phpt | 27 +- test/functional/sqlsrv/TC44_FetchArray.phpt | 18 +- test/functional/sqlsrv/TC51_StreamRead.phpt | 23 +- .../sqlsrv/TC55_StreamScrollable.phpt | 21 +- .../sqlsrv/sqlsrv_2008_dataTypes.phpt | 8 +- ...sqlsrv_data_types_fetch_binary_stream.phpt | 7 +- test/functional/sqlsrv/tools.inc | 2 +- 50 files changed, 816 insertions(+), 278 deletions(-) diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index e5cbe0a3..46e72670 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -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( 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( 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(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(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( 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( sql_len ) ); - +#if PHP_VERSION_ID < 80100 + SQLRETURN execReturn = core_sqlsrv_execute(driver_stmt, sql, static_cast(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(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(cbID); + // copy the last ID string and return it str = reinterpret_cast(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(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(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(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 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(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(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 quoted; + size_t quoted_len = quotes_needed + len; // length returned to the caller should not account for null terminator + quoted = reinterpret_cast(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 } } diff --git a/source/pdo_sqlsrv/pdo_stmt.cpp b/source/pdo_sqlsrv/pdo_stmt.cpp index 3f1703e7..d8ea9b20 100644 --- a/source/pdo_sqlsrv/pdo_stmt.cpp +++ b/source/pdo_sqlsrv/pdo_stmt.cpp @@ -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( 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(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( 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(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(zend_hash_index_find_ptr(stmt->bound_columns, i))) && (NULL == (bind_data = reinterpret_cast(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(zend_hash_index_find_ptr(stmt->bound_columns, i))) && + (NULL == (bind_data = reinterpret_cast(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( 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(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( driver_stmt->current_meta_data.size()), - "Invalid column number in pdo_sqlsrv_stmt_get_col_data" ); + SQLSRV_ASSERT(colno >= 0 && colno < static_cast(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(driver_stmt->current_meta_data[colno]->field_type), - static_cast(driver_stmt->current_meta_data[colno]->field_size), - true); + static_cast(driver_stmt->current_meta_data[colno]->field_type), + static_cast(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(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(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(ptr)), - reinterpret_cast( len ), true, &sqlsrv_phptype_out ); +#if PHP_VERSION_ID < 80100 + core_sqlsrv_get_field(driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast(ptr)), + reinterpret_cast(len), true, &sqlsrv_phptype_out); if (ptr) { zval* zval_ptr = reinterpret_cast(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(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); diff --git a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_debugDumpParams.phpt b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_debugDumpParams.phpt index b4b21562..e1dccd2b 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_debugDumpParams.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_debugDumpParams.phpt @@ -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 \ No newline at end of file +param_type=(2|3) \ No newline at end of file diff --git a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_getColumnMeta.phpt b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_getColumnMeta.phpt index e907a6da..d40209e3 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_getColumnMeta.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_getColumnMeta.phpt @@ -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 diff --git a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc index c5b79a22..44d88454 100644 --- a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc +++ b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc @@ -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; +} diff --git a/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt b/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt index 97d712e7..64f9671a 100644 --- a/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt +++ b/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt @@ -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); diff --git a/test/functional/pdo_sqlsrv/PDO27_ReadOnlyAttr.phpt b/test/functional/pdo_sqlsrv/PDO27_ReadOnlyAttr.phpt index dcd61d09..4755808d 100644 --- a/test/functional/pdo_sqlsrv/PDO27_ReadOnlyAttr.phpt +++ b/test/functional/pdo_sqlsrv/PDO27_ReadOnlyAttr.phpt @@ -10,7 +10,7 @@ PHPT_EXEC=true ---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"]=> diff --git a/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt b/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt index e26f73e7..a271d96c 100644 --- a/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt +++ b/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt @@ -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); diff --git a/test/functional/pdo_sqlsrv/pdo_022_xml_bind_value.phpt b/test/functional/pdo_sqlsrv/pdo_022_xml_bind_value.phpt index 64ffa50b..5e1a34b5 100644 --- a/test/functional/pdo_sqlsrv/pdo_022_xml_bind_value.phpt +++ b/test/functional/pdo_sqlsrv/pdo_022_xml_bind_value.phpt @@ -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 diff --git a/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name.phpt b/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name.phpt index 2a8236b3..0c7d89fc 100644 --- a/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name.phpt +++ b/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name.phpt @@ -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); diff --git a/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name_errors.phpt b/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name_errors.phpt index 39d30729..98d68f63 100644 --- a/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name_errors.phpt +++ b/test/functional/pdo_sqlsrv/pdo_035_binary_encoding_error_bound_by_name_errors.phpt @@ -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); diff --git a/test/functional/pdo_sqlsrv/pdo_1018_quote_param_str_natl_char.phpt b/test/functional/pdo_sqlsrv/pdo_1018_quote_param_str_natl_char.phpt index 5b39f9f1..478bcf91 100644 --- a/test/functional/pdo_sqlsrv/pdo_1018_quote_param_str_natl_char.phpt +++ b/test/functional/pdo_sqlsrv/pdo_1018_quote_param_str_natl_char.phpt @@ -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)); diff --git a/test/functional/pdo_sqlsrv/pdo_1079_sql_variant_buffered_queries.phpt b/test/functional/pdo_sqlsrv/pdo_1079_sql_variant_buffered_queries.phpt index 1ba60606..0bbfcff3 100644 --- a/test/functional/pdo_sqlsrv/pdo_1079_sql_variant_buffered_queries.phpt +++ b/test/functional/pdo_sqlsrv/pdo_1079_sql_variant_buffered_queries.phpt @@ -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"]=> diff --git a/test/functional/pdo_sqlsrv/pdo_270_fetch_binary.phpt b/test/functional/pdo_sqlsrv/pdo_270_fetch_binary.phpt index f3f52b80..7ce39da6 100644 --- a/test/functional/pdo_sqlsrv/pdo_270_fetch_binary.phpt +++ b/test/functional/pdo_sqlsrv/pdo_270_fetch_binary.phpt @@ -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); diff --git a/test/functional/pdo_sqlsrv/pdo_569_query_varcharmax_ae.phpt b/test/functional/pdo_sqlsrv/pdo_569_query_varcharmax_ae.phpt index d41175a2..83395bd5 100644 --- a/test/functional/pdo_sqlsrv/pdo_569_query_varcharmax_ae.phpt +++ b/test/functional/pdo_sqlsrv/pdo_569_query_varcharmax_ae.phpt @@ -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); diff --git a/test/functional/pdo_sqlsrv/pdo_937_metadata.phpt b/test/functional/pdo_sqlsrv/pdo_937_metadata.phpt index d0cad7e7..403e5cb7 100644 --- a/test/functional/pdo_sqlsrv/pdo_937_metadata.phpt +++ b/test/functional/pdo_sqlsrv/pdo_937_metadata.phpt @@ -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"]=> diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt index 253460ea..2f320ce6 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt index e575d3fd..4fffc614 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt index b1cf8235..7fce47d4 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt index cb92c950..0d2947f1 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt index ce4aa395..e9d882c2 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt @@ -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; diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt index 8eb2b918..b234a725 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt index 43ead937..bb374008 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt index 1a281bdb..ff17dc7e 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt @@ -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"; diff --git a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt index ebf19765..9204f684 100644 --- a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt +++ b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt @@ -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"; diff --git a/test/functional/pdo_sqlsrv/pdo_data_classification.phpt b/test/functional/pdo_sqlsrv/pdo_data_classification.phpt index 13add5bb..ce734a9c 100644 --- a/test/functional/pdo_sqlsrv/pdo_data_classification.phpt +++ b/test/functional/pdo_sqlsrv/pdo_data_classification.phpt @@ -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()); } diff --git a/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt b/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt index f97be99e..df57f6e6 100644 --- a/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt +++ b/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt @@ -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()); } diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_cursorBuffered_float_bindColumn_lob.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_cursorBuffered_float_bindColumn_lob.phpt index 4239aef5..8682a6bc 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_cursorBuffered_float_bindColumn_lob.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_cursorBuffered_float_bindColumn_lob.phpt @@ -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"; diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_datetime_time_as_objects.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_datetime_time_as_objects.phpt index 174f98e4..b2747edf 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_datetime_time_as_objects.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_datetime_time_as_objects.phpt @@ -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(); diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt index 5f106b2e..b3d529ba 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt @@ -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; diff --git a/test/functional/pdo_sqlsrv/pdo_get_attr_invalid.phpt b/test/functional/pdo_sqlsrv/pdo_get_attr_invalid.phpt index 09be0c7d..5ab1f50d 100644 --- a/test/functional/pdo_sqlsrv/pdo_get_attr_invalid.phpt +++ b/test/functional/pdo_sqlsrv/pdo_get_attr_invalid.phpt @@ -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. diff --git a/test/functional/pdo_sqlsrv/pdo_insert_fetch_invalid_utf16.phpt b/test/functional/pdo_sqlsrv/pdo_insert_fetch_invalid_utf16.phpt index c90e3135..387fbb42 100644 --- a/test/functional/pdo_sqlsrv/pdo_insert_fetch_invalid_utf16.phpt +++ b/test/functional/pdo_sqlsrv/pdo_insert_fetch_invalid_utf16.phpt @@ -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 { diff --git a/test/functional/pdo_sqlsrv/pdo_lastInsertId.phpt b/test/functional/pdo_sqlsrv/pdo_lastInsertId.phpt index 7dfe4bbb..99ea03a5 100644 --- a/test/functional/pdo_sqlsrv/pdo_lastInsertId.phpt +++ b/test/functional/pdo_sqlsrv/pdo_lastInsertId.phpt @@ -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\)) diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt index 025f94c3..71a35f82 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt @@ -6,7 +6,7 @@ prepare with emulate prepare and binding uft8 characters --FILE-- 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]+ diff --git a/test/functional/pdo_sqlsrv/pdostatement_Buffqry.phpt b/test/functional/pdo_sqlsrv/pdostatement_Buffqry.phpt index 31e36a88..e453fcf7 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_Buffqry.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_Buffqry.phpt @@ -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(); diff --git a/test/functional/pdo_sqlsrv/pdostatement_debugDumpParams.phpt b/test/functional/pdo_sqlsrv/pdostatement_debugDumpParams.phpt index 64364ec3..deba3dbb 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_debugDumpParams.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_debugDumpParams.phpt @@ -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 diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt index 8791a96b..bc21e3dc 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt @@ -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"]=> diff --git a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt index bf54175a..75bfeca9 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt @@ -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"]=> diff --git a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt index f3485ec6..fa7e015b 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt @@ -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"]=> diff --git a/test/functional/sqlsrv/MsHelper.inc b/test/functional/sqlsrv/MsHelper.inc index 2e35366a..c9d18688 100644 --- a/test/functional/sqlsrv/MsHelper.inc +++ b/test/functional/sqlsrv/MsHelper.inc @@ -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) diff --git a/test/functional/sqlsrv/TC32_DeleteQuery.phpt b/test/functional/sqlsrv/TC32_DeleteQuery.phpt index e7ea92fb..68a43827 100644 --- a/test/functional/sqlsrv/TC32_DeleteQuery.phpt +++ b/test/functional/sqlsrv/TC32_DeleteQuery.phpt @@ -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 { diff --git a/test/functional/sqlsrv/TC43_FetchData.phpt b/test/functional/sqlsrv/TC43_FetchData.phpt index ad446f0c..0e6c6a0d 100644 --- a/test/functional/sqlsrv/TC43_FetchData.phpt +++ b/test/functional/sqlsrv/TC43_FetchData.phpt @@ -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; diff --git a/test/functional/sqlsrv/TC44_FetchArray.phpt b/test/functional/sqlsrv/TC44_FetchArray.phpt index b6073f6b..13d9336e 100644 --- a/test/functional/sqlsrv/TC44_FetchArray.phpt +++ b/test/functional/sqlsrv/TC44_FetchArray.phpt @@ -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; } } diff --git a/test/functional/sqlsrv/TC51_StreamRead.phpt b/test/functional/sqlsrv/TC51_StreamRead.phpt index 967aab1d..4a61216d 100644 --- a/test/functional/sqlsrv/TC51_StreamRead.phpt +++ b/test/functional/sqlsrv/TC51_StreamRead.phpt @@ -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(); } diff --git a/test/functional/sqlsrv/TC55_StreamScrollable.phpt b/test/functional/sqlsrv/TC55_StreamScrollable.phpt index f3c88b1f..ad14bd69 100644 --- a/test/functional/sqlsrv/TC55_StreamScrollable.phpt +++ b/test/functional/sqlsrv/TC55_StreamScrollable.phpt @@ -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(); } diff --git a/test/functional/sqlsrv/sqlsrv_2008_dataTypes.phpt b/test/functional/sqlsrv/sqlsrv_2008_dataTypes.phpt index f7fa0151..eef68e38 100644 --- a/test/functional/sqlsrv/sqlsrv_2008_dataTypes.phpt +++ b/test/functional/sqlsrv/sqlsrv_2008_dataTypes.phpt @@ -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" ); diff --git a/test/functional/sqlsrv/sqlsrv_data_types_fetch_binary_stream.phpt b/test/functional/sqlsrv/sqlsrv_data_types_fetch_binary_stream.phpt index 56924648..3e425f4b 100644 --- a/test/functional/sqlsrv/sqlsrv_data_types_fetch_binary_stream.phpt +++ b/test/functional/sqlsrv/sqlsrv_data_types_fetch_binary_stream.phpt @@ -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) diff --git a/test/functional/sqlsrv/tools.inc b/test/functional/sqlsrv/tools.inc index ad2899c9..275dfdec 100644 --- a/test/functional/sqlsrv/tools.inc +++ b/test/functional/sqlsrv/tools.inc @@ -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;