1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 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_01.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: Wez Furlong <wez@php.net> | |
16 | | Marcus Boerger <helly@php.net> | |
17 | | Sterling Hughes <sterling@php.net> | |
18 | +----------------------------------------------------------------------+ |
19 | */ |
20 | |
21 | /* $Id$ */ |
22 | |
23 | /* The PDO Database Handle Class */ |
24 | |
25 | #ifdef HAVE_CONFIG_H |
26 | #include "config.h" |
27 | #endif |
28 | |
29 | #include "php.h" |
30 | #include "php_ini.h" |
31 | #include "ext/standard/info.h" |
32 | #include "php_pdo.h" |
33 | #include "php_pdo_driver.h" |
34 | #include "php_pdo_int.h" |
35 | #include "zend_exceptions.h" |
36 | #include "zend_object_handlers.h" |
37 | #include "zend_hash.h" |
38 | |
39 | static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC); |
40 | |
41 | void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC) /* {{{ */ |
42 | { |
43 | pdo_error_type *pdo_err = &dbh->error_code; |
44 | char *message = NULL; |
45 | const char *msg; |
46 | |
47 | if (dbh && dbh->error_mode == PDO_ERRMODE_SILENT) { |
48 | #if 0 |
49 | /* BUG: if user is running in silent mode and hits an error at the driver level |
50 | * when they use the PDO methods to call up the error information, they may |
51 | * get bogus information */ |
52 | return; |
53 | #endif |
54 | } |
55 | |
56 | if (stmt) { |
57 | pdo_err = &stmt->error_code; |
58 | } |
59 | |
60 | strncpy(*pdo_err, sqlstate, 6); |
61 | |
62 | /* hash sqlstate to error messages */ |
63 | msg = pdo_sqlstate_state_to_description(*pdo_err); |
64 | if (!msg) { |
65 | msg = "<<Unknown error>>" ; |
66 | } |
67 | |
68 | if (supp) { |
69 | spprintf(&message, 0, "SQLSTATE[%s]: %s: %s" , *pdo_err, msg, supp); |
70 | } else { |
71 | spprintf(&message, 0, "SQLSTATE[%s]: %s" , *pdo_err, msg); |
72 | } |
73 | |
74 | if (dbh && dbh->error_mode != PDO_ERRMODE_EXCEPTION) { |
75 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , message); |
76 | } else { |
77 | zval *ex, *info; |
78 | zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception(); |
79 | |
80 | MAKE_STD_ZVAL(ex); |
81 | object_init_ex(ex, pdo_ex); |
82 | |
83 | zend_update_property_string(def_ex, ex, "message" , sizeof("message" )-1, message TSRMLS_CC); |
84 | zend_update_property_string(def_ex, ex, "code" , sizeof("code" )-1, *pdo_err TSRMLS_CC); |
85 | |
86 | MAKE_STD_ZVAL(info); |
87 | array_init(info); |
88 | |
89 | add_next_index_string(info, *pdo_err, 1); |
90 | add_next_index_long(info, 0); |
91 | |
92 | zend_update_property(pdo_ex, ex, "errorInfo" , sizeof("errorInfo" )-1, info TSRMLS_CC); |
93 | zval_ptr_dtor(&info); |
94 | |
95 | zend_throw_exception_object(ex TSRMLS_CC); |
96 | } |
97 | |
98 | if (message) { |
99 | efree(message); |
100 | } |
101 | } |
102 | /* }}} */ |
103 | |
104 | PDO_API void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ |
105 | { |
106 | pdo_error_type *pdo_err = &dbh->error_code; |
107 | const char *msg = "<<Unknown>>" ; |
108 | char *supp = NULL; |
109 | long native_code = 0; |
110 | char *message = NULL; |
111 | zval *info = NULL; |
112 | |
113 | if (dbh == NULL || dbh->error_mode == PDO_ERRMODE_SILENT) { |
114 | return; |
115 | } |
116 | |
117 | if (stmt) { |
118 | pdo_err = &stmt->error_code; |
119 | } |
120 | |
121 | /* hash sqlstate to error messages */ |
122 | msg = pdo_sqlstate_state_to_description(*pdo_err); |
123 | if (!msg) { |
124 | msg = "<<Unknown error>>" ; |
125 | } |
126 | |
127 | if (dbh->methods->fetch_err) { |
128 | MAKE_STD_ZVAL(info); |
129 | array_init(info); |
130 | |
131 | add_next_index_string(info, *pdo_err, 1); |
132 | |
133 | if (dbh->methods->fetch_err(dbh, stmt, info TSRMLS_CC)) { |
134 | zval **item; |
135 | |
136 | if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 1, (void**)&item)) { |
137 | native_code = Z_LVAL_PP(item); |
138 | } |
139 | |
140 | if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 2, (void**)&item)) { |
141 | supp = estrndup(Z_STRVAL_PP(item), Z_STRLEN_PP(item)); |
142 | } |
143 | } |
144 | } |
145 | |
146 | if (supp) { |
147 | spprintf(&message, 0, "SQLSTATE[%s]: %s: %ld %s" , *pdo_err, msg, native_code, supp); |
148 | } else { |
149 | spprintf(&message, 0, "SQLSTATE[%s]: %s" , *pdo_err, msg); |
150 | } |
151 | |
152 | if (dbh->error_mode == PDO_ERRMODE_WARNING) { |
153 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , message); |
154 | } else if (EG(exception) == NULL) { |
155 | zval *ex; |
156 | zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception(); |
157 | |
158 | MAKE_STD_ZVAL(ex); |
159 | object_init_ex(ex, pdo_ex); |
160 | |
161 | zend_update_property_string(def_ex, ex, "message" , sizeof("message" )-1, message TSRMLS_CC); |
162 | zend_update_property_string(def_ex, ex, "code" , sizeof("code" )-1, *pdo_err TSRMLS_CC); |
163 | |
164 | if (info) { |
165 | zend_update_property(pdo_ex, ex, "errorInfo" , sizeof("errorInfo" )-1, info TSRMLS_CC); |
166 | } |
167 | |
168 | zend_throw_exception_object(ex TSRMLS_CC); |
169 | } |
170 | |
171 | if (info) { |
172 | zval_ptr_dtor(&info); |
173 | } |
174 | |
175 | if (message) { |
176 | efree(message); |
177 | } |
178 | |
179 | if (supp) { |
180 | efree(supp); |
181 | } |
182 | } |
183 | /* }}} */ |
184 | |
185 | static char *dsn_from_uri(char *uri, char *buf, size_t buflen TSRMLS_DC) /* {{{ */ |
186 | { |
187 | php_stream *stream; |
188 | char *dsn = NULL; |
189 | |
190 | stream = php_stream_open_wrapper(uri, "rb" , REPORT_ERRORS, NULL); |
191 | if (stream) { |
192 | dsn = php_stream_get_line(stream, buf, buflen, NULL); |
193 | php_stream_close(stream); |
194 | } |
195 | return dsn; |
196 | } |
197 | /* }}} */ |
198 | |
199 | /* {{{ proto void PDO::__construct(string dsn[, string username[, string passwd [, array options]]]) |
200 | */ |
201 | static PHP_METHOD(PDO, dbh_constructor) |
202 | { |
203 | zval *object = getThis(); |
204 | pdo_dbh_t *dbh = NULL; |
205 | zend_bool is_persistent = FALSE; |
206 | char *data_source; |
207 | int data_source_len; |
208 | char *colon; |
209 | char *username=NULL, *password=NULL; |
210 | int usernamelen, passwordlen; |
211 | pdo_driver_t *driver = NULL; |
212 | zval *options = NULL; |
213 | char alt_dsn[512]; |
214 | int call_factory = 1; |
215 | |
216 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!a!" , &data_source, &data_source_len, |
217 | &username, &usernamelen, &password, &passwordlen, &options)) { |
218 | ZVAL_NULL(object); |
219 | return; |
220 | } |
221 | |
222 | /* parse the data source name */ |
223 | colon = strchr(data_source, ':'); |
224 | |
225 | if (!colon) { |
226 | /* let's see if this string has a matching dsn in the php.ini */ |
227 | char *ini_dsn = NULL; |
228 | |
229 | snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s" , data_source); |
230 | if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) { |
231 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name" ); |
232 | zval_dtor(object); |
233 | ZVAL_NULL(object); |
234 | return; |
235 | } |
236 | |
237 | data_source = ini_dsn; |
238 | colon = strchr(data_source, ':'); |
239 | |
240 | if (!colon) { |
241 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via INI: %s)" , alt_dsn); |
242 | ZVAL_NULL(object); |
243 | return; |
244 | } |
245 | } |
246 | |
247 | if (!strncmp(data_source, "uri:" , sizeof("uri:" )-1)) { |
248 | /* the specified URI holds connection details */ |
249 | data_source = dsn_from_uri(data_source + sizeof("uri:" )-1, alt_dsn, sizeof(alt_dsn) TSRMLS_CC); |
250 | if (!data_source) { |
251 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source URI" ); |
252 | ZVAL_NULL(object); |
253 | return; |
254 | } |
255 | colon = strchr(data_source, ':'); |
256 | if (!colon) { |
257 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via URI)" ); |
258 | ZVAL_NULL(object); |
259 | return; |
260 | } |
261 | } |
262 | |
263 | driver = pdo_find_driver(data_source, colon - data_source); |
264 | |
265 | if (!driver) { |
266 | /* NB: don't want to include the data_source in the error message as |
267 | * it might contain a password */ |
268 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "could not find driver" ); |
269 | ZVAL_NULL(object); |
270 | return; |
271 | } |
272 | |
273 | dbh = (pdo_dbh_t *) zend_object_store_get_object(object TSRMLS_CC); |
274 | |
275 | /* is this supposed to be a persistent connection ? */ |
276 | if (options) { |
277 | zval **v; |
278 | int plen = 0; |
279 | char *hashkey = NULL; |
280 | zend_rsrc_list_entry *le; |
281 | pdo_dbh_t *pdbh = NULL; |
282 | |
283 | if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT, (void**)&v)) { |
284 | if (Z_TYPE_PP(v) == IS_STRING && !is_numeric_string(Z_STRVAL_PP(v), Z_STRLEN_PP(v), NULL, NULL, 0) && Z_STRLEN_PP(v) > 0) { |
285 | /* user specified key */ |
286 | plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s:%s" , data_source, |
287 | username ? username : "" , |
288 | password ? password : "" , |
289 | Z_STRVAL_PP(v)); |
290 | is_persistent = 1; |
291 | } else { |
292 | convert_to_long_ex(v); |
293 | is_persistent = Z_LVAL_PP(v) ? 1 : 0; |
294 | plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s" , data_source, |
295 | username ? username : "" , |
296 | password ? password : "" ); |
297 | } |
298 | } |
299 | |
300 | if (is_persistent) { |
301 | /* let's see if we have one cached.... */ |
302 | if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) { |
303 | if (Z_TYPE_P(le) == php_pdo_list_entry()) { |
304 | pdbh = (pdo_dbh_t*)le->ptr; |
305 | |
306 | /* is the connection still alive ? */ |
307 | if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh TSRMLS_CC)) { |
308 | /* nope... need to kill it */ |
309 | pdbh = NULL; |
310 | } |
311 | } |
312 | } |
313 | |
314 | if (pdbh) { |
315 | call_factory = 0; |
316 | } else { |
317 | /* need a brand new pdbh */ |
318 | pdbh = pecalloc(1, sizeof(*pdbh), 1); |
319 | |
320 | if (!pdbh) { |
321 | php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle" ); |
322 | /* NOTREACHED */ |
323 | } |
324 | |
325 | pdbh->is_persistent = 1; |
326 | if (!(pdbh->persistent_id = pemalloc(plen + 1, 1))) { |
327 | php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle" ); |
328 | } |
329 | memcpy((char *)pdbh->persistent_id, hashkey, plen+1); |
330 | pdbh->persistent_id_len = plen+1; |
331 | pdbh->refcount = 1; |
332 | pdbh->std.properties = NULL; |
333 | } |
334 | } |
335 | |
336 | if (pdbh) { |
337 | /* let's copy the emalloc bits over from the other handle */ |
338 | if (pdbh->std.properties) { |
339 | zend_hash_destroy(dbh->std.properties); |
340 | efree(dbh->std.properties); |
341 | if (dbh->std.properties_table) { |
342 | efree(dbh->std.properties_table); |
343 | } |
344 | } else { |
345 | pdbh->std.ce = dbh->std.ce; |
346 | pdbh->def_stmt_ce = dbh->def_stmt_ce; |
347 | pdbh->def_stmt_ctor_args = dbh->def_stmt_ctor_args; |
348 | pdbh->std.properties = dbh->std.properties; |
349 | pdbh->std.properties_table = dbh->std.properties_table; |
350 | } |
351 | /* kill the non-persistent thingamy */ |
352 | efree(dbh); |
353 | /* switch over to the persistent one */ |
354 | dbh = pdbh; |
355 | zend_object_store_set_object(object, dbh TSRMLS_CC); |
356 | dbh->refcount++; |
357 | } |
358 | |
359 | if (hashkey) { |
360 | efree(hashkey); |
361 | } |
362 | } |
363 | |
364 | if (call_factory) { |
365 | dbh->data_source_len = strlen(colon + 1); |
366 | dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent); |
367 | dbh->username = username ? pestrdup(username, is_persistent) : NULL; |
368 | dbh->password = password ? pestrdup(password, is_persistent) : NULL; |
369 | dbh->default_fetch_type = PDO_FETCH_BOTH; |
370 | } |
371 | |
372 | dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1 TSRMLS_CC); |
373 | |
374 | if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) { |
375 | php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory" ); |
376 | } |
377 | |
378 | if (!call_factory) { |
379 | /* we got a persistent guy from our cache */ |
380 | goto options; |
381 | } |
382 | |
383 | if (driver->db_handle_factory(dbh, options TSRMLS_CC)) { |
384 | /* all set */ |
385 | |
386 | if (is_persistent) { |
387 | zend_rsrc_list_entry le; |
388 | |
389 | /* register in the persistent list etc. */ |
390 | /* we should also need to replace the object store entry, |
391 | since it was created with emalloc */ |
392 | |
393 | le.type = php_pdo_list_entry(); |
394 | le.ptr = dbh; |
395 | |
396 | if (FAILURE == zend_hash_update(&EG(persistent_list), |
397 | (char*)dbh->persistent_id, dbh->persistent_id_len, (void*)&le, |
398 | sizeof(le), NULL)) { |
399 | php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to register persistent entry" ); |
400 | } |
401 | } |
402 | |
403 | dbh->driver = driver; |
404 | options: |
405 | if (options) { |
406 | zval **attr_value; |
407 | char *str_key; |
408 | ulong long_key; |
409 | |
410 | zend_hash_internal_pointer_reset(Z_ARRVAL_P(options)); |
411 | while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(options), (void**)&attr_value) |
412 | && HASH_KEY_IS_LONG == zend_hash_get_current_key(Z_ARRVAL_P(options), &str_key, &long_key, 0)) { |
413 | |
414 | pdo_dbh_attribute_set(dbh, long_key, *attr_value TSRMLS_CC); |
415 | zend_hash_move_forward(Z_ARRVAL_P(options)); |
416 | } |
417 | } |
418 | |
419 | return; |
420 | } |
421 | |
422 | /* the connection failed; things will tidy up in free_storage */ |
423 | /* XXX raise exception */ |
424 | ZVAL_NULL(object); |
425 | } |
426 | /* }}} */ |
427 | |
428 | static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */ |
429 | { |
430 | if (ctor_args) { |
431 | if (Z_TYPE_P(ctor_args) != IS_ARRAY) { |
432 | pdo_raise_impl_error(dbh, NULL, "HY000" , "constructor arguments must be passed as an array" TSRMLS_CC); |
433 | return NULL; |
434 | } |
435 | if (!dbstmt_ce->constructor) { |
436 | pdo_raise_impl_error(dbh, NULL, "HY000" , "user-supplied statement does not accept constructor arguments" TSRMLS_CC); |
437 | return NULL; |
438 | } |
439 | } |
440 | |
441 | Z_TYPE_P(object) = IS_OBJECT; |
442 | object_init_ex(object, dbstmt_ce); |
443 | Z_SET_REFCOUNT_P(object, 1); |
444 | Z_SET_ISREF_P(object); |
445 | |
446 | return object; |
447 | } /* }}} */ |
448 | |
449 | static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */ |
450 | { |
451 | zval *query_string; |
452 | zval z_key; |
453 | |
454 | MAKE_STD_ZVAL(query_string); |
455 | ZVAL_STRINGL(query_string, stmt->query_string, stmt->query_stringlen, 1); |
456 | ZVAL_STRINGL(&z_key, "queryString" , sizeof("queryString" )-1, 0); |
457 | std_object_handlers.write_property(object, &z_key, query_string, 0 TSRMLS_CC); |
458 | zval_ptr_dtor(&query_string); |
459 | |
460 | if (dbstmt_ce->constructor) { |
461 | zend_fcall_info fci; |
462 | zend_fcall_info_cache fcc; |
463 | zval *retval = NULL; |
464 | |
465 | fci.size = sizeof(zend_fcall_info); |
466 | fci.function_table = &dbstmt_ce->function_table; |
467 | fci.function_name = NULL; |
468 | fci.object_ptr = object; |
469 | fci.symbol_table = NULL; |
470 | fci.retval_ptr_ptr = &retval; |
471 | fci.params = NULL; |
472 | fci.no_separation = 1; |
473 | |
474 | zend_fcall_info_args(&fci, ctor_args TSRMLS_CC); |
475 | |
476 | fcc.initialized = 1; |
477 | fcc.function_handler = dbstmt_ce->constructor; |
478 | fcc.calling_scope = EG(scope); |
479 | fcc.called_scope = Z_OBJCE_P(object); |
480 | fcc.object_ptr = object; |
481 | |
482 | if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) { |
483 | zval_dtor(object); |
484 | ZVAL_NULL(object); |
485 | object = NULL; /* marks failure */ |
486 | } else if (retval) { |
487 | zval_ptr_dtor(&retval); |
488 | } |
489 | |
490 | if (fci.params) { |
491 | efree(fci.params); |
492 | } |
493 | } |
494 | } |
495 | /* }}} */ |
496 | |
497 | /* {{{ proto object PDO::prepare(string statement [, array options]) |
498 | Prepares a statement for execution and returns a statement object */ |
499 | static PHP_METHOD(PDO, prepare) |
500 | { |
501 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
502 | pdo_stmt_t *stmt; |
503 | char *statement; |
504 | int statement_len; |
505 | zval *options = NULL, **opt, **item, *ctor_args; |
506 | zend_class_entry *dbstmt_ce, **pce; |
507 | |
508 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a" , &statement, |
509 | &statement_len, &options)) { |
510 | RETURN_FALSE; |
511 | } |
512 | |
513 | PDO_DBH_CLEAR_ERR(); |
514 | PDO_CONSTRUCT_CHECK; |
515 | |
516 | if (ZEND_NUM_ARGS() > 1 && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS, (void**)&opt)) { |
517 | if (Z_TYPE_PP(opt) != IS_ARRAY || zend_hash_index_find(Z_ARRVAL_PP(opt), 0, (void**)&item) == FAILURE |
518 | || Z_TYPE_PP(item) != IS_STRING |
519 | || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE |
520 | ) { |
521 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
522 | "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); " |
523 | "the classname must be a string specifying an existing class" |
524 | TSRMLS_CC); |
525 | PDO_HANDLE_DBH_ERR(); |
526 | RETURN_FALSE; |
527 | } |
528 | dbstmt_ce = *pce; |
529 | if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce TSRMLS_CC)) { |
530 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
531 | "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC); |
532 | PDO_HANDLE_DBH_ERR(); |
533 | RETURN_FALSE; |
534 | } |
535 | if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) { |
536 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
537 | "user-supplied statement class cannot have a public constructor" TSRMLS_CC); |
538 | PDO_HANDLE_DBH_ERR(); |
539 | RETURN_FALSE; |
540 | } |
541 | if (zend_hash_index_find(Z_ARRVAL_PP(opt), 1, (void**)&item) == SUCCESS) { |
542 | if (Z_TYPE_PP(item) != IS_ARRAY) { |
543 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
544 | "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); " |
545 | "ctor_args must be an array" |
546 | TSRMLS_CC); |
547 | PDO_HANDLE_DBH_ERR(); |
548 | RETURN_FALSE; |
549 | } |
550 | ctor_args = *item; |
551 | } else { |
552 | ctor_args = NULL; |
553 | } |
554 | } else { |
555 | dbstmt_ce = dbh->def_stmt_ce; |
556 | ctor_args = dbh->def_stmt_ctor_args; |
557 | } |
558 | |
559 | if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, ctor_args TSRMLS_CC)) { |
560 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
561 | "failed to instantiate user-supplied statement class" |
562 | TSRMLS_CC); |
563 | PDO_HANDLE_DBH_ERR(); |
564 | RETURN_FALSE; |
565 | } |
566 | stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC); |
567 | |
568 | /* unconditionally keep this for later reference */ |
569 | stmt->query_string = estrndup(statement, statement_len); |
570 | stmt->query_stringlen = statement_len; |
571 | stmt->default_fetch_type = dbh->default_fetch_type; |
572 | stmt->dbh = dbh; |
573 | /* give it a reference to me */ |
574 | zend_objects_store_add_ref(getThis() TSRMLS_CC); |
575 | php_pdo_dbh_addref(dbh TSRMLS_CC); |
576 | stmt->database_object_handle = *getThis(); |
577 | /* we haven't created a lazy object yet */ |
578 | ZVAL_NULL(&stmt->lazy_object_ref); |
579 | |
580 | if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options TSRMLS_CC)) { |
581 | pdo_stmt_construct(stmt, return_value, dbstmt_ce, ctor_args TSRMLS_CC); |
582 | return; |
583 | } |
584 | |
585 | PDO_HANDLE_DBH_ERR(); |
586 | |
587 | /* kill the object handle for the stmt here */ |
588 | zval_dtor(return_value); |
589 | |
590 | RETURN_FALSE; |
591 | } |
592 | /* }}} */ |
593 | |
594 | /* {{{ proto bool PDO::beginTransaction() |
595 | Initiates a transaction */ |
596 | static PHP_METHOD(PDO, beginTransaction) |
597 | { |
598 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
599 | |
600 | if (zend_parse_parameters_none() == FAILURE) { |
601 | return; |
602 | } |
603 | PDO_CONSTRUCT_CHECK; |
604 | |
605 | if (dbh->in_txn) { |
606 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is already an active transaction" ); |
607 | RETURN_FALSE; |
608 | } |
609 | |
610 | if (!dbh->methods->begin) { |
611 | /* TODO: this should be an exception; see the auto-commit mode |
612 | * comments below */ |
613 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "This driver doesn't support transactions" ); |
614 | RETURN_FALSE; |
615 | } |
616 | |
617 | if (dbh->methods->begin(dbh TSRMLS_CC)) { |
618 | dbh->in_txn = 1; |
619 | RETURN_TRUE; |
620 | } |
621 | |
622 | PDO_HANDLE_DBH_ERR(); |
623 | RETURN_FALSE; |
624 | } |
625 | /* }}} */ |
626 | |
627 | /* {{{ proto bool PDO::commit() |
628 | Commit a transaction */ |
629 | static PHP_METHOD(PDO, commit) |
630 | { |
631 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
632 | |
633 | if (zend_parse_parameters_none() == FAILURE) { |
634 | return; |
635 | } |
636 | PDO_CONSTRUCT_CHECK; |
637 | |
638 | if (!dbh->in_txn) { |
639 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction" ); |
640 | RETURN_FALSE; |
641 | } |
642 | |
643 | if (dbh->methods->commit(dbh TSRMLS_CC)) { |
644 | dbh->in_txn = 0; |
645 | RETURN_TRUE; |
646 | } |
647 | |
648 | PDO_HANDLE_DBH_ERR(); |
649 | RETURN_FALSE; |
650 | } |
651 | /* }}} */ |
652 | |
653 | /* {{{ proto bool PDO::rollBack() |
654 | roll back a transaction */ |
655 | static PHP_METHOD(PDO, rollBack) |
656 | { |
657 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
658 | |
659 | if (zend_parse_parameters_none() == FAILURE) { |
660 | return; |
661 | } |
662 | PDO_CONSTRUCT_CHECK; |
663 | |
664 | if (!dbh->in_txn) { |
665 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction" ); |
666 | RETURN_FALSE; |
667 | } |
668 | |
669 | if (dbh->methods->rollback(dbh TSRMLS_CC)) { |
670 | dbh->in_txn = 0; |
671 | RETURN_TRUE; |
672 | } |
673 | |
674 | PDO_HANDLE_DBH_ERR(); |
675 | RETURN_FALSE; |
676 | } |
677 | /* }}} */ |
678 | |
679 | /* {{{ proto bool PDO::inTransaction() |
680 | determine if inside a transaction */ |
681 | static PHP_METHOD(PDO, inTransaction) |
682 | { |
683 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
684 | |
685 | if (zend_parse_parameters_none() == FAILURE) { |
686 | return; |
687 | } |
688 | PDO_CONSTRUCT_CHECK; |
689 | |
690 | if (!dbh->methods->in_transaction) { |
691 | RETURN_BOOL(dbh->in_txn); |
692 | } |
693 | |
694 | RETURN_BOOL(dbh->methods->in_transaction(dbh TSRMLS_CC)); |
695 | } |
696 | /* }}} */ |
697 | |
698 | static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC) /* {{{ */ |
699 | { |
700 | |
701 | #define PDO_LONG_PARAM_CHECK \ |
702 | if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_BOOL) { \ |
703 | pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer" TSRMLS_CC); \ |
704 | PDO_HANDLE_DBH_ERR(); \ |
705 | return FAILURE; \ |
706 | } \ |
707 | |
708 | switch (attr) { |
709 | case PDO_ATTR_ERRMODE: |
710 | PDO_LONG_PARAM_CHECK; |
711 | convert_to_long(value); |
712 | switch (Z_LVAL_P(value)) { |
713 | case PDO_ERRMODE_SILENT: |
714 | case PDO_ERRMODE_WARNING: |
715 | case PDO_ERRMODE_EXCEPTION: |
716 | dbh->error_mode = Z_LVAL_P(value); |
717 | return SUCCESS; |
718 | default: |
719 | pdo_raise_impl_error(dbh, NULL, "HY000" , "invalid error mode" TSRMLS_CC); |
720 | PDO_HANDLE_DBH_ERR(); |
721 | return FAILURE; |
722 | } |
723 | return FAILURE; |
724 | |
725 | case PDO_ATTR_CASE: |
726 | PDO_LONG_PARAM_CHECK; |
727 | convert_to_long(value); |
728 | switch (Z_LVAL_P(value)) { |
729 | case PDO_CASE_NATURAL: |
730 | case PDO_CASE_UPPER: |
731 | case PDO_CASE_LOWER: |
732 | dbh->desired_case = Z_LVAL_P(value); |
733 | return SUCCESS; |
734 | default: |
735 | pdo_raise_impl_error(dbh, NULL, "HY000" , "invalid case folding mode" TSRMLS_CC); |
736 | PDO_HANDLE_DBH_ERR(); |
737 | return FAILURE; |
738 | } |
739 | return FAILURE; |
740 | |
741 | case PDO_ATTR_ORACLE_NULLS: |
742 | PDO_LONG_PARAM_CHECK; |
743 | convert_to_long(value); |
744 | dbh->oracle_nulls = Z_LVAL_P(value); |
745 | return SUCCESS; |
746 | |
747 | case PDO_ATTR_DEFAULT_FETCH_MODE: |
748 | if (Z_TYPE_P(value) == IS_ARRAY) { |
749 | zval **tmp; |
750 | if (zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) { |
751 | if (Z_LVAL_PP(tmp) == PDO_FETCH_INTO || Z_LVAL_PP(tmp) == PDO_FETCH_CLASS) { |
752 | pdo_raise_impl_error(dbh, NULL, "HY000" , "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes" TSRMLS_CC); |
753 | return FAILURE; |
754 | } |
755 | } |
756 | } else { |
757 | PDO_LONG_PARAM_CHECK; |
758 | } |
759 | convert_to_long(value); |
760 | if (Z_LVAL_P(value) == PDO_FETCH_USE_DEFAULT) { |
761 | pdo_raise_impl_error(dbh, NULL, "HY000" , "invalid fetch mode type" TSRMLS_CC); |
762 | return FAILURE; |
763 | } |
764 | dbh->default_fetch_type = Z_LVAL_P(value); |
765 | return SUCCESS; |
766 | |
767 | case PDO_ATTR_STRINGIFY_FETCHES: |
768 | PDO_LONG_PARAM_CHECK; |
769 | convert_to_long(value); |
770 | dbh->stringify = Z_LVAL_P(value) ? 1 : 0; |
771 | return SUCCESS; |
772 | |
773 | case PDO_ATTR_STATEMENT_CLASS: { |
774 | /* array(string classname, array(mixed ctor_args)) */ |
775 | zend_class_entry **pce; |
776 | zval **item; |
777 | |
778 | if (dbh->is_persistent) { |
779 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
780 | "PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances" |
781 | TSRMLS_CC); |
782 | PDO_HANDLE_DBH_ERR(); |
783 | return FAILURE; |
784 | } |
785 | if (Z_TYPE_P(value) != IS_ARRAY |
786 | || zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&item) == FAILURE |
787 | || Z_TYPE_PP(item) != IS_STRING |
788 | || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE |
789 | ) { |
790 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
791 | "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); " |
792 | "the classname must be a string specifying an existing class" |
793 | TSRMLS_CC); |
794 | PDO_HANDLE_DBH_ERR(); |
795 | return FAILURE; |
796 | } |
797 | if (!instanceof_function(*pce, pdo_dbstmt_ce TSRMLS_CC)) { |
798 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
799 | "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC); |
800 | PDO_HANDLE_DBH_ERR(); |
801 | return FAILURE; |
802 | } |
803 | if ((*pce)->constructor && !((*pce)->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) { |
804 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
805 | "user-supplied statement class cannot have a public constructor" TSRMLS_CC); |
806 | PDO_HANDLE_DBH_ERR(); |
807 | return FAILURE; |
808 | } |
809 | dbh->def_stmt_ce = *pce; |
810 | if (dbh->def_stmt_ctor_args) { |
811 | zval_ptr_dtor(&dbh->def_stmt_ctor_args); |
812 | dbh->def_stmt_ctor_args = NULL; |
813 | } |
814 | if (zend_hash_index_find(Z_ARRVAL_P(value), 1, (void**)&item) == SUCCESS) { |
815 | if (Z_TYPE_PP(item) != IS_ARRAY) { |
816 | pdo_raise_impl_error(dbh, NULL, "HY000" , |
817 | "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); " |
818 | "ctor_args must be an array" |
819 | TSRMLS_CC); |
820 | PDO_HANDLE_DBH_ERR(); |
821 | return FAILURE; |
822 | } |
823 | Z_ADDREF_PP(item); |
824 | dbh->def_stmt_ctor_args = *item; |
825 | } |
826 | return SUCCESS; |
827 | } |
828 | |
829 | default: |
830 | ; |
831 | } |
832 | |
833 | if (!dbh->methods->set_attribute) { |
834 | goto fail; |
835 | } |
836 | |
837 | PDO_DBH_CLEAR_ERR(); |
838 | if (dbh->methods->set_attribute(dbh, attr, value TSRMLS_CC)) { |
839 | return SUCCESS; |
840 | } |
841 | |
842 | fail: |
843 | if (attr == PDO_ATTR_AUTOCOMMIT) { |
844 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The auto-commit mode cannot be changed for this driver" ); |
845 | } else if (!dbh->methods->set_attribute) { |
846 | pdo_raise_impl_error(dbh, NULL, "IM001" , "driver does not support setting attributes" TSRMLS_CC); |
847 | } else { |
848 | PDO_HANDLE_DBH_ERR(); |
849 | } |
850 | return FAILURE; |
851 | } |
852 | /* }}} */ |
853 | |
854 | /* {{{ proto bool PDO::setAttribute(long attribute, mixed value) |
855 | Set an attribute */ |
856 | static PHP_METHOD(PDO, setAttribute) |
857 | { |
858 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
859 | long attr; |
860 | zval *value; |
861 | |
862 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz" , &attr, &value)) { |
863 | RETURN_FALSE; |
864 | } |
865 | |
866 | PDO_DBH_CLEAR_ERR(); |
867 | PDO_CONSTRUCT_CHECK; |
868 | |
869 | if (pdo_dbh_attribute_set(dbh, attr, value TSRMLS_CC) != FAILURE) { |
870 | RETURN_TRUE; |
871 | } |
872 | RETURN_FALSE; |
873 | } |
874 | /* }}} */ |
875 | |
876 | /* {{{ proto mixed PDO::getAttribute(long attribute) |
877 | Get an attribute */ |
878 | static PHP_METHOD(PDO, getAttribute) |
879 | { |
880 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
881 | long attr; |
882 | |
883 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l" , &attr)) { |
884 | RETURN_FALSE; |
885 | } |
886 | |
887 | PDO_DBH_CLEAR_ERR(); |
888 | PDO_CONSTRUCT_CHECK; |
889 | |
890 | /* handle generic PDO-level attributes */ |
891 | switch (attr) { |
892 | case PDO_ATTR_PERSISTENT: |
893 | RETURN_BOOL(dbh->is_persistent); |
894 | |
895 | case PDO_ATTR_CASE: |
896 | RETURN_LONG(dbh->desired_case); |
897 | |
898 | case PDO_ATTR_ORACLE_NULLS: |
899 | RETURN_LONG(dbh->oracle_nulls); |
900 | |
901 | case PDO_ATTR_ERRMODE: |
902 | RETURN_LONG(dbh->error_mode); |
903 | |
904 | case PDO_ATTR_DRIVER_NAME: |
905 | RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len, 1); |
906 | |
907 | case PDO_ATTR_STATEMENT_CLASS: |
908 | array_init(return_value); |
909 | add_next_index_string(return_value, dbh->def_stmt_ce->name, 1); |
910 | if (dbh->def_stmt_ctor_args) { |
911 | Z_ADDREF_P(dbh->def_stmt_ctor_args); |
912 | add_next_index_zval(return_value, dbh->def_stmt_ctor_args); |
913 | } |
914 | return; |
915 | case PDO_ATTR_DEFAULT_FETCH_MODE: |
916 | RETURN_LONG(dbh->default_fetch_type); |
917 | |
918 | } |
919 | |
920 | if (!dbh->methods->get_attribute) { |
921 | pdo_raise_impl_error(dbh, NULL, "IM001" , "driver does not support getting attributes" TSRMLS_CC); |
922 | RETURN_FALSE; |
923 | } |
924 | |
925 | switch (dbh->methods->get_attribute(dbh, attr, return_value TSRMLS_CC)) { |
926 | case -1: |
927 | PDO_HANDLE_DBH_ERR(); |
928 | RETURN_FALSE; |
929 | |
930 | case 0: |
931 | pdo_raise_impl_error(dbh, NULL, "IM001" , "driver does not support that attribute" TSRMLS_CC); |
932 | RETURN_FALSE; |
933 | |
934 | default: |
935 | return; |
936 | } |
937 | } |
938 | /* }}} */ |
939 | |
940 | /* {{{ proto long PDO::exec(string query) |
941 | Execute a query that does not return a row set, returning the number of affected rows */ |
942 | static PHP_METHOD(PDO, exec) |
943 | { |
944 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
945 | char *statement; |
946 | int statement_len; |
947 | long ret; |
948 | |
949 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s" , &statement, &statement_len)) { |
950 | RETURN_FALSE; |
951 | } |
952 | |
953 | if (!statement_len) { |
954 | pdo_raise_impl_error(dbh, NULL, "HY000" , "trying to execute an empty query" TSRMLS_CC); |
955 | RETURN_FALSE; |
956 | } |
957 | PDO_DBH_CLEAR_ERR(); |
958 | PDO_CONSTRUCT_CHECK; |
959 | ret = dbh->methods->doer(dbh, statement, statement_len TSRMLS_CC); |
960 | if(ret == -1) { |
961 | PDO_HANDLE_DBH_ERR(); |
962 | RETURN_FALSE; |
963 | } else { |
964 | RETURN_LONG(ret); |
965 | } |
966 | } |
967 | /* }}} */ |
968 | |
969 | |
970 | /* {{{ proto string PDO::lastInsertId([string seqname]) |
971 | Returns the id of the last row that we affected on this connection. Some databases require a sequence or table name to be passed in. Not always meaningful. */ |
972 | static PHP_METHOD(PDO, lastInsertId) |
973 | { |
974 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
975 | char *name = NULL; |
976 | int namelen; |
977 | |
978 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!" , &name, &namelen)) { |
979 | RETURN_FALSE; |
980 | } |
981 | |
982 | PDO_DBH_CLEAR_ERR(); |
983 | PDO_CONSTRUCT_CHECK; |
984 | if (!dbh->methods->last_id) { |
985 | pdo_raise_impl_error(dbh, NULL, "IM001" , "driver does not support lastInsertId()" TSRMLS_CC); |
986 | RETURN_FALSE; |
987 | } else { |
988 | Z_STRVAL_P(return_value) = dbh->methods->last_id(dbh, name, (unsigned int *)&Z_STRLEN_P(return_value) TSRMLS_CC); |
989 | if (!Z_STRVAL_P(return_value)) { |
990 | PDO_HANDLE_DBH_ERR(); |
991 | RETURN_FALSE; |
992 | } else { |
993 | Z_TYPE_P(return_value) = IS_STRING; |
994 | } |
995 | } |
996 | } |
997 | /* }}} */ |
998 | |
999 | /* {{{ proto string PDO::errorCode() |
1000 | Fetch the error code associated with the last operation on the database handle */ |
1001 | static PHP_METHOD(PDO, errorCode) |
1002 | { |
1003 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
1004 | |
1005 | if (zend_parse_parameters_none() == FAILURE) { |
1006 | return; |
1007 | } |
1008 | PDO_CONSTRUCT_CHECK; |
1009 | |
1010 | if (dbh->query_stmt) { |
1011 | RETURN_STRING(dbh->query_stmt->error_code, 1); |
1012 | } |
1013 | |
1014 | if (dbh->error_code[0] == '\0') { |
1015 | RETURN_NULL(); |
1016 | } |
1017 | |
1018 | /** |
1019 | * Making sure that we fallback to the default implementation |
1020 | * if the dbh->error_code is not null. |
1021 | */ |
1022 | RETURN_STRING(dbh->error_code, 1); |
1023 | } |
1024 | /* }}} */ |
1025 | |
1026 | /* {{{ proto int PDO::errorInfo() |
1027 | Fetch extended error information associated with the last operation on the database handle */ |
1028 | static PHP_METHOD(PDO, errorInfo) |
1029 | { |
1030 | int error_count; |
1031 | int error_count_diff = 0; |
1032 | int error_expected_count = 3; |
1033 | |
1034 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
1035 | |
1036 | if (zend_parse_parameters_none() == FAILURE) { |
1037 | return; |
1038 | } |
1039 | |
1040 | PDO_CONSTRUCT_CHECK; |
1041 | |
1042 | array_init(return_value); |
1043 | |
1044 | if (dbh->query_stmt) { |
1045 | add_next_index_string(return_value, dbh->query_stmt->error_code, 1); |
1046 | } else { |
1047 | add_next_index_string(return_value, dbh->error_code, 1); |
1048 | } |
1049 | |
1050 | if (dbh->methods->fetch_err) { |
1051 | dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value TSRMLS_CC); |
1052 | } |
1053 | |
1054 | /** |
1055 | * In order to be consistent, we have to make sure we add the good amount |
1056 | * of nulls depending on the current number of elements. We make a simple |
1057 | * difference and add the needed elements |
1058 | */ |
1059 | error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value)); |
1060 | |
1061 | if (error_expected_count > error_count) { |
1062 | int current_index; |
1063 | |
1064 | error_count_diff = error_expected_count - error_count; |
1065 | for (current_index = 0; current_index < error_count_diff; current_index++) { |
1066 | add_next_index_null(return_value); |
1067 | } |
1068 | } |
1069 | } |
1070 | /* }}} */ |
1071 | |
1072 | /* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args]) |
1073 | Prepare and execute $sql; returns the statement object for iteration */ |
1074 | static PHP_METHOD(PDO, query) |
1075 | { |
1076 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
1077 | pdo_stmt_t *stmt; |
1078 | char *statement; |
1079 | int statement_len; |
1080 | |
1081 | /* Return a meaningful error when no parameters were passed */ |
1082 | if (!ZEND_NUM_ARGS()) { |
1083 | zend_parse_parameters(0 TSRMLS_CC, "z|z" , NULL, NULL); |
1084 | RETURN_FALSE; |
1085 | } |
1086 | |
1087 | if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s" , &statement, |
1088 | &statement_len)) { |
1089 | RETURN_FALSE; |
1090 | } |
1091 | |
1092 | PDO_DBH_CLEAR_ERR(); |
1093 | PDO_CONSTRUCT_CHECK; |
1094 | |
1095 | if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC)) { |
1096 | pdo_raise_impl_error(dbh, NULL, "HY000" , "failed to instantiate user supplied statement class" TSRMLS_CC); |
1097 | return; |
1098 | } |
1099 | stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC); |
1100 | |
1101 | /* unconditionally keep this for later reference */ |
1102 | stmt->query_string = estrndup(statement, statement_len); |
1103 | stmt->query_stringlen = statement_len; |
1104 | |
1105 | stmt->default_fetch_type = dbh->default_fetch_type; |
1106 | stmt->active_query_string = stmt->query_string; |
1107 | stmt->active_query_stringlen = statement_len; |
1108 | stmt->dbh = dbh; |
1109 | /* give it a reference to me */ |
1110 | zend_objects_store_add_ref(getThis() TSRMLS_CC); |
1111 | php_pdo_dbh_addref(dbh TSRMLS_CC); |
1112 | stmt->database_object_handle = *getThis(); |
1113 | /* we haven't created a lazy object yet */ |
1114 | ZVAL_NULL(&stmt->lazy_object_ref); |
1115 | |
1116 | if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL TSRMLS_CC)) { |
1117 | PDO_STMT_CLEAR_ERR(); |
1118 | if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) { |
1119 | |
1120 | /* now execute the statement */ |
1121 | PDO_STMT_CLEAR_ERR(); |
1122 | if (stmt->methods->executer(stmt TSRMLS_CC)) { |
1123 | int ret = 1; |
1124 | if (!stmt->executed) { |
1125 | if (stmt->dbh->alloc_own_columns) { |
1126 | ret = pdo_stmt_describe_columns(stmt TSRMLS_CC); |
1127 | } |
1128 | stmt->executed = 1; |
1129 | } |
1130 | if (ret) { |
1131 | pdo_stmt_construct(stmt, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC); |
1132 | return; |
1133 | } |
1134 | } |
1135 | } |
1136 | /* something broke */ |
1137 | dbh->query_stmt = stmt; |
1138 | dbh->query_stmt_zval = *return_value; |
1139 | PDO_HANDLE_STMT_ERR(); |
1140 | } else { |
1141 | PDO_HANDLE_DBH_ERR(); |
1142 | zval_dtor(return_value); |
1143 | } |
1144 | |
1145 | RETURN_FALSE; |
1146 | } |
1147 | /* }}} */ |
1148 | |
1149 | /* {{{ proto string PDO::quote(string string [, int paramtype]) |
1150 | quotes string for use in a query. The optional paramtype acts as a hint for drivers that have alternate quoting styles. The default value is PDO_PARAM_STR */ |
1151 | static PHP_METHOD(PDO, quote) |
1152 | { |
1153 | pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); |
1154 | char *str; |
1155 | int str_len; |
1156 | long paramtype = PDO_PARAM_STR; |
1157 | char *qstr; |
1158 | int qlen; |
1159 | |
1160 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l" , &str, &str_len, ¶mtype)) { |
1161 | RETURN_FALSE; |
1162 | } |
1163 | |
1164 | PDO_DBH_CLEAR_ERR(); |
1165 | PDO_CONSTRUCT_CHECK; |
1166 | if (!dbh->methods->quoter) { |
1167 | pdo_raise_impl_error(dbh, NULL, "IM001" , "driver does not support quoting" TSRMLS_CC); |
1168 | RETURN_FALSE; |
1169 | } |
1170 | |
1171 | if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype TSRMLS_CC)) { |
1172 | RETURN_STRINGL(qstr, qlen, 0); |
1173 | } |
1174 | PDO_HANDLE_DBH_ERR(); |
1175 | RETURN_FALSE; |
1176 | } |
1177 | /* }}} */ |
1178 | |
1179 | /* {{{ proto int PDO::__wakeup() |
1180 | Prevents use of a PDO instance that has been unserialized */ |
1181 | static PHP_METHOD(PDO, __wakeup) |
1182 | { |
1183 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances" ); |
1184 | } |
1185 | /* }}} */ |
1186 | |
1187 | /* {{{ proto int PDO::__sleep() |
1188 | Prevents serialization of a PDO instance */ |
1189 | static PHP_METHOD(PDO, __sleep) |
1190 | { |
1191 | zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances" ); |
1192 | } |
1193 | /* }}} */ |
1194 | |
1195 | /* {{{ proto array PDO::getAvailableDrivers() |
1196 | Return array of available PDO drivers */ |
1197 | static PHP_METHOD(PDO, getAvailableDrivers) |
1198 | { |
1199 | HashPosition pos; |
1200 | pdo_driver_t **pdriver; |
1201 | |
1202 | if (zend_parse_parameters_none() == FAILURE) { |
1203 | return; |
1204 | } |
1205 | |
1206 | array_init(return_value); |
1207 | |
1208 | zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos); |
1209 | while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) { |
1210 | add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1); |
1211 | zend_hash_move_forward_ex(&pdo_driver_hash, &pos); |
1212 | } |
1213 | } |
1214 | /* }}} */ |
1215 | |
1216 | /* {{{ arginfo */ |
1217 | ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 1) |
1218 | ZEND_ARG_INFO(0, dsn) |
1219 | ZEND_ARG_INFO(0, username) |
1220 | ZEND_ARG_INFO(0, passwd) |
1221 | ZEND_ARG_INFO(0, options) /* array */ |
1222 | ZEND_END_ARG_INFO() |
1223 | |
1224 | ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_prepare, 0, 0, 1) |
1225 | ZEND_ARG_INFO(0, statement) |
1226 | ZEND_ARG_INFO(0, options) /* array */ |
1227 | ZEND_END_ARG_INFO() |
1228 | |
1229 | ZEND_BEGIN_ARG_INFO(arginfo_pdo_setattribute, 0) |
1230 | ZEND_ARG_INFO(0, attribute) |
1231 | ZEND_ARG_INFO(0, value) |
1232 | ZEND_END_ARG_INFO() |
1233 | |
1234 | ZEND_BEGIN_ARG_INFO(arginfo_pdo_getattribute, 0) |
1235 | ZEND_ARG_INFO(0, attribute) |
1236 | ZEND_END_ARG_INFO() |
1237 | |
1238 | ZEND_BEGIN_ARG_INFO(arginfo_pdo_exec, 0) |
1239 | ZEND_ARG_INFO(0, query) |
1240 | ZEND_END_ARG_INFO() |
1241 | |
1242 | ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_lastinsertid, 0, 0, 0) |
1243 | ZEND_ARG_INFO(0, seqname) |
1244 | ZEND_END_ARG_INFO() |
1245 | |
1246 | ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1) |
1247 | ZEND_ARG_INFO(0, string) |
1248 | ZEND_ARG_INFO(0, paramtype) |
1249 | ZEND_END_ARG_INFO() |
1250 | |
1251 | ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0) |
1252 | ZEND_END_ARG_INFO() |
1253 | /* }}} */ |
1254 | |
1255 | const zend_function_entry pdo_dbh_functions[] = { |
1256 | ZEND_MALIAS(PDO, __construct, dbh_constructor, arginfo_pdo___construct, ZEND_ACC_PUBLIC) |
1257 | PHP_ME(PDO, prepare, arginfo_pdo_prepare, ZEND_ACC_PUBLIC) |
1258 | PHP_ME(PDO, beginTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC) |
1259 | PHP_ME(PDO, commit, arginfo_pdo__void, ZEND_ACC_PUBLIC) |
1260 | PHP_ME(PDO, rollBack, arginfo_pdo__void, ZEND_ACC_PUBLIC) |
1261 | PHP_ME(PDO, inTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC) |
1262 | PHP_ME(PDO, setAttribute, arginfo_pdo_setattribute, ZEND_ACC_PUBLIC) |
1263 | PHP_ME(PDO, exec, arginfo_pdo_exec, ZEND_ACC_PUBLIC) |
1264 | PHP_ME(PDO, query, NULL, ZEND_ACC_PUBLIC) |
1265 | PHP_ME(PDO, lastInsertId, arginfo_pdo_lastinsertid, ZEND_ACC_PUBLIC) |
1266 | PHP_ME(PDO, errorCode, arginfo_pdo__void, ZEND_ACC_PUBLIC) |
1267 | PHP_ME(PDO, errorInfo, arginfo_pdo__void, ZEND_ACC_PUBLIC) |
1268 | PHP_ME(PDO, getAttribute, arginfo_pdo_getattribute, ZEND_ACC_PUBLIC) |
1269 | PHP_ME(PDO, quote, arginfo_pdo_quote, ZEND_ACC_PUBLIC) |
1270 | PHP_ME(PDO, __wakeup, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) |
1271 | PHP_ME(PDO, __sleep, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) |
1272 | PHP_ME(PDO, getAvailableDrivers, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
1273 | {NULL, NULL, NULL} |
1274 | }; |
1275 | |
1276 | /* {{{ overloaded object handlers for PDO class */ |
1277 | int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC) |
1278 | { |
1279 | const zend_function_entry *funcs; |
1280 | zend_function func; |
1281 | zend_internal_function *ifunc = (zend_internal_function*)&func; |
1282 | int namelen; |
1283 | char *lc_name; |
1284 | |
1285 | if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) { |
1286 | return 0; |
1287 | } |
1288 | funcs = dbh->methods->get_driver_methods(dbh, kind TSRMLS_CC); |
1289 | if (!funcs) { |
1290 | return 0; |
1291 | } |
1292 | |
1293 | if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) { |
1294 | php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO methods." ); |
1295 | } |
1296 | zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL, NULL, dbh->is_persistent, 0); |
1297 | |
1298 | while (funcs->fname) { |
1299 | ifunc->type = ZEND_INTERNAL_FUNCTION; |
1300 | ifunc->handler = funcs->handler; |
1301 | ifunc->function_name = (char*)funcs->fname; |
1302 | ifunc->scope = dbh->std.ce; |
1303 | ifunc->prototype = NULL; |
1304 | if (funcs->flags) { |
1305 | ifunc->fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE; |
1306 | } else { |
1307 | ifunc->fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_NEVER_CACHE; |
1308 | } |
1309 | if (funcs->arg_info) { |
1310 | zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info; |
1311 | |
1312 | ifunc->arg_info = (zend_arg_info*)funcs->arg_info + 1; |
1313 | ifunc->num_args = funcs->num_args; |
1314 | if (info->required_num_args == -1) { |
1315 | ifunc->required_num_args = funcs->num_args; |
1316 | } else { |
1317 | ifunc->required_num_args = info->required_num_args; |
1318 | } |
1319 | if (info->return_reference) { |
1320 | ifunc->fn_flags |= ZEND_ACC_RETURN_REFERENCE; |
1321 | } |
1322 | if (funcs->arg_info[funcs->num_args].is_variadic) { |
1323 | ifunc->fn_flags |= ZEND_ACC_VARIADIC; |
1324 | } |
1325 | } else { |
1326 | ifunc->arg_info = NULL; |
1327 | ifunc->num_args = 0; |
1328 | ifunc->required_num_args = 0; |
1329 | } |
1330 | namelen = strlen(funcs->fname); |
1331 | lc_name = emalloc(namelen+1); |
1332 | zend_str_tolower_copy(lc_name, funcs->fname, namelen); |
1333 | zend_hash_add(dbh->cls_methods[kind], lc_name, namelen+1, &func, sizeof(func), NULL); |
1334 | efree(lc_name); |
1335 | funcs++; |
1336 | } |
1337 | |
1338 | return 1; |
1339 | } |
1340 | |
1341 | static union _zend_function *dbh_method_get( |
1342 | #if PHP_API_VERSION >= 20041225 |
1343 | zval **object_pp, |
1344 | #else |
1345 | zval *object, |
1346 | #endif |
1347 | char *method_name, int method_len, const zend_literal *key TSRMLS_DC) |
1348 | { |
1349 | zend_function *fbc = NULL; |
1350 | char *lc_method_name; |
1351 | #if PHP_API_VERSION >= 20041225 |
1352 | zval *object = *object_pp; |
1353 | #endif |
1354 | pdo_dbh_t *dbh = zend_object_store_get_object(object TSRMLS_CC); |
1355 | |
1356 | lc_method_name = emalloc(method_len + 1); |
1357 | zend_str_tolower_copy(lc_method_name, method_name, method_len); |
1358 | |
1359 | if ((fbc = std_object_handlers.get_method(object_pp, method_name, method_len, key TSRMLS_CC)) == NULL) { |
1360 | /* not a pre-defined method, nor a user-defined method; check |
1361 | * the driver specific methods */ |
1362 | if (!dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { |
1363 | if (!pdo_hash_methods(dbh, |
1364 | PDO_DBH_DRIVER_METHOD_KIND_DBH TSRMLS_CC) |
1365 | || !dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { |
1366 | goto out; |
1367 | } |
1368 | } |
1369 | |
1370 | if (zend_hash_find(dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], |
1371 | lc_method_name, method_len+1, (void**)&fbc) == FAILURE) { |
1372 | if (!fbc) { |
1373 | fbc = NULL; |
1374 | } |
1375 | } |
1376 | } |
1377 | |
1378 | out: |
1379 | efree(lc_method_name); |
1380 | return fbc; |
1381 | } |
1382 | |
1383 | static int dbh_compare(zval *object1, zval *object2 TSRMLS_DC) |
1384 | { |
1385 | return -1; |
1386 | } |
1387 | |
1388 | static zend_object_handlers pdo_dbh_object_handlers; |
1389 | |
1390 | void pdo_dbh_init(TSRMLS_D) |
1391 | { |
1392 | zend_class_entry ce; |
1393 | |
1394 | INIT_CLASS_ENTRY(ce, "PDO" , pdo_dbh_functions); |
1395 | pdo_dbh_ce = zend_register_internal_class(&ce TSRMLS_CC); |
1396 | pdo_dbh_ce->create_object = pdo_dbh_new; |
1397 | |
1398 | memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); |
1399 | pdo_dbh_object_handlers.get_method = dbh_method_get; |
1400 | pdo_dbh_object_handlers.compare_objects = dbh_compare; |
1401 | |
1402 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL" , (long)PDO_PARAM_BOOL); |
1403 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL" , (long)PDO_PARAM_NULL); |
1404 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT" , (long)PDO_PARAM_INT); |
1405 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR" , (long)PDO_PARAM_STR); |
1406 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB" , (long)PDO_PARAM_LOB); |
1407 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT" , (long)PDO_PARAM_STMT); |
1408 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT" , (long)PDO_PARAM_INPUT_OUTPUT); |
1409 | |
1410 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC" , (long)PDO_PARAM_EVT_ALLOC); |
1411 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE" , (long)PDO_PARAM_EVT_FREE); |
1412 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_PRE" , (long)PDO_PARAM_EVT_EXEC_PRE); |
1413 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_POST" , (long)PDO_PARAM_EVT_EXEC_POST); |
1414 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_PRE" , (long)PDO_PARAM_EVT_FETCH_PRE); |
1415 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST" , (long)PDO_PARAM_EVT_FETCH_POST); |
1416 | REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE" , (long)PDO_PARAM_EVT_NORMALIZE); |
1417 | |
1418 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY" , (long)PDO_FETCH_LAZY); |
1419 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC" ,(long)PDO_FETCH_ASSOC); |
1420 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM" , (long)PDO_FETCH_NUM); |
1421 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH" , (long)PDO_FETCH_BOTH); |
1422 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ" , (long)PDO_FETCH_OBJ); |
1423 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND" ,(long)PDO_FETCH_BOUND); |
1424 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN" ,(long)PDO_FETCH_COLUMN); |
1425 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS" ,(long)PDO_FETCH_CLASS); |
1426 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO" , (long)PDO_FETCH_INTO); |
1427 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC" , (long)PDO_FETCH_FUNC); |
1428 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP" ,(long)PDO_FETCH_GROUP); |
1429 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE" ,(long)PDO_FETCH_UNIQUE); |
1430 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_KEY_PAIR" ,(long)PDO_FETCH_KEY_PAIR); |
1431 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE" ,(long)PDO_FETCH_CLASSTYPE); |
1432 | #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1 |
1433 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE" ,(long)PDO_FETCH_SERIALIZE); |
1434 | #endif |
1435 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_PROPS_LATE" ,(long)PDO_FETCH_PROPS_LATE); |
1436 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED" ,(long)PDO_FETCH_NAMED); |
1437 | |
1438 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT" , (long)PDO_ATTR_AUTOCOMMIT); |
1439 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH" , (long)PDO_ATTR_PREFETCH); |
1440 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT" , (long)PDO_ATTR_TIMEOUT); |
1441 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE" , (long)PDO_ATTR_ERRMODE); |
1442 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION" , (long)PDO_ATTR_SERVER_VERSION); |
1443 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION" , (long)PDO_ATTR_CLIENT_VERSION); |
1444 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO" , (long)PDO_ATTR_SERVER_INFO); |
1445 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS" , (long)PDO_ATTR_CONNECTION_STATUS); |
1446 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE" , (long)PDO_ATTR_CASE); |
1447 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME" , (long)PDO_ATTR_CURSOR_NAME); |
1448 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR" , (long)PDO_ATTR_CURSOR); |
1449 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS" , (long)PDO_ATTR_ORACLE_NULLS); |
1450 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT" , (long)PDO_ATTR_PERSISTENT); |
1451 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS" , (long)PDO_ATTR_STATEMENT_CLASS); |
1452 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES" , (long)PDO_ATTR_FETCH_TABLE_NAMES); |
1453 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES" , (long)PDO_ATTR_FETCH_CATALOG_NAMES); |
1454 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME" , (long)PDO_ATTR_DRIVER_NAME); |
1455 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES" ,(long)PDO_ATTR_STRINGIFY_FETCHES); |
1456 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN" ,(long)PDO_ATTR_MAX_COLUMN_LEN); |
1457 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES" ,(long)PDO_ATTR_EMULATE_PREPARES); |
1458 | REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE" ,(long)PDO_ATTR_DEFAULT_FETCH_MODE); |
1459 | |
1460 | REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT" , (long)PDO_ERRMODE_SILENT); |
1461 | REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING" , (long)PDO_ERRMODE_WARNING); |
1462 | REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION" , (long)PDO_ERRMODE_EXCEPTION); |
1463 | |
1464 | REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL" , (long)PDO_CASE_NATURAL); |
1465 | REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER" , (long)PDO_CASE_LOWER); |
1466 | REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER" , (long)PDO_CASE_UPPER); |
1467 | |
1468 | REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL" , (long)PDO_NULL_NATURAL); |
1469 | REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING" , (long)PDO_NULL_EMPTY_STRING); |
1470 | REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING" , (long)PDO_NULL_TO_STRING); |
1471 | |
1472 | REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE" , PDO_ERR_NONE); |
1473 | |
1474 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT" , (long)PDO_FETCH_ORI_NEXT); |
1475 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR" , (long)PDO_FETCH_ORI_PRIOR); |
1476 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST" , (long)PDO_FETCH_ORI_FIRST); |
1477 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST" , (long)PDO_FETCH_ORI_LAST); |
1478 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS" , (long)PDO_FETCH_ORI_ABS); |
1479 | REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL" , (long)PDO_FETCH_ORI_REL); |
1480 | |
1481 | REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY" , (long)PDO_CURSOR_FWDONLY); |
1482 | REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL" , (long)PDO_CURSOR_SCROLL); |
1483 | |
1484 | #if 0 |
1485 | REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP" , (long)PDO_ERR_CANT_MAP); |
1486 | REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX" , (long)PDO_ERR_SYNTAX); |
1487 | REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT" , (long)PDO_ERR_CONSTRAINT); |
1488 | REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND" , (long)PDO_ERR_NOT_FOUND); |
1489 | REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS" , (long)PDO_ERR_ALREADY_EXISTS); |
1490 | REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED" , (long)PDO_ERR_NOT_IMPLEMENTED); |
1491 | REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH" , (long)PDO_ERR_MISMATCH); |
1492 | REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED" , (long)PDO_ERR_TRUNCATED); |
1493 | REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED" , (long)PDO_ERR_DISCONNECTED); |
1494 | REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM" , (long)PDO_ERR_NO_PERM); |
1495 | #endif |
1496 | |
1497 | } |
1498 | |
1499 | static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC) |
1500 | { |
1501 | int i; |
1502 | |
1503 | if (--dbh->refcount) |
1504 | return; |
1505 | |
1506 | if (dbh->query_stmt) { |
1507 | zval_dtor(&dbh->query_stmt_zval); |
1508 | dbh->query_stmt = NULL; |
1509 | } |
1510 | |
1511 | if (dbh->methods) { |
1512 | dbh->methods->closer(dbh TSRMLS_CC); |
1513 | } |
1514 | |
1515 | if (dbh->data_source) { |
1516 | pefree((char *)dbh->data_source, dbh->is_persistent); |
1517 | } |
1518 | if (dbh->username) { |
1519 | pefree(dbh->username, dbh->is_persistent); |
1520 | } |
1521 | if (dbh->password) { |
1522 | pefree(dbh->password, dbh->is_persistent); |
1523 | } |
1524 | |
1525 | if (dbh->persistent_id) { |
1526 | pefree((char *)dbh->persistent_id, dbh->is_persistent); |
1527 | } |
1528 | |
1529 | if (dbh->def_stmt_ctor_args) { |
1530 | zval_ptr_dtor(&dbh->def_stmt_ctor_args); |
1531 | } |
1532 | |
1533 | for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) { |
1534 | if (dbh->cls_methods[i]) { |
1535 | zend_hash_destroy(dbh->cls_methods[i]); |
1536 | pefree(dbh->cls_methods[i], dbh->is_persistent); |
1537 | } |
1538 | } |
1539 | |
1540 | pefree(dbh, dbh->is_persistent); |
1541 | } |
1542 | |
1543 | PDO_API void php_pdo_dbh_addref(pdo_dbh_t *dbh TSRMLS_DC) |
1544 | { |
1545 | dbh->refcount++; |
1546 | } |
1547 | |
1548 | PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh TSRMLS_DC) |
1549 | { |
1550 | dbh_free(dbh TSRMLS_CC); |
1551 | } |
1552 | |
1553 | static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC) |
1554 | { |
1555 | if (dbh->in_txn && dbh->methods && dbh->methods->rollback) { |
1556 | dbh->methods->rollback(dbh TSRMLS_CC); |
1557 | dbh->in_txn = 0; |
1558 | } |
1559 | |
1560 | if (dbh->is_persistent && dbh->methods && dbh->methods->persistent_shutdown) { |
1561 | dbh->methods->persistent_shutdown(dbh TSRMLS_CC); |
1562 | } |
1563 | zend_object_std_dtor(&dbh->std TSRMLS_CC); |
1564 | dbh->std.properties = NULL; |
1565 | dbh->std.properties_table = NULL; |
1566 | dbh_free(dbh TSRMLS_CC); |
1567 | } |
1568 | |
1569 | zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC) |
1570 | { |
1571 | zend_object_value retval; |
1572 | pdo_dbh_t *dbh; |
1573 | |
1574 | dbh = emalloc(sizeof(*dbh)); |
1575 | memset(dbh, 0, sizeof(*dbh)); |
1576 | zend_object_std_init(&dbh->std, ce TSRMLS_CC); |
1577 | object_properties_init(&dbh->std, ce); |
1578 | rebuild_object_properties(&dbh->std); |
1579 | dbh->refcount = 1; |
1580 | dbh->def_stmt_ce = pdo_dbstmt_ce; |
1581 | |
1582 | retval.handle = zend_objects_store_put(dbh, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbh_free_storage, NULL TSRMLS_CC); |
1583 | retval.handlers = &pdo_dbh_object_handlers; |
1584 | |
1585 | return retval; |
1586 | } |
1587 | |
1588 | /* }}} */ |
1589 | |
1590 | ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor) |
1591 | { |
1592 | if (rsrc->ptr) { |
1593 | pdo_dbh_t *dbh = (pdo_dbh_t*)rsrc->ptr; |
1594 | dbh_free(dbh TSRMLS_CC); |
1595 | rsrc->ptr = NULL; |
1596 | } |
1597 | } |
1598 | |
1599 | /* |
1600 | * Local variables: |
1601 | * tab-width: 4 |
1602 | * c-basic-offset: 4 |
1603 | * End: |
1604 | * vim600: noet sw=4 ts=4 fdm=marker |
1605 | * vim<600: noet sw=4 ts=4 |
1606 | */ |
1607 | |