diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index f4420dcbdd4ec..7ed6760e17c93 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -46,7 +46,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64); # define FALSE 0 #endif -#define PDO_DRIVER_API 20150127 +#define PDO_DRIVER_API 20161017 enum pdo_param_type { PDO_PARAM_NULL, @@ -76,6 +76,11 @@ enum pdo_param_type { */ PDO_PARAM_ZVAL, + /* this defines the start of the range for driver specific params. + * Drivers should define their own param constants beginning with this + * value. */ + PDO_PARAM_DRIVER_SPECIFIC = 1000, + /* magic flag to denote a parameter as being input/output */ PDO_PARAM_INPUT_OUTPUT = 0x80000000 }; diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 70d1a1cf601f3..1fddd26e74e9a 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -151,30 +151,67 @@ static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_l static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype) { + pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; + const char *hex = "0123456789abcdef"; + zend_bool is_unicode = 0; size_t i; char * q; *quotedlen = 0; - /* Detect quoted length, adding extra char for doubled single quotes */ - for(i=0;i> 4) & 0xF]; + *q++ = hex[(*unquoted++) & 0xF]; + } + + break; + + default: + if (H->unicode_strings) { + is_unicode = 1; + } + if ((paramtype & PDO_DBLIB_PARAM_STR_UNICODE) == PDO_DBLIB_PARAM_STR_UNICODE) { + is_unicode = 1; + } + if ((paramtype & PDO_DBLIB_PARAM_STR_ASCII) == PDO_DBLIB_PARAM_STR_ASCII) { + is_unicode = 0; + } - *quotedlen += 2; /* +2 for opening, closing quotes */ - q = *quoted = emalloc(*quotedlen+1); /* Add byte for terminal null */ - *q++ = '\''; + /* Detect quoted length, adding extra char for doubled single quotes */ + for (i = 0; i < unquotedlen; i++) { + if (unquoted[i] == '\'') ++*quotedlen; + ++*quotedlen; + } - for (i=0;idriver_data; + switch(attr) { case PDO_ATTR_TIMEOUT: case PDO_DBLIB_ATTR_QUERY_TIMEOUT: return SUCCEED == dbsettime(zval_get_long(val)) ? 1 : 0; case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: - ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier = zval_get_long(val); + H->stringify_uniqueidentifier = zval_get_long(val); + return 1; + case PDO_DBLIB_ATTR_UNICODE_STRINGS: + H->unicode_strings = zval_get_long(val); return 1; default: return 0; @@ -271,9 +313,15 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value) { + pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; + switch (attr) { case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: - ZVAL_BOOL(return_value, ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier); + ZVAL_BOOL(return_value, H->stringify_uniqueidentifier); + break; + + case PDO_DBLIB_ATTR_UNICODE_STRINGS: + ZVAL_BOOL(return_value, H->unicode_strings); break; default: @@ -348,6 +396,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) H->login = dblogin(); H->err.sqlstate = dbh->error_code; H->stringify_uniqueidentifier = 0; + H->unicode_strings = 0; if (!H->login) { goto cleanup; @@ -369,6 +418,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) dbsettime(query_timeout); /* Statement Timeout */ H->stringify_uniqueidentifier = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, 0); + H->unicode_strings = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_UNICODE_STRINGS, 0); } DBERRHANDLE(H->login, (EHANDLEFUNC) pdo_dblib_error_handler); diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c index d19429ec34b5d..44b9409e4e539 100644 --- a/ext/pdo_dblib/pdo_dblib.c +++ b/ext/pdo_dblib/pdo_dblib.c @@ -194,6 +194,10 @@ 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); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_UNICODE_STRINGS", (long) PDO_DBLIB_ATTR_UNICODE_STRINGS); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_PARAM_BINARY", (long) PDO_DBLIB_PARAM_BINARY); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_PARAM_STR_UNICODE", (long) PDO_DBLIB_PARAM_STR_UNICODE); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_PARAM_STR_ASCII", (long) PDO_DBLIB_PARAM_STR_ASCII); 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 01c538eed7ab7..f06745d55dcdf 100644 --- a/ext/pdo_dblib/php_pdo_dblib_int.h +++ b/ext/pdo_dblib/php_pdo_dblib_int.h @@ -116,6 +116,7 @@ typedef struct { pdo_dblib_err err; unsigned stringify_uniqueidentifier:1; + unsigned unicode_strings:1; } pdo_dblib_db_handle; typedef struct { @@ -147,6 +148,13 @@ enum { PDO_DBLIB_ATTR_CONNECTION_TIMEOUT = PDO_ATTR_DRIVER_SPECIFIC, PDO_DBLIB_ATTR_QUERY_TIMEOUT, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, + PDO_DBLIB_ATTR_UNICODE_STRINGS, +}; + +enum { + PDO_DBLIB_PARAM_BINARY = PDO_PARAM_DRIVER_SPECIFIC, + PDO_DBLIB_PARAM_STR_UNICODE = 0x40000000, + PDO_DBLIB_PARAM_STR_ASCII = 0x20000000, }; #endif diff --git a/ext/pdo_dblib/tests/pdo_dblib_quote.phpt b/ext/pdo_dblib/tests/pdo_dblib_quote.phpt index 543093d6ce6d3..b22e6e987bd21 100644 --- a/ext/pdo_dblib/tests/pdo_dblib_quote.phpt +++ b/ext/pdo_dblib/tests/pdo_dblib_quote.phpt @@ -14,7 +14,16 @@ var_dump($db->quote(42, PDO::PARAM_INT)); var_dump($db->quote(null, PDO::PARAM_NULL)); var_dump($db->quote('\'', PDO::PARAM_STR)); var_dump($db->quote('foo', PDO::PARAM_STR)); +var_dump($db->quote('foo', PDO::PARAM_STR | PDO::DBLIB_PARAM_STR_ASCII)); +var_dump($db->quote('über', PDO::PARAM_STR | PDO::DBLIB_PARAM_STR_UNICODE)); +var_dump($db->quote('foo', PDO::DBLIB_PARAM_BINARY)); +var_dump($db->quote(123, PDO::DBLIB_PARAM_BINARY)); // numbers will be cast to strings rather than converted to hex + +$db->setAttribute(PDO::DBLIB_ATTR_UNICODE_STRINGS, true); +var_dump($db->quote('foo', PDO::PARAM_STR | PDO::DBLIB_PARAM_STR_ASCII)); var_dump($db->quote('über', PDO::PARAM_STR)); +var_dump($db->quote('über', PDO::PARAM_STR | PDO::DBLIB_PARAM_STR_UNICODE)); + ?> --EXPECT-- string(3) "'1'" @@ -23,4 +32,10 @@ string(4) "'42'" string(2) "''" string(4) "''''" string(5) "'foo'" -string(7) "'über'" +string(5) "'foo'" +string(8) "N'über'" +string(8) "0x666f6f" +string(8) "0x313233" +string(5) "'foo'" +string(8) "N'über'" +string(8) "N'über'"