diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index acdc0dd90d61..1ac4acc82504 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1185,6 +1185,35 @@ static PHP_METHOD(PDO, quote) } /* }}} */ +/* {{{ proto string PDO::quoteName(string identifier) + Quotes string for use as a table or column name. */ +static PHP_METHOD(PDO, quoteName) +{ + pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + char *str; + int str_len; + char *qstr; + int qlen; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len)) { + RETURN_FALSE; + } + + PDO_DBH_CLEAR_ERR(); + PDO_CONSTRUCT_CHECK; + if (!dbh->methods->name_quoter) { + pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support name quoting" TSRMLS_CC); + RETURN_FALSE; + } + + if (dbh->methods->name_quoter(dbh, str, str_len, &qstr, &qlen TSRMLS_CC)) { + RETURN_STRINGL(qstr, qlen, 0); + } + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; +} +/* }}} */ + /* {{{ proto int PDO::__wakeup() Prevents use of a PDO instance that has been unserialized */ static PHP_METHOD(PDO, __wakeup) @@ -1257,6 +1286,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1) ZEND_ARG_INFO(0, paramtype) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quotename, 0, 0, 1) + ZEND_ARG_INFO(0, identifier) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0) ZEND_END_ARG_INFO() /* }}} */ @@ -1276,6 +1309,7 @@ const zend_function_entry pdo_dbh_functions[] = { PHP_ME(PDO, errorInfo, arginfo_pdo__void, ZEND_ACC_PUBLIC) PHP_ME(PDO, getAttribute, arginfo_pdo_getattribute, ZEND_ACC_PUBLIC) PHP_ME(PDO, quote, arginfo_pdo_quote, ZEND_ACC_PUBLIC) + PHP_ME(PDO, quoteName, arginfo_pdo_quotename, ZEND_ACC_PUBLIC) PHP_ME(PDO, __wakeup, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) PHP_ME(PDO, __sleep, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) PHP_ME(PDO, getAvailableDrivers, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index b9c46bae7400..81f2f8dbbd61 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -250,6 +250,9 @@ typedef long (*pdo_dbh_do_func)(pdo_dbh_t *dbh, const char *sql, long sql_len TS /* quote a string */ typedef int (*pdo_dbh_quote_func)(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC); +/* quote an identifier */ +typedef int (*pdo_dbh_quote_name_func)(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen); + /* transaction related */ typedef int (*pdo_dbh_txn_func)(pdo_dbh_t *dbh TSRMLS_DC); @@ -311,6 +314,7 @@ struct pdo_dbh_methods { pdo_dbh_get_driver_methods_func get_driver_methods; pdo_dbh_request_shutdown persistent_shutdown; pdo_dbh_txn_func in_transaction; + pdo_dbh_quote_name_func name_quoter; }; /* }}} */ diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 77832f952047..a8daf1b151ae 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -166,6 +166,26 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquote return 1; } +/* {{{ dblib_handle_name_quoter */ +static int dblib_handle_name_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen TSRMLS_DC) +{ + int i; + int j = 0; + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)[j++] = '['; + for (i = 0; i < unquotedlen; i++) { + (*quoted)[j++] = unquoted[i]; + if (unquoted[i] == ']') { + (*quoted)[j++] = ']'; + } + } + (*quoted)[j++] = ']'; + (*quoted)[j] = '\0'; + *quotedlen = j; + return 1; +} +/* }}} */ + static int pdo_dblib_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC) { pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; @@ -256,7 +276,8 @@ static struct pdo_dbh_methods dblib_methods = { NULL, /* check liveness */ NULL, /* get driver methods */ NULL, /* request shutdown */ - NULL /* in transaction */ + NULL, /* in_transaction */ + dblib_handle_name_quoter, }; static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index e39555fb97ef..2e6097a0f6bc 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -313,6 +313,26 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unqu } /* }}} */ +/* {{{ firebird_handle_name_quoter */ +static int firebird_handle_name_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen TSRMLS_DC) +{ + int i; + int j = 0; + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)[j++] = '"'; + for (i = 0; i < unquotedlen; i++) { + (*quoted)[j++] = unquoted[i]; + if (unquoted[i] == '"') { + (*quoted)[j++] = '"'; + } + } + (*quoted)[j++] = '"'; + (*quoted)[j] = '\0'; + *quotedlen = j; + return 1; +} +/* }}} */ + /* called by PDO to start a transaction */ static int firebird_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ { @@ -639,7 +659,11 @@ static struct pdo_dbh_methods firebird_methods = { /* {{{ */ NULL, /* last_id not supported */ pdo_firebird_fetch_error_func, firebird_handle_get_attribute, - NULL /* check_liveness */ + NULL, /* check liveness */ + NULL, /* get driver methods */ + NULL, /* request shutdown */ + NULL, /* in_transaction */ + firebird_handle_name_quoter, }; /* }}} */ diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c index aa7109b51651..746c7cc41c2a 100755 --- a/ext/pdo_mysql/mysql_driver.c +++ b/ext/pdo_mysql/mysql_driver.c @@ -314,10 +314,35 @@ static int mysql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquote } /* }}} */ +/* {{{ mysql_handle_name_quoter */ +static int mysql_handle_name_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen TSRMLS_DC) +{ + pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data; + int i; + int j = 0; + PDO_DBG_ENTER("mysql_handle_name_quoter"); + PDO_DBG_INF_FMT("dbh=%p", dbh); + PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted); + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)[j++] = '`'; + for (i = 0; i < unquotedlen; i++) { + (*quoted)[j++] = unquoted[i]; + if (unquoted[i] == '`') { + (*quoted)[j++] = '`'; + } + } + (*quoted)[j++] = '`'; + (*quoted)[j] = '\0'; + *quotedlen = j; + PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted); + PDO_DBG_RETURN(1); +} +/* }}} */ + /* {{{ mysql_handle_begin */ static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) { - PDO_DBG_ENTER("mysql_handle_quoter"); + PDO_DBG_ENTER("mysql_handle_begin"); PDO_DBG_INF_FMT("dbh=%p", dbh); PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC)); } @@ -522,7 +547,11 @@ static struct pdo_dbh_methods mysql_methods = { pdo_mysql_last_insert_id, pdo_mysql_fetch_error_func, pdo_mysql_get_attribute, - pdo_mysql_check_liveness + pdo_mysql_check_liveness, + NULL, /* get_driver_methods */ + NULL, /* persistent_shutdown */ + NULL, /* in_transaction */ + mysql_handle_name_quoter, }; /* }}} */ diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c index cb920ab14a26..adf12c23d1cc 100755 --- a/ext/pdo_oci/oci_driver.c +++ b/ext/pdo_oci/oci_driver.c @@ -403,6 +403,26 @@ static int oci_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedl } /* }}} */ +/* {{{ oci_handle_name_quoter */ +static int oci_handle_name_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen TSRMLS_DC) +{ + int i; + int j = 0; + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)[j++] = '"'; + for (i = 0; i < unquotedlen; i++) { + (*quoted)[j++] = unquoted[i]; + if (unquoted[i] == '"') { + (*quoted)[j++] = '"'; + } + } + (*quoted)[j++] = '"'; + (*quoted)[j] = '\0'; + *quotedlen = j; + return 1; +} +/* }}} */ + static int oci_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ { /* with Oracle, there is nothing special to be done */ @@ -581,7 +601,10 @@ static struct pdo_dbh_methods oci_methods = { pdo_oci_fetch_error_func, oci_handle_get_attribute, pdo_oci_check_liveness, /* check_liveness */ - NULL /* get_driver_methods */ + NULL, /* get_driver_methods */ + NULL, /* persistent_shutdown */ + NULL, /* in_transaction */ + oci_handle_name_quoter, }; static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index 23ea5e58a256..ece095a9623d 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -342,6 +342,26 @@ static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquote return 1; } +/* {{{ pgsql_handle_name_quoter */ +static int pgsql_handle_name_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen TSRMLS_DC) +{ + int i; + int j = 0; + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)[j++] = '"'; + for (i = 0; i < unquotedlen; i++) { + (*quoted)[j++] = unquoted[i]; + if (unquoted[i] == '"') { + (*quoted)[j++] = '"'; + } + } + (*quoted)[j++] = '"'; + (*quoted)[j] = '\0'; + *quotedlen = j; + return 1; +} +/* }}} */ + static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC) { pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; @@ -1030,8 +1050,9 @@ static struct pdo_dbh_methods pgsql_methods = { pdo_pgsql_get_attribute, pdo_pgsql_check_liveness, /* check_liveness */ pdo_pgsql_get_driver_methods, /* get_driver_methods */ - NULL, + NULL, /* persistent_shutdown */ pgsql_handle_in_transaction, + pgsql_handle_name_quoter, }; static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 480c728d1546..cc98d74a06d0 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -238,6 +238,26 @@ static int sqlite_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquot return 1; } +/* {{{ sqlite_handle_name_quoter */ +static int sqlite_handle_name_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen TSRMLS_DC) +{ + int i; + int j = 0; + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)[j++] = '"'; + for (i = 0; i < unquotedlen; i++) { + (*quoted)[j++] = unquoted[i]; + if (unquoted[i] == '"') { + (*quoted)[j++] = '"'; + } + } + (*quoted)[j++] = '"'; + (*quoted)[j] = '\0'; + *quotedlen = j; + return 1; +} +/* }}} */ + static int sqlite_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; @@ -755,7 +775,9 @@ static struct pdo_dbh_methods sqlite_methods = { pdo_sqlite_get_attribute, NULL, /* check_liveness: not needed */ get_driver_methods, - pdo_sqlite_request_shutdown + pdo_sqlite_request_shutdown, + NULL, /* in_transaction */ + sqlite_handle_name_quoter, }; static char *make_filename_safe(const char *filename TSRMLS_DC) diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_quote_name.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_quote_name.phpt new file mode 100644 index 000000000000..8162a555cf0e --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_quote_name.phpt @@ -0,0 +1,20 @@ +--TEST-- +PDO SQLite quote name +--SKIPIF-- + +--FILE-- +quoteName('id') . "\n"; +echo $pdo->quoteName('order') . "\n"; +echo $pdo->quoteName('') . "\n"; +echo $pdo->quoteName('x"y') . "\n"; +?> +--EXPECT-- +"id" +"order" +"" +"x""y"