-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathstatement.h
More file actions
630 lines (545 loc) · 16.6 KB
/
statement.h
File metadata and controls
630 lines (545 loc) · 16.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
/* Copyright (c) 2023, 2024, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is designed to work with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have either included with
the program or referenced in the documentation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef RUN_COMMAND_H
#define RUN_COMMAND_H
#include <cstddef>
#include <forward_list>
#include <new>
#include <string>
#include <string_view>
#include "lex_string.h"
#include "my_alloc.h"
#include "my_inttypes.h"
#include "mysql_time.h"
#include "sql/current_thd.h"
#include "sql/sql_class.h"
#include "sql/sql_cursor.h"
#include "sql/sql_prepare.h" // Prepared_statement
#include "sql/statement/protocol_local_v2.h"
#include "sql/statement/statement_runnable.h"
#include "utils.h"
/**
There must be one function of this kind in order for the symbols in the
server's dynamic library to be visible to components.
*/
int dummy_function_to_ensure_we_are_linked_into_the_server();
/**
* @brief
* Statement_handle is extension of Ed_connection. Some of the
* limitations in Ed_connection is that,
* - It does not support reading result metadata
* - It does not support prepared statement, parameters and cursors.
*
* Above limitation leads to implementation of this interface.
*
* Statement_handle supports both execution of regular and
* prepared statement.
*
* Note that we can get rid of Ed_connection implementation
* as we support more functionality with Statement_handle.
*/
class Statement_handle {
public:
Statement_handle(THD *thd, const char *query, size_t length);
/**
* @brief Check if error is reported.
*
* @return true of error is reported.
*/
bool is_error() const { return m_diagnostics_area->is_error(); }
/**
* @brief Check if error is reported.
*
* @return true of error is reported.
*/
const char *get_last_error() {
assert(is_error());
return convert_and_store(&m_warning_mem_root,
m_diagnostics_area->message_text(),
strlen(m_diagnostics_area->message_text()),
system_charset_info, m_expected_charset);
}
/**
* @brief Get the last mysql errno.
*
* @return unsigned int
*/
unsigned int get_last_errno() const {
assert(is_error());
return m_diagnostics_area->mysql_errno();
}
/**
* @brief Get the mysql error state.
*
* @return const char*
*/
const char *get_mysql_state() {
assert(is_error());
return convert_and_store(&m_warning_mem_root,
m_diagnostics_area->returned_sqlstate(),
strlen(m_diagnostics_area->returned_sqlstate()),
system_charset_info, m_expected_charset);
}
/**
* @brief Get number of warnings generated.
*
* @return ulonglong
*/
ulonglong warning_count() const { return m_warnings_count; }
/**
* @brief Get list of all warnings.
*
* @return Warning*
*/
Warning *get_warnings();
/**
* @brief Get the next result sets generated while executing the statement.
*
* @return Result_set*
*/
Result_set *get_result_sets() { return m_result_sets; }
/**
* @brief Get the current result set object
*
* @return Result_set*
*/
Result_set *get_current_result_set() { return m_current_rset; }
/**
* @brief Make the next result set the current result set.
* We do it once we have read the current result set.
*
*/
void next_result_set() {
auto next_rset = m_current_rset->get_next();
m_current_rset = next_rset;
}
/**
* @brief Execute the SQL command.
* This can be either Regular or Prepared statement.
*
* @return true upon failure.
* @return false upon success.
*/
virtual bool execute() = 0;
/**
* @brief Check if we are processing a prepared statement.
*
* @return true upon failure.
* @return false upon success.
*/
virtual bool is_prepared_statement() = 0;
/**
* @brief Check if the statement has been executed or prepared
*
* @return true upon executed or prepared
* @return false otherwise
*/
virtual bool is_executed_or_prepared() = 0;
/**
* @brief Feel all the result collected so far, from query execution.
*
*/
void free_old_result();
/**
* @brief Get the query string being executed.
*
* @return std::string_view
*/
std::string_view get_query() { return m_query; }
/**
* @brief Set the capacity in bytes allowed for caching results.
*
* @param capacity of the result set
*/
void set_capacity(size_t capacity) {
m_protocol.set_result_set_capacity(capacity);
}
/**
* @brief Get the capacity in bytes allowed for caching results.
*
* @return size_t
*/
size_t get_capacity() { return m_protocol.get_result_set_capacity(); }
/**
* @brief Set thd protocol to enable result pass through.
*
* @param use_thd_protocol - parameter that decides if THD protocol should be
* used
*/
void set_use_thd_protocol(bool use_thd_protocol) {
m_use_thd_protocol = use_thd_protocol;
}
/**
* @brief Check if thd protocol is used.
*
* @return true if enabled.
* @return false if not.
*/
bool is_using_thd_protocol() const { return m_use_thd_protocol; }
/**
* @brief Set either Protocol_local_v2 when m_use_thd_protocol is not set or
* or classical protocol when m_use_thd_protocol is set to THD.
*/
void set_thd_protocol();
/**
* @brief Reset THD protocol.
*/
void reset_thd_protocol();
/**
* @brief Set the expected charset
*
* @param charset_name Name of the charset
*/
void set_expected_charset(const char *charset_name) {
m_expected_charset =
get_charset_by_csname(charset_name, MY_CS_PRIMARY, MYF(0));
}
/**
* @brief Get the expected charset
*
* @return const char* the expected charset name
*/
const char *get_expected_charset() {
if (m_expected_charset == nullptr) return nullptr;
return m_expected_charset->csname;
}
/**
* @brief Get the num rows per fetch.
*
* @return size_t
*/
size_t get_num_rows_per_fetch() { return m_num_rows_per_fetch; }
/**
* @brief Set the num of rows to be retrieved per fetch.
*
* @param num_rows_per_fetch number of rows per fetch
*/
void set_num_rows_per_fetch(size_t num_rows_per_fetch) {
m_num_rows_per_fetch = num_rows_per_fetch;
}
/**
* @brief Destroy the Statement_handle object
*
*/
virtual ~Statement_handle() { free_old_result(); }
protected:
/**
* @brief Send statement execution status after execute().
*/
void send_statement_status();
protected:
// The query being executed.
std::string m_query;
// Details about error or warning occured.
MEM_ROOT m_warning_mem_root;
Warning *m_warnings;
ulonglong m_warnings_count = 0;
Diagnostics_area *m_diagnostics_area;
// The thread executing the statement.
THD *m_thd;
// List of all results generated by the query.
Result_set *m_result_sets;
// The last result generated by the guery.
Result_set *m_current_rset;
// Do not intercept the results in the protocol, but pass it to
// THD* protocol. E.g., if this is set to 'false', the results are
// captured into Protocol_result_v2, else it goes to THD->get_protocol()
bool m_use_thd_protocol = false;
// Max rows to read per fetch() call.
size_t m_num_rows_per_fetch = 1;
CHARSET_INFO *m_expected_charset;
// Collect result set from single statement.
void add_result_set(Result_set *result_set);
// Set result set from prepared statement with cursor.
// This is called at the end of fetch().
void set_result_set(Result_set *result_set);
/**
* @brief Copy the warnings generated for the query from the
* diagnostics area
*/
void copy_warnings();
// Protocol that intercepts all the rows from query executed.
Protocol_local_v2 m_protocol;
friend class Protocol_local_v2;
// Protocol used by THD before switching.
Protocol *m_saved_protocol{nullptr};
// No copies.
Statement_handle(const Statement_handle &) = delete;
// No move.
Statement_handle(Statement_handle &&) = delete;
// No self assignment.
Statement_handle &operator=(const Statement_handle &) = delete;
// No move.
Statement_handle &operator=(Statement_handle &&) = delete;
};
/**
* @brief Regular_statement_handle enables execution of all SQL statements
* except for prepared statements.
*/
class Regular_statement_handle : public Statement_handle {
public:
Regular_statement_handle(THD *thd, const char *query, uint length)
: Statement_handle(thd, query, length) {}
/**
* @brief Execute a regular statement.
*
* @return true if statement fails.
* @return false if statement succeeds.
*/
bool execute() override;
/**
* @brief Convey that this is regular statement.
*
* @return Always returns 'false'
*/
bool is_prepared_statement() override { return false; }
/**
* @brief Check if the statement has been executed
*
* @return true if executed
* @return false otherwise
*/
bool is_executed_or_prepared() override { return m_is_executed; }
private:
// Flag to show whether statement has been executed. Change to true after
// execute is called
bool m_is_executed = false;
// Used by execute() above.
bool execute(Server_runnable *server_runnable);
};
/**
* @brief Prepared_statement_handle enables support for prepared
* statement execution. Supports parameters and cursors.
*/
class Prepared_statement_handle : public Statement_handle {
public:
Prepared_statement_handle(THD *thd, const char *query, uint length)
: Statement_handle(thd, query, length),
m_parameter_mem_root(key_memory_prepared_statement_main_mem_root,
thd->variables.query_alloc_block_size) {}
/**
* @brief Prepares the statement using m_query.
*
* If the statement is already in executing mode, close the cursor
* deallocate the previous statement and start preparing new statement
* using m_query.
*
* @return true if fails.
* @return false if succeeds.
*/
bool prepare();
/**
* @brief Set the parameter value in a prepared statement.
*
* @param idx Index of '?' in prepared statement.
* @param is_null Set parameter to NULL value.
* @param type Set the parameters field type.
* @param is_unsigned Mark parameter as unsigned.
* @param data Pointer to buffer containing the value.
* @param data_length Length of buffer 'data'
* @param name Name of parameter (mostly unused)
* @param name_length Length of 'name'
*
* @return true if fails.
* @return false if succeeds.
*/
bool set_parameter(uint idx, bool is_null, enum_field_types type,
bool is_unsigned, const void *data,
unsigned long data_length, const char *name,
unsigned long name_length);
/**
* @brief Get the parameter object
*
* @param index of the parameter
* @return Item_param*
*/
Item_param *get_parameter(size_t index);
/**
* @brief Execute the statement that is prepared.
*
* If a statement is not yet prepared, we fail.
*
* If a statement was already in EXECUTED state, we close the cursor
* and execute the statement again.
*
* @return true
* @return false
*/
bool execute() override;
/**
* @brief Fetch rows from statement using cursor.
*
* Not all statement uses cursor. Check is_cursor_open() and
* then invoke this call.
*
* Attempt to call fetch rows without preparing or executing the
* statement will cause failure.
*
* Attempt to call fetch() without cursor in use, will cause failure.
*
* @return true
* @return false
*/
bool fetch();
/**
* @brief Check if the statement uses cursor and it is open.
*
* If the API is called without preparing the statement will
* result in 'false'
*
* @return true if cursor is in use
* @return false if cursor not in use.
*/
bool is_cursor_open() {
if (!m_stmt) return false;
return m_stmt->m_cursor && m_stmt->m_cursor->is_open();
}
/**
* @brief Check if the statement uses cursor.
*
* If the API is called without executing the statement
* will result in 'false'
*
* @return true if statement uses cursor.
* @return false if statement does not uses cursor.
*/
bool uses_cursor() {
if (!m_stmt || m_stmt->m_arena.get_state() != Query_arena::STMT_EXECUTED)
return false;
return m_stmt->m_cursor != nullptr;
}
/**
* @brief Reset the statement parameters and cursors.
*
* Invoking this API will close the cursor in use.
* This is invoked generally before executing
* the statement for the second time, after prepare.
*
* @return true
* @return false
*/
bool reset();
/**
* @brief Close the statement that is prepared.
*
* @return true
* @return false
*/
bool close();
/**
* @brief Get number of parameters used in the statement.
*
* This should be called after preparing a statement.
*
* @return uint
*/
uint get_param_count() { return m_stmt ? m_stmt->m_param_count : 0; }
/**
* @brief Convey that this is prepared statement.
*
* @return Always returns true
*/
bool is_prepared_statement() override { return true; }
/**
* @brief Check if the statement has been executed or prepared
*
* @return true if executed or prepared
* @return false otherwise
*/
bool is_executed_or_prepared() override {
return m_stmt != nullptr &&
m_stmt->m_arena.get_state() > Query_arena::STMT_INITIALIZED;
}
/**
* @brief Virtual destroy for Prepared_statement_handle object
*
*/
virtual ~Prepared_statement_handle() override { internal_close(); }
private:
/**
* @brief This is a wrapper function used to execute
* and operation on Prepared_statement. This takes case of using
* relevant protocol, diagnostic area, backup the current query arena
* before executing the prepared statement operation.
*
* @tparam Function type of function to run
* @param exec_func function to run
* @return true
* @return false
*/
template <typename Function>
bool run(Function exec_func);
// See prepare()
bool internal_prepare();
// See execute()
bool internal_execute();
// See fetch()
bool internal_fetch();
// See reset()
bool internal_reset();
/**
* @brief Reset the statement parameters and cursors.
*
* @param invalidate_params When set to true parameters are invalidated.
*
* @return true on failure.
* @return false on execute.
*/
bool internal_reset(bool invalidate_params);
// See close()
bool internal_close();
/**
* @brief Method to enable cursor.
*
* @return true if cursor can be used for a statement.
* @return false if cursor can not be used for a statement.
*/
bool enable_cursor();
/**
* @brief Create a parameter buffers
*
* @return true on failure
* @return false on success
*/
bool create_parameter_buffers();
// The prepared statement implementation.
Prepared_statement *m_stmt{nullptr};
// Parameters values.
PS_PARAM *m_parameters{nullptr};
/*
Store the parameter and parameter values in a separate mem_root.
These can be even stored in m_stmt's mem_root. But reprepare() would
free up the memory used by the prepared statement. Hence, using separate
mem_root.
*/
MEM_ROOT m_parameter_mem_root;
/*
Size of each parameter buffer allocated in mem_root.
We re-use the same buffer, if the parameter value size fit
within this max.
*/
ulong *m_parameter_buffer_max{nullptr};
/*
Denotes if new parameters were set.
This is set 'true' for the first time. It is set to 'false' upon
re-execute without rebinding any parameters.
*/
bool m_bound_new_parameter_types{true};
};
#endif