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/php_string.h" 29#include "ext/standard/info.h" 30#include "pdo/php_pdo.h" 31#include "pdo/php_pdo_driver.h" 32#include "php_pdo_dblib.h" 33#include "php_pdo_dblib_int.h" 34#include "zend_exceptions.h" 35 36 37/* {{{ pdo_dblib_get_field_name 38 * 39 * Return the data type name for a given TDS number 40 * 41 */ 42static char *pdo_dblib_get_field_name(int type) 43{ 44 /* 45 * I don't return dbprtype(type) because it does not fully describe the type 46 * (example: varchar is reported as char by dbprtype) 47 * 48 * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory() 49 * to make this future proof. 50 */ 51 52 switch (type) { 53 case 31: return "nvarchar"; 54 case 34: return "image"; 55 case 35: return "text"; 56 case 36: return "uniqueidentifier"; 57 case 37: return "varbinary"; /* & timestamp - Sybase AS12 */ 58 case 38: return "bigint"; /* & bigintn - Sybase AS12 */ 59 case 39: return "varchar"; /* & sysname & nvarchar - Sybase AS12 */ 60 case 40: return "date"; 61 case 41: return "time"; 62 case 42: return "datetime2"; 63 case 43: return "datetimeoffset"; 64 case 45: return "binary"; /* Sybase AS12 */ 65 case 47: return "char"; /* & nchar & uniqueidentifierstr Sybase AS12 */ 66 case 48: return "tinyint"; 67 case 50: return "bit"; /* Sybase AS12 */ 68 case 52: return "smallint"; 69 case 55: return "decimal"; /* Sybase AS12 */ 70 case 56: return "int"; 71 case 58: return "smalldatetime"; 72 case 59: return "real"; 73 case 60: return "money"; 74 case 61: return "datetime"; 75 case 62: return "float"; 76 case 63: return "numeric"; /* or uint, ubigint, usmallint Sybase AS12 */ 77 case 98: return "sql_variant"; 78 case 99: return "ntext"; 79 case 104: return "bit"; 80 case 106: return "decimal"; /* decimal n on sybase */ 81 case 108: return "numeric"; /* numeric n on sybase */ 82 case 122: return "smallmoney"; 83 case 127: return "bigint"; 84 case 165: return "varbinary"; 85 case 167: return "varchar"; 86 case 173: return "binary"; 87 case 175: return "char"; 88 case 189: return "timestamp"; 89 case 231: return "nvarchar"; 90 case 239: return "nchar"; 91 case 240: return "geometry"; 92 case 241: return "xml"; 93 default: return "unknown"; 94 } 95} 96/* }}} */ 97 98static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) 99{ 100 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 101 pdo_dblib_db_handle *H = S->H; 102 103 /* Cancel any pending results */ 104 dbcancel(H->link); 105 106 efree(stmt->columns); 107 stmt->columns = NULL; 108 109 return 1; 110} 111 112static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) 113{ 114 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 115 116 efree(stmt->columns); 117 stmt->columns = NULL; 118 119 efree(S); 120 121 return 1; 122} 123 124static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) 125{ 126 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 127 pdo_dblib_db_handle *H = S->H; 128 RETCODE ret; 129 130 ret = dbresults(H->link); 131 132 if (FAIL == ret) { 133 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL" TSRMLS_CC); 134 return 0; 135 } 136 137 if(NO_MORE_RESULTS == ret) { 138 return 0; 139 } 140 141 stmt->row_count = DBCOUNT(H->link); 142 stmt->column_count = dbnumcols(H->link); 143 144 return 1; 145} 146 147static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) 148{ 149 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 150 pdo_dblib_db_handle *H = S->H; 151 RETCODE ret; 152 153 dbsetuserdata(H->link, (BYTE*) &S->err); 154 155 pdo_dblib_stmt_cursor_closer(stmt TSRMLS_CC); 156 157 if (FAIL == dbcmd(H->link, stmt->active_query_string)) { 158 return 0; 159 } 160 161 if (FAIL == dbsqlexec(H->link)) { 162 return 0; 163 } 164 165 ret = pdo_dblib_stmt_next_rowset(stmt TSRMLS_CC); 166 167 stmt->row_count = DBCOUNT(H->link); 168 stmt->column_count = dbnumcols(H->link); 169 170 return 1; 171} 172 173static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt, 174 enum pdo_fetch_orientation ori, long offset TSRMLS_DC) 175{ 176 177 RETCODE ret; 178 179 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 180 pdo_dblib_db_handle *H = S->H; 181 182 ret = dbnextrow(H->link); 183 184 if (FAIL == ret) { 185 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL" TSRMLS_CC); 186 return 0; 187 } 188 189 if(NO_MORE_ROWS == ret) { 190 return 0; 191 } 192 193 return 1; 194} 195 196static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) 197{ 198 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 199 pdo_dblib_db_handle *H = S->H; 200 201 if(colno >= stmt->column_count || colno < 0) { 202 return FAILURE; 203 } 204 205 struct pdo_column_data *col = &stmt->columns[colno]; 206 207 col->name = (char*)dbcolname(H->link, colno+1); 208 col->maxlen = dbcollen(H->link, colno+1); 209 col->namelen = strlen(col->name); 210 col->param_type = PDO_PARAM_STR; 211 212 return 1; 213} 214 215static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, 216 unsigned long *len, int *caller_frees TSRMLS_DC) 217{ 218 219 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 220 pdo_dblib_db_handle *H = S->H; 221 222 int coltype; 223 unsigned int tmp_len; 224 char *tmp_ptr = NULL; 225 226 coltype = dbcoltype(H->link, colno+1); 227 228 *len = dbdatlen(H->link, colno+1); 229 *ptr = dbdata(H->link, colno+1); 230 231 if (*len == 0 && *ptr == NULL) { 232 return 1; 233 } 234 235 switch (coltype) { 236 case SQLVARBINARY: 237 case SQLBINARY: 238 case SQLIMAGE: 239 case SQLTEXT: 240 /* FIXME: Above types should be returned as a stream as they can be VERY large */ 241 case SQLCHAR: 242 case SQLVARCHAR: 243 tmp_ptr = emalloc(*len + 1); 244 memcpy(tmp_ptr, *ptr, *len); 245 tmp_ptr[*len] = '\0'; 246 *ptr = tmp_ptr; 247 break; 248 case SQLMONEY: 249 case SQLMONEY4: 250 case SQLMONEYN: { 251 DBFLT8 money_value; 252 dbconvert(NULL, coltype, *ptr, *len, SQLFLT8, (LPBYTE)&money_value, 8); 253 *len = spprintf(&tmp_ptr, 0, "%.4f", money_value); 254 *ptr = tmp_ptr; 255 break; 256 } 257 case SQLUNIQUE: { 258 *len = 36+1; 259 tmp_ptr = emalloc(*len + 1); 260 261 /* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */ 262 *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len); 263 php_strtoupper(tmp_ptr, *len); 264 *ptr = tmp_ptr; 265 break; 266 } 267 default: 268 if (dbwillconvert(coltype, SQLCHAR)) { 269 tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */ 270 tmp_ptr = emalloc(tmp_len); 271 *len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1); 272 *ptr = tmp_ptr; 273 } else { 274 *len = 0; /* FIXME: Silently fails and returns null on conversion errors */ 275 *ptr = NULL; 276 } 277 } 278 279 *caller_frees = 1; 280 281 return 1; 282} 283 284static int pdo_dblib_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, 285 enum pdo_param_event event_type TSRMLS_DC) 286{ 287 return 1; 288} 289 290static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) 291{ 292 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 293 pdo_dblib_db_handle *H = S->H; 294 DBTYPEINFO* dbtypeinfo; 295 296 if(colno >= stmt->column_count || colno < 0) { 297 return FAILURE; 298 } 299 300 array_init(return_value); 301 302 dbtypeinfo = dbcoltypeinfo(H->link, colno+1); 303 304 if(!dbtypeinfo) return FAILURE; 305 306 add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) ); 307 add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision ); 308 add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale ); 309 add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1), 1); 310 add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)), 1); 311 add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1)); 312 add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1)); 313 314 return 1; 315} 316 317 318struct pdo_stmt_methods dblib_stmt_methods = { 319 pdo_dblib_stmt_dtor, 320 pdo_dblib_stmt_execute, 321 pdo_dblib_stmt_fetch, 322 pdo_dblib_stmt_describe, 323 pdo_dblib_stmt_get_col, 324 pdo_dblib_stmt_param_hook, 325 NULL, /* set attr */ 326 NULL, /* get attr */ 327 pdo_dblib_stmt_get_column_meta, /* meta */ 328 pdo_dblib_stmt_next_rowset, /* nextrow */ 329 pdo_dblib_stmt_cursor_closer 330}; 331 332