Return to pdo.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / pdo |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 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: pdo.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 22: ! 23: #ifdef HAVE_CONFIG_H ! 24: #include "config.h" ! 25: #endif ! 26: ! 27: #include <ctype.h> ! 28: #include "php.h" ! 29: #include "php_ini.h" ! 30: #include "ext/standard/info.h" ! 31: #include "php_pdo.h" ! 32: #include "php_pdo_driver.h" ! 33: #include "php_pdo_int.h" ! 34: #include "zend_exceptions.h" ! 35: ! 36: static zend_class_entry *spl_ce_RuntimeException; ! 37: ! 38: ZEND_DECLARE_MODULE_GLOBALS(pdo) ! 39: static PHP_GINIT_FUNCTION(pdo); ! 40: ! 41: /* True global resources - no need for thread safety here */ ! 42: ! 43: /* the registry of PDO drivers */ ! 44: HashTable pdo_driver_hash; ! 45: ! 46: /* we use persistent resources for the driver connection stuff */ ! 47: static int le_ppdo; ! 48: ! 49: int php_pdo_list_entry(void) ! 50: { ! 51: return le_ppdo; ! 52: } ! 53: ! 54: /* for exceptional circumstances */ ! 55: zend_class_entry *pdo_exception_ce; ! 56: ! 57: PDO_API zend_class_entry *php_pdo_get_dbh_ce(void) ! 58: { ! 59: return pdo_dbh_ce; ! 60: } ! 61: ! 62: PDO_API zend_class_entry *php_pdo_get_exception(void) ! 63: { ! 64: return pdo_exception_ce; ! 65: } ! 66: ! 67: PDO_API char *php_pdo_str_tolower_dup(const char *src, int len) ! 68: { ! 69: char *dest = emalloc(len + 1); ! 70: zend_str_tolower_copy(dest, src, len); ! 71: return dest; ! 72: } ! 73: ! 74: PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC) ! 75: { ! 76: #if can_handle_soft_dependency_on_SPL && defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)) ! 77: if (!root) { ! 78: if (!spl_ce_RuntimeException) { ! 79: zend_class_entry **pce; ! 80: ! 81: if (zend_hash_find(CG(class_table), "runtimeexception", sizeof("RuntimeException"), (void **) &pce) == SUCCESS) { ! 82: spl_ce_RuntimeException = *pce; ! 83: return *pce; ! 84: } ! 85: } else { ! 86: return spl_ce_RuntimeException; ! 87: } ! 88: } ! 89: #endif ! 90: #if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2) ! 91: return zend_exception_get_default(); ! 92: #else ! 93: return zend_exception_get_default(TSRMLS_C); ! 94: #endif ! 95: } ! 96: ! 97: zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce; ! 98: ! 99: /* {{{ proto array pdo_drivers() ! 100: Return array of available PDO drivers */ ! 101: PHP_FUNCTION(pdo_drivers) ! 102: { ! 103: HashPosition pos; ! 104: pdo_driver_t **pdriver; ! 105: ! 106: if (zend_parse_parameters_none() == FAILURE) { ! 107: return; ! 108: } ! 109: ! 110: array_init(return_value); ! 111: ! 112: zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos); ! 113: while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) { ! 114: add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1); ! 115: zend_hash_move_forward_ex(&pdo_driver_hash, &pos); ! 116: } ! 117: } ! 118: /* }}} */ ! 119: ! 120: /* {{{ arginfo */ ! 121: ZEND_BEGIN_ARG_INFO(arginfo_pdo_drivers, 0) ! 122: ZEND_END_ARG_INFO() ! 123: /* }}} */ ! 124: ! 125: /* {{{ pdo_functions[] */ ! 126: const zend_function_entry pdo_functions[] = { ! 127: PHP_FE(pdo_drivers, arginfo_pdo_drivers) ! 128: PHP_FE_END ! 129: }; ! 130: /* }}} */ ! 131: ! 132: /* {{{ pdo_functions[] */ ! 133: #if ZEND_MODULE_API_NO >= 20050922 ! 134: static const zend_module_dep pdo_deps[] = { ! 135: #ifdef HAVE_SPL ! 136: ZEND_MOD_REQUIRED("spl") ! 137: #endif ! 138: ZEND_MOD_END ! 139: }; ! 140: #endif ! 141: /* }}} */ ! 142: ! 143: /* {{{ pdo_module_entry */ ! 144: zend_module_entry pdo_module_entry = { ! 145: #if ZEND_MODULE_API_NO >= 20050922 ! 146: STANDARD_MODULE_HEADER_EX, NULL, ! 147: pdo_deps, ! 148: #else ! 149: STANDARD_MODULE_HEADER, ! 150: #endif ! 151: "PDO", ! 152: pdo_functions, ! 153: PHP_MINIT(pdo), ! 154: PHP_MSHUTDOWN(pdo), ! 155: NULL, ! 156: NULL, ! 157: PHP_MINFO(pdo), ! 158: "1.0.4dev", ! 159: PHP_MODULE_GLOBALS(pdo), ! 160: PHP_GINIT(pdo), ! 161: NULL, ! 162: NULL, ! 163: STANDARD_MODULE_PROPERTIES_EX ! 164: }; ! 165: /* }}} */ ! 166: ! 167: /* TODO: visit persistent handles: for each persistent statement handle, ! 168: * remove bound parameter associations */ ! 169: ! 170: #ifdef COMPILE_DL_PDO ! 171: ZEND_GET_MODULE(pdo) ! 172: #endif ! 173: ! 174: /* {{{ PHP_GINIT_FUNCTION */ ! 175: static PHP_GINIT_FUNCTION(pdo) ! 176: { ! 177: pdo_globals->global_value = 0; ! 178: } ! 179: /* }}} */ ! 180: ! 181: PDO_API int php_pdo_register_driver(pdo_driver_t *driver) ! 182: { ! 183: if (driver->api_version != PDO_DRIVER_API) { ! 184: zend_error(E_ERROR, "PDO: driver %s requires PDO API version %ld; this is PDO version %d", ! 185: driver->driver_name, driver->api_version, PDO_DRIVER_API); ! 186: return FAILURE; ! 187: } ! 188: if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) { ! 189: zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers"); ! 190: return FAILURE; /* NOTREACHED */ ! 191: } ! 192: ! 193: return zend_hash_add(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len, ! 194: (void**)&driver, sizeof(pdo_driver_t *), NULL); ! 195: } ! 196: ! 197: PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver) ! 198: { ! 199: if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) { ! 200: return; ! 201: } ! 202: ! 203: zend_hash_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len); ! 204: } ! 205: ! 206: pdo_driver_t *pdo_find_driver(const char *name, int namelen) ! 207: { ! 208: pdo_driver_t **driver = NULL; ! 209: ! 210: zend_hash_find(&pdo_driver_hash, (char*)name, namelen, (void**)&driver); ! 211: ! 212: return driver ? *driver : NULL; ! 213: } ! 214: ! 215: PDO_API int php_pdo_parse_data_source(const char *data_source, ! 216: unsigned long data_source_len, struct pdo_data_src_parser *parsed, ! 217: int nparams) ! 218: { ! 219: int i, j; ! 220: int valstart = -1; ! 221: int semi = -1; ! 222: int optstart = 0; ! 223: int nlen; ! 224: int n_matches = 0; ! 225: int n_semicolumns = 0; ! 226: ! 227: i = 0; ! 228: while (i < data_source_len) { ! 229: /* looking for NAME= */ ! 230: ! 231: if (data_source[i] == '\0') { ! 232: break; ! 233: } ! 234: ! 235: if (data_source[i] != '=') { ! 236: ++i; ! 237: continue; ! 238: } ! 239: ! 240: valstart = ++i; ! 241: ! 242: /* now we're looking for VALUE; or just VALUE<NUL> */ ! 243: semi = -1; ! 244: n_semicolumns = 0; ! 245: while (i < data_source_len) { ! 246: if (data_source[i] == '\0') { ! 247: semi = i++; ! 248: break; ! 249: } ! 250: if (data_source[i] == ';') { ! 251: if ((i + 1 >= data_source_len) || data_source[i+1] != ';') { ! 252: semi = i++; ! 253: break; ! 254: } else { ! 255: n_semicolumns++; ! 256: i += 2; ! 257: continue; ! 258: } ! 259: } ! 260: ++i; ! 261: } ! 262: ! 263: if (semi == -1) { ! 264: semi = i; ! 265: } ! 266: ! 267: /* find the entry in the array */ ! 268: nlen = valstart - optstart - 1; ! 269: for (j = 0; j < nparams; j++) { ! 270: if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') { ! 271: /* got a match */ ! 272: if (parsed[j].freeme) { ! 273: efree(parsed[j].optval); ! 274: } ! 275: ! 276: if (n_semicolumns == 0) { ! 277: parsed[j].optval = estrndup(data_source + valstart, semi - valstart - n_semicolumns); ! 278: } else { ! 279: int vlen = semi - valstart; ! 280: char *orig_val = data_source + valstart; ! 281: char *new_val = (char *) emalloc(vlen - n_semicolumns + 1); ! 282: ! 283: parsed[j].optval = new_val; ! 284: ! 285: while (vlen && *orig_val) { ! 286: *new_val = *orig_val; ! 287: new_val++; ! 288: ! 289: if (*orig_val == ';') { ! 290: orig_val+=2; ! 291: vlen-=2; ! 292: } else { ! 293: orig_val++; ! 294: vlen--; ! 295: } ! 296: } ! 297: *new_val = '\0'; ! 298: } ! 299: ! 300: parsed[j].freeme = 1; ! 301: ++n_matches; ! 302: break; ! 303: } ! 304: } ! 305: ! 306: while (i < data_source_len && isspace(data_source[i])) { ! 307: i++; ! 308: } ! 309: ! 310: optstart = i; ! 311: } ! 312: ! 313: return n_matches; ! 314: } ! 315: ! 316: static const char digit_vec[] = "0123456789"; ! 317: PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC) ! 318: { ! 319: char buffer[65]; ! 320: char outbuf[65] = ""; ! 321: register char *p; ! 322: long long_val; ! 323: char *dst = outbuf; ! 324: ! 325: if (i64 < 0) { ! 326: i64 = -i64; ! 327: *dst++ = '-'; ! 328: } ! 329: ! 330: if (i64 == 0) { ! 331: *dst++ = '0'; ! 332: *dst++ = '\0'; ! 333: return estrdup(outbuf); ! 334: } ! 335: ! 336: p = &buffer[sizeof(buffer)-1]; ! 337: *p = '\0'; ! 338: ! 339: while ((pdo_uint64_t)i64 > (pdo_uint64_t)LONG_MAX) { ! 340: pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10; ! 341: unsigned int rem = (unsigned int)(i64 - quo*10U); ! 342: *--p = digit_vec[rem]; ! 343: i64 = (pdo_int64_t)quo; ! 344: } ! 345: long_val = (long)i64; ! 346: while (long_val != 0) { ! 347: long quo = long_val / 10; ! 348: *--p = digit_vec[(unsigned int)(long_val - quo * 10)]; ! 349: long_val = quo; ! 350: } ! 351: while ((*dst++ = *p++) != 0) ! 352: ; ! 353: *dst = '\0'; ! 354: return estrdup(outbuf); ! 355: } ! 356: ! 357: /* {{{ PHP_MINIT_FUNCTION */ ! 358: PHP_MINIT_FUNCTION(pdo) ! 359: { ! 360: zend_class_entry ce; ! 361: ! 362: spl_ce_RuntimeException = NULL; ! 363: ! 364: if (FAILURE == pdo_sqlstate_init_error_table()) { ! 365: return FAILURE; ! 366: } ! 367: ! 368: zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1); ! 369: ! 370: le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor, ! 371: "PDO persistent database", module_number); ! 372: ! 373: INIT_CLASS_ENTRY(ce, "PDOException", NULL); ! 374: ! 375: pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC); ! 376: ! 377: zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC); ! 378: ! 379: pdo_dbh_init(TSRMLS_C); ! 380: pdo_stmt_init(TSRMLS_C); ! 381: ! 382: return SUCCESS; ! 383: } ! 384: /* }}} */ ! 385: ! 386: /* {{{ PHP_MSHUTDOWN_FUNCTION */ ! 387: PHP_MSHUTDOWN_FUNCTION(pdo) ! 388: { ! 389: zend_hash_destroy(&pdo_driver_hash); ! 390: pdo_sqlstate_fini_error_table(); ! 391: return SUCCESS; ! 392: } ! 393: /* }}} */ ! 394: ! 395: /* {{{ PHP_MINFO_FUNCTION */ ! 396: PHP_MINFO_FUNCTION(pdo) ! 397: { ! 398: HashPosition pos; ! 399: char *drivers = NULL, *ldrivers = estrdup(""); ! 400: pdo_driver_t **pdriver; ! 401: ! 402: php_info_print_table_start(); ! 403: php_info_print_table_header(2, "PDO support", "enabled"); ! 404: ! 405: zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos); ! 406: while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) { ! 407: spprintf(&drivers, 0, "%s, %s", ldrivers, (*pdriver)->driver_name); ! 408: zend_hash_move_forward_ex(&pdo_driver_hash, &pos); ! 409: efree(ldrivers); ! 410: ldrivers = drivers; ! 411: } ! 412: ! 413: php_info_print_table_row(2, "PDO drivers", drivers ? drivers+2 : ""); ! 414: ! 415: if (drivers) { ! 416: efree(drivers); ! 417: } else { ! 418: efree(ldrivers); ! 419: } ! 420: ! 421: php_info_print_table_end(); ! 422: ! 423: } ! 424: /* }}} */ ! 425: ! 426: /* ! 427: * Local variables: ! 428: * tab-width: 4 ! 429: * c-basic-offset: 4 ! 430: * End: ! 431: * vim600: noet sw=4 ts=4 fdm=marker ! 432: * vim<600: noet sw=4 ts=4 ! 433: */