From a000bff2c3cbfd1d3add3ad22d12824da16479a9 Mon Sep 17 00:00:00 2001 From: Alexander Zhuravlev Date: Mon, 4 Jul 2016 12:47:18 +0300 Subject: [PATCH 1/2] pdo_dblib: stringify uniqidentifier field Keep old 5.6 behavior: return Uniqidentifier value as 36-byte hex string (not binary), when PDO::ATTR_STRINGIFY_FETCHES is TRUE pdo_dblib: Stringify uniqidentifier field Keep old 5.6 behavior: return Uniqidentifier value as 36-byte hex string (not binary), when PDO::ATTR_STRINGIFY_FETCHES is TRUE Tests added. pdo_dblib: Stringify uniqidentifier field Keep old 5.6 behavior: return Uniqidentifier value as 36-byte hex string (not binary), when PDO::ATTR_STRINGIFY_FETCHES is TRUE Tests fix. pdo_dblib: Stringify uniqueidentifier field Added separate PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER attribute instead of PDO::ATTR_STRINGIFY_FETCHES. pdo_dblib: Stringify uniqueidentifier field Added `getAttribute` support for PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER. Simplify storage of stringify_uniqueidentifier attribute --- ext/pdo_dblib/dblib_driver.c | 35 +++++++--- ext/pdo_dblib/dblib_stmt.c | 21 ++++-- ext/pdo_dblib/pdo_dblib.c | 1 + ext/pdo_dblib/php_pdo_dblib_int.h | 4 +- .../tests/stringify_uniqueidentifier.phpt | 67 +++++++++++++++++++ 5 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index d071027e59d..0a55cc4ff74 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -280,16 +280,28 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) switch(attr) { case PDO_ATTR_TIMEOUT: return 0; + + case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: + ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier = zval_get_long(val); + return 1; + default: return 1; } - } static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value) { - /* dblib_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; */ - return 0; + switch (attr) { + case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: + ZVAL_BOOL(return_value, ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier); + break; + + default: + return 0; + } + + return 1; } static struct pdo_dbh_methods dblib_methods = { @@ -347,6 +359,15 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars); + H = pecalloc(1, sizeof(*H), dbh->is_persistent); + H->login = dblogin(); + H->err.sqlstate = dbh->error_code; + H->stringify_uniqueidentifier = 0; + + if (!H->login) { + goto cleanup; + } + if (driver_options) { int connect_timeout = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_CONNECTION_TIMEOUT, -1); int query_timeout = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_QUERY_TIMEOUT, -1); @@ -361,14 +382,8 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) dbsetlogintime(connect_timeout); /* Connection/Login Timeout */ dbsettime(query_timeout); /* Statement Timeout */ - } - H = pecalloc(1, sizeof(*H), dbh->is_persistent); - H->login = dblogin(); - H->err.sqlstate = dbh->error_code; - - if (!H->login) { - goto cleanup; + H->stringify_uniqueidentifier = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, 0); } DBERRHANDLE(H->login, (EHANDLEFUNC) pdo_dblib_error_handler); diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index a1055434d37..8ec4f782fd8 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -120,7 +120,7 @@ static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt) dbcancel(H->link); pdo_dblib_err_dtor(&H->err); - + return 1; } @@ -213,7 +213,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno) pdo_dblib_db_handle *H = S->H; struct pdo_column_data *col; char *fname; - + if(colno >= stmt->column_count || colno < 0) { return FAILURE; } @@ -376,16 +376,28 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, break; } + #ifdef SQLUNIQUE case SQLUNIQUE: { #else case 36: { /* FreeTDS hack */ #endif - zv = emalloc(sizeof(zval)); - ZVAL_STRINGL(zv, data, 16); /* uniqueidentifier is a 16-byte binary number */ + if (H->stringify_uniqueidentifier) { // 36-char hex string representation + tmp_data_len = 36; + tmp_data = safe_emalloc(tmp_data_len, sizeof(char), 1); + data_len = (unsigned int) dbconvert(NULL, SQLUNIQUE, (BYTE*)data, data_len, SQLCHAR, (BYTE*)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 { // a 16-byte binary representation + zv = emalloc(sizeof(zval)); + ZVAL_STRINGL(zv, data, 16); + } break; } + default: { if (dbwillconvert(coltype, SQLCHAR)) { tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */ @@ -479,4 +491,3 @@ struct pdo_stmt_methods dblib_stmt_methods = { pdo_dblib_stmt_next_rowset, /* nextrow */ pdo_dblib_stmt_cursor_closer }; - diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c index 578be2ee10b..b855224c683 100644 --- a/ext/pdo_dblib/pdo_dblib.c +++ b/ext/pdo_dblib/pdo_dblib.c @@ -179,6 +179,7 @@ PHP_MINIT_FUNCTION(pdo_dblib) { REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_CONNECTION_TIMEOUT", (long) PDO_DBLIB_ATTR_CONNECTION_TIMEOUT); REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_QUERY_TIMEOUT", (long) PDO_DBLIB_ATTR_QUERY_TIMEOUT); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER", (long) PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER); if (FAIL == dbinit()) { return FAILURE; diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h index 01586881d55..87a0038ef4c 100644 --- a/ext/pdo_dblib/php_pdo_dblib_int.h +++ b/ext/pdo_dblib/php_pdo_dblib_int.h @@ -113,6 +113,7 @@ typedef struct { DBPROCESS *link; pdo_dblib_err err; + unsigned stringify_uniqueidentifier:1; } pdo_dblib_db_handle; typedef struct { @@ -142,7 +143,8 @@ ZEND_EXTERN_MODULE_GLOBALS(dblib) enum { PDO_DBLIB_ATTR_CONNECTION_TIMEOUT = PDO_ATTR_DRIVER_SPECIFIC, - PDO_DBLIB_ATTR_QUERY_TIMEOUT + PDO_DBLIB_ATTR_QUERY_TIMEOUT, + PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, }; #endif diff --git a/ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt b/ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt new file mode 100644 index 00000000000..79847bf2a19 --- /dev/null +++ b/ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt @@ -0,0 +1,67 @@ +--TEST-- +PDO_DBLIB: Uniqueidentifier column data type stringifying +--SKIPIF-- + +--FILE-- +setAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, true); +var_dump(true === $db->getAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER)); +$db->setAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, false); +var_dump(false === $db->getAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER)); + + +//-------------------------------------------------------------------------------- +// 2. Binary +//-------------------------------------------------------------------------------- +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['guid'] === $testGUIDBinary); + + +//-------------------------------------------------------------------------------- +// 3. PDO::ATTR_STRINGIFY_FETCHES must not affect `uniqueidentifier` representation +//-------------------------------------------------------------------------------- +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); + +var_dump($row['guid'] === $testGUIDBinary); + + +//-------------------------------------------------------------------------------- +// 4. Stringifying +// ! With TDS protocol version <7.0 binary will be returned and the test will fail ! +// TODO: something from PDO::ATTR_SERVER_VERSION, PDO::ATTR_CLIENT_VERSION or PDO::ATTR_SERVER_INFO should be used +// to get TDS version and skip this test in this case. +//-------------------------------------------------------------------------------- +$db->setAttribute(PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, true); +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['guid'] === $testGUID); +var_dump($row['guid']); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +string(36) "82A88958-672B-4C22-842F-216E2B88E72A" From 57509fb969c1cce74dfb9dfec882b92aefd9be69 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 25 Aug 2016 19:43:39 +0200 Subject: [PATCH 2/2] update NEWS --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 630b1c62f8e..d215a2b6ce5 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,10 @@ PHP NEWS . Fixed bug #60665 (call to empty() on NULL result using PDO::FETCH_LAZY returns false). (cmb) +- PDO_DBlib: + . Implemented stringify 'uniqueidentifier' fields. + (Alexander Zhuravlev, Adam Baratz) + - PDO_pgsql: . Implemented FR #72633 (Postgres PDO lastInsertId() should work without specifying a sequence). (Pablo Santiago Sánchez, Matteo)