Coverage Report

Created: 2024-04-24 06:23

/src/tarantool/src/box/sql/prepare.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
 * This file contains the implementation of the sql_prepare()
34
 * interface, and routines that contribute to loading the database schema
35
 * from disk.
36
 */
37
#include "sqlInt.h"
38
#include "tarantoolInt.h"
39
#include "box/space.h"
40
#include "box/session.h"
41
42
int
43
sql_stmt_compile(const char *zSql, int nBytes, struct Vdbe *pReprepare,
44
     struct Vdbe **ppStmt, const char **pzTail)
45
7.28k
{
46
7.28k
  int rc = 0; /* Result code */
47
7.28k
  Parse sParse;   /* Parsing context */
48
7.28k
  sql_parser_create(&sParse, current_session()->sql_flags);
49
7.28k
  sParse.pReprepare = pReprepare;
50
7.28k
  *ppStmt = NULL;
51
52
  /* Check to verify that it is possible to get a read lock on all
53
   * database schemas.  The inability to get a read lock indicates that
54
   * some other database connection is holding a write-lock, which in
55
   * turn means that the other connection has made uncommitted changes
56
   * to the schema.
57
   *
58
   * Were we to proceed and prepare the statement against the uncommitted
59
   * schema changes and if those schema changes are subsequently rolled
60
   * back and different changes are made in their place, then when this
61
   * prepared statement goes to run the schema cookie would fail to detect
62
   * the schema change.  Disaster would follow.
63
   *
64
   * Note that setting READ_UNCOMMITTED overrides most lock detection,
65
   * but it does *not* override schema lock detection, so this all still
66
   * works even if READ_UNCOMMITTED is set.
67
   */
68
7.28k
  if (nBytes >= 0 && (nBytes == 0 || zSql[nBytes - 1] != 0)) {
69
7.28k
    char *zSqlCopy;
70
7.28k
    int mxLen = SQL_MAX_SQL_LENGTH;
71
7.28k
    if (nBytes > mxLen) {
72
0
      diag_set(ClientError, ER_SQL_PARSER_LIMIT,
73
0
         "SQL command length", nBytes, mxLen);
74
0
      rc = -1;
75
0
      goto end_prepare;
76
0
    }
77
7.28k
    zSqlCopy = sql_xstrndup(zSql, nBytes);
78
7.28k
    if (zSqlCopy) {
79
7.28k
      sqlRunParser(&sParse, zSqlCopy);
80
7.28k
      sParse.zTail = &zSql[sParse.zTail - zSqlCopy];
81
7.28k
      sql_xfree(zSqlCopy);
82
7.28k
    } else {
83
0
      sParse.zTail = &zSql[nBytes];
84
0
    }
85
7.28k
  } else {
86
0
    sqlRunParser(&sParse, zSql);
87
0
  }
88
7.28k
  assert(0 == sParse.nQueryLoop || sParse.is_aborted);
89
90
7.28k
  if (pzTail) {
91
0
    *pzTail = sParse.zTail;
92
0
  }
93
7.28k
  if (sParse.is_aborted)
94
2.57k
    rc = -1;
95
96
7.28k
  if (rc == 0 && sParse.pVdbe != NULL && sParse.explain) {
97
0
    static const char *const azColName[] = {
98
0
      /*  0 */ "addr",
99
0
      /*  1 */ "integer",
100
0
      /*  2 */ "opcode",
101
0
      /*  3 */ "text",
102
0
      /*  4 */ "p1",
103
0
      /*  5 */ "integer",
104
0
      /*  6 */ "p2",
105
0
      /*  7 */ "integer",
106
0
      /*  8 */ "p3",
107
0
      /*  9 */ "integer",
108
0
      /* 10 */ "p4",
109
0
      /* 11 */ "text",
110
0
      /* 12 */ "p5",
111
0
      /* 13 */ "text",
112
0
      /* 14 */ "comment",
113
0
      /* 15 */ "text",
114
0
      /* 16 */ "selectid",
115
0
      /* 17 */ "integer",
116
0
      /* 18 */ "order",
117
0
      /* 19 */ "integer",
118
0
      /* 20 */ "from",
119
0
      /* 21 */ "integer",
120
0
      /* 22 */ "detail",
121
0
      /* 23 */ "text",
122
0
    };
123
124
0
    int name_first, name_count;
125
0
    if (sParse.explain == 2) {
126
0
      name_first = 16;
127
0
      name_count = 4;
128
0
    } else {
129
0
      name_first = 0;
130
0
      name_count = 8;
131
0
    }
132
0
    sqlVdbeSetNumCols(sParse.pVdbe, name_count);
133
0
    for (int i = 0; i < name_count; i++) {
134
0
      int name_index = 2 * i + name_first;
135
0
      vdbe_metadata_set_col_name(sParse.pVdbe, i,
136
0
               azColName[name_index]);
137
0
      vdbe_metadata_set_col_type(sParse.pVdbe, i,
138
0
               azColName[name_index + 1]);
139
0
    }
140
0
  }
141
142
7.28k
  if (sql_get()->init.busy == 0) {
143
7.28k
    Vdbe *pVdbe = sParse.pVdbe;
144
7.28k
    sqlVdbeSetSql(pVdbe, zSql, (int)(sParse.zTail - zSql));
145
7.28k
  }
146
7.28k
  if (sParse.pVdbe != NULL && rc != 0) {
147
0
    sqlVdbeFinalize(sParse.pVdbe);
148
0
    assert(!(*ppStmt));
149
7.28k
  } else {
150
7.28k
    *ppStmt = sParse.pVdbe;
151
7.28k
  }
152
153
  /* Delete any TriggerPrg structures allocated while parsing this statement. */
154
7.28k
  while (sParse.pTriggerPrg) {
155
0
    TriggerPrg *pT = sParse.pTriggerPrg;
156
0
    sParse.pTriggerPrg = pT->pNext;
157
0
    sql_xfree(pT);
158
0
  }
159
160
7.28k
 end_prepare:
161
162
7.28k
  sql_parser_destroy(&sParse);
163
7.28k
  return rc;
164
7.28k
}
165
166
/*
167
 * Rerun the compilation of a statement after a schema change.
168
 */
