Skip to content

PDO_DBlib: stringify 'uniqueidentifier' fields #2001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions ext/pdo_dblib/dblib_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
21 changes: 16 additions & 5 deletions ext/pdo_dblib/dblib_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -479,4 +491,3 @@ struct pdo_stmt_methods dblib_stmt_methods = {
pdo_dblib_stmt_next_rowset, /* nextrow */
pdo_dblib_stmt_cursor_closer
};

1 change: 1 addition & 0 deletions ext/pdo_dblib/pdo_dblib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion ext/pdo_dblib/php_pdo_dblib_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ typedef struct {
DBPROCESS *link;

pdo_dblib_err err;
unsigned stringify_uniqueidentifier:1;
} pdo_dblib_db_handle;

typedef struct {
Expand Down Expand Up @@ -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
Expand Down
67 changes: 67 additions & 0 deletions ext/pdo_dblib/tests/stringify_uniqueidentifier.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
--TEST--
PDO_DBLIB: Uniqueidentifier column data type stringifying
--SKIPIF--
<?php
if (!extension_loaded('pdo_dblib')) die('skip not loaded');
require __DIR__ . '/config.inc';
?>
--FILE--
<?php
require __DIR__ . '/config.inc';


$testGUID = '82A88958-672B-4C22-842F-216E2B88E72A';
$testGUIDBinary = base64_decode('WImogitnIkyELyFuK4jnKg==');

$sql = "SELECT CAST('$testGUID' as uniqueidentifier) as [guid]";

//--------------------------------------------------------------------------------
// 1. Get and Set the attribute
//--------------------------------------------------------------------------------
$db->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"