You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

456 lines
12 KiB

22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2004 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_0.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: George Schlossnagle <george@omniti.com> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #include "php.h"
  20. #include "php_pdo_driver.h"
  21. #include "php_pdo_int.h"
  22. #define PDO_PARSER_TEXT 1
  23. #define PDO_PARSER_BIND 2
  24. #define PDO_PARSER_BIND_POS 3
  25. #define PDO_PARSER_EOI 4
  26. #define RET(i) {s->cur = cursor; return i; }
  27. #define YYCTYPE char
  28. #define YYCURSOR cursor
  29. #define YYLIMIT s->lim
  30. #define YYMARKER s->ptr
  31. #define YYFILL(n)
  32. typedef struct Scanner {
  33. char *lim, *ptr, *cur, *tok;
  34. } Scanner;
  35. static int scan(Scanner *s)
  36. {
  37. char *cursor = s->cur;
  38. std:
  39. s->tok = cursor;
  40. /*!re2c
  41. BINDCHR = [:][a-zA-Z0-9_]+;
  42. QUESTION = [?];
  43. SPECIALS = [:?"'];
  44. ESCQQ = [\\]["];
  45. ESCQ = [\\]['];
  46. EOF = [\000];
  47. ANYNOEOF = [\001-\377];
  48. */
  49. /*!re2c
  50. (["] (ESCQQ|ANYNOEOF\[\\"])* ["]) { RET(PDO_PARSER_TEXT); }
  51. (['] (ESCQ|ANYNOEOF\[\\"])* [']) { RET(PDO_PARSER_TEXT); }
  52. BINDCHR { RET(PDO_PARSER_BIND); }
  53. QUESTION { RET(PDO_PARSER_BIND_POS); }
  54. SPECIALS { RET(PDO_PARSER_TEXT); }
  55. (ANYNOEOF\SPECIALS)+ { RET(PDO_PARSER_TEXT); }
  56. EOF { RET(PDO_PARSER_EOI); }
  57. */
  58. }
  59. struct placeholder {
  60. char *pos;
  61. int len;
  62. int bindno;
  63. int qlen; /* quoted length of value */
  64. char *quoted; /* quoted value */
  65. int freeq;
  66. struct placeholder *next;
  67. };
  68. PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
  69. char **outquery, int *outquery_len TSRMLS_DC)
  70. {
  71. Scanner s;
  72. char *ptr, *newbuffer;
  73. int t;
  74. int bindno = 0;
  75. int ret = 0;
  76. int newbuffer_len;
  77. HashTable *params;
  78. struct pdo_bound_param_data *param;
  79. int query_type = PDO_PLACEHOLDER_NONE;
  80. struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
  81. ptr = *outquery;
  82. s.cur = inquery;
  83. s.lim = inquery + inquery_len;
  84. /* phase 1: look for args */
  85. while((t = scan(&s)) != PDO_PARSER_EOI) {
  86. if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
  87. if (t == PDO_PARSER_BIND) {
  88. query_type |= PDO_PLACEHOLDER_NAMED;
  89. } else {
  90. query_type |= PDO_PLACEHOLDER_POSITIONAL;
  91. }
  92. plc = emalloc(sizeof(*plc));
  93. memset(plc, 0, sizeof(*plc));
  94. plc->next = NULL;
  95. plc->pos = s.tok;
  96. plc->len = s.cur - s.tok;
  97. plc->bindno = bindno++;
  98. if (placetail) {
  99. placetail->next = plc;
  100. } else {
  101. placeholders = plc;
  102. }
  103. placetail = plc;
  104. }
  105. }
  106. if (bindno == 0) {
  107. /* nothing to do; good! */
  108. return 0;
  109. }
  110. /* did the query make sense to me? */
  111. if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
  112. /* they mixed both types; punt */
  113. pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
  114. return -1;
  115. }
  116. if (stmt->supports_placeholders == query_type) {
  117. /* query matches native syntax */
  118. ret = 0;
  119. goto clean_up;
  120. }
  121. params = stmt->bound_params;
  122. /* Do we have placeholders but no bound params */
  123. if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
  124. pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
  125. ret = -1;
  126. goto clean_up;
  127. }
  128. /* what are we going to do ? */
  129. if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
  130. /* query generation */
  131. newbuffer_len = inquery_len;
  132. /* let's quote all the values */
  133. for (plc = placeholders; plc; plc = plc->next) {
  134. if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
  135. ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
  136. } else {
  137. ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
  138. }
  139. if (ret == FAILURE) {
  140. /* parameter was not defined */
  141. ret = -1;
  142. pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
  143. goto clean_up;
  144. }
  145. if (stmt->dbh->methods->quoter) {
  146. if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
  147. php_stream *stm;
  148. php_stream_from_zval_no_verify(stm, &param->parameter);
  149. if (stm) {
  150. size_t len;
  151. char *buf = NULL;
  152. len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
  153. if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
  154. param->param_type TSRMLS_CC)) {
  155. /* bork */
  156. ret = -1;
  157. strcpy(stmt->error_code, stmt->dbh->error_code);
  158. efree(buf);
  159. goto clean_up;
  160. }
  161. efree(buf);
  162. } else {
  163. pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
  164. ret = -1;
  165. goto clean_up;
  166. }
  167. plc->freeq = 1;
  168. } else {
  169. switch (Z_TYPE_P(param->parameter)) {
  170. case IS_NULL:
  171. plc->quoted = "NULL";
  172. plc->qlen = sizeof("NULL")-1;
  173. plc->freeq = 0;
  174. break;
  175. case IS_BOOL:
  176. convert_to_long(param->parameter);
  177. case IS_LONG:
  178. case IS_DOUBLE:
  179. convert_to_string(param->parameter);
  180. plc->qlen = Z_STRLEN_P(param->parameter);
  181. plc->quoted = Z_STRVAL_P(param->parameter);
  182. plc->freeq = 0;
  183. break;
  184. default:
  185. convert_to_string(param->parameter);
  186. if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
  187. Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
  188. param->param_type TSRMLS_CC)) {
  189. /* bork */
  190. ret = -1;
  191. strcpy(stmt->error_code, stmt->dbh->error_code);
  192. goto clean_up;
  193. }
  194. plc->freeq = 1;
  195. }
  196. }
  197. } else {
  198. plc->quoted = Z_STRVAL_P(param->parameter);
  199. plc->qlen = Z_STRLEN_P(param->parameter);
  200. }
  201. newbuffer_len += plc->qlen;
  202. }
  203. rewrite:
  204. /* allocate output buffer */
  205. newbuffer = emalloc(newbuffer_len + 1);
  206. *outquery = newbuffer;
  207. /* and build the query */
  208. plc = placeholders;
  209. ptr = inquery;
  210. do {
  211. t = plc->pos - ptr;
  212. if (t) {
  213. memcpy(newbuffer, ptr, t);
  214. newbuffer += t;
  215. }
  216. memcpy(newbuffer, plc->quoted, plc->qlen);
  217. newbuffer += plc->qlen;
  218. ptr = plc->pos + plc->len;
  219. plc = plc->next;
  220. } while (plc);
  221. t = (inquery + inquery_len) - ptr;
  222. if (t) {
  223. memcpy(newbuffer, ptr, t);
  224. newbuffer += t;
  225. }
  226. *newbuffer = '\0';
  227. *outquery_len = newbuffer - *outquery;
  228. ret = 1;
  229. goto clean_up;
  230. } else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
  231. /* rewrite ? to :pdoX */
  232. char idxbuf[32];
  233. newbuffer_len = inquery_len;
  234. for (plc = placeholders; plc; plc = plc->next) {
  235. snprintf(idxbuf, sizeof(idxbuf), ":pdo%d", plc->bindno);
  236. plc->quoted = estrdup(idxbuf);
  237. plc->qlen = strlen(plc->quoted);
  238. plc->freeq = 1;
  239. newbuffer_len += plc->qlen;
  240. }
  241. goto rewrite;
  242. } else {
  243. /* rewrite :name to ? */
  244. newbuffer_len = inquery_len;
  245. if (stmt->bound_param_map == NULL) {
  246. ALLOC_HASHTABLE(stmt->bound_param_map);
  247. zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
  248. }
  249. for (plc = placeholders; plc; plc = plc->next) {
  250. char *name;
  251. name = estrndup(plc->pos, plc->len);
  252. zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
  253. efree(name);
  254. plc->quoted = "?";
  255. plc->qlen = 1;
  256. }
  257. goto rewrite;
  258. }
  259. clean_up:
  260. while (placeholders) {
  261. plc = placeholders;
  262. placeholders = plc->next;
  263. if (plc->freeq) {
  264. efree(plc->quoted);
  265. }
  266. efree(plc);
  267. }
  268. return ret;
  269. }
  270. #if 0
  271. int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
  272. int *outquery_len TSRMLS_DC)
  273. {
  274. Scanner s;
  275. char *ptr;
  276. int t;
  277. int bindno = 0;
  278. int newbuffer_len;
  279. int padding;
  280. HashTable *params = stmt->bound_params;
  281. struct pdo_bound_param_data *param;
  282. /* allocate buffer for query with expanded binds, ptr is our writing pointer */
  283. newbuffer_len = inquery_len;
  284. /* calculate the possible padding factor due to quoting */
  285. if(stmt->dbh->max_escaped_char_length) {
  286. padding = stmt->dbh->max_escaped_char_length;
  287. } else {
  288. padding = 3;
  289. }
  290. if(params) {
  291. zend_hash_internal_pointer_reset(params);
  292. while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
  293. if(param->parameter) {
  294. convert_to_string(param->parameter);
  295. /* accomodate a string that needs to be fully quoted
  296. bind placeholders are at least 2 characters, so
  297. the accomodate their own "'s
  298. */
  299. newbuffer_len += padding * Z_STRLEN_P(param->parameter);
  300. }
  301. zend_hash_move_forward(params);
  302. }
  303. }
  304. *outquery = (char *) emalloc(newbuffer_len + 1);
  305. *outquery_len = 0;
  306. ptr = *outquery;
  307. s.cur = inquery;
  308. s.lim = inquery + inquery_len;
  309. while((t = scan(&s)) != PDO_PARSER_EOI) {
  310. if(t == PDO_PARSER_TEXT) {
  311. memcpy(ptr, s.tok, s.cur - s.tok);
  312. ptr += (s.cur - s.tok);
  313. *outquery_len += (s.cur - s.tok);
  314. }
  315. else if(t == PDO_PARSER_BIND) {
  316. if(!params) {
  317. /* error */
  318. efree(*outquery);
  319. *outquery = NULL;
  320. return (int) (s.cur - inquery);
  321. }
  322. /* lookup bind first via hash and then index */
  323. /* stupid keys need to be null-terminated, even though we know their length */
  324. if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))
  325. ||
  326. (SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)))
  327. {
  328. char *quotedstr;
  329. int quotedstrlen;
  330. /* restore the in-string key, doesn't need null-termination here */
  331. /* currently everything is a string here */
  332. /* quote the bind value if necessary */
  333. if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
  334. Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
  335. {
  336. memcpy(ptr, quotedstr, quotedstrlen);
  337. ptr += quotedstrlen;
  338. *outquery_len += quotedstrlen;
  339. efree(quotedstr);
  340. } else {
  341. memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
  342. ptr += Z_STRLEN_P(param->parameter);
  343. *outquery_len += (Z_STRLEN_P(param->parameter));
  344. }
  345. }
  346. else {
  347. /* error and cleanup */
  348. efree(*outquery);
  349. *outquery = NULL;
  350. return (int) (s.cur - inquery);
  351. }
  352. bindno++;
  353. }
  354. else if(t == PDO_PARSER_BIND_POS) {
  355. if(!params) {
  356. /* error */
  357. efree(*outquery);
  358. *outquery = NULL;
  359. return (int) (s.cur - inquery);
  360. }
  361. /* lookup bind by index */
  362. if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))
  363. {
  364. char *quotedstr;
  365. int quotedstrlen;
  366. /* currently everything is a string here */
  367. /* quote the bind value if necessary */
  368. if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
  369. Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
  370. {
  371. memcpy(ptr, quotedstr, quotedstrlen);
  372. ptr += quotedstrlen;
  373. *outquery_len += quotedstrlen;
  374. efree(quotedstr);
  375. } else {
  376. memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
  377. ptr += Z_STRLEN_P(param->parameter);
  378. *outquery_len += (Z_STRLEN_P(param->parameter));
  379. }
  380. }
  381. else {
  382. /* error and cleanup */
  383. efree(*outquery);
  384. *outquery = NULL;
  385. return (int) (s.cur - inquery);
  386. }
  387. bindno++;
  388. }
  389. }
  390. *ptr = '\0';
  391. return 0;
  392. }
  393. #endif
  394. /*
  395. * Local variables:
  396. * tab-width: 4
  397. * c-basic-offset: 4
  398. * End:
  399. * vim600: noet sw=4 ts=4 fdm=marker ft=c
  400. * vim<600: noet sw=4 ts=4
  401. */