169
int
170
sqlReprepare(Vdbe * p)
171
0
{
172
0
  struct Vdbe *pNew;
173
0
  const char *zSql;
174
175
0
  zSql = sql_sql(p);
176
0
  assert(zSql != 0);
177
0
  if (sql_stmt_compile(zSql, -1, p, &pNew, 0) != 0) {
178
0
    assert(pNew == 0);
179
0
    return -1;
180
0
  }
181
0
  assert(pNew != 0);
182
0
  sqlVdbeSwap(pNew, p);
183
0
  sqlTransferBindings(pNew, p);
184
0
  sqlVdbeResetStepResult(pNew);
185
0
  sqlVdbeFinalize(pNew);
186
0
  return 0;
187
0
}
188
189
void
190
sql_parser_create(struct Parse *parser, uint32_t sql_flags)
191
7.28k
{
192
7.28k
  memset(parser, 0, sizeof(struct Parse));
193
7.28k
  parser->sql_flags = sql_flags;
194
7.28k
  parser->line_count = 1;
195
7.28k
  parser->line_pos = 1;
196
7.28k
  parser->has_autoinc = false;
197
7.28k
  region_create(&parser->region, &cord()->slabc);
198
7.28k
}
199
200
void
201
sql_parser_destroy(Parse *parser)
202
7.28k
{
203
7.28k
  assert(parser != NULL);
204
0
  assert(!parser->parse_only || parser->pVdbe == NULL);
205
0
  sql_xfree(parser->default_funcs);
206
7.28k
  sql_xfree(parser->aLabel);
207
7.28k
  sql_expr_list_delete(parser->pConstExpr);
208
7.28k
  struct create_fk_constraint_parse_def *create_fk_constraint_parse_def =
209
7.28k
    &parser->create_fk_constraint_parse_def;
210
7.28k
  create_fk_constraint_parse_def_destroy(create_fk_constraint_parse_def);
211
7.28k
  assert(sql_get()->lookaside.bDisable >= parser->disableLookaside);
212
0
  sql_get()->lookaside.bDisable -= parser->disableLookaside;
213
7.28k
  parser->disableLookaside = 0;
214
7.28k
  switch (parser->parsed_ast_type) {
215
0
  case AST_TYPE_SELECT:
216
0
    sql_select_delete(parser->parsed_ast.select);
217
0
    break;
218
0
  case AST_TYPE_EXPR:
219
0
    sql_expr_delete(parser->parsed_ast.expr);
220
0
    break;
221
0
  case AST_TYPE_TRIGGER:
222
0
    sql_trigger_delete(parser->parsed_ast.trigger);
223
0
    break;
224
7.28k
  default:
225
7.28k
    assert(parser->parsed_ast_type == AST_TYPE_UNDEFINED);
226
7.28k
  }
227
7.28k
  region_destroy(&parser->region);
228
7.28k
}