diff --git a/appveyor.yml b/appveyor.yml index e7d4af30..f1994bc2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,16 +27,16 @@ environment: PHP_SDK_DIR: c:\projects\php\x86 PHP_INSTALL_DIR: c:\projects\php\x86\bin platform: x86 - - BUILD_PLATFORM: x64 + - BUILD_PLATFORM: x86 TEST_PHP_SQL_SERVER: (local)\SQL2012SP1 SQL_INSTANCE: SQL2012SP1 PHP_VC: 14 PHP_MAJOR_VER: 7.0 PHP_MINOR_VER: latest - PHP_SDK_DIR: c:\projects\php\x64 - PHP_INSTALL_DIR: c:\projects\php\x64\bin + PHP_SDK_DIR: c:\projects\php\x86 + PHP_INSTALL_DIR: c:\projects\php\x86\bin PHP_ZTS: --disable-zts - platform: x64 + platform: x86 - BUILD_PLATFORM: x86 TEST_PHP_SQL_SERVER: (local)\SQL2014 SQL_INSTANCE: SQL2014 diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 957389e4..7dafef7d 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -357,18 +357,18 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ try { // check is only < because params are 0 based - CHECK_CUSTOM_ERROR( param_num >= SQL_SERVER_MAX_PARAMS, stmt, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, param_num + 1 ) { + CHECK_CUSTOM_ERROR( param_num >= SQL_SERVER_MAX_PARAMS, stmt, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, param_num + 1 ){ throw core::CoreException(); } // resize the statements array of int_ptrs if the parameter isn't already set. - if( stmt->param_ind_ptrs.size() < static_cast(param_num + 1) ) { + if( stmt->param_ind_ptrs.size() < static_cast( param_num + 1 )){ stmt->param_ind_ptrs.resize( param_num + 1, SQL_NULL_DATA ); } SQLLEN& ind_ptr = stmt->param_ind_ptrs[ param_num ]; zval* param_ref = param_z; - if ( Z_ISREF_P( param_z ) ) { + if( Z_ISREF_P( param_z )){ ZVAL_DEREF( param_z ); } bool zval_was_null = ( Z_TYPE_P( param_z ) == IS_NULL ); @@ -379,24 +379,24 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ // we always let that match if they want a string back. if( direction == SQL_PARAM_INPUT_OUTPUT ) { bool match = false; - switch( php_out_type ) { + switch( php_out_type ){ case SQLSRV_PHPTYPE_INT: - if( zval_was_null || zval_was_bool ) { + if( zval_was_null || zval_was_bool ){ convert_to_long( param_z ); } if( zval_was_long ){ convert_to_string( param_z ); - if ( encoding != SQLSRV_ENCODING_SYSTEM && encoding != SQLSRV_ENCODING_UTF8 && encoding != SQLSRV_ENCODING_BINARY ) { + if( encoding != SQLSRV_ENCODING_SYSTEM && encoding != SQLSRV_ENCODING_UTF8 && encoding != SQLSRV_ENCODING_BINARY ){ encoding = SQLSRV_ENCODING_SYSTEM; } match = Z_TYPE_P( param_z ) == IS_STRING; } - else { + else{ match = Z_TYPE_P( param_z ) == IS_LONG; } break; case SQLSRV_PHPTYPE_FLOAT: - if( zval_was_null ) { + if( zval_was_null ){ convert_to_double( param_z ); } match = Z_TYPE_P( param_z ) == IS_DOUBLE; @@ -415,23 +415,23 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ SQLSRV_ASSERT( false, "Unknown SQLSRV_PHPTYPE_* constant given." ); break; } - CHECK_CUSTOM_ERROR( !match, stmt, SQLSRV_ERROR_INPUT_OUTPUT_PARAM_TYPE_MATCH, param_num + 1 ) { + CHECK_CUSTOM_ERROR( !match, stmt, SQLSRV_ERROR_INPUT_OUTPUT_PARAM_TYPE_MATCH, param_num + 1 ){ throw core::CoreException(); } } // if it's an output parameter and the user asks for a certain type, we have to convert the zval to that type so // when the buffer is filled, the type is correct - if( direction == SQL_PARAM_OUTPUT ) { + if( direction == SQL_PARAM_OUTPUT ){ switch( php_out_type ) { case SQLSRV_PHPTYPE_INT: if( zval_was_long ){ convert_to_string( param_z ); - if ( encoding != SQLSRV_ENCODING_SYSTEM && encoding != SQLSRV_ENCODING_UTF8 && encoding != SQLSRV_ENCODING_BINARY ) { + if( encoding != SQLSRV_ENCODING_SYSTEM && encoding != SQLSRV_ENCODING_UTF8 && encoding != SQLSRV_ENCODING_BINARY ){ encoding = SQLSRV_ENCODING_SYSTEM; } } - else { + else{ convert_to_long( param_z ); } break; @@ -456,20 +456,20 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ ( encoding == SQLSRV_ENCODING_SYSTEM || encoding == SQLSRV_ENCODING_UTF8 || encoding == SQLSRV_ENCODING_BINARY ), "core_sqlsrv_bind_param: invalid encoding" ); - if ( stmt->conn->ce_option.enabled && ( sql_type == SQL_UNKNOWN_TYPE || column_size == SQLSRV_UNKNOWN_SIZE )) { + if( stmt->conn->ce_option.enabled && ( sql_type == SQL_UNKNOWN_TYPE || column_size == SQLSRV_UNKNOWN_SIZE )){ ae_get_sql_type_info( stmt, param_num, direction, param_z, encoding, sql_type, column_size, decimal_digits TSRMLS_CC ); // change long to double if the sql type is decimal - if ( sql_type == SQL_DECIMAL && Z_TYPE_P( param_z ) == IS_LONG ) - convert_to_double( param_z ); + if(( sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC ) && Z_TYPE_P(param_z) == IS_LONG ) + convert_to_double( param_z ); } - else { + else{ // if the sql type is unknown, then set the default based on the PHP type passed in - if ( sql_type == SQL_UNKNOWN_TYPE ) { + if( sql_type == SQL_UNKNOWN_TYPE ){ default_sql_type( stmt, param_num, param_z, encoding, sql_type TSRMLS_CC ); } // if the size is unknown, then set the default based on the PHP type passed in - if ( column_size == SQLSRV_UNKNOWN_SIZE ) { + if( column_size == SQLSRV_UNKNOWN_SIZE ){ default_sql_size_and_scale( stmt, static_cast(param_num), param_z, encoding, column_size, decimal_digits TSRMLS_CC ); } } @@ -477,7 +477,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ c_type = default_c_type( stmt, param_num, param_z, encoding TSRMLS_CC ); // set the buffer based on the PHP parameter type - switch( Z_TYPE_P( param_z )) { + switch( Z_TYPE_P( param_z )){ case IS_NULL: { @@ -491,12 +491,12 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ case IS_FALSE: case IS_LONG: { - // if it is boolean, set the lval to 0 or 1 - convert_to_long( param_z ); + // if it is boolean, set the lval to 0 or 1 + convert_to_long( param_z ); buffer = ¶m_z->value; buffer_len = sizeof( Z_LVAL_P( param_z )); ind_ptr = buffer_len; - if( direction != SQL_PARAM_INPUT ) { + if( direction != SQL_PARAM_INPUT ){ // save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned sqlsrv_output_param output_param( param_ref, static_cast( param_num ), zval_was_bool ); save_output_param_for_later( stmt, output_param TSRMLS_CC ); @@ -508,7 +508,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ buffer = ¶m_z->value; buffer_len = sizeof( Z_DVAL_P( param_z )); ind_ptr = buffer_len; - if( direction != SQL_PARAM_INPUT ) { + if( direction != SQL_PARAM_INPUT ){ // save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned sqlsrv_output_param output_param( param_ref, static_cast( param_num ), false ); save_output_param_for_later( stmt, output_param TSRMLS_CC ); @@ -516,82 +516,115 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ } break; case IS_STRING: - buffer = Z_STRVAL_P( param_z ); - buffer_len = Z_STRLEN_P( param_z ); - // if the encoding is UTF-8, translate from UTF-8 to UTF-16 (the type variables should have already been adjusted) - if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 ) { - - zval wbuffer_z; - ZVAL_NULL( &wbuffer_z ); - - bool converted = convert_input_param_to_utf16( param_z, &wbuffer_z ); - CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE, - param_num + 1, get_last_error_message() ) { - throw core::CoreException(); + { + buffer = Z_STRVAL_P( param_z ); + buffer_len = Z_STRLEN_P( param_z ); + + if( stmt->conn->ce_option.enabled && ( sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC )){ + // get the double value + double dval = zend_strtod( ZSTR_VAL( Z_STR_P( param_z )), NULL ); + // find the precision: number of digits before decimal place + decimal_digits + size_t numDigitsBeforeDec = 0; + double temp = dval; + if( abs( dval ) < 1){ + numDigitsBeforeDec = 0; + } + else{ + while( abs( temp ) > 1 ){ + temp /= 10; + numDigitsBeforeDec++; + } + } + size_t precision = numDigitsBeforeDec + decimal_digits; + // when passing a precision 0 to strppintf, it still returns a string with precision of 1 + // work around it by manually rounding the zval + if( precision == 0 && abs( dval ) < 1 ){ + if( dval < 0.5 ) + dval = 0; + else + dval = 1; + } + // reformat it with the right number of decimal digits + zend_string *str = strpprintf( 0, "%.*G", ( int )precision, dval ); + zend_string_release( Z_STR_P( param_z )); + ZVAL_NEW_STR( param_z, str ); } - buffer = Z_STRVAL_P( &wbuffer_z ); - buffer_len = Z_STRLEN_P( &wbuffer_z ); - core::sqlsrv_add_index_zval(*stmt, &(stmt->param_input_strings), param_num, &wbuffer_z TSRMLS_CC); - } - ind_ptr = buffer_len; - if( direction != SQL_PARAM_INPUT ) { - // PHP 5.4 added interned strings, so since we obviously want to change that string here in some fashion, - // we reallocate the string if it's interned - if ( ZSTR_IS_INTERNED( Z_STR_P( param_z ))) { - core::sqlsrv_zval_stringl( param_z, static_cast(buffer), buffer_len ); - buffer = Z_STRVAL_P( param_z ); - buffer_len = Z_STRLEN_P( param_z ); - } - - // if it's a UTF-8 input output parameter (signified by the C type being SQL_C_WCHAR) - // or if the PHP type is a binary encoded string with a N(VAR)CHAR/NTEXTSQL type, - // convert it to wchar first - if( direction == SQL_PARAM_INPUT_OUTPUT && - ( c_type == SQL_C_WCHAR || - ( c_type == SQL_C_BINARY && - ( sql_type == SQL_WCHAR || - sql_type == SQL_WVARCHAR || - sql_type == SQL_WLONGVARCHAR )))) { + + // if the encoding is UTF-8, translate from UTF-8 to UTF-16 (the type variables should have already been adjusted) + if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 ){ - bool converted = convert_input_param_to_utf16( param_z, param_z ); - CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE, - param_num + 1, get_last_error_message() ) { + zval wbuffer_z; + ZVAL_NULL( &wbuffer_z ); + + bool converted = convert_input_param_to_utf16( param_z, &wbuffer_z ); + CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE, + param_num + 1, get_last_error_message() ){ throw core::CoreException(); } - buffer = Z_STRVAL_P( param_z ); - buffer_len = Z_STRLEN_P( param_z ); - ind_ptr = buffer_len; + buffer = Z_STRVAL_P( &wbuffer_z ); + buffer_len = Z_STRLEN_P( &wbuffer_z ); + core::sqlsrv_add_index_zval( *stmt, &( stmt->param_input_strings ), param_num, &wbuffer_z TSRMLS_CC ); } + ind_ptr = buffer_len; + if( direction != SQL_PARAM_INPUT ){ + // PHP 5.4 added interned strings, so since we obviously want to change that string here in some fashion, + // we reallocate the string if it's interned + if( ZSTR_IS_INTERNED( Z_STR_P( param_z ))){ + core::sqlsrv_zval_stringl( param_z, static_cast(buffer), buffer_len ); + buffer = Z_STRVAL_P( param_z ); + buffer_len = Z_STRLEN_P( param_z ); + } - // since this is an output string, assure there is enough space to hold the requested size and - // set all the variables necessary (param_z, buffer, buffer_len, and ind_ptr) - resize_output_buffer_if_necessary( stmt, param_z, param_num, encoding, c_type, sql_type, column_size, decimal_digits, - buffer, buffer_len TSRMLS_CC ); + // if it's a UTF-8 input output parameter (signified by the C type being SQL_C_WCHAR) + // or if the PHP type is a binary encoded string with a N(VAR)CHAR/NTEXTSQL type, + // convert it to wchar first + if( direction == SQL_PARAM_INPUT_OUTPUT && + ( c_type == SQL_C_WCHAR || + ( c_type == SQL_C_BINARY && + ( sql_type == SQL_WCHAR || + sql_type == SQL_WVARCHAR || + sql_type == SQL_WLONGVARCHAR )))){ - // save the parameter to be adjusted and/or converted after the results are processed - sqlsrv_output_param output_param( param_ref, encoding, param_num, static_cast( buffer_len ), zval_was_long ); + bool converted = convert_input_param_to_utf16( param_z, param_z ); + CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE, + param_num + 1, get_last_error_message() ){ + throw core::CoreException(); + } + buffer = Z_STRVAL_P( param_z ); + buffer_len = Z_STRLEN_P( param_z ); + ind_ptr = buffer_len; + } - save_output_param_for_later( stmt, output_param TSRMLS_CC ); + // since this is an output string, assure there is enough space to hold the requested size and + // set all the variables necessary (param_z, buffer, buffer_len, and ind_ptr) + resize_output_buffer_if_necessary( stmt, param_z, param_num, encoding, c_type, sql_type, column_size, decimal_digits, + buffer, buffer_len TSRMLS_CC ); - // For output parameters, if we set the column_size to be same as the buffer_len, - // then if there is a truncation due to the data coming from the server being - // greater than the column_size, we don't get any truncation error. In order to - // avoid this silent truncation, we set the column_size to be "MAX" size for - // string types. This will guarantee that there is no silent truncation for - // output parameters. - // if column encryption is enabled, at this point the correct column size has been set by SQLDescribeParam - if( direction == SQL_PARAM_OUTPUT && !stmt->conn->ce_option.enabled ) { - - switch( sql_type ) { + // save the parameter to be adjusted and/or converted after the results are processed + sqlsrv_output_param output_param( param_ref, encoding, param_num, static_cast( buffer_len ), zval_was_long ); + + save_output_param_for_later( stmt, output_param TSRMLS_CC ); + + // For output parameters, if we set the column_size to be same as the buffer_len, + // then if there is a truncation due to the data coming from the server being + // greater than the column_size, we don't get any truncation error. In order to + // avoid this silent truncation, we set the column_size to be "MAX" size for + // string types. This will guarantee that there is no silent truncation for + // output parameters. + // if column encryption is enabled, at this point the correct column size has been set by SQLDescribeParam + if( direction == SQL_PARAM_OUTPUT && !stmt->conn->ce_option.enabled ){ + + switch( sql_type ){ case SQL_VARBINARY: case SQL_VARCHAR: - case SQL_WVARCHAR: + case SQL_WVARCHAR: column_size = SQL_SS_LENGTH_UNLIMITED; break; default: break; + } } } } @@ -624,36 +657,36 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ zend_class_entry *class_entry = Z_OBJCE_P( param_z TSRMLS_CC ); - while( class_entry != NULL ) { + while( class_entry != NULL ){ SQLSRV_ASSERT( class_entry->name != NULL, "core_sqlsrv_bind_param: class_entry->name is NULL." ); if( class_entry->name->len == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL && - stricmp( class_entry->name->val, DateTime::DATETIME_CLASS_NAME ) == 0 ) { + stricmp( class_entry->name->val, DateTime::DATETIME_CLASS_NAME ) == 0 ){ valid_class_name_found = true; break; } - else { + else{ // Check the parent class_entry = class_entry->parent; } } - CHECK_CUSTOM_ERROR( !valid_class_name_found, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { + CHECK_CUSTOM_ERROR( !valid_class_name_found, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ){ throw core::CoreException(); } // if the user specifies the 'date' sql type, giving it the normal format will cause a 'date overflow error' // meaning there is too much information in the character string. If the user specifies the 'datetimeoffset' // sql type, it lacks the timezone. - if( sql_type == SQL_SS_TIMESTAMPOFFSET ) { + if( sql_type == SQL_SS_TIMESTAMPOFFSET ){ core::sqlsrv_zval_stringl( &format_z, const_cast( DateTime::DATETIMEOFFSET_FORMAT ), DateTime::DATETIMEOFFSET_FORMAT_LEN ); } - else if( sql_type == SQL_TYPE_DATE ) { + else if( sql_type == SQL_TYPE_DATE ){ core::sqlsrv_zval_stringl( &format_z, const_cast( DateTime::DATE_FORMAT ), DateTime::DATE_FORMAT_LEN ); } - else { + else{ core::sqlsrv_zval_stringl( &format_z, const_cast( DateTime::DATETIME_FORMAT ), DateTime::DATETIME_FORMAT_LEN ); } // call the DateTime::format member function to convert the object to a string that SQL Server understands @@ -664,12 +697,12 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ int zr = call_user_function( EG( function_table ), param_z, &function_z, &buffer_z, 1, params TSRMLS_CC ); zend_string_release( Z_STR( format_z )); zend_string_release( Z_STR( function_z )); - CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { + CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ){ throw core::CoreException(); } buffer = Z_STRVAL( buffer_z ); zr = add_next_index_zval( &( stmt->param_datetime_buffers ), &buffer_z ); - CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { + CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ){ throw core::CoreException(); } buffer_len = Z_STRLEN( buffer_z ) - 1; @@ -685,7 +718,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ break; } - if( zval_was_null ) { + if( zval_was_null ){ ind_ptr = SQL_NULL_DATA; } @@ -693,13 +726,13 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr TSRMLS_CC ); if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP ) { - if ( decimal_digits == 3 ) + if( decimal_digits == 3 ) core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, 0 ); else if (decimal_digits == 0) core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, 0 ); } } - catch( core::CoreException& e ) { + catch( core::CoreException& e ){ stmt->free_param_data( TSRMLS_C ); SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS ); throw e; diff --git a/test/functional/pdo_sqlsrv/pdo_decimal_precision.phpt b/test/functional/pdo_sqlsrv/pdo_decimal_precision.phpt new file mode 100644 index 00000000..3a9fca9f --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_decimal_precision.phpt @@ -0,0 +1,64 @@ +--TEST-- +Insert into decimal columns with inputs of various scale and precision +--SKIPIF-- + +--FILE-- + "decimal", "c2_decimal4" => "decimal(19,4)")); + + insertRow($conn, $tableName, array("c1_decimal0" => 0.9, "c2_decimal4" => 0.9)); + insertRow($conn, $tableName, array("c1_decimal0" => 9.9, "c2_decimal4" => 9.9)); + insertRow($conn, $tableName, array("c1_decimal0" => 999.999, "c2_decimal4" => 999.999)); + insertRow($conn, $tableName, array("c1_decimal0" => 99999.99999, "c2_decimal4" => 99999.99999)); + + $query = "SELECT * FROM $tableName"; + $stmt = $conn->query($query); + $row = $stmt->fetchAll(PDO::FETCH_ASSOC); + var_dump($row); + + dropTable($conn, $tableName); + unset($stmt); + unset($conn); +} catch (PDOException $e) { + var_dump($e->errorInfo); +} + +?> +--EXPECT-- +array(4) { + [0]=> + array(2) { + ["c1_decimal0"]=> + string(1) "1" + ["c2_decimal4"]=> + string(5) ".9000" + } + [1]=> + array(2) { + ["c1_decimal0"]=> + string(2) "10" + ["c2_decimal4"]=> + string(6) "9.9000" + } + [2]=> + array(2) { + ["c1_decimal0"]=> + string(4) "1000" + ["c2_decimal4"]=> + string(8) "999.9990" + } + [3]=> + array(2) { + ["c1_decimal0"]=> + string(6) "100000" + ["c2_decimal4"]=> + string(11) "100000.0000" + } +} \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_decimal_precision.phpt b/test/functional/sqlsrv/sqlsrv_decimal_precision.phpt new file mode 100644 index 00000000..3eca7363 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_decimal_precision.phpt @@ -0,0 +1,54 @@ +--TEST-- +Insert into decimal columns with inputs of various scale and precision +--SKIPIF-- + +--FILE-- + 0.9, "c2_decimal4" => 0.9)); +AE\insertRow($conn, $tableName, array("c1_decimal0" => 9.9, "c2_decimal4" => 9.9)); +AE\insertRow($conn, $tableName, array("c1_decimal0" => 999.999, "c2_decimal4" => 999.999)); +AE\insertRow($conn, $tableName, array("c1_decimal0" => 99999.99999, "c2_decimal4" => 99999.99999)); + +$query = "SELECT * FROM $tableName"; +$stmt = sqlsrv_query($conn, $query); +while (($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) != NULL) { + var_dump($row); +} + +dropTable($conn, $tableName); +sqlsrv_free_stmt($stmt); +sqlsrv_close($conn); + +?> +--EXPECT-- +array(2) { + ["c1_decimal0"]=> + string(1) "1" + ["c2_decimal4"]=> + string(5) ".9000" +} +array(2) { + ["c1_decimal0"]=> + string(2) "10" + ["c2_decimal4"]=> + string(6) "9.9000" +} +array(2) { + ["c1_decimal0"]=> + string(4) "1000" + ["c2_decimal4"]=> + string(8) "999.9990" +} +array(2) { + ["c1_decimal0"]=> + string(6) "100000" + ["c2_decimal4"]=> + string(11) "100000.0000" +} \ No newline at end of file