Annotation of embedaddon/php/ext/pdo_mysql/mysql_driver.c, revision 1.1.1.1

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: George Schlossnagle <george@omniti.com>                      |
                     16:   |         Wez Furlong <wez@php.net>                                    |
                     17:   |         Johannes Schlueter <johannes@mysql.com>                      |
                     18:   +----------------------------------------------------------------------+
                     19: */
                     20: 
                     21: /* $Id: mysql_driver.c 321634 2012-01-01 13:15:04Z felipe $ */
                     22: 
                     23: #ifdef HAVE_CONFIG_H
                     24: #include "config.h"
                     25: #endif
                     26: 
                     27: #include "php.h"
                     28: #include "php_ini.h"
                     29: #include "ext/standard/info.h"
                     30: #include "pdo/php_pdo.h"
                     31: #include "pdo/php_pdo_driver.h"
                     32: #include "php_pdo_mysql.h"
                     33: #include "php_pdo_mysql_int.h"
                     34: #ifndef PDO_USE_MYSQLND
                     35: #include <mysqld_error.h>
                     36: #endif
                     37: #include "zend_exceptions.h"
                     38: 
                     39: #if PDO_USE_MYSQLND
                     40: #      define pdo_mysql_init(persistent) mysqlnd_init(persistent)
                     41: #else
                     42: #      define pdo_mysql_init(persistent) mysql_init(NULL)
                     43: #endif
                     44: 
                     45: #if !defined(HAVE_MYSQL_SQLSTATE) && !defined(PDO_USE_MYSQLND)
                     46: static const char *pdo_mysql_get_sqlstate(unsigned int my_errno) { /* {{{ */
                     47:        switch (my_errno) {
                     48:                /* import auto-generated case: code */
                     49: #include "php_pdo_mysql_sqlstate.h"
                     50:        default: return "HY000";
                     51:        }
                     52: }
                     53: /* }}} */
                     54: #endif
                     55: 
                     56: /* {{{ _pdo_mysql_error */
                     57: int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC)
                     58: {
                     59:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                     60:        pdo_error_type *pdo_err; 
                     61:        pdo_mysql_error_info *einfo;
                     62:        pdo_mysql_stmt *S = NULL;
                     63: 
                     64:        PDO_DBG_ENTER("_pdo_mysql_error");
                     65:        PDO_DBG_INF_FMT("file=%s line=%d", file, line);
                     66:        if (stmt) {
                     67:                S = (pdo_mysql_stmt*)stmt->driver_data;
                     68:                pdo_err = &stmt->error_code;
                     69:                einfo   = &S->einfo;
                     70:        } else {
                     71:                pdo_err = &dbh->error_code;
                     72:                einfo   = &H->einfo;
                     73:        }
                     74: 
                     75: #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
                     76:        if (S && S->stmt) {
                     77:                einfo->errcode = mysql_stmt_errno(S->stmt);
                     78:        }
                     79:        else
                     80: #endif
                     81:        {
                     82:                einfo->errcode = mysql_errno(H->server);
                     83:        }
                     84: 
                     85:        einfo->file = file;
                     86:        einfo->line = line;
                     87: 
                     88:        if (einfo->errmsg) {
                     89:                pefree(einfo->errmsg, dbh->is_persistent);
                     90:                einfo->errmsg = NULL;
                     91:        }
                     92: 
                     93:        if (einfo->errcode) {
                     94:                if (einfo->errcode == 2014) {
                     95:                        einfo->errmsg = pestrdup(
                     96:                                "Cannot execute queries while other unbuffered queries are active.  "
                     97:                                "Consider using PDOStatement::fetchAll().  Alternatively, if your code "
                     98:                                "is only ever going to run against mysql, you may enable query "
                     99:                                "buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.",
                    100:                                dbh->is_persistent);
                    101:                } else if (einfo->errcode == 2057) {
                    102:                        einfo->errmsg = pestrdup(
                    103:                                "A stored procedure returning result sets of different size was called. "
                    104:                                "This is not supported by libmysql",
                    105:                                dbh->is_persistent);
                    106: 
                    107:                } else {
                    108:                        einfo->errmsg = pestrdup(mysql_error(H->server), dbh->is_persistent);
                    109:                }
                    110:        } else { /* no error */
                    111:                strcpy(*pdo_err, PDO_ERR_NONE);
                    112:                PDO_DBG_RETURN(0);
                    113:        }
                    114: 
                    115: #if defined(HAVE_MYSQL_SQLSTATE) || defined(PDO_USE_MYSQLND)
                    116: # if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
                    117:        if (S && S->stmt) {
                    118:                strcpy(*pdo_err, mysql_stmt_sqlstate(S->stmt));
                    119:        } else
                    120: # endif
                    121:        {
                    122:                strcpy(*pdo_err, mysql_sqlstate(H->server));
                    123:        }
                    124: #else
                    125:        strcpy(*pdo_err, pdo_mysql_get_sqlstate(einfo->errcode));
                    126: #endif
                    127: 
                    128:        if (!dbh->methods) {
                    129:                PDO_DBG_INF("Throwing exception");
                    130:                zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
                    131:                                *pdo_err, einfo->errcode, einfo->errmsg);
                    132:        }
                    133: 
                    134:        PDO_DBG_RETURN(einfo->errcode);
                    135: }
                    136: /* }}} */
                    137: 
                    138: /* {{{ pdo_mysql_fetch_error_func */
                    139: static int pdo_mysql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
                    140: {
                    141:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    142:        pdo_mysql_error_info *einfo = &H->einfo;
                    143: 
                    144:        PDO_DBG_ENTER("pdo_mysql_fetch_error_func");
                    145:        PDO_DBG_INF_FMT("dbh=%p stmt=%p", dbh, stmt);
                    146:        if (stmt) {
                    147:                pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
                    148:                einfo = &S->einfo;
                    149:        } else {
                    150:                einfo = &H->einfo;
                    151:        }
                    152: 
                    153:        if (einfo->errcode) {
                    154:                add_next_index_long(info, einfo->errcode);
                    155:                add_next_index_string(info, einfo->errmsg, 1);
                    156:        }
                    157: 
                    158:        PDO_DBG_RETURN(1);
                    159: }
                    160: /* }}} */
                    161: 
                    162: /* {{{ mysql_handle_closer */
                    163: static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
                    164: {
                    165:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    166:        
                    167:        PDO_DBG_ENTER("mysql_handle_closer");
                    168:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    169:        if (H) {
                    170:                if (H->server) {
                    171:                        mysql_close(H->server);
                    172:                        H->server = NULL;
                    173:                }
                    174:                if (H->einfo.errmsg) {
                    175:                        pefree(H->einfo.errmsg, dbh->is_persistent);
                    176:                        H->einfo.errmsg = NULL;
                    177:                }
                    178:                pefree(H, dbh->is_persistent);
                    179:                dbh->driver_data = NULL;
                    180:        }
                    181:        PDO_DBG_RETURN(0);
                    182: }
                    183: /* }}} */
                    184: 
                    185: /* {{{ mysql_handle_preparer */
                    186: static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
                    187: {
                    188:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    189:        pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
                    190: #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
                    191:        char *nsql = NULL;
                    192:        int nsql_len = 0;
                    193:        int ret;
                    194:        int server_version;
                    195: #endif
                    196:        
                    197:        PDO_DBG_ENTER("mysql_handle_preparer");
                    198:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    199:        PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
                    200: 
                    201:        S->H = H;
                    202:        stmt->driver_data = S;
                    203:        stmt->methods = &mysql_stmt_methods;
                    204: 
                    205:        if (H->emulate_prepare) {
                    206:                goto end;
                    207:        }
                    208: 
                    209: #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
                    210:        server_version = mysql_get_server_version(H->server);
                    211:        if (server_version < 40100) {
                    212:                goto fallback;
                    213:        }
                    214:        stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
                    215:        ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
                    216: 
                    217:        if (ret == 1) {
                    218:                /* query was rewritten */
                    219:                sql = nsql;
                    220:                sql_len = nsql_len;
                    221:        } else if (ret == -1) {
                    222:                /* failed to parse */
                    223:                strcpy(dbh->error_code, stmt->error_code);
                    224:                PDO_DBG_RETURN(0);
                    225:        }
                    226: 
                    227:        if (!(S->stmt = mysql_stmt_init(H->server))) {
                    228:                pdo_mysql_error(dbh);
                    229:                if (nsql) {
                    230:                        efree(nsql);
                    231:                }
                    232:                PDO_DBG_RETURN(0);
                    233:        }
                    234:        
                    235:        if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
                    236:                /* TODO: might need to pull statement specific info here? */
                    237:                /* if the query isn't supported by the protocol, fallback to emulation */
                    238:                if (mysql_errno(H->server) == 1295) {
                    239:                        if (nsql) {
                    240:                                efree(nsql);
                    241:                        }
                    242:                        goto fallback;
                    243:                }
                    244:                pdo_mysql_error(dbh);
                    245:                if (nsql) {
                    246:                        efree(nsql);
                    247:                }
                    248:                PDO_DBG_RETURN(0);
                    249:        }
                    250:        if (nsql) {
                    251:                efree(nsql);
                    252:        }
                    253: 
                    254:        S->num_params = mysql_stmt_param_count(S->stmt);
                    255: 
                    256:        if (S->num_params) {
                    257:                S->params_given = 0;
                    258: #ifdef PDO_USE_MYSQLND
                    259:                S->params = NULL;
                    260: #else
                    261:                S->params = ecalloc(S->num_params, sizeof(MYSQL_BIND));
                    262:                S->in_null = ecalloc(S->num_params, sizeof(my_bool));
                    263:                S->in_length = ecalloc(S->num_params, sizeof(unsigned long));
                    264: #endif
                    265:        }
                    266:        dbh->alloc_own_columns = 1;
                    267: 
                    268:        S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
                    269: 
                    270:        PDO_DBG_RETURN(1);
                    271: 
                    272: fallback:
                    273: #endif
                    274: end:
                    275:        stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
                    276:        
                    277:        PDO_DBG_RETURN(1);
                    278: }
                    279: /* }}} */
                    280: 
                    281: /* {{{ mysql_handle_doer */
                    282: static long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
                    283: {
                    284:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    285:        PDO_DBG_ENTER("mysql_handle_doer");
                    286:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    287:        PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
                    288: 
                    289:        if (mysql_real_query(H->server, sql, sql_len)) {
                    290:                pdo_mysql_error(dbh);
                    291:                PDO_DBG_RETURN(-1);
                    292:        } else {
                    293:                my_ulonglong c = mysql_affected_rows(H->server);
                    294:                if (c == (my_ulonglong) -1) {
                    295:                        pdo_mysql_error(dbh);
                    296:                        PDO_DBG_RETURN(H->einfo.errcode ? -1 : 0);
                    297:                } else {
                    298: 
                    299: #if defined(HAVE_MYSQL_NEXT_RESULT) || defined(PDO_USE_MYSQLND)
                    300:                        /* MULTI_QUERY support - eat up all unfetched result sets */
                    301:                        MYSQL_RES* result;
                    302:                        while (mysql_more_results(H->server)) {
                    303:                                if (mysql_next_result(H->server)) {
                    304:                                        PDO_DBG_RETURN(1);
                    305:                                }
                    306:                                result = mysql_store_result(H->server);
                    307:                                if (result) {
                    308:                                        mysql_free_result(result);
                    309:                                }
                    310:                        }
                    311: #endif
                    312:                        PDO_DBG_RETURN((int)c);
                    313:                }
                    314:        }
                    315: }
                    316: /* }}} */
                    317: 
                    318: /* {{{ pdo_mysql_last_insert_id */
                    319: static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
                    320: {
                    321:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    322:        char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
                    323:        PDO_DBG_ENTER("pdo_mysql_last_insert_id");
                    324:        *len = strlen(id);
                    325:        PDO_DBG_RETURN(id);
                    326: }
                    327: /* }}} */ 
                    328: 
                    329: /* {{{ mysql_handle_quoter */
                    330: static int mysql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype  TSRMLS_DC)
                    331: {
                    332:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    333:        PDO_DBG_ENTER("mysql_handle_quoter");
                    334:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    335:        PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted);
                    336:        *quoted = safe_emalloc(2, unquotedlen, 3);
                    337:        *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
                    338:        (*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
                    339:        (*quoted)[++*quotedlen] = '\0';
                    340:        PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted);
                    341:        PDO_DBG_RETURN(1);
                    342: }
                    343: /* }}} */
                    344: 
                    345: /* {{{ mysql_handle_begin */
                    346: static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
                    347: {
                    348:        PDO_DBG_ENTER("mysql_handle_quoter");
                    349:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    350:        PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC));
                    351: }
                    352: /* }}} */
                    353: 
                    354: /* {{{ mysql_handle_commit */
                    355: static int mysql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
                    356: {
                    357:        PDO_DBG_ENTER("mysql_handle_commit");
                    358:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    359: #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
                    360:        PDO_DBG_RETURN(0 <= mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server));
                    361: #else
                    362:        PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC));
                    363: #endif
                    364: }
                    365: /* }}} */
                    366: 
                    367: /* {{{ mysql_handle_rollback */
                    368: static int mysql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
                    369: {
                    370:        PDO_DBG_ENTER("mysql_handle_rollback");
                    371:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    372: #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
                    373:        PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server));
                    374: #else
                    375:        PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC));
                    376: #endif
                    377: }
                    378: /* }}} */
                    379: 
                    380: /* {{{ mysql_handle_autocommit */
                    381: static inline int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
                    382: {
                    383:        PDO_DBG_ENTER("mysql_handle_autocommit");
                    384:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    385:        PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit);
                    386: #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
                    387:        PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit));
                    388: #else
                    389:        if (dbh->auto_commit) {
                    390:                PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC));
                    391:        } else {
                    392:                PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC));
                    393:        }
                    394: #endif
                    395: }
                    396: /* }}} */
                    397: 
                    398: /* {{{ pdo_mysql_set_attribute */
                    399: static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
                    400: {
                    401:        PDO_DBG_ENTER("pdo_mysql_set_attribute");
                    402:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    403:        PDO_DBG_INF_FMT("attr=%l", attr);
                    404:        switch (attr) {
                    405:                case PDO_ATTR_AUTOCOMMIT:               
                    406:                        convert_to_boolean(val);
                    407:        
                    408:                        /* ignore if the new value equals the old one */                        
                    409:                        if (dbh->auto_commit ^ Z_BVAL_P(val)) {
                    410:                                dbh->auto_commit = Z_BVAL_P(val);
                    411:                                mysql_handle_autocommit(dbh TSRMLS_CC);
                    412:                        }
                    413:                        PDO_DBG_RETURN(1);
                    414: 
                    415:                case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
                    416:                        ((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
                    417:                        PDO_DBG_RETURN(1);
                    418:                case PDO_MYSQL_ATTR_DIRECT_QUERY:
                    419:                case PDO_ATTR_EMULATE_PREPARES:
                    420:                        ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
                    421:                        PDO_DBG_RETURN(1);
                    422:                case PDO_ATTR_FETCH_TABLE_NAMES:
                    423:                        ((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = Z_BVAL_P(val);
                    424:                        PDO_DBG_RETURN(1);
                    425: #ifndef PDO_USE_MYSQLND
                    426:                case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
                    427:                        if (Z_LVAL_P(val) < 0) {
                    428:                                /* TODO: Johannes, can we throw a warning here? */
                    429:                                ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = 1024*1024;
                    430:                                PDO_DBG_INF_FMT("Adjusting invalid buffer size to =%l", ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size);
                    431:                        } else {
                    432:                                ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = Z_LVAL_P(val);
                    433:                        }
                    434:                        PDO_DBG_RETURN(1);
                    435:                        break;
                    436: #endif
                    437: 
                    438:                default:
                    439:                        PDO_DBG_RETURN(0);
                    440:        }
                    441: }
                    442: /* }}} */
                    443: 
                    444: /* {{{ pdo_mysql_get_attribute */
                    445: static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
                    446: {
                    447:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    448: 
                    449:        PDO_DBG_ENTER("pdo_mysql_get_attribute");
                    450:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    451:        PDO_DBG_INF_FMT("attr=%l", attr);
                    452:        switch (attr) {
                    453:                case PDO_ATTR_CLIENT_VERSION:
                    454:                        ZVAL_STRING(return_value, (char *)mysql_get_client_info(), 1);
                    455:                        break;
                    456: 
                    457:                case PDO_ATTR_SERVER_VERSION:
                    458:                        ZVAL_STRING(return_value, (char *)mysql_get_server_info(H->server), 1);
                    459:                        break;
                    460: 
                    461:                case PDO_ATTR_CONNECTION_STATUS:
                    462:                        ZVAL_STRING(return_value, (char *)mysql_get_host_info(H->server), 1);
                    463:                        break;
                    464:                case PDO_ATTR_SERVER_INFO: {
                    465:                        char *tmp;
                    466: #ifdef PDO_USE_MYSQLND
                    467:                        unsigned int tmp_len;
                    468: 
                    469:                        if (mysqlnd_stat(H->server, &tmp, &tmp_len) == PASS) {
                    470:                                ZVAL_STRINGL(return_value, tmp, tmp_len, 0);
                    471: #else
                    472:                        if ((tmp = (char *)mysql_stat(H->server))) {
                    473:                                ZVAL_STRING(return_value, tmp, 1);
                    474: #endif
                    475:                        } else {
                    476:                                pdo_mysql_error(dbh);
                    477:                                PDO_DBG_RETURN(-1);
                    478:                        }
                    479:                }
                    480:                        break;
                    481:                case PDO_ATTR_AUTOCOMMIT:
                    482:                        ZVAL_LONG(return_value, dbh->auto_commit);
                    483:                        break;
                    484:                        
                    485:                case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
                    486:                        ZVAL_LONG(return_value, H->buffered);
                    487:                        break;
                    488: 
                    489:                case PDO_MYSQL_ATTR_DIRECT_QUERY:
                    490:                        ZVAL_LONG(return_value, H->emulate_prepare);
                    491:                        break;
                    492: 
                    493: #ifndef PDO_USE_MYSQLND
                    494:                case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
                    495:                        ZVAL_LONG(return_value, H->max_buffer_size);
                    496:                        break;
                    497: #endif
                    498: 
                    499:                default:
                    500:                        PDO_DBG_RETURN(0);      
                    501:        }
                    502: 
                    503:        PDO_DBG_RETURN(1);
                    504: }
                    505: /* }}} */
                    506: 
                    507: /* {{{ pdo_mysql_check_liveness */
                    508: static int pdo_mysql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC)
                    509: {
                    510:        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
                    511: #if MYSQL_VERSION_ID <= 32230
                    512:        void (*handler) (int);
                    513:        unsigned int my_errno;
                    514: #endif
                    515: 
                    516:        PDO_DBG_ENTER("pdo_mysql_check_liveness");
                    517:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    518: 
                    519: #if MYSQL_VERSION_ID > 32230
                    520:        if (mysql_ping(H->server)) {
                    521:                PDO_DBG_RETURN(FAILURE);
                    522:        }
                    523: #else /* no mysql_ping() */
                    524:        handler = signal(SIGPIPE, SIG_IGN);
                    525:        mysql_stat(H->server);
                    526:        switch (mysql_errno(H->server)) {
                    527:                case CR_SERVER_GONE_ERROR:
                    528:                case CR_SERVER_LOST:
                    529:                        signal(SIGPIPE, handler);
                    530:                        PDO_DBG_RETURN(FAILURE);
                    531:                default:
                    532:                        break;
                    533:        }
                    534:        signal(SIGPIPE, handler);
                    535: #endif /* end mysql_ping() */
                    536:        PDO_DBG_RETURN(SUCCESS);
                    537: } 
                    538: /* }}} */
                    539: 
                    540: /* {{{ mysql_methods */
                    541: static struct pdo_dbh_methods mysql_methods = {
                    542:        mysql_handle_closer,
                    543:        mysql_handle_preparer,
                    544:        mysql_handle_doer,
                    545:        mysql_handle_quoter,
                    546:        mysql_handle_begin,
                    547:        mysql_handle_commit,
                    548:        mysql_handle_rollback,
                    549:        pdo_mysql_set_attribute,
                    550:        pdo_mysql_last_insert_id,
                    551:        pdo_mysql_fetch_error_func,
                    552:        pdo_mysql_get_attribute,
                    553:        pdo_mysql_check_liveness
                    554: };
                    555: /* }}} */
                    556: 
                    557: #ifdef PHP_WIN32
                    558: # define MYSQL_UNIX_ADDR       NULL
                    559: #else
                    560: # define MYSQL_UNIX_ADDR       PDO_MYSQL_G(default_socket)
                    561: #endif
                    562: 
                    563: /* {{{ pdo_mysql_handle_factory */
                    564: static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
                    565: {
                    566:        pdo_mysql_db_handle *H;
                    567:        int i, ret = 0;
                    568:        char *host = NULL, *unix_socket = NULL;
                    569:        unsigned int port = 3306;
                    570:        char *dbname;
                    571:        struct pdo_data_src_parser vars[] = {
                    572:                { "charset",  NULL,     0 },
                    573:                { "dbname",   "",       0 },
                    574:                { "host",   "localhost",        0 },
                    575:                { "port",   "3306",     0 },
                    576:                { "unix_socket",  MYSQL_UNIX_ADDR,      0 },
                    577:        };
                    578:        int connect_opts = 0
                    579: #ifdef CLIENT_MULTI_RESULTS
                    580:                |CLIENT_MULTI_RESULTS
                    581: #endif
                    582: #ifdef CLIENT_MULTI_STATEMENTS
                    583:                |CLIENT_MULTI_STATEMENTS
                    584: #endif
                    585:                ;
                    586: 
                    587: #ifdef PDO_USE_MYSQLND
                    588:        int dbname_len = 0;
                    589:        int password_len = 0;
                    590: #endif
                    591:        PDO_DBG_ENTER("pdo_mysql_handle_factory");
                    592:        PDO_DBG_INF_FMT("dbh=%p", dbh);
                    593: #ifdef CLIENT_MULTI_RESULTS
                    594:        PDO_DBG_INF("multi results");
                    595: #endif
                    596: 
                    597:        php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
                    598: 
                    599:        H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
                    600: 
                    601:        H->einfo.errcode = 0;
                    602:        H->einfo.errmsg = NULL;
                    603: 
                    604:        /* allocate an environment */
                    605: 
                    606:        /* handle for the server */
                    607:        if (!(H->server = pdo_mysql_init(dbh->is_persistent))) {
                    608:                pdo_mysql_error(dbh);
                    609:                goto cleanup;
                    610:        }
                    611:        
                    612:        dbh->driver_data = H;
                    613: 
                    614: #ifndef PDO_USE_MYSQLND
                    615:        H->max_buffer_size = 1024*1024;
                    616: #endif
                    617: 
                    618:        H->buffered = H->emulate_prepare = 1;
                    619: 
                    620:        /* handle MySQL options */
                    621:        if (driver_options) {
                    622:                long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
                    623:                long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
                    624:                char *init_cmd = NULL;
                    625: #ifndef PDO_USE_MYSQLND
                    626:                char *default_file = NULL, *default_group = NULL;
                    627:                long compress = 0;
                    628: #endif
                    629: #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
                    630:                char *ssl_key = NULL, *ssl_cert = NULL, *ssl_ca = NULL, *ssl_capath = NULL, *ssl_cipher = NULL;
                    631: #endif
                    632:                H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1 TSRMLS_CC);
                    633: 
                    634:                H->emulate_prepare = pdo_attr_lval(driver_options,
                    635:                        PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
                    636:                H->emulate_prepare = pdo_attr_lval(driver_options, 
                    637:                        PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
                    638: 
                    639: #ifndef PDO_USE_MYSQLND
                    640:                H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
                    641: #endif
                    642: 
                    643:                if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_FOUND_ROWS, 0 TSRMLS_CC)) {
                    644:                        connect_opts |= CLIENT_FOUND_ROWS;
                    645:                }
                    646: 
                    647:                if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_IGNORE_SPACE, 0 TSRMLS_CC)) {
                    648:                        connect_opts |= CLIENT_IGNORE_SPACE;
                    649:                }
                    650: 
                    651:                if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
                    652:                        pdo_mysql_error(dbh);
                    653:                        goto cleanup;
                    654:                }
                    655: 
                    656: #if PHP_API_VERSION < 20100412
                    657:                if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode))
                    658: #else
                    659:                if (PG(open_basedir) && PG(open_basedir)[0] != '\0') 
                    660: #endif
                    661:                {
                    662:                        local_infile = 0;
                    663:                }
                    664: #if defined(MYSQL_OPT_LOCAL_INFILE) || defined(PDO_USE_MYSQLND)
                    665:                if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
                    666:                        pdo_mysql_error(dbh);
                    667:                        goto cleanup;
                    668:                }
                    669: #endif
                    670: #ifdef MYSQL_OPT_RECONNECT
                    671:                /* since 5.0.3, the default for this option is 0 if not specified.
                    672:                 * we want the old behaviour
                    673:                 * mysqlnd doesn't support reconnect, thus we don't have "|| defined(PDO_USE_MYSQLND)"
                    674:                */
                    675:                {
                    676:                        long reconnect = 1;
                    677:                        mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
                    678:                }
                    679: #endif
                    680:                init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
                    681:                if (init_cmd) {
                    682:                        if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
                    683:                                efree(init_cmd);
                    684:                                pdo_mysql_error(dbh);
                    685:                                goto cleanup;
                    686:                        }
                    687:                        efree(init_cmd);
                    688:                }
                    689: #ifndef PDO_USE_MYSQLND                
                    690:                default_file = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_FILE, NULL TSRMLS_CC);
                    691:                if (default_file) {
                    692:                        if (mysql_options(H->server, MYSQL_READ_DEFAULT_FILE, (const char *)default_file)) {
                    693:                                efree(default_file);
                    694:                                pdo_mysql_error(dbh);
                    695:                                goto cleanup;
                    696:                        }
                    697:                        efree(default_file);
                    698:                }
                    699:                
                    700:                default_group= pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP, NULL TSRMLS_CC);
                    701:                if (default_group) {
                    702:                        if (mysql_options(H->server, MYSQL_READ_DEFAULT_GROUP, (const char *)default_group)) {
                    703:                                efree(default_group);
                    704:                                pdo_mysql_error(dbh);
                    705:                                goto cleanup;
                    706:                        }
                    707:                        efree(default_group);
                    708:                }
                    709: 
                    710:                compress = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_COMPRESS, 0 TSRMLS_CC);
                    711:                if (compress) {
                    712:                        if (mysql_options(H->server, MYSQL_OPT_COMPRESS, 0)) {
                    713:                                pdo_mysql_error(dbh);
                    714:                                goto cleanup;
                    715:                        }
                    716:                }
                    717: #endif
                    718: #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
                    719:                ssl_key = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_KEY, NULL TSRMLS_CC);
                    720:                ssl_cert = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CERT, NULL TSRMLS_CC);
                    721:                ssl_ca = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CA, NULL TSRMLS_CC);
                    722:                ssl_capath = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CAPATH, NULL TSRMLS_CC);
                    723:                ssl_cipher = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CIPHER, NULL TSRMLS_CC);
                    724:                
                    725:                if (ssl_key || ssl_cert || ssl_ca || ssl_capath || ssl_cipher) {
                    726:                        mysql_ssl_set(H->server, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher);
                    727:                        if (ssl_key) {
                    728:                                efree(ssl_key);
                    729:                        }
                    730:                        if (ssl_cert) {
                    731:                                efree(ssl_cert);
                    732:                        }
                    733:                        if (ssl_ca) {
                    734:                                efree(ssl_ca);
                    735:                        }
                    736:                        if (ssl_capath) {
                    737:                                efree(ssl_capath);
                    738:                        }
                    739:                        if (ssl_cipher) {
                    740:                                efree(ssl_cipher);
                    741:                        }
                    742:                }
                    743: #endif
                    744:        }
                    745: 
                    746: #ifdef PDO_MYSQL_HAS_CHARSET
                    747:        if (vars[0].optval && mysql_options(H->server, MYSQL_SET_CHARSET_NAME, vars[0].optval)) {
                    748:                pdo_mysql_error(dbh);
                    749:                goto cleanup;
                    750:        }
                    751: #endif
                    752: 
                    753:        dbname = vars[1].optval;
                    754:        host = vars[2].optval;  
                    755:        if(vars[3].optval) {
                    756:                port = atoi(vars[3].optval);
                    757:        }
                    758:        if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
                    759:                unix_socket = vars[4].optval;  
                    760:        }
                    761: 
                    762:        /* TODO: - Check zval cache + ZTS */
                    763: #ifdef PDO_USE_MYSQLND
                    764:        if (dbname) {
                    765:                dbname_len = strlen(dbname);
                    766:        }
                    767: 
                    768:        if (dbh->password) {
                    769:                password_len = strlen(dbh->password);
                    770:        }
                    771: 
                    772:        if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
                    773:                                                port, unix_socket, connect_opts TSRMLS_CC) == NULL) {
                    774: #else
                    775:        if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
                    776: #endif
                    777:                pdo_mysql_error(dbh);
                    778:                goto cleanup;
                    779:        }
                    780: 
                    781:        if (!dbh->auto_commit) {
                    782:                mysql_handle_autocommit(dbh TSRMLS_CC);
                    783:        }
                    784: 
                    785:        H->attached = 1;
                    786: 
                    787:        dbh->alloc_own_columns = 1;
                    788:        dbh->max_escaped_char_length = 2;
                    789:        dbh->methods = &mysql_methods;
                    790: 
                    791:        ret = 1;
                    792:        
                    793: cleanup:
                    794:        for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
                    795:                if (vars[i].freeme) {
                    796:                        efree(vars[i].optval);
                    797:                }
                    798:        }
                    799:        
                    800:        dbh->methods = &mysql_methods;
                    801: 
                    802:        PDO_DBG_RETURN(ret);
                    803: }
                    804: /* }}} */
                    805: 
                    806: pdo_driver_t pdo_mysql_driver = {
                    807:        PDO_DRIVER_HEADER(mysql),
                    808:        pdo_mysql_handle_factory
                    809: };
                    810: 
                    811: /*
                    812:  * Local variables:
                    813:  * tab-width: 4
                    814:  * c-basic-offset: 4
                    815:  * End:
                    816:  * vim600: noet sw=4 ts=4 fdm=marker
                    817:  * vim<600: noet sw=4 ts=4
                    818:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>