Back to index

php5  5.3.10
pdo.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Wez Furlong <wez@php.net>                                    |
00016   |         Marcus Boerger <helly@php.net>                               |
00017   |         Sterling Hughes <sterling@php.net>                           |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: pdo.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include <ctype.h>
00028 #include "php.h"
00029 #include "php_ini.h"
00030 #include "ext/standard/info.h"
00031 #include "php_pdo.h"
00032 #include "php_pdo_driver.h"
00033 #include "php_pdo_int.h"
00034 #include "zend_exceptions.h"
00035 
00036 static zend_class_entry *spl_ce_RuntimeException;
00037 
00038 ZEND_DECLARE_MODULE_GLOBALS(pdo)
00039 static PHP_GINIT_FUNCTION(pdo);
00040 
00041 /* True global resources - no need for thread safety here */
00042 
00043 /* the registry of PDO drivers */
00044 HashTable pdo_driver_hash;
00045 
00046 /* we use persistent resources for the driver connection stuff */
00047 static int le_ppdo;
00048 
00049 int php_pdo_list_entry(void)
00050 {
00051        return le_ppdo;
00052 }
00053 
00054 /* for exceptional circumstances */
00055 zend_class_entry *pdo_exception_ce;
00056 
00057 PDO_API zend_class_entry *php_pdo_get_dbh_ce(void)
00058 {
00059        return pdo_dbh_ce;
00060 }
00061 
00062 PDO_API zend_class_entry *php_pdo_get_exception(void)
00063 {
00064        return pdo_exception_ce;
00065 }
00066 
00067 PDO_API char *php_pdo_str_tolower_dup(const char *src, int len)
00068 {
00069        char *dest = emalloc(len + 1);
00070        zend_str_tolower_copy(dest, src, len);
00071        return dest;
00072 }
00073 
00074 PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC)
00075 {
00076 #if can_handle_soft_dependency_on_SPL && defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
00077        if (!root) {
00078               if (!spl_ce_RuntimeException) {
00079                      zend_class_entry **pce;
00080 
00081                      if (zend_hash_find(CG(class_table), "runtimeexception", sizeof("RuntimeException"), (void **) &pce) == SUCCESS) {
00082                             spl_ce_RuntimeException = *pce;
00083                             return *pce;
00084                      }
00085               } else {
00086                      return spl_ce_RuntimeException;
00087               }
00088        }
00089 #endif
00090 #if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2)
00091        return zend_exception_get_default();
00092 #else
00093        return zend_exception_get_default(TSRMLS_C);
00094 #endif
00095 }
00096 
00097 zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce;
00098 
00099 /* {{{ proto array pdo_drivers()
00100  Return array of available PDO drivers */
00101 PHP_FUNCTION(pdo_drivers)
00102 {
00103        HashPosition pos;
00104        pdo_driver_t **pdriver;
00105 
00106        if (zend_parse_parameters_none() == FAILURE) {
00107               return;
00108        }
00109        
00110        array_init(return_value);
00111 
00112        zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
00113        while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
00114               add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1);
00115               zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
00116        }
00117 }
00118 /* }}} */
00119 
00120 /* {{{ arginfo */
00121 ZEND_BEGIN_ARG_INFO(arginfo_pdo_drivers, 0)
00122 ZEND_END_ARG_INFO()
00123 /* }}} */
00124 
00125 /* {{{ pdo_functions[] */
00126 const zend_function_entry pdo_functions[] = {
00127        PHP_FE(pdo_drivers,             arginfo_pdo_drivers)
00128        PHP_FE_END
00129 };
00130 /* }}} */
00131 
00132 /* {{{ pdo_functions[] */
00133 #if ZEND_MODULE_API_NO >= 20050922
00134 static const zend_module_dep pdo_deps[] = {
00135 #ifdef HAVE_SPL
00136        ZEND_MOD_REQUIRED("spl")
00137 #endif
00138        ZEND_MOD_END
00139 };
00140 #endif
00141 /* }}} */
00142 
00143 /* {{{ pdo_module_entry */
00144 zend_module_entry pdo_module_entry = {
00145 #if ZEND_MODULE_API_NO >= 20050922
00146        STANDARD_MODULE_HEADER_EX, NULL,
00147        pdo_deps,
00148 #else
00149        STANDARD_MODULE_HEADER,
00150 #endif
00151        "PDO",
00152        pdo_functions,
00153        PHP_MINIT(pdo),
00154        PHP_MSHUTDOWN(pdo),
00155        NULL,
00156        NULL,
00157        PHP_MINFO(pdo),
00158        "1.0.4dev",
00159        PHP_MODULE_GLOBALS(pdo),
00160        PHP_GINIT(pdo),
00161        NULL,
00162        NULL,
00163        STANDARD_MODULE_PROPERTIES_EX
00164 };
00165 /* }}} */
00166 
00167 /* TODO: visit persistent handles: for each persistent statement handle,
00168  * remove bound parameter associations */
00169 
00170 #ifdef COMPILE_DL_PDO
00171 ZEND_GET_MODULE(pdo)
00172 #endif
00173 
00174 /* {{{ PHP_GINIT_FUNCTION */
00175 static PHP_GINIT_FUNCTION(pdo)
00176 {
00177        pdo_globals->global_value = 0;
00178 }
00179 /* }}} */
00180 
00181 PDO_API int php_pdo_register_driver(pdo_driver_t *driver)
00182 {
00183        if (driver->api_version != PDO_DRIVER_API) {
00184               zend_error(E_ERROR, "PDO: driver %s requires PDO API version %ld; this is PDO version %d",
00185                      driver->driver_name, driver->api_version, PDO_DRIVER_API);
00186               return FAILURE;
00187        }
00188        if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
00189               zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
00190               return FAILURE;      /* NOTREACHED */
00191        }
00192 
00193        return zend_hash_add(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len,
00194                      (void**)&driver, sizeof(pdo_driver_t *), NULL);
00195 }
00196 
00197 PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver)
00198 {
00199        if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
00200               return;
00201        }
00202 
00203        zend_hash_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len);
00204 }
00205 
00206 pdo_driver_t *pdo_find_driver(const char *name, int namelen)
00207 {
00208        pdo_driver_t **driver = NULL;
00209        
00210        zend_hash_find(&pdo_driver_hash, (char*)name, namelen, (void**)&driver);
00211 
00212        return driver ? *driver : NULL;
00213 }
00214 
00215 PDO_API int php_pdo_parse_data_source(const char *data_source,
00216               unsigned long data_source_len, struct pdo_data_src_parser *parsed,
00217               int nparams)
00218 {
00219        int i, j;
00220        int valstart = -1;
00221        int semi = -1;
00222        int optstart = 0;
00223        int nlen;
00224        int n_matches = 0;
00225        int n_semicolumns = 0;
00226 
00227        i = 0;
00228        while (i < data_source_len) {
00229               /* looking for NAME= */
00230 
00231               if (data_source[i] == '\0') {
00232                      break;
00233               }
00234 
00235               if (data_source[i] != '=') {
00236                      ++i;
00237                      continue;
00238               }
00239 
00240               valstart = ++i;
00241 
00242               /* now we're looking for VALUE; or just VALUE<NUL> */
00243               semi = -1;
00244               n_semicolumns = 0;
00245               while (i < data_source_len) {
00246                      if (data_source[i] == '\0') {
00247                             semi = i++;
00248                             break;
00249                      }
00250                      if (data_source[i] == ';') {
00251                             if ((i + 1 >= data_source_len) || data_source[i+1] != ';') {
00252                                    semi = i++;
00253                                    break;
00254                             } else {
00255                                    n_semicolumns++; 
00256                                    i += 2;
00257                                    continue;
00258                             }
00259                      }
00260                      ++i;
00261               }
00262 
00263               if (semi == -1) {
00264                      semi = i;
00265               }
00266 
00267               /* find the entry in the array */
00268               nlen = valstart - optstart - 1;
00269               for (j = 0; j < nparams; j++) {
00270                      if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
00271                             /* got a match */
00272                             if (parsed[j].freeme) {
00273                                    efree(parsed[j].optval);
00274                             }
00275 
00276                             if (n_semicolumns == 0) {
00277                                    parsed[j].optval = estrndup(data_source + valstart, semi - valstart - n_semicolumns);
00278                             } else {
00279                                    int vlen = semi - valstart;
00280                                    char *orig_val = data_source + valstart;
00281                                    char *new_val  = (char *) emalloc(vlen - n_semicolumns + 1);
00282                             
00283                                    parsed[j].optval = new_val;
00284 
00285                                    while (vlen && *orig_val) {
00286                                           *new_val = *orig_val;
00287                                           new_val++;
00288 
00289                                           if (*orig_val == ';') {
00290                                                  orig_val+=2; 
00291                                                  vlen-=2;
00292                                           } else {
00293                                                  orig_val++;
00294                                                  vlen--;
00295                                           }
00296                                    }
00297                                    *new_val = '\0';
00298                             }
00299 
00300                             parsed[j].freeme = 1;
00301                             ++n_matches;
00302                             break;
00303                      }
00304               }
00305 
00306               while (i < data_source_len && isspace(data_source[i])) {
00307                      i++;
00308               }
00309 
00310               optstart = i;
00311        }
00312 
00313        return n_matches;
00314 }
00315 
00316 static const char digit_vec[] = "0123456789";
00317 PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC)
00318 {
00319        char buffer[65];
00320        char outbuf[65] = "";
00321        register char *p;
00322        long long_val;
00323        char *dst = outbuf;
00324 
00325        if (i64 < 0) {
00326               i64 = -i64;
00327               *dst++ = '-';
00328        }
00329 
00330        if (i64 == 0) {
00331               *dst++ = '0';
00332               *dst++ = '\0';
00333               return estrdup(outbuf);
00334        }
00335 
00336        p = &buffer[sizeof(buffer)-1];
00337        *p = '\0';
00338 
00339        while ((pdo_uint64_t)i64 > (pdo_uint64_t)LONG_MAX) {
00340               pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10;
00341               unsigned int rem = (unsigned int)(i64 - quo*10U);
00342               *--p = digit_vec[rem];
00343               i64 = (pdo_int64_t)quo;
00344        }
00345        long_val = (long)i64;
00346        while (long_val != 0) {
00347               long quo = long_val / 10;
00348               *--p = digit_vec[(unsigned int)(long_val - quo * 10)];
00349               long_val = quo;
00350        }
00351        while ((*dst++ = *p++) != 0)
00352               ;
00353        *dst = '\0';
00354        return estrdup(outbuf);
00355 }
00356 
00357 /* {{{ PHP_MINIT_FUNCTION */
00358 PHP_MINIT_FUNCTION(pdo)
00359 {
00360        zend_class_entry ce;
00361 
00362        spl_ce_RuntimeException = NULL;
00363 
00364        if (FAILURE == pdo_sqlstate_init_error_table()) {
00365               return FAILURE;
00366        }
00367 
00368        zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
00369 
00370        le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
00371               "PDO persistent database", module_number);
00372 
00373        INIT_CLASS_ENTRY(ce, "PDOException", NULL);
00374 
00375        pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC);
00376 
00377        zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
00378 
00379        pdo_dbh_init(TSRMLS_C);
00380        pdo_stmt_init(TSRMLS_C);
00381 
00382        return SUCCESS;
00383 }
00384 /* }}} */
00385 
00386 /* {{{ PHP_MSHUTDOWN_FUNCTION */
00387 PHP_MSHUTDOWN_FUNCTION(pdo)
00388 {
00389        zend_hash_destroy(&pdo_driver_hash);
00390        pdo_sqlstate_fini_error_table();
00391        return SUCCESS;
00392 }
00393 /* }}} */
00394 
00395 /* {{{ PHP_MINFO_FUNCTION */
00396 PHP_MINFO_FUNCTION(pdo)
00397 {
00398        HashPosition pos;
00399        char *drivers = NULL, *ldrivers = estrdup("");
00400        pdo_driver_t **pdriver;
00401        
00402        php_info_print_table_start();
00403        php_info_print_table_header(2, "PDO support", "enabled");
00404 
00405        zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
00406        while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
00407               spprintf(&drivers, 0, "%s, %s", ldrivers, (*pdriver)->driver_name);
00408               zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
00409               efree(ldrivers);
00410               ldrivers = drivers;
00411        }
00412        
00413        php_info_print_table_row(2, "PDO drivers", drivers ? drivers+2 : "");
00414 
00415        if (drivers) {
00416               efree(drivers);
00417        } else {
00418               efree(ldrivers);
00419        }
00420 
00421        php_info_print_table_end();
00422 
00423 }
00424 /* }}} */
00425 
00426 /*
00427  * Local variables:
00428  * tab-width: 4
00429  * c-basic-offset: 4
00430  * End:
00431  * vim600: noet sw=4 ts=4 fdm=marker
00432  * vim<600: noet sw=4 ts=4
00433  */