1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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 35static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) 36{ 37 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 38 pdo_dblib_err *einfo = &H->err; 39 pdo_dblib_stmt *S = NULL; 40 char *message; 41 char *msg; 42 43 if (stmt) { 44 S = (pdo_dblib_stmt*)stmt->driver_data; 45 einfo = &S->err; 46 } 47 48 if (einfo->dberr == SYBESMSG && einfo->lastmsg) { 49 msg = einfo->lastmsg; 50 } else if (einfo->dberr == SYBESMSG && DBLIB_G(err).lastmsg) { 51 msg = DBLIB_G(err).lastmsg; 52 DBLIB_G(err).lastmsg = NULL; 53 } else { 54 msg = einfo->dberrstr; 55 } 56 57 spprintf(&message, 0, "%s [%d] (severity %d) [%s]", 58 msg, einfo->dberr, einfo->severity, stmt ? stmt->active_query_string : ""); 59 60 add_next_index_long(info, einfo->dberr); 61 add_next_index_string(info, message, 0); 62 add_next_index_long(info, einfo->oserr); 63 add_next_index_long(info, einfo->severity); 64 if (einfo->oserrstr) { 65 add_next_index_string(info, einfo->oserrstr, 1); 66 } 67 68 return 1; 69} 70 71 72static int dblib_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) 73{ 74 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 75 76 if (H) { 77 if (H->link) { 78 dbclose(H->link); 79 H->link = NULL; 80 } 81 if (H->login) { 82 dbfreelogin(H->login); 83 H->login = NULL; 84 } 85 pefree(H, dbh->is_persistent); 86 dbh->driver_data = NULL; 87 } 88 return 0; 89} 90 91static int dblib_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) 92{ 93 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 94 pdo_dblib_stmt *S = ecalloc(1, sizeof(*S)); 95 96 S->H = H; 97 stmt->driver_data = S; 98 stmt->methods = &dblib_stmt_methods; 99 stmt->supports_placeholders = PDO_PLACEHOLDER_NONE; 100 S->err.sqlstate = stmt->error_code; 101 102 return 1; 103} 104 105static long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) 106{ 107 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 108 RETCODE ret, resret; 109 110 dbsetuserdata(H->link, (BYTE*)&H->err); 111 112 if (FAIL == dbcmd(H->link, sql)) { 113 return -1; 114 } 115 116 if (FAIL == dbsqlexec(H->link)) { 117 return -1; 118 } 119 120 resret = dbresults(H->link); 121 122 if (resret == FAIL) { 123 return -1; 124 } 125 126 ret = dbnextrow(H->link); 127 if (ret == FAIL) { 128 return -1; 129 } 130 131 if (dbnumcols(H->link) <= 0) { 132 return DBCOUNT(H->link); 133 } 134 135 /* throw away any rows it might have returned */ 136 dbcanquery(H->link); 137 138 return DBCOUNT(H->link); 139} 140 141static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC) 142{ 143 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 144 char *q; 145 int l = 1; 146 147 *quoted = q = safe_emalloc(2, unquotedlen, 3); 148 *q++ = '\''; 149 150 while (unquotedlen--) { 151 if (*unquoted == '\'') { 152 *q++ = '\''; 153 *q++ = '\''; 154 l += 2; 155 } else { 156 *q++ = *unquoted; 157 ++l; 158 } 159 unquoted++; 160 } 161 162 *q++ = '\''; 163 *q++ = '\0'; 164 *quotedlen = l+1; 165 166 return 1; 167} 168 169static int pdo_dblib_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC) 170{ 171 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 172 RETCODE ret; 173 174 if (FAIL == dbcmd(H->link, cmd)) { 175 return 0; 176 } 177 178 if (FAIL == dbsqlexec(H->link)) { 179 return 0; 180 } 181 182 return 1; 183} 184 185static int dblib_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) 186{ 187 return pdo_dblib_transaction_cmd("BEGIN TRANSACTION", dbh TSRMLS_CC); 188} 189 190static int dblib_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) 191{ 192 return pdo_dblib_transaction_cmd("COMMIT TRANSACTION", dbh TSRMLS_CC); 193} 194 195static int dblib_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) 196{ 197 return pdo_dblib_transaction_cmd("ROLLBACK TRANSACTION", dbh TSRMLS_CC); 198} 199 200char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC) 201{ 202 pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; 203 204 RETCODE ret; 205 char *id = NULL; 206 207 /* 208 * Would use scope_identity() but it's not implemented on Sybase 209 */ 210 211 if (FAIL == dbcmd(H->link, "SELECT @@IDENTITY")) { 212 return NULL; 213 } 214 215 if (FAIL == dbsqlexec(H->link)) { 216 return NULL; 217 } 218 219 ret = dbresults(H->link); 220 if (ret == FAIL || ret == NO_MORE_RESULTS) { 221 dbcancel(H->link); 222 return NULL; 223 } 224 225 ret = dbnextrow(H->link); 226 227 if (ret == FAIL || ret == NO_MORE_ROWS) { 228 dbcancel(H->link); 229 return NULL; 230 } 231 232 if (dbdatlen(H->link, 1) == 0) { 233 dbcancel(H->link); 234 return NULL; 235 } 236 237 id = emalloc(32); 238 *len = dbconvert(NULL, (dbcoltype(H->link, 1)) , (dbdata(H->link, 1)) , (dbdatlen(H->link, 1)), SQLCHAR, id, (DBINT)-1); 239 240 dbcancel(H->link); 241 return id; 242} 243 244static struct pdo_dbh_methods dblib_methods = { 245 dblib_handle_closer, 246 dblib_handle_preparer, 247 dblib_handle_doer, 248 dblib_handle_quoter, 249 dblib_handle_begin, /* begin */ 250 dblib_handle_commit, /* commit */ 251 dblib_handle_rollback, /* rollback */ 252 NULL, /*set attr */ 253 dblib_handle_last_id, /* last insert id */ 254 dblib_fetch_error, /* fetch error */ 255 NULL, /* get attr */ 256 NULL, /* check liveness */ 257 NULL, /* get driver methods */ 258 NULL, /* request shutdown */ 259 NULL /* in transaction */ 260}; 261 262static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) 263{ 264 pdo_dblib_db_handle *H; 265 int i, ret = 0; 266 struct pdo_data_src_parser vars[] = { 267 { "charset", NULL, 0 }, 268 { "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 }, 269 { "host", "127.0.0.1", 0 }, 270 { "dbname", NULL, 0 }, 271 { "secure", NULL, 0 }, /* DBSETLSECURE */ 272 /* TODO: DBSETLVERSION ? */ 273 }; 274 275 php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5); 276 277 H = pecalloc(1, sizeof(*H), dbh->is_persistent); 278 H->login = dblogin(); 279 H->err.sqlstate = dbh->error_code; 280 281 if (!H->login) { 282 goto cleanup; 283 } 284 285 if (dbh->username) { 286 DBSETLUSER(H->login, dbh->username); 287 } 288 if (dbh->password) { 289 DBSETLPWD(H->login, dbh->password); 290 } 291 292#if !PHP_DBLIB_IS_MSSQL 293 if (vars[0].optval) { 294 DBSETLCHARSET(H->login, vars[0].optval); 295 } 296#endif 297 298 DBSETLAPP(H->login, vars[1].optval); 299 300#if PHP_DBLIB_IS_MSSQL 301 dbprocerrhandle(H->login, (EHANDLEFUNC) error_handler); 302 dbprocmsghandle(H->login, (MHANDLEFUNC) msg_handler); 303#endif 304 305 H->link = dbopen(H->login, vars[2].optval); 306 307 if (H->link == NULL) { 308 goto cleanup; 309 } 310 311 /* dblib do not return more than this length from text/image */ 312 DBSETOPT(H->link, DBTEXTLIMIT, "2147483647"); 313 314 /* limit text/image from network */ 315 DBSETOPT(H->link, DBTEXTSIZE, "2147483647"); 316 317 /* allow double quoted indentifiers */ 318 DBSETOPT(H->link, DBQUOTEDIDENT, NULL); 319 320 if (vars[3].optval && FAIL == dbuse(H->link, vars[3].optval)) { 321 goto cleanup; 322 } 323 324 ret = 1; 325 dbh->max_escaped_char_length = 2; 326 dbh->alloc_own_columns = 1; 327 328cleanup: 329 for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) { 330 if (vars[i].freeme) { 331 efree(vars[i].optval); 332 } 333 } 334 335 dbh->methods = &dblib_methods; 336 dbh->driver_data = H; 337 338 if (!ret) { 339 zend_throw_exception_ex(php_pdo_get_exception(), DBLIB_G(err).dberr TSRMLS_CC, 340 "SQLSTATE[%s] %s (severity %d)", 341 DBLIB_G(err).sqlstate, 342 DBLIB_G(err).dberrstr, 343 DBLIB_G(err).severity); 344 } 345 346 return ret; 347} 348 349pdo_driver_t pdo_dblib_driver = { 350#if PDO_DBLIB_IS_MSSQL 351 PDO_DRIVER_HEADER(mssql), 352#elif defined(PHP_WIN32) 353#define PDO_DBLIB_IS_SYBASE 354 PDO_DRIVER_HEADER(sybase), 355#else 356 PDO_DRIVER_HEADER(dblib), 357#endif 358 pdo_dblib_handle_factory 359}; 360 361