mysqlnd_ps.c 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2006-2016 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. | Authors: Andrey Hristov <andrey@mysql.com> |
  16. | Ulf Wendel <uwendel@mysql.com> |
  17. | Georg Richter <georg@mysql.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #include "php.h"
  22. #include "mysqlnd.h"
  23. #include "mysqlnd_wireprotocol.h"
  24. #include "mysqlnd_priv.h"
  25. #include "mysqlnd_result.h"
  26. #include "mysqlnd_result_meta.h"
  27. #include "mysqlnd_statistics.h"
  28. #include "mysqlnd_debug.h"
  29. #include "mysqlnd_block_alloc.h"
  30. #include "mysqlnd_ext_plugin.h"
  31. #define MYSQLND_SILENT
  32. const char * const mysqlnd_not_bound_as_blob = "Can't send long data for non-string/non-binary data types";
  33. const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
  34. /* Exported by mysqlnd_ps_codec.c */
  35. enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC);
  36. static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
  37. static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC);
  38. /* {{{ mysqlnd_stmt::store_result */
  39. static MYSQLND_RES *
  40. MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
  41. {
  42. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  43. enum_func_status ret;
  44. MYSQLND_CONN_DATA * conn;
  45. MYSQLND_RES * result;
  46. DBG_ENTER("mysqlnd_stmt::store_result");
  47. if (!stmt || !stmt->conn || !stmt->result) {
  48. DBG_RETURN(NULL);
  49. }
  50. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  51. conn = stmt->conn;
  52. /* be compliant with libmysql - NULL will turn */
  53. if (!stmt->field_count) {
  54. DBG_RETURN(NULL);
  55. }
  56. if (stmt->cursor_exists) {
  57. /* Silently convert buffered to unbuffered, for now */
  58. DBG_RETURN(s->m->use_result(s TSRMLS_CC));
  59. }
  60. /* Nothing to store for UPSERT/LOAD DATA*/
  61. if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA ||
  62. stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
  63. {
  64. SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
  65. UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  66. DBG_RETURN(NULL);
  67. }
  68. stmt->default_rset_handler = s->m->store_result;
  69. SET_EMPTY_ERROR(*stmt->error_info);
  70. SET_EMPTY_ERROR(*conn->error_info);
  71. MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
  72. result = stmt->result;
  73. result->type = MYSQLND_RES_PS_BUF;
  74. /* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
  75. result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, TRUE, result->persistent TSRMLS_CC);
  76. if (!result->stored_data) {
  77. SET_OOM_ERROR(*conn->error_info);
  78. DBG_RETURN(NULL);
  79. }
  80. ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE TSRMLS_CC);
  81. result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered;
  82. if (PASS == ret) {
  83. /* Overflow ? */
  84. if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
  85. MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
  86. if (result->stored_data->row_count) {
  87. /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */
  88. if (result->stored_data->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) {
  89. SET_OOM_ERROR(*conn->error_info);
  90. DBG_RETURN(NULL);
  91. }
  92. /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */
  93. set->data = mnd_emalloc((size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
  94. if (!set->data) {
  95. SET_OOM_ERROR(*conn->error_info);
  96. DBG_RETURN(NULL);
  97. }
  98. memset(set->data, 0, (size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
  99. }
  100. /* Position at the first row */
  101. set->data_cursor = set->data;
  102. } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
  103. /*TODO*/
  104. }
  105. /* libmysql API docs say it should be so for SELECT statements */
  106. stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count;
  107. stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
  108. } else {
  109. COPY_CLIENT_ERROR(*conn->error_info, result->stored_data->error_info);
  110. stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
  111. mnd_efree(stmt->result);
  112. stmt->result = NULL;
  113. stmt->state = MYSQLND_STMT_PREPARED;
  114. }
  115. DBG_RETURN(result);
  116. }
  117. /* }}} */
  118. /* {{{ mysqlnd_stmt::get_result */
  119. static MYSQLND_RES *
  120. MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
  121. {
  122. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  123. MYSQLND_CONN_DATA * conn;
  124. MYSQLND_RES *result;
  125. DBG_ENTER("mysqlnd_stmt::get_result");
  126. if (!stmt || !stmt->conn || !stmt->result) {
  127. DBG_RETURN(NULL);
  128. }
  129. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  130. conn = stmt->conn;
  131. /* be compliant with libmysql - NULL will turn */
  132. if (!stmt->field_count) {
  133. DBG_RETURN(NULL);
  134. }
  135. if (stmt->cursor_exists) {
  136. /* Silently convert buffered to unbuffered, for now */
  137. DBG_RETURN(s->m->use_result(s TSRMLS_CC));
  138. }
  139. /* Nothing to store for UPSERT/LOAD DATA*/
  140. if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
  141. SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
  142. UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  143. DBG_RETURN(NULL);
  144. }
  145. SET_EMPTY_ERROR(*stmt->error_info);
  146. SET_EMPTY_ERROR(*conn->error_info);
  147. MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
  148. do {
  149. result = conn->m->result_init(stmt->result->field_count, stmt->persistent TSRMLS_CC);
  150. if (!result) {
  151. SET_OOM_ERROR(*conn->error_info);
  152. break;
  153. }
  154. result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
  155. if (!result->meta) {
  156. SET_OOM_ERROR(*conn->error_info);
  157. break;
  158. }
  159. if ((result = result->m.store_result(result, conn, MYSQLND_STORE_PS | MYSQLND_STORE_NO_COPY TSRMLS_CC))) {
  160. stmt->upsert_status->affected_rows = result->stored_data->row_count;
  161. stmt->state = MYSQLND_STMT_PREPARED;
  162. result->type = MYSQLND_RES_PS_BUF;
  163. } else {
  164. COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
  165. stmt->state = MYSQLND_STMT_PREPARED;
  166. break;
  167. }
  168. DBG_RETURN(result);
  169. } while (0);
  170. if (result) {
  171. result->m.free_result(result, TRUE TSRMLS_CC);
  172. }
  173. DBG_RETURN(NULL);
  174. }
  175. /* }}} */
  176. /* {{{ mysqlnd_stmt::more_results */
  177. static zend_bool
  178. MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * s TSRMLS_DC)
  179. {
  180. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  181. DBG_ENTER("mysqlnd_stmt::more_results");
  182. /* (conn->state == CONN_NEXT_RESULT_PENDING) too */
  183. DBG_RETURN((stmt && stmt->conn && (stmt->conn->m->get_server_status(stmt->conn TSRMLS_CC) & SERVER_MORE_RESULTS_EXISTS))?
  184. TRUE:
  185. FALSE);
  186. }
  187. /* }}} */
  188. /* {{{ mysqlnd_stmt::next_result */
  189. static enum_func_status
  190. MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC)
  191. {
  192. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  193. MYSQLND_CONN_DATA * conn;
  194. DBG_ENTER("mysqlnd_stmt::next_result");
  195. if (!stmt || !stmt->conn || !stmt->result) {
  196. DBG_RETURN(FAIL);
  197. }
  198. conn = stmt->conn;
  199. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  200. if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS)) {
  201. DBG_RETURN(FAIL);
  202. }
  203. DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
  204. /* Free space for next result */
  205. s->m->free_stmt_result(s TSRMLS_CC);
  206. {
  207. enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC);
  208. DBG_RETURN(ret);
  209. }
  210. }
  211. /* }}} */
  212. /* {{{ mysqlnd_stmt_skip_metadata */
  213. static enum_func_status
  214. mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC)
  215. {
  216. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  217. /* Follows parameter metadata, we have just to skip it, as libmysql does */
  218. unsigned int i = 0;
  219. enum_func_status ret = FAIL;
  220. MYSQLND_PACKET_RES_FIELD * field_packet;
  221. DBG_ENTER("mysqlnd_stmt_skip_metadata");
  222. if (!stmt || !stmt->conn || !stmt->conn->protocol) {
  223. DBG_RETURN(FAIL);
  224. }
  225. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  226. field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
  227. if (!field_packet) {
  228. SET_OOM_ERROR(*stmt->error_info);
  229. SET_OOM_ERROR(*stmt->conn->error_info);
  230. } else {
  231. ret = PASS;
  232. field_packet->skip_parsing = TRUE;
  233. for (;i < stmt->param_count; i++) {
  234. if (FAIL == PACKET_READ(field_packet, stmt->conn)) {
  235. ret = FAIL;
  236. break;
  237. }
  238. }
  239. PACKET_FREE(field_packet);
  240. }
  241. DBG_RETURN(ret);
  242. }
  243. /* }}} */
  244. /* {{{ mysqlnd_stmt_read_prepare_response */
  245. static enum_func_status
  246. mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
  247. {
  248. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  249. MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp;
  250. enum_func_status ret = FAIL;
  251. DBG_ENTER("mysqlnd_stmt_read_prepare_response");
  252. if (!stmt || !stmt->conn || !stmt->conn->protocol) {
  253. DBG_RETURN(FAIL);
  254. }
  255. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  256. prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
  257. if (!prepare_resp) {
  258. SET_OOM_ERROR(*stmt->error_info);
  259. SET_OOM_ERROR(*stmt->conn->error_info);
  260. goto done;
  261. }
  262. if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) {
  263. goto done;
  264. }
  265. if (0xFF == prepare_resp->error_code) {
  266. COPY_CLIENT_ERROR(*stmt->error_info, prepare_resp->error_info);
  267. COPY_CLIENT_ERROR(*stmt->conn->error_info, prepare_resp->error_info);
  268. goto done;
  269. }
  270. ret = PASS;
  271. stmt->stmt_id = prepare_resp->stmt_id;
  272. stmt->warning_count = stmt->conn->upsert_status->warning_count = prepare_resp->warning_count;
  273. stmt->field_count = stmt->conn->field_count = prepare_resp->field_count;
  274. stmt->param_count = prepare_resp->param_count;
  275. stmt->upsert_status->affected_rows = 0; /* be like libmysql */
  276. done:
  277. PACKET_FREE(prepare_resp);
  278. DBG_RETURN(ret);
  279. }
  280. /* }}} */
  281. /* {{{ mysqlnd_stmt_prepare_read_eof */
  282. static enum_func_status
  283. mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC)
  284. {
  285. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  286. MYSQLND_PACKET_EOF * fields_eof;
  287. enum_func_status ret = FAIL;
  288. DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
  289. if (!stmt || !stmt->conn || !stmt->conn->protocol) {
  290. DBG_RETURN(FAIL);
  291. }
  292. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  293. fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
  294. if (!fields_eof) {
  295. SET_OOM_ERROR(*stmt->error_info);
  296. SET_OOM_ERROR(*stmt->conn->error_info);
  297. } else {
  298. if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
  299. if (stmt->result) {
  300. stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
  301. mnd_efree(stmt->result);
  302. memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
  303. stmt->state = MYSQLND_STMT_INITTED;
  304. }
  305. } else {
  306. stmt->upsert_status->server_status = fields_eof->server_status;
  307. stmt->upsert_status->warning_count = fields_eof->warning_count;
  308. stmt->state = MYSQLND_STMT_PREPARED;
  309. }
  310. PACKET_FREE(fields_eof);
  311. }
  312. DBG_RETURN(ret);
  313. }
  314. /* }}} */
  315. /* {{{ mysqlnd_stmt::prepare */
  316. static enum_func_status
  317. MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const query, unsigned int query_len TSRMLS_DC)
  318. {
  319. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  320. MYSQLND_STMT * s_to_prepare = s;
  321. MYSQLND_STMT_DATA * stmt_to_prepare = stmt;
  322. DBG_ENTER("mysqlnd_stmt::prepare");
  323. if (!stmt || !stmt->conn) {
  324. DBG_RETURN(FAIL);
  325. }
  326. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  327. DBG_INF_FMT("query=%s", query);
  328. SET_ERROR_AFF_ROWS(stmt);
  329. SET_ERROR_AFF_ROWS(stmt->conn);
  330. SET_EMPTY_ERROR(*stmt->error_info);
  331. SET_EMPTY_ERROR(*stmt->conn->error_info);
  332. if (stmt->state > MYSQLND_STMT_INITTED) {
  333. /* See if we have to clean the wire */
  334. if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
  335. /* Do implicit use_result and then flush the result */
  336. stmt->default_rset_handler = s->m->use_result;
  337. stmt->default_rset_handler(s TSRMLS_CC);
  338. }
  339. /* No 'else' here please :) */
  340. if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE && stmt->result) {
  341. stmt->result->m.skip_result(stmt->result TSRMLS_CC);
  342. }
  343. /*
  344. Create a new test statement, which we will prepare, but if anything
  345. fails, we will scrap it.
  346. */
  347. s_to_prepare = stmt->conn->m->stmt_init(stmt->conn TSRMLS_CC);
  348. if (!s_to_prepare) {
  349. goto fail;
  350. }
  351. stmt_to_prepare = s_to_prepare->data;
  352. }
  353. if (FAIL == stmt_to_prepare->conn->m->simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, (const zend_uchar *) query, query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) ||
  354. FAIL == mysqlnd_stmt_read_prepare_response(s_to_prepare TSRMLS_CC))
  355. {
  356. goto fail;
  357. }
  358. if (stmt_to_prepare->param_count) {
  359. if (FAIL == mysqlnd_stmt_skip_metadata(s_to_prepare TSRMLS_CC) ||
  360. FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
  361. {
  362. goto fail;
  363. }
  364. }
  365. /*
  366. Read metadata only if there is actual result set.
  367. Beware that SHOW statements bypass the PS framework and thus they send
  368. no metadata at prepare.
  369. */
  370. if (stmt_to_prepare->field_count) {
  371. MYSQLND_RES * result = stmt->conn->m->result_init(stmt_to_prepare->field_count, stmt_to_prepare->persistent TSRMLS_CC);
  372. if (!result) {
  373. SET_OOM_ERROR(*stmt->conn->error_info);
  374. goto fail;
  375. }
  376. /* Allocate the result now as it is needed for the reading of metadata */
  377. stmt_to_prepare->result = result;
  378. result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn TSRMLS_CC);
  379. result->type = MYSQLND_RES_PS_BUF;
  380. if (FAIL == result->m.read_result_metadata(result, stmt_to_prepare->conn TSRMLS_CC) ||
  381. FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
  382. {
  383. goto fail;
  384. }
  385. }
  386. if (stmt_to_prepare != stmt) {
  387. /* swap */
  388. size_t real_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
  389. char * tmp_swap = mnd_malloc(real_size);
  390. memcpy(tmp_swap, s, real_size);
  391. memcpy(s, s_to_prepare, real_size);
  392. memcpy(s_to_prepare, tmp_swap, real_size);
  393. mnd_free(tmp_swap);
  394. {
  395. MYSQLND_STMT_DATA * tmp_swap_data = stmt_to_prepare;
  396. stmt_to_prepare = stmt;
  397. stmt = tmp_swap_data;
  398. }
  399. s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
  400. }
  401. stmt->state = MYSQLND_STMT_PREPARED;
  402. DBG_INF("PASS");
  403. DBG_RETURN(PASS);
  404. fail:
  405. if (stmt_to_prepare != stmt && s_to_prepare) {
  406. s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
  407. }
  408. stmt->state = MYSQLND_STMT_INITTED;
  409. DBG_INF("FAIL");
  410. DBG_RETURN(FAIL);
  411. }
  412. /* }}} */
  413. /* {{{ mysqlnd_stmt_execute_parse_response */
  414. static enum_func_status
  415. mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC)
  416. {
  417. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  418. enum_func_status ret;
  419. MYSQLND_CONN_DATA * conn;
  420. DBG_ENTER("mysqlnd_stmt_execute_parse_response");
  421. if (!stmt || !stmt->conn) {
  422. DBG_RETURN(FAIL);
  423. }
  424. conn = stmt->conn;
  425. CONN_SET_STATE(conn, CONN_QUERY_SENT);
  426. ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC);
  427. if (ret == FAIL) {
  428. COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
  429. memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status));
  430. stmt->upsert_status->affected_rows = conn->upsert_status->affected_rows;
  431. if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
  432. /* close the statement here, the connection has been closed */
  433. }
  434. stmt->state = MYSQLND_STMT_PREPARED;
  435. stmt->send_types_to_server = 1;
  436. } else {
  437. /*
  438. stmt->send_types_to_server has already been set to 0 in
  439. mysqlnd_stmt_execute_generate_request / mysqlnd_stmt_execute_store_params
  440. In case there is a situation in which binding was done for integer and the
  441. value is > LONG_MAX or < LONG_MIN, there is string conversion and we have
  442. to resend the types. Next execution will also need to resend the type.
  443. */
  444. SET_EMPTY_ERROR(*stmt->error_info);
  445. SET_EMPTY_ERROR(*stmt->conn->error_info);
  446. *stmt->upsert_status = *conn->upsert_status; /* copy status */
  447. stmt->state = MYSQLND_STMT_EXECUTED;
  448. if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type == QUERY_LOAD_LOCAL) {
  449. DBG_INF("PASS");
  450. DBG_RETURN(PASS);
  451. }
  452. stmt->result->type = MYSQLND_RES_PS_BUF;
  453. if (!stmt->result->conn) {
  454. /*
  455. For SHOW we don't create (bypasses PS in server)
  456. a result set at prepare and thus a connection was missing
  457. */
  458. stmt->result->conn = stmt->conn->m->get_reference(stmt->conn TSRMLS_CC);
  459. }
  460. /* Update stmt->field_count as SHOW sets it to 0 at prepare */
  461. stmt->field_count = stmt->result->field_count = conn->field_count;
  462. if (stmt->result->stored_data) {
  463. stmt->result->stored_data->lengths = NULL;
  464. } else if (stmt->result->unbuf) {
  465. stmt->result->unbuf->lengths = NULL;
  466. }
  467. if (stmt->field_count) {
  468. stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
  469. /*
  470. We need to set this because the user might not call
  471. use_result() or store_result() and we should be able to scrap the
  472. data on the line, if he just decides to close the statement.
  473. */
  474. DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status,
  475. stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
  476. if (stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS) {
  477. DBG_INF("cursor exists");
  478. stmt->cursor_exists = TRUE;
  479. CONN_SET_STATE(conn, CONN_READY);
  480. /* Only cursor read */
  481. stmt->default_rset_handler = s->m->use_result;
  482. DBG_INF("use_result");
  483. } else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
  484. DBG_INF("asked for cursor but got none");
  485. /*
  486. We have asked for CURSOR but got no cursor, because the condition
  487. above is not fulfilled. Then...
  488. This is a single-row result set, a result set with no rows, EXPLAIN,
  489. SHOW VARIABLES, or some other command which either a) bypasses the
  490. cursors framework in the server and writes rows directly to the
  491. network or b) is more efficient if all (few) result set rows are
  492. precached on client and server's resources are freed.
  493. */
  494. /* preferred is buffered read */
  495. stmt->default_rset_handler = s->m->store_result;
  496. DBG_INF("store_result");
  497. } else {
  498. DBG_INF("no cursor");
  499. /* preferred is unbuffered read */
  500. stmt->default_rset_handler = s->m->use_result;
  501. DBG_INF("use_result");
  502. }
  503. }
  504. }
  505. #ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET
  506. if (stmt->upsert_status->server_status & SERVER_PS_OUT_PARAMS) {
  507. s->m->free_stmt_content(s TSRMLS_CC);
  508. DBG_INF("PS OUT Variable RSet, skipping");
  509. /* OUT params result set. Skip for now to retain compatibility */
  510. ret = mysqlnd_stmt_execute_parse_response(s TSRMLS_CC);
  511. }
  512. #endif
  513. DBG_INF(ret == PASS? "PASS":"FAIL");
  514. DBG_RETURN(ret);
  515. }
  516. /* }}} */
  517. /* {{{ mysqlnd_stmt::execute */
  518. static enum_func_status
  519. MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
  520. {
  521. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  522. enum_func_status ret;
  523. MYSQLND_CONN_DATA * conn;
  524. zend_uchar *request = NULL;
  525. size_t request_len;
  526. zend_bool free_request;
  527. DBG_ENTER("mysqlnd_stmt::execute");
  528. if (!stmt || !stmt->conn) {
  529. DBG_RETURN(FAIL);
  530. }
  531. conn = stmt->conn;
  532. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  533. SET_ERROR_AFF_ROWS(stmt);
  534. SET_ERROR_AFF_ROWS(stmt->conn);
  535. if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) {
  536. /*
  537. We don need to copy the data from the buffers which we will clean.
  538. Because it has already been copied. See
  539. #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  540. */
  541. #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  542. if (stmt->result_bind &&
  543. stmt->result_zvals_separated_once == TRUE &&
  544. stmt->state >= MYSQLND_STMT_USER_FETCHING)
  545. {
  546. /*
  547. We need to copy the data from the buffers which we will clean.
  548. The bound variables point to them only if the user has started
  549. to fetch data (MYSQLND_STMT_USER_FETCHING).
  550. We need to check 'result_zvals_separated_once' or we will leak
  551. in the following scenario
  552. prepare("select 1 from dual");
  553. execute();
  554. fetch(); <-- no binding, but that's not a problem
  555. bind_result();
  556. execute(); <-- here we will leak because we separate without need
  557. */
  558. unsigned int i;
  559. for (i = 0; i < stmt->field_count; i++) {
  560. if (stmt->result_bind[i].bound == TRUE) {
  561. zval_copy_ctor(stmt->result_bind[i].zv);
  562. }
  563. }
  564. }
  565. #endif
  566. s->m->flush(s TSRMLS_CC);
  567. /*
  568. Executed, but the user hasn't started to fetch
  569. This will clean also the metadata, but after the EXECUTE call we will
  570. have it again.
  571. */
  572. stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
  573. stmt->state = MYSQLND_STMT_PREPARED;
  574. } else if (stmt->state < MYSQLND_STMT_PREPARED) {
  575. /* Only initted - error */
  576. SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
  577. mysqlnd_out_of_sync);
  578. SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  579. DBG_INF("FAIL");
  580. DBG_RETURN(FAIL);
  581. }
  582. if (stmt->param_count) {
  583. unsigned int i, not_bound = 0;
  584. if (!stmt->param_bind) {
  585. SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
  586. "No data supplied for parameters in prepared statement");
  587. DBG_INF("FAIL");
  588. DBG_RETURN(FAIL);
  589. }
  590. for (i = 0; i < stmt->param_count; i++) {
  591. if (stmt->param_bind[i].zv == NULL) {
  592. not_bound++;
  593. }
  594. }
  595. if (not_bound) {
  596. char * msg;
  597. mnd_sprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement",
  598. not_bound, not_bound>1 ?"s":"");
  599. SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, msg);
  600. if (msg) {
  601. mnd_sprintf_free(msg);
  602. }
  603. DBG_INF("FAIL");
  604. DBG_RETURN(FAIL);
  605. }
  606. }
  607. ret = s->m->generate_execute_request(s, &request, &request_len, &free_request TSRMLS_CC);
  608. if (ret == PASS) {
  609. /* support for buffer types should be added here ! */
  610. ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, request, request_len,
  611. PROT_LAST /* we will handle the response packet*/,
  612. FALSE, FALSE TSRMLS_CC);
  613. } else {
  614. SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM.");
  615. }
  616. if (free_request) {
  617. mnd_efree(request);
  618. }
  619. if (ret == FAIL) {
  620. COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
  621. DBG_INF("FAIL");
  622. DBG_RETURN(FAIL);
  623. }
  624. stmt->execute_count++;
  625. ret = s->m->parse_execute_response(s TSRMLS_CC);
  626. DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
  627. if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status->affected_rows) {
  628. MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status->affected_rows);
  629. }
  630. DBG_RETURN(ret);
  631. }
  632. /* }}} */
  633. /* {{{ mysqlnd_stmt_fetch_row_buffered */
  634. enum_func_status
  635. mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
  636. {
  637. MYSQLND_STMT * s = (MYSQLND_STMT *) param;
  638. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  639. const MYSQLND_RES_METADATA * const meta = result->meta;
  640. unsigned int field_count = meta->field_count;
  641. DBG_ENTER("mysqlnd_stmt_fetch_row_buffered");
  642. *fetched_anything = FALSE;
  643. DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L);
  644. /* If we haven't read everything */
  645. if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
  646. MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
  647. if (set->data_cursor &&
  648. (set->data_cursor - set->data) < (result->stored_data->row_count * field_count))
  649. {
  650. /* The user could have skipped binding - don't crash*/
  651. if (stmt->result_bind) {
  652. unsigned int i;
  653. zval **current_row = set->data_cursor;
  654. if (NULL == current_row[0]) {
  655. uint64_t row_num = (set->data_cursor - set->data) / field_count;
  656. enum_func_status rc = result->stored_data->m.row_decoder(result->stored_data->row_buffers[row_num],
  657. current_row,
  658. meta->field_count,
  659. meta->fields,
  660. result->conn->options->int_and_float_native,
  661. result->conn->stats TSRMLS_CC);
  662. if (PASS != rc) {
  663. DBG_RETURN(FAIL);
  664. }
  665. result->stored_data->initialized_rows++;
  666. if (stmt->update_max_length) {
  667. for (i = 0; i < result->field_count; i++) {
  668. /*
  669. NULL fields are 0 length, 0 is not more than 0
  670. String of zero size, definitely can't be the next max_length.
  671. Thus for NULL and zero-length we are quite efficient.
  672. */
  673. if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
  674. unsigned long len = Z_STRLEN_P(current_row[i]);
  675. if (meta->fields[i].max_length < len) {
  676. meta->fields[i].max_length = len;
  677. }
  678. }
  679. }
  680. }
  681. }
  682. for (i = 0; i < result->field_count; i++) {
  683. /* Clean what we copied last time */
  684. #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  685. if (stmt->result_bind[i].zv) {
  686. zval_dtor(stmt->result_bind[i].zv);
  687. }
  688. #endif
  689. /* copy the type */
  690. if (stmt->result_bind[i].bound == TRUE) {
  691. DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
  692. if (Z_TYPE_P(current_row[i]) != IS_NULL) {
  693. /*
  694. Copy the value.
  695. Pre-condition is that the zvals in the result_bind buffer
  696. have been ZVAL_NULL()-ed or to another simple type
  697. (int, double, bool but not string). Because of the reference
  698. counting the user can't delete the strings the variables point to.
  699. */
  700. Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
  701. stmt->result_bind[i].zv->value = current_row[i]->value;
  702. #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  703. zval_copy_ctor(stmt->result_bind[i].zv);
  704. #endif
  705. } else {
  706. ZVAL_NULL(stmt->result_bind[i].zv);
  707. }
  708. }
  709. }
  710. }
  711. set->data_cursor += field_count;
  712. *fetched_anything = TRUE;
  713. /* buffered result sets don't have a connection */
  714. MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
  715. DBG_INF("row fetched");
  716. } else {
  717. set->data_cursor = NULL;
  718. DBG_INF("no more data");
  719. }
  720. } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) {
  721. /*TODO*/
  722. }
  723. DBG_INF("PASS");
  724. DBG_RETURN(PASS);
  725. }
  726. /* }}} */
  727. /* {{{ mysqlnd_stmt_fetch_row_unbuffered */
  728. enum_func_status
  729. mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
  730. {
  731. enum_func_status ret;
  732. MYSQLND_STMT * s = (MYSQLND_STMT *) param;
  733. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  734. MYSQLND_PACKET_ROW * row_packet;
  735. const MYSQLND_RES_METADATA * const meta = result->meta;
  736. DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
  737. *fetched_anything = FALSE;
  738. if (result->unbuf->eof_reached) {
  739. /* No more rows obviously */
  740. DBG_INF("EOF already reached");
  741. DBG_RETURN(PASS);
  742. }
  743. if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) {
  744. SET_CLIENT_ERROR(*result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
  745. UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  746. DBG_ERR("command out of sync");
  747. DBG_RETURN(FAIL);
  748. }
  749. if (!(row_packet = result->unbuf->row_packet)) {
  750. DBG_RETURN(FAIL);
  751. }
  752. /* Let the row packet fill our buffer and skip additional malloc + memcpy */
  753. row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
  754. /*
  755. If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to
  756. result->unbuf->m.free_last_data() before it. The function returns always true.
  757. */
  758. if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
  759. unsigned int i, field_count = result->field_count;
  760. if (!row_packet->skip_extraction) {
  761. result->unbuf->m.free_last_data(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC);
  762. result->unbuf->last_row_data = row_packet->fields;
  763. result->unbuf->last_row_buffer = row_packet->row_buffer;
  764. row_packet->fields = NULL;
  765. row_packet->row_buffer = NULL;
  766. if (PASS != result->unbuf->m.row_decoder(result->unbuf->last_row_buffer,
  767. result->unbuf->last_row_data,
  768. row_packet->field_count,
  769. row_packet->fields_metadata,
  770. result->conn->options->int_and_float_native,
  771. result->conn->stats TSRMLS_CC))
  772. {
  773. DBG_RETURN(FAIL);
  774. }
  775. for (i = 0; i < field_count; i++) {
  776. if (stmt->result_bind[i].bound == TRUE) {
  777. zval *data = result->unbuf->last_row_data[i];
  778. /*
  779. stmt->result_bind[i].zv has been already destructed
  780. in result->unbuf->m.free_last_data()
  781. */
  782. #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  783. zval_dtor(stmt->result_bind[i].zv);
  784. #endif
  785. if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
  786. if ((Z_TYPE_P(data) == IS_STRING) && (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) {
  787. meta->fields[i].max_length = Z_STRLEN_P(data);
  788. }
  789. stmt->result_bind[i].zv->value = data->value;
  790. /* copied data, thus also the ownership. Thus null data */
  791. ZVAL_NULL(data);
  792. }
  793. }
  794. }
  795. MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF);
  796. } else {
  797. DBG_INF("skipping extraction");
  798. /*
  799. Data has been allocated and usually result->unbuf->m.free_last_data()
  800. frees it but we can't call this function as it will cause problems with
  801. the bound variables. Thus we need to do part of what it does or Zend will
  802. report leaks.
  803. */
  804. row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
  805. row_packet->row_buffer = NULL;
  806. }
  807. result->unbuf->row_count++;
  808. *fetched_anything = TRUE;
  809. } else if (ret == FAIL) {
  810. if (row_packet->error_info.error_no) {
  811. COPY_CLIENT_ERROR(*stmt->conn->error_info, row_packet->error_info);
  812. COPY_CLIENT_ERROR(*stmt->error_info, row_packet->error_info);
  813. }
  814. CONN_SET_STATE(result->conn, CONN_READY);
  815. result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
  816. } else if (row_packet->eof) {
  817. DBG_INF("EOF");
  818. /* Mark the connection as usable again */
  819. result->unbuf->eof_reached = TRUE;
  820. memset(result->conn->upsert_status, 0, sizeof(*result->conn->upsert_status));
  821. result->conn->upsert_status->warning_count = row_packet->warning_count;
  822. result->conn->upsert_status->server_status = row_packet->server_status;
  823. /*
  824. result->row_packet will be cleaned when
  825. destroying the result object
  826. */
  827. if (result->conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS) {
  828. CONN_SET_STATE(result->conn, CONN_NEXT_RESULT_PENDING);
  829. } else {
  830. CONN_SET_STATE(result->conn, CONN_READY);
  831. }
  832. }
  833. DBG_INF_FMT("ret=%s fetched_anything=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
  834. DBG_RETURN(ret);
  835. }
  836. /* }}} */
  837. /* {{{ mysqlnd_stmt::use_result */
  838. static MYSQLND_RES *
  839. MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC)
  840. {
  841. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  842. MYSQLND_RES * result;
  843. MYSQLND_CONN_DATA * conn;
  844. DBG_ENTER("mysqlnd_stmt::use_result");
  845. if (!stmt || !stmt->conn || !stmt->result) {
  846. DBG_RETURN(NULL);
  847. }
  848. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  849. conn = stmt->conn;
  850. if (!stmt->field_count ||
  851. (!stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_FETCHING_DATA) ||
  852. (stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) ||
  853. (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
  854. {
  855. SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
  856. UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  857. DBG_ERR("command out of sync");
  858. DBG_RETURN(NULL);
  859. }
  860. SET_EMPTY_ERROR(*stmt->error_info);
  861. MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);
  862. result = stmt->result;
  863. result->m.use_result(stmt->result, TRUE TSRMLS_CC);
  864. result->unbuf->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
  865. mysqlnd_stmt_fetch_row_unbuffered;
  866. stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
  867. DBG_INF_FMT("%p", result);
  868. DBG_RETURN(result);
  869. }
  870. /* }}} */
  871. #define STMT_ID_LENGTH 4
  872. /* {{{ mysqlnd_fetch_row_cursor */
  873. enum_func_status
  874. mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
  875. {
  876. enum_func_status ret;
  877. MYSQLND_STMT * s = (MYSQLND_STMT *) param;
  878. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  879. zend_uchar buf[STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
  880. MYSQLND_PACKET_ROW * row_packet;
  881. DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
  882. if (!stmt || !stmt->conn || !result || !result->conn || !result->unbuf) {
  883. DBG_ERR("no statement");
  884. DBG_RETURN(FAIL);
  885. }
  886. DBG_INF_FMT("stmt=%lu flags=%u", stmt->stmt_id, flags);
  887. if (stmt->state < MYSQLND_STMT_USER_FETCHING) {
  888. /* Only initted - error */
  889. SET_CLIENT_ERROR(*stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
  890. mysqlnd_out_of_sync);
  891. DBG_ERR("command out of sync");
  892. DBG_RETURN(FAIL);
  893. }
  894. if (!(row_packet = result->unbuf->row_packet)) {
  895. DBG_RETURN(FAIL);
  896. }
  897. SET_EMPTY_ERROR(*stmt->error_info);
  898. SET_EMPTY_ERROR(*stmt->conn->error_info);
  899. int4store(buf, stmt->stmt_id);
  900. int4store(buf + STMT_ID_LENGTH, 1); /* for now fetch only one row */
  901. if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, buf, sizeof(buf),
  902. PROT_LAST /* we will handle the response packet*/,
  903. FALSE, TRUE TSRMLS_CC)) {
  904. COPY_CLIENT_ERROR(*stmt->error_info, *stmt->conn->error_info);
  905. DBG_RETURN(FAIL);
  906. }
  907. row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
  908. memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status));
  909. if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
  910. const MYSQLND_RES_METADATA * const meta = result->meta;
  911. unsigned int i, field_count = result->field_count;
  912. if (!row_packet->skip_extraction) {
  913. result->unbuf->m.free_last_data(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC);
  914. result->unbuf->last_row_data = row_packet->fields;
  915. result->unbuf->last_row_buffer = row_packet->row_buffer;
  916. row_packet->fields = NULL;
  917. row_packet->row_buffer = NULL;
  918. if (PASS != result->unbuf->m.row_decoder(result->unbuf->last_row_buffer,
  919. result->unbuf->last_row_data,
  920. row_packet->field_count,
  921. row_packet->fields_metadata,
  922. result->conn->options->int_and_float_native,
  923. result->conn->stats TSRMLS_CC))
  924. {
  925. DBG_RETURN(FAIL);
  926. }
  927. /* If no result bind, do nothing. We consumed the data */
  928. for (i = 0; i < field_count; i++) {
  929. if (stmt->result_bind[i].bound == TRUE) {
  930. zval *data = result->unbuf->last_row_data[i];
  931. /*
  932. stmt->result_bind[i].zv has been already destructed
  933. in result->unbuf->m.free_last_data()
  934. */
  935. #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  936. zval_dtor(stmt->result_bind[i].zv);
  937. #endif
  938. DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, stmt->result_bind[i].zv,
  939. Z_TYPE_P(data), Z_REFCOUNT_P(stmt->result_bind[i].zv));
  940. if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data))) {
  941. if ((Z_TYPE_P(data) == IS_STRING) && (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) {
  942. meta->fields[i].max_length = Z_STRLEN_P(data);
  943. }
  944. stmt->result_bind[i].zv->value = data->value;
  945. /* copied data, thus also the ownership. Thus null data */
  946. ZVAL_NULL(data);
  947. }
  948. }
  949. }
  950. } else {
  951. DBG_INF("skipping extraction");
  952. /*
  953. Data has been allocated and usually result->unbuf->m.free_last_data()
  954. frees it but we can't call this function as it will cause problems with
  955. the bound variables. Thus we need to do part of what it does or Zend will
  956. report leaks.
  957. */
  958. row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
  959. row_packet->row_buffer = NULL;
  960. }
  961. /* We asked for one row, the next one should be EOF, eat it */
  962. ret = PACKET_READ(row_packet, result->conn);
  963. if (row_packet->row_buffer) {
  964. row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
  965. row_packet->row_buffer = NULL;
  966. }
  967. MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
  968. result->unbuf->row_count++;
  969. *fetched_anything = TRUE;
  970. } else {
  971. *fetched_anything = FALSE;
  972. stmt->upsert_status->warning_count =
  973. stmt->conn->upsert_status->warning_count =
  974. row_packet->warning_count;
  975. stmt->upsert_status->server_status =
  976. stmt->conn->upsert_status->server_status =
  977. row_packet->server_status;
  978. result->unbuf->eof_reached = row_packet->eof;
  979. }
  980. stmt->upsert_status->warning_count =
  981. stmt->conn->upsert_status->warning_count =
  982. row_packet->warning_count;
  983. stmt->upsert_status->server_status =
  984. stmt->conn->upsert_status->server_status =
  985. row_packet->server_status;
  986. DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u",
  987. ret == PASS? "PASS":"FAIL", *fetched_anything,
  988. row_packet->server_status, row_packet->warning_count,
  989. result->unbuf->eof_reached);
  990. DBG_RETURN(ret);
  991. }
  992. /* }}} */
  993. /* {{{ mysqlnd_stmt::fetch */
  994. static enum_func_status
  995. MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fetched_anything TSRMLS_DC)
  996. {
  997. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  998. enum_func_status ret;
  999. DBG_ENTER("mysqlnd_stmt::fetch");
  1000. if (!stmt || !stmt->conn) {
  1001. DBG_RETURN(FAIL);
  1002. }
  1003. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  1004. if (!stmt->result ||
  1005. stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
  1006. SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  1007. DBG_ERR("command out of sync");
  1008. DBG_RETURN(FAIL);
  1009. } else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
  1010. /* Execute only once. We have to free the previous contents of user's bound vars */
  1011. stmt->default_rset_handler(s TSRMLS_CC);
  1012. }
  1013. stmt->state = MYSQLND_STMT_USER_FETCHING;
  1014. SET_EMPTY_ERROR(*stmt->error_info);
  1015. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1016. DBG_INF_FMT("result_bind=%p separated_once=%u", stmt->result_bind, stmt->result_zvals_separated_once);
  1017. /*
  1018. The user might have not bound any variables for result.
  1019. Do the binding once she does it.
  1020. */
  1021. if (stmt->result_bind && !stmt->result_zvals_separated_once) {
  1022. unsigned int i;
  1023. /*
  1024. mysqlnd_stmt_store_result() has been called free the bind
  1025. variables to prevent leaking of their previous content.
  1026. */
  1027. for (i = 0; i < stmt->result->field_count; i++) {
  1028. if (stmt->result_bind[i].bound == TRUE) {
  1029. zval_dtor(stmt->result_bind[i].zv);
  1030. ZVAL_NULL(stmt->result_bind[i].zv);
  1031. }
  1032. }
  1033. stmt->result_zvals_separated_once = TRUE;
  1034. }
  1035. ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything TSRMLS_CC);
  1036. DBG_RETURN(ret);
  1037. }
  1038. /* }}} */
  1039. /* {{{ mysqlnd_stmt::reset */
  1040. static enum_func_status
  1041. MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s TSRMLS_DC)
  1042. {
  1043. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1044. enum_func_status ret = PASS;
  1045. zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
  1046. DBG_ENTER("mysqlnd_stmt::reset");
  1047. if (!stmt || !stmt->conn) {
  1048. DBG_RETURN(FAIL);
  1049. }
  1050. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  1051. SET_EMPTY_ERROR(*stmt->error_info);
  1052. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1053. if (stmt->stmt_id) {
  1054. MYSQLND_CONN_DATA * conn = stmt->conn;
  1055. if (stmt->param_bind) {
  1056. unsigned int i;
  1057. DBG_INF("resetting long data");
  1058. /* Reset Long Data */
  1059. for (i = 0; i < stmt->param_count; i++) {
  1060. if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
  1061. stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
  1062. }
  1063. }
  1064. }
  1065. s->m->flush(s TSRMLS_CC);
  1066. /*
  1067. Don't free now, let the result be usable. When the stmt will again be
  1068. executed then the result set will be cleaned, the bound variables will
  1069. be separated before that.
  1070. */
  1071. int4store(cmd_buf, stmt->stmt_id);
  1072. if (CONN_GET_STATE(conn) == CONN_READY &&
  1073. FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, cmd_buf,
  1074. sizeof(cmd_buf), PROT_OK_PACKET,
  1075. FALSE, TRUE TSRMLS_CC))) {
  1076. COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
  1077. }
  1078. *stmt->upsert_status = *conn->upsert_status;
  1079. }
  1080. DBG_INF(ret == PASS? "PASS":"FAIL");
  1081. DBG_RETURN(ret);
  1082. }
  1083. /* }}} */
  1084. /* {{{ mysqlnd_stmt::flush */
  1085. static enum_func_status
  1086. MYSQLND_METHOD(mysqlnd_stmt, flush)(MYSQLND_STMT * const s TSRMLS_DC)
  1087. {
  1088. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1089. enum_func_status ret = PASS;
  1090. DBG_ENTER("mysqlnd_stmt::flush");
  1091. if (!stmt || !stmt->conn) {
  1092. DBG_RETURN(FAIL);
  1093. }
  1094. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  1095. if (stmt->stmt_id) {
  1096. /*
  1097. If the user decided to close the statement right after execute()
  1098. We have to call the appropriate use_result() or store_result() and
  1099. clean.
  1100. */
  1101. do {
  1102. if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
  1103. DBG_INF("fetching result set header");
  1104. stmt->default_rset_handler(s TSRMLS_CC);
  1105. stmt->state = MYSQLND_STMT_USER_FETCHING;
  1106. }
  1107. if (stmt->result) {
  1108. DBG_INF("skipping result");
  1109. stmt->result->m.skip_result(stmt->result TSRMLS_CC);
  1110. }
  1111. } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
  1112. }
  1113. DBG_INF(ret == PASS? "PASS":"FAIL");
  1114. DBG_RETURN(ret);
  1115. }
  1116. /* }}} */
  1117. /* {{{ mysqlnd_stmt::send_long_data */
  1118. static enum_func_status
  1119. MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
  1120. const char * const data, unsigned long length TSRMLS_DC)
  1121. {
  1122. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1123. enum_func_status ret = FAIL;
  1124. MYSQLND_CONN_DATA * conn;
  1125. zend_uchar * cmd_buf;
  1126. enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
  1127. DBG_ENTER("mysqlnd_stmt::send_long_data");
  1128. if (!stmt || !stmt->conn) {
  1129. DBG_RETURN(FAIL);
  1130. }
  1131. DBG_INF_FMT("stmt=%lu param_no=%u data_len=%lu", stmt->stmt_id, param_no, length);
  1132. conn = stmt->conn;
  1133. SET_EMPTY_ERROR(*stmt->error_info);
  1134. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1135. if (stmt->state < MYSQLND_STMT_PREPARED) {
  1136. SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
  1137. DBG_ERR("not prepared");
  1138. DBG_RETURN(FAIL);
  1139. }
  1140. if (!stmt->param_bind) {
  1141. SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  1142. DBG_ERR("command out of sync");
  1143. DBG_RETURN(FAIL);
  1144. }
  1145. if (param_no >= stmt->param_count) {
  1146. SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
  1147. DBG_ERR("invalid param_no");
  1148. DBG_RETURN(FAIL);
  1149. }
  1150. if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {
  1151. SET_STMT_ERROR(stmt, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, mysqlnd_not_bound_as_blob);
  1152. DBG_ERR("param_no is not of a blob type");
  1153. DBG_RETURN(FAIL);
  1154. }
  1155. /*
  1156. XXX: Unfortunately we have to allocate additional buffer to be able the
  1157. additional data, which is like a header inside the payload.
  1158. This should be optimised, but it will be a pervasive change, so
  1159. conn->m->simple_command() will accept not a buffer, but actually MYSQLND_STRING*
  1160. terminated by NULL, to send. If the strings are not big, we can collapse them
  1161. on the buffer every connection has, but otherwise we will just send them
  1162. one by one to the wire.
  1163. */
  1164. if (CONN_GET_STATE(conn) == CONN_READY) {
  1165. size_t packet_len;
  1166. cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
  1167. if (cmd_buf) {
  1168. stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
  1169. int4store(cmd_buf, stmt->stmt_id);
  1170. int2store(cmd_buf + STMT_ID_LENGTH, param_no);
  1171. memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length);
  1172. /* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/
  1173. ret = conn->m->simple_command(conn, cmd, cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC);
  1174. mnd_efree(cmd_buf);
  1175. if (FAIL == ret) {
  1176. COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
  1177. }
  1178. } else {
  1179. ret = FAIL;
  1180. SET_OOM_ERROR(*stmt->error_info);
  1181. SET_OOM_ERROR(*conn->error_info);
  1182. }
  1183. /*
  1184. Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not
  1185. sent response packets. According to documentation the only way to get an error
  1186. is to have out-of-memory on the server-side. However, that's not true, as if
  1187. max_allowed_packet_size is smaller than the chunk being sent to the server, the
  1188. latter will complain with an error message. However, normally we don't expect
  1189. an error message, thus we continue. When sending the next command, which expects
  1190. response we will read the unexpected data and error message will look weird.
  1191. Therefore we do non-blocking read to clean the line, if there is a need.
  1192. Nevertheless, there is a built-in protection when sending a command packet, that
  1193. checks if the line is clear - useful for debug purposes and to be switched off
  1194. in release builds.
  1195. Maybe we can make it automatic by checking what's the value of
  1196. max_allowed_packet_size on the server and resending the data.
  1197. */
  1198. #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
  1199. #if HAVE_USLEEP && !defined(PHP_WIN32)
  1200. usleep(120000);
  1201. #endif
  1202. if ((packet_len = conn->net->m.consume_uneaten_data(conn->net, cmd TSRMLS_CC))) {
  1203. php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error "
  1204. "while sending long data. Probably max_allowed_packet_size "
  1205. "is smaller than the data. You have to increase it or send "
  1206. "smaller chunks of data. Answer was "MYSQLND_SZ_T_SPEC" bytes long.", packet_len);
  1207. SET_STMT_ERROR(stmt, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE,
  1208. "Server responded to COM_STMT_SEND_LONG_DATA.");
  1209. ret = FAIL;
  1210. }
  1211. #endif
  1212. }
  1213. DBG_INF(ret == PASS? "PASS":"FAIL");
  1214. DBG_RETURN(ret);
  1215. }
  1216. /* }}} */
  1217. /* {{{ mysqlnd_stmt::bind_parameters */
  1218. static enum_func_status
  1219. MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
  1220. {
  1221. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1222. DBG_ENTER("mysqlnd_stmt::bind_param");
  1223. if (!stmt || !stmt->conn) {
  1224. DBG_RETURN(FAIL);
  1225. }
  1226. DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
  1227. if (stmt->state < MYSQLND_STMT_PREPARED) {
  1228. SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
  1229. DBG_ERR("not prepared");
  1230. if (param_bind) {
  1231. s->m->free_parameter_bind(s, param_bind TSRMLS_CC);
  1232. }
  1233. DBG_RETURN(FAIL);
  1234. }
  1235. SET_EMPTY_ERROR(*stmt->error_info);
  1236. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1237. if (stmt->param_count) {
  1238. unsigned int i = 0;
  1239. if (!param_bind) {
  1240. SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported");
  1241. DBG_ERR("Re-binding (still) not supported");
  1242. DBG_RETURN(FAIL);
  1243. } else if (stmt->param_bind) {
  1244. DBG_INF("Binding");
  1245. /*
  1246. There is already result bound.
  1247. Forbid for now re-binding!!
  1248. */
  1249. for (i = 0; i < stmt->param_count; i++) {
  1250. /*
  1251. We may have the last reference, then call zval_ptr_dtor() or we may leak memory.
  1252. Switching from bind_one_parameter to bind_parameters may result in zv being NULL
  1253. */
  1254. if (stmt->param_bind[i].zv) {
  1255. zval_ptr_dtor(&stmt->param_bind[i].zv);
  1256. }
  1257. }
  1258. if (stmt->param_bind != param_bind) {
  1259. s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
  1260. }
  1261. }
  1262. stmt->param_bind = param_bind;
  1263. for (i = 0; i < stmt->param_count; i++) {
  1264. /* The client will use stmt_send_long_data */
  1265. DBG_INF_FMT("%u is of type %u", i, stmt->param_bind[i].type);
  1266. /* Prevent from freeing */
  1267. /* Don't update is_ref, or we will leak during conversion */
  1268. Z_ADDREF_P(stmt->param_bind[i].zv);
  1269. stmt->param_bind[i].flags = 0;
  1270. if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
  1271. stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
  1272. }
  1273. }
  1274. stmt->send_types_to_server = 1;
  1275. }
  1276. DBG_INF("PASS");
  1277. DBG_RETURN(PASS);
  1278. }
  1279. /* }}} */
  1280. /* {{{ mysqlnd_stmt::bind_one_parameter */
  1281. static enum_func_status
  1282. MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigned int param_no,
  1283. zval * const zv, zend_uchar type TSRMLS_DC)
  1284. {
  1285. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1286. DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
  1287. if (!stmt || !stmt->conn) {
  1288. DBG_RETURN(FAIL);
  1289. }
  1290. DBG_INF_FMT("stmt=%lu param_no=%u param_count=%u type=%u", stmt->stmt_id, param_no, stmt->param_count, type);
  1291. if (stmt->state < MYSQLND_STMT_PREPARED) {
  1292. SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
  1293. DBG_ERR("not prepared");
  1294. DBG_RETURN(FAIL);
  1295. }
  1296. if (param_no >= stmt->param_count) {
  1297. SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
  1298. DBG_ERR("invalid param_no");
  1299. DBG_RETURN(FAIL);
  1300. }
  1301. SET_EMPTY_ERROR(*stmt->error_info);
  1302. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1303. if (stmt->param_count) {
  1304. if (!stmt->param_bind) {
  1305. stmt->param_bind = mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent);
  1306. if (!stmt->param_bind) {
  1307. DBG_RETURN(FAIL);
  1308. }
  1309. }
  1310. /* Prevent from freeing */
  1311. /* Don't update is_ref, or we will leak during conversion */
  1312. Z_ADDREF_P(zv);
  1313. DBG_INF("Binding");
  1314. /* Release what we had, if we had */
  1315. if (stmt->param_bind[param_no].zv) {
  1316. zval_ptr_dtor(&stmt->param_bind[param_no].zv);
  1317. }
  1318. if (type == MYSQL_TYPE_LONG_BLOB) {
  1319. /* The client will use stmt_send_long_data */
  1320. stmt->param_bind[param_no].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
  1321. }
  1322. stmt->param_bind[param_no].zv = zv;
  1323. stmt->param_bind[param_no].type = type;
  1324. stmt->send_types_to_server = 1;
  1325. }
  1326. DBG_INF("PASS");
  1327. DBG_RETURN(PASS);
  1328. }
  1329. /* }}} */
  1330. /* {{{ mysqlnd_stmt::refresh_bind_param */
  1331. static enum_func_status
  1332. MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const s TSRMLS_DC)
  1333. {
  1334. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1335. DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
  1336. if (!stmt || !stmt->conn) {
  1337. DBG_RETURN(FAIL);
  1338. }
  1339. DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
  1340. if (stmt->state < MYSQLND_STMT_PREPARED) {
  1341. SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
  1342. DBG_ERR("not prepared");
  1343. DBG_RETURN(FAIL);
  1344. }
  1345. SET_EMPTY_ERROR(*stmt->error_info);
  1346. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1347. if (stmt->param_count) {
  1348. stmt->send_types_to_server = 1;
  1349. }
  1350. DBG_RETURN(PASS);
  1351. }
  1352. /* }}} */
  1353. /* {{{ mysqlnd_stmt::bind_result */
  1354. static enum_func_status
  1355. MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
  1356. MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC)
  1357. {
  1358. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1359. DBG_ENTER("mysqlnd_stmt::bind_result");
  1360. if (!stmt || !stmt->conn) {
  1361. DBG_RETURN(FAIL);
  1362. }
  1363. DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
  1364. if (stmt->state < MYSQLND_STMT_PREPARED) {
  1365. SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
  1366. if (result_bind) {
  1367. s->m->free_result_bind(s, result_bind TSRMLS_CC);
  1368. }
  1369. DBG_ERR("not prepared");
  1370. DBG_RETURN(FAIL);
  1371. }
  1372. SET_EMPTY_ERROR(*stmt->error_info);
  1373. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1374. if (stmt->field_count) {
  1375. unsigned int i = 0;
  1376. if (!result_bind) {
  1377. DBG_ERR("no result bind passed");
  1378. DBG_RETURN(FAIL);
  1379. }
  1380. mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
  1381. stmt->result_zvals_separated_once = FALSE;
  1382. stmt->result_bind = result_bind;
  1383. for (i = 0; i < stmt->field_count; i++) {
  1384. /* Prevent from freeing */
  1385. Z_ADDREF_P(stmt->result_bind[i].zv);
  1386. DBG_INF_FMT("ref of %p = %u", stmt->result_bind[i].zv, Z_REFCOUNT_P(stmt->result_bind[i].zv));
  1387. /*
  1388. Don't update is_ref !!! it's not our job
  1389. Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
  1390. will fail.
  1391. */
  1392. stmt->result_bind[i].bound = TRUE;
  1393. }
  1394. } else if (result_bind) {
  1395. s->m->free_result_bind(s, result_bind TSRMLS_CC);
  1396. }
  1397. DBG_INF("PASS");
  1398. DBG_RETURN(PASS);
  1399. }
  1400. /* }}} */
  1401. /* {{{ mysqlnd_stmt::bind_result */
  1402. static enum_func_status
  1403. MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
  1404. {
  1405. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1406. DBG_ENTER("mysqlnd_stmt::bind_result");
  1407. if (!stmt || !stmt->conn) {
  1408. DBG_RETURN(FAIL);
  1409. }
  1410. DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
  1411. if (stmt->state < MYSQLND_STMT_PREPARED) {
  1412. SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
  1413. DBG_ERR("not prepared");
  1414. DBG_RETURN(FAIL);
  1415. }
  1416. if (param_no >= stmt->field_count) {
  1417. SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
  1418. DBG_ERR("invalid param_no");
  1419. DBG_RETURN(FAIL);
  1420. }
  1421. SET_EMPTY_ERROR(*stmt->error_info);
  1422. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1423. if (stmt->field_count) {
  1424. mysqlnd_stmt_separate_one_result_bind(s, param_no TSRMLS_CC);
  1425. /* Guaranteed is that stmt->result_bind is NULL */
  1426. if (!stmt->result_bind) {
  1427. stmt->result_bind = mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent);
  1428. } else {
  1429. stmt->result_bind = mnd_perealloc(stmt->result_bind, stmt->field_count * sizeof(MYSQLND_RESULT_BIND), stmt->persistent);
  1430. }
  1431. if (!stmt->result_bind) {
  1432. DBG_RETURN(FAIL);
  1433. }
  1434. ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
  1435. /*
  1436. Don't update is_ref !!! it's not our job
  1437. Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
  1438. will fail.
  1439. */
  1440. stmt->result_bind[param_no].bound = TRUE;
  1441. }
  1442. DBG_INF("PASS");
  1443. DBG_RETURN(PASS);
  1444. }
  1445. /* }}} */
  1446. /* {{{ mysqlnd_stmt::insert_id */
  1447. static uint64_t
  1448. MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s TSRMLS_DC)
  1449. {
  1450. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1451. return stmt? stmt->upsert_status->last_insert_id : 0;
  1452. }
  1453. /* }}} */
  1454. /* {{{ mysqlnd_stmt::affected_rows */
  1455. static uint64_t
  1456. MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
  1457. {
  1458. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1459. return stmt? stmt->upsert_status->affected_rows : 0;
  1460. }
  1461. /* }}} */
  1462. /* {{{ mysqlnd_stmt::num_rows */
  1463. static uint64_t
  1464. MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
  1465. {
  1466. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1467. return stmt && stmt->result? mysqlnd_num_rows(stmt->result):0;
  1468. }
  1469. /* }}} */
  1470. /* {{{ mysqlnd_stmt::warning_count */
  1471. static unsigned int
  1472. MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s TSRMLS_DC)
  1473. {
  1474. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1475. return stmt? stmt->upsert_status->warning_count : 0;
  1476. }
  1477. /* }}} */
  1478. /* {{{ mysqlnd_stmt::server_status */
  1479. static unsigned int
  1480. MYSQLND_METHOD(mysqlnd_stmt, server_status)(const MYSQLND_STMT * const s TSRMLS_DC)
  1481. {
  1482. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1483. return stmt? stmt->upsert_status->server_status : 0;
  1484. }
  1485. /* }}} */
  1486. /* {{{ mysqlnd_stmt::field_count */
  1487. static unsigned int
  1488. MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const s TSRMLS_DC)
  1489. {
  1490. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1491. return stmt? stmt->field_count : 0;
  1492. }
  1493. /* }}} */
  1494. /* {{{ mysqlnd_stmt::param_count */
  1495. static unsigned int
  1496. MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const s TSRMLS_DC)
  1497. {
  1498. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1499. return stmt? stmt->param_count : 0;
  1500. }
  1501. /* }}} */
  1502. /* {{{ mysqlnd_stmt::errno */
  1503. static unsigned int
  1504. MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s TSRMLS_DC)
  1505. {
  1506. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1507. return stmt? stmt->error_info->error_no : 0;
  1508. }
  1509. /* }}} */
  1510. /* {{{ mysqlnd_stmt::error */
  1511. static const char *
  1512. MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s TSRMLS_DC)
  1513. {
  1514. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1515. return stmt? stmt->error_info->error : 0;
  1516. }
  1517. /* }}} */
  1518. /* {{{ mysqlnd_stmt::sqlstate */
  1519. static const char *
  1520. MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s TSRMLS_DC)
  1521. {
  1522. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1523. return stmt && stmt->error_info->sqlstate[0] ? stmt->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
  1524. }
  1525. /* }}} */
  1526. /* {{{ mysqlnd_stmt::data_seek */
  1527. static enum_func_status
  1528. MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const s, uint64_t row TSRMLS_DC)
  1529. {
  1530. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1531. return stmt && stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
  1532. }
  1533. /* }}} */
  1534. /* {{{ mysqlnd_stmt::param_metadata */
  1535. static MYSQLND_RES *
  1536. MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
  1537. {
  1538. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1539. if (!stmt || !stmt->param_count) {
  1540. return NULL;
  1541. }
  1542. return NULL;
  1543. }
  1544. /* }}} */
  1545. /* {{{ mysqlnd_stmt::result_metadata */
  1546. static MYSQLND_RES *
  1547. MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
  1548. {
  1549. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1550. MYSQLND_RES *result;
  1551. DBG_ENTER("mysqlnd_stmt::result_metadata");
  1552. if (!stmt) {
  1553. DBG_RETURN(NULL);
  1554. }
  1555. DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
  1556. if (!stmt->field_count || !stmt->conn || !stmt->result || !stmt->result->meta) {
  1557. DBG_INF("NULL");
  1558. DBG_RETURN(NULL);
  1559. }
  1560. if (stmt->update_max_length && stmt->result->stored_data) {
  1561. /* stored result, we have to update the max_length before we clone the meta data :( */
  1562. stmt->result->stored_data->m.initialize_result_set_rest(stmt->result->stored_data, stmt->result->meta, stmt->conn->stats,
  1563. stmt->conn->options->int_and_float_native TSRMLS_CC);
  1564. }
  1565. /*
  1566. TODO: This implementation is kind of a hack,
  1567. find a better way to do it. In different functions I have put
  1568. fuses to check for result->m.fetch_row() being NULL. This should
  1569. be handled in a better way.
  1570. In the meantime we don't need a zval cache reference for this fake
  1571. result set, so we don't get one.
  1572. */
  1573. do {
  1574. result = stmt->conn->m->result_init(stmt->field_count, stmt->persistent TSRMLS_CC);
  1575. if (!result) {
  1576. break;
  1577. }
  1578. result->type = MYSQLND_RES_NORMAL;
  1579. result->unbuf = mysqlnd_result_unbuffered_init(stmt->field_count, TRUE, result->persistent TSRMLS_CC);
  1580. if (!result->unbuf) {
  1581. break;
  1582. }
  1583. result->unbuf->eof_reached = TRUE;
  1584. result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
  1585. if (!result->meta) {
  1586. break;
  1587. }
  1588. DBG_INF_FMT("result=%p", result);
  1589. DBG_RETURN(result);
  1590. } while (0);
  1591. SET_OOM_ERROR(*stmt->conn->error_info);
  1592. if (result) {
  1593. result->m.free_result(result, TRUE TSRMLS_CC);
  1594. }
  1595. DBG_RETURN(NULL);
  1596. }
  1597. /* }}} */
  1598. /* {{{ mysqlnd_stmt::attr_set */
  1599. static enum_func_status
  1600. MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
  1601. enum mysqlnd_stmt_attr attr_type,
  1602. const void * const value TSRMLS_DC)
  1603. {
  1604. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1605. DBG_ENTER("mysqlnd_stmt::attr_set");
  1606. if (!stmt) {
  1607. DBG_RETURN(FAIL);
  1608. }
  1609. DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
  1610. switch (attr_type) {
  1611. case STMT_ATTR_UPDATE_MAX_LENGTH:{
  1612. zend_uchar bval = *(zend_uchar *) value;
  1613. /*
  1614. XXX : libmysql uses my_bool, but mysqli uses ulong as storage on the stack
  1615. and mysqlnd won't be used out of the scope of PHP -> use ulong.
  1616. */
  1617. stmt->update_max_length = bval? TRUE:FALSE;
  1618. break;
  1619. }
  1620. case STMT_ATTR_CURSOR_TYPE: {
  1621. unsigned int ival = *(unsigned int *) value;
  1622. if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) {
  1623. SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
  1624. DBG_INF("FAIL");
  1625. DBG_RETURN(FAIL);
  1626. }
  1627. stmt->flags = ival;
  1628. break;
  1629. }
  1630. case STMT_ATTR_PREFETCH_ROWS: {
  1631. unsigned int ival = *(unsigned int *) value;
  1632. if (ival == 0) {
  1633. ival = MYSQLND_DEFAULT_PREFETCH_ROWS;
  1634. } else if (ival > 1) {
  1635. SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
  1636. DBG_INF("FAIL");
  1637. DBG_RETURN(FAIL);
  1638. }
  1639. stmt->prefetch_rows = ival;
  1640. break;
  1641. }
  1642. default:
  1643. SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
  1644. DBG_RETURN(FAIL);
  1645. }
  1646. DBG_INF("PASS");
  1647. DBG_RETURN(PASS);
  1648. }
  1649. /* }}} */
  1650. /* {{{ mysqlnd_stmt::attr_get */
  1651. static enum_func_status
  1652. MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
  1653. enum mysqlnd_stmt_attr attr_type,
  1654. void * const value TSRMLS_DC)
  1655. {
  1656. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1657. DBG_ENTER("mysqlnd_stmt::attr_set");
  1658. if (!stmt) {
  1659. DBG_RETURN(FAIL);
  1660. }
  1661. DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
  1662. switch (attr_type) {
  1663. case STMT_ATTR_UPDATE_MAX_LENGTH:
  1664. *(zend_bool *) value= stmt->update_max_length;
  1665. break;
  1666. case STMT_ATTR_CURSOR_TYPE:
  1667. *(unsigned long *) value= stmt->flags;
  1668. break;
  1669. case STMT_ATTR_PREFETCH_ROWS:
  1670. *(unsigned long *) value= stmt->prefetch_rows;
  1671. break;
  1672. default:
  1673. DBG_RETURN(FAIL);
  1674. }
  1675. DBG_INF_FMT("value=%lu", value);
  1676. DBG_RETURN(PASS);
  1677. }
  1678. /* }}} */
  1679. /* free_result() doesn't actually free stmt->result but only the buffers */
  1680. /* {{{ mysqlnd_stmt::free_result */
  1681. static enum_func_status
  1682. MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s TSRMLS_DC)
  1683. {
  1684. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1685. DBG_ENTER("mysqlnd_stmt::free_result");
  1686. if (!stmt || !stmt->conn) {
  1687. DBG_RETURN(FAIL);
  1688. }
  1689. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  1690. if (!stmt->result) {
  1691. DBG_INF("no result");
  1692. DBG_RETURN(PASS);
  1693. }
  1694. /*
  1695. If right after execute() we have to call the appropriate
  1696. use_result() or store_result() and clean.
  1697. */
  1698. if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
  1699. DBG_INF("fetching result set header");
  1700. /* Do implicit use_result and then flush the result */
  1701. stmt->default_rset_handler = s->m->use_result;
  1702. stmt->default_rset_handler(s TSRMLS_CC);
  1703. }
  1704. if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
  1705. DBG_INF("skipping result");
  1706. /* Flush if anything is left and unbuffered set */
  1707. stmt->result->m.skip_result(stmt->result TSRMLS_CC);
  1708. /*
  1709. Separate the bound variables, which point to the result set, then
  1710. destroy the set.
  1711. */
  1712. mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
  1713. /* Now we can destroy the result set */
  1714. stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
  1715. }
  1716. if (stmt->state > MYSQLND_STMT_PREPARED) {
  1717. /* As the buffers have been freed, we should go back to PREPARED */
  1718. stmt->state = MYSQLND_STMT_PREPARED;
  1719. }
  1720. /* Line is free! */
  1721. CONN_SET_STATE(stmt->conn, CONN_READY);
  1722. DBG_RETURN(PASS);
  1723. }
  1724. /* }}} */
  1725. /* {{{ mysqlnd_stmt_separate_result_bind */
  1726. static void
  1727. mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC)
  1728. {
  1729. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1730. unsigned int i;
  1731. DBG_ENTER("mysqlnd_stmt_separate_result_bind");
  1732. if (!stmt) {
  1733. DBG_VOID_RETURN;
  1734. }
  1735. DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count);
  1736. if (!stmt->result_bind) {
  1737. DBG_VOID_RETURN;
  1738. }
  1739. /*
  1740. Because only the bound variables can point to our internal buffers, then
  1741. separate or free only them. Free is possible because the user could have
  1742. lost reference.
  1743. */
  1744. for (i = 0; i < stmt->field_count; i++) {
  1745. /* Let's try with no cache */
  1746. if (stmt->result_bind[i].bound == TRUE) {
  1747. DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNT_P(stmt->result_bind[i].zv));
  1748. /*
  1749. We have to separate the actual zval value of the bound
  1750. variable from our allocated zvals or we will face double-free
  1751. */
  1752. if (Z_REFCOUNT_P(stmt->result_bind[i].zv) > 1) {
  1753. #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  1754. zval_copy_ctor(stmt->result_bind[i].zv);
  1755. #endif
  1756. zval_ptr_dtor(&stmt->result_bind[i].zv);
  1757. } else {
  1758. /*
  1759. If it is a string, what is pointed will be freed
  1760. later in free_result(). We need to remove the variable to
  1761. which the user has lost reference.
  1762. */
  1763. #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  1764. ZVAL_NULL(stmt->result_bind[i].zv);
  1765. #endif
  1766. zval_ptr_dtor(&stmt->result_bind[i].zv);
  1767. }
  1768. }
  1769. }
  1770. s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC);
  1771. stmt->result_bind = NULL;
  1772. DBG_VOID_RETURN;
  1773. }
  1774. /* }}} */
  1775. /* {{{ mysqlnd_stmt_separate_one_result_bind */
  1776. static void
  1777. mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
  1778. {
  1779. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1780. DBG_ENTER("mysqlnd_stmt_separate_one_result_bind");
  1781. if (!stmt) {
  1782. DBG_VOID_RETURN;
  1783. }
  1784. DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no);
  1785. if (!stmt->result_bind) {
  1786. DBG_VOID_RETURN;
  1787. }
  1788. /*
  1789. Because only the bound variables can point to our internal buffers, then
  1790. separate or free only them. Free is possible because the user could have
  1791. lost reference.
  1792. */
  1793. /* Let's try with no cache */
  1794. if (stmt->result_bind[param_no].bound == TRUE) {
  1795. DBG_INF_FMT("%u has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
  1796. /*
  1797. We have to separate the actual zval value of the bound
  1798. variable from our allocated zvals or we will face double-free
  1799. */
  1800. if (Z_REFCOUNT_P(stmt->result_bind[param_no].zv) > 1) {
  1801. #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  1802. zval_copy_ctor(stmt->result_bind[param_no].zv);
  1803. #endif
  1804. zval_ptr_dtor(&stmt->result_bind[param_no].zv);
  1805. } else {
  1806. /*
  1807. If it is a string, what is pointed will be freed
  1808. later in free_result(). We need to remove the variable to
  1809. which the user has lost reference.
  1810. */
  1811. #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
  1812. ZVAL_NULL(stmt->result_bind[param_no].zv);
  1813. #endif
  1814. zval_ptr_dtor(&stmt->result_bind[param_no].zv);
  1815. }
  1816. }
  1817. DBG_VOID_RETURN;
  1818. }
  1819. /* }}} */
  1820. /* {{{ mysqlnd_stmt::free_stmt_result */
  1821. static void
  1822. MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(MYSQLND_STMT * const s TSRMLS_DC)
  1823. {
  1824. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1825. DBG_ENTER("mysqlnd_stmt::free_stmt_result");
  1826. if (!stmt) {
  1827. DBG_VOID_RETURN;
  1828. }
  1829. /*
  1830. First separate the bound variables, which point to the result set, then
  1831. destroy the set.
  1832. */
  1833. mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
  1834. /* Not every statement has a result set attached */
  1835. if (stmt->result) {
  1836. stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
  1837. stmt->result = NULL;
  1838. }
  1839. if (stmt->error_info->error_list) {
  1840. zend_llist_clean(stmt->error_info->error_list);
  1841. mnd_pefree(stmt->error_info->error_list, s->persistent);
  1842. stmt->error_info->error_list = NULL;
  1843. }
  1844. DBG_VOID_RETURN;
  1845. }
  1846. /* }}} */
  1847. /* {{{ mysqlnd_stmt::free_stmt_content */
  1848. static void
  1849. MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC)
  1850. {
  1851. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1852. DBG_ENTER("mysqlnd_stmt::free_stmt_content");
  1853. if (!stmt) {
  1854. DBG_VOID_RETURN;
  1855. }
  1856. DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u", stmt->stmt_id, stmt->param_bind, stmt->param_count);
  1857. /* Destroy the input bind */
  1858. if (stmt->param_bind) {
  1859. unsigned int i;
  1860. /*
  1861. Because only the bound variables can point to our internal buffers, then
  1862. separate or free only them. Free is possible because the user could have
  1863. lost reference.
  1864. */
  1865. for (i = 0; i < stmt->param_count; i++) {
  1866. /*
  1867. If bind_one_parameter was used, but not everything was
  1868. bound and nothing was fetched, then some `zv` could be NULL
  1869. */
  1870. if (stmt->param_bind[i].zv) {
  1871. zval_ptr_dtor(&stmt->param_bind[i].zv);
  1872. }
  1873. }
  1874. s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
  1875. stmt->param_bind = NULL;
  1876. }
  1877. s->m->free_stmt_result(s TSRMLS_CC);
  1878. DBG_VOID_RETURN;
  1879. }
  1880. /* }}} */
  1881. /* {{{ mysqlnd_stmt::net_close */
  1882. static enum_func_status
  1883. MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
  1884. {
  1885. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1886. MYSQLND_CONN_DATA * conn;
  1887. zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
  1888. enum_mysqlnd_collected_stats statistic = STAT_LAST;
  1889. DBG_ENTER("mysqlnd_stmt::net_close");
  1890. if (!stmt || !stmt->conn) {
  1891. DBG_RETURN(FAIL);
  1892. }
  1893. DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
  1894. conn = stmt->conn;
  1895. SET_EMPTY_ERROR(*stmt->error_info);
  1896. SET_EMPTY_ERROR(*stmt->conn->error_info);
  1897. /*
  1898. If the user decided to close the statement right after execute()
  1899. We have to call the appropriate use_result() or store_result() and
  1900. clean.
  1901. */
  1902. do {
  1903. if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
  1904. DBG_INF("fetching result set header");
  1905. stmt->default_rset_handler(s TSRMLS_CC);
  1906. stmt->state = MYSQLND_STMT_USER_FETCHING;
  1907. }
  1908. /* unbuffered set not fetched to the end ? Clean the line */
  1909. if (stmt->result) {
  1910. DBG_INF("skipping result");
  1911. stmt->result->m.skip_result(stmt->result TSRMLS_CC);
  1912. }
  1913. } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
  1914. /*
  1915. After this point we are allowed to free the result set,
  1916. as we have cleaned the line
  1917. */
  1918. if (stmt->stmt_id) {
  1919. MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_FREE_RESULT_IMPLICIT:
  1920. STAT_FREE_RESULT_EXPLICIT);
  1921. int4store(cmd_buf, stmt->stmt_id);
  1922. if (CONN_GET_STATE(conn) == CONN_READY &&
  1923. FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf),
  1924. PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
  1925. FALSE, TRUE TSRMLS_CC)) {
  1926. COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
  1927. DBG_RETURN(FAIL);
  1928. }
  1929. }
  1930. switch (stmt->execute_count) {
  1931. case 0:
  1932. statistic = STAT_PS_PREPARED_NEVER_EXECUTED;
  1933. break;
  1934. case 1:
  1935. statistic = STAT_PS_PREPARED_ONCE_USED;
  1936. break;
  1937. default:
  1938. break;
  1939. }
  1940. if (statistic != STAT_LAST) {
  1941. MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
  1942. }
  1943. if (stmt->execute_cmd_buffer.buffer) {
  1944. mnd_pefree(stmt->execute_cmd_buffer.buffer, stmt->persistent);
  1945. stmt->execute_cmd_buffer.buffer = NULL;
  1946. }
  1947. s->m->free_stmt_content(s TSRMLS_CC);
  1948. if (stmt->conn) {
  1949. stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
  1950. stmt->conn = NULL;
  1951. }
  1952. DBG_RETURN(PASS);
  1953. }
  1954. /* }}} */
  1955. /* {{{ mysqlnd_stmt::dtor */
  1956. static enum_func_status
  1957. MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
  1958. {
  1959. MYSQLND_STMT_DATA * stmt = (s != NULL) ? s->data:NULL;
  1960. enum_func_status ret = FAIL;
  1961. zend_bool persistent = (s != NULL) ? s->persistent : 0;
  1962. DBG_ENTER("mysqlnd_stmt::dtor");
  1963. if (stmt) {
  1964. DBG_INF_FMT("stmt=%p", stmt);
  1965. MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
  1966. STAT_STMT_CLOSE_EXPLICIT);
  1967. ret = s->m->net_close(s, implicit TSRMLS_CC);
  1968. mnd_pefree(stmt, persistent);
  1969. }
  1970. mnd_pefree(s, persistent);
  1971. DBG_INF(ret == PASS? "PASS":"FAIL");
  1972. DBG_RETURN(ret);
  1973. }
  1974. /* }}} */
  1975. /* {{{ mysqlnd_stmt::alloc_param_bind */
  1976. static MYSQLND_PARAM_BIND *
  1977. MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind)(MYSQLND_STMT * const s TSRMLS_DC)
  1978. {
  1979. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1980. DBG_ENTER("mysqlnd_stmt::alloc_param_bind");
  1981. if (!stmt) {
  1982. DBG_RETURN(NULL);
  1983. }
  1984. DBG_RETURN(mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent));
  1985. }
  1986. /* }}} */
  1987. /* {{{ mysqlnd_stmt::alloc_result_bind */
  1988. static MYSQLND_RESULT_BIND *
  1989. MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind)(MYSQLND_STMT * const s TSRMLS_DC)
  1990. {
  1991. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  1992. DBG_ENTER("mysqlnd_stmt::alloc_result_bind");
  1993. if (!stmt) {
  1994. DBG_RETURN(NULL);
  1995. }
  1996. DBG_RETURN(mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent));
  1997. }
  1998. /* }}} */
  1999. /* {{{ param_bind::free_parameter_bind */
  2000. PHPAPI void
  2001. MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * param_bind TSRMLS_DC)
  2002. {
  2003. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  2004. if (stmt) {
  2005. mnd_pefree(param_bind, stmt->persistent);
  2006. }
  2007. }
  2008. /* }}} */
  2009. /* {{{ mysqlnd_stmt::free_result_bind */
  2010. PHPAPI void
  2011. MYSQLND_METHOD(mysqlnd_stmt, free_result_bind)(MYSQLND_STMT * const s, MYSQLND_RESULT_BIND * result_bind TSRMLS_DC)
  2012. {
  2013. MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
  2014. if (stmt) {
  2015. mnd_pefree(result_bind, stmt->persistent);
  2016. }
  2017. }
  2018. /* }}} */
  2019. MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
  2020. MYSQLND_METHOD(mysqlnd_stmt, prepare),
  2021. MYSQLND_METHOD(mysqlnd_stmt, execute),
  2022. MYSQLND_METHOD(mysqlnd_stmt, use_result),
  2023. MYSQLND_METHOD(mysqlnd_stmt, store_result),
  2024. MYSQLND_METHOD(mysqlnd_stmt, get_result),
  2025. MYSQLND_METHOD(mysqlnd_stmt, more_results),
  2026. MYSQLND_METHOD(mysqlnd_stmt, next_result),
  2027. MYSQLND_METHOD(mysqlnd_stmt, free_result),
  2028. MYSQLND_METHOD(mysqlnd_stmt, data_seek),
  2029. MYSQLND_METHOD(mysqlnd_stmt, reset),
  2030. MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close),
  2031. MYSQLND_METHOD(mysqlnd_stmt, dtor),
  2032. MYSQLND_METHOD(mysqlnd_stmt, fetch),
  2033. MYSQLND_METHOD(mysqlnd_stmt, bind_parameters),
  2034. MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter),
  2035. MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
  2036. MYSQLND_METHOD(mysqlnd_stmt, bind_result),
  2037. MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
  2038. MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
  2039. MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
  2040. MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
  2041. MYSQLND_METHOD(mysqlnd_stmt, insert_id),
  2042. MYSQLND_METHOD(mysqlnd_stmt, affected_rows),
  2043. MYSQLND_METHOD(mysqlnd_stmt, num_rows),
  2044. MYSQLND_METHOD(mysqlnd_stmt, param_count),
  2045. MYSQLND_METHOD(mysqlnd_stmt, field_count),
  2046. MYSQLND_METHOD(mysqlnd_stmt, warning_count),
  2047. MYSQLND_METHOD(mysqlnd_stmt, errno),
  2048. MYSQLND_METHOD(mysqlnd_stmt, error),
  2049. MYSQLND_METHOD(mysqlnd_stmt, sqlstate),
  2050. MYSQLND_METHOD(mysqlnd_stmt, attr_get),
  2051. MYSQLND_METHOD(mysqlnd_stmt, attr_set),
  2052. MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind),
  2053. MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind),
  2054. MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind),
  2055. MYSQLND_METHOD(mysqlnd_stmt, free_result_bind),
  2056. MYSQLND_METHOD(mysqlnd_stmt, server_status),
  2057. mysqlnd_stmt_execute_generate_request,
  2058. mysqlnd_stmt_execute_parse_response,
  2059. MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content),
  2060. MYSQLND_METHOD(mysqlnd_stmt, flush),
  2061. MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)
  2062. MYSQLND_CLASS_METHODS_END;
  2063. /* {{{ _mysqlnd_stmt_init */
  2064. MYSQLND_STMT *
  2065. _mysqlnd_stmt_init(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
  2066. {
  2067. MYSQLND_STMT * ret;
  2068. DBG_ENTER("_mysqlnd_stmt_init");
  2069. ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_prepared_statement(conn TSRMLS_CC);
  2070. DBG_RETURN(ret);
  2071. }
  2072. /* }}} */
  2073. /* {{{ _mysqlnd_init_ps_subsystem */
  2074. void _mysqlnd_init_ps_subsystem()
  2075. {
  2076. mysqlnd_stmt_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt));
  2077. _mysqlnd_init_ps_fetch_subsystem();
  2078. }
  2079. /* }}} */
  2080. /*
  2081. * Local variables:
  2082. * tab-width: 4
  2083. * c-basic-offset: 4
  2084. * End:
  2085. * vim600: noet sw=4 ts=4 fdm=marker
  2086. * vim<600: noet sw=4 ts=4
  2087. */