Skip to content

Commit 715b9aa

Browse files
committed
Implemented PDO Driver specific SQL parsers
RFC: http://wiki.php.net/rfc/pdo_driver_specific_parsers
1 parent ac94792 commit 715b9aa

31 files changed

+391
-44
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ php
137137
# ------------------------------------------------------------------------------
138138
/ext/json/json_scanner.c
139139
/ext/json/php_json_scanner_defs.h
140-
/ext/pdo/pdo_sql_parser.c
140+
/ext/pdo*/*_sql_parser.c
141141
/ext/phar/phar_path_check.c
142142
/ext/standard/url_scanner_ex.c
143143
/ext/standard/var_unserializer.c

ext/pdo/pdo_sql_parser.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: George Schlossnagle <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#define PDO_PARSER_TEXT 1
18+
#define PDO_PARSER_BIND 2
19+
#define PDO_PARSER_BIND_POS 3
20+
#define PDO_PARSER_ESCAPED_QUESTION 4
21+
#define PDO_PARSER_EOI 5
22+
23+
#define PDO_PARSER_BINDNO_ESCAPED_CHAR -1
24+
25+
#define RET(i) {s->cur = cursor; return i; }
26+
#define SKIP_ONE(i) {s->cur = s->tok + 1; return i; }
27+
28+
#define YYCTYPE unsigned char
29+
#define YYCURSOR cursor
30+
#define YYLIMIT s->end
31+
#define YYMARKER s->ptr
32+
#define YYFILL(n) { RET(PDO_PARSER_EOI); }

ext/pdo/pdo_sql_parser.re

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,26 @@
1717
#include "php.h"
1818
#include "php_pdo_driver.h"
1919
#include "php_pdo_int.h"
20+
#include "pdo_sql_parser.h"
2021

21-
#define PDO_PARSER_TEXT 1
22-
#define PDO_PARSER_BIND 2
23-
#define PDO_PARSER_BIND_POS 3
24-
#define PDO_PARSER_ESCAPED_QUESTION 4
25-
#define PDO_PARSER_EOI 5
26-
27-
#define PDO_PARSER_BINDNO_ESCAPED_CHAR -1
28-
29-
#define RET(i) {s->cur = cursor; return i; }
30-
#define SKIP_ONE(i) {s->cur = s->tok + 1; return i; }
31-
32-
#define YYCTYPE unsigned char
33-
#define YYCURSOR cursor
34-
#define YYLIMIT s->end
35-
#define YYMARKER s->ptr
36-
#define YYFILL(n) { RET(PDO_PARSER_EOI); }
37-
38-
typedef struct Scanner {
39-
const char *ptr, *cur, *tok, *end;
40-
} Scanner;
41-
42-
static int scan(Scanner *s)
22+
static int default_scanner(pdo_scanner_t *s)
4323
{
4424
const char *cursor = s->cur;
4525

4626
s->tok = cursor;
4727
/*!re2c
4828
BINDCHR = [:][a-zA-Z0-9_]+;
4929
QUESTION = [?];
50-
ESCQUESTION = [?][?];
5130
COMMENTS = ("/*"([^*]+|[*]+[^/*])*[*]*"*/"|"--"[^\r\n]*);
52-
SPECIALS = [:?"'-/];
53-
MULTICHAR = [:]{2,};
31+
SPECIALS = [:?"'/-];
32+
MULTICHAR = ([:]{2,}|[?]{2,});
5433
ANYNOEOF = [\001-\377];
5534
*/
5635
5736
/*!re2c
58-
(["](([\\]ANYNOEOF)|ANYNOEOF\["\\])*["]) { RET(PDO_PARSER_TEXT); }
59-
(['](([\\]ANYNOEOF)|ANYNOEOF\['\\])*[']) { RET(PDO_PARSER_TEXT); }
37+
(["]((["]["])|ANYNOEOF\["])*["]) { RET(PDO_PARSER_TEXT); }
38+
(['](([']['])|ANYNOEOF\['])*[']) { RET(PDO_PARSER_TEXT); }
6039
MULTICHAR { RET(PDO_PARSER_TEXT); }
61-
ESCQUESTION { RET(PDO_PARSER_ESCAPED_QUESTION); }
6240
BINDCHR { RET(PDO_PARSER_BIND); }
6341
QUESTION { RET(PDO_PARSER_BIND_POS); }
6442
SPECIALS { SKIP_ONE(PDO_PARSER_TEXT); }
@@ -81,7 +59,7 @@ static void free_param_name(zval *el) {
8159

8260
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, zend_string *inquery, zend_string **outquery)
8361
{
84-
Scanner s;
62+
pdo_scanner_t s;
8563
char *newbuffer;
8664
ptrdiff_t t;
8765
uint32_t bindno = 0;
@@ -91,6 +69,9 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, zend_string *inquery, zend_string
9169
struct pdo_bound_param_data *param;
9270
int query_type = PDO_PLACEHOLDER_NONE;
9371
struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
72+
int (*scan)(pdo_scanner_t *s);
73+
74+
scan = stmt->dbh->methods->scanner ? stmt->dbh->methods->scanner : default_scanner;
9475

9576
s.cur = ZSTR_VAL(inquery);
9677
s.end = s.cur + ZSTR_LEN(inquery) + 1;

ext/pdo/php_pdo_driver.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef struct _pdo_dbh_t pdo_dbh_t;
2424
typedef struct _pdo_dbh_object_t pdo_dbh_object_t;
2525
typedef struct _pdo_stmt_t pdo_stmt_t;
2626
typedef struct _pdo_row_t pdo_row_t;
27+
typedef struct _pdo_scanner_t pdo_scanner_t;
2728
struct pdo_bound_param_data;
2829

2930
#ifndef TRUE
@@ -33,7 +34,7 @@ struct pdo_bound_param_data;
3334
# define FALSE 0
3435
#endif
3536

36-
#define PDO_DRIVER_API 20170320
37+
#define PDO_DRIVER_API 20240423
3738

3839
/* Doctrine hardcodes these constants, avoid changing their values. */
3940
enum pdo_param_type {
@@ -275,6 +276,9 @@ typedef void (*pdo_dbh_request_shutdown)(pdo_dbh_t *dbh);
275276
* with any zvals in the driver_data that would be freed if the handle is destroyed. */
276277
typedef void (*pdo_dbh_get_gc_func)(pdo_dbh_t *dbh, zend_get_gc_buffer *buffer);
277278

279+
/* driver specific re2s sql parser, overrides the default one if present */
280+
typedef int (*pdo_dbh_sql_scanner)(pdo_scanner_t *s);
281+
278282
/* for adding methods to the dbh or stmt objects
279283
pointer to a list of driver specific functions. The convention is
280284
to prefix the function names using the PDO driver name; this will
@@ -307,6 +311,7 @@ struct pdo_dbh_methods {
307311
/* if defined to NULL, PDO will use its internal transaction tracking state */
308312
pdo_dbh_txn_func in_transaction;
309313
pdo_dbh_get_gc_func get_gc;
314+
pdo_dbh_sql_scanner scanner;
310315
};
311316

312317
/* }}} */
@@ -647,6 +652,10 @@ struct _pdo_row_t {
647652
pdo_stmt_t *stmt;
648653
};
649654

655+
struct _pdo_scanner_t {
656+
const char *ptr, *cur, *tok, *end;
657+
};
658+
650659
/* Call this in MINIT to register the PDO driver.
651660
* Registering the driver might fail and should be reported accordingly in MINIT. */
652661
PDO_API zend_result php_pdo_register_driver(const pdo_driver_t *driver);

ext/pdo_dblib/dblib_driver.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,8 @@ static const struct pdo_dbh_methods dblib_methods = {
436436
NULL, /* get driver methods */
437437
NULL, /* request shutdown */
438438
NULL, /* in transaction, use PDO's internal tracking mechanism */
439-
NULL /* get gc */
439+
NULL, /* get gc */
440+
NULL /* scanner */
440441
};
441442

442443
static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options)

ext/pdo_firebird/firebird_driver.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,8 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
12741274
NULL, /* get driver methods */
12751275
NULL, /* request shutdown */
12761276
pdo_firebird_in_manually_transaction,
1277-
NULL /* get gc */
1277+
NULL, /* get gc */
1278+
NULL /* scanner */
12781279
};
12791280
/* }}} */
12801281

