diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-12-17 12:05:37 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-12-22 15:56:34 +0100 |
commit | caa710037e663fd78f67533b29611183090068b2 (patch) | |
tree | 7acbcdf527eb148899d6cb90e9f2cb233a3ec2ed | |
parent | 57d69b51373bfb1aa5117022c63c93c612e707f6 (diff) | |
download | php-git-caa710037e663fd78f67533b29611183090068b2.tar.gz |
Rewrite PDO result binding
Instead of requiring the type to be determined in advance by the
describer function and then requiring get_col to return a buffer
of appropriate type, allow get_col to return an arbitrary zval.
See UPGRADING.INTERNALS for a more detailed description of the
change.
This makes the result fetching simpler, more efficient and more
flexible. The general possibility already existed via the special
PDO_PARAM_ZVAL type, but the usage was very inconvenient and/or
inefficient. Now it's possible to easily implement behavior like
"return int if it fits, otherwise string" and to avoid any kind
of complex management of temporary buffers.
This also fixes bug #40913 (our second highest voted bug of all
time, for some reason). PARAM_LOB result bindings will now
consistently return a stream resource, independently of the used
database driver.
I've tried my best to update all PDO drivers for this change, but
some of the changes may be broken, as I cannot test or even build
some of these drivers (in particular PDO dblib and PDO oci).
Fixes are appreciated -- a working CI setup would be even more
appreciated ;)
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | UPGRADING | 4 | ||||
-rw-r--r-- | UPGRADING.INTERNALS | 22 | ||||
-rw-r--r-- | ext/pdo/pdo_stmt.c | 162 | ||||
-rw-r--r-- | ext/pdo/php_pdo_driver.h | 39 | ||||
-rw-r--r-- | ext/pdo/tests/debug_emulated_prepares.phpt | 6 | ||||
-rw-r--r-- | ext/pdo_dblib/dblib_stmt.c | 69 | ||||
-rw-r--r-- | ext/pdo_firebird/firebird_driver.c | 1 | ||||
-rw-r--r-- | ext/pdo_firebird/firebird_statement.c | 166 | ||||
-rw-r--r-- | ext/pdo_firebird/php_pdo_firebird_int.h | 3 | ||||
-rw-r--r-- | ext/pdo_mysql/mysql_statement.c | 42 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_stmt_blobs.phpt | 10 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt | 27 | ||||
-rw-r--r-- | ext/pdo_oci/oci_statement.c | 34 | ||||
-rw-r--r-- | ext/pdo_odbc/odbc_stmt.c | 102 | ||||
-rw-r--r-- | ext/pdo_pgsql/pgsql_statement.c | 160 | ||||
-rw-r--r-- | ext/pdo_pgsql/php_pdo_pgsql_int.h | 2 | ||||
-rw-r--r-- | ext/pdo_pgsql/tests/bug62498.phpt | 36 | ||||
-rw-r--r-- | ext/pdo_pgsql/tests/debug_emulated_prepares.phpt | 6 | ||||
-rw-r--r-- | ext/pdo_sqlite/sqlite_statement.c | 26 | ||||
-rw-r--r-- | ext/pdo_sqlite/tests/bug79664.phpt | 4 | ||||
-rw-r--r-- | ext/pdo_sqlite/tests/debugdumpparams_001.phpt | 6 |
22 files changed, 347 insertions, 584 deletions
@@ -21,6 +21,10 @@ PHP NEWS - OpenSSL: . Bump minimal OpenSSL version to 1.0.2. (Jakub Zelenka) +- PDO: + . Fixed bug #40913 (PDO_MYSQL: PDO::PARAM_LOB does not bind to a stream for + fetching a BLOB). (Nikita) + - PSpell: . Convert resource<pspell> to object \PSpell. (Sara) . Convert resource<pspell config> to object \PSPellConfig. (Sara) @@ -42,6 +42,10 @@ PHP 8.1 UPGRADE NOTES - PDO: . PDO::ATTR_STRINGIFY_FETCHES now also stringifies values of type bool to "0" or "1". Previously booleans were not stringified. + . Calling bindColumn() with PDO::PARAM_LOB (and assuming stringification is + not enabled) will now consistently bind a stream result, as documented. + Previously the result would be either a stream or a string depending on the + used database driver and the time the binding is performed. - PDO MySQL: . Integers and floats in result sets will now be returned using native PHP diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index c1ddd4fad2..0f51f91cc2 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -25,3 +25,25 @@ PHP 8.1 INTERNALS UPGRADE NOTES configuration. If the an algorithm doesn't make use of any additional configuration, the argument is to be marked with ZEND_ATTRIBUTE_UNUSED. + + b. ext/pdo + - The "preparer" callback now accepts a zend_string* instead of + char* + size_t pair the query string. Similarly, the query_string and + active_query_string members of pdo_stmt_t are now zend_string*. + - The way in which drivers provide results has changed: Previously, + the "describer" callback populated the "pdo_type" member in the + pdo_column_data structure, and the "get_col" callback then had to return + pointers to data of appropriate type. + + In PHP 8.1, the "describer" callback no longer determines the pdo_type + (and this member has been removed from pdo_column_data). Instead, the + "get_col" callback accepts a zval pointer that may be populated with a + value of arbitrary type. This gives drivers more flexibility in + determining result types (e.g. based on whether a specific integer fits + the PHP integer type) and avoid awkward juggling of temporary buffers. + + As the "describer" no longer determines pdo_type, the "get_column_meta" + function is now responsible for providing this information for use by + getColumnMeta(). The type provided here does not need to match the type + returned by get_col (in fact no corresponding type might exist, e.g. for + floats). It should be the closest logical equivalent for the column type. diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index e1c51ef29a..18116b80fb 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -486,14 +486,8 @@ PHP_METHOD(PDOStatement, execute) } /* }}} */ -static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override) /* {{{ */ +static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, enum pdo_param_type *type_override) /* {{{ */ { - struct pdo_column_data *col; - char *value = NULL; - size_t value_len = 0; - int caller_frees = 0; - int type, new_type; - if (colno < 0) { zend_value_error("Column index must be greater than or equal to 0"); ZVAL_NULL(dest); @@ -506,126 +500,62 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ return; } - col = &stmt->columns[colno]; - type = PDO_PARAM_TYPE(col->param_type); - new_type = type_override ? (int)PDO_PARAM_TYPE(*type_override) : type; - - value = NULL; - value_len = 0; + ZVAL_NULL(dest); + stmt->methods->get_col(stmt, colno, dest, type_override); - stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees); - - switch (type) { - case PDO_PARAM_ZVAL: - if (value && value_len == sizeof(zval)) { - ZVAL_COPY_VALUE(dest, (zval *)value); - - if (Z_TYPE_P(dest) == IS_STRING && Z_STRLEN_P(dest) == 0 - && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING) { - zval_ptr_dtor_str(dest); - ZVAL_NULL(dest); - } - } else { - ZVAL_NULL(dest); - } + if (Z_TYPE_P(dest) == IS_STRING && Z_STRLEN_P(dest) == 0 + && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING) { + zval_ptr_dtor_str(dest); + ZVAL_NULL(dest); + } - if (Z_TYPE_P(dest) == IS_NULL) { - type = new_type; - } - break; + /* If stringification is requested, override with PDO_PARAM_STR. */ + enum pdo_param_type pdo_param_str = PDO_PARAM_STR; + if (stmt->dbh->stringify) { + type_override = &pdo_param_str; + } - case PDO_PARAM_INT: - if (value && value_len == sizeof(zend_long)) { - ZVAL_LONG(dest, *(zend_long*)value); + if (type_override && Z_TYPE_P(dest) != IS_NULL) { + switch (*type_override) { + case PDO_PARAM_INT: + convert_to_long(dest); break; - } - ZVAL_NULL(dest); - break; - - case PDO_PARAM_BOOL: - if (value && value_len == sizeof(zend_bool)) { - ZVAL_BOOL(dest, *(zend_bool*)value); + case PDO_PARAM_BOOL: + convert_to_boolean(dest); break; - } - ZVAL_NULL(dest); - break; - - case PDO_PARAM_LOB: - if (value == NULL) { - ZVAL_NULL(dest); - } else if (value_len == 0) { - /* Warning, empty strings need to be passed as stream */ - if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) { - zend_string *buf; - buf = php_stream_copy_to_mem((php_stream*)value, PHP_STREAM_COPY_ALL, 0); - if (buf == NULL) { + case PDO_PARAM_STR: + if (Z_TYPE_P(dest) == IS_FALSE) { + /* Return "0" rather than "", because this is what database drivers that + * don't have a dedicated boolean type would return. */ + zval_ptr_dtor_nogc(dest); + ZVAL_INTERNED_STR(dest, ZSTR_CHAR('0')); + } else if (Z_TYPE_P(dest) == IS_RESOURCE) { + /* Convert LOB stream to string */ + php_stream *stream; + php_stream_from_zval_no_verify(stream, dest); + zend_string *str = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0); + zval_ptr_dtor_nogc(dest); + if (str == NULL) { ZVAL_EMPTY_STRING(dest); } else { - ZVAL_STR(dest, buf); + ZVAL_STR(dest, str); } - php_stream_close((php_stream*)value); - } else { - php_stream_to_zval((php_stream*)value, dest); - } - } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) { - /* they gave us a string, but LOBs are represented as streams in PDO */ - zend_string *str = zend_string_init(value, value_len, 0); - php_stream *stream = php_stream_memory_open(TEMP_STREAM_READONLY, str); - if (stream) { - php_stream_to_zval(stream, dest); } else { - ZVAL_NULL(dest); + convert_to_string(dest); } - zend_string_release(str); - } else { - ZVAL_STRINGL(dest, value, value_len); - } - break; - - case PDO_PARAM_STR: - if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) { - ZVAL_STRINGL(dest, value, value_len); - break; - } - default: - ZVAL_NULL(dest); - } - - if (type != new_type) { - switch (new_type) { - case PDO_PARAM_INT: - convert_to_long_ex(dest); - break; - case PDO_PARAM_BOOL: - convert_to_boolean_ex(dest); - break; - case PDO_PARAM_STR: - convert_to_string_ex(dest); break; case PDO_PARAM_NULL: - convert_to_null_ex(dest); + convert_to_null(dest); break; - default: - ; - } - } - - if (caller_frees && value) { - efree(value); - } - - if (stmt->dbh->stringify) { - switch (Z_TYPE_P(dest)) { - case IS_FALSE: - /* Return "0" rather than "", because this is what database drivers that - * don't have a dedicated boolean type would return. */ - zval_ptr_dtor_nogc(dest); - ZVAL_INTERNED_STR(dest, ZSTR_CHAR('0')); + case PDO_PARAM_LOB: + if (Z_TYPE_P(dest) == IS_STRING) { + php_stream *stream = + php_stream_memory_open(TEMP_STREAM_READONLY, Z_STR_P(dest)); + zval_ptr_dtor_str(dest); + php_stream_to_zval(stream, dest); + } break; - case IS_TRUE: - case IS_LONG: - case IS_DOUBLE: - convert_to_string(dest); + default: break; } } @@ -673,7 +603,7 @@ static bool do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, ze zval_ptr_dtor(Z_REFVAL(param->parameter)); /* set new value */ - fetch_value(stmt, Z_REFVAL(param->parameter), param->paramno, (int *)¶m->param_type); + fetch_value(stmt, Z_REFVAL(param->parameter), param->paramno, ¶m->param_type); /* TODO: some smart thing that avoids duplicating the value in the * general loop below. For now, if you're binding output columns, @@ -1761,10 +1691,6 @@ PHP_METHOD(PDOStatement, getColumnMeta) add_assoc_str(return_value, "name", zend_string_copy(col->name)); add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */ add_assoc_long(return_value, "precision", col->precision); - if (col->param_type != PDO_PARAM_ZVAL) { - /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */ - add_assoc_long(return_value, "pdo_type", col->param_type); - } } /* }}} */ diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index da53c1a3b9..ea78eb187d 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -46,32 +46,14 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64); enum pdo_param_type { PDO_PARAM_NULL, - - /* int as in long (the php native int type). - * If you mark a column as an int, PDO expects get_col to return - * a pointer to a long */ + PDO_PARAM_BOOL, PDO_PARAM_INT, - - /* get_col ptr should point to start of the string buffer */ PDO_PARAM_STR, - - /* get_col: when len is 0 ptr should point to a php_stream *, - * otherwise it should behave like a string. Indicate a NULL field - * value by setting the ptr to NULL */ PDO_PARAM_LOB, - /* get_col: will expect the ptr to point to a new PDOStatement object handle, - * but this isn't wired up yet */ + /* get_col: Not supported (yet?) */ PDO_PARAM_STMT, /* hierarchical result set */ - /* get_col ptr should point to a zend_bool */ - PDO_PARAM_BOOL, - - /* get_col ptr should point to a zval* - and the driver is responsible for adding correct type information to get_column_meta() - */ - PDO_PARAM_ZVAL, - /* magic flag to denote a parameter as being input/output */ PDO_PARAM_INPUT_OUTPUT = 0x80000000, @@ -343,13 +325,13 @@ typedef int (*pdo_stmt_fetch_func)(pdo_stmt_t *stmt, * Driver should populate stmt->columns[colno] with appropriate info */ typedef int (*pdo_stmt_describe_col_func)(pdo_stmt_t *stmt, int colno); -/* retrieves pointer and size of the value for a column. - * Note that PDO expects the driver to manage the lifetime of this data; - * it will copy the value into a zval on behalf of the script. - * If the driver sets caller_frees, ptr should point to emalloc'd memory - * and PDO will free it as soon as it is done using it. - */ -typedef int (*pdo_stmt_get_col_data_func)(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees); +/* Retrieves zval value of a column. If type is non-NULL, then this specifies the type which + * the user requested through bindColumn(). The driver does not need to check this argument, + * as PDO will perform any necessary conversions itself. However, it might be used to fetch + * a value more efficiently into the final type, or make the behavior dependent on the requested + * type. */ +typedef int (*pdo_stmt_get_col_data_func)( + pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type); /* hook for bound params */ enum pdo_param_event { @@ -382,8 +364,8 @@ typedef int (*pdo_stmt_get_attr_func)(pdo_stmt_t *stmt, zend_long attr, zval *va * name => the column name * len => the length/size of the column * precision => precision of the column - * pdo_type => an integer, one of the PDO_PARAM_XXX values * + * pdo_type => an integer, one of the PDO_PARAM_XXX values * scale => the floating point scale * table => the table for that column * type => a string representation of the type, mapped to the PHP equivalent type name @@ -541,7 +523,6 @@ struct pdo_column_data { zend_string *name; size_t maxlen; zend_ulong precision; - enum pdo_param_type param_type; }; /* describes a bound parameter */ diff --git a/ext/pdo/tests/debug_emulated_prepares.phpt b/ext/pdo/tests/debug_emulated_prepares.phpt index f347c7e4ea..e981f7db39 100644 --- a/ext/pdo/tests/debug_emulated_prepares.phpt +++ b/ext/pdo/tests/debug_emulated_prepares.phpt @@ -47,17 +47,17 @@ Key: Name: [5] :bool paramno=-1 name=[5] ":bool" is_param=1 -param_type=5 +param_type=1 Key: Name: [4] :int paramno=-1 name=[4] ":int" is_param=1 -param_type=1 +param_type=2 Key: Name: [7] :string paramno=-1 name=[7] ":string" is_param=1 -param_type=2 +param_type=3 Key: Name: [5] :null paramno=-1 name=[5] ":null" diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index 0dca4c79cf..03e69a4ac0 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -251,7 +251,6 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno) } col->maxlen = dbcollen(H->link, colno+1); - col->param_type = PDO_PARAM_ZVAL; return 1; } @@ -304,14 +303,12 @@ static int pdo_dblib_stmt_should_stringify_col(pdo_stmt_t *stmt, int coltype) return 0; } -static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_len, zval **ptr) +static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_len, zval *zv) { DBCHAR *tmp_data; - DBINT tmp_data_len; - zval *zv; /* FIXME: We allocate more than we need here */ - tmp_data_len = 32 + (2 * (data_len)); + DBINT tmp_data_len = 32 + (2 * (data_len)); switch (coltype) { case SQLDATETIME: @@ -326,7 +323,6 @@ static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_le tmp_data = emalloc(tmp_data_len); data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len); - zv = emalloc(sizeof(zval)); if (data_len > 0) { /* to prevent overflows, tmp_data_len is provided as a dest len for dbconvert() * this code previously passed a dest len of -1 @@ -342,12 +338,9 @@ static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_le } efree(tmp_data); - - *ptr = zv; } -static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, - zend_ulong *len, int *caller_frees) +static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *zv, enum pdo_param_type *type) { pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; @@ -357,7 +350,6 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, LPBYTE data; DBCHAR *tmp_data; DBINT data_len, tmp_data_len; - zval *zv = NULL; coltype = dbcoltype(H->link, colno+1); data = dbdata(H->link, colno+1); @@ -365,10 +357,8 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, if (data_len != 0 || data != NULL) { if (pdo_dblib_stmt_should_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) { - pdo_dblib_stmt_stringify_col(coltype, data, data_len, &zv); - } - - if (!zv) { + pdo_dblib_stmt_stringify_col(coltype, data, data_len, zv); + } else { switch (coltype) { case SQLCHAR: case SQLVARCHAR: @@ -382,7 +372,6 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, case SQLVARBINARY: case SQLBINARY: case SQLIMAGE: { - zv = emalloc(sizeof(zval)); ZVAL_STRINGL(zv, (DBCHAR *) data, data_len); break; @@ -407,50 +396,31 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, #endif ); - zv = emalloc(sizeof(zval)); ZVAL_STRINGL(zv, tmp_data, dl); efree(tmp_data); break; } - case SQLFLT4: { - zv = emalloc(sizeof(zval)); + case SQLFLT4: ZVAL_DOUBLE(zv, *(DBFLT4 *) data); - break; - } - case SQLFLT8: { - zv = emalloc(sizeof(zval)); + case SQLFLT8: ZVAL_DOUBLE(zv, *(DBFLT8 *) data); - break; - } - case SQLINT8: { - zv = emalloc(sizeof(zval)); + case SQLINT8: ZVAL_LONG(zv, *(DBBIGINT *) data); - break; - } - case SQLINT4: { - zv = emalloc(sizeof(zval)); + case SQLINT4: ZVAL_LONG(zv, *(DBINT *) data); - break; - } - case SQLINT2: { - zv = emalloc(sizeof(zval)); + case SQLINT2: ZVAL_LONG(zv, *(DBSMALLINT *) data); - break; - } case SQLINT1: - case SQLBIT: { - zv = emalloc(sizeof(zval)); + case SQLBIT: ZVAL_LONG(zv, *(DBTINYINT *) data); - break; - } case SQLDECIMAL: case SQLNUMERIC: case SQLMONEY: @@ -458,10 +428,7 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, case SQLMONEYN: { DBFLT8 float_value; dbconvert(NULL, coltype, data, 8, SQLFLT8, (LPBYTE) &float_value, -1); - - zv = emalloc(sizeof(zval)); ZVAL_DOUBLE(zv, float_value); - break; } @@ -472,12 +439,10 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, tmp_data = safe_emalloc(tmp_data_len, sizeof(char), 1); data_len = dbconvert(NULL, SQLUNIQUE, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len); php_strtoupper(tmp_data, data_len); - zv = emalloc(sizeof(zval)); ZVAL_STRINGL(zv, tmp_data, data_len); efree(tmp_data); } else { /* 16-byte binary representation */ - zv = emalloc(sizeof(zval)); ZVAL_STRINGL(zv, (DBCHAR *) data, 16); } break; @@ -485,7 +450,7 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, default: { if (dbwillconvert(coltype, SQLCHAR)) { - pdo_dblib_stmt_stringify_col(coltype, data, data_len, &zv); + pdo_dblib_stmt_stringify_col(coltype, data, data_len, zv); } break; @@ -494,16 +459,6 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, } } - if (zv != NULL) { - *ptr = (char*)zv; - *len = sizeof(zval); - } else { - *ptr = NULL; - *len = 0; - } - - *caller_frees = 1; - return 1; } diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 171dbef6e0..54aaefed6c 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -532,7 +532,6 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */ S = ecalloc(1, sizeof(*S)-sizeof(XSQLDA) + XSQLDA_LENGTH(num_sqlda.sqld)); S->H = H; S->stmt = s; - S->fetch_buf = ecalloc(1,sizeof(char*) * num_sqlda.sqld); S->out_sqlda.version = PDO_FB_SQLDA_VERSION; S->out_sqlda.sqln = stmt->column_count = num_sqlda.sqld; S->named_params = np; diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index e80e26a2f8..c0ce2618ac 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -49,7 +49,7 @@ static void free_sqlda(XSQLDA const *sqlda) /* {{{ */ static int firebird_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */ { pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; - int result = 1, i; + int result = 1; /* release the statement */ if (isc_dsql_free_statement(S->H->isc_status, &S->stmt, DSQL_drop)) { @@ -57,14 +57,6 @@ static int firebird_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */ result = 0; } - /* clean up the fetch buffers if they have been used */ - for (i = 0; i < S->out_sqlda.sqld; ++i) { - if (S->fetch_buf[i]) { - efree(S->fetch_buf[i]); - } - } - efree(S->fetch_buf); - zend_hash_destroy(S->named_params); FREE_HASHTABLE(S->named_params); @@ -219,8 +211,18 @@ static int firebird_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */ memmove(cp, var->aliasname, var->aliasname_length); *(cp+var->aliasname_length) = '\0'; + return 1; +} +/* }}} */ + +static int firebird_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) +{ + pdo_firebird_stmt *S = (pdo_firebird_stmt *) stmt->driver_data; + XSQLVAR *var = &S->out_sqlda.sqlvar[colno]; + + enum pdo_param_type param_type; if (var->sqlscale < 0) { - col->param_type = PDO_PARAM_STR; + param_type = PDO_PARAM_STR; } else { switch (var->sqltype & ~1) { case SQL_SHORT: @@ -228,31 +230,25 @@ static int firebird_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */ #if SIZEOF_ZEND_LONG >= 8 case SQL_INT64: #endif - col->param_type = PDO_PARAM_INT; + param_type = PDO_PARAM_INT; break; #ifdef SQL_BOOLEAN case SQL_BOOLEAN: - col->param_type = PDO_PARAM_BOOL; + param_type = PDO_PARAM_BOOL; break; #endif default: - col->param_type = PDO_PARAM_STR; + param_type = PDO_PARAM_STR; break; } } + add_assoc_long(return_value, "pdo_type", param_type); return 1; } -/* }}} */ - -#define FETCH_BUF(buf,type,len,lenvar) ((buf) = (buf) ? (buf) : \ - emalloc((len) ? (len * sizeof(type)) : ((*(unsigned long*)lenvar) = sizeof(type)))) - -#define CHAR_BUF_LEN 24 /* fetch a blob into a fetch buffer */ -static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ */ - zend_ulong *len, ISC_QUAD *blob_id) +static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, zval *result, ISC_QUAD *blob_id) { pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; pdo_firebird_db_handle *H = S->H; @@ -260,7 +256,8 @@ static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ * char const bl_item = isc_info_blob_total_length; char bl_info[20]; unsigned short i; - int result = *len = 0; + int retval = 0; + size_t len = 0; if (isc_open_blob(H->isc_status, &H->db, &H->tr, &blobh, blob_id)) { RECORD_ERROR(stmt); @@ -287,7 +284,7 @@ static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ * item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2); if (item == isc_info_blob_total_length) { - *len = isc_vax_integer(&bl_info[i+2], item_len); + len = isc_vax_integer(&bl_info[i+2], item_len); break; } i += item_len+2; @@ -295,49 +292,47 @@ static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ * /* we've found the blob's length, now fetch! */ - if (*len) { + if (len) { zend_ulong cur_len; unsigned short seg_len; ISC_STATUS stat; + zend_string *str = zend_string_alloc(len, 0); - *ptr = S->fetch_buf[colno] = erealloc(S->fetch_buf[colno], *len+1); - - for (cur_len = stat = 0; (!stat || stat == isc_segment) && cur_len < *len; cur_len += seg_len) { + for (cur_len = stat = 0; (!stat || stat == isc_segment) && cur_len < len; cur_len += seg_len) { - unsigned short chunk_size = (*len-cur_len) > USHRT_MAX ? USHRT_MAX - : (unsigned short)(*len-cur_len); + unsigned short chunk_size = (len - cur_len) > USHRT_MAX ? USHRT_MAX + : (unsigned short)(len - cur_len); - stat = isc_get_segment(H->isc_status, &blobh, &seg_len, chunk_size, &(*ptr)[cur_len]); + stat = isc_get_segment(H->isc_status, &blobh, &seg_len, chunk_size, ZSTR_VAL(str) + cur_len); } - (*ptr)[*len++] = '\0'; + ZSTR_VAL(str)[len] = '\0'; + ZVAL_STR(result, str); if (H->isc_status[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) { H->last_app_error = "Error reading from BLOB"; goto fetch_blob_end; } } - result = 1; + retval = 1; fetch_blob_end: if (isc_close_blob(H->isc_status, &blobh)) { RECORD_ERROR(stmt); return 0; } - return result; + return retval; } /* }}} */ -static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ */ - zend_ulong *len, int *caller_frees) +static int firebird_stmt_get_col( + pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) { pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; XSQLVAR const *var = &S->out_sqlda.sqlvar[colno]; if (*var->sqlind == -1) { - /* A NULL value */ - *ptr = NULL; - *len = 0; + ZVAL_NULL(result); } else { if (var->sqlscale < 0) { static ISC_INT64 const scales[] = { 1, 10, 100, 1000, @@ -358,6 +353,7 @@ static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, /* {{ LL_LIT(1000000000000000000) }; ISC_INT64 n, f = scales[-var->sqlscale]; + zend_string *str; switch (var->sqltype & ~1) { case SQL_SHORT: @@ -372,65 +368,53 @@ static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, /* {{ EMPTY_SWITCH_DEFAULT_CASE() } - *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL); - if ((var->sqltype & ~1) == SQL_DOUBLE) { - *len = slprintf(*ptr, CHAR_BUF_LEN, "%.*F", -var->sqlscale, *(double*)var->sqldata); + str = zend_strpprintf(0, "%.*F", -var->sqlscale, *(double*)var->sqldata); } else if (n >= 0) { - *len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d.%0*" LL_MASK "d", + str = zend_strpprintf(0, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -var->sqlscale, n % f); } else if (n <= -f) { - *len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d.%0*" LL_MASK "d", + str = zend_strpprintf(0, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -var->sqlscale, -n % f); } else { - *len = slprintf(*ptr, CHAR_BUF_LEN, "-0.%0*" LL_MASK "d", -var->sqlscale, -n % f); + str = zend_strpprintf(0, "-0.%0*" LL_MASK "d", -var->sqlscale, -n % f); } + ZVAL_STR(result, str); } else { switch (var->sqltype & ~1) { struct tm t; char *fmt; case SQL_VARYING: - *ptr = &var->sqldata[2]; - *len = *(short*)var->sqldata; + ZVAL_STRINGL_FAST(result, &var->sqldata[2], *(short*)var->sqldata); break; case SQL_TEXT: - *ptr = var->sqldata; - *len = var->sqllen; + ZVAL_STRINGL_FAST(result, var->sqldata, var->sqllen); break; case SQL_SHORT: - *len = sizeof(zend_long); - *ptr = FETCH_BUF(S->fetch_buf[colno], zend_long, 1, NULL); - *(zend_long *)*ptr = *(short*)var->sqldata; + ZVAL_LONG(result, *(short*)var->sqldata); break; case SQL_LONG: - *len = sizeof(zend_long); - *ptr = FETCH_BUF(S->fetch_buf[colno], zend_long, 1, NULL); - *(zend_long *)*ptr = *(ISC_LONG*)var->sqldata; + ZVAL_LONG(result, *(ISC_LONG*)var->sqldata); break; case SQL_INT64: #if SIZEOF_ZEND_LONG >= 8 - *len = sizeof(zend_long); - *ptr = FETCH_BUF(S->fetch_buf[colno], zend_long, 1, NULL); - *(zend_long *)*ptr = *(ISC_INT64*)var->sqldata; + ZVAL_LONG(result, *(ISC_INT64*)var->sqldata); #else - *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL); - *len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d", *(ISC_INT64*)var->sqldata); + ZVAL_STR(result, zend_strpprintf(0, "%" LL_MASK "d", *(ISC_INT64*)var->sqldata)); #endif break; case SQL_FLOAT: - *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL); - *len = slprintf(*ptr, CHAR_BUF_LEN, "%F", *(float*)var->sqldata); + /* TODO: Why is this not returned as the native type? */ + ZVAL_STR(result, zend_strpprintf(0, "%F", *(float*)var->sqldata)); break; case SQL_DOUBLE: - *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL); - *len = slprintf(*ptr, CHAR_BUF_LEN, "%F" , *(double*)var->sqldata); + /* TODO: Why is this not returned as the native type? */ + ZVAL_STR(result, zend_strpprintf(0, "%F", *(double*)var->sqldata)); break; #ifdef SQL_BOOLEAN case SQL_BOOLEAN: - *len = sizeof(zend_bool); - *ptr = FETCH_BUF(S->fetch_buf[colno], zend_bool, 1, NULL); - *(zend_bool*)*ptr = *(FB_BOOLEAN*)var->sqldata; + ZVAL_BOOL(result, *(FB_BOOLEAN*)var->sqldata); break; #endif case SQL_TYPE_DATE: @@ -446,19 +430,17 @@ static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, /* {{ fmt = S->H->timestamp_format ? S->H->timestamp_format : PDO_FB_DEF_TIMESTAMP_FMT; } /* convert the timestamp into a string */ - *len = 80; - *ptr = FETCH_BUF(S->fetch_buf[colno], char, *len, NULL); - *len = strftime(*ptr, *len, fmt, &t); + char buf[80]; + size_t len = strftime(buf, sizeof(buf), fmt, &t); + ZVAL_STRINGL(result, buf, len); break; case SQL_BLOB: - return firebird_fetch_blob(stmt,colno,ptr,len, - (ISC_QUAD*)var->sqldata); + return firebird_fetch_blob(stmt, colno, result, (ISC_QUAD*)var->sqldata); } } } return 1; } -/* }}} */ static int firebird_bind_blob(pdo_stmt_t *stmt, ISC_QUAD *blob_id, zval *param) { @@ -550,9 +532,6 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat var = &sqlda->sqlvar[param->paramno]; switch (event_type) { - char *value; - zend_ulong value_len; - int caller_frees; zval *parameter; case PDO_PARAM_EVT_ALLOC: @@ -728,9 +707,6 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat if (param->is_param) { break; } - value = NULL; - value_len = 0; - caller_frees = 0; if (Z_ISREF(param->parameter)) { parameter = Z_REFVAL(param->parameter); } else { @@ -738,37 +714,7 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat } zval_ptr_dtor(parameter); ZVAL_NULL(parameter); - - if (firebird_stmt_get_col(stmt, param->paramno, &value, &value_len, &caller_frees)) { - switch (PDO_PARAM_TYPE(param->param_type)) { - case PDO_PARAM_STR: - if (value) { - ZVAL_STRINGL(parameter, value, value_len); - break; - } - case PDO_PARAM_INT: - if (value) { - ZVAL_LONG(parameter, *(zend_long*)value); - break; - } - case PDO_PARAM_EVT_NORMALIZE: - if (!param->is_param) { - char *s = ZSTR_VAL(param->name); - while (*s != '\0') { - *s = toupper(*s); - s++; - } - } - break; - default: - ZVAL_NULL(parameter); - } - if (value && caller_frees) { - efree(value); - } - return 1; - } - return 0; + return firebird_stmt_get_col(stmt, param->paramno, parameter, NULL); default: ; } @@ -843,7 +789,7 @@ const struct pdo_stmt_methods firebird_stmt_methods = { /* {{{ */ firebird_stmt_param_hook, firebird_stmt_set_attribute, firebird_stmt_get_attribute, - NULL, /* get_column_meta_func */ + firebird_stmt_get_column_meta, NULL, /* next_rowset_func */ firebird_stmt_cursor_closer }; diff --git a/ext/pdo_firebird/php_pdo_firebird_int.h b/ext/pdo_firebird/php_pdo_firebird_int.h index 70a895b4b9..f0ba0d08b4 100644 --- a/ext/pdo_firebird/php_pdo_firebird_int.h +++ b/ext/pdo_firebird/php_pdo_firebird_int.h @@ -113,9 +113,6 @@ typedef struct { /* the named params that were converted to ?'s by the driver */ HashTable *named_params; - /* allocated space to convert fields values to other types */ - char **fetch_buf; - /* the input SQLDA */ XSQLDA *in_sqlda; diff --git a/ext/pdo_mysql/mysql_statement.c b/ext/pdo_mysql/mysql_statement.c index f2ba5aa95a..e1f6c6ff95 100644 --- a/ext/pdo_mysql/mysql_statement.c +++ b/ext/pdo_mysql/mysql_statement.c @@ -658,18 +658,13 @@ static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */ cols[i].precision = S->fields[i].decimals; cols[i].maxlen = S->fields[i].length; - -#ifdef PDO_USE_MYSQLND - cols[i].param_type = PDO_PARAM_ZVAL; -#else - cols[i].param_type = PDO_PARAM_STR; -#endif } PDO_DBG_RETURN(1); } /* }}} */ -static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees) /* {{{ */ +static int pdo_mysql_stmt_get_col( + pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) /* {{{ */ { pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data; @@ -685,38 +680,33 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_ } #ifdef PDO_USE_MYSQLND if (S->stmt) { - Z_TRY_ADDREF(S->stmt->data->result_bind[colno].zv); - *ptr = (char*)&S->stmt->data->result_bind[colno].zv; + ZVAL_COPY(result, &S->stmt->data->result_bind[colno].zv); } else { - Z_TRY_ADDREF(S->current_row[colno]); - *ptr = (char*)&S->current_row[colno]; + ZVAL_COPY(result, &S->current_row[colno]); } - *len = sizeof(zval); PDO_DBG_RETURN(1); #else if (S->stmt) { if (S->out_null[colno]) { - *ptr = NULL; - *len = 0; PDO_DBG_RETURN(1); } - *ptr = S->bound_result[colno].buffer; - if (S->out_length[colno] > S->bound_result[colno].buffer_length) { + + size_t length = S->out_length[colno]; + if (length > S->bound_result[colno].buffer_length) { /* mysql lied about the column width */ strcpy(stmt->error_code, "01004"); /* truncated */ - S->out_length[colno] = S->bound_result[colno].buffer_length; - *len = S->out_length[colno]; - PDO_DBG_RETURN(0); + length = S->out_length[colno] = S->bound_result[colno].buffer_length; } - *len = S->out_length[colno]; + ZVAL_STRINGL_FAST(result, S->bound_result[colno].buffer, length); PDO_DBG_RETURN(1); } if (S->current_data == NULL) { PDO_DBG_RETURN(0); } - *ptr = S->current_data[colno]; - *len = S->current_lengths[colno]; + if (S->current_data[colno]) { + ZVAL_STRINGL_FAST(result, S->current_data[colno], S->current_lengths[colno]); + } PDO_DBG_RETURN(1); #endif } /* }}} */ @@ -815,7 +805,7 @@ static int pdo_mysql_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *retu add_assoc_string(return_value, "native_type", str); } -#ifdef PDO_USE_MYSQLND + enum pdo_param_type param_type; switch (F->type) { case MYSQL_TYPE_BIT: case MYSQL_TYPE_YEAR: @@ -826,13 +816,13 @@ static int pdo_mysql_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *retu #if SIZEOF_ZEND_LONG==8 case MYSQL_TYPE_LONGLONG: #endif - add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT); + param_type = PDO_PARAM_INT; break; default: - add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); + param_type = PDO_PARAM_STR; break; } -#endif + add_assoc_long(return_value, "pdo_type", param_type); add_assoc_zval(return_value, "flags", &flags); add_assoc_string(return_value, "table", (char *) (F->table?F->table : "")); diff --git a/ext/pdo_mysql/tests/pdo_mysql_stmt_blobs.phpt b/ext/pdo_mysql/tests/pdo_mysql_stmt_blobs.phpt index 9bdd03d7bd..7f45e56b6b 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_stmt_blobs.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_stmt_blobs.phpt @@ -48,9 +48,15 @@ MySQLPDOTest::skip(); return false; } - if ($label !== $value) { + if (!is_resource($label)) { + printf("[%03d + 3] Returned value is not a stream resource\n", $offset); + return false; + } + + $contents = stream_get_contents($label); + if ($contents !== $value) { printf("[%03d + 3] Returned value seems to be wrong (%d vs. %d characters). Check manually\n", - $offset, strlen($label), strlen($value)); + $offset, strlen($contents), strlen($value)); return false; } diff --git a/ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt b/ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt index b5b0275f04..0e87b118ee 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt @@ -139,23 +139,22 @@ try { $real_as_float = (false === stristr($row['_mode'], "REAL_AS_FLOAT")) ? false : true; $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); - $is_mysqlnd = MySQLPDOTest::isPDOMySQLnd(); - test_meta($db, 20, 'BIT(8)', 1, 'BIT', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); - test_meta($db, 30, 'TINYINT', -127, 'TINY', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); - test_meta($db, 40, 'TINYINT UNSIGNED', 255, 'TINY', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); - test_meta($db, 50, 'BOOLEAN', 1, NULL, ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); + test_meta($db, 20, 'BIT(8)', 1, 'BIT', PDO::PARAM_INT); + test_meta($db, 30, 'TINYINT', -127, 'TINY', PDO::PARAM_INT); + test_meta($db, 40, 'TINYINT UNSIGNED', 255, 'TINY', PDO::PARAM_INT); + test_meta($db, 50, 'BOOLEAN', 1, NULL, PDO::PARAM_INT); - test_meta($db, 60, 'SMALLINT', -32768, 'SHORT', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); - test_meta($db, 70, 'SMALLINT UNSIGNED', 65535, 'SHORT', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); + test_meta($db, 60, 'SMALLINT', -32768, 'SHORT', PDO::PARAM_INT); + test_meta($db, 70, 'SMALLINT UNSIGNED', 65535, 'SHORT', PDO::PARAM_INT); - test_meta($db, 80, 'MEDIUMINT', -8388608, 'INT24', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); - test_meta($db, 90, 'MEDIUMINT UNSIGNED', 16777215, 'INT24', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); + test_meta($db, 80, 'MEDIUMINT', -8388608, 'INT24', PDO::PARAM_INT); + test_meta($db, 90, 'MEDIUMINT UNSIGNED', 16777215, 'INT24', PDO::PARAM_INT); - test_meta($db, 100, 'INT', -2147483648, 'LONG', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); - test_meta($db, 110, 'INT UNSIGNED', 4294967295, 'LONG', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); + test_meta($db, 100, 'INT', -2147483648, 'LONG', PDO::PARAM_INT); + test_meta($db, 110, 'INT UNSIGNED', 4294967295, 'LONG', PDO::PARAM_INT); - test_meta($db, 120, 'BIGINT', '-9223372036854775808', 'LONGLONG', ($is_mysqlnd) ? ((PHP_INT_SIZE == 4) ? PDO::PARAM_STR : PDO::PARAM_INT) : PDO::PARAM_STR); - test_meta($db, 130, 'BIGINT UNSIGNED', '18446744073709551615', 'LONGLONG', ($is_mysqlnd) ? ((PHP_INT_SIZE == 4) ? PDO::PARAM_STR : PDO::PARAM_INT) : PDO::PARAM_STR); + test_meta($db, 120, 'BIGINT', '-9223372036854775808', 'LONGLONG', (PHP_INT_SIZE == 4) ? PDO::PARAM_STR : PDO::PARAM_INT); + test_meta($db, 130, 'BIGINT UNSIGNED', '18446744073709551615', 'LONGLONG', (PHP_INT_SIZE == 4) ? PDO::PARAM_STR : PDO::PARAM_INT); test_meta($db, 130, 'REAL', -1.01, ($real_as_float) ? 'FLOAT' : 'DOUBLE', PDO::PARAM_STR); test_meta($db, 140, 'REAL UNSIGNED', 1.01, ($real_as_float) ? 'FLOAT' : 'DOUBLE', PDO::PARAM_STR); @@ -186,7 +185,7 @@ try { test_meta($db, 340, 'TIME', '14:37:00', 'TIME', PDO::PARAM_STR); test_meta($db, 350, 'TIMESTAMP', '2008-03-23 14:38:00', 'TIMESTAMP', PDO::PARAM_STR); test_meta($db, 360, 'DATETIME', '2008-03-23 14:38:00', 'DATETIME', PDO::PARAM_STR); - test_meta($db, 370, 'YEAR', '2008', 'YEAR', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR); + test_meta($db, 370, 'YEAR', '2008', 'YEAR', PDO::PARAM_INT); test_meta($db, 380, 'CHAR(1)', 'a', 'STRING', PDO::PARAM_STR); test_meta($db, 390, 'CHAR(10)', '0123456789', 'STRING', PDO::PARAM_STR); diff --git a/ext/pdo_oci/oci_statement.c b/ext/pdo_oci/oci_statement.c index 0ab043f041..2a2bd58b90 100644 --- a/ext/pdo_oci/oci_statement.c +++ b/ext/pdo_oci/oci_statement.c @@ -555,12 +555,10 @@ static int oci_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */ } S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */ S->cols[colno].data = emalloc(S->cols[colno].datalen + 1); - col->param_type = PDO_PARAM_STR; break; case SQLT_BLOB: case SQLT_CLOB: - col->param_type = PDO_PARAM_LOB; STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL)); S->cols[colno].datalen = sizeof(OCILobLocator*); dyn = TRUE; @@ -590,9 +588,6 @@ static int oci_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */ S->cols[colno].data = emalloc(S->cols[colno].datalen + 1); dtype = SQLT_CHR; - - /* returning data as a string */ - col->param_type = PDO_PARAM_STR; } STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1, @@ -742,7 +737,7 @@ static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLoca return NULL; } -static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees) /* {{{ */ +static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) /* {{{ */ { pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data; pdo_oci_column *C = &S->cols[colno]; @@ -750,30 +745,27 @@ static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len /* check the indicator to ensure that the data is intact */ if (C->indicator == -1) { /* A NULL value */ - *ptr = NULL; - *len = 0; + ZVAL_NULL(result); return 1; } else if (C->indicator == 0) { /* it was stored perfectly */ if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) { if (C->data) { - *ptr = (char*)oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)C->data); + php_stream *stream = oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)C->data); OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY); + php_stream_to_zval(stream, result); + return 1; } - *len = (size_t) 0; - return *ptr ? 1 : 0; + return 0; } - *ptr = C->data; - *len = (size_t) C->fetched_len; + ZVAL_STRINFL_FAST(result, C->data, C->fetched_len); return 1; } else { /* it was truncated */ php_error_docref(NULL, E_WARNING, "Column %d data was too large for buffer and was truncated to fit it", colno); - - *ptr = C->data; - *len = (size_t) C->fetched_len; + ZVAL_STRINL(result, C->data, C->fetched_len); return 1; } } /* }}} */ @@ -943,6 +935,16 @@ static int oci_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_val add_assoc_string(return_value, "native_type", "NULL"); } + switch (dtype) { + case SQLT_BLOB: + case SQLT_CLOB: + add_assoc_long(return_value, "pdo_type", PDO_PARAM_LOB); + break; + default: + add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); + break; + } + /* column can be null */ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_IS_NULL", (param, OCI_DTYPE_PARAM, &isnull, 0, OCI_ATTR_IS_NULL, S->err)); diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index fdc427d5b0..f71d539271 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -88,31 +88,28 @@ static int pdo_odbc_utf82ucs2(pdo_stmt_t *stmt, int is_unicode, const char *buf, return PDO_ODBC_CONV_NOT_REQUIRED; } -static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, const char *buf, - zend_ulong buflen, zend_ulong *outlen) +static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, zval *result) { #ifdef PHP_WIN32 - if (is_unicode && buflen) { + ZEND_ASSERT(Z_TYPE_P(result) == IS_STRING); + if (is_unicode && Z_STRLEN_P(result) != 0) { pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; DWORD ret; - ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), NULL, 0, NULL, NULL); + ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) Z_STRVAL_P(result), Z_STRLEN_P(result)/sizeof(WCHAR), NULL, 0, NULL, NULL); if (ret == 0) { return PDO_ODBC_CONV_FAIL; } - if (S->convbufsize <= ret) { - S->convbufsize = ret + 1; - S->convbuf = erealloc(S->convbuf, S->convbufsize); - } - - ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), S->convbuf, S->convbufsize, NULL, NULL); + zend_string *str = zend_string_alloc(ret, 0); + ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) Z_STRVAL_P(result), Z_STRLEN_P(result)/sizeof(WCHAR), ZSTR_VAL(str), ZSTR_LEN(str), NULL, NULL); if (ret == 0) { return PDO_ODBC_CONV_FAIL; } - *outlen = ret; - S->convbuf[*outlen] = '\0'; + ZSTR_VAL(str)[ret] = '\0'; + zval_ptr_dtor_str(result); + ZVAL_STR(result, str); return PDO_ODBC_CONV_OK; } #endif @@ -480,38 +477,27 @@ static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *p P = param->driver_data; if (P->outbuf) { - zend_ulong ulen; - char *srcbuf; - zend_ulong srclen = 0; - if (Z_ISREF(param->parameter)) { parameter = Z_REFVAL(param->parameter); } else { parameter = ¶m->parameter; } zval_ptr_dtor(parameter); - ZVAL_NULL(parameter); switch (P->len) { case SQL_NULL_DATA: + ZVAL_NULL(parameter); break; default: - switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) { + ZVAL_STRINGL(parameter, P->outbuf, P->len); + switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, parameter)) { case PDO_ODBC_CONV_FAIL: /* something fishy, but allow it to come back as binary */ case PDO_ODBC_CONV_NOT_REQUIRED: - srcbuf = P->outbuf; - srclen = P->len; break; case PDO_ODBC_CONV_OK: - srcbuf = S->convbuf; - srclen = ulen; break; } - - ZVAL_NEW_STR(parameter, zend_string_alloc(srclen, 0)); - memcpy(Z_STRVAL_P(parameter), srcbuf, srclen); - Z_STRVAL_P(parameter)[Z_STRLEN_P(parameter)] = '\0'; } } return 1; @@ -612,9 +598,6 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno) col->name = zend_string_init(S->cols[colno].colname, colnamelen, 0); S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype); - /* returning data as a string */ - col->param_type = PDO_PARAM_STR; - /* tell ODBC to put it straight into our buffer, but only if it * isn't "long" data, and only if we haven't already bound a long * column. */ @@ -642,16 +625,19 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno) return 1; } -static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong *len, int *caller_frees) +static int odbc_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) +{ + add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); + return 1; +} + +static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) { pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; pdo_odbc_column *C = &S->cols[colno]; - zend_ulong ulen; /* if it is a column containing "long" data, perform late binding now */ if (C->is_long) { - zend_ulong used = 0; - char *buf; RETCODE rc; /* fetch it into C->data, which is allocated with a length @@ -676,11 +662,9 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong this loop has to work whether or not SQLGetData() provides the total column length. calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read for that size would be slower except maybe for extremely long columns.*/ - char *buf2; - - buf2 = emalloc(256); - buf = estrndup(C->data, 256); - used = 255; /* not 256; the driver NUL terminated the buffer */ + char *buf2 = emalloc(256); + zend_string *str = zend_string_init(C->data, 255, 0); + size_t used = 255; /* not 256; the driver NUL terminated the buffer */ do { C->fetched_len = 0; @@ -692,12 +676,12 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size) (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */ - buf = erealloc(buf, used + 255+1); - memcpy(buf + used, buf2, 255); + str = zend_string_realloc(str, used + 255, 0); + memcpy(ZSTR_VAL(str) + used, buf2, 255); used = used + 255; } else if (rc==SQL_SUCCESS) { - buf = erealloc(buf, used + C->fetched_len+1); - memcpy(buf + used, buf2, C->fetched_len); + str = zend_string_realloc(str, used + C->fetched_len, 0); + memcpy(ZSTR_VAL(str) + used, buf2, C->fetched_len); used = used + C->fetched_len; } else { /* includes SQL_NO_DATA */ @@ -709,11 +693,8 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong efree(buf2); /* NULL terminate the buffer once, when finished, for use with the rest of PHP */ - buf[used] = '\0'; - - *ptr = buf; - *caller_frees = 1; - *len = used; + ZSTR_VAL(str)[used] = '\0'; + ZVAL_STR(result, str); if (C->is_unicode) { goto unicode_conv; } @@ -721,8 +702,6 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong } /* something went caca */ - *ptr = NULL; - *len = 0; return 1; } @@ -730,40 +709,29 @@ in_data: /* check the indicator to ensure that the data is intact */ if (C->fetched_len == SQL_NULL_DATA) { /* A NULL value */ - *ptr = NULL; - *len = 0; + ZVAL_NULL(result); return 1; } else if (C->fetched_len >= 0) { /* it was stored perfectly */ - *ptr = C->data; - *len = C->fetched_len; + ZVAL_STRINGL_FAST(result, C->data, C->fetched_len); if (C->is_unicode) { goto unicode_conv; } return 1; } else { /* no data? */ - *ptr = NULL; - *len = 0; + ZVAL_NULL(result); return 1; } - unicode_conv: - switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) { +unicode_conv: + switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, result)) { case PDO_ODBC_CONV_FAIL: /* oh well. They can have the binary version of it */ case PDO_ODBC_CONV_NOT_REQUIRED: /* shouldn't happen... */ return 1; - case PDO_ODBC_CONV_OK: - if (*caller_frees) { - efree(*ptr); - } - *ptr = emalloc(ulen + 1); - *len = ulen; - memcpy(*ptr, S->convbuf, ulen+1); - *caller_frees = 1; return 1; } return 1; @@ -873,8 +841,8 @@ const struct pdo_stmt_methods odbc_stmt_methods = { odbc_stmt_get_col, odbc_stmt_param_hook, odbc_stmt_set_param, - odbc_stmt_get_attr, /* get attr */ - NULL, /* get column meta */ + odbc_stmt_get_attr, + odbc_stmt_get_column_meta, odbc_stmt_next_rowset, odbc_stmt_close_cursor }; diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index bf07af59a5..98ea8cb780 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -467,7 +467,6 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; struct pdo_column_data *cols = stmt->columns; - struct pdo_bound_param_data *param; char *str; if (!S->result) { @@ -480,122 +479,79 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno) cols[colno].precision = PQfmod(S->result, colno); S->cols[colno].pgsql_type = PQftype(S->result, colno); - switch (S->cols[colno].pgsql_type) { - - case BOOLOID: - cols[colno].param_type = PDO_PARAM_BOOL; - break; - - case OIDOID: - /* did the user bind the column as a LOB ? */ - if (stmt->bound_columns && ( - (param = zend_hash_index_find_ptr(stmt->bound_columns, colno)) != NULL || - (param = zend_hash_find_ptr(stmt->bound_columns, cols[colno].name)) != NULL)) { - - if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) { - cols[colno].param_type = PDO_PARAM_LOB; - break; - } - } - cols[colno].param_type = PDO_PARAM_INT; - break; - - case INT2OID: - case INT4OID: - cols[colno].param_type = PDO_PARAM_INT; - break; - - case INT8OID: - if (sizeof(zend_long)>=8) { - cols[colno].param_type = PDO_PARAM_INT; - } else { - cols[colno].param_type = PDO_PARAM_STR; - } - break; - - case BYTEAOID: - cols[colno].param_type = PDO_PARAM_LOB; - break; - - default: - cols[colno].param_type = PDO_PARAM_STR; - } - return 1; } -static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees ) +static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; - struct pdo_column_data *cols = stmt->columns; - size_t tmp_len; - if (!S->result) { return 0; } /* We have already increased count by 1 in pgsql_stmt_fetch() */ if (PQgetisnull(S->result, S->current_row - 1, colno)) { /* Check if we got NULL */ - *ptr = NULL; - *len = 0; + ZVAL_NULL(result); } else { - *ptr = PQgetvalue(S->result, S->current_row - 1, colno); - *len = PQgetlength(S->result, S->current_row - 1, colno); - - switch (cols[colno].param_type) { + char *ptr = PQgetvalue(S->result, S->current_row - 1, colno); + size_t len = PQgetlength(S->result, S->current_row - 1, colno); - case PDO_PARAM_INT: - ZEND_ATOL(S->cols[colno].intval, *ptr); - *ptr = (char *) &(S->cols[colno].intval); - *len = sizeof(zend_long); + switch (S->cols[colno].pgsql_type) { + case BOOLOID: + ZVAL_BOOL(result, *ptr == 't'); break; - case PDO_PARAM_BOOL: - S->cols[colno].boolval = **ptr == 't'; - *ptr = (char *) &(S->cols[colno].boolval); - *len = sizeof(zend_bool); + case INT2OID: + case INT4OID: +#if SIZEOF_ZEND_LONG >= 8 + case INT8OID: +#endif + { + zend_long intval; + ZEND_ATOL(intval, ptr); + ZVAL_LONG(result, intval); break; + } - case PDO_PARAM_LOB: - if (S->cols[colno].pgsql_type == OIDOID) { - /* ooo, a real large object */ - char *end_ptr; - Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10); + case OIDOID: { + char *end_ptr; + Oid oid = (Oid)strtoul(ptr, &end_ptr, 10); + if (type && *type == PDO_PARAM_LOB) { + /* If column was bound as LOB, return a stream. */ int loid = lo_open(S->H->server, oid, INV_READ); if (loid >= 0) { - *ptr = (char*)pdo_pgsql_create_lob_stream(&stmt->database_object_handle, loid, oid); - *len = 0; - return *ptr ? 1 : 0; + php_stream *stream = pdo_pgsql_create_lob_stream(&stmt->database_object_handle, loid, oid); + if (stream) { + php_stream_to_zval(stream, result); + return 1; + } } - *ptr = NULL; - *len = 0; return 0; } else { - char *tmp_ptr = (char *)PQunescapeBytea((unsigned char *)*ptr, &tmp_len); - if (!tmp_ptr) { - /* PQunescapeBytea returned an error */ - *len = 0; - return 0; - } - if (!tmp_len) { - /* Empty string, return as empty stream */ - *ptr = (char *)php_stream_memory_create(TEMP_STREAM_READONLY); - PQfreemem(tmp_ptr); - *len = 0; - } else { - *ptr = estrndup(tmp_ptr, tmp_len); - PQfreemem(tmp_ptr); - *len = tmp_len; - *caller_frees = 1; - } + /* Otherwise return OID as integer. */ + ZVAL_LONG(result, oid); } break; - case PDO_PARAM_NULL: - case PDO_PARAM_STR: - case PDO_PARAM_STMT: - case PDO_PARAM_INPUT_OUTPUT: - case PDO_PARAM_ZVAL: + } + + case BYTEAOID: { + size_t tmp_len; + char *tmp_ptr = (char *)PQunescapeBytea((unsigned char *) ptr, &tmp_len); + if (!tmp_ptr) { + /* PQunescapeBytea returned an error */ + return 0; + } + + zend_string *str = zend_string_init(tmp_ptr, tmp_len, 0); + php_stream *stream = php_stream_memory_open(TEMP_STREAM_READONLY, str); + php_stream_to_zval(stream, result); + zend_string_release(str); + PQfreemem(tmp_ptr); + break; + } + default: + ZVAL_STRINGL_FAST(result, ptr, len); break; } } @@ -698,6 +654,26 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *r } PQclear(res); } + + enum pdo_param_type param_type; + switch (S->cols[colno].pgsql_type) { + case BOOLOID: + param_type = PDO_PARAM_BOOL; + break; + case INT2OID: + case INT4OID: + case INT8OID: + param_type = PDO_PARAM_INT; + break; + case OIDOID: + case BYTEAOID: + param_type = PDO_PARAM_LOB; + break; + default: + param_type = PDO_PARAM_STR; + } + add_assoc_long(return_value, "pdo_type", param_type); + return 1; } diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h index 1f5ea30063..b4bc6318e7 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql_int.h +++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h @@ -48,9 +48,7 @@ typedef struct { } pdo_pgsql_db_handle; typedef struct { - zend_long intval; Oid pgsql_type; - zend_bool boolval; } pdo_pgsql_column; typedef struct { diff --git a/ext/pdo_pgsql/tests/bug62498.phpt b/ext/pdo_pgsql/tests/bug62498.phpt index 1620e7e77a..2970278204 100644 --- a/ext/pdo_pgsql/tests/bug62498.phpt +++ b/ext/pdo_pgsql/tests/bug62498.phpt @@ -56,14 +56,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(4) "int2" + ["pdo_type"]=> + int(2) ["name"]=> string(7) "int2col" ["len"]=> int(2) ["precision"]=> int(-1) - ["pdo_type"]=> - int(1) } [1]=> array(8) { @@ -75,14 +75,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(4) "int4" + ["pdo_type"]=> + int(2) ["name"]=> string(7) "int4col" ["len"]=> int(4) ["precision"]=> int(-1) - ["pdo_type"]=> - int(1) } [2]=> array(8) { @@ -94,14 +94,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(4) "int8" + ["pdo_type"]=> + int(2) ["name"]=> string(7) "int8col" ["len"]=> int(8) ["precision"]=> int(-1) - ["pdo_type"]=> - int(1) } [3]=> array(8) { @@ -113,14 +113,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(7) "varchar" + ["pdo_type"]=> + int(3) ["name"]=> string(9) "stringcol" ["len"]=> int(-1) ["precision"]=> int(259) - ["pdo_type"]=> - int(2) } [4]=> array(8) { @@ -132,14 +132,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(4) "bool" + ["pdo_type"]=> + int(1) ["name"]=> string(7) "boolcol" ["len"]=> int(1) ["precision"]=> int(-1) - ["pdo_type"]=> - int(5) } [5]=> array(8) { @@ -151,14 +151,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(4) "date" + ["pdo_type"]=> + int(3) ["name"]=> string(7) "datecol" ["len"]=> int(4) ["precision"]=> int(-1) - ["pdo_type"]=> - int(2) } [6]=> array(8) { @@ -170,14 +170,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(4) "text" + ["pdo_type"]=> + int(3) ["name"]=> string(7) "textcol" ["len"]=> int(-1) ["precision"]=> int(-1) - ["pdo_type"]=> - int(2) } [7]=> array(8) { @@ -189,14 +189,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(9) "timestamp" + ["pdo_type"]=> + int(3) ["name"]=> string(5) "tscol" ["len"]=> int(8) ["precision"]=> int(-1) - ["pdo_type"]=> - int(2) } [8]=> array(8) { @@ -208,14 +208,14 @@ array(9) { string(13) "bugtest_62498" ["native_type"]=> string(5) "bytea" + ["pdo_type"]=> + int(4) ["name"]=> string(8) "byteacol" ["len"]=> int(-1) ["precision"]=> int(-1) - ["pdo_type"]=> - int(3) } } Done diff --git a/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt b/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt index dfbbcb4ad4..5c8f590351 100644 --- a/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt +++ b/ext/pdo_pgsql/tests/debug_emulated_prepares.phpt @@ -31,17 +31,17 @@ Key: Name: [5] :bool paramno=-1 name=[5] ":bool" is_param=1 -param_type=2 +param_type=3 Key: Name: [4] :int paramno=-1 name=[4] ":int" is_param=1 -param_type=1 +param_type=2 Key: Name: [7] :string paramno=-1 name=[7] ":string" is_param=1 -param_type=2 +param_type=3 Key: Name: [5] :null paramno=-1 name=[5] ":null" diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 3769b1e049..66ec692cf8 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -247,21 +247,11 @@ static int pdo_sqlite_stmt_describe(pdo_stmt_t *stmt, int colno) stmt->columns[colno].maxlen = SIZE_MAX; stmt->columns[colno].precision = 0; - switch (sqlite3_column_type(S->stmt, colno)) { - case SQLITE_INTEGER: - case SQLITE_FLOAT: - case SQLITE3_TEXT: - case SQLITE_BLOB: - case SQLITE_NULL: - default: - stmt->columns[colno].param_type = PDO_PARAM_STR; - break; - } - return 1; } -static int pdo_sqlite_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees) +static int pdo_sqlite_stmt_get_col( + pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) { pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data; if (!S->stmt) { @@ -274,18 +264,17 @@ static int pdo_sqlite_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size } switch (sqlite3_column_type(S->stmt, colno)) { case SQLITE_NULL: - *ptr = NULL; - *len = 0; + ZVAL_NULL(result); return 1; case SQLITE_BLOB: - *ptr = (char*)sqlite3_column_blob(S->stmt, colno); - *len = sqlite3_column_bytes(S->stmt, colno); + ZVAL_STRINGL_FAST(result, + sqlite3_column_blob(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno)); return 1; default: - *ptr = (char*)sqlite3_column_text(S->stmt, colno); - *len = sqlite3_column_bytes(S->stmt, colno); + ZVAL_STRINGL_FAST(result, + (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno)); return 1; } } @@ -341,6 +330,7 @@ static int pdo_sqlite_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *ret #endif add_assoc_zval(return_value, "flags", &flags); + add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); return SUCCESS; } diff --git a/ext/pdo_sqlite/tests/bug79664.phpt b/ext/pdo_sqlite/tests/bug79664.phpt index fae39aea3e..a3648099dc 100644 --- a/ext/pdo_sqlite/tests/bug79664.phpt +++ b/ext/pdo_sqlite/tests/bug79664.phpt @@ -21,12 +21,12 @@ array(6) { ["flags"]=> array(0) { } + ["pdo_type"]=> + int(3) ["name"]=> string(1) "1" ["len"]=> int(-1) ["precision"]=> int(0) - ["pdo_type"]=> - int(2) } diff --git a/ext/pdo_sqlite/tests/debugdumpparams_001.phpt b/ext/pdo_sqlite/tests/debugdumpparams_001.phpt index 4402b5c815..88dc21ce82 100644 --- a/ext/pdo_sqlite/tests/debugdumpparams_001.phpt +++ b/ext/pdo_sqlite/tests/debugdumpparams_001.phpt @@ -23,15 +23,15 @@ Key: Name: [2] :a paramno=-1 name=[2] ":a" is_param=1 -param_type=1 +param_type=2 Key: Name: [2] :b paramno=-1 name=[2] ":b" is_param=1 -param_type=2 +param_type=3 Key: Position #2: paramno=2 name=[0] "" is_param=1 -param_type=2 +param_type=3 NULL |