Skip to content

Commit

Permalink
PDO: Store/pass query_string as zend_string
Browse files Browse the repository at this point in the history
Rather than storing char* + size_t, use a zend_string*. Also
avoid various copies of the query string.
  • Loading branch information
nikic committed Dec 14, 2020
1 parent c288b52 commit 2d51c20
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 102 deletions.
31 changes: 12 additions & 19 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,9 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt
zval query_string;
zend_string *key;

ZVAL_STRINGL(&query_string, stmt->query_string, stmt->query_stringlen);
ZVAL_STR(&query_string, stmt->query_string);
key = zend_string_init("queryString", sizeof("queryString") - 1, 0);
zend_std_write_property(Z_OBJ_P(object), key, &query_string, NULL);
zval_ptr_dtor(&query_string);
zend_string_release_ex(key, 0);

if (dbstmt_ce->constructor) {
Expand Down Expand Up @@ -490,22 +489,21 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt
PHP_METHOD(PDO, prepare)
{
pdo_stmt_t *stmt;
char *statement;
size_t statement_len;
zend_string *statement;
zval *options = NULL, *value, *item, ctor_args;
zend_class_entry *dbstmt_ce, *pce;
pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(ZEND_THIS);
pdo_dbh_t *dbh = dbh_obj->inner;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STRING(statement, statement_len)
Z_PARAM_STR(statement)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY(options)
ZEND_PARSE_PARAMETERS_END();

PDO_CONSTRUCT_CHECK;

if (statement_len == 0) {
if (ZSTR_LEN(statement) == 0) {
zend_argument_value_error(1, "cannot be empty");
RETURN_THROWS();
}
Expand Down Expand Up @@ -557,16 +555,15 @@ PHP_METHOD(PDO, prepare)
stmt = Z_PDO_STMT_P(return_value);

/* unconditionally keep this for later reference */
stmt->query_string = estrndup(statement, statement_len);
stmt->query_stringlen = statement_len;
stmt->query_string = zend_string_copy(statement);
stmt->default_fetch_type = dbh->default_fetch_type;
stmt->dbh = dbh;
/* give it a reference to me */
ZVAL_OBJ_COPY(&stmt->database_object_handle, &dbh_obj->std);
/* we haven't created a lazy object yet */
ZVAL_UNDEF(&stmt->lazy_object_ref);

if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options)) {
if (dbh->methods->preparer(dbh, statement, stmt, options)) {
pdo_stmt_construct(execute_data, stmt, return_value, dbstmt_ce, &ctor_args);
return;
}
Expand Down Expand Up @@ -1051,23 +1048,22 @@ PHP_METHOD(PDO, errorInfo)
PHP_METHOD(PDO, query)
{
pdo_stmt_t *stmt;
char *statement;
size_t statement_len;
zend_string *statement;
zend_long fetch_mode;
zend_bool fetch_mode_is_null = 1;
zval *args = NULL;
uint32_t num_args = 0;
pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(ZEND_THIS);
pdo_dbh_t *dbh = dbh_obj->inner;

if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l!*", &statement, &statement_len,
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "S|l!*", &statement,
&fetch_mode, &fetch_mode_is_null, &args, &num_args)) {
RETURN_THROWS();
}

PDO_CONSTRUCT_CHECK;

if (statement_len == 0) {
if (ZSTR_LEN(statement) == 0) {
zend_argument_value_error(1, "cannot be empty");
RETURN_THROWS();
}
Expand All @@ -1080,19 +1076,16 @@ PHP_METHOD(PDO, query)
stmt = Z_PDO_STMT_P(return_value);

/* unconditionally keep this for later reference */
stmt->query_string = estrndup(statement, statement_len);
stmt->query_stringlen = statement_len;

stmt->query_string = zend_string_copy(statement);
stmt->active_query_string = zend_string_copy(stmt->query_string);
stmt->default_fetch_type = dbh->default_fetch_type;
stmt->active_query_string = stmt->query_string;
stmt->active_query_stringlen = statement_len;
stmt->dbh = dbh;
/* give it a reference to me */
ZVAL_OBJ_COPY(&stmt->database_object_handle, &dbh_obj->std);
/* we haven't created a lazy object yet */
ZVAL_UNDEF(&stmt->lazy_object_ref);

if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
if (dbh->methods->preparer(dbh, statement, stmt, NULL)) {
PDO_STMT_CLEAR_ERR();
if (fetch_mode_is_null || pdo_stmt_setup_fetch_mode(stmt, fetch_mode, 2, args, num_args)) {
/* now execute the statement */
Expand Down
29 changes: 13 additions & 16 deletions ext/pdo/pdo_sql_parser.re
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,9 @@ static void free_param_name(zval *el) {
efree(Z_PTR_P(el));
}

PDO_API int pdo_parse_params(pdo_stmt_t *stmt, const char *inquery, size_t inquery_len,
char **outquery, size_t *outquery_len)
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, zend_string *inquery, zend_string **outquery)
{
Scanner s;
const char *ptr;
char *newbuffer;
ptrdiff_t t;
uint32_t bindno = 0;
Expand All @@ -96,9 +94,8 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, const char *inquery, size_t inque
int query_type = PDO_PLACEHOLDER_NONE;
struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;

ptr = *outquery;
s.cur = inquery;
s.end = inquery + inquery_len + 1;
s.cur = ZSTR_VAL(inquery);
s.end = s.cur + ZSTR_LEN(inquery) + 1;

/* phase 1: look for args */
while((t = scan(&s)) != PDO_PARSER_EOI) {
Expand All @@ -110,7 +107,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, const char *inquery, size_t inque

if (t == PDO_PARSER_BIND) {
ptrdiff_t len = s.cur - s.tok;
if ((inquery < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
if ((ZSTR_VAL(inquery) < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
continue;
}
query_type |= PDO_PLACEHOLDER_NAMED;
Expand Down Expand Up @@ -179,7 +176,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, const char *inquery, size_t inque
if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
/* query matches native syntax */
if (escapes) {
newbuffer_len = inquery_len;
newbuffer_len = ZSTR_LEN(inquery);
goto rewrite;
}

Expand All @@ -201,7 +198,7 @@ safe:
if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
/* query generation */

newbuffer_len = inquery_len;
newbuffer_len = ZSTR_LEN(inquery);

/* let's quote all the values */
for (plc = placeholders; plc && params; plc = plc->next) {
Expand Down Expand Up @@ -328,12 +325,12 @@ safe:

rewrite:
/* allocate output buffer */
newbuffer = emalloc(newbuffer_len + 1);
*outquery = newbuffer;
*outquery = zend_string_alloc(newbuffer_len, 0);
newbuffer = ZSTR_VAL(*outquery);

/* and build the query */
const char *ptr = ZSTR_VAL(inquery);
plc = placeholders;
ptr = inquery;

do {
t = plc->pos - ptr;
Expand All @@ -353,13 +350,13 @@ rewrite:
plc = plc->next;
} while (plc);

t = (inquery + inquery_len) - ptr;
t = ZSTR_VAL(inquery) + ZSTR_LEN(inquery) - ptr;
if (t) {
memcpy(newbuffer, ptr, t);
newbuffer += t;
}
*newbuffer = '\0';
*outquery_len = newbuffer - *outquery;
ZSTR_LEN(*outquery) = newbuffer - ZSTR_VAL(*outquery);

ret = 1;
goto clean_up;
Expand All @@ -370,7 +367,7 @@ rewrite:
const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
int bind_no = 1;

newbuffer_len = inquery_len;
newbuffer_len = ZSTR_LEN(inquery);

if (stmt->bound_param_map == NULL) {
ALLOC_HASHTABLE(stmt->bound_param_map);
Expand Down Expand Up @@ -416,7 +413,7 @@ rewrite:
} else {
/* rewrite :name to ? */

newbuffer_len = inquery_len;
newbuffer_len = ZSTR_LEN(inquery);

if (stmt->bound_param_map == NULL) {
ALLOC_HASHTABLE(stmt->bound_param_map);
Expand Down
26 changes: 12 additions & 14 deletions ext/pdo/pdo_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,18 +443,16 @@ PHP_METHOD(PDOStatement, execute)
*/

/* string is leftover from previous calls so PDOStatement::debugDumpParams() can access */
if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
efree(stmt->active_query_string);
if (stmt->active_query_string) {
zend_string_release(stmt->active_query_string);
stmt->active_query_string = NULL;
}
stmt->active_query_string = NULL;

ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
&stmt->active_query_string, &stmt->active_query_stringlen);
ret = pdo_parse_params(stmt, stmt->query_string, &stmt->active_query_string);

if (ret == 0) {
/* no changes were made */
stmt->active_query_string = stmt->query_string;
stmt->active_query_stringlen = stmt->query_stringlen;
stmt->active_query_string = zend_string_copy(stmt->query_string);
ret = 1;
} else if (ret == -1) {
/* something broke */
Expand Down Expand Up @@ -2035,16 +2033,16 @@ PHP_METHOD(PDOStatement, debugDumpParams)
}

/* break into multiple operations so query string won't be truncated at FORMAT_CONV_MAX_PRECISION */
php_stream_printf(out, "SQL: [%zd] ", stmt->query_stringlen);
php_stream_write(out, stmt->query_string, stmt->query_stringlen);
php_stream_printf(out, "SQL: [%zd] ", ZSTR_LEN(stmt->query_string));
php_stream_write(out, ZSTR_VAL(stmt->query_string), ZSTR_LEN(stmt->query_string));
php_stream_write(out, "\n", 1);

/* show parsed SQL if emulated prepares enabled */
/* pointers will be equal if PDO::query() was invoked */
if (stmt->active_query_string != NULL && stmt->active_query_string != stmt->query_string) {
/* break into multiple operations so query string won't be truncated at FORMAT_CONV_MAX_PRECISION */
php_stream_printf(out, "Sent SQL: [%zd] ", stmt->active_query_stringlen);
php_stream_write(out, stmt->active_query_string, stmt->active_query_stringlen);
php_stream_printf(out, "Sent SQL: [%zd] ", ZSTR_LEN(stmt->active_query_string));
php_stream_write(out, ZSTR_VAL(stmt->active_query_string), ZSTR_LEN(stmt->active_query_string));
php_stream_write(out, "\n", 1);
}

Expand Down Expand Up @@ -2175,11 +2173,11 @@ PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
if (stmt->methods && stmt->methods->dtor) {
stmt->methods->dtor(stmt);
}
if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
efree(stmt->active_query_string);
if (stmt->active_query_string) {
zend_string_release(stmt->active_query_string);
}
if (stmt->query_string) {
efree(stmt->query_string);
zend_string_release(stmt->query_string);
}

pdo_stmt_reset_columns(stmt);
Expand Down
11 changes: 4 additions & 7 deletions ext/pdo/php_pdo_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ typedef struct {
typedef int (*pdo_dbh_close_func)(pdo_dbh_t *dbh);

/* prepare a statement and stash driver specific portion into stmt */
typedef int (*pdo_dbh_prepare_func)(pdo_dbh_t *dbh, const char *sql, size_t sql_len, pdo_stmt_t *stmt, zval *driver_options);
typedef int (*pdo_dbh_prepare_func)(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options);

/* execute a statement (that does not return a result set) */
typedef zend_long (*pdo_dbh_do_func)(pdo_dbh_t *dbh, const char *sql, size_t sql_len);
Expand Down Expand Up @@ -604,12 +604,10 @@ struct _pdo_stmt_t {
zend_long row_count;

/* used to hold the statement's current query */
char *query_string;
size_t query_stringlen;
zend_string *query_string;

/* the copy of the query with expanded binds ONLY for emulated-prepare drivers */
char *active_query_string;
size_t active_query_stringlen;
zend_string *active_query_string;

/* the cursor specific error code. */
pdo_error_type error_code;
Expand Down Expand Up @@ -685,8 +683,7 @@ PDO_API int php_pdo_parse_data_source(const char *data_source,
PDO_API zend_class_entry *php_pdo_get_dbh_ce(void);
PDO_API zend_class_entry *php_pdo_get_exception(void);

PDO_API int pdo_parse_params(pdo_stmt_t *stmt, const char *inquery, size_t inquery_len,
char **outquery, size_t *outquery_len);
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, zend_string *inquery, zend_string **outquery);

PDO_API void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt,
const char *sqlstate, const char *supp);
Expand Down
4 changes: 2 additions & 2 deletions ext/pdo_dblib/dblib_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info)
}

spprintf(&message, 0, "%s [%d] (severity %d) [%s]",
msg, einfo->dberr, einfo->severity, stmt ? stmt->active_query_string : "");
msg, einfo->dberr, einfo->severity, stmt ? ZSTR_VAL(stmt->active_query_string) : "");

add_next_index_long(info, einfo->dberr);
add_next_index_string(info, message);
Expand Down Expand Up @@ -94,7 +94,7 @@ static int dblib_handle_closer(pdo_dbh_t *dbh)
return 0;
}

static int dblib_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len, pdo_stmt_t *stmt, zval *driver_options)
static int dblib_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options)
{
pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
pdo_dblib_stmt *S = ecalloc(1, sizeof(*S));
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/dblib_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt)

pdo_dblib_stmt_cursor_closer(stmt);

if (FAIL == dbcmd(H->link, stmt->active_query_string)) {
if (FAIL == dbcmd(H->link, ZSTR_VAL(stmt->active_query_string))) {
return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions ext/pdo_firebird/firebird_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ static int firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
/* }}} */

/* called by PDO to prepare an SQL query */
static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len, /* {{{ */
static int firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */
pdo_stmt_t *stmt, zval *driver_options)
{
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
Expand All @@ -524,7 +524,7 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_
zend_hash_init(np, 8, NULL, NULL, 0);

/* allocate and prepare statement */
if (!firebird_alloc_prepare_stmt(dbh, sql, sql_len, &num_sqlda, &s, np)) {
if (!firebird_alloc_prepare_stmt(dbh, ZSTR_VAL(sql), ZSTR_LEN(sql), &num_sqlda, &s, np)) {
break;
}

Expand Down
Loading

0 comments on commit 2d51c20

Please sign in to comment.