/Firebird-2.5.1.26351-0/src/dsql/dsql.cpp

# · C++ · 3406 lines · 2202 code · 500 blank · 704 comment · 439 complexity · 2a4aff76d17df2fb617ef6efae2dc1ca MD5 · raw file

  1. /*
  2. * PROGRAM: Dynamic SQL runtime support
  3. * MODULE: dsql.cpp
  4. * DESCRIPTION: Local processing for External entry points.
  5. *
  6. * The contents of this file are subject to the Interbase Public
  7. * License Version 1.0 (the "License"); you may not use this file
  8. * except in compliance with the License. You may obtain a copy
  9. * of the License at http://www.Inprise.com/IPL.html
  10. *
  11. * Software distributed under the License is distributed on an
  12. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
  13. * or implied. See the License for the specific language governing
  14. * rights and limitations under the License.
  15. *
  16. * The Original Code was created by Inprise Corporation
  17. * and its predecessors. Portions created by Inprise Corporation are
  18. * Copyright (C) Inprise Corporation.
  19. *
  20. * All Rights Reserved.
  21. * Contributor(s): ______________________________________.
  22. * 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
  23. * conditionals, as the engine now fully supports
  24. * readonly databases.
  25. * December 2001 Mike Nordell: Major overhaul to (try to) make it C++
  26. * 2001.6.3 Claudio Valderrama: fixed a bad behaved loop in get_plan_info()
  27. * and get_rsb_item() that caused a crash when plan info was requested.
  28. * 2001.6.9 Claudio Valderrama: Added nod_del_view, nod_current_role and nod_breakleave.
  29. * 2002.10.29 Nickolay Samofatov: Added support for savepoints
  30. * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
  31. * 2004.01.16 Vlad Horsun: added support for EXECUTE BLOCK statement
  32. * Adriano dos Santos Fernandes
  33. */
  34. #include "firebird.h"
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include "../dsql/dsql.h"
  39. #include "../dsql/node.h"
  40. #include "../jrd/ibase.h"
  41. #include "../jrd/align.h"
  42. #include "../jrd/intl.h"
  43. #include "../jrd/jrd.h"
  44. #include "../dsql/Parser.h"
  45. #include "../dsql/ddl_proto.h"
  46. #include "../dsql/dsql_proto.h"
  47. #include "../dsql/errd_proto.h"
  48. #include "../dsql/gen_proto.h"
  49. #include "../dsql/hsh_proto.h"
  50. #include "../dsql/make_proto.h"
  51. #include "../dsql/movd_proto.h"
  52. #include "../dsql/parse_proto.h"
  53. #include "../dsql/pass1_proto.h"
  54. #include "../jrd/blb_proto.h"
  55. #include "../jrd/cmp_proto.h"
  56. #include "../jrd/gds_proto.h"
  57. #include "../jrd/inf_proto.h"
  58. #include "../jrd/jrd_proto.h"
  59. #include "../jrd/tra_proto.h"
  60. #include "../jrd/trace/TraceManager.h"
  61. #include "../jrd/trace/TraceDSQLHelpers.h"
  62. #include "../common/classes/init.h"
  63. #include "../common/utils_proto.h"
  64. #ifdef SCROLLABLE_CURSORS
  65. #include "../jrd/scroll_cursors.h"
  66. #endif
  67. #include "../common/StatusArg.h"
  68. #ifdef HAVE_CTYPE_H
  69. #include <ctype.h>
  70. #endif
  71. using namespace Jrd;
  72. using namespace Dsql;
  73. using namespace Firebird;
  74. static void close_cursor(thread_db*, dsql_req*);
  75. static USHORT convert(SLONG, UCHAR*);
  76. static void execute_blob(thread_db*, dsql_req*, USHORT, const UCHAR*, USHORT, const UCHAR*,
  77. USHORT, UCHAR*, USHORT, UCHAR*);
  78. static void execute_immediate(thread_db*, Attachment*, jrd_tra**,
  79. USHORT, const TEXT*, USHORT,
  80. USHORT, const UCHAR*, /*USHORT,*/ USHORT, const UCHAR*,
  81. USHORT, UCHAR*, /*USHORT,*/ USHORT, UCHAR*);
  82. static void execute_request(thread_db*, dsql_req*, jrd_tra**, USHORT, const UCHAR*,
  83. USHORT, const UCHAR*, USHORT, UCHAR*, USHORT, UCHAR*, bool);
  84. static SSHORT filter_sub_type(const dsql_nod*);
  85. static bool get_indices(SLONG*, const UCHAR**, SLONG*, SCHAR**);
  86. static USHORT get_request_info(thread_db*, dsql_req*, SLONG, UCHAR*);
  87. static bool get_rsb_item(SLONG*, const UCHAR**, SLONG*, SCHAR**, USHORT*, USHORT*);
  88. static dsql_dbb* init(Attachment*);
  89. static void map_in_out(dsql_req*, dsql_msg*, USHORT, const UCHAR*, USHORT, UCHAR*, const UCHAR* = 0);
  90. static USHORT parse_blr(USHORT, const UCHAR*, const USHORT, dsql_par*);
  91. static dsql_req* prepare(thread_db*, dsql_dbb*, jrd_tra*, USHORT, const TEXT*, USHORT, USHORT);
  92. static UCHAR* put_item(UCHAR, const USHORT, const UCHAR*, UCHAR*, const UCHAR* const, const bool copy = true);
  93. static void release_request(thread_db*, dsql_req*, bool);
  94. static void sql_info(thread_db*, dsql_req*, USHORT, const UCHAR*, ULONG, UCHAR*);
  95. static UCHAR* var_info(dsql_msg*, const UCHAR*, const UCHAR* const, UCHAR*,
  96. const UCHAR* const, USHORT, bool);
  97. static inline bool reqTypeWithCursor(REQ_TYPE req_type)
  98. {
  99. switch (req_type)
  100. {
  101. case REQ_SELECT:
  102. case REQ_SELECT_BLOCK:
  103. case REQ_SELECT_UPD:
  104. case REQ_EMBED_SELECT:
  105. case REQ_GET_SEGMENT:
  106. case REQ_PUT_SEGMENT:
  107. return true;
  108. }
  109. return false;
  110. }
  111. #ifdef DSQL_DEBUG
  112. unsigned DSQL_debug = 0;
  113. #endif
  114. namespace
  115. {
  116. const UCHAR db_hdr_info_items[] =
  117. {
  118. isc_info_db_sql_dialect,
  119. isc_info_ods_version,
  120. isc_info_ods_minor_version,
  121. #ifdef SCROLLABLE_CURSORS
  122. isc_info_base_level,
  123. #endif
  124. isc_info_db_read_only,
  125. isc_info_end
  126. };
  127. const UCHAR explain_info[] =
  128. {
  129. isc_info_access_path
  130. };
  131. const UCHAR record_info[] =
  132. {
  133. isc_info_req_update_count, isc_info_req_delete_count,
  134. isc_info_req_select_count, isc_info_req_insert_count
  135. };
  136. const UCHAR sql_records_info[] =
  137. {
  138. isc_info_sql_records
  139. };
  140. } // namespace
  141. #ifdef DSQL_DEBUG
  142. IMPLEMENT_TRACE_ROUTINE(dsql_trace, "DSQL")
  143. #endif
  144. dsql_dbb::~dsql_dbb()
  145. {
  146. thread_db* tdbb = JRD_get_thread_data();
  147. while (!dbb_requests.isEmpty())
  148. release_request(tdbb, dbb_requests[0], true);
  149. HSHD_finish(this);
  150. }
  151. /**
  152. DSQL_allocate_statement
  153. @brief Allocate a statement handle.
  154. @param tdbb
  155. @param attachment
  156. **/
  157. dsql_req* DSQL_allocate_statement(thread_db* tdbb, Attachment* attachment)
  158. {
  159. SET_TDBB(tdbb);
  160. dsql_dbb* const database = init(attachment);
  161. Jrd::ContextPoolHolder context(tdbb, database->createPool());
  162. // allocate the request block
  163. MemoryPool& pool = *tdbb->getDefaultPool();
  164. dsql_req* const request = FB_NEW(pool) CompiledStatement(pool);
  165. request->req_dbb = database;
  166. database->dbb_requests.add(request);
  167. return request;
  168. }
  169. /**
  170. DSQL_execute
  171. @brief Execute a non-SELECT dynamic SQL statement.
  172. @param tdbb
  173. @param tra_handle
  174. @param request
  175. @param in_blr_length
  176. @param in_blr
  177. @param in_msg_type
  178. @param in_msg_length
  179. @param in_msg
  180. @param out_blr_length
  181. @param out_blr
  182. @param out_msg_type OBSOLETE
  183. @param out_msg_length
  184. @param out_msg
  185. **/
  186. void DSQL_execute(thread_db* tdbb,
  187. jrd_tra** tra_handle,
  188. dsql_req* request,
  189. USHORT in_blr_length, const UCHAR* in_blr,
  190. USHORT in_msg_type, USHORT in_msg_length, const UCHAR* in_msg,
  191. USHORT out_blr_length, UCHAR* out_blr,
  192. /*USHORT out_msg_type,*/ USHORT out_msg_length, UCHAR* out_msg)
  193. {
  194. SET_TDBB(tdbb);
  195. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  196. if (request->req_flags & REQ_orphan)
  197. {
  198. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  199. Arg::Gds(isc_bad_req_handle));
  200. }
  201. if ((SSHORT) in_msg_type == -1) {
  202. request->req_type = REQ_EMBED_SELECT;
  203. }
  204. // Only allow NULL trans_handle if we're starting a transaction
  205. if (!*tra_handle && request->req_type != REQ_START_TRANS)
  206. {
  207. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  208. Arg::Gds(isc_bad_trans_handle));
  209. }
  210. // If the request is a SELECT or blob statement then this is an open.
  211. // Make sure the cursor is not already open.
  212. if (reqTypeWithCursor(request->req_type)) {
  213. if (request->req_flags & REQ_cursor_open)
  214. {
  215. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
  216. Arg::Gds(isc_dsql_cursor_open_err));
  217. }
  218. }
  219. // A select with a non zero output length is a singleton select
  220. const bool singleton = (request->req_type == REQ_SELECT && out_msg_length != 0);
  221. if (request->req_type != REQ_EMBED_SELECT)
  222. {
  223. execute_request(tdbb, request, tra_handle,
  224. in_blr_length, in_blr, in_msg_length, in_msg,
  225. out_blr_length, out_blr, out_msg_length, out_msg,
  226. singleton);
  227. }
  228. else
  229. {
  230. request->req_transaction = *tra_handle;
  231. }
  232. // If the output message length is zero on a REQ_SELECT then we must
  233. // be doing an OPEN cursor operation.
  234. // If we do have an output message length, then we're doing
  235. // a singleton SELECT. In that event, we don't add the cursor
  236. // to the list of open cursors (it's not really open).
  237. if (reqTypeWithCursor(request->req_type) && !singleton)
  238. {
  239. request->req_flags |= REQ_cursor_open;
  240. TRA_link_cursor(request->req_transaction, request);
  241. }
  242. }
  243. /**
  244. DSQL_execute_immediate
  245. @brief Execute a non-SELECT dynamic SQL statement.
  246. @param tdbb
  247. @param attachment
  248. @param tra_handle
  249. @param length
  250. @param string
  251. @param dialect
  252. @param in_blr_length
  253. @param in_blr
  254. @param in_msg_type OBSOLETE
  255. @param in_msg_length
  256. @param in_msg
  257. @param out_blr_length
  258. @param out_blr
  259. @param out_msg_type OBSOLETE
  260. @param out_msg_length
  261. @param out_msg
  262. **/
  263. void DSQL_execute_immediate(thread_db* tdbb,
  264. Attachment* attachment,
  265. jrd_tra** tra_handle,
  266. USHORT length, const TEXT* string, USHORT dialect,
  267. USHORT in_blr_length, const UCHAR* in_blr,
  268. /*USHORT in_msg_type,*/ USHORT in_msg_length, const UCHAR* in_msg,
  269. USHORT out_blr_length, UCHAR* out_blr,
  270. /*USHORT out_msg_type,*/ USHORT out_msg_length, UCHAR* out_msg)
  271. {
  272. execute_immediate(tdbb, attachment, tra_handle, length,
  273. string, dialect,
  274. in_blr_length, in_blr, /*in_msg_type,*/ in_msg_length, in_msg,
  275. out_blr_length, out_blr, /*out_msg_type,*/ out_msg_length, out_msg);
  276. }
  277. /**
  278. DSQL_fetch
  279. @brief Fetch next record from a dynamic SQL cursor
  280. @param user_status
  281. @param req_handle
  282. @param blr_length
  283. @param blr
  284. @param msg_type OBSOLETE
  285. @param msg_length
  286. @param dsql_msg
  287. @param direction
  288. @param offset
  289. **/
  290. ISC_STATUS DSQL_fetch(thread_db* tdbb,
  291. dsql_req* request,
  292. USHORT blr_length, const UCHAR* blr,
  293. /*USHORT msg_type,*/ USHORT msg_length, UCHAR* dsql_msg_buf
  294. #ifdef SCROLLABLE_CURSORS
  295. , USHORT direction, SLONG offset
  296. #endif
  297. )
  298. {
  299. SET_TDBB(tdbb);
  300. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  301. // if the cursor isn't open, we've got a problem
  302. if (reqTypeWithCursor(request->req_type))
  303. {
  304. if (!(request->req_flags & REQ_cursor_open))
  305. {
  306. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) <<
  307. Arg::Gds(isc_dsql_cursor_err) <<
  308. Arg::Gds(isc_dsql_cursor_not_open));
  309. }
  310. }
  311. #ifdef SCROLLABLE_CURSORS
  312. // check whether we need to send an asynchronous scrolling message
  313. // to the engine; the engine will automatically advance one record
  314. // in the same direction as before, so optimize out messages of that
  315. // type
  316. if (request->req_type == REQ_SELECT && request->req_dbb->dbb_base_level >= 5)
  317. {
  318. switch (direction)
  319. {
  320. case isc_fetch_next:
  321. if (!(request->req_flags & REQ_backwards))
  322. offset = 0;
  323. else {
  324. direction = blr_forward;
  325. offset = 1;
  326. request->req_flags &= ~REQ_backwards;
  327. }
  328. break;
  329. case isc_fetch_prior:
  330. if (request->req_flags & REQ_backwards)
  331. offset = 0;
  332. else {
  333. direction = blr_backward;
  334. offset = 1;
  335. request->req_flags |= REQ_backwards;
  336. }
  337. break;
  338. case isc_fetch_first:
  339. direction = blr_bof_forward;
  340. offset = 1;
  341. request->req_flags &= ~REQ_backwards;
  342. break;
  343. case isc_fetch_last:
  344. direction = blr_eof_backward;
  345. offset = 1;
  346. request->req_flags |= REQ_backwards;
  347. break;
  348. case isc_fetch_absolute:
  349. direction = blr_bof_forward;
  350. request->req_flags &= ~REQ_backwards;
  351. break;
  352. case isc_fetch_relative:
  353. if (offset < 0) {
  354. direction = blr_backward;
  355. offset = -offset;
  356. request->req_flags |= REQ_backwards;
  357. }
  358. else {
  359. direction = blr_forward;
  360. request->req_flags &= ~REQ_backwards;
  361. }
  362. break;
  363. default:
  364. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  365. Arg::Gds(isc_dsql_sqlda_err));
  366. }
  367. if (offset)
  368. {
  369. DSC desc;
  370. dsql_msg* message = (dsql_msg*) request->req_async;
  371. desc.dsc_dtype = dtype_short;
  372. desc.dsc_scale = 0;
  373. desc.dsc_length = sizeof(USHORT);
  374. desc.dsc_flags = 0;
  375. desc.dsc_address = (UCHAR*) & direction;
  376. dsql_par* offset_parameter = message->msg_parameters;
  377. dsql_par* parameter = offset_parameter->par_next;
  378. MOVD_move(tdbb, &desc, &parameter->par_desc);
  379. desc.dsc_dtype = dtype_long;
  380. desc.dsc_scale = 0;
  381. desc.dsc_length = sizeof(SLONG);
  382. desc.dsc_flags = 0;
  383. desc.dsc_address = (UCHAR*) & offset;
  384. MOVD_move(tdbb, &desc, &offset_parameter->par_desc);
  385. DsqlCheckout dcoHolder(request->req_dbb);
  386. if (isc_receive2(tdbb->tdbb_status_vector, &request->req_request,
  387. message->msg_number, message->msg_length,
  388. message->msg_buffer, 0, direction, offset))
  389. {
  390. Firebird::status_exception::raise(tdbb->tdbb_status_vector);
  391. }
  392. }
  393. }
  394. #endif
  395. dsql_msg* message = (dsql_msg*) request->req_receive;
  396. // Set up things for tracing this call
  397. Attachment* att = request->req_dbb->dbb_attachment;
  398. TraceDSQLFetch trace(att, request);
  399. // Insure that the blr for the message is parsed, regardless of
  400. // whether anything is found by the call to receive.
  401. if (blr_length) {
  402. parse_blr(blr_length, blr, msg_length, message->msg_parameters);
  403. }
  404. if (request->req_type == REQ_GET_SEGMENT)
  405. {
  406. // For get segment, use the user buffer and indicator directly.
  407. dsql_par* parameter = request->req_blob->blb_segment;
  408. dsql_par* null = parameter->par_null;
  409. USHORT* ret_length = (USHORT *) (dsql_msg_buf + (IPTR) null->par_user_desc.dsc_address);
  410. UCHAR* buffer = dsql_msg_buf + (IPTR) parameter->par_user_desc.dsc_address;
  411. *ret_length = BLB_get_segment(tdbb, request->req_blob->blb_blob,
  412. buffer, parameter->par_user_desc.dsc_length);
  413. if (request->req_blob->blb_blob->blb_flags & BLB_eof)
  414. return 100;
  415. if (request->req_blob->blb_blob->blb_fragment_size)
  416. return 101;
  417. return 0;
  418. }
  419. JRD_receive(tdbb, request->req_request, message->msg_number, message->msg_length,
  420. message->msg_buffer, 0);
  421. const dsql_par* const eof = request->req_eof;
  422. const bool eof_reached = eof && !*((USHORT*) eof->par_desc.dsc_address);
  423. if (eof_reached)
  424. {
  425. trace.fetch(true, res_successful);
  426. return 100;
  427. }
  428. map_in_out(NULL, message, 0, blr, msg_length, dsql_msg_buf);
  429. trace.fetch(false, res_successful);
  430. return FB_SUCCESS;
  431. }
  432. /**
  433. DSQL_free_statement
  434. @brief Release request for a dsql statement
  435. @param user_status
  436. @param req_handle
  437. @param option
  438. **/
  439. void DSQL_free_statement(thread_db* tdbb, dsql_req* request, USHORT option)
  440. {
  441. SET_TDBB(tdbb);
  442. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  443. if (option & DSQL_drop) {
  444. // Release everything associated with the request
  445. release_request(tdbb, request, true);
  446. }
  447. else if (option & DSQL_unprepare) {
  448. // Release everything but the request itself
  449. release_request(tdbb, request, false);
  450. }
  451. else if (option & DSQL_close) {
  452. // Just close the cursor associated with the request
  453. if (reqTypeWithCursor(request->req_type))
  454. {
  455. if (!(request->req_flags & REQ_cursor_open))
  456. {
  457. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-501) <<
  458. Arg::Gds(isc_dsql_cursor_close_err));
  459. }
  460. close_cursor(tdbb, request);
  461. }
  462. }
  463. }
  464. /**
  465. DSQL_insert
  466. @brief Insert next record into a dynamic SQL cursor
  467. @param user_status
  468. @param req_handle
  469. @param blr_length
  470. @param blr
  471. @param msg_type OBSOLETE
  472. @param msg_length
  473. @param dsql_msg
  474. **/
  475. void DSQL_insert(thread_db* tdbb,
  476. dsql_req* request,
  477. USHORT blr_length, const UCHAR* blr,
  478. /*USHORT msg_type,*/ USHORT msg_length, const UCHAR* dsql_msg_buf)
  479. {
  480. SET_TDBB(tdbb);
  481. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  482. if (request->req_flags & REQ_orphan)
  483. {
  484. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  485. Arg::Gds(isc_bad_req_handle));
  486. }
  487. // if the cursor isn't open, we've got a problem
  488. if (request->req_type == REQ_PUT_SEGMENT)
  489. {
  490. if (!(request->req_flags & REQ_cursor_open))
  491. {
  492. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) <<
  493. Arg::Gds(isc_dsql_cursor_err) <<
  494. Arg::Gds(isc_dsql_cursor_not_open));
  495. }
  496. }
  497. dsql_msg* message = (dsql_msg*) request->req_receive;
  498. // Insure that the blr for the message is parsed, regardless of
  499. // whether anything is found by the call to receive.
  500. if (blr_length)
  501. parse_blr(blr_length, blr, msg_length, message->msg_parameters);
  502. if (request->req_type == REQ_PUT_SEGMENT) {
  503. // For put segment, use the user buffer and indicator directly.
  504. dsql_par* parameter = request->req_blob->blb_segment;
  505. const UCHAR* buffer = dsql_msg_buf + (IPTR) parameter->par_user_desc.dsc_address;
  506. BLB_put_segment(tdbb, request->req_blob->blb_blob, buffer,
  507. parameter->par_user_desc.dsc_length);
  508. }
  509. }
  510. /**
  511. DSQL_prepare
  512. @brief Prepare a statement for execution.
  513. @param user_status
  514. @param trans_handle
  515. @param req_handle
  516. @param length
  517. @param string
  518. @param dialect
  519. @param item_length
  520. @param items
  521. @param buffer_length
  522. @param buffer
  523. **/
  524. void DSQL_prepare(thread_db* tdbb,
  525. jrd_tra* transaction,
  526. dsql_req** req_handle,
  527. USHORT length, const TEXT* string, USHORT dialect,
  528. USHORT item_length, const UCHAR* items,
  529. USHORT buffer_length, UCHAR* buffer)
  530. {
  531. SET_TDBB(tdbb);
  532. dsql_req* const old_request = *req_handle;
  533. if (!old_request) {
  534. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  535. Arg::Gds(isc_bad_req_handle));
  536. }
  537. dsql_dbb* database = old_request->req_dbb;
  538. if (!database) {
  539. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  540. Arg::Gds(isc_bad_req_handle));
  541. }
  542. // check to see if old request has an open cursor
  543. if (old_request && (old_request->req_flags & REQ_cursor_open)) {
  544. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-519) <<
  545. Arg::Gds(isc_dsql_open_cursor_request));
  546. }
  547. dsql_req* request = NULL;
  548. try {
  549. // Figure out which parser version to use
  550. // Since the API to dsql8_prepare is public and can not be changed, there needs to
  551. // be a way to send the parser version to DSQL so that the parser can compare the keyword
  552. // version to the parser version. To accomplish this, the parser version is combined with
  553. // the client dialect and sent across that way. In dsql8_prepare_statement, the parser version
  554. // and client dialect are separated and passed on to their final destinations. The information
  555. // is combined as follows:
  556. // Dialect * 10 + parser_version
  557. //
  558. // and is extracted in dsql8_prepare_statement as follows:
  559. // parser_version = ((dialect *10)+parser_version)%10
  560. // client_dialect = ((dialect *10)+parser_version)/10
  561. //
  562. // For example, parser_version = 1 and client dialect = 1
  563. //
  564. // combined = (1 * 10) + 1 == 11
  565. //
  566. // parser = (combined) %10 == 1
  567. // dialect = (combined) / 19 == 1
  568. //
  569. // If the parser version is not part of the dialect, then assume that the
  570. // connection being made is a local classic connection.
  571. USHORT parser_version;
  572. if ((dialect / 10) == 0)
  573. parser_version = 2;
  574. else {
  575. parser_version = dialect % 10;
  576. dialect /= 10;
  577. }
  578. // Allocate a new request block and then prepare the request. We want to
  579. // keep the old request around, as is, until we know that we are able
  580. // to prepare the new one.
  581. // It would be really *nice* to know *why* we want to
  582. // keep the old request around -- 1994-October-27 David Schnepper
  583. // Because that's the client's allocated statement handle and we
  584. // don't want to trash the context in it -- 2001-Oct-27 Ann Harrison
  585. request = prepare(tdbb, database, transaction, length, string, dialect, parser_version);
  586. // Can not prepare a CREATE DATABASE/SCHEMA statement
  587. if (request->req_type == REQ_CREATE_DB)
  588. {
  589. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-530) <<
  590. Arg::Gds(isc_dsql_crdb_prepare_err));
  591. }
  592. request->req_flags |= REQ_prepared;
  593. // Now that we know that the new request exists, zap the old one.
  594. {
  595. Jrd::ContextPoolHolder context(tdbb, &old_request->req_pool);
  596. release_request(tdbb, old_request, true);
  597. }
  598. *req_handle = request;
  599. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  600. sql_info(tdbb, request, item_length, items, buffer_length, buffer);
  601. }
  602. catch (const Firebird::Exception&)
  603. {
  604. if (request)
  605. {
  606. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  607. release_request(tdbb, request, true);
  608. }
  609. throw;
  610. }
  611. }
  612. /**
  613. DSQL_set_cursor_name
  614. @brief Set a cursor name for a dynamic request
  615. @param user_status
  616. @param req_handle
  617. @param input_cursor
  618. @param type OBSOLETE
  619. **/
  620. void DSQL_set_cursor(thread_db* tdbb,
  621. dsql_req* request,
  622. const TEXT* input_cursor)
  623. //USHORT type)
  624. {
  625. SET_TDBB(tdbb);
  626. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  627. const size_t MAX_CURSOR_LENGTH = 132 - 1;
  628. Firebird::string cursor = input_cursor;
  629. if (cursor[0] == '\"')
  630. {
  631. // Quoted cursor names eh? Strip'em.
  632. // Note that "" will be replaced with ".
  633. // The code is very strange, because it doesn't check for "" really
  634. // and thus deletes one isolated " in the middle of the cursor.
  635. for (Firebird::string::iterator i = cursor.begin(); i < cursor.end(); ++i)
  636. {
  637. if (*i == '\"') {
  638. cursor.erase(i);
  639. }
  640. }
  641. }
  642. else // not quoted name
  643. {
  644. const Firebird::string::size_type i = cursor.find(' ');
  645. if (i != Firebird::string::npos)
  646. {
  647. cursor.resize(i);
  648. }
  649. cursor.upper();
  650. }
  651. USHORT length = (USHORT) fb_utils::name_length(cursor.c_str());
  652. if (length == 0) {
  653. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
  654. Arg::Gds(isc_dsql_decl_err) <<
  655. Arg::Gds(isc_dsql_cursor_invalid));
  656. }
  657. if (length > MAX_CURSOR_LENGTH) {
  658. length = MAX_CURSOR_LENGTH;
  659. }
  660. cursor.resize(length);
  661. // If there already is a different cursor by the same name, bitch
  662. const dsql_sym* symbol = HSHD_lookup(request->req_dbb, cursor.c_str(), length, SYM_cursor, 0);
  663. if (symbol)
  664. {
  665. if (request->req_cursor == symbol)
  666. return;
  667. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
  668. Arg::Gds(isc_dsql_decl_err) <<
  669. Arg::Gds(isc_dsql_cursor_redefined) << Arg::Str(symbol->sym_string));
  670. }
  671. // If there already is a cursor and its name isn't the same, ditto.
  672. // We already know there is no cursor by this name in the hash table
  673. if (!request->req_cursor) {
  674. request->req_cursor = MAKE_symbol(request->req_dbb, cursor.c_str(), length, SYM_cursor, request);
  675. }
  676. else {
  677. fb_assert(request->req_cursor != symbol);
  678. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
  679. Arg::Gds(isc_dsql_decl_err) <<
  680. Arg::Gds(isc_dsql_cursor_redefined) << Arg::Str(request->req_cursor->sym_string));
  681. }
  682. }
  683. /**
  684. DSQL_sql_info
  685. @brief Provide information on dsql statement
  686. @param user_status
  687. @param req_handle
  688. @param item_length
  689. @param items
  690. @param info_length
  691. @param info
  692. **/
  693. void DSQL_sql_info(thread_db* tdbb,
  694. dsql_req* request,
  695. USHORT item_length, const UCHAR* items,
  696. ULONG info_length, UCHAR* info)
  697. {
  698. SET_TDBB(tdbb);
  699. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  700. sql_info(tdbb, request, item_length, items, info_length, info);
  701. }
  702. /**
  703. close_cursor
  704. @brief Close an open cursor.
  705. @param request
  706. @param tdbb
  707. **/
  708. static void close_cursor(thread_db* tdbb, dsql_req* request)
  709. {
  710. SET_TDBB(tdbb);
  711. Attachment* attachment = request->req_dbb->dbb_attachment;
  712. if (request->req_request)
  713. {
  714. ThreadStatusGuard status_vector(tdbb);
  715. try
  716. {
  717. if (request->req_type == REQ_GET_SEGMENT || request->req_type == REQ_PUT_SEGMENT)
  718. {
  719. BLB_close(tdbb, request->req_blob->blb_blob);
  720. request->req_blob->blb_blob = NULL;
  721. }
  722. else
  723. {
  724. // Report some remaining fetches if any
  725. if (request->req_fetch_baseline)
  726. {
  727. TraceDSQLFetch trace(attachment, request);
  728. trace.fetch(true, res_successful);
  729. }
  730. if (request->req_traced && TraceManager::need_dsql_free(attachment))
  731. {
  732. TraceSQLStatementImpl stmt(request, NULL);
  733. TraceManager::event_dsql_free(attachment, &stmt, DSQL_close);
  734. }
  735. JRD_unwind_request(tdbb, request->req_request, 0);
  736. }
  737. }
  738. catch (Firebird::Exception&)
  739. {
  740. }
  741. }
  742. request->req_flags &= ~REQ_cursor_open;
  743. TRA_unlink_cursor(request->req_transaction, request);
  744. }
  745. /**
  746. convert
  747. @brief Convert a number to VAX form -- least significant bytes first.
  748. Return the length.
  749. @param number
  750. @param buffer
  751. **/
  752. // CVC: This routine should disappear in favor of a centralized function.
  753. static USHORT convert( SLONG number, UCHAR* buffer)
  754. {
  755. const UCHAR* p;
  756. #ifndef WORDS_BIGENDIAN
  757. p = (UCHAR*) &number;
  758. *buffer++ = *p++;
  759. *buffer++ = *p++;
  760. *buffer++ = *p++;
  761. *buffer++ = *p++;
  762. #else
  763. p = (UCHAR*) (&number + 1);
  764. *buffer++ = *--p;
  765. *buffer++ = *--p;
  766. *buffer++ = *--p;
  767. *buffer++ = *--p;
  768. #endif
  769. return 4;
  770. }
  771. /**
  772. execute_blob
  773. @brief Open or create a blob.
  774. @param tdbb
  775. @param request
  776. @param in_blr_length
  777. @param in_blr
  778. @param in_msg_length
  779. @param in_msg
  780. @param out_blr_length
  781. @param out_blr
  782. @param out_msg_length
  783. @param out_msg
  784. **/
  785. static void execute_blob(thread_db* tdbb,
  786. dsql_req* request,
  787. USHORT in_blr_length,
  788. const UCHAR* in_blr,
  789. USHORT in_msg_length,
  790. const UCHAR* in_msg,
  791. USHORT out_blr_length,
  792. UCHAR* out_blr,
  793. USHORT out_msg_length,
  794. UCHAR* out_msg)
  795. {
  796. UCHAR bpb[24];
  797. dsql_blb* blob = request->req_blob;
  798. map_in_out(request, blob->blb_open_in_msg, in_blr_length, in_blr, in_msg_length, NULL, in_msg);
  799. UCHAR* p = bpb;
  800. *p++ = isc_bpb_version1;
  801. SSHORT filter = filter_sub_type(blob->blb_to);
  802. if (filter) {
  803. *p++ = isc_bpb_target_type;
  804. *p++ = 2;
  805. *p++ = static_cast<UCHAR>(filter);
  806. *p++ = filter >> 8;
  807. }
  808. filter = filter_sub_type(blob->blb_from);
  809. if (filter) {
  810. *p++ = isc_bpb_source_type;
  811. *p++ = 2;
  812. *p++ = static_cast<UCHAR>(filter);
  813. *p++ = filter >> 8;
  814. }
  815. USHORT bpb_length = p - bpb;
  816. if (bpb_length == 1) {
  817. bpb_length = 0;
  818. }
  819. dsql_par* parameter = blob->blb_blob_id;
  820. const dsql_par* null = parameter->par_null;
  821. if (request->req_type == REQ_GET_SEGMENT)
  822. {
  823. bid* blob_id = (bid*) parameter->par_desc.dsc_address;
  824. if (null && *((SSHORT *) null->par_desc.dsc_address) < 0) {
  825. memset(blob_id, 0, sizeof(bid));
  826. }
  827. request->req_blob->blb_blob =
  828. BLB_open2(tdbb, request->req_transaction, blob_id, bpb_length, bpb, true);
  829. }
  830. else
  831. {
  832. request->req_request = NULL;
  833. bid* blob_id = (bid*) parameter->par_desc.dsc_address;
  834. memset(blob_id, 0, sizeof(bid));
  835. request->req_blob->blb_blob =
  836. BLB_create2(tdbb, request->req_transaction, blob_id, bpb_length, bpb);
  837. map_in_out(NULL, blob->blb_open_out_msg, out_blr_length, out_blr, out_msg_length, out_msg);
  838. }
  839. }
  840. /**
  841. execute_immediate
  842. @brief Common part of prepare and execute a statement.
  843. @param tdbb
  844. @param attachment
  845. @param tra_handle
  846. @param length
  847. @param string
  848. @param dialect
  849. @param in_blr_length
  850. @param in_blr
  851. @param in_msg_type OBSOLETE
  852. @param in_msg_length
  853. @param in_msg
  854. @param out_blr_length
  855. @param out_blr
  856. @param out_msg_type OBSOLETE
  857. @param out_msg_length
  858. @param out_msg
  859. **/
  860. static void execute_immediate(thread_db* tdbb,
  861. Attachment* attachment,
  862. jrd_tra** tra_handle,
  863. USHORT length, const TEXT* string, USHORT dialect,
  864. USHORT in_blr_length, const UCHAR* in_blr,
  865. /*USHORT in_msg_type,*/ USHORT in_msg_length, const UCHAR* in_msg,
  866. USHORT out_blr_length, UCHAR* out_blr,
  867. /*USHORT out_msg_type,*/ USHORT out_msg_length, UCHAR* out_msg)
  868. {
  869. SET_TDBB(tdbb);
  870. dsql_dbb* const database = init(attachment);
  871. dsql_req* request = NULL;
  872. try {
  873. // Figure out which parser version to use
  874. // Since the API to dsql8_execute_immediate is public and can not be changed, there needs to
  875. // be a way to send the parser version to DSQL so that the parser can compare the keyword
  876. // version to the parser version. To accomplish this, the parser version is combined with
  877. // the client dialect and sent across that way. In dsql8_execute_immediate, the parser version
  878. // and client dialect are separated and passed on to their final destinations. The information
  879. // is combined as follows:
  880. // Dialect * 10 + parser_version
  881. //
  882. // and is extracted in dsql8_execute_immediate as follows:
  883. // parser_version = ((dialect *10)+parser_version)%10
  884. // client_dialect = ((dialect *10)+parser_version)/10
  885. //
  886. // For example, parser_version = 1 and client dialect = 1
  887. //
  888. // combined = (1 * 10) + 1 == 11
  889. //
  890. // parser = (combined) %10 == 1
  891. // dialect = (combined) / 19 == 1
  892. //
  893. // If the parser version is not part of the dialect, then assume that the
  894. // connection being made is a local classic connection.
  895. USHORT parser_version;
  896. if ((dialect / 10) == 0)
  897. parser_version = 2;
  898. else {
  899. parser_version = dialect % 10;
  900. dialect /= 10;
  901. }
  902. request = prepare(tdbb, database, *tra_handle, length, string, dialect, parser_version);
  903. // Only allow NULL trans_handle if we're starting a transaction
  904. if (!*tra_handle && request->req_type != REQ_START_TRANS)
  905. {
  906. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  907. Arg::Gds(isc_bad_trans_handle));
  908. }
  909. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  910. // A select with a non zero output length is a singleton select
  911. const bool singleton = (request->req_type == REQ_SELECT && out_msg_length != 0);
  912. execute_request(tdbb, request, tra_handle,
  913. in_blr_length, in_blr, in_msg_length, in_msg,
  914. out_blr_length, out_blr, out_msg_length, out_msg,
  915. singleton);
  916. release_request(tdbb, request, true);
  917. }
  918. catch (const Firebird::Exception&)
  919. {
  920. if (request)
  921. {
  922. Jrd::ContextPoolHolder context(tdbb, &request->req_pool);
  923. release_request(tdbb, request, true);
  924. }
  925. throw;
  926. }
  927. }
  928. /**
  929. execute_request
  930. @brief Execute a dynamic SQL statement.
  931. @param tdbb
  932. @param request
  933. @param trans_handle
  934. @param in_blr_length
  935. @param in_blr
  936. @param in_msg_length
  937. @param in_msg
  938. @param out_blr_length
  939. @param out_blr
  940. @param out_msg_length
  941. @param out_msg
  942. @param singleton
  943. **/
  944. static void execute_request(thread_db* tdbb,
  945. dsql_req* request,
  946. jrd_tra** tra_handle,
  947. USHORT in_blr_length, const UCHAR* in_blr,
  948. USHORT in_msg_length, const UCHAR* in_msg,
  949. USHORT out_blr_length, UCHAR* out_blr,
  950. USHORT out_msg_length, UCHAR* out_msg,
  951. bool singleton)
  952. {
  953. request->req_transaction = *tra_handle;
  954. switch (request->req_type)
  955. {
  956. case REQ_START_TRANS:
  957. JRD_start_transaction(tdbb, &request->req_transaction, 1, &request->req_dbb->dbb_attachment,
  958. request->req_blr_data.getCount(), request->req_blr_data.begin());
  959. *tra_handle = request->req_transaction;
  960. return;
  961. case REQ_COMMIT:
  962. JRD_commit_transaction(tdbb, &request->req_transaction);
  963. *tra_handle = NULL;
  964. return;
  965. case REQ_COMMIT_RETAIN:
  966. JRD_commit_retaining(tdbb, &request->req_transaction);
  967. return;
  968. case REQ_ROLLBACK:
  969. JRD_rollback_transaction(tdbb, &request->req_transaction);
  970. *tra_handle = NULL;
  971. return;
  972. case REQ_ROLLBACK_RETAIN:
  973. JRD_rollback_retaining(tdbb, &request->req_transaction);
  974. return;
  975. case REQ_CREATE_DB:
  976. case REQ_DDL:
  977. {
  978. TraceDSQLExecute trace(request->req_dbb->dbb_attachment, request);
  979. DDL_execute(request);
  980. trace.finish(false, res_successful);
  981. return;
  982. }
  983. case REQ_GET_SEGMENT:
  984. execute_blob(tdbb, request,
  985. in_blr_length, in_blr, in_msg_length, in_msg,
  986. out_blr_length, out_blr, out_msg_length, out_msg);
  987. return;
  988. case REQ_PUT_SEGMENT:
  989. execute_blob(tdbb, request,
  990. in_blr_length, in_blr, in_msg_length, in_msg,
  991. out_blr_length, out_blr, out_msg_length, out_msg);
  992. return;
  993. case REQ_SELECT:
  994. case REQ_SELECT_UPD:
  995. case REQ_EMBED_SELECT:
  996. case REQ_INSERT:
  997. case REQ_UPDATE:
  998. case REQ_UPDATE_CURSOR:
  999. case REQ_DELETE:
  1000. case REQ_DELETE_CURSOR:
  1001. case REQ_EXEC_PROCEDURE:
  1002. case REQ_SET_GENERATOR:
  1003. case REQ_SAVEPOINT:
  1004. case REQ_EXEC_BLOCK:
  1005. case REQ_SELECT_BLOCK:
  1006. break;
  1007. default:
  1008. // Catch invalid request types
  1009. fb_assert(false);
  1010. }
  1011. // If there is no data required, just start the request
  1012. dsql_msg* message = request->req_send;
  1013. if (message)
  1014. map_in_out(request, message, in_blr_length, in_blr, in_msg_length, NULL, in_msg);
  1015. // we need to map_in_out before tracing of execution start to let trace
  1016. // manager know statement parameters values
  1017. TraceDSQLExecute trace(request->req_dbb->dbb_attachment, request);
  1018. if (!message)
  1019. JRD_start(tdbb, request->req_request, request->req_transaction, 0);
  1020. else
  1021. {
  1022. JRD_start_and_send(tdbb, request->req_request, request->req_transaction, message->msg_number,
  1023. message->msg_length, message->msg_buffer,
  1024. 0);
  1025. }
  1026. // Selectable execute block should get the "proc fetch" flag assigned,
  1027. // which ensures that the savepoint stack is preserved while suspending
  1028. if (request->req_type == REQ_SELECT_BLOCK)
  1029. {
  1030. fb_assert(request->req_request);
  1031. request->req_request->req_flags |= req_proc_fetch;
  1032. }
  1033. // REQ_EXEC_BLOCK has no outputs so there are no out_msg
  1034. // supplied from client side, but REQ_EXEC_BLOCK requires
  1035. // 2-byte message for EOS synchronization
  1036. const bool isBlock = (request->req_type == REQ_EXEC_BLOCK);
  1037. message = request->req_receive;
  1038. if ((out_msg_length && message) || isBlock)
  1039. {
  1040. char temp_buffer[FB_DOUBLE_ALIGN * 2];
  1041. dsql_msg temp_msg;
  1042. // Insure that the blr for the message is parsed, regardless of
  1043. // whether anything is found by the call to receive.
  1044. if (out_msg_length && out_blr_length) {
  1045. parse_blr(out_blr_length, out_blr, out_msg_length, message->msg_parameters);
  1046. }
  1047. else if (!out_msg_length && isBlock) {
  1048. message = &temp_msg;
  1049. message->msg_number = 1;
  1050. message->msg_length = 2;
  1051. message->msg_buffer = (UCHAR*) FB_ALIGN((U_IPTR) temp_buffer, FB_DOUBLE_ALIGN);
  1052. }
  1053. JRD_receive(tdbb, request->req_request, message->msg_number, message->msg_length,
  1054. message->msg_buffer, 0);
  1055. if (out_msg_length)
  1056. map_in_out(NULL, message, 0, out_blr, out_msg_length, out_msg);
  1057. // if this is a singleton select, make sure there's in fact one record
  1058. if (singleton)
  1059. {
  1060. USHORT counter;
  1061. // Create a temp message buffer and try two more receives.
  1062. // If both succeed then the first is the next record and the
  1063. // second is either another record or the end of record message.
  1064. // In either case, there's more than one record.
  1065. UCHAR* message_buffer = (UCHAR*) gds__alloc((ULONG) message->msg_length);
  1066. ISC_STATUS status = FB_SUCCESS;
  1067. ISC_STATUS_ARRAY localStatus;
  1068. for (counter = 0; counter < 2 && !status; counter++)
  1069. {
  1070. AutoSetRestore<ISC_STATUS*> autoStatus(&tdbb->tdbb_status_vector, localStatus);
  1071. fb_utils::init_status(localStatus);
  1072. try
  1073. {
  1074. JRD_receive(tdbb, request->req_request, message->msg_number,
  1075. message->msg_length, message_buffer, 0);
  1076. status = FB_SUCCESS;
  1077. }
  1078. catch (Firebird::Exception&)
  1079. {
  1080. status = tdbb->tdbb_status_vector[1];
  1081. }
  1082. }
  1083. gds__free(message_buffer);
  1084. // two successful receives means more than one record
  1085. // a req_sync error on the first pass above means no records
  1086. // a non-req_sync error on any of the passes above is an error
  1087. if (!status)
  1088. status_exception::raise(Arg::Gds(isc_sing_select_err));
  1089. else if (status == isc_req_sync && counter == 1)
  1090. status_exception::raise(Arg::Gds(isc_stream_eof));
  1091. else if (status != isc_req_sync)
  1092. status_exception::raise(localStatus);
  1093. }
  1094. }
  1095. UCHAR buffer[20]; // Not used after retrieved
  1096. if (request->req_type == REQ_UPDATE_CURSOR)
  1097. {
  1098. sql_info(tdbb, request, sizeof(sql_records_info), sql_records_info, sizeof(buffer), buffer);
  1099. if (!request->req_updates)
  1100. {
  1101. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-913) <<
  1102. Arg::Gds(isc_deadlock) <<
  1103. Arg::Gds(isc_update_conflict));
  1104. }
  1105. }
  1106. else if (request->req_type == REQ_DELETE_CURSOR)
  1107. {
  1108. sql_info(tdbb, request, sizeof(sql_records_info), sql_records_info, sizeof(buffer), buffer);
  1109. if (!request->req_deletes)
  1110. {
  1111. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-913) <<
  1112. Arg::Gds(isc_deadlock) <<
  1113. Arg::Gds(isc_update_conflict));
  1114. }
  1115. }
  1116. const bool have_cursor = reqTypeWithCursor(request->req_type) && !singleton;
  1117. trace.finish(have_cursor, res_successful);
  1118. }
  1119. /**
  1120. filter_sub_type
  1121. @brief Determine the sub_type to use in filtering
  1122. a blob.
  1123. @param node
  1124. **/
  1125. static SSHORT filter_sub_type(const dsql_nod* node)
  1126. {
  1127. if (node->nod_type == nod_constant)
  1128. return (SSHORT) node->getSlong();
  1129. const dsql_par* parameter = (dsql_par*) node->nod_arg[e_par_parameter];
  1130. const dsql_par* null = parameter->par_null;
  1131. if (null)
  1132. {
  1133. if (*((SSHORT *) null->par_desc.dsc_address))
  1134. return 0;
  1135. }
  1136. return *((SSHORT *) parameter->par_desc.dsc_address);
  1137. }
  1138. /**
  1139. get_indices
  1140. @brief Retrieve the indices from the index tree in
  1141. the request info buffer (explain_ptr), and print them out
  1142. in the plan buffer. Return true on success and false on failure.
  1143. @param explain_length_ptr
  1144. @param explain_ptr
  1145. @param plan_length_ptr
  1146. @param plan_ptr
  1147. **/
  1148. static bool get_indices(SLONG* explain_length_ptr, const UCHAR** explain_ptr,
  1149. SLONG* plan_length_ptr, SCHAR** plan_ptr)
  1150. {
  1151. USHORT length;
  1152. SLONG explain_length = *explain_length_ptr;
  1153. const UCHAR* explain = *explain_ptr;
  1154. SLONG& plan_length = *plan_length_ptr;
  1155. SCHAR*& plan = *plan_ptr;
  1156. // go through the index tree information, just
  1157. // extracting the indices used
  1158. explain_length--;
  1159. switch (*explain++)
  1160. {
  1161. case isc_info_rsb_and:
  1162. case isc_info_rsb_or:
  1163. if (!get_indices(&explain_length, &explain, &plan_length, &plan))
  1164. return false;
  1165. if (!get_indices(&explain_length, &explain, &plan_length, &plan))
  1166. return false;
  1167. break;
  1168. case isc_info_rsb_dbkey:
  1169. break;
  1170. case isc_info_rsb_index:
  1171. explain_length--;
  1172. length = *explain++;
  1173. // if this isn't the first index, put out a comma
  1174. if (plan[-1] != '(' && plan[-1] != ' ') {
  1175. plan_length -= 2;
  1176. if (plan_length < 0)
  1177. return false;
  1178. *plan++ = ',';
  1179. *plan++ = ' ';
  1180. }
  1181. // now put out the index name
  1182. if ((plan_length -= length) < 0)
  1183. return false;
  1184. explain_length -= length;
  1185. while (length--)
  1186. *plan++ = *explain++;
  1187. break;
  1188. default:
  1189. return false;
  1190. }
  1191. *explain_length_ptr = explain_length;
  1192. *explain_ptr = explain;
  1193. //*plan_length_ptr = plan_length;
  1194. //*plan_ptr = plan;
  1195. return true;
  1196. }
  1197. /**
  1198. DSQL_get_plan_info
  1199. @brief Get the access plan for the request and turn
  1200. it into a textual representation suitable for
  1201. human reading.
  1202. @param request
  1203. @param buffer_length
  1204. @param out_buffer
  1205. @param realloc
  1206. **/
  1207. ULONG DSQL_get_plan_info(thread_db* tdbb,
  1208. const dsql_req* request,
  1209. SLONG buffer_length,
  1210. SCHAR** out_buffer,
  1211. const bool realloc)
  1212. {
  1213. if (!request->req_request) // DDL
  1214. return 0;
  1215. Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> explain_buffer;
  1216. explain_buffer.resize(BUFFER_LARGE);
  1217. // get the access path info for the underlying request from the engine
  1218. try
  1219. {
  1220. JRD_request_info(tdbb, request->req_request, 0,
  1221. sizeof(explain_info), explain_info,
  1222. explain_buffer.getCount(), explain_buffer.begin());
  1223. if (explain_buffer[0] == isc_info_truncated)
  1224. {
  1225. explain_buffer.resize(MAX_USHORT);
  1226. JRD_request_info(tdbb, request->req_request, 0,
  1227. sizeof(explain_info), explain_info,
  1228. explain_buffer.getCount(), explain_buffer.begin());
  1229. if (explain_buffer[0] == isc_info_truncated)
  1230. {
  1231. return 0;
  1232. }
  1233. }
  1234. }
  1235. catch (Firebird::Exception&)
  1236. {
  1237. return 0;
  1238. }
  1239. SCHAR* buffer_ptr = *out_buffer;
  1240. SCHAR* plan;
  1241. for (int i = 0; i < 2; i++)
  1242. {
  1243. const UCHAR* explain = explain_buffer.begin();
  1244. if (*explain++ != isc_info_access_path)
  1245. {
  1246. return 0;
  1247. }
  1248. SLONG explain_length = (ULONG) *explain++;
  1249. explain_length += (ULONG) (*explain++) << 8;
  1250. plan = buffer_ptr;
  1251. // CVC: What if we need to do 2nd pass? Those variables were only initialized
  1252. // at the begining of the function hence they had trash the second time.
  1253. USHORT join_count = 0, level = 0;
  1254. const ULONG full_len = buffer_length;
  1255. memset(plan, 0, full_len);
  1256. // This is testing code for the limit case,
  1257. // please do not enable for normal operations.
  1258. /*
  1259. if (full_len == ULONG(MAX_USHORT) - 4)
  1260. {
  1261. const size_t test_offset = 55000;
  1262. memset(plan, '.', test_offset);
  1263. plan += test_offset;
  1264. buffer_length -= test_offset;
  1265. }
  1266. */
  1267. // keep going until we reach the end of the explain info
  1268. while (explain_length > 0 && buffer_length > 0)
  1269. {
  1270. if (!get_rsb_item(&explain_length, &explain, &buffer_length, &plan, &join_count, &level))
  1271. {
  1272. // don't allocate buffer of the same length second time
  1273. // and let user know plan is incomplete
  1274. if (buffer_ptr != *out_buffer ||
  1275. (!realloc && full_len == ULONG(MAX_USHORT) - 4))
  1276. {
  1277. const ptrdiff_t diff = buffer_ptr + full_len - plan;
  1278. if (diff < 3) {
  1279. plan -= 3 - diff;
  1280. }
  1281. fb_assert(plan > buffer_ptr);
  1282. *plan++ = '.';
  1283. *plan++ = '.';
  1284. *plan++ = '.';
  1285. if (!realloc)
  1286. return plan - buffer_ptr;
  1287. ++i;
  1288. break;
  1289. }
  1290. if (!realloc)
  1291. return full_len - buffer_length;
  1292. // assume we have run out of room in the buffer, try again with a larger one
  1293. const size_t new_length = MAX_USHORT;
  1294. char* const temp = static_cast<char*>(gds__alloc(new_length));
  1295. if (!temp) {
  1296. // NOMEM. Do not attempt one more try
  1297. i++;
  1298. break;
  1299. }
  1300. buffer_ptr = temp;
  1301. buffer_length = (SLONG) new_length;
  1302. break;
  1303. }
  1304. }
  1305. if (buffer_ptr == *out_buffer)
  1306. break;
  1307. }
  1308. *out_buffer = buffer_ptr;
  1309. return plan - *out_buffer;
  1310. }
  1311. /**
  1312. get_request_info
  1313. @brief Get the records updated/deleted for record
  1314. @param request
  1315. @param buffer_length
  1316. @param buffer
  1317. **/
  1318. static USHORT get_request_info(thread_db* tdbb,
  1319. dsql_req* request,
  1320. SLONG buffer_length,
  1321. UCHAR* buffer)
  1322. {
  1323. if (!request->req_request) // DDL
  1324. return 0;
  1325. // get the info for the request from the engine
  1326. try
  1327. {
  1328. JRD_request_info(tdbb, request->req_request, 0,
  1329. sizeof(record_info), record_info,
  1330. buffer_length, buffer);
  1331. }
  1332. catch (Firebird::Exception&)
  1333. {
  1334. return 0;
  1335. }
  1336. const UCHAR* data = buffer;
  1337. request->req_updates = request->req_deletes = 0;
  1338. request->req_selects = request->req_inserts = 0;
  1339. UCHAR p;
  1340. while ((p = *data++) != isc_info_end)
  1341. {
  1342. const USHORT data_length = static_cast<USHORT>(gds__vax_integer(data, 2));
  1343. data += 2;
  1344. switch (p)
  1345. {
  1346. case isc_info_req_update_count:
  1347. request->req_updates = gds__vax_integer(data, data_length);
  1348. break;
  1349. case isc_info_req_delete_count:
  1350. request->req_deletes = gds__vax_integer(data, data_length);
  1351. break;
  1352. case isc_info_req_select_count:
  1353. request->req_selects = gds__vax_integer(data, data_length);
  1354. break;
  1355. case isc_info_req_insert_count:
  1356. request->req_inserts = gds__vax_integer(data, data_length);
  1357. break;
  1358. default:
  1359. break;
  1360. }
  1361. data += data_length;
  1362. }
  1363. return data - buffer;
  1364. }
  1365. /**
  1366. get_rsb_item
  1367. @brief Use recursion to print out a reverse-polish
  1368. access plan of joins and join types. Return true on success
  1369. and false on failure
  1370. @param explain_length_ptr
  1371. @param explain_ptr
  1372. @param plan_length_ptr
  1373. @param plan_ptr
  1374. @param parent_join_count
  1375. @param level_ptr
  1376. **/
  1377. static bool get_rsb_item(SLONG* explain_length_ptr,
  1378. const UCHAR** explain_ptr,
  1379. SLONG* plan_length_ptr,
  1380. SCHAR** plan_ptr,
  1381. USHORT* parent_join_count,
  1382. USHORT* level_ptr)
  1383. {
  1384. const SCHAR* p;
  1385. SSHORT rsb_type;
  1386. SLONG explain_length = *explain_length_ptr;
  1387. const UCHAR* explain = *explain_ptr;
  1388. SLONG& plan_length = *plan_length_ptr;
  1389. SCHAR*& plan = *plan_ptr;
  1390. explain_length--;
  1391. switch (*explain++)
  1392. {
  1393. case isc_info_rsb_begin:
  1394. if (!*level_ptr)
  1395. {
  1396. // put out the PLAN prefix
  1397. p = "\nPLAN ";
  1398. if ((plan_length -= strlen(p)) < 0)
  1399. return false;
  1400. while (*p)
  1401. *plan++ = *p++;
  1402. }
  1403. (*level_ptr)++;
  1404. break;
  1405. case isc_info_rsb_end:
  1406. if (*level_ptr) {
  1407. (*level_ptr)--;
  1408. }
  1409. // else --*parent_join_count; ???
  1410. break;
  1411. case isc_info_rsb_relation:
  1412. // for the single relation case, initiate
  1413. // the relation with a parenthesis
  1414. if (!*parent_join_count) {
  1415. if (--plan_length < 0)
  1416. return false;
  1417. *plan++ = '(';
  1418. }
  1419. // if this isn't the first relation, put out a comma
  1420. if (plan[-1] != '(') {
  1421. plan_length -= 2;
  1422. if (plan_length < 0)
  1423. return false;
  1424. *plan++ = ',';
  1425. *plan++ = ' ';
  1426. }
  1427. // put out the relation name
  1428. { // scope to keep length local.
  1429. explain_length--;
  1430. SSHORT length = (USHORT) *explain++;
  1431. explain_length -= length;
  1432. if ((plan_length -= length) < 0)
  1433. return false;
  1434. while (length--)
  1435. *plan++ = *explain++;
  1436. } // scope
  1437. break;
  1438. case isc_info_rsb_type:
  1439. explain_length--;
  1440. // for stream types which have multiple substreams, print out
  1441. // the stream type and recursively print out the substreams so
  1442. // we will know where to put the parentheses
  1443. switch (rsb_type = *explain++)
  1444. {
  1445. case isc_info_rsb_union:
  1446. case isc_info_rsb_recursive:
  1447. // put out all the substreams of the join
  1448. { // scope to have union_count, union_level and union_join_count local.
  1449. explain_length--;
  1450. fb_assert(*explain > 0U);
  1451. USHORT union_count = (USHORT) *explain++ - 1;
  1452. // finish the first union member
  1453. USHORT union_level = *level_ptr;
  1454. USHORT union_join_count = 0;
  1455. while (explain_length > 0 && plan_length > 0)
  1456. {
  1457. if (!get_rsb_item(&explain_length, &explain, &plan_length, &plan,
  1458. &union_join_count, &union_level))
  1459. {
  1460. return false;
  1461. }
  1462. if (union_level == *level_ptr)
  1463. break;
  1464. }
  1465. // for the rest of the members, start the level at 0 so each
  1466. // gets its own "PLAN ... " line
  1467. while (union_count)
  1468. {
  1469. union_join_count = 0;
  1470. union_level = 0;
  1471. while (explain_length > 0 && plan_length > 0)
  1472. {
  1473. if (!get_rsb_item(&explain_length, &explain, &plan_length,
  1474. &plan, &union_join_count, &union_level))
  1475. {
  1476. return false;
  1477. }
  1478. if (!union_level)
  1479. break;
  1480. }
  1481. union_count--;
  1482. }
  1483. } // scope
  1484. break;
  1485. case isc_info_rsb_cross:
  1486. case isc_info_rsb_left_cross:
  1487. case isc_info_rsb_merge:
  1488. // if this join is itself part of a join list,
  1489. // but not the first item, then put out a comma
  1490. if (*parent_join_count && plan[-1] != '(')
  1491. {
  1492. plan_length -= 2;
  1493. if (plan_length < 0)
  1494. return false;
  1495. *plan++ = ',';
  1496. *plan++ = ' ';
  1497. }
  1498. // put out the join type
  1499. if (rsb_type == isc_info_rsb_cross || rsb_type == isc_info_rsb_left_cross)
  1500. {
  1501. p = "JOIN (";
  1502. }
  1503. else {
  1504. p = "MERGE (";
  1505. }
  1506. if ((plan_length -= strlen(p)) < 0)
  1507. return false;
  1508. while (*p)
  1509. *plan++ = *p++;
  1510. // put out all the substreams of the join
  1511. explain_length--;
  1512. { // scope to have join_count local.
  1513. USHORT join_count = (USHORT) *explain++;
  1514. while (join_count && explain_length > 0 && plan_length > 0)
  1515. {
  1516. if (!get_rsb_item(&explain_length, &explain, &plan_length,
  1517. &plan, &join_count, level_ptr))
  1518. {
  1519. return false;
  1520. }
  1521. // CVC: Here's the additional stop condition.
  1522. if (!*level_ptr) {
  1523. break;
  1524. }
  1525. }
  1526. } // scope
  1527. // put out the final parenthesis for the join
  1528. if (--plan_length < 0)
  1529. return false;
  1530. *plan++ = ')';
  1531. // this qualifies as a stream, so decrement the join count
  1532. if (*parent_join_count)
  1533. -- * parent_join_count;
  1534. break;
  1535. case isc_info_rsb_indexed:
  1536. case isc_info_rsb_navigate:
  1537. case isc_info_rsb_sequential:
  1538. case isc_info_rsb_ext_sequential:
  1539. case isc_info_rsb_ext_indexed:
  1540. case isc_info_rsb_virt_sequential:
  1541. switch (rsb_type)
  1542. {
  1543. case isc_info_rsb_indexed:
  1544. case isc_info_rsb_ext_indexed:
  1545. p = " INDEX (";
  1546. break;
  1547. case isc_info_rsb_navigate:
  1548. p = " ORDER ";
  1549. break;
  1550. default:
  1551. p = " NATURAL";
  1552. }
  1553. if ((plan_length -= strlen(p)) < 0)
  1554. return false;
  1555. while (*p)
  1556. *plan++ = *p++;
  1557. // print out additional index information
  1558. if (rsb_type == isc_info_rsb_indexed || rsb_type == isc_info_rsb_navigate ||
  1559. rsb_type == isc_info_rsb_ext_indexed)
  1560. {
  1561. if (!get_indices(&explain_length, &explain, &plan_length, &plan))
  1562. return false;
  1563. }
  1564. if (rsb_type == isc_info_rsb_navigate && *explain == isc_info_rsb_indexed)
  1565. {
  1566. USHORT idx_count = 1;
  1567. if (!get_rsb_item(&explain_length, &explain, &plan_length, &plan, &idx_count, level_ptr))
  1568. {
  1569. return false;
  1570. }
  1571. }
  1572. if (rsb_type == isc_info_rsb_indexed || rsb_type == isc_info_rsb_ext_indexed)
  1573. {
  1574. if (--plan_length < 0)
  1575. return false;
  1576. *plan++ = ')';
  1577. }
  1578. // detect the end of a single relation and put out a final parenthesis
  1579. if (!*parent_join_count)
  1580. {
  1581. if (--plan_length < 0)
  1582. return false;
  1583. *plan++ = ')';
  1584. }
  1585. // this also qualifies as a stream, so decrement the join count
  1586. if (*parent_join_count)
  1587. -- * parent_join_count;
  1588. break;
  1589. case isc_info_rsb_sort:
  1590. // if this sort is on behalf of a union, don't bother to
  1591. // print out the sort, because unions handle the sort on all
  1592. // substreams at once, and a plan maps to each substream
  1593. // in the union, so the sort doesn't really apply to a particular plan
  1594. if (explain_length > 2 && (explain[0] == isc_info_rsb_begin) &&
  1595. (explain[1] == isc_info_rsb_type) && (explain[2] == isc_info_rsb_union))
  1596. {
  1597. break;
  1598. }
  1599. // if this isn't the first item in the list, put out a comma
  1600. if (*parent_join_count && plan[-1] != '(')
  1601. {
  1602. plan_length -= 2;
  1603. if (plan_length < 0)
  1604. return false;
  1605. *plan++ = ',';
  1606. *plan++ = ' ';
  1607. }
  1608. p = "SORT (";
  1609. if ((plan_length -= strlen(p)) < 0)
  1610. return false;
  1611. while (*p)
  1612. *plan++ = *p++;
  1613. // the rsb_sort should always be followed by a begin...end block,
  1614. // allowing us to include everything inside the sort in parentheses
  1615. { // scope to have save_level local.
  1616. const USHORT save_level = *level_ptr;
  1617. while (explain_length > 0 && plan_length > 0)
  1618. {
  1619. if (!get_rsb_item(&explain_length, &explain, &plan_length,
  1620. &plan, parent_join_count, level_ptr))
  1621. {
  1622. return false;
  1623. }
  1624. if (*level_ptr == save_level)
  1625. break;
  1626. }
  1627. if (--plan_length < 0)
  1628. return false;
  1629. *plan++ = ')';
  1630. } // scope
  1631. break;
  1632. default:
  1633. break;
  1634. } // switch (rsb_type = *explain++)
  1635. break;
  1636. default:
  1637. break;
  1638. }
  1639. *explain_length_ptr = explain_length;
  1640. *explain_ptr = explain;
  1641. //*plan_length_ptr = plan_length;
  1642. //*plan_ptr = plan;
  1643. return true;
  1644. }
  1645. /**
  1646. init
  1647. @brief Initialize dynamic SQL. This is called only once.
  1648. @param db_handle
  1649. **/
  1650. static dsql_dbb* init(Attachment* attachment)
  1651. {
  1652. thread_db* tdbb = JRD_get_thread_data();
  1653. if (!attachment->att_dsql_instance)
  1654. {
  1655. MemoryPool& pool = *attachment->att_database->createPool();
  1656. dsql_dbb* const database = FB_NEW(pool) dsql_dbb(pool);
  1657. database->dbb_attachment = attachment;
  1658. database->dbb_database = attachment->att_database;
  1659. attachment->att_dsql_instance = database;
  1660. UCHAR buffer[BUFFER_TINY];
  1661. try
  1662. {
  1663. ThreadStatusGuard status_vector(tdbb);
  1664. INF_database_info(db_hdr_info_items, sizeof(db_hdr_info_items), buffer, sizeof(buffer));
  1665. }
  1666. catch (Firebird::Exception&)
  1667. {
  1668. return database;
  1669. }
  1670. const UCHAR* data = buffer;
  1671. UCHAR p;
  1672. while ((p = *data++) != isc_info_end)
  1673. {
  1674. const SSHORT l = static_cast<SSHORT>(gds__vax_integer(data, 2));
  1675. data += 2;
  1676. switch (p)
  1677. {
  1678. case isc_info_db_sql_dialect:
  1679. fb_assert(l == 1);
  1680. database->dbb_db_SQL_dialect = (USHORT) data[0];
  1681. break;
  1682. case isc_info_ods_version:
  1683. database->dbb_ods_version = gds__vax_integer(data, l);
  1684. if (database->dbb_ods_version <= 7)
  1685. {
  1686. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1687. Arg::Gds(isc_dsql_too_old_ods) << Arg::Num(8));
  1688. }
  1689. break;
  1690. case isc_info_ods_minor_version:
  1691. database->dbb_minor_version = gds__vax_integer(data, l);
  1692. break;
  1693. // This flag indicates the version level of the engine
  1694. // itself, so we can tell what capabilities the engine
  1695. // code itself (as opposed to the on-disk structure).
  1696. // Apparently the base level up to now indicated the major
  1697. // version number, but for 4.1 the base level is being
  1698. // incremented, so the base level indicates an engine version
  1699. // as follows:
  1700. // 1 == v1.x
  1701. // 2 == v2.x
  1702. // 3 == v3.x
  1703. // 4 == v4.0 only
  1704. // 5 == v4.1. (v5, too?)
  1705. // 6 == v6, FB1
  1706. // Note: this info item is so old it apparently uses an
  1707. // archaic format, not a standard vax integer format.
  1708. #ifdef SCROLLABLE_CURSORS
  1709. case isc_info_base_level:
  1710. fb_assert(l == 2 && data[0] == UCHAR(1));
  1711. database->dbb_base_level = (USHORT) data[1];
  1712. break;
  1713. #endif
  1714. case isc_info_db_read_only:
  1715. fb_assert(l == 1);
  1716. database->dbb_read_only = (USHORT) data[0] ? true : false;
  1717. break;
  1718. default:
  1719. break;
  1720. }
  1721. data += l;
  1722. }
  1723. }
  1724. return attachment->att_dsql_instance;
  1725. }
  1726. /**
  1727. map_in_out
  1728. @brief Map data from external world into message or
  1729. from message to external world.
  1730. @param request
  1731. @param message
  1732. @param blr_length
  1733. @param blr
  1734. @param msg_length
  1735. @param dsql_msg_buf
  1736. @param in_dsql_msg_buf
  1737. **/
  1738. static void map_in_out( dsql_req* request,
  1739. dsql_msg* message,
  1740. USHORT blr_length,
  1741. const UCHAR* blr,
  1742. USHORT msg_length,
  1743. UCHAR* dsql_msg_buf,
  1744. const UCHAR* in_dsql_msg_buf)
  1745. {
  1746. thread_db* tdbb = JRD_get_thread_data();
  1747. USHORT count = parse_blr(blr_length, blr, msg_length, message->msg_parameters);
  1748. // When mapping data from the external world, request will be non-NULL.
  1749. // When mapping data from an internal message, request will be NULL.
  1750. dsql_par* parameter;
  1751. for (parameter = message->msg_parameters; parameter; parameter = parameter->par_next)
  1752. {
  1753. if (parameter->par_index)
  1754. {
  1755. // Make sure the message given to us is long enough
  1756. dsc desc = parameter->par_user_desc;
  1757. USHORT length = (IPTR) desc.dsc_address + desc.dsc_length;
  1758. if (length > msg_length)
  1759. break;
  1760. if (!desc.dsc_dtype)
  1761. break;
  1762. SSHORT* flag = NULL;
  1763. dsql_par* const null_ind = parameter->par_null;
  1764. if (null_ind != NULL)
  1765. {
  1766. const USHORT null_offset = (IPTR) null_ind->par_user_desc.dsc_address;
  1767. length = null_offset + sizeof(SSHORT);
  1768. if (length > msg_length)
  1769. break;
  1770. if (!request) {
  1771. flag = reinterpret_cast<SSHORT*>(dsql_msg_buf + null_offset);
  1772. *flag = *reinterpret_cast<const SSHORT*>(null_ind->par_desc.dsc_address);
  1773. }
  1774. else {
  1775. flag = reinterpret_cast<SSHORT*>(null_ind->par_desc.dsc_address);
  1776. *flag = *reinterpret_cast<const SSHORT*>(in_dsql_msg_buf + null_offset);
  1777. }
  1778. }
  1779. if (!request)
  1780. {
  1781. desc.dsc_address = dsql_msg_buf + (IPTR) desc.dsc_address;
  1782. if (!flag || *flag >= 0)
  1783. {
  1784. MOVD_move(tdbb, &parameter->par_desc, &desc);
  1785. }
  1786. else
  1787. {
  1788. memset(desc.dsc_address, 0, desc.dsc_length);
  1789. }
  1790. }
  1791. else if (!flag || *flag >= 0)
  1792. {
  1793. if (!(parameter->par_desc.dsc_flags & DSC_null))
  1794. {
  1795. // Safe cast because desc is used as source only.
  1796. desc.dsc_address = const_cast<UCHAR*>(in_dsql_msg_buf) + (IPTR) desc.dsc_address;
  1797. MOVD_move(tdbb, &desc, &parameter->par_desc);
  1798. }
  1799. }
  1800. else
  1801. {
  1802. memset(parameter->par_desc.dsc_address, 0, parameter->par_desc.dsc_length);
  1803. }
  1804. count--;
  1805. }
  1806. }
  1807. // If we got here because the loop was exited early or if part of the
  1808. // message given to us hasn't been used, complain.
  1809. if (parameter || count)
  1810. {
  1811. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1812. Arg::Gds(isc_dsql_sqlda_err));
  1813. }
  1814. dsql_par* dbkey;
  1815. if (request && ((dbkey = request->req_parent_dbkey) != NULL) &&
  1816. ((parameter = request->req_dbkey) != NULL))
  1817. {
  1818. MOVD_move(tdbb, &dbkey->par_desc, &parameter->par_desc);
  1819. dsql_par* null_ind = parameter->par_null;
  1820. if (null_ind != NULL)
  1821. {
  1822. SSHORT* flag = (SSHORT *) null_ind->par_desc.dsc_address;
  1823. *flag = 0;
  1824. }
  1825. }
  1826. dsql_par* rec_version;
  1827. if (request && ((rec_version = request->req_parent_rec_version) != NULL) &&
  1828. ((parameter = request->req_rec_version) != NULL))
  1829. {
  1830. MOVD_move(tdbb, &rec_version->par_desc, &parameter->par_desc);
  1831. dsql_par* null_ind = parameter->par_null;
  1832. if (null_ind != NULL)
  1833. {
  1834. SSHORT* flag = (SSHORT *) null_ind->par_desc.dsc_address;
  1835. *flag = 0;
  1836. }
  1837. }
  1838. }
  1839. /**
  1840. parse_blr
  1841. @brief Parse the message of a blr request.
  1842. @param blr_length
  1843. @param blr
  1844. @param msg_length
  1845. @param parameters
  1846. **/
  1847. static USHORT parse_blr(USHORT blr_length,
  1848. const UCHAR* blr, const USHORT msg_length, dsql_par* parameters_list)
  1849. {
  1850. Firebird::HalfStaticArray<dsql_par*, 16> parameters;
  1851. for (dsql_par* param = parameters_list; param; param = param->par_next)
  1852. {
  1853. if (param->par_index)
  1854. {
  1855. if (param->par_index > parameters.getCount())
  1856. parameters.grow(param->par_index);
  1857. fb_assert(!parameters[param->par_index - 1]);
  1858. parameters[param->par_index - 1] = param;
  1859. }
  1860. }
  1861. // If there's no blr length, then the format of the current message buffer
  1862. // is identical to the format of the previous one.
  1863. if (!blr_length)
  1864. {
  1865. return parameters.getCount();
  1866. }
  1867. if (*blr != blr_version4 && *blr != blr_version5)
  1868. {
  1869. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1870. Arg::Gds(isc_dsql_sqlda_err));
  1871. }
  1872. blr++; // skip the blr_version
  1873. if (*blr++ != blr_begin || *blr++ != blr_message)
  1874. {
  1875. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1876. Arg::Gds(isc_dsql_sqlda_err));
  1877. }
  1878. ++blr; // skip the message number
  1879. USHORT count = *blr++;
  1880. count += (*blr++) << 8;
  1881. count /= 2;
  1882. if (count != parameters.getCount())
  1883. {
  1884. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1885. Arg::Gds(isc_dsql_sqlda_err));
  1886. }
  1887. USHORT offset = 0;
  1888. for (USHORT index = 1; index <= count; index++)
  1889. {
  1890. dsc desc;
  1891. desc.dsc_scale = 0;
  1892. desc.dsc_sub_type = 0;
  1893. desc.dsc_flags = 0;
  1894. switch (*blr++)
  1895. {
  1896. case blr_text:
  1897. desc.dsc_dtype = dtype_text;
  1898. desc.dsc_sub_type = ttype_dynamic;
  1899. desc.dsc_length = *blr++;
  1900. desc.dsc_length += (*blr++) << 8;
  1901. break;
  1902. case blr_varying:
  1903. desc.dsc_dtype = dtype_varying;
  1904. desc.dsc_sub_type = ttype_dynamic;
  1905. desc.dsc_length = *blr++ + sizeof(USHORT);
  1906. desc.dsc_length += (*blr++) << 8;
  1907. break;
  1908. case blr_text2:
  1909. desc.dsc_dtype = dtype_text;
  1910. desc.dsc_sub_type = *blr++;
  1911. desc.dsc_sub_type += (*blr++) << 8;
  1912. desc.dsc_length = *blr++;
  1913. desc.dsc_length += (*blr++) << 8;
  1914. break;
  1915. case blr_varying2:
  1916. desc.dsc_dtype = dtype_varying;
  1917. desc.dsc_sub_type = *blr++;
  1918. desc.dsc_sub_type += (*blr++) << 8;
  1919. desc.dsc_length = *blr++ + sizeof(USHORT);
  1920. desc.dsc_length += (*blr++) << 8;
  1921. break;
  1922. case blr_short:
  1923. desc.dsc_dtype = dtype_short;
  1924. desc.dsc_length = sizeof(SSHORT);
  1925. desc.dsc_scale = *blr++;
  1926. break;
  1927. case blr_long:
  1928. desc.dsc_dtype = dtype_long;
  1929. desc.dsc_length = sizeof(SLONG);
  1930. desc.dsc_scale = *blr++;
  1931. break;
  1932. case blr_int64:
  1933. desc.dsc_dtype = dtype_int64;
  1934. desc.dsc_length = sizeof(SINT64);
  1935. desc.dsc_scale = *blr++;
  1936. break;
  1937. case blr_quad:
  1938. desc.dsc_dtype = dtype_quad;
  1939. desc.dsc_length = sizeof(SLONG) * 2;
  1940. desc.dsc_scale = *blr++;
  1941. break;
  1942. case blr_float:
  1943. desc.dsc_dtype = dtype_real;
  1944. desc.dsc_length = sizeof(float);
  1945. break;
  1946. case blr_double:
  1947. case blr_d_float:
  1948. desc.dsc_dtype = dtype_double;
  1949. desc.dsc_length = sizeof(double);
  1950. break;
  1951. case blr_timestamp:
  1952. desc.dsc_dtype = dtype_timestamp;
  1953. desc.dsc_length = sizeof(SLONG) * 2;
  1954. break;
  1955. case blr_sql_date:
  1956. desc.dsc_dtype = dtype_sql_date;
  1957. desc.dsc_length = sizeof(SLONG);
  1958. break;
  1959. case blr_sql_time:
  1960. desc.dsc_dtype = dtype_sql_time;
  1961. desc.dsc_length = sizeof(SLONG);
  1962. break;
  1963. case blr_blob2:
  1964. {
  1965. desc.dsc_dtype = dtype_blob;
  1966. desc.dsc_length = sizeof(ISC_QUAD);
  1967. desc.dsc_sub_type = *blr++;
  1968. desc.dsc_sub_type += (*blr++) << 8;
  1969. USHORT textType = *blr++;
  1970. textType += (*blr++) << 8;
  1971. desc.setTextType(textType);
  1972. }
  1973. break;
  1974. default:
  1975. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1976. Arg::Gds(isc_dsql_sqlda_err));
  1977. }
  1978. USHORT align = type_alignments[desc.dsc_dtype];
  1979. if (align)
  1980. offset = FB_ALIGN(offset, align);
  1981. desc.dsc_address = (UCHAR*)(IPTR) offset;
  1982. offset += desc.dsc_length;
  1983. if (*blr++ != blr_short || *blr++ != 0)
  1984. {
  1985. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  1986. Arg::Gds(isc_dsql_sqlda_err));
  1987. }
  1988. align = type_alignments[dtype_short];
  1989. if (align)
  1990. offset = FB_ALIGN(offset, align);
  1991. USHORT null_offset = offset;
  1992. offset += sizeof(SSHORT);
  1993. dsql_par* const parameter = parameters[index - 1];
  1994. fb_assert(parameter);
  1995. parameter->par_user_desc = desc;
  1996. // ASF: Older than 2.5 engine hasn't validating strings in DSQL. After this has been
  1997. // implemented in 2.5, selecting a NONE column with UTF-8 attachment charset started
  1998. // failing. The real problem is that the client encodes SQL_TEXT/SQL_VARYING using
  1999. // blr_text/blr_varying (i.e. with the connection charset). I'm reseting the charset
  2000. // here at the server as a way to make older (and not yet changed) client work
  2001. // correctly.
  2002. if (parameter->par_user_desc.isText())
  2003. parameter->par_user_desc.setTextType(ttype_none);
  2004. dsql_par* null = parameter->par_null;
  2005. if (null)
  2006. {
  2007. null->par_user_desc.dsc_dtype = dtype_short;
  2008. null->par_user_desc.dsc_scale = 0;
  2009. null->par_user_desc.dsc_length = sizeof(SSHORT);
  2010. null->par_user_desc.dsc_address = (UCHAR*)(IPTR) null_offset;
  2011. }
  2012. }
  2013. if (*blr++ != (UCHAR) blr_end || offset != msg_length)
  2014. {
  2015. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  2016. Arg::Gds(isc_dsql_sqlda_err));
  2017. }
  2018. return count;
  2019. }
  2020. /**
  2021. prepare
  2022. @brief Prepare a statement for execution. Return SQL status
  2023. code. Note: caller is responsible for pool handling.
  2024. @param request
  2025. @param string_length
  2026. @param string
  2027. @param client_dialect
  2028. @param parser_version
  2029. **/
  2030. static dsql_req* prepare(thread_db* tdbb, dsql_dbb* database, jrd_tra* transaction,
  2031. USHORT string_length,
  2032. const TEXT* string,
  2033. USHORT client_dialect, USHORT parser_version)
  2034. {
  2035. ISC_STATUS_ARRAY local_status;
  2036. MOVE_CLEAR(local_status, sizeof(local_status));
  2037. TraceDSQLPrepare trace(database->dbb_attachment, string_length, string);
  2038. if (client_dialect > SQL_DIALECT_CURRENT)
  2039. {
  2040. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
  2041. Arg::Gds(isc_wish_list));
  2042. }
  2043. if (string && !string_length)
  2044. {
  2045. size_t sql_length = strlen(string);
  2046. if (sql_length > MAX_USHORT)
  2047. sql_length = MAX_USHORT;
  2048. string_length = static_cast<USHORT>(sql_length);
  2049. }
  2050. if (!string || !string_length) {
  2051. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
  2052. // Unexpected end of command
  2053. // CVC: Nothing will be line 1, column 1 for the user.
  2054. Arg::Gds(isc_command_end_err2) << Arg::Num(1) << Arg::Num(1));
  2055. }
  2056. // Get rid of the trailing ";" if there is one.
  2057. for (const TEXT* p = string + string_length; p-- > string;)
  2058. {
  2059. if (*p != ' ') {
  2060. if (*p == ';')
  2061. string_length = p - string;
  2062. break;
  2063. }
  2064. }
  2065. // allocate the statement block, then prepare the statement
  2066. Jrd::ContextPoolHolder context(tdbb, database->createPool());
  2067. MemoryPool& pool = *tdbb->getDefaultPool();
  2068. CompiledStatement* statement = FB_NEW(pool) CompiledStatement(pool);
  2069. statement->req_dbb = database;
  2070. database->dbb_requests.add(statement);
  2071. statement->req_transaction = transaction;
  2072. statement->req_client_dialect = client_dialect;
  2073. statement->req_traced = true;
  2074. trace.setStatement(statement);
  2075. try {
  2076. // Parse the SQL statement. If it croaks, return
  2077. Parser parser(*tdbb->getDefaultPool(), client_dialect, statement->req_dbb->dbb_db_SQL_dialect,
  2078. parser_version, string, string_length, tdbb->getAttachment()->att_charset);
  2079. dsql_nod* node = parser.parse();
  2080. statement->req_sql_text = FB_NEW(pool) RefString(pool, parser.getTransformedString());
  2081. if (!node)
  2082. {
  2083. // CVC: Apparently, dsql_ypparse won't return if the command is incomplete,
  2084. // because yyerror() will call ERRD_post().
  2085. // This may be a special case, but we don't know about positions here.
  2086. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
  2087. // Unexpected end of command
  2088. Arg::Gds(isc_command_end_err));
  2089. }
  2090. // allocate the send and receive messages
  2091. statement->req_send = FB_NEW(pool) dsql_msg;
  2092. dsql_msg* message = FB_NEW(pool) dsql_msg;
  2093. statement->req_receive = message;
  2094. message->msg_number = 1;
  2095. #ifdef SCROLLABLE_CURSORS
  2096. if (statement->req_dbb->dbb_base_level >= 5) {
  2097. // allocate a message in which to send scrolling information
  2098. // outside of the normal send/receive protocol
  2099. statement->req_async = message = FB_NEW(*tdsql->getDefaultPool()) dsql_msg;
  2100. message->msg_number = 2;
  2101. }
  2102. #endif
  2103. statement->req_type = REQ_SELECT;
  2104. statement->req_flags &= ~REQ_cursor_open;
  2105. // No work is done during pass1 for set transaction - like
  2106. // checking for valid table names. This is because that will
  2107. // require a valid transaction handle.
  2108. // Error will be caught at execute time.
  2109. node = PASS1_statement(statement, node);
  2110. if (!node)
  2111. return statement;
  2112. switch (statement->req_type)
  2113. {
  2114. case REQ_COMMIT:
  2115. case REQ_COMMIT_RETAIN:
  2116. case REQ_ROLLBACK:
  2117. case REQ_ROLLBACK_RETAIN:
  2118. case REQ_GET_SEGMENT:
  2119. case REQ_PUT_SEGMENT:
  2120. case REQ_START_TRANS:
  2121. statement->req_traced = false;
  2122. break;
  2123. default:
  2124. statement->req_traced = true;
  2125. }
  2126. // stop here for statements not requiring code generation
  2127. if (statement->req_type == REQ_DDL && parser.isStmtAmbiguous() &&
  2128. statement->req_dbb->dbb_db_SQL_dialect != client_dialect)
  2129. {
  2130. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-817) <<
  2131. Arg::Gds(isc_ddl_not_allowed_by_db_sql_dial) << Arg::Num(statement->req_dbb->dbb_db_SQL_dialect));
  2132. }
  2133. switch (statement->req_type)
  2134. {
  2135. case REQ_COMMIT:
  2136. case REQ_COMMIT_RETAIN:
  2137. case REQ_ROLLBACK:
  2138. case REQ_ROLLBACK_RETAIN:
  2139. return statement;
  2140. // Work on blob segment statements
  2141. case REQ_GET_SEGMENT:
  2142. case REQ_PUT_SEGMENT:
  2143. GEN_port(statement, statement->req_blob->blb_open_in_msg);
  2144. GEN_port(statement, statement->req_blob->blb_open_out_msg);
  2145. GEN_port(statement, statement->req_blob->blb_segment_msg);
  2146. return statement;
  2147. // Generate BLR, DDL or TPB for statement
  2148. // Start transactions takes parameters via a parameter block.
  2149. // The statement blr string is used for that
  2150. case REQ_START_TRANS:
  2151. GEN_start_transaction(statement, node);
  2152. return statement;
  2153. }
  2154. if (client_dialect > SQL_DIALECT_V5)
  2155. statement->req_flags |= REQ_blr_version5;
  2156. else
  2157. statement->req_flags |= REQ_blr_version4;
  2158. GEN_request(statement, node);
  2159. const ULONG length = (ULONG) statement->req_blr_data.getCount();
  2160. // stop here for ddl statements
  2161. if (statement->req_type == REQ_CREATE_DB || statement->req_type == REQ_DDL)
  2162. {
  2163. // Notify Trace API manager about new DDL request cooked.
  2164. trace.prepare(res_successful);
  2165. return statement;
  2166. }
  2167. // have the access method compile the statement
  2168. #ifdef DSQL_DEBUG
  2169. if (DSQL_debug & 64) {
  2170. dsql_trace("Resulting BLR code for DSQL:");
  2171. gds__trace_raw("Statement:\n");
  2172. gds__trace_raw(string, string_length);
  2173. gds__trace_raw("\nBLR:\n");
  2174. fb_print_blr(statement->req_blr_data.begin(),
  2175. (ULONG) statement->req_blr_data.getCount(),
  2176. gds__trace_printer, 0, 0);
  2177. }
  2178. #endif
  2179. // check for warnings
  2180. if (tdbb->tdbb_status_vector[2] == isc_arg_warning) {
  2181. // save a status vector
  2182. memcpy(local_status, tdbb->tdbb_status_vector, sizeof(ISC_STATUS_ARRAY));
  2183. }
  2184. ISC_STATUS status = FB_SUCCESS;
  2185. try
  2186. {
  2187. JRD_compile(tdbb,
  2188. statement->req_dbb->dbb_attachment,
  2189. &statement->req_request,
  2190. length,
  2191. statement->req_blr_data.begin(),
  2192. statement->req_sql_text,
  2193. statement->req_debug_data.getCount(),
  2194. statement->req_debug_data.begin());
  2195. }
  2196. catch (const Firebird::Exception&)
  2197. {
  2198. status = tdbb->tdbb_status_vector[1];
  2199. trace.prepare(status == isc_no_priv ? res_unauthorized : res_failed);
  2200. }
  2201. // restore warnings (if there are any)
  2202. if (local_status[2] == isc_arg_warning)
  2203. {
  2204. int indx, len, warning;
  2205. // find end of a status vector
  2206. PARSE_STATUS(tdbb->tdbb_status_vector, indx, warning);
  2207. if (indx)
  2208. --indx;
  2209. // calculate length of saved warnings
  2210. PARSE_STATUS(local_status, len, warning);
  2211. len -= 2;
  2212. if ((len + indx - 1) < ISC_STATUS_LENGTH)
  2213. memcpy(&tdbb->tdbb_status_vector[indx], &local_status[2], sizeof(ISC_STATUS) * len);
  2214. }
  2215. // free blr memory
  2216. statement->req_blr_data.free();
  2217. if (status)
  2218. Firebird::status_exception::raise(tdbb->tdbb_status_vector);
  2219. // Notify Trace API manager about new request cooked.
  2220. trace.prepare(res_successful);
  2221. return statement;
  2222. }
  2223. catch (const Firebird::Exception&)
  2224. {
  2225. trace.prepare(res_failed);
  2226. statement->req_traced = false;
  2227. release_request(tdbb, statement, true);
  2228. throw;
  2229. }
  2230. }
  2231. /**
  2232. put_item
  2233. @brief Put information item in output buffer if there is room, and
  2234. return an updated pointer. If there isn't room for the item,
  2235. indicate truncation and return NULL.
  2236. @param item
  2237. @param length
  2238. @param string
  2239. @param ptr
  2240. @param end
  2241. @param copy
  2242. **/
  2243. static UCHAR* put_item( UCHAR item,
  2244. const USHORT length,
  2245. const UCHAR* string,
  2246. UCHAR* ptr,
  2247. const UCHAR* const end,
  2248. const bool copy)
  2249. {
  2250. if (ptr + length + 3 >= end) {
  2251. *ptr = isc_info_truncated;
  2252. return NULL;
  2253. }
  2254. *ptr++ = item;
  2255. *ptr++ = (UCHAR) length;
  2256. *ptr++ = length >> 8;
  2257. if (length && copy)
  2258. memcpy(ptr, string, length);
  2259. return ptr + length;
  2260. }
  2261. /**
  2262. release_request
  2263. @brief Release a dynamic request.
  2264. @param request
  2265. @param top_level
  2266. **/
  2267. static void release_request(thread_db* tdbb, dsql_req* request, bool drop)
  2268. {
  2269. SET_TDBB(tdbb);
  2270. // If request is parent, orphan the children and
  2271. // release a portion of their requests
  2272. for (dsql_req* child = request->req_offspring; child; child = child->req_sibling)
  2273. {
  2274. child->req_flags |= REQ_orphan;
  2275. child->req_parent = NULL;
  2276. Jrd::ContextPoolHolder context(tdbb, &child->req_pool);
  2277. release_request(tdbb, child, false);
  2278. }
  2279. // For requests that are linked to a parent, unlink it
  2280. if (request->req_parent)
  2281. {
  2282. dsql_req* parent = request->req_parent;
  2283. for (dsql_req** ptr = &parent->req_offspring; *ptr; ptr = &(*ptr)->req_sibling)
  2284. {
  2285. if (*ptr == request) {
  2286. *ptr = request->req_sibling;
  2287. break;
  2288. }
  2289. }
  2290. request->req_parent = NULL;
  2291. }
  2292. // If the request had an open cursor, close it
  2293. if (request->req_flags & REQ_cursor_open) {
  2294. close_cursor(tdbb, request);
  2295. }
  2296. Attachment* att = request->req_dbb->dbb_attachment;
  2297. const bool need_trace_free = request->req_traced && TraceManager::need_dsql_free(att);
  2298. if (need_trace_free)
  2299. {
  2300. TraceSQLStatementImpl stmt(request, NULL);
  2301. TraceManager::event_dsql_free(att, &stmt, DSQL_drop);
  2302. }
  2303. request->req_traced = false;
  2304. // If request is named, clear it from the hash table
  2305. if (request->req_name) {
  2306. HSHD_remove(request->req_name);
  2307. request->req_name = NULL;
  2308. }
  2309. if (request->req_cursor) {
  2310. HSHD_remove(request->req_cursor);
  2311. request->req_cursor = NULL;
  2312. }
  2313. // If a request has been compiled, release it now
  2314. if (request->req_request)
  2315. {
  2316. ThreadStatusGuard status_vector(tdbb);
  2317. try
  2318. {
  2319. CMP_release(tdbb, request->req_request);
  2320. request->req_request = NULL;
  2321. }
  2322. catch (Firebird::Exception&)
  2323. {
  2324. }
  2325. }
  2326. request->req_sql_text = NULL;
  2327. // free blr memory
  2328. request->req_blr_data.free();
  2329. // Release the entire request if explicitly asked for
  2330. if (drop)
  2331. {
  2332. dsql_dbb* dbb = request->req_dbb;
  2333. size_t pos;
  2334. if (dbb->dbb_requests.find(request, pos)) {
  2335. dbb->dbb_requests.remove(pos);
  2336. }
  2337. dbb->deletePool(&request->req_pool);
  2338. }
  2339. }
  2340. /**
  2341. sql_info
  2342. @brief Return DSQL information buffer.
  2343. @param request
  2344. @param item_length
  2345. @param items
  2346. @param info_length
  2347. @param info
  2348. **/
  2349. static void sql_info(thread_db* tdbb,
  2350. dsql_req* request,
  2351. USHORT item_length,
  2352. const UCHAR* items,
  2353. ULONG info_length,
  2354. UCHAR* info)
  2355. {
  2356. if (!item_length || !items || !info_length || !info)
  2357. return;
  2358. UCHAR buffer[BUFFER_SMALL];
  2359. memset(buffer, 0, sizeof(buffer));
  2360. // Pre-initialize buffer. This is necessary because we don't want to transfer rubbish over the wire
  2361. memset(info, 0, info_length);
  2362. const UCHAR* const end_items = items + item_length;
  2363. const UCHAR* const end_info = info + info_length;
  2364. UCHAR *start_info;
  2365. if (*items == isc_info_length) {
  2366. start_info = info;
  2367. items++;
  2368. }
  2369. else {
  2370. start_info = NULL;
  2371. }
  2372. // CVC: Is it the idea that this pointer remains with its previous value
  2373. // in the loop or should it be made NULL in each iteration?
  2374. dsql_msg** message = NULL;
  2375. USHORT first_index = 0;
  2376. while (items < end_items && *items != isc_info_end)
  2377. {
  2378. ULONG length;
  2379. USHORT number;
  2380. const UCHAR item = *items++;
  2381. switch (item)
  2382. {
  2383. case isc_info_sql_select:
  2384. case isc_info_sql_bind:
  2385. message = (item == isc_info_sql_select) ? &request->req_receive : &request->req_send;
  2386. if (info + 1 >= end_info) {
  2387. *info = isc_info_truncated;
  2388. return;
  2389. }
  2390. *info++ = item;
  2391. break;
  2392. case isc_info_sql_stmt_type:
  2393. switch (request->req_type)
  2394. {
  2395. case REQ_SELECT:
  2396. case REQ_EMBED_SELECT:
  2397. number = isc_info_sql_stmt_select;
  2398. break;
  2399. case REQ_SELECT_UPD:
  2400. number = isc_info_sql_stmt_select_for_upd;
  2401. break;
  2402. case REQ_CREATE_DB:
  2403. case REQ_DDL:
  2404. number = isc_info_sql_stmt_ddl;
  2405. break;
  2406. case REQ_GET_SEGMENT:
  2407. number = isc_info_sql_stmt_get_segment;
  2408. break;
  2409. case REQ_PUT_SEGMENT:
  2410. number = isc_info_sql_stmt_put_segment;
  2411. break;
  2412. case REQ_COMMIT:
  2413. case REQ_COMMIT_RETAIN:
  2414. number = isc_info_sql_stmt_commit;
  2415. break;
  2416. case REQ_ROLLBACK:
  2417. case REQ_ROLLBACK_RETAIN:
  2418. number = isc_info_sql_stmt_rollback;
  2419. break;
  2420. case REQ_START_TRANS:
  2421. number = isc_info_sql_stmt_start_trans;
  2422. break;
  2423. case REQ_INSERT:
  2424. number = isc_info_sql_stmt_insert;
  2425. break;
  2426. case REQ_UPDATE:
  2427. case REQ_UPDATE_CURSOR:
  2428. number = isc_info_sql_stmt_update;
  2429. break;
  2430. case REQ_DELETE:
  2431. case REQ_DELETE_CURSOR:
  2432. number = isc_info_sql_stmt_delete;
  2433. break;
  2434. case REQ_EXEC_PROCEDURE:
  2435. number = isc_info_sql_stmt_exec_procedure;
  2436. break;
  2437. case REQ_SET_GENERATOR:
  2438. number = isc_info_sql_stmt_set_generator;
  2439. break;
  2440. case REQ_SAVEPOINT:
  2441. number = isc_info_sql_stmt_savepoint;
  2442. break;
  2443. case REQ_EXEC_BLOCK:
  2444. number = isc_info_sql_stmt_exec_procedure;
  2445. break;
  2446. case REQ_SELECT_BLOCK:
  2447. number = isc_info_sql_stmt_select;
  2448. break;
  2449. default:
  2450. number = 0;
  2451. break;
  2452. }
  2453. length = convert((SLONG) number, buffer);
  2454. info = put_item(item, length, buffer, info, end_info);
  2455. if (!info) {
  2456. return;
  2457. }
  2458. break;
  2459. case isc_info_sql_sqlda_start:
  2460. length = *items++;
  2461. first_index = static_cast<USHORT>(gds__vax_integer(items, length));
  2462. items += length;
  2463. break;
  2464. case isc_info_sql_batch_fetch:
  2465. if (request->req_flags & REQ_no_batch)
  2466. number = 0;
  2467. else
  2468. number = 1;
  2469. length = convert((SLONG) number, buffer);
  2470. if (!(info = put_item(item, length, buffer, info, end_info))) {
  2471. return;
  2472. }
  2473. break;
  2474. case isc_info_sql_records:
  2475. length = get_request_info(tdbb, request, sizeof(buffer), buffer);
  2476. if (length && !(info = put_item(item, length, buffer, info, end_info)))
  2477. {
  2478. return;
  2479. }
  2480. break;
  2481. case isc_info_sql_get_plan:
  2482. {
  2483. // be careful, get_plan_info() will reallocate the buffer to a
  2484. // larger size if it is not big enough
  2485. //UCHAR* buffer_ptr = buffer;
  2486. UCHAR* buffer_ptr = info + 3;
  2487. // Somebody decided to put a platform-dependent NEWLINE at the beginning,
  2488. // see get_rsb_item! This idea predates FB1.
  2489. static const size_t minPlan = strlen("\nPLAN (T NATURAL)");
  2490. if (info + minPlan + 3 >= end_info)
  2491. {
  2492. fb_assert(info < end_info);
  2493. *info = isc_info_truncated;
  2494. info = NULL;
  2495. length = 0;
  2496. }
  2497. else
  2498. {
  2499. //length = DSQL_get_plan_info(tdbb, request, sizeof(buffer),
  2500. // reinterpret_cast<SCHAR**>(&buffer_ptr));
  2501. length = DSQL_get_plan_info(tdbb, request, (end_info - info - 4),
  2502. reinterpret_cast<SCHAR**>(&buffer_ptr),
  2503. false);
  2504. }
  2505. if (length)
  2506. {
  2507. if (length > MAX_USHORT)
  2508. {
  2509. fb_assert(info < end_info);
  2510. *info = isc_info_truncated;
  2511. info = NULL;
  2512. }
  2513. else
  2514. info = put_item(item, length, buffer_ptr, info, end_info, false);
  2515. }
  2516. //if (length > sizeof(buffer) || buffer_ptr != buffer) {
  2517. // gds__free(buffer_ptr);
  2518. //}
  2519. if (!info) {
  2520. return;
  2521. }
  2522. }
  2523. break;
  2524. case isc_info_sql_num_variables:
  2525. case isc_info_sql_describe_vars:
  2526. if (message)
  2527. {
  2528. number = (*message) ? (*message)->msg_index : 0;
  2529. length = convert((SLONG) number, buffer);
  2530. if (!(info = put_item(item, length, buffer, info, end_info))) {
  2531. return;
  2532. }
  2533. if (item == isc_info_sql_num_variables) {
  2534. continue;
  2535. }
  2536. const UCHAR* end_describe = items;
  2537. while (end_describe < end_items &&
  2538. *end_describe != isc_info_end && *end_describe != isc_info_sql_describe_end)
  2539. {
  2540. end_describe++;
  2541. }
  2542. info = var_info(*message, items, end_describe, info, end_info, first_index,
  2543. message == &request->req_send);
  2544. if (!info) {
  2545. return;
  2546. }
  2547. items = end_describe;
  2548. if (*items == isc_info_sql_describe_end) {
  2549. items++;
  2550. }
  2551. break;
  2552. }
  2553. // else fall into
  2554. default:
  2555. buffer[0] = item;
  2556. length = 1 + convert((SLONG) isc_infunk, buffer + 1);
  2557. if (!(info = put_item(isc_info_error, length, buffer, info, end_info))) {
  2558. return;
  2559. }
  2560. }
  2561. }
  2562. *info++ = isc_info_end;
  2563. if (start_info && (end_info - info >= 7))
  2564. {
  2565. const SLONG number = info - start_info;
  2566. fb_assert(number > 0);
  2567. memmove(start_info + 7, start_info, number);
  2568. USHORT length = convert(number, buffer);
  2569. fb_assert(length == 4); // We only accept SLONG
  2570. put_item(isc_info_length, length, buffer, start_info, end_info);
  2571. }
  2572. }
  2573. /**
  2574. var_info
  2575. @brief Provide information on an internal message.
  2576. @param message
  2577. @param items
  2578. @param end_describe
  2579. @param info
  2580. @param end
  2581. @param first_index
  2582. **/
  2583. static UCHAR* var_info(dsql_msg* message,
  2584. const UCHAR* items,
  2585. const UCHAR* const end_describe,
  2586. UCHAR* info,
  2587. const UCHAR* const end,
  2588. USHORT first_index,
  2589. bool input_message)
  2590. {
  2591. if (!message || !message->msg_index)
  2592. return info;
  2593. Firebird::HalfStaticArray<const dsql_par*, 16> parameters;
  2594. for (const dsql_par* param = message->msg_parameters; param; param = param->par_next)
  2595. {
  2596. if (param->par_index)
  2597. {
  2598. if (param->par_index > parameters.getCount())
  2599. parameters.grow(param->par_index);
  2600. fb_assert(!parameters[param->par_index - 1]);
  2601. parameters[param->par_index - 1] = param;
  2602. }
  2603. }
  2604. UCHAR buf[128];
  2605. for (size_t i = 0; i < parameters.getCount(); i++)
  2606. {
  2607. const dsql_par* param = parameters[i];
  2608. fb_assert(param);
  2609. if (param->par_index >= first_index)
  2610. {
  2611. SLONG sql_len = param->par_desc.dsc_length;
  2612. SLONG sql_sub_type = 0;
  2613. SLONG sql_scale = 0;
  2614. SLONG sql_type = 0;
  2615. switch (param->par_desc.dsc_dtype)
  2616. {
  2617. case dtype_real:
  2618. sql_type = SQL_FLOAT;
  2619. break;
  2620. case dtype_array:
  2621. sql_type = SQL_ARRAY;
  2622. break;
  2623. case dtype_timestamp:
  2624. sql_type = SQL_TIMESTAMP;
  2625. break;
  2626. case dtype_sql_date:
  2627. sql_type = SQL_TYPE_DATE;
  2628. break;
  2629. case dtype_sql_time:
  2630. sql_type = SQL_TYPE_TIME;
  2631. break;
  2632. case dtype_double:
  2633. sql_type = SQL_DOUBLE;
  2634. sql_scale = param->par_desc.dsc_scale;
  2635. break;
  2636. case dtype_text:
  2637. if (input_message && (param->par_desc.dsc_flags & DSC_null))
  2638. {
  2639. sql_type = SQL_NULL;
  2640. sql_len = 0;
  2641. }
  2642. else
  2643. {
  2644. sql_type = SQL_TEXT;
  2645. sql_sub_type = param->par_desc.dsc_sub_type;
  2646. }
  2647. break;
  2648. case dtype_blob:
  2649. sql_type = SQL_BLOB;
  2650. sql_sub_type = param->par_desc.dsc_sub_type;
  2651. sql_scale = param->par_desc.dsc_scale;
  2652. break;
  2653. case dtype_varying:
  2654. sql_type = SQL_VARYING;
  2655. sql_len -= sizeof(USHORT);
  2656. sql_sub_type = param->par_desc.dsc_sub_type;
  2657. break;
  2658. case dtype_short:
  2659. case dtype_long:
  2660. case dtype_int64:
  2661. switch (param->par_desc.dsc_dtype)
  2662. {
  2663. case dtype_short:
  2664. sql_type = SQL_SHORT;
  2665. break;
  2666. case dtype_long:
  2667. sql_type = SQL_LONG;
  2668. break;
  2669. default:
  2670. sql_type = SQL_INT64;
  2671. }
  2672. sql_scale = param->par_desc.dsc_scale;
  2673. if (param->par_desc.dsc_sub_type)
  2674. sql_sub_type = param->par_desc.dsc_sub_type;
  2675. break;
  2676. case dtype_quad:
  2677. sql_type = SQL_QUAD;
  2678. sql_scale = param->par_desc.dsc_scale;
  2679. break;
  2680. default:
  2681. ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
  2682. Arg::Gds(isc_dsql_datatype_err));
  2683. }
  2684. if (sql_type && (param->par_desc.dsc_flags & DSC_nullable))
  2685. sql_type++;
  2686. for (const UCHAR* describe = items; describe < end_describe;)
  2687. {
  2688. USHORT length;
  2689. const TEXT* name;
  2690. const UCHAR* buffer = buf;
  2691. UCHAR item = *describe++;
  2692. switch (item)
  2693. {
  2694. case isc_info_sql_sqlda_seq:
  2695. length = convert((SLONG) param->par_index, buf);
  2696. break;
  2697. case isc_info_sql_message_seq:
  2698. length = 0;
  2699. break;
  2700. case isc_info_sql_type:
  2701. length = convert((SLONG) sql_type, buf);
  2702. break;
  2703. case isc_info_sql_sub_type:
  2704. length = convert((SLONG) sql_sub_type, buf);
  2705. break;
  2706. case isc_info_sql_scale:
  2707. length = convert((SLONG) sql_scale, buf);
  2708. break;
  2709. case isc_info_sql_length:
  2710. length = convert((SLONG) sql_len, buf);
  2711. break;
  2712. case isc_info_sql_null_ind:
  2713. length = convert((SLONG) (sql_type & 1), buf);
  2714. break;
  2715. case isc_info_sql_field:
  2716. if (name = param->par_name) {
  2717. length = strlen(name);
  2718. buffer = reinterpret_cast<const UCHAR*>(name);
  2719. }
  2720. else
  2721. length = 0;
  2722. break;
  2723. case isc_info_sql_relation:
  2724. if (name = param->par_rel_name) {
  2725. length = strlen(name);
  2726. buffer = reinterpret_cast<const UCHAR*>(name);
  2727. }
  2728. else
  2729. length = 0;
  2730. break;
  2731. case isc_info_sql_owner:
  2732. if (name = param->par_owner_name) {
  2733. length = strlen(name);
  2734. buffer = reinterpret_cast<const UCHAR*>(name);
  2735. }
  2736. else
  2737. length = 0;
  2738. break;
  2739. case isc_info_sql_relation_alias:
  2740. if (name = param->par_rel_alias) {
  2741. length = strlen(name);
  2742. buffer = reinterpret_cast<const UCHAR*>(name);
  2743. }
  2744. else
  2745. length = 0;
  2746. break;
  2747. case isc_info_sql_alias:
  2748. if (name = param->par_alias) {
  2749. length = strlen(name);
  2750. buffer = reinterpret_cast<const UCHAR*>(name);
  2751. }
  2752. else
  2753. length = 0;
  2754. break;
  2755. default:
  2756. buf[0] = item;
  2757. item = isc_info_error;
  2758. length = 1 + convert((SLONG) isc_infunk, buf + 1);
  2759. break;
  2760. }
  2761. if (!(info = put_item(item, length, buffer, info, end)))
  2762. return info;
  2763. }
  2764. if (info + 1 >= end) {
  2765. *info = isc_info_truncated;
  2766. return NULL;
  2767. }
  2768. *info++ = isc_info_sql_describe_end;
  2769. } // if()
  2770. } // for()
  2771. return info;
  2772. }