root/ext/pdo_dblib/dblib_driver.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dblib_fetch_error
  2. dblib_handle_closer
  3. dblib_handle_preparer
  4. dblib_handle_doer
  5. dblib_handle_quoter
  6. pdo_dblib_transaction_cmd
  7. dblib_handle_begin
  8. dblib_handle_commit
  9. dblib_handle_rollback
  10. dblib_handle_last_id
  11. pdo_dblib_handle_factory

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 5                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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   |         Frank M. Kromann <frank@kromann.info>                        |
  17   +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id$ */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 # include "config.h"
  24 #endif
  25 
  26 #include "php.h"
  27 #include "php_ini.h"
  28 #include "ext/standard/info.h"
  29 #include "pdo/php_pdo.h"
  30 #include "pdo/php_pdo_driver.h"
  31 #include "php_pdo_dblib.h"
  32 #include "php_pdo_dblib_int.h"
  33 #include "zend_exceptions.h"
  34 
  35 /* Cache of the server supported datatypes, initialized in handle_factory */
  36 zval* pdo_dblib_datatypes;
  37 
  38 static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
  39 {
  40         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
  41         pdo_dblib_err *einfo = &H->err;
  42         pdo_dblib_stmt *S = NULL;
  43         char *message;
  44         char *msg;
  45 
  46         if (stmt) {
  47                 S = (pdo_dblib_stmt*)stmt->driver_data;
  48                 einfo = &S->err;
  49         }
  50 
  51         if (einfo->dberr == SYBESMSG && einfo->lastmsg) {
  52                 msg = einfo->lastmsg;
  53         } else if (einfo->dberr == SYBESMSG && DBLIB_G(err).lastmsg) {
  54                 msg = DBLIB_G(err).lastmsg;
  55                 DBLIB_G(err).lastmsg = NULL;
  56         } else {
  57                 msg = einfo->dberrstr;
  58         }
  59 
  60         spprintf(&message, 0, "%s [%d] (severity %d) [%s]",
  61                 msg, einfo->dberr, einfo->severity, stmt ? stmt->active_query_string : "");
  62 
  63         add_next_index_long(info, einfo->dberr);
  64         add_next_index_string(info, message, 0);
  65         add_next_index_long(info, einfo->oserr);
  66         add_next_index_long(info, einfo->severity);
  67         if (einfo->oserrstr) {
  68                 add_next_index_string(info, einfo->oserrstr, 1);
  69         }
  70 
  71         return 1;
  72 }
  73 
  74 
  75 static int dblib_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
  76 {
  77         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
  78 
  79         if (H) {
  80                 if (H->link) {
  81                         dbclose(H->link);
  82                         H->link = NULL;
  83                 }
  84                 if (H->login) {
  85                         dbfreelogin(H->login);
  86                         H->login = NULL;
  87                 }
  88                 pefree(H, dbh->is_persistent);
  89                 dbh->driver_data = NULL;
  90         }
  91         return 0;
  92 }
  93 
  94 static int dblib_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
  95 {
  96         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
  97         pdo_dblib_stmt *S = ecalloc(1, sizeof(*S));
  98         
  99         S->H = H;
 100         stmt->driver_data = S;
 101         stmt->methods = &dblib_stmt_methods;
 102         stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
 103         S->err.sqlstate = stmt->error_code;
 104 
 105         return 1;
 106 }
 107 
 108 static long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
 109 {
 110         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
 111         RETCODE ret, resret;
 112 
 113         dbsetuserdata(H->link, (BYTE*)&H->err);
 114 
 115         if (FAIL == dbcmd(H->link, sql)) {
 116                 return -1;
 117         }
 118 
 119         if (FAIL == dbsqlexec(H->link)) {
 120                 return -1;
 121         }
 122         
 123         resret = dbresults(H->link);
 124 
 125         if (resret == FAIL) {
 126                 return -1;
 127         }
 128 
 129         ret = dbnextrow(H->link);
 130         if (ret == FAIL) {
 131                 return -1;
 132         }
 133 
 134         if (dbnumcols(H->link) <= 0) {
 135                 return DBCOUNT(H->link);
 136         }
 137 
 138         /* throw away any rows it might have returned */
 139         dbcanquery(H->link);
 140 
 141         return DBCOUNT(H->link);
 142 }
 143 
 144 static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
 145 {
 146         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
 147         char *q;
 148         int l = 1;
 149 
 150         *quoted = q = safe_emalloc(2, unquotedlen, 3);
 151         *q++ = '\'';
 152 
 153         while (unquotedlen--) {
 154                 if (*unquoted == '\'') {
 155                         *q++ = '\'';
 156                         *q++ = '\'';
 157                         l += 2;
 158                 } else {
 159                         *q++ = *unquoted;
 160                         ++l;
 161                 }
 162                 unquoted++;
 163         }
 164 
 165         *q++ = '\'';
 166         *q++ = '\0';
 167         *quotedlen = l+1;
 168         
 169         return 1;
 170 }
 171 
 172 static int pdo_dblib_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC)
 173 {
 174         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
 175         RETCODE ret;
 176         
 177         if (FAIL == dbcmd(H->link, cmd)) {
 178                 return 0;
 179         }
 180         
 181         if (FAIL == dbsqlexec(H->link)) {
 182                 return 0;
 183         }
 184         
 185         return 1;
 186 }
 187 
 188 static int dblib_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
 189 {
 190         return pdo_dblib_transaction_cmd("BEGIN TRANSACTION", dbh TSRMLS_CC);
 191 }
 192 
 193 static int dblib_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
 194 {
 195         return pdo_dblib_transaction_cmd("COMMIT TRANSACTION", dbh TSRMLS_CC);
 196 }
 197 
 198 static int dblib_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
 199 {
 200         return pdo_dblib_transaction_cmd("ROLLBACK TRANSACTION", dbh TSRMLS_CC);
 201 }
 202 
 203 char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC) 
 204 {
 205         pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
 206 
 207         RETCODE ret;
 208         char *id = NULL;
 209 
 210         /* 
 211          * Would use scope_identity() but it's not implemented on Sybase
 212          */
 213         
 214         if (FAIL == dbcmd(H->link, "SELECT @@IDENTITY")) {
 215                 return NULL;
 216         }
 217         
 218         if (FAIL == dbsqlexec(H->link)) {
 219                 return NULL;
 220         }
 221         
 222         ret = dbresults(H->link);
 223         if (ret == FAIL || ret == NO_MORE_RESULTS) {
 224                 dbcancel(H->link);
 225                 return NULL;
 226         }
 227 
 228         ret = dbnextrow(H->link);
 229         
 230         if (ret == FAIL || ret == NO_MORE_ROWS) {
 231                 dbcancel(H->link);
 232                 return NULL;
 233         }
 234 
 235         if (dbdatlen(H->link, 1) == 0) {
 236                 dbcancel(H->link);
 237                 return NULL;
 238         }
 239 
 240         id = emalloc(32);
 241         *len = dbconvert(NULL, (dbcoltype(H->link, 1)) , (dbdata(H->link, 1)) , (dbdatlen(H->link, 1)), SQLCHAR, id, (DBINT)-1);
 242                 
 243         dbcancel(H->link);
 244         return id;
 245 }
 246 
 247 static struct pdo_dbh_methods dblib_methods = {
 248         dblib_handle_closer,
 249         dblib_handle_preparer,
 250         dblib_handle_doer,
 251         dblib_handle_quoter,
 252         dblib_handle_begin, /* begin */
 253         dblib_handle_commit, /* commit */
 254         dblib_handle_rollback, /* rollback */
 255         NULL, /*set attr */
 256         dblib_handle_last_id, /* last insert id */
 257         dblib_fetch_error, /* fetch error */
 258         NULL, /* get attr */
 259         NULL, /* check liveness */
 260         NULL, /* get driver methods */
 261         NULL, /* request shutdown */
 262         NULL  /* in transaction */
 263 };
 264 
 265 static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
 266 {
 267         pdo_dblib_db_handle *H;
 268         int i, nvars, nvers, ret = 0;
 269         int *val;
 270         
 271         const pdo_dblib_keyval tdsver[] = {
 272                  {"4.2",DBVERSION_42}
 273                 ,{"4.6",DBVERSION_46}
 274                 ,{"5.0",DBVERSION_70} /* FIXME: This does not work with Sybase, but environ will */
 275                 ,{"6.0",DBVERSION_70}
 276                 ,{"7.0",DBVERSION_70}
 277 #ifdef DBVERSION_71
 278                 ,{"7.1",DBVERSION_71}
 279 #endif
 280 #ifdef DBVERSION_72
 281                 ,{"7.2",DBVERSION_72}
 282                 ,{"8.0",DBVERSION_72}
 283 #endif
 284                 ,{"10.0",DBVERSION_100}
 285                 ,{"auto",0} /* Only works with FreeTDS. Other drivers will bork */
 286                 
 287         };
 288         
 289         struct pdo_data_src_parser vars[] = {
 290                 { "charset",    NULL,   0 }
 291                 ,{ "appname",   "PHP " PDO_DBLIB_FLAVOUR,       0 }
 292                 ,{ "host",              "127.0.0.1", 0 }
 293                 ,{ "dbname",    NULL,   0 }
 294                 ,{ "secure",    NULL,   0 } /* DBSETLSECURE */
 295                 ,{ "version",   NULL,   0 } /* DBSETLVERSION */
 296         };
 297         
 298         nvars = sizeof(vars)/sizeof(vars[0]);
 299         nvers = sizeof(tdsver)/sizeof(tdsver[0]);
 300         
 301         php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars);
 302 
 303         H = pecalloc(1, sizeof(*H), dbh->is_persistent);
 304         H->login = dblogin();
 305         H->err.sqlstate = dbh->error_code;
 306 
 307         if (!H->login) {
 308                 goto cleanup;
 309         }
 310 
 311         DBERRHANDLE(H->login, (EHANDLEFUNC) error_handler);
 312         DBMSGHANDLE(H->login, (MHANDLEFUNC) msg_handler);
 313         
 314         if(vars[5].optval) {
 315                 for(i=0;i<nvers;i++) {
 316                         if(strcmp(vars[5].optval,tdsver[i].key) == 0) {
 317                                 if(FAIL==dbsetlversion(H->login, tdsver[i].value)) {
 318                                         pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Failed to set version specified in connection string." TSRMLS_CC);         
 319                                         goto cleanup;
 320                                 }
 321                                 break;
 322                         }
 323                 }
 324                 
 325                 if (i==nvers) {
 326                         printf("Invalid version '%s'\n", vars[5].optval);
 327                         pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Invalid version specified in connection string." TSRMLS_CC);               
 328                         goto cleanup; /* unknown version specified */
 329                 }
 330         }
 331 
 332         if (dbh->username) {
 333                 if(FAIL == DBSETLUSER(H->login, dbh->username)) {
 334                         goto cleanup;
 335                 }
 336         }
 337 
 338         if (dbh->password) {
 339                 if(FAIL == DBSETLPWD(H->login, dbh->password)) {
 340                         goto cleanup;
 341                 }
 342         }
 343         
 344 #if !PHP_DBLIB_IS_MSSQL
 345         if (vars[0].optval) {
 346                 DBSETLCHARSET(H->login, vars[0].optval);
 347         }
 348 #endif
 349 
 350         DBSETLAPP(H->login, vars[1].optval);
 351 
 352 /* DBSETLDBNAME is only available in FreeTDS 0.92 or above */
 353 #ifdef DBSETLDBNAME
 354         if (vars[3].optval) {
 355                 if(FAIL == DBSETLDBNAME(H->login, vars[3].optval)) goto cleanup;
 356         }
 357 #endif
 358 
 359         H->link = dbopen(H->login, vars[2].optval);
 360 
 361         if (!H->link) {
 362                 goto cleanup;
 363         }
 364 
 365 /*
 366  * FreeTDS < 0.92 does not support the DBSETLDBNAME option
 367  * Send use database here after login (Will not work with SQL Azure)
 368  */
 369 #ifndef DBSETLDBNAME
 370         if (vars[3].optval) {
 371                 if(FAIL == dbuse(H->link, vars[3].optval)) goto cleanup;
 372         }
 373 #endif
 374 
 375 #if PHP_DBLIB_IS_MSSQL
 376         /* dblib do not return more than this length from text/image */
 377         DBSETOPT(H->link, DBTEXTLIMIT, "2147483647");
 378 #endif
 379 
 380         /* limit text/image from network */
 381         DBSETOPT(H->link, DBTEXTSIZE, "2147483647");
 382 
 383         /* allow double quoted indentifiers */
 384         DBSETOPT(H->link, DBQUOTEDIDENT, "1");
 385 
 386         ret = 1;
 387         dbh->max_escaped_char_length = 2;
 388         dbh->alloc_own_columns = 1;
 389 
 390 cleanup:
 391         for (i = 0; i < nvars; i++) {
 392                 if (vars[i].freeme) {
 393                         efree(vars[i].optval);
 394                 }
 395         }
 396 
 397         dbh->methods = &dblib_methods;
 398         dbh->driver_data = H;
 399 
 400         if (!ret) {
 401                 zend_throw_exception_ex(php_pdo_get_exception(), DBLIB_G(err).dberr TSRMLS_CC,
 402                         "SQLSTATE[%s] %s (severity %d)",
 403                         DBLIB_G(err).sqlstate,
 404                         DBLIB_G(err).dberrstr,
 405                         DBLIB_G(err).severity);
 406         }
 407 
 408         return ret;
 409 }
 410 
 411 pdo_driver_t pdo_dblib_driver = {
 412 #if PDO_DBLIB_IS_MSSQL
 413         PDO_DRIVER_HEADER(mssql),
 414 #elif defined(PHP_WIN32)
 415 #define PDO_DBLIB_IS_SYBASE
 416         PDO_DRIVER_HEADER(sybase),
 417 #else
 418         PDO_DRIVER_HEADER(dblib),
 419 #endif
 420         pdo_dblib_handle_factory
 421 };
 422 

/* [<][>][^][v][top][bottom][index][help] */