ext/pdo_mysql/Makefile.frag

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
$(srcdir)/mysql_sql_parser.c: $(srcdir)/mysql_sql_parser.re
2+
@(cd $(top_srcdir); \
3+
if test -f ./mysql_sql_parser.re; then \
4+
$(RE2C) $(RE2C_FLAGS) --no-generation-date -o mysql_sql_parser.c mysql_sql_parser.re; \
5+
else \
6+
$(RE2C) $(RE2C_FLAGS) --no-generation-date -o ext/pdo_mysql/mysql_sql_parser.c ext/pdo_mysql/mysql_sql_parser.re; \
7+
fi)

ext/pdo_mysql/Makefile.frag.w32

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ext\pdo_mysql\mysql_sql_parser.c: ext\pdo_mysql\mysql_sql_parser.re
2+
cd $(PHP_SRC_DIR)
3+
$(RE2C) $(RE2C_FLAGS) --no-generation-date -o ext/pdo_mysql/mysql_sql_parser.c ext/pdo_mysql/mysql_sql_parser.re

ext/pdo_mysql/config.m4

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ if test "$PHP_PDO_MYSQL" != "no"; then
8585
AC_DEFINE_UNQUOTED(PDO_MYSQL_UNIX_ADDR, "$PDO_MYSQL_SOCKET", [ ])
8686
fi
8787

