dblib_stmt.c 14 KB

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