PHP Mysql "Typed" mode Brian Shire & Facebook Inc. Provides mysql_t_* functions that mirror existing functions except that their return values are pre-cast to their corresponding mysql database types. This is useful if you'd like to easily optimize the storage characteristics of serialization for insertion into caches such as APC or Memcache. (This would require a binary serialization rather than the string serialization in native PHP). Values will consume less memory if stored as their integer values rather than as strings for example. WARNING: This could possibly cause problems with new versions of Mysql and/or cause loss of data due to invalid casting, please verify your data for specific applications before use. To use: Apply the patch with the following commands: cd php-5.x.x patch -p1 -i php_mysql_t.patch You can then use the mysql_t_* functions or alternatively, set mysql.typed_mode=1 to change the behavior of existing mysql functions. Provide feedback to diff --git a/ext/mysql/php_mysql.c b/ext/mysql/php_mysql.c index ae7cf04..9823ffe 100644 --- a/ext/mysql/php_mysql.c +++ b/ext/mysql/php_mysql.c @@ -158,9 +158,13 @@ zend_function_entry mysql_functions[] = { PHP_FE(mysql_num_rows, NULL) PHP_FE(mysql_num_fields, NULL) PHP_FE(mysql_fetch_row, NULL) + PHP_FE(mysql_fetch_row_t, NULL) /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ PHP_FE(mysql_fetch_array, NULL) + PHP_FE(mysql_fetch_array_t, NULL) /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ PHP_FE(mysql_fetch_assoc, NULL) + PHP_FE(mysql_fetch_assoc_t, NULL) /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ PHP_FE(mysql_fetch_object, NULL) + PHP_FE(mysql_fetch_object_t, NULL) /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ PHP_FE(mysql_data_seek, NULL) PHP_FE(mysql_fetch_lengths, NULL) PHP_FE(mysql_fetch_field, NULL) @@ -361,6 +365,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("mysql.default_socket", NULL, PHP_INI_ALL, OnUpdateStringUnempty, default_socket, zend_mysql_globals, mysql_globals) STD_PHP_INI_ENTRY("mysql.connect_timeout", "60", PHP_INI_ALL, OnUpdateLong, connect_timeout, zend_mysql_globals, mysql_globals) STD_PHP_INI_BOOLEAN("mysql.trace_mode", "0", PHP_INI_ALL, OnUpdateLong, trace_mode, zend_mysql_globals, mysql_globals) + STD_PHP_INI_BOOLEAN("mysql.typed_mode", "0", PHP_INI_ALL, OnUpdateLong, typed_mode, zend_mysql_globals, mysql_globals) /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ PHP_INI_END() /* }}} */ @@ -377,6 +382,7 @@ static PHP_GINIT_FUNCTION(mysql) mysql_globals->connect_error = NULL; mysql_globals->connect_timeout = 0; mysql_globals->trace_mode = 0; + mysql_globals->typed_mode = 0; /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ mysql_globals->result_allocated = 0; } /* }}} */ @@ -1945,9 +1951,75 @@ PHP_FUNCTION(mysql_num_fields) } /* }}} */ +/**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +static int mysql_makevalue(zval **data, MYSQL_FIELD *mysql_field, char *mysql_value, uint mysql_length TSRMLS_DC) { + + switch(mysql_field->type) { + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_YEAR: + Z_TYPE_PP(data) = IS_LONG; + ZVAL_LONG(*data, strtol(mysql_value, NULL, 10)); + break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: +#if MYSQL_VERSION_ID >= 50000 + case MYSQL_TYPE_NEWDECIMAL: +#endif + Z_TYPE_PP(data) = IS_DOUBLE; + ZVAL_DOUBLE(*data, zend_strtod(mysql_value, NULL)); + break; + + case MYSQL_TYPE_NULL: + Z_TYPE_PP(data) = IS_NULL; + break; + + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_GEOMETRY: +#if MYSQL_VERSION_ID >= 50000 + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_VARCHAR: +#endif + if(PG(magic_quotes_runtime)) { + Z_TYPE_PP(data) = IS_STRING; + Z_STRVAL_PP(data) = php_addslashes(mysql_value, mysql_length, &Z_STRLEN_PP(data), 0 TSRMLS_CC); + } else { + ZVAL_STRINGL(*data, mysql_value, mysql_length, 1); + } + break; + default: + return 0; + } + + return 1; + +} +/**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ + + /* {{{ php_mysql_fetch_hash */ -static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type, int expected_args, int into_object) + +/**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +/* static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type, int expected_args, int into_object, int typed) */ +static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type, int expected_args, int into_object, int typed) +/**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ { zval **result, **arg2; MYSQL_RES *mysql_result; @@ -2026,12 +2098,17 @@ static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type, MAKE_STD_ZVAL(data); - if (PG(magic_quotes_runtime)) { - Z_TYPE_P(data) = IS_STRING; - Z_STRVAL_P(data) = php_addslashes(mysql_row[i], mysql_row_lengths[i], &Z_STRLEN_P(data), 0 TSRMLS_CC); - } else { - ZVAL_STRINGL(data, mysql_row[i], mysql_row_lengths[i], 1); + /**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ + /* If typed flag is set (ie: mysql_*_t function) then return values as the correct PHP type */ + if(!typed || typed && !mysql_makevalue(&data, mysql_field, mysql_row[i], mysql_row_lengths[i] TSRMLS_CC)) { + if (PG(magic_quotes_runtime)) { + Z_TYPE_P(data) = IS_STRING; + Z_STRVAL_P(data) = php_addslashes(mysql_row[i], mysql_row_lengths[i], &Z_STRLEN_P(data), 0 TSRMLS_CC); + } else { + ZVAL_STRINGL(data, mysql_row[i], mysql_row_lengths[i], 1); + } } + /**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ if (result_type & MYSQL_NUM) { add_index_zval(return_value, i, data); @@ -2127,41 +2204,85 @@ static void php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type, Gets a result row as an enumerated array */ PHP_FUNCTION(mysql_fetch_row) { - php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_NUM, 1, 0); + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_NUM, 1, 0, MySG(typed_mode)); /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ } /* }}} */ +/**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +/* {{{ proto array mysql_fetch_row_t(resource result) + Gets a result row as an enumerated array */ +PHP_FUNCTION(mysql_fetch_row_t) +{ + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_NUM, 1, 0, 1); +} +/* }}} */ +/**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ + /* {{{ proto object mysql_fetch_object(resource result [, string class_name [, NULL|array ctor_params]]) Fetch a result row as an object */ PHP_FUNCTION(mysql_fetch_object) { - php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_ASSOC, 2, 1); + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_ASSOC, 2, 1, MySG(typed_mode)); /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ + + if (Z_TYPE_P(return_value) == IS_ARRAY) { + object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value)); + } +} +/* }}} */ + +/**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +/* {{{ proto object mysql_fetch_object_t(resource result [, string class_name [, NULL|array ctor_params]]) + Fetch a result row as an object */ +PHP_FUNCTION(mysql_fetch_object_t) +{ + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_ASSOC, 2, 1, 1); if (Z_TYPE_P(return_value) == IS_ARRAY) { object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value)); } } /* }}} */ +/**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ /* {{{ proto array mysql_fetch_array(resource result [, int result_type]) Fetch a result row as an array (associative, numeric or both) */ PHP_FUNCTION(mysql_fetch_array) { - php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 2, 0); + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 2, 0, MySG(typed_mode)); /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +} +/* }}} */ + +/**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +/* {{{ proto array mysql_fetch_array_t(resource result [, int result_type]) + Fetch a result row as an array (associative, numeric or both) */ +PHP_FUNCTION(mysql_fetch_array_t) +{ + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 2, 0, 1); } /* }}} */ +/**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ /* {{{ proto array mysql_fetch_assoc(resource result) Fetch a result row as an associative array */ PHP_FUNCTION(mysql_fetch_assoc) { - php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_ASSOC, 1, 0); + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_ASSOC, 1, 0, MySG(typed_mode)); /**** PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ } /* }}} */ +/**** BEGIN PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ +/* {{{ proto array mysql_fetch_assoc_t(resource result) + Fetch a result row as an associative array */ +PHP_FUNCTION(mysql_fetch_assoc_t) +{ + php_mysql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_ASSOC, 1, 0, 1); +} +/**** END PATCH: "php_mysql_t", (c)2007 Brian Shire & Facebook Inc, Licensed under MIT License ***/ + +/* }}} */ /* {{{ proto bool mysql_data_seek(resource result, int row_number) Move internal result pointer */ PHP_FUNCTION(mysql_data_seek)