/src/tarantool/src/box/sql/vdbeapi.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. |
3 | | * |
4 | | * Redistribution and use in source and binary forms, with or |
5 | | * without modification, are permitted provided that the following |
6 | | * conditions are met: |
7 | | * |
8 | | * 1. Redistributions of source code must retain the above |
9 | | * copyright notice, this list of conditions and the |
10 | | * following disclaimer. |
11 | | * |
12 | | * 2. Redistributions in binary form must reproduce the above |
13 | | * copyright notice, this list of conditions and the following |
14 | | * disclaimer in the documentation and/or other materials |
15 | | * provided with the distribution. |
16 | | * |
17 | | * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND |
18 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
19 | | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
21 | | * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
22 | | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
25 | | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
26 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
28 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | | * SUCH DAMAGE. |
30 | | */ |
31 | | |
32 | | /* |
33 | | * |
34 | | * This file contains code use to implement APIs that are part of the |
35 | | * VDBE. |
36 | | */ |
37 | | #include "sqlInt.h" |
38 | | #include "mem.h" |
39 | | #include "vdbeInt.h" |
40 | | #include "box/session.h" |
41 | | |
42 | | /* |
43 | | * Invoke the profile callback. This routine is only called if we already |
44 | | * know that the profile callback is defined and needs to be invoked. |
45 | | */ |
46 | | static SQL_NOINLINE void |
47 | | invokeProfileCallback(struct Vdbe *p) |
48 | 0 | { |
49 | 0 | struct sql *db = sql_get(); |
50 | 0 | sql_int64 iNow; |
51 | 0 | sql_int64 iElapse; |
52 | 0 | assert(p->startTime > 0); |
53 | 0 | assert(db->xProfile != 0 || (db->mTrace & SQL_TRACE_PROFILE) != 0); |
54 | 0 | assert(db->init.busy == 0); |
55 | 0 | assert(p->zSql != 0); |
56 | 0 | sqlOsCurrentTimeInt64(db->pVfs, &iNow); |
57 | 0 | iElapse = (iNow - p->startTime) * 1000000; |
58 | 0 | if (db->xProfile) { |
59 | 0 | db->xProfile(db->pProfileArg, p->zSql, iElapse); |
60 | 0 | } |
61 | 0 | if (db->mTrace & SQL_TRACE_PROFILE) { |
62 | 0 | db->xTrace(SQL_TRACE_PROFILE, db->pTraceArg, p, |
63 | 0 | (void *)&iElapse); |
64 | 0 | } |
65 | 0 | p->startTime = 0; |
66 | 0 | } |
67 | | |
68 | | int |
69 | | sql_stmt_finalize(struct Vdbe *v) |
70 | 0 | { |
71 | 0 | if (v == NULL) |
72 | 0 | return 0; |
73 | 0 | if (v->startTime > 0) |
74 | 0 | invokeProfileCallback(v); |
75 | 0 | return sqlVdbeFinalize(v); |
76 | 0 | } |
77 | | |
78 | | int |
79 | | sql_stmt_reset(struct Vdbe *v) |
80 | 0 | { |
81 | 0 | assert(v != NULL); |
82 | 0 | if (v->startTime > 0) |
83 | 0 | invokeProfileCallback(v); |
84 | 0 | int rc = sqlVdbeReset(v); |
85 | 0 | sqlVdbeRewind(v); |
86 | 0 | return rc; |
87 | 0 | } |
88 | | |
89 | | bool |
90 | | sql_metadata_is_full() |
91 | 0 | { |
92 | 0 | return current_session()->sql_flags & SQL_FullMetadata; |
93 | 0 | } |
94 | | |
95 | | /* |
96 | | * Execute the statement pStmt, either until a row of data is ready, the |
97 | | * statement is completely executed or an error occurs. |
98 | | * |
99 | | * This routine implements the bulk of the logic behind the sql_step() |
100 | | * API. The only thing omitted is the automatic recompile if a |
101 | | * schema change has occurred. That detail is handled by the |
102 | | * outer sql_step() wrapper procedure. |
103 | | */ |
104 | | static int |
105 | | sqlStep(Vdbe * p) |
106 | 0 | { |
107 | 0 | struct sql *db = sql_get(); |
108 | 0 | int rc; |
109 | |
|
110 | 0 | assert(p); |
111 | 0 | if (p->magic != VDBE_MAGIC_RUN) |
112 | 0 | sql_stmt_reset(p); |
113 | |
|
114 | 0 | if (p->pc <= 0 && p->expired) { |
115 | 0 | p->is_aborted = true; |
116 | 0 | return -1; |
117 | 0 | } |
118 | 0 | if (p->pc < 0) { |
119 | 0 | if ((db->xProfile || (db->mTrace & SQL_TRACE_PROFILE) != 0) |
120 | 0 | && !db->init.busy && p->zSql) { |
121 | 0 | sqlOsCurrentTimeInt64(db->pVfs, &p->startTime); |
122 | 0 | } else { |
123 | 0 | assert(p->startTime == 0); |
124 | 0 | } |
125 | | |
126 | 0 | db->nVdbeActive++; |
127 | 0 | p->pc = 0; |
128 | 0 | } |
129 | 0 | if (p->explain) { |
130 | 0 | rc = sqlVdbeList(p); |
131 | 0 | } else { |
132 | 0 | db->nVdbeExec++; |
133 | 0 | rc = sqlVdbeExec(p); |
134 | 0 | db->nVdbeExec--; |
135 | 0 | } |
136 | | |
137 | | /* If the statement completed successfully, invoke the profile callback */ |
138 | 0 | if (rc != SQL_ROW && p->startTime > 0) |
139 | 0 | invokeProfileCallback(p); |
140 | |
|
141 | 0 | if (rc != SQL_ROW && rc != SQL_DONE) { |
142 | | /* If this statement was prepared using sql_prepare(), and an |
143 | | * error has occurred, then return an error. |
144 | | */ |
145 | 0 | if (p->is_aborted) |
146 | 0 | rc = -1; |
147 | 0 | } |
148 | 0 | return rc; |
149 | 0 | } |
150 | | |
151 | | int |
152 | | sql_step(struct Vdbe *v) |
153 | 0 | { |
154 | 0 | assert(v != NULL); |
155 | 0 | return sqlStep(v); |
156 | 0 | } |
157 | | |
158 | | int |
159 | | sql_column_count(struct Vdbe *pVm) |
160 | 0 | { |
161 | 0 | return pVm ? pVm->nResColumn : 0; |
162 | 0 | } |
163 | | |
164 | | char * |
165 | | sql_stmt_result_to_msgpack(struct Vdbe *vdbe, uint32_t *tuple_size, |
166 | | struct region *region) |
167 | 0 | { |
168 | 0 | return mem_encode_array(vdbe->pResultSet, vdbe->nResColumn, tuple_size, |
169 | 0 | region); |
170 | 0 | } |
171 | | |
172 | | char * |
173 | | sql_stmt_func_result_to_msgpack(struct Vdbe *vdbe, uint32_t *size, |
174 | | struct region *region) |
175 | 0 | { |
176 | 0 | assert(vdbe->nResColumn == 1); |
177 | 0 | return mem_to_mp(vdbe->pResultSet, size, region); |
178 | 0 | } |
179 | | |
180 | | const char * |
181 | | sql_column_name(struct Vdbe *p, int n) |
182 | 0 | { |
183 | 0 | assert(n < sql_column_count(p) && n >= 0); |
184 | 0 | return p->metadata[n].name; |
185 | 0 | } |
186 | | |
187 | | const char * |
188 | | sql_column_datatype(struct Vdbe *p, int n) |
189 | 0 | { |
190 | 0 | assert(n < sql_column_count(p) && n >= 0); |
191 | 0 | return p->metadata[n].type; |
192 | 0 | } |
193 | | |
194 | | const char * |
195 | | sql_column_coll(struct Vdbe *p, int n) |
196 | 0 | { |
197 | 0 | assert(n < sql_column_count(p) && n >= 0); |
198 | 0 | return p->metadata[n].collation; |
199 | 0 | } |
200 | | |
201 | | int |
202 | | sql_column_nullable(struct Vdbe *p, int n) |
203 | 0 | { |
204 | 0 | assert(n < sql_column_count(p) && n >= 0); |
205 | 0 | return p->metadata[n].nullable; |
206 | 0 | } |
207 | | |
208 | | bool |
209 | | sql_column_is_autoincrement(struct Vdbe *p, int n) |
210 | 0 | { |
211 | 0 | assert(n < sql_column_count(p) && n >= 0); |
212 | 0 | return p->metadata[n].is_actoincrement; |
213 | 0 | } |
214 | | |
215 | | const char * |
216 | 0 | sql_column_span(struct Vdbe *p, int n) { |
217 | 0 | assert(n < sql_column_count(p) && n >= 0); |
218 | 0 | return p->metadata[n].span; |
219 | 0 | } |
220 | | |
221 | | uint64_t |
222 | | sql_stmt_schema_version(const struct Vdbe *v) |
223 | 0 | { |
224 | 0 | return v->schema_ver; |
225 | 0 | } |
226 | | |
227 | | static size_t |
228 | | sql_metadata_size(const struct sql_column_metadata *metadata) |
229 | 0 | { |
230 | 0 | size_t size = sizeof(*metadata); |
231 | 0 | if (metadata->type != NULL) |
232 | 0 | size += strlen(metadata->type); |
233 | 0 | if (metadata->name != NULL) |
234 | 0 | size += strlen(metadata->name); |
235 | 0 | if (metadata->collation != NULL) |
236 | 0 | size += strlen(metadata->collation); |
237 | 0 | return size; |
238 | 0 | } |
239 | | |
240 | | size_t |
241 | | sql_stmt_est_size(const struct Vdbe *v) |
242 | 0 | { |
243 | 0 | size_t size = sizeof(*v); |
244 | | /* Names and types of result set columns */ |
245 | 0 | for (int i = 0; i < v->nResColumn; ++i) |
246 | 0 | size += sql_metadata_size(&v->metadata[i]); |
247 | | /* Opcodes */ |
248 | 0 | size += sizeof(struct VdbeOp) * v->nOp; |
249 | | /* Memory cells */ |
250 | 0 | size += sizeof(struct Mem) * v->nMem; |
251 | | /* Bindings */ |
252 | 0 | size += sizeof(struct Mem) * v->nVar; |
253 | | /* Bindings included in the result set */ |
254 | 0 | size += sizeof(uint32_t) * v->res_var_count; |
255 | | /* Cursors */ |
256 | 0 | size += sizeof(struct VdbeCursor *) * v->nCursor; |
257 | |
|
258 | 0 | for (int i = 0; i < v->nOp; ++i) { |
259 | | /* Estimate size of p4 operand. */ |
260 | 0 | if (v->aOp[i].p4type == P4_NOTUSED) |
261 | 0 | continue; |
262 | 0 | switch (v->aOp[i].p4type) { |
263 | 0 | case P4_DYNAMIC: |
264 | 0 | case P4_STATIC: |
265 | 0 | if (v->aOp[i].opcode == OP_Blob || |
266 | 0 | v->aOp[i].opcode == OP_String) |
267 | 0 | size += v->aOp[i].p1; |
268 | 0 | else if (v->aOp[i].opcode == OP_String8) |
269 | 0 | size += strlen(v->aOp[i].p4.z); |
270 | 0 | break; |
271 | 0 | case P4_BOOL: |
272 | 0 | size += sizeof(v->aOp[i].p4.b); |
273 | 0 | break; |
274 | 0 | case P4_INT32: |
275 | 0 | size += sizeof(v->aOp[i].p4.i); |
276 | 0 | break; |
277 | 0 | case P4_UINT64: |
278 | 0 | case P4_INT64: |
279 | 0 | size += sizeof(*v->aOp[i].p4.pI64); |
280 | 0 | break; |
281 | 0 | case P4_REAL: |
282 | 0 | size += sizeof(*v->aOp[i].p4.pReal); |
283 | 0 | break; |
284 | 0 | case P4_DEC: |
285 | 0 | size += sizeof(*v->aOp[i].p4.dec); |
286 | 0 | break; |
287 | 0 | default: |
288 | 0 | size += sizeof(v->aOp[i].p4.p); |
289 | 0 | break; |
290 | 0 | } |
291 | 0 | } |
292 | 0 | size += strlen(v->zSql); |
293 | 0 | return size; |
294 | 0 | } |
295 | | |
296 | | const char * |
297 | | sql_stmt_query_str(const struct Vdbe *v) |
298 | 0 | { |
299 | 0 | return v->zSql; |
300 | 0 | } |
301 | | |
302 | | /******************************* sql_bind_ ************************** |
303 | | * |
304 | | * Routines used to attach values to wildcards in a compiled SQL statement. |
305 | | */ |
306 | | /* |
307 | | * Unbind the value bound to variable i in virtual machine p. This is the |
308 | | * the same as binding a NULL value to the column. |
309 | | */ |
310 | | static int |
311 | | vdbeUnbind(struct Vdbe *p, int i) |
312 | 0 | { |
313 | 0 | Mem *pVar; |
314 | 0 | assert(p != NULL); |
315 | 0 | assert(p->magic == VDBE_MAGIC_RUN && p->pc < 0); |
316 | 0 | assert(i > 0); |
317 | 0 | if(i > p->nVar) { |
318 | 0 | diag_set(ClientError, ER_SQL_EXECUTE, "The number of "\ |
319 | 0 | "parameters is too large"); |
320 | 0 | return -1; |
321 | 0 | } |
322 | 0 | i--; |
323 | 0 | pVar = &p->aVar[i]; |
324 | 0 | mem_destroy(pVar); |
325 | 0 | return 0; |
326 | 0 | } |
327 | | |
328 | | /** |
329 | | * This function sets type for bound variable. |
330 | | * We should bind types only for variables which occur in |
331 | | * result set of SELECT query. For example: |
332 | | * |
333 | | * SELECT id, ?, ?, a WHERE id = ?; |
334 | | * |
335 | | * In this case we should set types only for two variables. |
336 | | * That one which is situated under WHERE condition - is out |
337 | | * of our interest. |
338 | | * |
339 | | * For named binding parameters we should propagate type |
340 | | * for all occurrences of this parameter - since binding |
341 | | * routine takes place only once for each DISTINCT parameter |
342 | | * from list. |
343 | | * |
344 | | * @param v Current VDBE. |
345 | | * @param position Ordinal position of binding parameter. |
346 | | * @param type String literal representing type of binding param. |
347 | | * @retval 0 on success. |
348 | | */ |
349 | | static int |
350 | | sql_bind_type(struct Vdbe *v, uint32_t position, const char *type) |
351 | 0 | { |
352 | 0 | if (v->res_var_count < position) |
353 | 0 | return 0; |
354 | 0 | int rc = 0; |
355 | 0 | if (vdbe_metadata_set_col_type(v, v->var_pos[position - 1], type) != 0) |
356 | 0 | rc = -1; |
357 | 0 | const char *bind_name = v->metadata[position - 1].name; |
358 | 0 | if (strcmp(bind_name, "?") == 0) |
359 | 0 | return rc; |
360 | 0 | for (uint32_t i = position; i < v->res_var_count; ++i) { |
361 | 0 | if (strcmp(bind_name, v->metadata[i].name) == 0) { |
362 | 0 | if (vdbe_metadata_set_col_type(v, v->var_pos[i], |
363 | 0 | type) != 0) |
364 | 0 | return -1; |
365 | 0 | } |
366 | 0 | } |
367 | 0 | return 0; |
368 | 0 | } |
369 | | |
370 | | void |
371 | | sql_unbind(struct Vdbe *v) |
372 | 0 | { |
373 | 0 | for (int i = 1; i < v->nVar + 1; ++i) { |
374 | 0 | int rc = vdbeUnbind(v, i); |
375 | 0 | assert(rc == 0); |
376 | 0 | (void) rc; |
377 | | /* |
378 | | * We should re-set boolean type - unassigned |
379 | | * binding slots are assumed to contain NULL |
380 | | * value, which has boolean type. |
381 | | */ |
382 | 0 | sql_bind_type(v, i, "boolean"); |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | | void |
387 | | sql_reset_autoinc_id_list(struct Vdbe *v) |
388 | 0 | { |
389 | 0 | stailq_create(&v->autoinc_id_list); |
390 | 0 | } |
391 | | |
392 | | int |
393 | | sql_bind_double(struct Vdbe *p, int i, double rValue) |
394 | 0 | { |
395 | 0 | if (vdbeUnbind(p, i) != 0) |
396 | 0 | return -1; |
397 | 0 | int rc = sql_bind_type(p, i, "numeric"); |
398 | 0 | mem_set_double(&p->aVar[i - 1], rValue); |
399 | 0 | return rc; |
400 | 0 | } |
401 | | |
402 | | int |
403 | | sql_bind_boolean(struct Vdbe *p, int i, bool value) |
404 | 0 | { |
405 | 0 | if (vdbeUnbind(p, i) != 0) |
406 | 0 | return -1; |
407 | 0 | int rc = sql_bind_type(p, i, "boolean"); |
408 | 0 | mem_set_bool(&p->aVar[i - 1], value); |
409 | 0 | return rc; |
410 | 0 | } |
411 | | |
412 | | int |
413 | | sql_bind_int(struct Vdbe *p, int i, int iValue) |
414 | 0 | { |
415 | 0 | return sql_bind_int64(p, i, (i64) iValue); |
416 | 0 | } |
417 | | |
418 | | int |
419 | | sql_bind_int64(struct Vdbe *p, int i, int64_t iValue) |
420 | 0 | { |
421 | 0 | if (vdbeUnbind(p, i) != 0) |
422 | 0 | return -1; |
423 | 0 | int rc = sql_bind_type(p, i, "integer"); |
424 | 0 | mem_set_int(&p->aVar[i - 1], iValue); |
425 | 0 | return rc; |
426 | 0 | } |
427 | | |
428 | | int |
429 | | sql_bind_uint64(struct Vdbe *p, int i, uint64_t value) |
430 | 0 | { |
431 | 0 | if (vdbeUnbind(p, i) != 0) |
432 | 0 | return -1; |
433 | 0 | int rc = sql_bind_type(p, i, "integer"); |
434 | 0 | mem_set_uint(&p->aVar[i - 1], value); |
435 | 0 | return rc; |
436 | 0 | } |
437 | | |
438 | | int |
439 | | sql_bind_null(struct Vdbe *p, int i) |
440 | 0 | { |
441 | 0 | if (vdbeUnbind(p, i) != 0) |
442 | 0 | return -1; |
443 | 0 | return sql_bind_type(p, i, "boolean"); |
444 | 0 | } |
445 | | |
446 | | int |
447 | | sql_bind_ptr(struct Vdbe *p, int i, void *ptr) |
448 | 0 | { |
449 | 0 | int rc = vdbeUnbind(p, i); |
450 | 0 | if (rc == 0) { |
451 | 0 | rc = sql_bind_type(p, i, "varbinary"); |
452 | 0 | mem_set_ptr(&p->aVar[i - 1], ptr); |
453 | 0 | } |
454 | 0 | return rc; |
455 | 0 | } |
456 | | |
457 | | int |
458 | | sql_bind_str_static(struct Vdbe *vdbe, int i, const char *str, uint32_t len) |
459 | 0 | { |
460 | 0 | mem_set_str_static(&vdbe->aVar[i - 1], (char *)str, len); |
461 | 0 | return sql_bind_type(vdbe, i, "text"); |
462 | 0 | } |
463 | | |
464 | | int |
465 | | sql_bind_bin_static(struct Vdbe *vdbe, int i, const char *str, uint32_t size) |
466 | 0 | { |
467 | 0 | mem_set_bin_static(&vdbe->aVar[i - 1], (char *)str, size); |
468 | 0 | return sql_bind_type(vdbe, i, "text"); |
469 | 0 | } |
470 | | |
471 | | int |
472 | | sql_bind_array_static(struct Vdbe *vdbe, int i, const char *str, uint32_t size) |
473 | 0 | { |
474 | 0 | mem_set_array_static(&vdbe->aVar[i - 1], (char *)str, size); |
475 | 0 | return sql_bind_type(vdbe, i, "array"); |
476 | 0 | } |
477 | | |
478 | | int |
479 | | sql_bind_map_static(struct Vdbe *vdbe, int i, const char *str, uint32_t size) |
480 | 0 | { |
481 | 0 | mem_set_map_static(&vdbe->aVar[i - 1], (char *)str, size); |
482 | 0 | return sql_bind_type(vdbe, i, "map"); |
483 | 0 | } |
484 | | |
485 | | int |
486 | | sql_bind_uuid(struct Vdbe *p, int i, const struct tt_uuid *uuid) |
487 | 0 | { |
488 | 0 | if (vdbeUnbind(p, i) != 0 || sql_bind_type(p, i, "uuid") != 0) |
489 | 0 | return -1; |
490 | 0 | mem_set_uuid(&p->aVar[i - 1], uuid); |
491 | 0 | return 0; |
492 | 0 | } |
493 | | |
494 | | int |
495 | | sql_bind_dec(struct Vdbe *p, int i, const decimal_t *dec) |
496 | 0 | { |
497 | 0 | if (vdbeUnbind(p, i) != 0 || sql_bind_type(p, i, "decimal") != 0) |
498 | 0 | return -1; |
499 | 0 | mem_set_dec(&p->aVar[i - 1], dec); |
500 | 0 | return 0; |
501 | 0 | } |
502 | | |
503 | | int |
504 | | sql_bind_datetime(struct Vdbe *p, int i, const struct datetime *dt) |
505 | 0 | { |
506 | 0 | if (vdbeUnbind(p, i) != 0 || sql_bind_type(p, i, "datetime") != 0) |
507 | 0 | return -1; |
508 | 0 | mem_set_datetime(&p->aVar[i - 1], dt); |
509 | 0 | return 0; |
510 | 0 | } |
511 | | |
512 | | int |
513 | | sql_bind_interval(struct Vdbe *p, int i, const struct interval *itv) |
514 | 0 | { |
515 | 0 | if (vdbeUnbind(p, i) != 0 || sql_bind_type(p, i, "interval") != 0) |
516 | 0 | return -1; |
517 | 0 | mem_set_interval(&p->aVar[i - 1], itv); |
518 | 0 | return 0; |
519 | 0 | } |
520 | | |
521 | | int |
522 | | sql_bind_parameter_count(const struct Vdbe *p) |
523 | 0 | { |
524 | 0 | return p->nVar; |
525 | 0 | } |
526 | | |
527 | | const char * |
528 | | sql_bind_parameter_name(const struct Vdbe *p, int i) |
529 | 0 | { |
530 | 0 | if (p == NULL) |
531 | 0 | return NULL; |
532 | 0 | return sqlVListNumToName(p->pVList, i+1); |
533 | 0 | } |
534 | | |
535 | | /* |
536 | | * Given a wildcard parameter name, return the index of the variable |
537 | | * with that name. If there is no variable with the given name, |
538 | | * return 0. |
539 | | */ |
540 | | int |
541 | | sqlVdbeParameterIndex(Vdbe * p, const char *zName, int nName) |
542 | 0 | { |
543 | 0 | if (p == 0 || zName == 0) |
544 | 0 | return 0; |
545 | 0 | return sqlVListNameToNum(p->pVList, zName, nName); |
546 | 0 | } |
547 | | |
548 | | int |
549 | | sql_bind_parameter_lindex(struct Vdbe *v, const char *zName, int nName) |
550 | 0 | { |
551 | 0 | return sqlVdbeParameterIndex(v, zName, nName); |
552 | 0 | } |
553 | | |
554 | | int |
555 | | sqlTransferBindings(struct Vdbe *pFrom, struct Vdbe *pTo) |
556 | 0 | { |
557 | 0 | int i; |
558 | 0 | assert(pTo->nVar == pFrom->nVar); |
559 | 0 | for (i = 0; i < pFrom->nVar; i++) { |
560 | 0 | mem_move(&pTo->aVar[i], &pFrom->aVar[i]); |
561 | 0 | } |
562 | 0 | return 0; |
563 | 0 | } |
564 | | |
565 | | int |
566 | | sql_stmt_busy(const struct Vdbe *v) |
567 | 8.64k | { |
568 | 8.64k | assert(v != NULL); |
569 | 8.64k | return v->magic == VDBE_MAGIC_RUN && v->pc >= 0; |
570 | 8.64k | } |
571 | | |
572 | | const char * |
573 | | sql_sql(struct Vdbe *p) |
574 | 0 | { |
575 | 0 | return p ? p->zSql : 0; |
576 | 0 | } |