dblib_stmt.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Wez Furlong <wez@php.net> |
  14. | Frank M. Kromann <frank@kromann.info> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. # include "config.h"
  19. #endif
  20. #include "php.h"
  21. #include "php_ini.h"
  22. #include "ext/standard/php_string.h"
  23. #include "ext/standard/info.h"
  24. #include "pdo/php_pdo.h"
  25. #include "pdo/php_pdo_driver.h"
  26. #include "php_pdo_dblib.h"
  27. #include "php_pdo_dblib_int.h"
  28. #include "zend_exceptions.h"
  29. /* {{{ pdo_dblib_get_field_name
  30. *
  31. * Return the data type name for a given TDS number
  32. *
  33. */
  34. static char *pdo_dblib_get_field_name(int type)
  35. {
  36. /*
  37. * I don't return dbprtype(type) because it does not fully describe the type
  38. * (example: varchar is reported as char by dbprtype)
  39. *
  40. * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory()
  41. * to make this future proof.
  42. */
  43. switch (type) {
  44. case 31: return "nvarchar";
  45. case 34: return "image";
  46. case 35: return "text";
  47. case 36: return "uniqueidentifier";
  48. case 37: return "varbinary"; /* & timestamp - Sybase AS12 */
  49. case 38: return "bigint"; /* & bigintn - Sybase AS12 */
  50. case 39: return "varchar"; /* & sysname & nvarchar - Sybase AS12 */
  51. case 40: return "date";
  52. case 41: return "time";
  53. case 42: return "datetime2";
  54. case 43: return "datetimeoffset";
  55. case 45: return "binary"; /* Sybase AS12 */
  56. case 47: return "char"; /* & nchar & uniqueidentifierstr Sybase AS12 */
  57. case 48: return "tinyint";
  58. case 50: return "bit"; /* Sybase AS12 */
  59. case 52: return "smallint";
  60. case 55: return "decimal"; /* Sybase AS12 */
  61. case 56: return "int";
  62. case 58: return "smalldatetime";
  63. case 59: return "real";
  64. case 60: return "money";
  65. case 61: return "datetime";
  66. case 62: return "float";
  67. case 63: return "numeric"; /* or uint, ubigint, usmallint Sybase AS12 */
  68. case 98: return "sql_variant";
  69. case 99: return "ntext";
  70. case 104: return "bit";
  71. case 106: return "decimal"; /* decimal n on sybase */
  72. case 108: return "numeric"; /* numeric n on sybase */
  73. case 122: return "smallmoney";
  74. case 127: return "bigint";
  75. case 165: return "varbinary";
  76. case 167: return "varchar";
  77. case 173: return "binary";
  78. case 175: return "char";
  79. case 189: return "timestamp";
  80. case 231: return "nvarchar";
  81. case 239: return "nchar";
  82. case 240: return "geometry";
  83. case 241: return "xml";
  84. default: return "unknown";
  85. }
  86. }
  87. /* }}} */
  88. static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt)
  89. {
  90. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  91. pdo_dblib_db_handle *H = S->H;
  92. /* Cancel any pending results */
  93. dbcancel(H->link);
  94. pdo_dblib_err_dtor(&H->err);
  95. return 1;
  96. }
  97. static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt)
  98. {
  99. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  100. pdo_dblib_err_dtor(&S->err);
  101. efree(S);
  102. return 1;
  103. }
  104. static int pdo_dblib_stmt_next_rowset_no_cancel(pdo_stmt_t *stmt)
  105. {
  106. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  107. pdo_dblib_db_handle *H = S->H;
  108. RETCODE ret;
  109. int num_fields;
  110. do {
  111. ret = dbresults(H->link);
  112. num_fields = dbnumcols(H->link);
  113. } while (H->skip_empty_rowsets && num_fields <= 0 && ret == SUCCEED);
  114. if (FAIL == ret) {
  115. pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL");
  116. return 0;
  117. }
  118. if (NO_MORE_RESULTS == ret) {
  119. return 0;
  120. }
  121. if (H->skip_empty_rowsets && num_fields <= 0) {
  122. return 0;
  123. }
  124. stmt->row_count = DBCOUNT(H->link);
  125. stmt->column_count = num_fields;
  126. return 1;
  127. }
  128. static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt)
  129. {
  130. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  131. pdo_dblib_db_handle *H = S->H;
  132. RETCODE ret = SUCCESS;
  133. /* Ideally use dbcanquery here, but there is a bug in FreeTDS's implementation of dbcanquery
  134. * It has been resolved but is currently only available in nightly builds
  135. */
  136. while (NO_MORE_ROWS != ret) {
  137. ret = dbnextrow(H->link);
  138. if (FAIL == ret) {
  139. pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL");
  140. return 0;
  141. }
  142. }
  143. return pdo_dblib_stmt_next_rowset_no_cancel(stmt);
  144. }
  145. static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt)
  146. {
  147. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  148. pdo_dblib_db_handle *H = S->H;
  149. dbsetuserdata(H->link, (BYTE*) &S->err);
  150. pdo_dblib_stmt_cursor_closer(stmt);
  151. if (FAIL == dbcmd(H->link, ZSTR_VAL(stmt->active_query_string))) {
  152. return 0;
  153. }
  154. if (FAIL == dbsqlexec(H->link)) {
  155. return 0;
  156. }
  157. pdo_dblib_stmt_next_rowset_no_cancel(stmt);
  158. stmt->row_count = DBCOUNT(H->link);
  159. stmt->column_count = dbnumcols(H->link);
  160. return 1;
  161. }
  162. static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
  163. enum pdo_fetch_orientation ori, zend_long offset)
  164. {
  165. RETCODE ret;
  166. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  167. pdo_dblib_db_handle *H = S->H;
  168. ret = dbnextrow(H->link);
  169. if (FAIL == ret) {
  170. pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL");
  171. return 0;
  172. }
  173. if(NO_MORE_ROWS == ret) {
  174. return 0;
  175. }
  176. return 1;
  177. }
  178. static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno)
  179. {
  180. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  181. pdo_dblib_db_handle *H = S->H;
  182. struct pdo_column_data *col;
  183. char *fname;
  184. if(colno >= stmt->column_count || colno < 0) {
  185. return FAILURE;
  186. }
  187. if (colno == 0) {
  188. S->computed_column_name_count = 0;
  189. }
  190. col = &stmt->columns[colno];
  191. fname = (char*)dbcolname(H->link, colno+1);
  192. if (fname && *fname) {
  193. col->name = zend_string_init(fname, strlen(fname), 0);
  194. } else {
  195. if (S->computed_column_name_count > 0) {
  196. char buf[16];
  197. int len;
  198. len = snprintf(buf, sizeof(buf), "computed%d", S->computed_column_name_count);
  199. col->name = zend_string_init(buf, len, 0);
  200. } else {
  201. col->name = zend_string_init("computed", strlen("computed"), 0);
  202. }
  203. S->computed_column_name_count++;
  204. }
  205. col->maxlen = dbcollen(H->link, colno+1);
  206. return 1;
  207. }
  208. static int pdo_dblib_stmt_should_stringify_col(pdo_stmt_t *stmt, int coltype)
  209. {
  210. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  211. pdo_dblib_db_handle *H = S->H;
  212. switch (coltype) {
  213. case SQLDECIMAL:
  214. case SQLNUMERIC:
  215. case SQLMONEY:
  216. case SQLMONEY4:
  217. case SQLMONEYN:
  218. case SQLFLT4:
  219. case SQLFLT8:
  220. case SQLINT4:
  221. case SQLINT2:
  222. case SQLINT1:
  223. case SQLBIT:
  224. if (stmt->dbh->stringify) {
  225. return 1;
  226. }
  227. break;
  228. case SQLINT8:
  229. if (stmt->dbh->stringify) {
  230. return 1;
  231. }
  232. /* force stringify if DBBIGINT won't fit in zend_long */
  233. /* this should only be an issue for 32-bit machines */
  234. if (sizeof(zend_long) < sizeof(DBBIGINT)) {
  235. return 1;
  236. }
  237. break;
  238. #ifdef SQLMSDATETIME2
  239. case SQLMSDATETIME2:
  240. #endif
  241. case SQLDATETIME:
  242. case SQLDATETIM4:
  243. if (H->datetime_convert) {
  244. return 1;
  245. }
  246. break;
  247. }
  248. return 0;
  249. }
  250. static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_len, zval *zv)
  251. {
  252. DBCHAR *tmp_data;
  253. /* FIXME: We allocate more than we need here */
  254. DBINT tmp_data_len = 32 + (2 * (data_len));
  255. switch (coltype) {
  256. case SQLDATETIME:
  257. case SQLDATETIM4: {
  258. if (tmp_data_len < DATETIME_MAX_LEN) {
  259. tmp_data_len = DATETIME_MAX_LEN;
  260. }
  261. break;
  262. }
  263. }
  264. tmp_data = emalloc(tmp_data_len);
  265. data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len);
  266. if (data_len > 0) {
  267. /* to prevent overflows, tmp_data_len is provided as a dest len for dbconvert()
  268. * this code previously passed a dest len of -1
  269. * the FreeTDS impl of dbconvert() does an rtrim with that value, so replicate that behavior
  270. */
  271. while (data_len > 0 && tmp_data[data_len - 1] == ' ') {
  272. data_len--;
  273. }
  274. ZVAL_STRINGL(zv, tmp_data, data_len);
  275. } else {
  276. ZVAL_EMPTY_STRING(zv);
  277. }
  278. efree(tmp_data);
  279. }
  280. static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *zv, enum pdo_param_type *type)
  281. {
  282. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  283. pdo_dblib_db_handle *H = S->H;
  284. int coltype;
  285. LPBYTE data;
  286. DBCHAR *tmp_data;
  287. DBINT data_len, tmp_data_len;
  288. coltype = dbcoltype(H->link, colno+1);
  289. data = dbdata(H->link, colno+1);
  290. data_len = dbdatlen(H->link, colno+1);
  291. if (data_len != 0 || data != NULL) {
  292. if (pdo_dblib_stmt_should_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) {
  293. pdo_dblib_stmt_stringify_col(coltype, data, data_len, zv);
  294. } else {
  295. switch (coltype) {
  296. case SQLCHAR:
  297. case SQLVARCHAR:
  298. case SQLTEXT: {
  299. #ifdef ilia_0
  300. while (data_len>0 && data[data_len-1] == ' ') { /* nuke trailing whitespace */
  301. data_len--;
  302. }
  303. #endif
  304. }
  305. case SQLVARBINARY:
  306. case SQLBINARY:
  307. case SQLIMAGE: {
  308. ZVAL_STRINGL(zv, (DBCHAR *) data, data_len);
  309. break;
  310. }
  311. #ifdef SQLMSDATETIME2
  312. case SQLMSDATETIME2:
  313. #endif
  314. case SQLDATETIME:
  315. case SQLDATETIM4: {
  316. size_t dl;
  317. DBDATEREC di;
  318. DBDATEREC dt;
  319. dbconvert(H->link, coltype, data, -1, SQLDATETIME, (LPBYTE) &dt, -1);
  320. dbdatecrack(H->link, &di, (DBDATETIME *) &dt);
  321. dl = spprintf(&tmp_data, 20, "%04d-%02d-%02d %02d:%02d:%02d",
  322. #if defined(PHP_DBLIB_IS_MSSQL) || defined(MSDBLIB)
  323. di.year, di.month, di.day, di.hour, di.minute, di.second
  324. #else
  325. di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond
  326. #endif
  327. );
  328. ZVAL_STRINGL(zv, tmp_data, dl);
  329. efree(tmp_data);
  330. break;
  331. }
  332. case SQLFLT4:
  333. ZVAL_DOUBLE(zv, *(DBFLT4 *) data);
  334. break;
  335. case SQLFLT8:
  336. ZVAL_DOUBLE(zv, *(DBFLT8 *) data);
  337. break;
  338. case SQLINT8:
  339. ZVAL_LONG(zv, *(DBBIGINT *) data);
  340. break;
  341. case SQLINT4:
  342. ZVAL_LONG(zv, *(DBINT *) data);
  343. break;
  344. case SQLINT2:
  345. ZVAL_LONG(zv, *(DBSMALLINT *) data);
  346. break;
  347. case SQLINT1:
  348. case SQLBIT:
  349. ZVAL_LONG(zv, *(DBTINYINT *) data);
  350. break;
  351. case SQLDECIMAL:
  352. case SQLNUMERIC:
  353. case SQLMONEY:
  354. case SQLMONEY4:
  355. case SQLMONEYN: {
  356. DBFLT8 float_value;
  357. dbconvert(NULL, coltype, data, 8, SQLFLT8, (LPBYTE) &float_value, -1);
  358. ZVAL_DOUBLE(zv, float_value);
  359. break;
  360. }
  361. case SQLUNIQUE: {
  362. if (H->stringify_uniqueidentifier) {
  363. /* 36-char hex string representation */
  364. tmp_data_len = 36;
  365. tmp_data = safe_emalloc(tmp_data_len, sizeof(char), 1);
  366. data_len = dbconvert(NULL, SQLUNIQUE, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len);
  367. php_strtoupper(tmp_data, data_len);
  368. ZVAL_STRINGL(zv, tmp_data, data_len);
  369. efree(tmp_data);
  370. } else {
  371. /* 16-byte binary representation */
  372. ZVAL_STRINGL(zv, (DBCHAR *) data, 16);
  373. }
  374. break;
  375. }
  376. default: {
  377. if (dbwillconvert(coltype, SQLCHAR)) {
  378. pdo_dblib_stmt_stringify_col(coltype, data, data_len, zv);
  379. }
  380. break;
  381. }
  382. }
  383. }
  384. }
  385. return 1;
  386. }
  387. static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value)
  388. {
  389. pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
  390. pdo_dblib_db_handle *H = S->H;
  391. DBTYPEINFO* dbtypeinfo;
  392. int coltype;
  393. if(colno >= stmt->column_count || colno < 0) {
  394. return FAILURE;
  395. }
  396. array_init(return_value);
  397. dbtypeinfo = dbcoltypeinfo(H->link, colno+1);
  398. if(!dbtypeinfo) return FAILURE;
  399. coltype = dbcoltype(H->link, colno+1);
  400. add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
  401. add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
  402. add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
  403. add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1));
  404. add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(coltype));
  405. add_assoc_long(return_value, "native_type_id", coltype);
  406. add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1));
  407. switch (coltype) {
  408. case SQLBIT:
  409. case SQLINT1:
  410. case SQLINT2:
  411. case SQLINT4:
  412. add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
  413. break;
  414. default:
  415. add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
  416. break;
  417. }
  418. return 1;
  419. }
  420. const struct pdo_stmt_methods dblib_stmt_methods = {
  421. pdo_dblib_stmt_dtor,
  422. pdo_dblib_stmt_execute,
  423. pdo_dblib_stmt_fetch,
  424. pdo_dblib_stmt_describe,
  425. pdo_dblib_stmt_get_col,
  426. NULL, /* param hook */
  427. NULL, /* set attr */
  428. NULL, /* get attr */
  429. pdo_dblib_stmt_get_column_meta, /* meta */
  430. pdo_dblib_stmt_next_rowset, /* nextrow */
  431. pdo_dblib_stmt_cursor_closer
  432. };