1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | #include "monetdb_config.h" |
10 | #include "sql_parser.h" |
11 | #include "sql_symbol.h" |
12 | #include "sql_semantic.h" |
13 | #include "sql_env.h" |
14 | #include "sql_privileges.h" |
15 | #include "sql_string.h" |
16 | #include "sql_atom.h" |
17 | |
18 | #include <unistd.h> |
19 | #include <string.h> |
20 | #include <ctype.h> |
21 | |
22 | #include "rel_semantic.h" |
23 | #include "rel_unnest.h" |
24 | #include "rel_optimizer.h" |
25 | |
26 | /* |
27 | * For debugging purposes we need to be able to convert sql-tokens to |
28 | * a string representation. |
29 | * |
30 | * !SQL ERROR <sqlerrno> : <details> |
31 | * !SQL DEBUG <details> |
32 | * !SQL WARNING <details> |
33 | * !SQL <informative message, reserved for ...rows affected> |
34 | */ |
35 | |
36 | atom * |
37 | sql_add_arg(mvc *sql, atom *v) |
38 | { |
39 | atom** new_args; |
40 | int next_size = sql->argmax; |
41 | if (sql->argc == next_size) { |
42 | next_size *= 2; |
43 | new_args = RENEW_ARRAY(atom*,sql->args,next_size); |
44 | if(new_args) { |
45 | sql->args = new_args; |
46 | sql->argmax = next_size; |
47 | } else |
48 | return NULL; |
49 | } |
50 | sql->args[sql->argc++] = v; |
51 | return v; |
52 | } |
53 | |
54 | atom * |
55 | sql_set_arg(mvc *sql, int nr, atom *v) |
56 | { |
57 | atom** new_args; |
58 | int next_size = sql->argmax; |
59 | if (nr >= next_size) { |
60 | next_size *= 2; |
61 | if (nr >= next_size) |
62 | next_size = nr*2; |
63 | new_args = RENEW_ARRAY(atom*,sql->args,next_size); |
64 | if(new_args) { |
65 | sql->args = new_args; |
66 | sql->argmax = next_size; |
67 | } else |
68 | return NULL; |
69 | } |
70 | if (sql->argc < nr+1) |
71 | sql->argc = nr+1; |
72 | sql->args[nr] = v; |
73 | return v; |
74 | } |
75 | |
76 | void |
77 | sql_add_param(mvc *sql, const char *name, sql_subtype *st) |
78 | { |
79 | sql_arg *a = SA_ZNEW(sql->sa, sql_arg); |
80 | |
81 | if (name) |
82 | a->name = sa_strdup(sql->sa, name); |
83 | if (st && st->type) |
84 | a->type = *st; |
85 | a->inout = ARG_IN; |
86 | if (name && strcmp(name, "*" ) == 0) |
87 | a->type = *sql_bind_localtype("int" ); |
88 | if (!sql->params) |
89 | sql->params = sa_list(sql->sa); |
90 | list_append(sql->params, a); |
91 | } |
92 | |
93 | sql_arg * |
94 | sql_bind_param(mvc *sql, const char *name) |
95 | { |
96 | node *n; |
97 | |
98 | if (sql->params) { |
99 | for (n = sql->params->h; n; n = n->next) { |
100 | sql_arg *a = n->data; |
101 | |
102 | if (a->name && strcmp(a->name, name) == 0) |
103 | return a; |
104 | } |
105 | } |
106 | return NULL; |
107 | } |
108 | |
109 | static sql_arg * |
110 | sql_bind_paramnr(mvc *sql, int nr) |
111 | { |
112 | int i=0; |
113 | node *n; |
114 | |
115 | if (sql->params && nr < list_length(sql->params)) { |
116 | for (n = sql->params->h, i=0; n && i<nr; n = n->next, i++) |
117 | ; |
118 | |
119 | if (n) |
120 | return n->data; |
121 | } |
122 | return NULL; |
123 | } |
124 | |
125 | atom * |
126 | sql_bind_arg(mvc *sql, int nr) |
127 | { |
128 | if (nr < sql->argc) |
129 | return sql->args[nr]; |
130 | return NULL; |
131 | } |
132 | |
133 | void |
134 | sql_destroy_params(mvc *sql) |
135 | { |
136 | sql->params = NULL; |
137 | } |
138 | |
139 | void |
140 | sql_destroy_args(mvc *sql) |
141 | { |
142 | sql->argc = 0; |
143 | } |
144 | |
145 | |
146 | sql_schema * |
147 | cur_schema(mvc *sql) |
148 | { |
149 | return sql->session->schema; |
150 | } |
151 | |
152 | sql_schema * |
153 | tmp_schema(mvc *sql) |
154 | { |
155 | return mvc_bind_schema(sql, "tmp" ); |
156 | } |
157 | |
158 | char * |
159 | qname_schema(dlist *qname) |
160 | { |
161 | assert(qname && qname->h); |
162 | |
163 | if (dlist_length(qname) == 2) { |
164 | return qname->h->data.sval; |
165 | } else if (dlist_length(qname) == 3) { |
166 | return qname->h->next->data.sval; |
167 | } |
168 | return NULL; |
169 | } |
170 | |
171 | char * |
172 | qname_table(dlist *qname) |
173 | { |
174 | assert(qname && qname->h); |
175 | |
176 | if (dlist_length(qname) == 1) { |
177 | return qname->h->data.sval; |
178 | } else if (dlist_length(qname) == 2) { |
179 | return qname->h->next->data.sval; |
180 | } else if (dlist_length(qname) == 3) { |
181 | return qname->h->next->next->data.sval; |
182 | } |
183 | return "unknown" ; |
184 | } |
185 | |
186 | char * |
187 | qname_catalog(dlist *qname) |
188 | { |
189 | assert(qname && qname->h); |
190 | |
191 | if (dlist_length(qname) == 3) { |
192 | return qname->h->data.sval; |
193 | } |
194 | |
195 | return NULL; |
196 | } |
197 | |
198 | |
199 | int |
200 | set_type_param(mvc *sql, sql_subtype *type, int nr) |
201 | { |
202 | sql_arg *a = sql_bind_paramnr(sql, nr); |
203 | |
204 | if (!a) |
205 | return -1; |
206 | a->type = *type; |
207 | return 0; |
208 | } |
209 | |
210 | sql_subtype * |
211 | supertype(sql_subtype *super, sql_subtype *r, sql_subtype *i) |
212 | { |
213 | /* first find super type */ |
214 | char *tpe = r->type->sqlname; |
215 | int radix = r->type->radix; |
216 | int digits = 0; |
217 | int idigits = i->digits; |
218 | int rdigits = r->digits; |
219 | unsigned int scale = sql_max(i->scale, r->scale); |
220 | sql_subtype lsuper; |
221 | |
222 | lsuper = *r; |
223 | if (i->type->base.id > r->type->base.id || |
224 | (EC_VARCHAR(i->type->eclass) && !EC_VARCHAR(r->type->eclass))) { |
225 | lsuper = *i; |
226 | radix = i->type->radix; |
227 | tpe = i->type->sqlname; |
228 | } |
229 | if (!lsuper.type->localtype) |
230 | tpe = "smallint" ; |
231 | /* |
232 | * In case of different radix we should change one. |
233 | */ |
234 | if (i->type->radix != r->type->radix) { |
235 | if (radix == 10 || radix == 0 /* strings */) { |
236 | /* change to radix 10 */ |
237 | if (i->type->radix == 2) |
238 | idigits = bits2digits(idigits); |
239 | if (r->type->radix == 2) |
240 | rdigits = bits2digits(rdigits); |
241 | } else if (radix == 2) { /* change to radix 2 */ |
242 | if (i->type->radix == 10) |
243 | idigits = digits2bits(idigits); |
244 | if (r->type->radix == 10) |
245 | rdigits = digits2bits(rdigits); |
246 | } |
247 | } |
248 | /* handle OID horror */ |
249 | if (i->type->radix == r->type->radix && i->type->base.id < r->type->base.id && strcmp(i->type->sqlname, "oid" ) == 0) |
250 | tpe = i->type->sqlname; |
251 | if (scale == 0 && (idigits == 0 || rdigits == 0)) { |
252 | sql_find_subtype(&lsuper, tpe, 0, 0); |
253 | } else { |
254 | digits = sql_max(idigits - i->scale, rdigits - r->scale); |
255 | sql_find_subtype(&lsuper, tpe, digits+scale, scale); |
256 | } |
257 | *super = lsuper; |
258 | return super; |
259 | } |
260 | |
261 | char * toUpperCopy(char *dest, const char *src) |
262 | { |
263 | size_t i, len; |
264 | |
265 | if (src == NULL) { |
266 | *dest = '\0'; |
267 | return(dest); |
268 | } |
269 | |
270 | len = _strlen(src); |
271 | for (i = 0; i < len; i++) |
272 | dest[i] = (char)toupper((int)src[i]); |
273 | |
274 | dest[i] = '\0'; |
275 | return(dest); |
276 | } |
277 | |
278 | char *dlist2string(mvc *sql, dlist *l, int expression, char **err) |
279 | { |
280 | char *b = NULL; |
281 | dnode *n; |
282 | |
283 | for (n=l->h; n; n = n->next) { |
284 | char *s = NULL; |
285 | |
286 | if (n->type == type_string && n->data.sval) |
287 | s = _STRDUP(n->data.sval); |
288 | else if (n->type == type_symbol) |
289 | s = symbol2string(sql, n->data.sym, expression, err); |
290 | |
291 | if (!s) { |
292 | _DELETE(b); |
293 | return NULL; |
294 | } |
295 | if (b) { |
296 | char *o = NEW_ARRAY(char, strlen(b) + strlen(s) + 2); |
297 | if (o) |
298 | stpcpy(stpcpy(stpcpy(o, b), "." ), s); |
299 | _DELETE(b); |
300 | _DELETE(s); |
301 | b = o; |
302 | if (b == NULL) |
303 | return NULL; |
304 | } else { |
305 | b = s; |
306 | } |
307 | } |
308 | return b; |
309 | } |
310 | |
311 | char *symbol2string(mvc *sql, symbol *se, int expression, char **err) /**/ |
312 | { |
313 | int len = 0; |
314 | char buf[BUFSIZ]; |
315 | |
316 | buf[0] = 0; |
317 | switch (se->token) { |
318 | case SQL_NOP: { |
319 | dnode *lst = se->data.lval->h; |
320 | dnode *ops = lst->next->data.lval->h; |
321 | char *op = qname_fname(lst->data.lval); |
322 | |
323 | len = snprintf( buf+len, BUFSIZ-len, "%s(" , op); |
324 | for (; ops; ops = ops->next) { |
325 | char *tmp = symbol2string(sql, ops->data.sym, expression, err); |
326 | if (tmp == NULL) |
327 | return NULL; |
328 | len = snprintf( buf+len, BUFSIZ-len, "%s%s" , |
329 | tmp, |
330 | (ops->next)?"," :"" ); |
331 | _DELETE(tmp); |
332 | } |
333 | len = snprintf( buf+len, BUFSIZ-len, ")" ); |
334 | } break; |
335 | case SQL_BINOP: { |
336 | dnode *lst = se->data.lval->h; |
337 | char *op = qname_fname(lst->data.lval); |
338 | char *l; |
339 | char *r; |
340 | l = symbol2string(sql, lst->next->data.sym, expression, err); |
341 | if (l == NULL) |
342 | return NULL; |
343 | r = symbol2string(sql, lst->next->next->data.sym, expression, err); |
344 | if (r == NULL) { |
345 | _DELETE(l); |
346 | return NULL; |
347 | } |
348 | len = snprintf( buf+len, BUFSIZ-len, "%s(%s,%s)" , op, l, r); |
349 | _DELETE(l); |
350 | _DELETE(r); |
351 | } break; |
352 | case SQL_OP: { |
353 | dnode *lst = se->data.lval->h; |
354 | char *op = qname_fname(lst->data.lval); |
355 | len = snprintf( buf+len, BUFSIZ-len, "%s()" , op ); |
356 | } break; |
357 | case SQL_UNOP: { |
358 | dnode *lst = se->data.lval->h; |
359 | char *op = qname_fname(lst->data.lval); |
360 | char *l = symbol2string(sql, lst->next->data.sym, expression, err); |
361 | if (l == NULL) |
362 | return NULL; |
363 | len = snprintf( buf+len, BUFSIZ-len, "%s(%s)" , op, l); |
364 | _DELETE(l); |
365 | break; |
366 | } |
367 | case SQL_PARAMETER: |
368 | strcpy(buf,"?" ); |
369 | break; |
370 | case SQL_NULL: |
371 | strcpy(buf,"NULL" ); |
372 | break; |
373 | case SQL_ATOM:{ |
374 | AtomNode *an = (AtomNode *) se; |
375 | if (an && an->a) |
376 | return atom2sql(an->a); |
377 | else |
378 | strcpy(buf,"NULL" ); |
379 | break; |
380 | } |
381 | case SQL_NEXT:{ |
382 | const char *seq = qname_table(se->data.lval); |
383 | const char *sname = qname_schema(se->data.lval); |
384 | const char *s; |
385 | |
386 | if (!sname) |
387 | sname = sql->session->schema->base.name; |
388 | s = sql_escape_ident(seq); |
389 | if(!s) |
390 | return NULL; |
391 | len = snprintf( buf+len, BUFSIZ-len, "next value for \"%s\".\"%s\"" , sname, s); |
392 | c_delete(s); |
393 | } break; |
394 | case SQL_IDENT: |
395 | case SQL_COLUMN: { |
396 | /* can only be variables */ |
397 | dlist *l = se->data.lval; |
398 | assert(l->h->type != type_lng); |
399 | if (dlist_length(l) == 1 && l->h->type == type_int) { |
400 | atom *a = sql_bind_arg(sql, l->h->data.i_val); |
401 | return atom2sql(a); |
402 | } else if (expression && dlist_length(l) == 1 && l->h->type == type_string) { |
403 | /* when compiling an expression, a column of a table might be present in the symbol, so we need this case */ |
404 | return _STRDUP(l->h->data.sval); |
405 | } else if (expression && dlist_length(l) == 2 && l->h->type == type_string && l->h->next->type == type_string) { |
406 | char *first = l->h->data.sval; |
407 | char *second = l->h->next->data.sval; |
408 | char *res; |
409 | |
410 | if(!first || !second) { |
411 | return NULL; |
412 | } |
413 | res = NEW_ARRAY(char, strlen(first) + strlen(second) + 2); |
414 | if (res) { |
415 | stpcpy(stpcpy(stpcpy(res, first), "." ), second); |
416 | } |
417 | return res; |
418 | } else { |
419 | char *e = dlist2string(sql, l, expression, err); |
420 | if (e) |
421 | *err = e; |
422 | } |
423 | return NULL; |
424 | } |
425 | case SQL_CAST: { |
426 | dlist *dl = se->data.lval; |
427 | char *val; |
428 | char *tpe; |
429 | |
430 | val = symbol2string(sql, dl->h->data.sym, expression, err); |
431 | if (val == NULL) |
432 | return NULL; |
433 | tpe = subtype2string(&dl->h->next->data.typeval); |
434 | if (tpe == NULL) { |
435 | _DELETE(val); |
436 | return NULL; |
437 | } |
438 | len = snprintf( buf+len, BUFSIZ-len, "cast ( %s as %s )" , |
439 | val, tpe); |
440 | _DELETE(val); |
441 | _DELETE(tpe); |
442 | break; |
443 | } |
444 | case SQL_AGGR: |
445 | case SQL_SELECT: |
446 | case SQL_CASE: |
447 | case SQL_COALESCE: |
448 | case SQL_NULLIF: |
449 | default: |
450 | return NULL; |
451 | } |
452 | return _STRDUP(buf); |
453 | } |
454 | |