88-
PHP_NEW_EXTENSION(pdo_mysql, pdo_mysql.c mysql_driver.c mysql_statement.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
88+
PHP_NEW_EXTENSION(pdo_mysql, pdo_mysql.c mysql_driver.c mysql_statement.c mysql_sql_parser.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
8989

9090
PHP_ADD_EXTENSION_DEP(pdo_mysql, pdo)
91+
PHP_ADD_MAKEFILE_FRAGMENT
9192

9293
if test "$PHP_PDO_MYSQL" = "yes" || test "$PHP_PDO_MYSQL" = "mysqlnd"; then
9394
PHP_ADD_EXTENSION_DEP(pdo_mysql, mysqlnd)

ext/pdo_mysql/config.w32

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ if (PHP_PDO_MYSQL != "no") {
66
if (PHP_PDO_MYSQL == "yes" || PHP_PDO_MYSQL == "mysqlnd") {
77
AC_DEFINE('PDO_USE_MYSQLND', 1, 'Using MySQL native driver');
88
STDOUT.WriteLine("INFO: mysqlnd build");
9-
EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c");
9+
EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c mysql_sql_parser.c");
1010
ADD_EXTENSION_DEP('pdo_mysql', 'pdo');
11+
ADD_MAKEFILE_FRAGMENT();
1112
} else {
1213
if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) &&
1314
CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL",
1415
PHP_PDO_MYSQL + "\\include;" +
1516
PHP_PHP_BUILD + "\\include\\mysql;" +
1617
PHP_PDO_MYSQL)) {
17-
EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
18+
EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c mysql_sql_parser.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
19+
ADD_MAKEFILE_FRAGMENT();
1820
} else {
1921
WARNING("pdo_mysql not enabled; libraries and headers not found");
2022
}

0 commit comments

Comments
 (0)