diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index d071027e59df0..0a55cc4ff74e0 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 a1055434d37d7..8ec4f782fd851 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 578be2ee10b1e..b855224c683c8 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 01586881d55f1..87a0038ef4cfb 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 0000000000000..79847bf2a194a --- /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"