@@ -96,13 +96,14 @@ sqlsrv_phptype determine_sqlsrv_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sq
96
96
void determine_stmt_has_rows ( _Inout_ ss_sqlsrv_stmt* stmt );
97
97
bool is_valid_sqlsrv_phptype ( _In_ sqlsrv_phptype type );
98
98
bool is_valid_sqlsrv_sqltype ( _In_ sqlsrv_sqltype type );
99
- void parse_param_array ( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, zend_ulong index, _Out_ SQLSMALLINT& direction,
100
- _Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
101
- _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits );
102
99
void type_and_encoding ( INTERNAL_FUNCTION_PARAMETERS, _In_ int type );
103
100
void type_and_size_calc ( INTERNAL_FUNCTION_PARAMETERS, _In_ int type );
104
101
void type_and_precision_calc ( INTERNAL_FUNCTION_PARAMETERS, _In_ int type );
105
102
bool verify_and_set_encoding ( _In_ const char * encoding_string, _Inout_ sqlsrv_phptype& phptype_encoding );
103
+ zval* parse_param_array (_Inout_ ss_sqlsrv_stmt* stmt, _Inout_ HashTable* param_ht, zend_ulong index,
104
+ _Out_ SQLSMALLINT& direction, _Out_ SQLSRV_PHPTYPE& php_out_type,
105
+ _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
106
+ _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits);
106
107
107
108
}
108
109
@@ -1194,44 +1195,50 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt )
1194
1195
1195
1196
HashTable* params_ht = Z_ARRVAL_P ( params_z );
1196
1197
1197
- zend_ulong index = -1 ;
1198
- zend_string *key = NULL ;
1199
- zval* param_z = NULL ;
1200
-
1201
- ZEND_HASH_FOREACH_KEY_VAL ( params_ht, index, key, param_z ) {
1202
- zval* value_z = NULL ;
1203
- SQLSMALLINT direction = SQL_PARAM_INPUT;
1204
- SQLSRV_ENCODING encoding = stmt->encoding ();
1205
- if ( stmt->encoding () == SQLSRV_ENCODING_DEFAULT ) {
1206
- encoding = stmt->conn ->encoding ();
1207
- }
1208
- SQLSMALLINT sql_type = SQL_UNKNOWN_TYPE;
1209
- SQLULEN column_size = SQLSRV_UNKNOWN_SIZE;
1210
- SQLSMALLINT decimal_digits = 0 ;
1211
- SQLSRV_PHPTYPE php_out_type = SQLSRV_PHPTYPE_INVALID;
1212
-
1213
- // make sure it's an integer index
1214
- int type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
1215
- CHECK_CUSTOM_ERROR ( type != HASH_KEY_IS_LONG, stmt, SS_SQLSRV_ERROR_PARAM_INVALID_INDEX ) {
1216
- throw ss::SSException ();
1217
- }
1198
+ zend_ulong index = -1 ;
1199
+ zend_string *key = NULL ;
1200
+ zval* param_z = NULL ;
1218
1201
1219
- // if it's a parameter array
1220
- if ( Z_TYPE_P ( param_z ) == IS_ARRAY ) {
1202
+ ZEND_HASH_FOREACH_KEY_VAL ( params_ht, index, key, param_z ) {
1203
+ // make sure it's an integer index
1204
+ int type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
1205
+ CHECK_CUSTOM_ERROR (type != HASH_KEY_IS_LONG, stmt, SS_SQLSRV_ERROR_PARAM_INVALID_INDEX) {
1206
+ throw ss::SSException ();
1207
+ }
1221
1208
1222
- zval* var = NULL ;
1223
- int zr = ( NULL != ( var = zend_hash_index_find ( Z_ARRVAL_P ( param_z ), 0 ))) ? SUCCESS : FAILURE;
1224
- CHECK_CUSTOM_ERROR ( zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ) {
1225
- throw ss::SSException ();
1226
- }
1209
+ zval* value_z = NULL ;
1210
+ SQLSMALLINT direction = SQL_PARAM_INPUT;
1211
+ SQLSRV_ENCODING encoding = stmt->encoding ();
1212
+ if ( stmt->encoding () == SQLSRV_ENCODING_DEFAULT ) {
1213
+ encoding = stmt->conn ->encoding ();
1214
+ }
1215
+ SQLSMALLINT sql_type = SQL_UNKNOWN_TYPE;
1216
+ SQLULEN column_size = SQLSRV_UNKNOWN_SIZE;
1217
+ SQLSMALLINT decimal_digits = 0 ;
1218
+ SQLSRV_PHPTYPE php_out_type = SQLSRV_PHPTYPE_INVALID;
1227
1219
1228
- // parse the parameter array that the user gave
1229
- parse_param_array ( stmt, param_z, index, direction, php_out_type, encoding, sql_type, column_size,
1230
- decimal_digits );
1231
- value_z = var;
1220
+ // if it's a parameter array
1221
+ if (Z_TYPE_P (param_z) == IS_ARRAY) {
1222
+ try {
1223
+ HashTable* param_ht = Z_ARRVAL_P (param_z);
1224
+ // Check the number of elements in the array
1225
+ int num_elems = zend_hash_num_elements (param_ht);
1226
+ if (num_elems > 1 ) {
1227
+ value_z = parse_param_array (stmt, param_ht, index, direction, php_out_type, encoding, sql_type, column_size, decimal_digits);
1228
+ } else {
1229
+ // Simply get the first variable and use the defaults
1230
+ value_z = zend_hash_index_find (param_ht, 0 );
1231
+ if (value_z == NULL ) {
1232
+ THROW_SS_ERROR (stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 );
1233
+ }
1234
+ }
1235
+ } catch (core::CoreException&) {
1236
+ SQLFreeStmt (stmt->handle (), SQL_RESET_PARAMS);
1237
+ throw ;
1238
+ }
1232
1239
}
1233
1240
else {
1234
- CHECK_CUSTOM_ERROR ( !stmt->prepared && stmt->conn ->ce_option .enabled , stmt, SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED ) {
1241
+ CHECK_CUSTOM_ERROR (!stmt->prepared && stmt->conn ->ce_option .enabled , stmt, SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED) {
1235
1242
throw ss::SSException ();
1236
1243
}
1237
1244
value_z = param_z;
@@ -1252,7 +1259,6 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt )
1252
1259
}
1253
1260
1254
1261
// bind the parameter
1255
- SQLSRV_ASSERT ( value_z != NULL , " bind_params: value_z is null." );
1256
1262
core_sqlsrv_bind_param ( stmt, static_cast <SQLUSMALLINT>( index ), direction, value_z, php_out_type, encoding, sql_type, column_size,
1257
1263
decimal_digits );
1258
1264
@@ -1724,6 +1730,7 @@ sqlsrv_phptype determine_sqlsrv_php_type( _In_ ss_sqlsrv_stmt const* stmt, _In_
1724
1730
break ;
1725
1731
default :
1726
1732
sqlsrv_phptype.typeinfo .type = PHPTYPE_INVALID;
1733
+ SQLSRV_ASSERT (false , " An invalid php type was returned with (supposedly) validated sql type and column_size" );
1727
1734
break ;
1728
1735
}
1729
1736
@@ -1905,179 +1912,106 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_typ
1905
1912
1906
1913
}
1907
1914
1908
- void parse_param_array ( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array , zend_ulong index, _Out_ SQLSMALLINT& direction,
1915
+ zval* parse_param_array (_Inout_ ss_sqlsrv_stmt* stmt, _Inout_ HashTable* param_ht , zend_ulong index, _Out_ SQLSMALLINT& direction,
1909
1916
_Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
1910
- _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits )
1917
+ _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits)
1911
1918
{
1912
- zval* var_or_val = NULL ;
1913
- zval* temp = NULL ;
1914
- HashTable* param_ht = Z_ARRVAL_P ( param_array );
1915
- sqlsrv_sqltype sqlsrv_sql_type;
1916
- HashPosition pos;
1917
-
1918
- try {
1919
-
1920
- bool php_type_param_was_null = true ;
1921
- bool sql_type_param_was_null = true ;
1922
-
1923
- php_out_type = SQLSRV_PHPTYPE_INVALID;
1924
- encoding = SQLSRV_ENCODING_INVALID;
1925
-
1926
- // handle the array parameters that contain the value/var, direction, php_type, sql_type
1927
- zend_hash_internal_pointer_reset_ex ( param_ht, &pos );
1928
- if ( zend_hash_has_more_elements_ex ( param_ht, &pos ) == FAILURE ||
1929
- (var_or_val = zend_hash_get_current_data_ex (param_ht, &pos)) == NULL ) {
1930
-
1931
- THROW_SS_ERROR ( stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 );
1932
- }
1933
-
1934
- // if the direction is included, then use what they gave, otherwise INPUT is assumed
1935
- if ( zend_hash_move_forward_ex ( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex ( param_ht, &pos )) != NULL &&
1936
- Z_TYPE_P ( temp ) != IS_NULL ) {
1937
-
1938
- CHECK_CUSTOM_ERROR ( Z_TYPE_P ( temp ) != IS_LONG, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
1939
-
1919
+ zval* var_or_val = zend_hash_index_find (param_ht, 0 );
1920
+ bool php_type_param_is_null = true ;
1921
+ bool sql_type_param_is_null = true ;
1922
+
1923
+ // Assumption: there are more than only the variable, parse the rest of the array
1924
+ zval* dir = zend_hash_index_find (param_ht, 1 );
1925
+ if (Z_TYPE_P (dir) != IS_NULL) {
1926
+ // if param direction is specified, make sure it's valid
1927
+ CHECK_CUSTOM_ERROR (Z_TYPE_P (dir) != IS_LONG, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
1940
1928
throw ss::SSException ();
1941
1929
}
1942
- direction = static_cast <SQLSMALLINT>( Z_LVAL_P ( temp ));
1943
- CHECK_CUSTOM_ERROR ( direction != SQL_PARAM_INPUT && direction != SQL_PARAM_OUTPUT && direction != SQL_PARAM_INPUT_OUTPUT,
1944
- stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
1930
+ direction = static_cast <SQLSMALLINT>(Z_LVAL_P (dir));
1931
+
1932
+ CHECK_CUSTOM_ERROR (direction != SQL_PARAM_INPUT && direction != SQL_PARAM_OUTPUT && direction != SQL_PARAM_INPUT_OUTPUT,
1933
+ stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
1945
1934
throw ss::SSException ();
1946
1935
}
1947
-
1948
- CHECK_CUSTOM_ERROR ( !Z_ISREF_P ( var_or_val ) && ( direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT ), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1 ) {
1936
+ CHECK_CUSTOM_ERROR (direction != SQL_PARAM_INPUT && !Z_ISREF_P (var_or_val), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1 ) {
1949
1937
throw ss::SSException ();
1950
1938
}
1951
-
1952
- }
1953
- else {
1954
- direction = SQL_PARAM_INPUT;
1955
1939
}
1956
1940
1957
- // extract the php type and encoding from the 3rd parameter
1958
- if ( zend_hash_move_forward_ex ( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex ( param_ht, &pos )) != NULL &&
1959
- Z_TYPE_P ( temp ) != IS_NULL ) {
1960
-
1961
- php_type_param_was_null = false ;
1962
- sqlsrv_phptype sqlsrv_phptype;
1941
+ // Check if the user provides php type or sql type or both
1942
+ zval* phptype_z = zend_hash_index_find (param_ht, 2 );
1943
+ zval* sqltype_z = zend_hash_index_find (param_ht, 3 );
1963
1944
1964
- CHECK_CUSTOM_ERROR ( Z_TYPE_P ( temp ) != IS_LONG, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, index + 1 ) {
1945
+ php_type_param_is_null = (phptype_z == NULL || Z_TYPE_P (phptype_z) == IS_NULL);
1946
+ sql_type_param_is_null = (sqltype_z == NULL || Z_TYPE_P (sqltype_z) == IS_NULL);
1965
1947
1948
+ if (php_type_param_is_null) {
1949
+ // so set default for php type based on the variable
1950
+ if (Z_ISREF_P (var_or_val)) {
1951
+ php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P (Z_REFVAL_P (var_or_val))];
1952
+ } else {
1953
+ php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P (var_or_val)];
1954
+ }
1955
+ } else {
1956
+ CHECK_CUSTOM_ERROR (Z_TYPE_P (phptype_z) != IS_LONG, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, index + 1 ) {
1966
1957
throw ss::SSException ();
1967
1958
}
1968
1959
1969
- sqlsrv_phptype.value = Z_LVAL_P ( temp );
1970
-
1971
- CHECK_CUSTOM_ERROR ( !is_valid_sqlsrv_phptype ( sqlsrv_phptype ), stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE,
1972
- index + 1 ) {
1973
-
1960
+ sqlsrv_phptype srv_phptype;
1961
+ srv_phptype.value = Z_LVAL_P (phptype_z);
1962
+ CHECK_CUSTOM_ERROR (!is_valid_sqlsrv_phptype (srv_phptype), stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, index + 1 ) {
1974
1963
throw ss::SSException ();
1975
1964
}
1976
1965
1977
- php_out_type = static_cast <SQLSRV_PHPTYPE>( sqlsrv_phptype .typeinfo .type );
1978
- encoding = ( SQLSRV_ENCODING ) sqlsrv_phptype .typeinfo .encoding ;
1966
+ php_out_type = static_cast <SQLSRV_PHPTYPE>(srv_phptype .typeinfo .type );
1967
+ encoding = (SQLSRV_ENCODING)srv_phptype .typeinfo .encoding ;
1979
1968
// if the call has a SQLSRV_PHPTYPE_STRING/STREAM('default'), then the stream is in the encoding established
1980
1969
// by the connection
1981
- if ( encoding == SQLSRV_ENCODING_DEFAULT ) {
1970
+ if ( encoding == SQLSRV_ENCODING_DEFAULT) {
1982
1971
encoding = stmt->conn ->encoding ();
1983
1972
}
1984
1973
}
1985
- // set default for php type and encoding if not supplied
1986
- else {
1987
-
1988
- php_type_param_was_null = true ;
1989
1974
1990
- if ( Z_ISREF_P ( var_or_val )){
1991
- php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P ( Z_REFVAL_P ( var_or_val ))];
1992
- }
1993
- else {
1994
- php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P ( var_or_val )];
1995
- }
1996
- encoding = stmt->encoding ();
1997
- if ( encoding == SQLSRV_ENCODING_DEFAULT ) {
1998
- encoding = stmt->conn ->encoding ();
1975
+ if (sql_type_param_is_null) {
1976
+ // the sql type is not specified, which is required for always encrypted for non-prepared statements
1977
+ CHECK_CUSTOM_ERROR (stmt->conn ->ce_option .enabled && !stmt->prepared , stmt, SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED) {
1978
+ throw ss::SSException ();
1999
1979
}
2000
- }
2001
-
2002
- // get the server type, column size/precision and the decimal digits if provided
2003
- if ( zend_hash_move_forward_ex ( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex ( param_ht, &pos )) != NULL &&
2004
- Z_TYPE_P ( temp ) != IS_NULL ) {
2005
-
2006
- sql_type_param_was_null = false ;
2007
-
2008
- CHECK_CUSTOM_ERROR ( Z_TYPE_P ( temp ) != IS_LONG, stmt, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE, index + 1 ) {
2009
-
1980
+ } else {
1981
+ CHECK_CUSTOM_ERROR (Z_TYPE_P (sqltype_z) != IS_LONG, stmt, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE, index + 1 ) {
2010
1982
throw ss::SSException ();
2011
1983
}
2012
1984
2013
- sqlsrv_sql_type.value = Z_LVAL_P ( temp );
2014
-
2015
1985
// since the user supplied this type, make sure it's valid
2016
- CHECK_CUSTOM_ERROR ( ! is_valid_sqlsrv_sqltype ( sqlsrv_sql_type ), stmt, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE,
2017
- index + 1 ) {
2018
-
1986
+ sqlsrv_sqltype sqlsrv_sql_type;
1987
+ sqlsrv_sql_type. value = Z_LVAL_P (sqltype_z);
1988
+ CHECK_CUSTOM_ERROR (! is_valid_sqlsrv_sqltype (sqlsrv_sql_type), stmt, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE, index + 1 ) {
2019
1989
throw ss::SSException ();
2020
1990
}
2021
1991
2022
- bool size_okay = determine_column_size_or_precision ( stmt, sqlsrv_sql_type, &column_size, &decimal_digits );
2023
-
2024
- CHECK_CUSTOM_ERROR ( !size_okay, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION, index + 1 ) {
2025
-
1992
+ bool size_okay = determine_column_size_or_precision (stmt, sqlsrv_sql_type, &column_size, &decimal_digits);
1993
+ CHECK_CUSTOM_ERROR (!size_okay, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION, index + 1 ) {
2026
1994
throw ss::SSException ();
2027
1995
}
2028
1996
2029
1997
sql_type = sqlsrv_sql_type.typeinfo .type ;
2030
- }
2031
- // else the sql type and size are unknown, so tell the core layer to use its defaults
2032
- else {
2033
- CHECK_CUSTOM_ERROR ( !stmt->prepared && stmt->conn ->ce_option .enabled , stmt, SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED ) {
2034
- throw ss::SSException ();
2035
- }
2036
- sql_type_param_was_null = true ;
2037
-
2038
- sql_type = SQL_UNKNOWN_TYPE;
2039
- column_size = SQLSRV_UNKNOWN_SIZE;
2040
- decimal_digits = 0 ;
2041
- }
2042
-
2043
- // if the user for some reason provides an inout / output parameter with a null phptype and a specified
2044
- // sql server type, infer the php type from the sql server type.
2045
- if ( direction != SQL_PARAM_INPUT && php_type_param_was_null && !sql_type_param_was_null ) {
2046
-
2047
- sqlsrv_phptype sqlsrv_phptype;
2048
-
2049
- sqlsrv_phptype = determine_sqlsrv_php_type ( stmt, sql_type, (SQLUINTEGER)column_size, true );
2050
1998
2051
- // we DIE here since everything should have been validated already and to return the user an error
2052
- // for our own logic error would be confusing/misleading.
2053
- SQLSRV_ASSERT ( sqlsrv_phptype.typeinfo .type != PHPTYPE_INVALID, " An invalid php type was returned with (supposed) "
2054
- " validated sql type and column_size" );
1999
+ if (direction != SQL_PARAM_INPUT && php_type_param_is_null) {
2000
+ sqlsrv_phptype srv_phptype;
2001
+ srv_phptype = determine_sqlsrv_php_type (stmt, sql_type, (SQLUINTEGER)column_size, true );
2055
2002
2056
- php_out_type = static_cast <SQLSRV_PHPTYPE>( sqlsrv_phptype.typeinfo .type );
2057
- encoding = static_cast <SQLSRV_ENCODING>( sqlsrv_phptype.typeinfo .encoding );
2058
- }
2059
-
2060
- // verify that the parameter is a valid output param type
2061
- if ( direction == SQL_PARAM_OUTPUT ) {
2062
-
2063
- switch ( php_out_type ) {
2064
- case SQLSRV_PHPTYPE_NULL:
2065
- case SQLSRV_PHPTYPE_DATETIME:
2066
- case SQLSRV_PHPTYPE_STREAM:
2067
- THROW_CORE_ERROR ( stmt, SS_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE );
2068
- break ;
2069
- default :
2070
- break ;
2003
+ php_out_type = static_cast <SQLSRV_PHPTYPE>(srv_phptype.typeinfo .type );
2004
+ encoding = static_cast <SQLSRV_ENCODING>(srv_phptype.typeinfo .encoding );
2071
2005
}
2072
-
2073
2006
}
2074
2007
2008
+ if (direction == SQL_PARAM_OUTPUT) {
2009
+ if (php_out_type == SQLSRV_PHPTYPE_NULL || php_out_type == SQLSRV_PHPTYPE_DATETIME || php_out_type == SQLSRV_PHPTYPE_STREAM) {
2010
+ THROW_CORE_ERROR (stmt, SS_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE);
2011
+ }
2075
2012
}
2076
- catch ( core::CoreException& ) {
2077
2013
2078
- SQLFreeStmt ( stmt->handle (), SQL_RESET_PARAMS );
2079
- throw ;
2080
- }
2014
+ return var_or_val;
2081
2015
}
2082
2016
2083
2017
bool is_valid_sqlsrv_phptype ( _In_ sqlsrv_phptype type )
0 commit comments