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 * Updated for MSSQL 2008 SR2 extended types 40 * 41 */ 42static char *pdo_dblib_get_field_name(int type) 43{ 44 switch (type) { 45 case 34: return "image"; 46 case 35: return "text"; 47 case 36: return "uniqueidentifier"; 48 case 40: return "date"; 49 case 41: return "time"; 50 case 42: return "datetime2"; 51 case 43: return "datetimeoffset"; 52 case 48: return "tinyint"; 53 case 52: return "smallint"; 54 case 56: return "int"; 55 case 58: return "smalldatetime"; 56 case 59: return "real"; 57 case 60: return "money"; 58 case 61: return "datetime"; 59 case 62: return "float"; 60 case 98: return "sql_variant"; 61 case 99: return "ntext"; 62 case 104: return "bit"; 63 case 106: return "decimal"; 64 case 108: return "numeric"; 65 case 122: return "smallmoney"; 66 case 127: return "bigint"; 67 case 240: return "geometry"; 68 case 165: return "varbinary"; 69 case 167: return "varchar"; 70 case 173: return "binary"; 71 case 175: return "char"; 72 case 189: return "timestamp"; 73 case 231: return "nvarchar"; 74 case 239: return "nchar"; 75 case 241: return "xml"; 76 default: 77 return "unknown"; 78 break; 79 } 80} 81/* }}} */ 82 83static int dblib_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) 84{ 85 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 86 pdo_dblib_db_handle *H = S->H; 87 88 /* Cancel any pending results */ 89 dbcancel(H->link); 90 91 efree(stmt->columns); 92 stmt->columns = NULL; 93 94 return 1; 95} 96 97static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) 98{ 99 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 100 101 dblib_dblib_stmt_cursor_closer(stmt TSRMLS_CC); 102 103 efree(S); 104 105 return 1; 106} 107 108static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) 109{ 110 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 111 pdo_dblib_db_handle *H = S->H; 112 RETCODE ret; 113 114 ret = dbresults(H->link); 115 116 if (ret == FAIL || ret == NO_MORE_RESULTS) { 117 return 0; 118 } 119 120 stmt->row_count = DBCOUNT(H->link); 121 stmt->column_count = dbnumcols(H->link); 122 123 return 1; 124} 125 126static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) 127{ 128 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 129 pdo_dblib_db_handle *H = S->H; 130 RETCODE ret; 131 132 dbsetuserdata(H->link, (BYTE*) &S->err); 133 134 if (FAIL == dbcmd(H->link, stmt->active_query_string)) { 135 return 0; 136 } 137 138 if (FAIL == dbsqlexec(H->link)) { 139 return 0; 140 } 141 142 ret = pdo_dblib_stmt_next_rowset(stmt TSRMLS_CC); 143 144 if (ret == 0) { 145 return 0; 146 } 147 148 stmt->row_count = DBCOUNT(H->link); 149 stmt->column_count = dbnumcols(H->link); 150 151 return 1; 152} 153 154static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt, 155 enum pdo_fetch_orientation ori, long offset TSRMLS_DC) 156{ 157 158 RETCODE ret; 159 160 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 161 pdo_dblib_db_handle *H = S->H; 162 163 ret = dbnextrow(H->link); 164 165 if (ret == FAIL || ret == NO_MORE_ROWS) { 166 return 0; 167 } 168 169 return 1; 170} 171 172static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) 173{ 174 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 175 pdo_dblib_db_handle *H = S->H; 176 177 struct pdo_column_data *col = &stmt->columns[colno]; 178 179 col->name = (char*)dbcolname(H->link, colno+1); 180 col->maxlen = dbcollen(H->link, colno+1); 181 col->namelen = strlen(col->name); 182 col->param_type = PDO_PARAM_STR; 183 184 return 1; 185} 186 187static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, 188 unsigned long *len, int *caller_frees TSRMLS_DC) 189{ 190 191 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 192 pdo_dblib_db_handle *H = S->H; 193 194 int coltype; 195 unsigned int tmp_len; 196 char *tmp_ptr = NULL; 197 198 coltype = dbcoltype(H->link, colno+1); 199 200 *len = dbdatlen(H->link, colno+1); 201 *ptr = dbdata(H->link, colno+1); 202 203 if (*len == 0 && *ptr == NULL) { 204 return 1; 205 } 206 207 switch (coltype) { 208 case SQLCHAR: 209 case SQLTEXT: 210 case SQLVARBINARY: 211 case SQLBINARY: 212 case SQLIMAGE: 213 case SQLVARCHAR: 214 tmp_ptr = emalloc(*len + 1); 215 memcpy(tmp_ptr, *ptr, *len); 216 tmp_ptr[*len] = '\0'; 217 *ptr = tmp_ptr; 218 break; 219 case SQLMONEY: 220 case SQLMONEY4: 221 case SQLMONEYN: { 222 DBFLT8 money_value; 223 dbconvert(NULL, coltype, *ptr, *len, SQLFLT8, (LPBYTE)&money_value, 8); 224 *len = spprintf(&tmp_ptr, 0, "%.4f", money_value); 225 *ptr = tmp_ptr; 226 break; 227 } 228#ifdef SQLUNIQUE 229 case SQLUNIQUE: { 230#else 231 case 36: { /* FreeTDS hack, also used by ext/mssql */ 232#endif 233 *len = 36+1; 234 tmp_ptr = emalloc(*len + 1); 235 236 /* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */ 237#ifdef SQLUNIQUE 238 *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len); 239#else 240 *len = dbconvert(NULL, 36, *ptr, *len, SQLCHAR, tmp_ptr, *len); 241#endif 242 php_strtoupper(tmp_ptr, *len); 243 *ptr = tmp_ptr; 244 break; 245 } 246 default: 247 if (dbwillconvert(coltype, SQLCHAR)) { 248 tmp_len = 32 + (2 * (*len)); 249 tmp_ptr = emalloc(tmp_len); 250 *len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1); 251 *ptr = tmp_ptr; 252 } else { 253 *len = 0; 254 *ptr = NULL; 255 } 256 } 257 258 *caller_frees = 1; 259 260 return 1; 261} 262 263static int pdo_dblib_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, 264 enum pdo_param_event event_type TSRMLS_DC) 265{ 266 return 1; 267} 268 269static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) 270{ 271 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; 272 pdo_dblib_db_handle *H = S->H; 273 274 array_init(return_value); 275 276 DBTYPEINFO* dbtypeinfo; 277 dbtypeinfo = dbcoltypeinfo(H->link, colno+1); 278 279 add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) ); 280 add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision ); 281 add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale ); 282 add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1), 1); 283 add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)), 1); 284 285 return 1; 286} 287 288 289struct pdo_stmt_methods dblib_stmt_methods = { 290 pdo_dblib_stmt_dtor, 291 pdo_dblib_stmt_execute, 292 pdo_dblib_stmt_fetch, 293 pdo_dblib_stmt_describe, 294 pdo_dblib_stmt_get_col, 295 pdo_dblib_stmt_param_hook, 296 NULL, /* set attr */ 297 NULL, /* get attr */ 298 pdo_dblib_stmt_get_column_meta, /* meta */ 299 pdo_dblib_stmt_next_rowset, /* nextrow */ 300 dblib_dblib_stmt_cursor_closer 301}; 302 303