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 | /* |
10 | * authors M Kersten, N Nes |
11 | * SQL support implementation |
12 | * This module contains the wrappers around the SQL |
13 | * multi-version-catalog and support routines copied |
14 | * from the Version 4 code base. |
15 | */ |
16 | #include "monetdb_config.h" |
17 | #include "sql.h" |
18 | #include "streams.h" |
19 | #include "sql_result.h" |
20 | #include "sql_gencode.h" |
21 | #include "sql_storage.h" |
22 | #include "sql_scenario.h" |
23 | #include "store_sequence.h" |
24 | #include "sql_optimizer.h" |
25 | #include "sql_datetime.h" |
26 | #include "sql_partition.h" |
27 | #include "rel_unnest.h" |
28 | #include "rel_optimizer.h" |
29 | #include "rel_partition.h" |
30 | #include "rel_distribute.h" |
31 | #include "rel_select.h" |
32 | #include "rel_rel.h" |
33 | #include "rel_exp.h" |
34 | #include "rel_dump.h" |
35 | #include "rel_bin.h" |
36 | #include "bbp.h" |
37 | #include "opt_pipes.h" |
38 | #include "orderidx.h" |
39 | #include "clients.h" |
40 | #include "mal_instruction.h" |
41 | #include "mal_resource.h" |
42 | #include "mal_authorize.h" |
43 | #include "gdk_cand.h" |
44 | |
45 | static int |
46 | rel_is_table(sql_rel *rel) |
47 | { |
48 | if (!rel || is_base(rel->op)) |
49 | return 1; |
50 | return 0; |
51 | } |
52 | |
53 | static int |
54 | exp_is_point_select(sql_exp *e) |
55 | { |
56 | if (!e) |
57 | return 1; |
58 | if (e->type == e_cmp && !e->f && e->flag == (int) cmp_equal) { |
59 | sql_exp *r = e->r; |
60 | sql_exp *l = e->l; |
61 | |
62 | if (!is_func(l->type) && r->card <= CARD_AGGR) |
63 | return 1; |
64 | } |
65 | return 0; |
66 | } |
67 | |
68 | static int |
69 | rel_no_mitosis(sql_rel *rel) |
70 | { |
71 | int is_point = 0; |
72 | |
73 | if (!rel || is_basetable(rel->op)) |
74 | return 1; |
75 | if (is_topn(rel->op) || rel->op == op_project) |
76 | return rel_no_mitosis(rel->l); |
77 | if (is_modify(rel->op) && rel->card <= CARD_AGGR) |
78 | return rel_no_mitosis(rel->r); |
79 | if (is_select(rel->op) && rel_is_table(rel->l) && rel->exps) { |
80 | is_point = 0; |
81 | /* just one point expression makes this a point query */ |
82 | if (rel->exps->h) |
83 | if (exp_is_point_select(rel->exps->h->data)) |
84 | is_point = 1; |
85 | } |
86 | return is_point; |
87 | } |
88 | |
89 | static int |
90 | rel_need_distinct_query(sql_rel *rel) |
91 | { |
92 | int need_distinct = 0; |
93 | |
94 | while (!need_distinct && rel && is_project(rel->op) && !is_groupby(rel->op)) |
95 | rel = rel->l; |
96 | if (!need_distinct && rel && is_groupby(rel->op) && rel->exps) { |
97 | node *n, *m; |
98 | for (n = rel->exps->h; n && !need_distinct; n = n->next) { |
99 | sql_exp *e = n->data; |
100 | if (e->type == e_aggr) { |
101 | list *l = e->l; |
102 | |
103 | if (l) |
104 | for (m = l->h; m && !need_distinct; m = m->next) { |
105 | sql_exp *a = m->data; |
106 | |
107 | if (need_distinct(a)) |
108 | need_distinct = 1; |
109 | } |
110 | } |
111 | } |
112 | } |
113 | return need_distinct; |
114 | } |
115 | |
116 | sql_rel * |
117 | sql_symbol2relation(mvc *c, symbol *sym) |
118 | { |
119 | sql_rel *r; |
120 | sql_query *query = query_create(c); |
121 | |
122 | r = rel_semantic(query, sym); |
123 | if (r) |
124 | r = rel_unnest(c, r); |
125 | if (r) |
126 | r = rel_optimizer(c, r, 1); |
127 | if (r) |
128 | r = rel_distribute(c, r); |
129 | if (r) |
130 | r = rel_partition(c, r); |
131 | if (r && (rel_no_mitosis(r) || rel_need_distinct_query(r))) |
132 | c->no_mitosis = 1; |
133 | return r; |
134 | } |
135 | |
136 | /* |
137 | * After the SQL statement has been executed, its data structures |
138 | * should be garbage collected. For successful actions we have to finish |
139 | * the transaction as well, e.g. commit or rollback. |
140 | */ |
141 | int |
142 | sqlcleanup(mvc *c, int err) |
143 | { |
144 | sql_destroy_params(c); |
145 | sql_destroy_args(c); |
146 | |
147 | if ((c->emod & mod_locked) == mod_locked) { |
148 | /* here we should commit the transaction */ |
149 | if (!err) { |
150 | sql_trans_commit(c->session->tr); |
151 | /* write changes to disk */ |
152 | sql_trans_end(c->session); |
153 | store_apply_deltas(true); |
154 | sql_trans_begin(c->session); |
155 | } |
156 | store_unlock(); |
157 | c->emod = 0; |
158 | } |
159 | /* some statements dynamically disable caching */ |
160 | c->sym = NULL; |
161 | if (c->sa) |
162 | c->sa = sa_reset(c->sa); |
163 | if (err >0) |
164 | c->session->status = -err; |
165 | if (err <0) |
166 | c->session->status = err; |
167 | c->label = 0; |
168 | c->no_mitosis = 0; |
169 | scanner_query_processed(&(c->scanner)); |
170 | return err; |
171 | } |
172 | |
173 | /* |
174 | * The internal administration of the SQL compilation and execution state |
175 | * is administered by a state descriptor accessible in each phase. |
176 | * Failure to find the state descriptor aborts the session. |
177 | */ |
178 | |
179 | str |
180 | checkSQLContext(Client cntxt) |
181 | { |
182 | backend *be; |
183 | |
184 | if (cntxt == NULL) |
185 | throw(SQL, "mvc" , SQLSTATE(42005) "No client record" ); |
186 | if (cntxt->sqlcontext == NULL) |
187 | throw(SQL, "mvc" , SQLSTATE(42006) "SQL module not initialized" ); |
188 | be = (backend *) cntxt->sqlcontext; |
189 | if (be->mvc == NULL) |
190 | throw(SQL, "mvc" , SQLSTATE(42006) "SQL module not initialized, mvc struct missing" ); |
191 | return MAL_SUCCEED; |
192 | } |
193 | |
194 | str |
195 | getSQLContext(Client cntxt, MalBlkPtr mb, mvc **c, backend **b) |
196 | { |
197 | backend *be; |
198 | (void) mb; |
199 | str msg; |
200 | |
201 | if ((msg = checkSQLContext(cntxt)) != MAL_SUCCEED) |
202 | return msg; |
203 | be = (backend *) cntxt->sqlcontext; |
204 | if (c) |
205 | *c = be->mvc; |
206 | if (b) |
207 | *b = be; |
208 | return MAL_SUCCEED; |
209 | } |
210 | |
211 | str |
212 | SQLmvc(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
213 | { |
214 | mvc *sql = NULL; |
215 | str msg; |
216 | int *res = getArgReference_int(stk, pci, 0); |
217 | |
218 | if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL) |
219 | return msg; |
220 | if ((msg = checkSQLContext(cntxt)) != NULL) |
221 | return msg; |
222 | *res = 0; |
223 | return MAL_SUCCEED; |
224 | } |
225 | |
226 | str |
227 | SQLcommit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
228 | { |
229 | mvc *sql = NULL; |
230 | str msg; |
231 | (void) stk; |
232 | (void) pci; |
233 | |
234 | if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL) |
235 | return msg; |
236 | if ((msg = checkSQLContext(cntxt)) != NULL) |
237 | return msg; |
238 | |
239 | if (sql->session->auto_commit != 0) |
240 | throw(SQL, "sql.trans" , SQLSTATE(2DM30) "COMMIT not allowed in auto commit mode" ); |
241 | return mvc_commit(sql, 0, 0, false); |
242 | } |
243 | |
244 | str |
245 | SQLabort(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
246 | { |
247 | mvc *sql = NULL; |
248 | str msg; |
249 | (void) stk; |
250 | (void) pci; |
251 | |
252 | if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL) |
253 | return msg; |
254 | if ((msg = checkSQLContext(cntxt)) != NULL) |
255 | return msg; |
256 | |
257 | if (sql->session->tr->active) { |
258 | msg = mvc_rollback(sql, 0, NULL, false); |
259 | } |
260 | return msg; |
261 | } |
262 | |
263 | str |
264 | SQLshutdown_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
265 | { |
266 | str msg; |
267 | |
268 | if ((msg = CLTshutdown(cntxt, mb, stk, pci)) == MAL_SUCCEED) { |
269 | /* administer the shutdown in the system log*/ |
270 | fprintf(stderr, "#Shutdown:%s\n" , *getArgReference_str(stk, pci, 0)); |
271 | } |
272 | return msg; |
273 | } |
274 | |
275 | str |
276 | create_table_or_view(mvc *sql, char* sname, char *tname, sql_table *t, int temp) |
277 | { |
278 | sql_allocator *osa; |
279 | sql_schema *s = mvc_bind_schema(sql, sname); |
280 | sql_table *nt = NULL; |
281 | node *n; |
282 | int check = 0; |
283 | |
284 | if (STORE_READONLY) |
285 | return sql_error(sql, 06, SQLSTATE(25006) "schema statements cannot be executed on a readonly database." ); |
286 | |
287 | if (!s) |
288 | return sql_message(SQLSTATE(3F000) "CREATE %s: schema '%s' doesn't exist" , (t->query) ? "TABLE" : "VIEW" , sname); |
289 | if (mvc_bind_table(sql, s, t->base.name)) { |
290 | char *cd = (temp == SQL_DECLARED_TABLE) ? "DECLARE" : "CREATE" ; |
291 | return sql_message(SQLSTATE(42S01) "%s TABLE: name '%s' already in use" , cd, t->base.name); |
292 | } else if (temp != SQL_DECLARED_TABLE && (!mvc_schema_privs(sql, s) && !(isTempSchema(s) && temp == SQL_LOCAL_TEMP))) { |
293 | return sql_message(SQLSTATE(42000) "CREATE TABLE: insufficient privileges for user '%s' in schema '%s'" , stack_get_string(sql, "current_user" ), s->base.name); |
294 | } else if (temp == SQL_DECLARED_TABLE && !list_empty(t->keys.set)) { |
295 | return sql_message(SQLSTATE(42000) "DECLARE TABLE: '%s' cannot have constraints" , t->base.name); |
296 | } |
297 | |
298 | osa = sql->sa; |
299 | sql->sa = NULL; |
300 | |
301 | nt = sql_trans_create_table(sql->session->tr, s, tname, t->query, t->type, t->system, temp, t->commit_action, |
302 | t->sz, t->properties); |
303 | |
304 | /* first check default values */ |
305 | for (n = t->columns.set->h; n; n = n->next) { |
306 | sql_column *c = n->data; |
307 | |
308 | if (c->def) { |
309 | char *buf, *typestr; |
310 | sql_rel *r = NULL; |
311 | list *id_l; |
312 | |
313 | sql->sa = sa_create(); |
314 | if (!sql->sa) { |
315 | sql->sa = osa; |
316 | throw(SQL, "sql.catalog" ,SQLSTATE(HY001) MAL_MALLOC_FAIL); |
317 | } |
318 | buf = sa_alloc(sql->sa, strlen(c->def) + 8); |
319 | if (!buf) { |
320 | sa_destroy(sql->sa); |
321 | sql->sa = osa; |
322 | throw(SQL, "sql.catalog" ,SQLSTATE(HY001) MAL_MALLOC_FAIL); |
323 | } |
324 | typestr = subtype2string2(&c->type); |
325 | if (!typestr) { |
326 | sa_destroy(sql->sa); |
327 | sql->sa = osa; |
328 | throw(SQL, "sql.catalog" ,SQLSTATE(HY001) MAL_MALLOC_FAIL); |
329 | } |
330 | snprintf(buf, BUFSIZ, "select cast(%s as %s);" , c->def, typestr); |
331 | _DELETE(typestr); |
332 | r = rel_parse(sql, s, buf, m_deps); |
333 | if (!r || !is_project(r->op) || !r->exps || list_length(r->exps) != 1 || |
334 | rel_check_type(sql, &c->type, r, r->exps->h->data, type_equal) == NULL) { |
335 | if (r) |
336 | rel_destroy(r); |
337 | sa_destroy(sql->sa); |
338 | sql->sa = osa; |
339 | if (strlen(sql->errstr) > 6 && sql->errstr[5] == '!') |
340 | throw(SQL, "sql.catalog" , "%s" , sql->errstr); |
341 | else |
342 | throw(SQL, "sql.catalog" , SQLSTATE(42000) "%s" , sql->errstr); |
343 | } |
344 | id_l = rel_dependencies(sql, r); |
345 | mvc_create_dependencies(sql, id_l, nt->base.id, FUNC_DEPENDENCY); |
346 | rel_destroy(r); |
347 | sa_destroy(sql->sa); |
348 | sql->sa = NULL; |
349 | } |
350 | } |
351 | |
352 | for (n = t->columns.set->h; n; n = n->next) { |
353 | sql_column *c = n->data, *copied = mvc_copy_column(sql, nt, c); |
354 | |
355 | if (copied == NULL) { |
356 | sql->sa = osa; |
357 | throw(SQL, "sql.catalog" , SQLSTATE(42000) "CREATE TABLE: %s_%s_%s conflicts" , s->base.name, t->base.name, c->base.name); |
358 | } |
359 | if (isPartitionedByColumnTable(t) && c->base.id == t->part.pcol->base.id) |
360 | nt->part.pcol = copied; |
361 | } |
362 | if (isPartitionedByExpressionTable(t)) { |
363 | char *err = NULL; |
364 | |
365 | nt->part.pexp->exp = sa_strdup(sql->session->tr->sa, t->part.pexp->exp); |
366 | |
367 | sql->sa = sa_create(); |
368 | if (!sql->sa) { |
369 | sql->sa = osa; |
370 | throw(SQL, "sql.catalog" ,SQLSTATE(HY001) MAL_MALLOC_FAIL); |
371 | } |
372 | |
373 | err = bootstrap_partition_expression(sql, sql->session->tr->sa, nt, 1); |
374 | sa_destroy(sql->sa); |
375 | sql->sa = NULL; |
376 | if (err) { |
377 | sql->sa = osa; |
378 | return err; |
379 | } |
380 | } |
381 | check = sql_trans_set_partition_table(sql->session->tr, nt); |
382 | if (check == -1) { |
383 | sql->sa = osa; |
384 | throw(SQL, "sql.catalog" , SQLSTATE(42000) "CREATE TABLE: %s_%s: the partition's expression is too long" , s->base.name, t->base.name); |
385 | } else if (check) { |
386 | sql->sa = osa; |
387 | throw(SQL, "sql.catalog" , SQLSTATE(42000) "CREATE TABLE: %s_%s: an internal error occurred" , s->base.name, t->base.name); |
388 | } |
389 | |
390 | if (t->idxs.set) { |
391 | for (n = t->idxs.set->h; n; n = n->next) { |
392 | sql_idx *i = n->data; |
393 | mvc_copy_idx(sql, nt, i); |
394 | } |
395 | } |
396 | if (t->keys.set) { |
397 | for (n = t->keys.set->h; n; n = n->next) { |
398 | sql_key *k = n->data; |
399 | char *err = NULL; |
400 | |
401 | sql->sa = sa_create(); |
402 | if(!sql->sa) { |
403 | sql->sa = osa; |
404 | throw(SQL, "sql.catalog" ,SQLSTATE(HY001) MAL_MALLOC_FAIL); |
405 | } |
406 | |
407 | err = sql_partition_validate_key(sql, nt, k, "CREATE" ); |
408 | sa_destroy(sql->sa); |
409 | sql->sa = NULL; |
410 | if (err) { |
411 | sql->sa = osa; |
412 | return err; |
413 | } |
414 | mvc_copy_key(sql, nt, k); |
415 | } |
416 | } |
417 | if (t->members.set) { |
418 | for (n = t->members.set->h; n; n = n->next) { |
419 | sql_part *pt = n->data; |
420 | mvc_copy_part(sql, nt, pt); |
421 | } |
422 | } |
423 | if (t->triggers.set) { |
424 | for (n = t->triggers.set->h; n; n = n->next) { |
425 | sql_trigger *tr = n->data; |
426 | mvc_copy_trigger(sql, nt, tr); |
427 | } |
428 | } |
429 | /* also create dependencies when not renaming */ |
430 | if (nt->query && isView(nt)) { |
431 | sql_rel *r = NULL; |
432 | |
433 | sql->sa = sa_create(); |
434 | if (!sql->sa) { |
435 | sql->sa = osa; |
436 | throw(SQL, "sql.catalog" ,SQLSTATE(HY001) MAL_MALLOC_FAIL); |
437 | } |
438 | r = rel_parse(sql, s, nt->query, m_deps); |
439 | if (r) |
440 | r = rel_unnest(sql, r); |
441 | if (r) |
442 | r = rel_optimizer(sql, r, 0); |
443 | if (r) { |
444 | list *id_l = rel_dependencies(sql, r); |
445 | |
446 | mvc_create_dependencies(sql, id_l, nt->base.id, VIEW_DEPENDENCY); |
447 | } |
448 | sa_destroy(sql->sa); |
449 | } |
450 | sql->sa = osa; |
451 | return MAL_SUCCEED; |
452 | } |
453 | |
454 | str |
455 | create_table_from_emit(Client cntxt, char *sname, char *tname, sql_emit_col *columns, size_t ncols) |
456 | { |
457 | size_t i; |
458 | sql_table *t; |
459 | sql_schema *s; |
460 | mvc *sql = NULL; |
461 | str msg = MAL_SUCCEED; |
462 | |
463 | if ((msg = getSQLContext(cntxt, NULL, &sql, NULL)) != NULL) |
464 | return msg; |
465 | if ((msg = checkSQLContext(cntxt)) != NULL) |
466 | return msg; |
467 | |
468 | /* for some reason we don't have an allocator here, so make one */ |
469 | if (!(sql->sa = sa_create())) { |
470 | msg = sql_error(sql, 02, SQLSTATE(HY001) "CREATE TABLE: %s" , MAL_MALLOC_FAIL); |
471 | goto cleanup; |
472 | } |
473 | |
474 | if (!sname) |
475 | sname = "sys" ; |
476 | if (!(s = mvc_bind_schema(sql, sname))) { |
477 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: no such schema '%s'" , sname); |
478 | goto cleanup; |
479 | } |
480 | if (!(t = mvc_create_table(sql, s, tname, tt_table, 0, SQL_DECLARED_TABLE, CA_COMMIT, -1, 0))) { |
481 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not create table '%s'" , tname); |
482 | goto cleanup; |
483 | } |
484 | |
485 | for (i = 0; i < ncols; i++) { |
486 | BAT *b = columns[i].b; |
487 | str atoname = ATOMname(b->ttype); |
488 | sql_subtype tpe; |
489 | sql_column *col = NULL; |
490 | |
491 | if (!strcmp(atoname, "str" )) |
492 | sql_find_subtype(&tpe, "clob" , 0, 0); |
493 | else { |
494 | sql_subtype *t = sql_bind_localtype(atoname); |
495 | if (!t) { |
496 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not find type for column" ); |
497 | goto cleanup; |
498 | } |
499 | tpe = *t; |
500 | } |
501 | |
502 | if (!(col = mvc_create_column(sql, t, columns[i].name, &tpe))) { |
503 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not create column %s" , columns[i].name); |
504 | goto cleanup; |
505 | } |
506 | } |
507 | if ((msg = create_table_or_view(sql, sname, t->base.name, t, 0)) != MAL_SUCCEED) |
508 | goto cleanup; |
509 | if (!(t = mvc_bind_table(sql, s, tname))) { |
510 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind table %s" , tname); |
511 | goto cleanup; |
512 | } |
513 | for (i = 0; i < ncols; i++) { |
514 | BAT *b = columns[i].b; |
515 | sql_column *col = NULL; |
516 | |
517 | if (!(col = mvc_bind_column(sql, t, columns[i].name))) { |
518 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind column %s" , columns[i].name); |
519 | goto cleanup; |
520 | } |
521 | if ((msg = mvc_append_column(sql->session->tr, col, b)) != MAL_SUCCEED) |
522 | goto cleanup; |
523 | } |
524 | |
525 | cleanup: |
526 | if(sql->sa) { |
527 | sa_destroy(sql->sa); |
528 | sql->sa = NULL; |
529 | } |
530 | return msg; |
531 | } |
532 | |
533 | str |
534 | append_to_table_from_emit(Client cntxt, char *sname, char *tname, sql_emit_col *columns, size_t ncols) |
535 | { |
536 | size_t i; |
537 | sql_table *t; |
538 | sql_schema *s; |
539 | mvc *sql = NULL; |
540 | str msg = MAL_SUCCEED; |
541 | |
542 | if ((msg = getSQLContext(cntxt, NULL, &sql, NULL)) != NULL) |
543 | return msg; |
544 | if ((msg = checkSQLContext(cntxt)) != NULL) |
545 | return msg; |
546 | |
547 | /* for some reason we don't have an allocator here, so make one */ |
548 | if (!(sql->sa = sa_create())) { |
549 | msg = sql_error(sql, 02, SQLSTATE(HY001) "CREATE TABLE: %s" , MAL_MALLOC_FAIL); |
550 | goto cleanup; |
551 | } |
552 | |
553 | if (!sname) |
554 | sname = "sys" ; |
555 | if (!(s = mvc_bind_schema(sql, sname))) { |
556 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: no such schema '%s'" , sname); |
557 | goto cleanup; |
558 | } |
559 | if (!(t = mvc_bind_table(sql, s, tname))) { |
560 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind table %s" , tname); |
561 | goto cleanup; |
562 | } |
563 | for (i = 0; i < ncols; i++) { |
564 | BAT *b = columns[i].b; |
565 | sql_column *col = NULL; |
566 | |
567 | if (!(col = mvc_bind_column(sql,t, columns[i].name))) { |
568 | msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind column %s" , columns[i].name); |
569 | goto cleanup; |
570 | } |
571 | if ((msg = mvc_append_column(sql->session->tr, col, b)) != MAL_SUCCEED) |
572 | goto cleanup; |
573 | } |
574 | |
575 | cleanup: |
576 | if(sql->sa) { |
577 | sa_destroy(sql->sa); |
578 | sql->sa = NULL; |
579 | } |
580 | return msg; |
581 | } |
582 | |
583 | BAT * |
584 | mvc_bind(mvc *m, const char *sname, const char *tname, const char *cname, int access) |
585 | { |
586 | sql_trans *tr = m->session->tr; |
587 | BAT *b = NULL; |
588 | sql_schema *s = NULL; |
589 | sql_table *t = NULL; |
590 | sql_column *c = NULL; |
591 | |
592 | s = mvc_bind_schema(m, sname); |
593 | if (s == NULL) |
594 | return NULL; |
595 | t = mvc_bind_table(m, s, tname); |
596 | if (t == NULL) |
597 | return NULL; |
598 | c = mvc_bind_column(m, t, cname); |
599 | if (c == NULL) |
600 | return NULL; |
601 | |
602 | b = store_funcs.bind_col(tr, c, access); |
603 | return b; |
604 | } |
605 | |
606 | str |
607 | SQLcatalog(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
608 | { |
609 | (void) cntxt; |
610 | (void) mb; |
611 | (void) stk; |
612 | (void) pci; |
613 | return sql_message(SQLSTATE(25006) "Deprecated statement" ); |
614 | } |
615 | |
616 | /* setVariable(int *ret, str *name, any value) */ |
617 | str |
618 | setVariable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
619 | { |
620 | int *res = getArgReference_int(stk, pci, 0); |
621 | mvc *m = NULL; |
622 | str msg; |
623 | const char *varname = *getArgReference_str(stk, pci, 2); |
624 | int mtype = getArgType(mb, pci, 3); |
625 | ValRecord *src; |
626 | |
627 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
628 | return msg; |
629 | if ((msg = checkSQLContext(cntxt)) != NULL) |
630 | return msg; |
631 | |
632 | *res = 0; |
633 | if (mtype < 0 || mtype >= 255) |
634 | throw(SQL, "sql.setVariable" , SQLSTATE(42100) "Variable type error" ); |
635 | if (strcmp("optimizer" , varname) == 0) { |
636 | const char *newopt = *getArgReference_str(stk, pci, 3); |
637 | if (newopt) { |
638 | char buf[BUFSIZ]; |
639 | if (!isOptimizerPipe(newopt) && strchr(newopt, (int) ';') == 0) { |
640 | throw(SQL, "sql.setVariable" , SQLSTATE(42100) "optimizer '%s' unknown" , newopt); |
641 | } |
642 | snprintf(buf, BUFSIZ, "user_%d" , cntxt->idx); |
643 | if (!isOptimizerPipe(newopt) || strcmp(buf, newopt) == 0) { |
644 | msg = addPipeDefinition(cntxt, buf, newopt); |
645 | if (msg) |
646 | return msg; |
647 | if (stack_find_var(m, varname)) { |
648 | if(!stack_set_string(m, varname, buf)) |
649 | throw(SQL, "sql.setVariable" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
650 | } |
651 | } else if (stack_find_var(m, varname)) { |
652 | if(!stack_set_string(m, varname, newopt)) |
653 | throw(SQL, "sql.setVariable" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
654 | } |
655 | } |
656 | return MAL_SUCCEED; |
657 | } |
658 | src = &stk->stk[getArg(pci, 3)]; |
659 | if (stack_find_var(m, varname)) { |
660 | #ifdef HAVE_HGE |
661 | hge sgn = val_get_number(src); |
662 | #else |
663 | lng sgn = val_get_number(src); |
664 | #endif |
665 | if ((msg = sql_update_var(m, varname, src->val.sval, sgn)) != NULL) |
666 | return msg; |
667 | if(!stack_set_var(m, varname, src)) |
668 | throw(SQL, "sql.setVariable" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
669 | } else { |
670 | throw(SQL, "sql.setVariable" , SQLSTATE(42100) "variable '%s' unknown" , varname); |
671 | } |
672 | return MAL_SUCCEED; |
673 | } |
674 | |
675 | /* getVariable(int *ret, str *name) */ |
676 | str |
677 | getVariable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
678 | { |
679 | int mtype = getArgType(mb, pci, 0); |
680 | mvc *m = NULL; |
681 | str msg; |
682 | const char *varname = *getArgReference_str(stk, pci, 2); |
683 | atom *a; |
684 | ValRecord *dst, *src; |
685 | |
686 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
687 | return msg; |
688 | if ((msg = checkSQLContext(cntxt)) != NULL) |
689 | return msg; |
690 | if (mtype < 0 || mtype >= 255) |
691 | throw(SQL, "sql.getVariable" , SQLSTATE(42100) "Variable type error" ); |
692 | if (!(a = stack_get_var(m, varname))) |
693 | throw(SQL, "sql.getVariable" , SQLSTATE(42100) "variable '%s' unknown" , varname); |
694 | src = &a->data; |
695 | dst = &stk->stk[getArg(pci, 0)]; |
696 | if (VALcopy(dst, src) == NULL) |
697 | throw(MAL, "sql.getVariable" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
698 | return MAL_SUCCEED; |
699 | } |
700 | |
701 | str |
702 | sql_variables(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
703 | { |
704 | int i; |
705 | mvc *m = NULL; |
706 | BAT *vars; |
707 | str msg; |
708 | bat *res = getArgReference_bat(stk, pci, 0); |
709 | |
710 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
711 | return msg; |
712 | if ((msg = checkSQLContext(cntxt)) != NULL) |
713 | return msg; |
714 | |
715 | vars = COLnew(0, TYPE_str, m->topvars, TRANSIENT); |
716 | if (vars == NULL) |
717 | throw(SQL, "sql.variables" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
718 | for (i = 0; i < m->topvars && !m->vars[i].frame; i++) { |
719 | if (BUNappend(vars, m->vars[i].name, false) != GDK_SUCCEED) { |
720 | BBPreclaim(vars); |
721 | throw(SQL, "sql.variables" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
722 | } |
723 | } |
724 | *res = vars->batCacheid; |
725 | BBPkeepref(vars->batCacheid); |
726 | return MAL_SUCCEED; |
727 | } |
728 | |
729 | /* str mvc_logfile(int *d, str *filename); */ |
730 | str |
731 | mvc_logfile(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
732 | { |
733 | mvc *m = NULL; |
734 | str msg; |
735 | const char *filename = *getArgReference_str(stk, pci, 1); |
736 | |
737 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
738 | return msg; |
739 | if ((msg = checkSQLContext(cntxt)) != NULL) |
740 | return msg; |
741 | if (m->scanner.log) { |
742 | close_stream(m->scanner.log); |
743 | m->scanner.log = NULL; |
744 | } |
745 | |
746 | if (strcmp(filename, str_nil)) { |
747 | if((m->scanner.log = open_wastream(filename)) == NULL) |
748 | throw(SQL, "sql.logfile" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
749 | } |
750 | return MAL_SUCCEED; |
751 | } |
752 | |
753 | /* str mvc_next_value(lng *res, str *sname, str *seqname); */ |
754 | str |
755 | mvc_next_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
756 | { |
757 | mvc *m = NULL; |
758 | str msg; |
759 | sql_schema *s; |
760 | sql_sequence *seq; |
761 | lng *res = getArgReference_lng(stk, pci, 0); |
762 | const char *sname = *getArgReference_str(stk, pci, 1); |
763 | const char *seqname = *getArgReference_str(stk, pci, 2); |
764 | |
765 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
766 | return msg; |
767 | if ((msg = checkSQLContext(cntxt)) != NULL) |
768 | return msg; |
769 | if (!(s = mvc_bind_schema(m, sname))) |
770 | throw(SQL, "sql.next_value" , SQLSTATE(3F000) "Cannot find the schema %s" , sname); |
771 | if (!(seq = find_sql_sequence(s, seqname))) |
772 | throw(SQL, "sql.next_value" , SQLSTATE(HY050) "Failed to fetch sequence %s.%s" , sname, seqname); |
773 | |
774 | if (seq_next_value(seq, res)) { |
775 | m->last_id = *res; |
776 | stack_set_number(m, "last_id" , m->last_id); |
777 | return MAL_SUCCEED; |
778 | } |
779 | throw(SQL, "sql.next_value" , SQLSTATE(42000) "Error in fetching next value for sequence %s.%s" , sname, seqname); |
780 | } |
781 | |
782 | /* str mvc_get_value(lng *res, str *sname, str *seqname); */ |
783 | str |
784 | mvc_get_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
785 | { |
786 | mvc *m = NULL; |
787 | str msg; |
788 | sql_schema *s; |
789 | sql_sequence *seq; |
790 | lng *res = getArgReference_lng(stk, pci, 0); |
791 | const char *sname = *getArgReference_str(stk, pci, 1); |
792 | const char *seqname = *getArgReference_str(stk, pci, 2); |
793 | |
794 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
795 | return msg; |
796 | if ((msg = checkSQLContext(cntxt)) != NULL) |
797 | return msg; |
798 | if (!(s = mvc_bind_schema(m, sname))) |
799 | throw(SQL, "sql.get_value" , SQLSTATE(3F000) "Cannot find the schema %s" , sname); |
800 | if (!(seq = find_sql_sequence(s, seqname))) |
801 | throw(SQL, "sql.get_value" , SQLSTATE(HY050) "Failed to fetch sequence %s.%s" , sname, seqname); |
802 | |
803 | if (seq_get_value(seq, res)) |
804 | return MAL_SUCCEED; |
805 | throw(SQL, "sql.get_value" , SQLSTATE(42000) "Error in fetching current value for sequence %s.%s" , sname, seqname); |
806 | } |
807 | |
808 | static str |
809 | mvc_bat_next_get_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int (*bulk_func)(seqbulk *, lng *), const char *call, const char *action) |
810 | { |
811 | mvc *m = NULL; |
812 | str msg = MAL_SUCCEED, sname = NULL, seqname = NULL; |
813 | BAT *b = NULL, *c = NULL, *r = NULL, *it; |
814 | BUN p, q; |
815 | sql_schema *s = NULL; |
816 | sql_sequence *seq = NULL; |
817 | seqbulk *sb = NULL; |
818 | BATiter bi, ci; |
819 | bat *res = getArgReference_bat(stk, pci, 0); |
820 | bat schid = 0, seqid = 0; |
821 | |
822 | if (isaBatType(getArgType(mb, pci, 1))) |
823 | schid = *getArgReference_bat(stk, pci, 1); |
824 | else |
825 | sname = *getArgReference_str(stk, pci, 1); |
826 | if (isaBatType(getArgType(mb, pci, 2))) |
827 | seqid = *getArgReference_bat(stk, pci, 2); |
828 | else |
829 | seqname = *getArgReference_str(stk, pci, 2); |
830 | |
831 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
832 | return msg; |
833 | if ((msg = checkSQLContext(cntxt)) != NULL) |
834 | return msg; |
835 | |
836 | if (schid && !(b = BATdescriptor(schid))) { |
837 | msg = createException(SQL, call, SQLSTATE(HY005) "Cannot access column descriptor" ); |
838 | goto bailout; |
839 | } |
840 | if (seqid && !(c = BATdescriptor(seqid))) { |
841 | msg = createException(SQL, call, SQLSTATE(HY005) "Cannot access column descriptor" ); |
842 | goto bailout; |
843 | } |
844 | assert(b || c); |
845 | it = b ? b : c; /* Either b or c must be set */ |
846 | |
847 | if (!(r = COLnew(it->hseqbase, TYPE_lng, BATcount(it), TRANSIENT))) { |
848 | msg = createException(SQL, call, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
849 | goto bailout; |
850 | } |
851 | |
852 | if (!BATcount(it)) |
853 | goto bailout; /* Success case */ |
854 | |
855 | if (b) |
856 | bi = bat_iterator(b); |
857 | if (c) |
858 | ci = bat_iterator(c); |
859 | |
860 | BATloop(it, p, q) { |
861 | str nsname, nseqname; |
862 | lng l; |
863 | |
864 | if (b) |
865 | nsname = BUNtvar(bi, p); |
866 | else |
867 | nsname = sname; |
868 | if (c) |
869 | nseqname = BUNtvar(ci, p); |
870 | else |
871 | nseqname = seqname; |
872 | |
873 | if (!s || strcmp(s->base.name, nsname) != 0 || !seq || strcmp(seq->base.name, nseqname) != 0) { |
874 | if (sb) { |
875 | seqbulk_destroy(sb); |
876 | sb = NULL; |
877 | } |
878 | seq = NULL; |
879 | if ((!s || strcmp(s->base.name, nsname) != 0) && !(s = mvc_bind_schema(m, nsname))) { |
880 | msg = createException(SQL, call, SQLSTATE(3F000) "Cannot find the schema %s" , nsname); |
881 | goto bailout; |
882 | } |
883 | if (!(seq = find_sql_sequence(s, nseqname)) || !(sb = seqbulk_create(seq, BATcount(it)))) { |
884 | msg = createException(SQL, call, SQLSTATE(HY050) "Cannot find the sequence %s.%s" , nsname, nseqname); |
885 | goto bailout; |
886 | } |
887 | } |
888 | if (!bulk_func(sb, &l)) { |
889 | msg = createException(SQL, call, SQLSTATE(HY050) "Cannot %s sequence value %s.%s" , action, nsname, nseqname); |
890 | goto bailout; |
891 | } |
892 | if (BUNappend(r, &l, false) != GDK_SUCCEED) { |
893 | msg = createException(SQL, call, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
894 | goto bailout; |
895 | } |
896 | } |
897 | |
898 | bailout: |
899 | if (sb) |
900 | seqbulk_destroy(sb); |
901 | if (b) |
902 | BBPunfix(b->batCacheid); |
903 | if (c) |
904 | BBPunfix(c->batCacheid); |
905 | if (msg) |
906 | BBPreclaim(r); |
907 | else |
908 | BBPkeepref(*res = r->batCacheid); |
909 | return msg; |
910 | } |
911 | |
912 | str |
913 | mvc_bat_next_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
914 | { |
915 | return mvc_bat_next_get_value(cntxt, mb, stk, pci, seqbulk_next_value, "sql.next_value" , "generate next" ); |
916 | } |
917 | |
918 | str |
919 | mvc_bat_get_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
920 | { |
921 | return mvc_bat_next_get_value(cntxt, mb, stk, pci, seqbulk_get_value, "sql.get_value" , "get" ); |
922 | } |
923 | |
924 | str |
925 | mvc_getVersion(lng *version, const int *clientid) |
926 | { |
927 | mvc *m = NULL; |
928 | Client cntxt = MCgetClient(*clientid); |
929 | str msg; |
930 | |
931 | if ((msg = getSQLContext(cntxt, NULL, &m, NULL)) != NULL) |
932 | return msg; |
933 | if ((msg = checkSQLContext(cntxt)) != NULL) |
934 | return msg; |
935 | *version = -1; |
936 | if (m->session->tr) |
937 | *version = m->session->tr->stime; |
938 | return MAL_SUCCEED; |
939 | } |
940 | |
941 | /* str mvc_restart_seq(lng *res, str *sname, str *seqname, lng *start); */ |
942 | str |
943 | mvc_restart_seq(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
944 | { |
945 | mvc *m = NULL; |
946 | str msg; |
947 | sql_schema *s; |
948 | sql_sequence *seq; |
949 | lng *res = getArgReference_lng(stk, pci, 0); |
950 | const char *sname = *getArgReference_str(stk, pci, 1); |
951 | const char *seqname = *getArgReference_str(stk, pci, 2); |
952 | lng start = *getArgReference_lng(stk, pci, 3); |
953 | |
954 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
955 | return msg; |
956 | if ((msg = checkSQLContext(cntxt)) != NULL) |
957 | return msg; |
958 | if (!(s = mvc_bind_schema(m, sname))) |
959 | throw(SQL, "sql.restart" , SQLSTATE(3F000) "Cannot find the schema %s" , sname); |
960 | if (!(seq = find_sql_sequence(s, seqname))) |
961 | throw(SQL, "sql.restart" , SQLSTATE(HY050) "Failed to fetch sequence %s.%s" , sname, seqname); |
962 | if (is_lng_nil(start)) |
963 | throw(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot (re)start sequence %s.%s with NULL" , sname, seqname); |
964 | if (seq->minvalue && start < seq->minvalue) |
965 | throw(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value lesser than the minimum (" LLFMT" < " LLFMT")" , sname, seqname, start, seq->minvalue); |
966 | if (seq->maxvalue && start > seq->maxvalue) |
967 | throw(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value higher than the maximum (" LLFMT" > " LLFMT")" , sname, seqname, start, seq->maxvalue); |
968 | if (sql_trans_sequence_restart(m->session->tr, seq, start)) { |
969 | *res = start; |
970 | return MAL_SUCCEED; |
971 | } |
972 | throw(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot (re)start sequence %s.%s" , sname, seqname); |
973 | } |
974 | |
975 | str |
976 | mvc_bat_restart_seq(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
977 | { |
978 | mvc *m = NULL; |
979 | str msg = MAL_SUCCEED, sname = NULL, seqname = NULL; |
980 | BAT *b = NULL, *c = NULL, *d = NULL, *r = NULL, *it; |
981 | BUN p, q; |
982 | sql_schema *s = NULL; |
983 | sql_sequence *seq = NULL; |
984 | seqbulk *sb = NULL; |
985 | BATiter bi, ci; |
986 | bat *res = getArgReference_bat(stk, pci, 0); |
987 | bat schid = 0, seqid = 0, startid = 0; |
988 | lng start = 0, *di = NULL; |
989 | |
990 | if (isaBatType(getArgType(mb, pci, 1))) |
991 | schid = *getArgReference_bat(stk, pci, 1); |
992 | else |
993 | sname = *getArgReference_str(stk, pci, 1); |
994 | if (isaBatType(getArgType(mb, pci, 2))) |
995 | seqid = *getArgReference_bat(stk, pci, 2); |
996 | else |
997 | seqname = *getArgReference_str(stk, pci, 2); |
998 | if (isaBatType(getArgType(mb, pci, 3))) |
999 | startid = *getArgReference_bat(stk, pci, 3); |
1000 | else |
1001 | start = *getArgReference_lng(stk, pci, 3); |
1002 | |
1003 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1004 | return msg; |
1005 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1006 | return msg; |
1007 | |
1008 | if (schid && !(b = BATdescriptor(schid))) { |
1009 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
1010 | goto bailout; |
1011 | } |
1012 | if (seqid && !(c = BATdescriptor(seqid))) { |
1013 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
1014 | goto bailout; |
1015 | } |
1016 | if (startid && !(d = BATdescriptor(startid))) { |
1017 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
1018 | goto bailout; |
1019 | } |
1020 | assert(b || c || d); |
1021 | it = b ? b : c ? c : d; /* Either b, c or d must be set */ |
1022 | |
1023 | if (!(r = COLnew(it->hseqbase, TYPE_lng, BATcount(it), TRANSIENT))) { |
1024 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1025 | goto bailout; |
1026 | } |
1027 | |
1028 | if (!BATcount(it)) |
1029 | goto bailout; /* Success case */ |
1030 | |
1031 | if (b) |
1032 | bi = bat_iterator(b); |
1033 | if (c) |
1034 | ci = bat_iterator(c); |
1035 | if (d) |
1036 | di = (lng *) Tloc(d, 0); |
1037 | |
1038 | BATloop(it, p, q) { |
1039 | str nsname, nseqname; |
1040 | lng nstart; |
1041 | |
1042 | if (b) |
1043 | nsname = BUNtvar(bi, p); |
1044 | else |
1045 | nsname = sname; |
1046 | if (c) |
1047 | nseqname = BUNtvar(ci, p); |
1048 | else |
1049 | nseqname = seqname; |
1050 | if (di) |
1051 | nstart = di[p]; |
1052 | else |
1053 | nstart = start; |
1054 | |
1055 | if (!s || strcmp(s->base.name, nsname) != 0 || !seq || strcmp(seq->base.name, nseqname) != 0) { |
1056 | if (sb) { |
1057 | seqbulk_destroy(sb); |
1058 | sb = NULL; |
1059 | } |
1060 | seq = NULL; |
1061 | if ((!s || strcmp(s->base.name, nsname) != 0) && !(s = mvc_bind_schema(m, nsname))) { |
1062 | msg = createException(SQL, "sql.restart" , SQLSTATE(3F000) "Cannot find the schema %s" , nsname); |
1063 | goto bailout; |
1064 | } |
1065 | if (!(seq = find_sql_sequence(s, nseqname)) || !(sb = seqbulk_create(seq, BATcount(it)))) { |
1066 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot find the sequence %s.%s" , nsname, nseqname); |
1067 | goto bailout; |
1068 | } |
1069 | } |
1070 | if (is_lng_nil(nstart)) { |
1071 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot (re)start sequence %s.%s with NULL" , sname, seqname); |
1072 | goto bailout; |
1073 | } |
1074 | if (seq->minvalue && nstart < seq->minvalue) { |
1075 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value lesser than the minimum (" LLFMT" < " LLFMT")" , sname, seqname, start, seq->minvalue); |
1076 | goto bailout; |
1077 | } |
1078 | if (seq->maxvalue && nstart > seq->maxvalue) { |
1079 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value higher than the maximum (" LLFMT" > " LLFMT")" , sname, seqname, start, seq->maxvalue); |
1080 | goto bailout; |
1081 | } |
1082 | if (!sql_trans_seqbulk_restart(m->session->tr, sb, nstart)) { |
1083 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY050) "Cannot restart sequence %s.%s" , nsname, nseqname); |
1084 | goto bailout; |
1085 | } |
1086 | if (BUNappend(r, &nstart, false) != GDK_SUCCEED) { |
1087 | msg = createException(SQL, "sql.restart" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1088 | goto bailout; |
1089 | } |
1090 | } |
1091 | |
1092 | bailout: |
1093 | if (sb) |
1094 | seqbulk_destroy(sb); |
1095 | if (b) |
1096 | BBPunfix(b->batCacheid); |
1097 | if (c) |
1098 | BBPunfix(c->batCacheid); |
1099 | if (d) |
1100 | BBPunfix(d->batCacheid); |
1101 | if (msg) |
1102 | BBPreclaim(r); |
1103 | else |
1104 | BBPkeepref(*res = r->batCacheid); |
1105 | return msg; |
1106 | } |
1107 | |
1108 | static BAT * |
1109 | mvc_bind_dbat(mvc *m, const char *sname, const char *tname, int access) |
1110 | { |
1111 | sql_trans *tr = m->session->tr; |
1112 | BAT *b = NULL; |
1113 | sql_schema *s = NULL; |
1114 | sql_table *t = NULL; |
1115 | |
1116 | s = mvc_bind_schema(m, sname); |
1117 | if (s == NULL) |
1118 | return NULL; |
1119 | t = mvc_bind_table(m, s, tname); |
1120 | if (t == NULL) |
1121 | return NULL; |
1122 | |
1123 | b = store_funcs.bind_del(tr, t, access); |
1124 | return b; |
1125 | } |
1126 | |
1127 | BAT * |
1128 | mvc_bind_idxbat(mvc *m, const char *sname, const char *tname, const char *iname, int access) |
1129 | { |
1130 | sql_trans *tr = m->session->tr; |
1131 | BAT *b = NULL; |
1132 | sql_schema *s = NULL; |
1133 | sql_idx *i = NULL; |
1134 | |
1135 | s = mvc_bind_schema(m, sname); |
1136 | if (s == NULL) |
1137 | return NULL; |
1138 | i = mvc_bind_idx(m, s, iname); |
1139 | if (i == NULL) |
1140 | return NULL; |
1141 | |
1142 | (void) tname; |
1143 | b = store_funcs.bind_idx(tr, i, access); |
1144 | return b; |
1145 | } |
1146 | |
1147 | /* str mvc_bind_wrap(int *bid, str *sname, str *tname, str *cname, int *access); */ |
1148 | str |
1149 | mvc_bind_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1150 | { |
1151 | int upd = (pci->argc == 7 || pci->argc == 9); |
1152 | BAT *b = NULL, *bn; |
1153 | bat *bid = getArgReference_bat(stk, pci, 0); |
1154 | int coltype = getBatType(getArgType(mb, pci, 0)); |
1155 | mvc *m = NULL; |
1156 | str msg; |
1157 | const char *sname = *getArgReference_str(stk, pci, 2 + upd); |
1158 | const char *tname = *getArgReference_str(stk, pci, 3 + upd); |
1159 | const char *cname = *getArgReference_str(stk, pci, 4 + upd); |
1160 | int access = *getArgReference_int(stk, pci, 5 + upd); |
1161 | |
1162 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1163 | return msg; |
1164 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1165 | return msg; |
1166 | b = mvc_bind(m, sname, tname, cname, access); |
1167 | if (b && b->ttype != coltype) { |
1168 | BBPunfix(b->batCacheid); |
1169 | throw(SQL,"sql.bind" ,SQLSTATE(42000) "Column type mismatch" ); |
1170 | } |
1171 | if (b) { |
1172 | if (pci->argc == (8 + upd) && getArgType(mb, pci, 6 + upd) == TYPE_int) { |
1173 | BUN cnt = BATcount(b), psz; |
1174 | /* partitioned access */ |
1175 | int part_nr = *getArgReference_int(stk, pci, 6 + upd); |
1176 | int nr_parts = *getArgReference_int(stk, pci, 7 + upd); |
1177 | |
1178 | if (access == 0) { |
1179 | psz = cnt ? (cnt / nr_parts) : 0; |
1180 | bn = BATslice(b, part_nr * psz, (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz)); |
1181 | if(bn == NULL) { |
1182 | BBPunfix(b->batCacheid); |
1183 | throw(SQL, "sql.bind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1184 | } |
1185 | BAThseqbase(bn, part_nr * psz); |
1186 | } else { |
1187 | /* BAT b holds the UPD_ID bat */ |
1188 | oid l, h; |
1189 | BAT *c = mvc_bind(m, sname, tname, cname, 0); |
1190 | if (c == NULL) { |
1191 | BBPunfix(b->batCacheid); |
1192 | throw(SQL,"sql.bind" ,SQLSTATE(HY005) "Cannot access the update column %s.%s.%s" , |
1193 | sname,tname,cname); |
1194 | } |
1195 | cnt = BATcount(c); |
1196 | psz = cnt ? (cnt / nr_parts) : 0; |
1197 | l = part_nr * psz; |
1198 | h = (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz); |
1199 | h--; |
1200 | bn = BATselect(b, NULL, &l, &h, true, true, false); |
1201 | BBPunfix(c->batCacheid); |
1202 | if(bn == NULL) { |
1203 | BBPunfix(b->batCacheid); |
1204 | throw(SQL, "sql.bind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1205 | } |
1206 | } |
1207 | BBPunfix(b->batCacheid); |
1208 | b = bn; |
1209 | } else if (upd) { |
1210 | BAT *uv = mvc_bind(m, sname, tname, cname, RD_UPD_VAL); |
1211 | bat *uvl = getArgReference_bat(stk, pci, 1); |
1212 | |
1213 | if (uv == NULL) { |
1214 | BBPunfix(b->batCacheid); |
1215 | throw(SQL,"sql.bind" ,SQLSTATE(HY005) "Cannot access the update column %s.%s.%s" , |
1216 | sname,tname,cname); |
1217 | } |
1218 | BBPkeepref(*bid = b->batCacheid); |
1219 | BBPkeepref(*uvl = uv->batCacheid); |
1220 | return MAL_SUCCEED; |
1221 | } |
1222 | if (upd) { |
1223 | bat *uvl = getArgReference_bat(stk, pci, 1); |
1224 | |
1225 | if (BATcount(b)) { |
1226 | BAT *uv = mvc_bind(m, sname, tname, cname, RD_UPD_VAL); |
1227 | BAT *ui = mvc_bind(m, sname, tname, cname, RD_UPD_ID); |
1228 | BAT *id; |
1229 | BAT *vl; |
1230 | if (ui == NULL || uv == NULL) { |
1231 | bat_destroy(uv); |
1232 | bat_destroy(ui); |
1233 | BBPunfix(b->batCacheid); |
1234 | throw(SQL,"sql.bind" ,SQLSTATE(HY005) "Cannot access the insert column %s.%s.%s" , |
1235 | sname, tname, cname); |
1236 | } |
1237 | id = BATproject(b, ui); |
1238 | vl = BATproject(b, uv); |
1239 | bat_destroy(ui); |
1240 | bat_destroy(uv); |
1241 | if (id == NULL || vl == NULL) { |
1242 | BBPunfix(b->batCacheid); |
1243 | bat_destroy(id); |
1244 | bat_destroy(vl); |
1245 | throw(SQL, "sql.bind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1246 | } |
1247 | if ( BATcount(id) != BATcount(vl)){ |
1248 | BBPunfix(b->batCacheid); |
1249 | throw(SQL, "sql.bind" , SQLSTATE(0000) "Inconsistent BAT count" ); |
1250 | } |
1251 | BBPkeepref(*bid = id->batCacheid); |
1252 | BBPkeepref(*uvl = vl->batCacheid); |
1253 | } else { |
1254 | sql_schema *s = mvc_bind_schema(m, sname); |
1255 | sql_table *t = mvc_bind_table(m, s, tname); |
1256 | sql_column *c = mvc_bind_column(m, t, cname); |
1257 | |
1258 | *bid = e_bat(TYPE_oid); |
1259 | *uvl = e_bat(c->type.type->localtype); |
1260 | if(*bid == BID_NIL || *uvl == BID_NIL) { |
1261 | BBPunfix(b->batCacheid); |
1262 | throw(SQL, "sql.bind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1263 | } |
1264 | } |
1265 | BBPunfix(b->batCacheid); |
1266 | } else { |
1267 | BBPkeepref(*bid = b->batCacheid); |
1268 | } |
1269 | return MAL_SUCCEED; |
1270 | } |
1271 | if (sname && strcmp(sname, str_nil) != 0) |
1272 | throw(SQL, "sql.bind" , SQLSTATE(42000) "unable to find %s.%s(%s)" , sname, tname, cname); |
1273 | throw(SQL, "sql.bind" , SQLSTATE(42000) "unable to find %s(%s)" , tname, cname); |
1274 | } |
1275 | |
1276 | /* The output of this function are 7 columns: |
1277 | * - The sqlid of the column |
1278 | * - A flag indicating if the column's upper table is cleared or not. |
1279 | * - Number of read-only values of the column (inherited from the previous transaction). |
1280 | * - Number of inserted rows during the current transaction. |
1281 | * - Number of updated rows during the current transaction. |
1282 | * - Number of deletes of the column's table. |
1283 | * - the number in the transaction chain (.i.e for each savepoint a new transaction is added in the chain) |
1284 | * If the table is cleared, the values RDONLY, RD_INS and RD_UPD_ID and the number of deletes will be 0. |
1285 | */ |
1286 | |
1287 | static str |
1288 | mvc_insert_delta_values(mvc *m, BAT *col1, BAT *col2, BAT *col3, BAT *col4, BAT *col5, BAT *col6, BAT *col7, sql_column *c, bit cleared, lng deletes) |
1289 | { |
1290 | int level = 0; |
1291 | |
1292 | lng inserted = (lng) store_funcs.count_col(m->session->tr, c, 0); |
1293 | lng all = (lng) store_funcs.count_col(m->session->tr, c, 1); |
1294 | lng updates = (lng) store_funcs.count_col_upd(m->session->tr, c); |
1295 | lng readonly = all - inserted; |
1296 | |
1297 | assert(all >= inserted); |
1298 | |
1299 | if (BUNappend(col1, &c->base.id, false) != GDK_SUCCEED) { |
1300 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1301 | } |
1302 | if (BUNappend(col2, &cleared, false) != GDK_SUCCEED) { |
1303 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1304 | } |
1305 | if (BUNappend(col3, &readonly, false) != GDK_SUCCEED) { |
1306 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1307 | } |
1308 | if (BUNappend(col4, &inserted, false) != GDK_SUCCEED) { |
1309 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1310 | } |
1311 | if (BUNappend(col5, &updates, false) != GDK_SUCCEED) { |
1312 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1313 | } |
1314 | if (BUNappend(col6, &deletes, false) != GDK_SUCCEED) { |
1315 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1316 | } |
1317 | /* compute level using global transaction */ |
1318 | if (gtrans) { |
1319 | sql_column *oc = tr_find_column(gtrans, c); |
1320 | |
1321 | if (oc) { |
1322 | for(sql_delta *d = oc->data; d; d = d->next) |
1323 | level++; |
1324 | } |
1325 | } |
1326 | if (BUNappend(col7, &level, false) != GDK_SUCCEED) { |
1327 | return createException(SQL,"sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1328 | } |
1329 | return MAL_SUCCEED; |
1330 | } |
1331 | |
1332 | str |
1333 | mvc_delta_values(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1334 | { |
1335 | const char *sname = *getArgReference_str(stk, pci, 7), |
1336 | *tname = (pci->argc > 8) ? *getArgReference_str(stk, pci, 8) : NULL, |
1337 | *cname = (pci->argc > 9) ? *getArgReference_str(stk, pci, 9) : NULL; |
1338 | mvc *m; |
1339 | str msg = MAL_SUCCEED; |
1340 | BAT *col1 = NULL, *col2 = NULL, *col3 = NULL, *col4 = NULL, *col5 = NULL, *col6 = NULL, *col7 = NULL; |
1341 | bat *b1 = getArgReference_bat(stk, pci, 0), |
1342 | *b2 = getArgReference_bat(stk, pci, 1), |
1343 | *b3 = getArgReference_bat(stk, pci, 2), |
1344 | *b4 = getArgReference_bat(stk, pci, 3), |
1345 | *b5 = getArgReference_bat(stk, pci, 4), |
1346 | *b6 = getArgReference_bat(stk, pci, 5), |
1347 | *b7 = getArgReference_bat(stk, pci, 6); |
1348 | sql_schema *s = NULL; |
1349 | sql_table *t = NULL; |
1350 | sql_column *c = NULL; |
1351 | node *n; |
1352 | bit cleared; |
1353 | BUN nrows = 0; |
1354 | lng deletes; |
1355 | |
1356 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1357 | goto cleanup; |
1358 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1359 | goto cleanup; |
1360 | |
1361 | if (!(s = mvc_bind_schema(m, sname))) |
1362 | throw(SQL, "sql.delta" , SQLSTATE(3F000) "No such schema '%s'" , sname); |
1363 | |
1364 | if (tname) { |
1365 | if (!(t = mvc_bind_table(m, s, tname))) |
1366 | throw(SQL, "sql.delta" , SQLSTATE(3F000) "No such table '%s' in schema '%s'" , tname, s->base.name); |
1367 | if (isView(t)) |
1368 | throw(SQL, "sql.delta" , SQLSTATE(42000) "Views don't have delta values" ); |
1369 | if (isMergeTable(t)) |
1370 | throw(SQL, "sql.delta" , SQLSTATE(42000) "Merge tables don't have delta values" ); |
1371 | if (isStream(t)) |
1372 | throw(SQL, "sql.delta" , SQLSTATE(42000) "Stream tables don't have delta values" ); |
1373 | if (isRemote(t)) |
1374 | throw(SQL, "sql.delta" , SQLSTATE(42000) "Remote tables don't have delta values" ); |
1375 | if (isReplicaTable(t)) |
1376 | throw(SQL, "sql.delta" , SQLSTATE(42000) "Replica tables don't have delta values" ); |
1377 | if (cname) { |
1378 | if (!(c = mvc_bind_column(m, t, cname))) |
1379 | throw(SQL, "sql.delta" , SQLSTATE(3F000) "No such column '%s' in table '%s'" , cname, t->base.name); |
1380 | nrows = 1; |
1381 | } else { |
1382 | nrows = (BUN) t->columns.set->cnt; |
1383 | } |
1384 | } else if (s->tables.set) { |
1385 | for (n = s->tables.set->h; n ; n = n->next) { |
1386 | t = (sql_table *) n->data; |
1387 | if (!(isView(t) || isMergeTable(t) || isStream(t) || isRemote(t) || isReplicaTable(t))) |
1388 | nrows += t->columns.set->cnt; |
1389 | } |
1390 | } |
1391 | |
1392 | if ((col1 = COLnew(0, TYPE_int, nrows, TRANSIENT)) == NULL) { |
1393 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1394 | goto cleanup; |
1395 | } |
1396 | if ((col2 = COLnew(0, TYPE_bit, nrows, TRANSIENT)) == NULL) { |
1397 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1398 | goto cleanup; |
1399 | } |
1400 | if ((col3 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) { |
1401 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1402 | goto cleanup; |
1403 | } |
1404 | if ((col4 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) { |
1405 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1406 | goto cleanup; |
1407 | } |
1408 | if ((col5 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) { |
1409 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1410 | goto cleanup; |
1411 | } |
1412 | if ((col6 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) { |
1413 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1414 | goto cleanup; |
1415 | } |
1416 | if ((col7 = COLnew(0, TYPE_int, nrows, TRANSIENT)) == NULL) { |
1417 | msg = createException(SQL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1418 | goto cleanup; |
1419 | } |
1420 | |
1421 | if (nrows) { |
1422 | if (tname) { |
1423 | cleared = (t->cleared != 0); |
1424 | deletes = (lng) store_funcs.count_del(m->session->tr, t); |
1425 | if (cname) { |
1426 | if ((msg=mvc_insert_delta_values(m, col1, col2, col3, col4, col5, col6, col7, c, cleared, deletes)) != NULL) |
1427 | goto cleanup; |
1428 | } else { |
1429 | for (n = t->columns.set->h; n ; n = n->next) { |
1430 | c = (sql_column*) n->data; |
1431 | if ((msg=mvc_insert_delta_values(m, col1, col2, col3, col4, col5, col6, col7, c, cleared, deletes)) != NULL) |
1432 | goto cleanup; |
1433 | } |
1434 | } |
1435 | } else if (s->tables.set) { |
1436 | for (n = s->tables.set->h; n ; n = n->next) { |
1437 | t = (sql_table *) n->data; |
1438 | if (!(isView(t) || isMergeTable(t) || isStream(t) || isRemote(t) || isReplicaTable(t))) { |
1439 | cleared = (t->cleared != 0); |
1440 | deletes = (lng) store_funcs.count_del(m->session->tr, t); |
1441 | |
1442 | for (node *nn = t->columns.set->h; nn ; nn = nn->next) { |
1443 | c = (sql_column*) nn->data; |
1444 | |
1445 | if ((msg=mvc_insert_delta_values(m, col1, col2, col3, col4, col5, col6, col7, |
1446 | c, cleared, deletes)) != NULL) |
1447 | goto cleanup; |
1448 | } |
1449 | } |
1450 | } |
1451 | } |
1452 | } |
1453 | |
1454 | cleanup: |
1455 | if (msg) { |
1456 | if (col1) |
1457 | BBPreclaim(col1); |
1458 | if (col2) |
1459 | BBPreclaim(col2); |
1460 | if (col3) |
1461 | BBPreclaim(col3); |
1462 | if (col4) |
1463 | BBPreclaim(col4); |
1464 | if (col5) |
1465 | BBPreclaim(col5); |
1466 | if (col6) |
1467 | BBPreclaim(col6); |
1468 | if (col7) |
1469 | BBPreclaim(col7); |
1470 | } else { |
1471 | BBPkeepref(*b1 = col1->batCacheid); |
1472 | BBPkeepref(*b2 = col2->batCacheid); |
1473 | BBPkeepref(*b3 = col3->batCacheid); |
1474 | BBPkeepref(*b4 = col4->batCacheid); |
1475 | BBPkeepref(*b5 = col5->batCacheid); |
1476 | BBPkeepref(*b6 = col6->batCacheid); |
1477 | BBPkeepref(*b7 = col7->batCacheid); |
1478 | } |
1479 | return msg; |
1480 | } |
1481 | |
1482 | /* str mvc_bind_idxbat_wrap(int *bid, str *sname, str *tname, str *iname, int *access); */ |
1483 | str |
1484 | mvc_bind_idxbat_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1485 | { |
1486 | int upd = (pci->argc == 7 || pci->argc == 9); |
1487 | BAT *b = NULL, *bn; |
1488 | bat *bid = getArgReference_bat(stk, pci, 0); |
1489 | int coltype = getBatType(getArgType(mb, pci, 0)); |
1490 | mvc *m = NULL; |
1491 | str msg; |
1492 | const char *sname = *getArgReference_str(stk, pci, 2 + upd); |
1493 | const char *tname = *getArgReference_str(stk, pci, 3 + upd); |
1494 | const char *iname = *getArgReference_str(stk, pci, 4 + upd); |
1495 | int access = *getArgReference_int(stk, pci, 5 + upd); |
1496 | |
1497 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1498 | return msg; |
1499 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1500 | return msg; |
1501 | b = mvc_bind_idxbat(m, sname, tname, iname, access); |
1502 | if (b && b->ttype != coltype) |
1503 | throw(SQL,"sql.bind" ,SQLSTATE(42000) "Column type mismatch %s.%s.%s" ,sname,tname,iname); |
1504 | if (b) { |
1505 | if (pci->argc == (8 + upd) && getArgType(mb, pci, 6 + upd) == TYPE_int) { |
1506 | BUN cnt = BATcount(b), psz; |
1507 | /* partitioned access */ |
1508 | int part_nr = *getArgReference_int(stk, pci, 6 + upd); |
1509 | int nr_parts = *getArgReference_int(stk, pci, 7 + upd); |
1510 | |
1511 | if (access == 0) { |
1512 | psz = cnt ? (cnt / nr_parts) : 0; |
1513 | bn = BATslice(b, part_nr * psz, (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz)); |
1514 | if(bn == NULL) |
1515 | throw(SQL, "sql.bindidx" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1516 | BAThseqbase(bn, part_nr * psz); |
1517 | } else { |
1518 | /* BAT b holds the UPD_ID bat */ |
1519 | oid l, h; |
1520 | BAT *c = mvc_bind_idxbat(m, sname, tname, iname, 0); |
1521 | if ( c == NULL) { |
1522 | BBPunfix(b->batCacheid); |
1523 | throw(SQL,"sql.bindidx" ,SQLSTATE(42000) "Cannot access index column %s.%s.%s" ,sname,tname,iname); |
1524 | } |
1525 | cnt = BATcount(c); |
1526 | psz = cnt ? (cnt / nr_parts) : 0; |
1527 | l = part_nr * psz; |
1528 | h = (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz); |
1529 | h--; |
1530 | bn = BATselect(b, NULL, &l, &h, true, true, false); |
1531 | BBPunfix(c->batCacheid); |
1532 | if(bn == NULL) { |
1533 | BBPunfix(b->batCacheid); |
1534 | throw(SQL, "sql.bindidx" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1535 | } |
1536 | } |
1537 | BBPunfix(b->batCacheid); |
1538 | b = bn; |
1539 | } else if (upd) { |
1540 | BAT *uv = mvc_bind_idxbat(m, sname, tname, iname, RD_UPD_VAL); |
1541 | bat *uvl = getArgReference_bat(stk, pci, 1); |
1542 | if ( uv == NULL) |
1543 | throw(SQL,"sql.bindidx" ,SQLSTATE(42000) "Cannot access index column %s.%s.%s" ,sname,tname,iname); |
1544 | BBPkeepref(*bid = b->batCacheid); |
1545 | BBPkeepref(*uvl = uv->batCacheid); |
1546 | return MAL_SUCCEED; |
1547 | } |
1548 | if (upd) { |
1549 | bat *uvl = getArgReference_bat(stk, pci, 1); |
1550 | |
1551 | if (BATcount(b)) { |
1552 | BAT *uv = mvc_bind_idxbat(m, sname, tname, iname, RD_UPD_VAL); |
1553 | BAT *ui = mvc_bind_idxbat(m, sname, tname, iname, RD_UPD_ID); |
1554 | BAT *id, *vl; |
1555 | if ( ui == NULL || uv == NULL) { |
1556 | bat_destroy(uv); |
1557 | bat_destroy(ui); |
1558 | throw(SQL,"sql.bindidx" ,SQLSTATE(42000) "Cannot access index column %s.%s.%s" ,sname,tname,iname); |
1559 | } |
1560 | id = BATproject(b, ui); |
1561 | vl = BATproject(b, uv); |
1562 | bat_destroy(ui); |
1563 | bat_destroy(uv); |
1564 | if (id == NULL || vl == NULL) { |
1565 | bat_destroy(id); |
1566 | bat_destroy(vl); |
1567 | throw(SQL, "sql.idxbind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1568 | } |
1569 | assert(BATcount(id) == BATcount(vl)); |
1570 | BBPkeepref(*bid = id->batCacheid); |
1571 | BBPkeepref(*uvl = vl->batCacheid); |
1572 | } else { |
1573 | sql_schema *s = mvc_bind_schema(m, sname); |
1574 | sql_idx *i = mvc_bind_idx(m, s, iname); |
1575 | |
1576 | *bid = e_bat(TYPE_oid); |
1577 | *uvl = e_bat((i->type==join_idx)?TYPE_oid:TYPE_lng); |
1578 | if(*bid == BID_NIL || *uvl == BID_NIL) |
1579 | throw(SQL, "sql.idxbind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1580 | } |
1581 | BBPunfix(b->batCacheid); |
1582 | } else { |
1583 | BBPkeepref(*bid = b->batCacheid); |
1584 | } |
1585 | return MAL_SUCCEED; |
1586 | } |
1587 | if (sname) |
1588 | throw(SQL, "sql.idxbind" , SQLSTATE(HY005) "Cannot access column descriptor %s for %s.%s" , iname, sname, tname); |
1589 | throw(SQL, "sql.idxbind" , SQLSTATE(HY005) "Cannot access column descriptor %s for %s" , iname, tname); |
1590 | } |
1591 | |
1592 | str |
1593 | mvc_append_column(sql_trans *t, sql_column *c, BAT *ins) |
1594 | { |
1595 | int res = store_funcs.append_col(t, c, ins, TYPE_bat); |
1596 | if (res != 0) |
1597 | throw(SQL, "sql.append" , SQLSTATE(42000) "Cannot append values" ); |
1598 | return MAL_SUCCEED; |
1599 | } |
1600 | |
1601 | /*mvc_grow_wrap(int *bid, str *sname, str *tname, str *cname, ptr d) */ |
1602 | str |
1603 | mvc_grow_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1604 | { |
1605 | int *res = getArgReference_int(stk, pci, 0); |
1606 | bat Tid = *getArgReference_bat(stk, pci, 1); |
1607 | ptr Ins = getArgReference(stk, pci, 2); |
1608 | int tpe = getArgType(mb, pci, 2); |
1609 | BAT *tid = 0, *ins = 0; |
1610 | size_t cnt = 1; |
1611 | oid v = 0; |
1612 | |
1613 | (void)cntxt; |
1614 | *res = 0; |
1615 | if ((tid = BATdescriptor(Tid)) == NULL) |
1616 | throw(SQL, "sql.grow" , SQLSTATE(HY005) "Cannot access descriptor" ); |
1617 | if (tpe > GDKatomcnt) |
1618 | tpe = TYPE_bat; |
1619 | if (tpe == TYPE_bat && (ins = BATdescriptor(*(bat *) Ins)) == NULL) { |
1620 | BBPunfix(Tid); |
1621 | throw(SQL, "sql.grow" , SQLSTATE(HY005) "Cannot access descriptor" ); |
1622 | } |
1623 | if (ins) { |
1624 | cnt = BATcount(ins); |
1625 | BBPunfix(ins->batCacheid); |
1626 | } |
1627 | if (BATcount(tid)) { |
1628 | (void)BATmax(tid, &v); |
1629 | v++; |
1630 | } |
1631 | for(;cnt>0; cnt--, v++) { |
1632 | if (BUNappend(tid, &v, false) != GDK_SUCCEED) { |
1633 | BBPunfix(Tid); |
1634 | throw(SQL, "sql" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
1635 | } |
1636 | } |
1637 | BBPunfix(Tid); |
1638 | return MAL_SUCCEED; |
1639 | } |
1640 | |
1641 | /*mvc_append_wrap(int *bid, str *sname, str *tname, str *cname, ptr d) */ |
1642 | str |
1643 | mvc_append_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1644 | { |
1645 | int *res = getArgReference_int(stk, pci, 0); |
1646 | mvc *m = NULL; |
1647 | str msg; |
1648 | const char *sname = *getArgReference_str(stk, pci, 2); |
1649 | const char *tname = *getArgReference_str(stk, pci, 3); |
1650 | const char *cname = *getArgReference_str(stk, pci, 4); |
1651 | ptr ins = getArgReference(stk, pci, 5); |
1652 | int tpe = getArgType(mb, pci, 5); |
1653 | sql_schema *s; |
1654 | sql_table *t; |
1655 | sql_column *c; |
1656 | BAT *b = 0; |
1657 | |
1658 | *res = 0; |
1659 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1660 | return msg; |
1661 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1662 | return msg; |
1663 | if (tpe > GDKatomcnt) |
1664 | tpe = TYPE_bat; |
1665 | if (tpe == TYPE_bat && (ins = BATdescriptor(*(bat *) ins)) == NULL) |
1666 | throw(SQL, "sql.append" , SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s" , |
1667 | sname,tname,cname); |
1668 | if (ATOMextern(tpe)) |
1669 | ins = *(ptr *) ins; |
1670 | if ( tpe == TYPE_bat) |
1671 | b = (BAT*) ins; |
1672 | s = mvc_bind_schema(m, sname); |
1673 | if (s == NULL) { |
1674 | if (b) |
1675 | BBPunfix(b->batCacheid); |
1676 | throw(SQL, "sql.append" , SQLSTATE(3F000) "Schema missing %s" ,sname); |
1677 | } |
1678 | t = mvc_bind_table(m, s, tname); |
1679 | if (t == NULL) { |
1680 | if (b) |
1681 | BBPunfix(b->batCacheid); |
1682 | throw(SQL, "sql.append" , SQLSTATE(42S02) "Table missing %s" ,tname); |
1683 | } |
1684 | if( b && BATcount(b) > 4096 && !b->batTransient) |
1685 | BATmsync(b); |
1686 | if (cname[0] != '%' && (c = mvc_bind_column(m, t, cname)) != NULL) { |
1687 | store_funcs.append_col(m->session->tr, c, ins, tpe); |
1688 | } else if (cname[0] == '%') { |
1689 | sql_idx *i = mvc_bind_idx(m, s, cname + 1); |
1690 | if (i) |
1691 | store_funcs.append_idx(m->session->tr, i, ins, tpe); |
1692 | } |
1693 | if (b) { |
1694 | BBPunfix(b->batCacheid); |
1695 | } |
1696 | return MAL_SUCCEED; |
1697 | } |
1698 | |
1699 | /*mvc_update_wrap(int *bid, str *sname, str *tname, str *cname, ptr d) */ |
1700 | str |
1701 | mvc_update_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1702 | { |
1703 | int *res = getArgReference_int(stk, pci, 0); |
1704 | mvc *m = NULL; |
1705 | str msg; |
1706 | const char *sname = *getArgReference_str(stk, pci, 2); |
1707 | const char *tname = *getArgReference_str(stk, pci, 3); |
1708 | const char *cname = *getArgReference_str(stk, pci, 4); |
1709 | bat Tids = *getArgReference_bat(stk, pci, 5); |
1710 | bat Upd = *getArgReference_bat(stk, pci, 6); |
1711 | BAT *tids, *upd; |
1712 | int tpe = getArgType(mb, pci, 6); |
1713 | sql_schema *s; |
1714 | sql_table *t; |
1715 | sql_column *c; |
1716 | |
1717 | *res = 0; |
1718 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1719 | return msg; |
1720 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1721 | return msg; |
1722 | if (tpe > TYPE_any) |
1723 | tpe = TYPE_bat; |
1724 | else |
1725 | assert(0); |
1726 | if (tpe != TYPE_bat) |
1727 | throw(SQL, "sql.update" , SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s" , |
1728 | sname,tname,cname); |
1729 | if ((tids = BATdescriptor(Tids)) == NULL) |
1730 | throw(SQL, "sql.update" , SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s" , |
1731 | sname,tname,cname); |
1732 | if ((upd = BATdescriptor(Upd)) == NULL) { |
1733 | BBPunfix(tids->batCacheid); |
1734 | throw(SQL, "sql.update" , SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s" , |
1735 | sname,tname,cname); |
1736 | } |
1737 | s = mvc_bind_schema(m, sname); |
1738 | if (s == NULL) { |
1739 | BBPunfix(tids->batCacheid); |
1740 | BBPunfix(upd->batCacheid); |
1741 | throw(SQL, "sql.update" , SQLSTATE(3F000) "Schema missing %s" ,sname); |
1742 | } |
1743 | t = mvc_bind_table(m, s, tname); |
1744 | if (t == NULL) { |
1745 | BBPunfix(tids->batCacheid); |
1746 | BBPunfix(upd->batCacheid); |
1747 | throw(SQL, "sql.update" , SQLSTATE(42S02) "Table missing %s.%s" ,sname,tname); |
1748 | } |
1749 | if( upd && BATcount(upd) > 4096 && !upd->batTransient) |
1750 | BATmsync(upd); |
1751 | if( tids && BATcount(tids) > 4096 && !tids->batTransient) |
1752 | BATmsync(tids); |
1753 | if (cname[0] != '%' && (c = mvc_bind_column(m, t, cname)) != NULL) { |
1754 | store_funcs.update_col(m->session->tr, c, tids, upd, TYPE_bat); |
1755 | } else if (cname[0] == '%') { |
1756 | sql_idx *i = mvc_bind_idx(m, s, cname + 1); |
1757 | if (i) |
1758 | store_funcs.update_idx(m->session->tr, i, tids, upd, TYPE_bat); |
1759 | } |
1760 | BBPunfix(tids->batCacheid); |
1761 | BBPunfix(upd->batCacheid); |
1762 | return MAL_SUCCEED; |
1763 | } |
1764 | |
1765 | /* str mvc_clear_table_wrap(lng *res, str *sname, str *tname); */ |
1766 | str |
1767 | mvc_clear_table_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1768 | { |
1769 | sql_schema *s; |
1770 | sql_table *t; |
1771 | mvc *m = NULL; |
1772 | str msg; |
1773 | lng *res = getArgReference_lng(stk, pci, 0); |
1774 | const char *sname = *getArgReference_str(stk, pci, 1); |
1775 | const char *tname = *getArgReference_str(stk, pci, 2); |
1776 | |
1777 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1778 | return msg; |
1779 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1780 | return msg; |
1781 | s = mvc_bind_schema(m, sname); |
1782 | if (s == NULL) |
1783 | throw(SQL, "sql.clear_table" , SQLSTATE(3F000) "Schema missing %s" , sname); |
1784 | t = mvc_bind_table(m, s, tname); |
1785 | if (t == NULL) |
1786 | throw(SQL, "sql.clear_table" , SQLSTATE(42S02) "Table missing %s.%s" , sname,tname); |
1787 | *res = mvc_clear_table(m, t); |
1788 | return MAL_SUCCEED; |
1789 | } |
1790 | |
1791 | /*mvc_delete_wrap(int *d, str *sname, str *tname, ptr d) */ |
1792 | str |
1793 | mvc_delete_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
1794 | { |
1795 | int *res = getArgReference_int(stk, pci, 0); |
1796 | mvc *m = NULL; |
1797 | str msg; |
1798 | const char *sname = *getArgReference_str(stk, pci, 2); |
1799 | const char *tname = *getArgReference_str(stk, pci, 3); |
1800 | ptr ins = getArgReference(stk, pci, 4); |
1801 | int tpe = getArgType(mb, pci, 4); |
1802 | BAT *b = NULL; |
1803 | |
1804 | sql_schema *s; |
1805 | sql_table *t; |
1806 | |
1807 | *res = 0; |
1808 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
1809 | return msg; |
1810 | if ((msg = checkSQLContext(cntxt)) != NULL) |
1811 | return msg; |
1812 | if (tpe > TYPE_any) |
1813 | tpe = TYPE_bat; |
1814 | if (tpe == TYPE_bat && (b = BATdescriptor(*(bat *) ins)) == NULL) |
1815 | throw(SQL, "sql.delete" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
1816 | if (tpe != TYPE_bat || (b->ttype != TYPE_oid && b->ttype != TYPE_void)) { |
1817 | if (b) |
1818 | BBPunfix(b->batCacheid); |
1819 | throw(SQL, "sql.delete" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
1820 | } |
1821 | s = mvc_bind_schema(m, sname); |
1822 | if (s == NULL) { |
1823 | if (b) |
1824 | BBPunfix(b->batCacheid); |
1825 | throw(SQL, "sql.delete" , SQLSTATE(3F000) "Schema missing %s" ,sname); |
1826 | } |
1827 | t = mvc_bind_table(m, s, tname); |
1828 | if (t == NULL) { |
1829 | if (b) |
1830 | BBPunfix(b->batCacheid); |
1831 | throw(SQL, "sql.delete" , SQLSTATE(42S02) "Table missing %s.%s" ,sname,tname); |
1832 | } |
1833 | if( b && BATcount(b) > 4096 && !b->batTransient) |
1834 | BATmsync(b); |
1835 | store_funcs.delete_tab(m->session->tr, t, b, tpe); |
1836 | if (b) |
1837 | BBPunfix(b->batCacheid); |
1838 | return MAL_SUCCEED; |
1839 | } |
1840 | |
1841 | static BAT * |
1842 | setwritable(BAT *b) |
1843 | { |
1844 | BAT *bn = b; |
1845 | |
1846 | if (BATsetaccess(b, BAT_WRITE) != GDK_SUCCEED) { |
1847 | if (b->batSharecnt) { |
1848 | bn = COLcopy(b, b->ttype, true, TRANSIENT); |
1849 | if (bn != NULL) |
1850 | if (BATsetaccess(bn, BAT_WRITE) != GDK_SUCCEED) { |
1851 | BBPreclaim(bn); |
1852 | bn = NULL; |
1853 | } |
1854 | } else { |
1855 | bn = NULL; |
1856 | } |
1857 | BBPunfix(b->batCacheid); |
1858 | } |
1859 | return bn; |
1860 | } |
1861 | |
1862 | str |
1863 | DELTAbat2(bat *result, const bat *col, const bat *uid, const bat *uval) |
1864 | { |
1865 | return DELTAbat(result, col, uid, uval, NULL); |
1866 | } |
1867 | |
1868 | str |
1869 | DELTAsub2(bat *result, const bat *col, const bat *cid, const bat *uid, const bat *uval) |
1870 | { |
1871 | return DELTAsub(result, col, cid, uid, uval, NULL); |
1872 | } |
1873 | |
1874 | str |
1875 | DELTAproject2(bat *result, const bat *sub, const bat *col, const bat *uid, const bat *uval) |
1876 | { |
1877 | return DELTAproject(result, sub, col, uid, uval, NULL); |
1878 | } |
1879 | |
1880 | str |
1881 | DELTAbat(bat *result, const bat *col, const bat *uid, const bat *uval, const bat *ins) |
1882 | { |
1883 | BAT *c, *u_id, *u_val, *i = NULL, *res; |
1884 | |
1885 | if ((u_id = BBPquickdesc(*uid, false)) == NULL) |
1886 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1887 | if (ins && (i = BBPquickdesc(*ins, false)) == NULL) |
1888 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1889 | |
1890 | /* no updates, no inserts */ |
1891 | if (BATcount(u_id) == 0 && (!i || BATcount(i) == 0)) { |
1892 | BBPretain(*result = *col); |
1893 | return MAL_SUCCEED; |
1894 | } |
1895 | |
1896 | if ((c = BBPquickdesc(*col, false)) == NULL) |
1897 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1898 | |
1899 | /* bat may change */ |
1900 | if (i && BATcount(c) == 0 && BATcount(u_id) == 0) { |
1901 | BBPretain(*result = *ins); |
1902 | return MAL_SUCCEED; |
1903 | } |
1904 | |
1905 | c = BATdescriptor(*col); |
1906 | if (c == NULL) |
1907 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1908 | if ((res = COLcopy(c, c->ttype, true, TRANSIENT)) == NULL) { |
1909 | BBPunfix(c->batCacheid); |
1910 | throw(MAL, "sql.delta" , SQLSTATE(45002) "Cannot create copy of delta structure" ); |
1911 | } |
1912 | BBPunfix(c->batCacheid); |
1913 | |
1914 | if ((u_val = BATdescriptor(*uval)) == NULL) { |
1915 | BBPunfix(res->batCacheid); |
1916 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1917 | } |
1918 | if ((u_id = BATdescriptor(*uid)) == NULL) { |
1919 | BBPunfix(u_val->batCacheid); |
1920 | BBPunfix(res->batCacheid); |
1921 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1922 | } |
1923 | assert(BATcount(u_id) == BATcount(u_val)); |
1924 | if (BATcount(u_id) && |
1925 | BATreplace(res, u_id, u_val, true) != GDK_SUCCEED) { |
1926 | BBPunfix(u_id->batCacheid); |
1927 | BBPunfix(u_val->batCacheid); |
1928 | BBPunfix(res->batCacheid); |
1929 | throw(MAL, "sql.delta" , SQLSTATE(45002) "Cannot access delta structure" ); |
1930 | } |
1931 | BBPunfix(u_id->batCacheid); |
1932 | BBPunfix(u_val->batCacheid); |
1933 | |
1934 | if (i && BATcount(i)) { |
1935 | if ((i = BATdescriptor(*ins)) == NULL) { |
1936 | BBPunfix(res->batCacheid); |
1937 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1938 | } |
1939 | if (BATappend(res, i, NULL, true) != GDK_SUCCEED) { |
1940 | BBPunfix(res->batCacheid); |
1941 | BBPunfix(i->batCacheid); |
1942 | throw(MAL, "sql.delta" , SQLSTATE(45002) "Cannot access delta structure" ); |
1943 | } |
1944 | BBPunfix(i->batCacheid); |
1945 | } |
1946 | |
1947 | BBPkeepref(*result = res->batCacheid); |
1948 | return MAL_SUCCEED; |
1949 | } |
1950 | |
1951 | str |
1952 | DELTAsub(bat *result, const bat *col, const bat *cid, const bat *uid, const bat *uval, const bat *ins) |
1953 | { |
1954 | BAT *c, *cminu = NULL, *u_id, *u_val, *u, *i = NULL, *res; |
1955 | gdk_return ret; |
1956 | |
1957 | if ((u_id = BBPquickdesc(*uid, false)) == NULL) |
1958 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1959 | if (ins && (i = BBPquickdesc(*ins, false)) == NULL) |
1960 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1961 | |
1962 | /* no updates, no inserts */ |
1963 | if (BATcount(u_id) == 0 && (!i || BATcount(i) == 0)) { |
1964 | BBPretain(*result = *col); |
1965 | return MAL_SUCCEED; |
1966 | } |
1967 | |
1968 | if ((c = BBPquickdesc(*col, false)) == NULL) |
1969 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1970 | |
1971 | /* bat may change */ |
1972 | if (i && BATcount(c) == 0 && BATcount(u_id) == 0) { |
1973 | BBPretain(*result = *ins); |
1974 | return MAL_SUCCEED; |
1975 | } |
1976 | |
1977 | c = BATdescriptor(*col); |
1978 | if (c == NULL) |
1979 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1980 | res = c; |
1981 | if (BATcount(u_id)) { |
1982 | u_id = BATdescriptor(*uid); |
1983 | if (!u_id) { |
1984 | BBPunfix(c->batCacheid); |
1985 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
1986 | } |
1987 | cminu = BATdiff(c, u_id, NULL, NULL, false, false, BUN_NONE); |
1988 | if (!cminu) { |
1989 | BBPunfix(c->batCacheid); |
1990 | BBPunfix(u_id->batCacheid); |
1991 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL " intermediate" ); |
1992 | } |
1993 | res = BATproject(cminu, c); |
1994 | BBPunfix(c->batCacheid); |
1995 | BBPunfix(cminu->batCacheid); |
1996 | cminu = NULL; |
1997 | if (!res) { |
1998 | BBPunfix(u_id->batCacheid); |
1999 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL " intermediate" ); |
2000 | } |
2001 | c = res; |
2002 | |
2003 | if ((u_val = BATdescriptor(*uval)) == NULL) { |
2004 | BBPunfix(c->batCacheid); |
2005 | BBPunfix(u_id->batCacheid); |
2006 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2007 | } |
2008 | if (BATcount(u_val)) { |
2009 | u = BATproject(u_val, u_id); |
2010 | BBPunfix(u_val->batCacheid); |
2011 | BBPunfix(u_id->batCacheid); |
2012 | if (!u) { |
2013 | BBPunfix(c->batCacheid); |
2014 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2015 | } |
2016 | |
2017 | /* check selected updated values against candidates */ |
2018 | BAT *c_ids = BATdescriptor(*cid); |
2019 | |
2020 | if (!c_ids) { |
2021 | BBPunfix(c->batCacheid); |
2022 | BBPunfix(u->batCacheid); |
2023 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2024 | } |
2025 | cminu = BATintersect(u, c_ids, NULL, NULL, false, BUN_NONE); |
2026 | BBPunfix(c_ids->batCacheid); |
2027 | if (cminu == NULL) { |
2028 | BBPunfix(c->batCacheid); |
2029 | BBPunfix(u->batCacheid); |
2030 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2031 | } |
2032 | ret = BATappend(res, u, cminu, true); |
2033 | BBPunfix(u->batCacheid); |
2034 | if (cminu) |
2035 | BBPunfix(cminu->batCacheid); |
2036 | cminu = NULL; |
2037 | if (ret != GDK_SUCCEED) { |
2038 | BBPunfix(res->batCacheid); |
2039 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2040 | } |
2041 | |
2042 | ret = BATsort(&u, NULL, NULL, res, NULL, NULL, false, false, false); |
2043 | BBPunfix(res->batCacheid); |
2044 | if (ret != GDK_SUCCEED) { |
2045 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2046 | } |
2047 | res = u; |
2048 | } else { |
2049 | BBPunfix(u_val->batCacheid); |
2050 | BBPunfix(u_id->batCacheid); |
2051 | } |
2052 | } |
2053 | |
2054 | if (i) { |
2055 | i = BATdescriptor(*ins); |
2056 | if (!i) { |
2057 | BBPunfix(res->batCacheid); |
2058 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2059 | } |
2060 | if (BATcount(u_id)) { |
2061 | u_id = BATdescriptor(*uid); |
2062 | if (!u_id) { |
2063 | BBPunfix(res->batCacheid); |
2064 | BBPunfix(i->batCacheid); |
2065 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2066 | } |
2067 | cminu = BATdiff(i, u_id, NULL, NULL, false, false, BUN_NONE); |
2068 | BBPunfix(u_id->batCacheid); |
2069 | if (!cminu) { |
2070 | BBPunfix(res->batCacheid); |
2071 | BBPunfix(i->batCacheid); |
2072 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2073 | } |
2074 | } |
2075 | if (isVIEW(res)) { |
2076 | BAT *n = COLcopy(res, res->ttype, true, TRANSIENT); |
2077 | BBPunfix(res->batCacheid); |
2078 | res = n; |
2079 | if (res == NULL) { |
2080 | BBPunfix(i->batCacheid); |
2081 | if (cminu) |
2082 | BBPunfix(cminu->batCacheid); |
2083 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2084 | } |
2085 | } |
2086 | ret = BATappend(res, i, cminu, true); |
2087 | BBPunfix(i->batCacheid); |
2088 | if (cminu) |
2089 | BBPunfix(cminu->batCacheid); |
2090 | if (ret != GDK_SUCCEED) { |
2091 | BBPunfix(res->batCacheid); |
2092 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2093 | } |
2094 | |
2095 | ret = BATsort(&u, NULL, NULL, res, NULL, NULL, false, false, false); |
2096 | BBPunfix(res->batCacheid); |
2097 | if (ret != GDK_SUCCEED) |
2098 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2099 | res = u; |
2100 | } |
2101 | BATkey(res, true); |
2102 | BBPkeepref(*result = res->batCacheid); |
2103 | return MAL_SUCCEED; |
2104 | } |
2105 | |
2106 | str |
2107 | DELTAproject(bat *result, const bat *sub, const bat *col, const bat *uid, const bat *uval, const bat *ins) |
2108 | { |
2109 | BAT *s, *c, *u_id, *u_val, *i = NULL, *res, *tres; |
2110 | |
2111 | if ((s = BATdescriptor(*sub)) == NULL) |
2112 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2113 | |
2114 | if (ins && (i = BATdescriptor(*ins)) == NULL) { |
2115 | BBPunfix(s->batCacheid); |
2116 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2117 | } |
2118 | |
2119 | if (i && BATcount(s) == 0) { |
2120 | res = BATproject(s, i); |
2121 | BBPunfix(s->batCacheid); |
2122 | BBPunfix(i->batCacheid); |
2123 | if (res == NULL) |
2124 | throw(MAL, "sql.projectdelta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2125 | |
2126 | BBPkeepref(*result = res->batCacheid); |
2127 | return MAL_SUCCEED; |
2128 | } |
2129 | |
2130 | if ((c = BATdescriptor(*col)) == NULL) { |
2131 | BBPunfix(s->batCacheid); |
2132 | if (i) |
2133 | BBPunfix(i->batCacheid); |
2134 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2135 | } |
2136 | |
2137 | /* projection(sub,col).union(projection(sub,i)) */ |
2138 | res = c; |
2139 | if (i && BATcount(i)) { |
2140 | if (BATcount(c) == 0) { |
2141 | res = i; |
2142 | i = c; |
2143 | } else { |
2144 | if ((res = COLcopy(c, c->ttype, true, TRANSIENT)) == NULL) { |
2145 | BBPunfix(s->batCacheid); |
2146 | BBPunfix(i->batCacheid); |
2147 | BBPunfix(c->batCacheid); |
2148 | throw(MAL, "sql.projectdelta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2149 | } |
2150 | BBPunfix(c->batCacheid); |
2151 | if (BATappend(res, i, NULL, false) != GDK_SUCCEED) { |
2152 | BBPunfix(s->batCacheid); |
2153 | BBPunfix(i->batCacheid); |
2154 | throw(MAL, "sql.projectdelta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2155 | } |
2156 | } |
2157 | } |
2158 | if (i) |
2159 | BBPunfix(i->batCacheid); |
2160 | |
2161 | tres = BATproject(s, res); |
2162 | BBPunfix(res->batCacheid); |
2163 | if (tres == NULL) { |
2164 | BBPunfix(s->batCacheid); |
2165 | throw(MAL, "sql.projectdelta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2166 | } |
2167 | res = tres; |
2168 | |
2169 | if ((u_id = BATdescriptor(*uid)) == NULL) { |
2170 | BBPunfix(res->batCacheid); |
2171 | BBPunfix(s->batCacheid); |
2172 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2173 | } |
2174 | if (!BATcount(u_id)) { |
2175 | BBPunfix(u_id->batCacheid); |
2176 | BBPunfix(s->batCacheid); |
2177 | BBPkeepref(*result = res->batCacheid); |
2178 | return MAL_SUCCEED; |
2179 | } |
2180 | if ((u_val = BATdescriptor(*uval)) == NULL) { |
2181 | BBPunfix(u_id->batCacheid); |
2182 | BBPunfix(res->batCacheid); |
2183 | BBPunfix(s->batCacheid); |
2184 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2185 | } |
2186 | |
2187 | if (BATcount(u_val)) { |
2188 | BAT *os, *ou; |
2189 | /* figure out the positions in res that we have to |
2190 | * replace with values from u_val */ |
2191 | if (BATsemijoin(&ou, &os, u_id, s, NULL, NULL, false, BUN_NONE) != GDK_SUCCEED) { |
2192 | BBPunfix(s->batCacheid); |
2193 | BBPunfix(res->batCacheid); |
2194 | BBPunfix(u_id->batCacheid); |
2195 | BBPunfix(u_val->batCacheid); |
2196 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2197 | } |
2198 | /* BATcount(ou) == BATcount(os) */ |
2199 | if (BATcount(ou) != 0) { |
2200 | /* ou contains the position in u_id/u_val that |
2201 | * contain the new values */ |
2202 | BAT *nu_val = BATproject(ou, u_val); |
2203 | BBPunfix(ou->batCacheid); |
2204 | /* os contains the corresponding positions in |
2205 | * res that need to be replaced with those new |
2206 | * values */ |
2207 | if ((res = setwritable(res)) == NULL || |
2208 | BATreplace(res, os, nu_val, false) != GDK_SUCCEED) { |
2209 | if (res) |
2210 | BBPunfix(res->batCacheid); |
2211 | BBPunfix(os->batCacheid); |
2212 | BBPunfix(s->batCacheid); |
2213 | BBPunfix(u_id->batCacheid); |
2214 | BBPunfix(u_val->batCacheid); |
2215 | BBPunfix(nu_val->batCacheid); |
2216 | throw(MAL, "sql.delta" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2217 | } |
2218 | BBPunfix(nu_val->batCacheid); |
2219 | } else { |
2220 | /* nothing to replace */ |
2221 | BBPunfix(ou->batCacheid); |
2222 | } |
2223 | BBPunfix(os->batCacheid); |
2224 | } |
2225 | BBPunfix(s->batCacheid); |
2226 | BBPunfix(u_id->batCacheid); |
2227 | BBPunfix(u_val->batCacheid); |
2228 | |
2229 | BBPkeepref(*result = res->batCacheid); |
2230 | return MAL_SUCCEED; |
2231 | } |
2232 | |
2233 | str |
2234 | BATleftproject(bat *Res, const bat *Col, const bat *L, const bat *R) |
2235 | { |
2236 | BAT *c, *l, *r, *res; |
2237 | oid *p, *lp, *rp; |
2238 | BUN cnt = 0, i; |
2239 | |
2240 | c = BATdescriptor(*Col); |
2241 | if (c) |
2242 | cnt = BATcount(c); |
2243 | l = BATdescriptor(*L); |
2244 | r = BATdescriptor(*R); |
2245 | res = COLnew(0, TYPE_oid, cnt, TRANSIENT); |
2246 | if (!c || !l || !r || !res) { |
2247 | if (c) |
2248 | BBPunfix(c->batCacheid); |
2249 | if (l) |
2250 | BBPunfix(l->batCacheid); |
2251 | if (r) |
2252 | BBPunfix(r->batCacheid); |
2253 | if (res) |
2254 | BBPunfix(res->batCacheid); |
2255 | throw(MAL, "sql.delta" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
2256 | } |
2257 | p = (oid*)Tloc(res,0); |
2258 | for(i=0;i<cnt; i++) |
2259 | *p++ = oid_nil; |
2260 | BATsetcount(res, cnt); |
2261 | |
2262 | cnt = BATcount(l); |
2263 | p = (oid*)Tloc(res, 0); |
2264 | lp = (oid*)Tloc(l, 0); |
2265 | rp = (oid*)Tloc(r, 0); |
2266 | if (l->ttype == TYPE_void) { |
2267 | oid lp = l->tseqbase; |
2268 | if (r->ttype == TYPE_void) { |
2269 | oid rp = r->tseqbase; |
2270 | for(i=0;i<cnt; i++, lp++, rp++) |
2271 | p[lp] = rp; |
2272 | } else { |
2273 | for(i=0;i<cnt; i++, lp++) |
2274 | p[lp] = rp[i]; |
2275 | } |
2276 | } |
2277 | if (r->ttype == TYPE_void) { |
2278 | oid rp = r->tseqbase; |
2279 | for(i=0;i<cnt; i++, rp++) |
2280 | p[lp[i]] = rp; |
2281 | } else { |
2282 | for(i=0;i<cnt; i++) |
2283 | p[lp[i]] = rp[i]; |
2284 | } |
2285 | res->tsorted = false; |
2286 | res->trevsorted = false; |
2287 | res->tnil = false; |
2288 | res->tnonil = false; |
2289 | res->tkey = false; |
2290 | BBPunfix(c->batCacheid); |
2291 | BBPunfix(l->batCacheid); |
2292 | BBPunfix(r->batCacheid); |
2293 | BBPkeepref(*Res = res->batCacheid); |
2294 | return MAL_SUCCEED; |
2295 | } |
2296 | |
2297 | /* str SQLtid(bat *result, mvc *m, str *sname, str *tname) */ |
2298 | str |
2299 | SQLtid(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2300 | { |
2301 | bat *res = getArgReference_bat(stk, pci, 0); |
2302 | mvc *m = NULL; |
2303 | str msg = MAL_SUCCEED; |
2304 | sql_trans *tr; |
2305 | const char *sname = *getArgReference_str(stk, pci, 2); |
2306 | const char *tname = *getArgReference_str(stk, pci, 3); |
2307 | |
2308 | sql_schema *s; |
2309 | sql_table *t; |
2310 | sql_column *c; |
2311 | BAT *tids; |
2312 | size_t nr, inr = 0, dcnt; |
2313 | oid sb = 0; |
2314 | |
2315 | *res = bat_nil; |
2316 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
2317 | return msg; |
2318 | tr = m->session->tr; |
2319 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2320 | return msg; |
2321 | s = mvc_bind_schema(m, sname); |
2322 | if (s == NULL) |
2323 | throw(SQL, "sql.tid" , SQLSTATE(3F000) "Schema missing %s" ,sname); |
2324 | t = mvc_bind_table(m, s, tname); |
2325 | if (t == NULL) |
2326 | throw(SQL, "sql.tid" , SQLSTATE(42S02) "Table missing %s.%s" ,sname,tname); |
2327 | c = t->columns.set->h->data; |
2328 | |
2329 | nr = store_funcs.count_col(tr, c, 1); |
2330 | |
2331 | if (isTable(t) && t->access == TABLE_WRITABLE && (!isNew(t) /* alter */ ) && |
2332 | t->persistence == SQL_PERSIST && !t->commit_action) |
2333 | inr = store_funcs.count_col(tr, c, 0); |
2334 | nr -= inr; |
2335 | if (pci->argc == 6) { /* partitioned version */ |
2336 | size_t cnt = nr; |
2337 | int part_nr = *getArgReference_int(stk, pci, 4); |
2338 | int nr_parts = *getArgReference_int(stk, pci, 5); |
2339 | |
2340 | nr /= nr_parts; |
2341 | sb = (oid) (part_nr * nr); |
2342 | if (nr_parts == (part_nr + 1)) { /* last part gets the inserts */ |
2343 | nr = cnt - (part_nr * nr); /* keep rest */ |
2344 | nr += inr; |
2345 | } |
2346 | } else { |
2347 | nr += inr; |
2348 | } |
2349 | |
2350 | /* create void,void bat with length and oid's set */ |
2351 | tids = BATdense(sb, sb, (BUN) nr); |
2352 | if (tids == NULL) |
2353 | throw(SQL, "sql.tid" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2354 | |
2355 | /* V1 of the deleted list |
2356 | * 1) in case of deletes, bind_del, order it, put into a heap(of the tids bat) |
2357 | * 2) in mal recognize this type of bat. |
2358 | * 3) if function can handle it pass along, else fall back to first diff. |
2359 | * */ |
2360 | if ((dcnt = store_funcs.count_del(tr, t)) > 0) { |
2361 | BAT *d = store_funcs.bind_del(tr, t, RD_INS); |
2362 | |
2363 | if (d == NULL) { |
2364 | BBPunfix(tids->batCacheid); |
2365 | throw(SQL,"sql.tid" , SQLSTATE(45002) "Can not bind delete column" ); |
2366 | } |
2367 | |
2368 | #if 1 |
2369 | BAT *o; |
2370 | gdk_return ret = BATsort(&o, NULL, NULL, d, NULL, NULL, false, false, false); |
2371 | BBPunfix(d->batCacheid); |
2372 | if (ret != GDK_SUCCEED) |
2373 | throw(MAL, "sql.tids" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2374 | |
2375 | /* TODO handle dense o, ie full range out of the dense tids, could be at beginning or end (reduce range of tids) |
2376 | * else materialize */ |
2377 | /* copy into heap */ |
2378 | ret = BATnegcands(tids, o); |
2379 | BBPunfix(o->batCacheid); |
2380 | if (ret != GDK_SUCCEED) |
2381 | throw(MAL, "sql.tids" , SQLSTATE(45003) "TIDdeletes failed" ); |
2382 | #else |
2383 | BAT *diff; |
2384 | diff = BATdiff(tids, d, NULL, NULL, false, false, BUN_NONE); |
2385 | assert(pci->argc == 6 || BATcount(diff) == (nr-dcnt)); |
2386 | //if( !(pci->argc == 6 || BATcount(diff) == (nr-dcnt)) ) |
2387 | //msg = createException(SQL, "sql.tid", SQLSTATE(00000) "Invalid sqltid state argc=%d diff=" BUNFMT ", nr=%zd, dcnt=%zd", pci->argc, BATcount(diff), nr, dcnt); |
2388 | BBPunfix(d->batCacheid); |
2389 | BBPunfix(tids->batCacheid); |
2390 | if (diff == NULL) |
2391 | throw(SQL,"sql.tid" , SQLSTATE(45002) "Cannot subtract delete column" ); |
2392 | BAThseqbase(diff, sb); |
2393 | tids = diff; |
2394 | #endif |
2395 | } |
2396 | BBPkeepref(*res = tids->batCacheid); |
2397 | return msg; |
2398 | } |
2399 | |
2400 | /* unsafe pattern resultSet(tbl:bat[:str], attr:bat[:str], tpe:bat[:str], len:bat[:int],scale:bat[:int], cols:bat[:any]...) :int */ |
2401 | /* New result set rendering infrastructure */ |
2402 | |
2403 | static str |
2404 | mvc_result_set_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2405 | { |
2406 | int *res_id =getArgReference_int(stk,pci,0); |
2407 | bat tblId= *getArgReference_bat(stk, pci,1); |
2408 | bat atrId= *getArgReference_bat(stk, pci,2); |
2409 | bat tpeId= *getArgReference_bat(stk, pci,3); |
2410 | bat lenId= *getArgReference_bat(stk, pci,4); |
2411 | bat scaleId= *getArgReference_bat(stk, pci,5); |
2412 | bat bid; |
2413 | int i,res; |
2414 | str tblname, colname, tpename, msg= MAL_SUCCEED; |
2415 | int *digits, *scaledigits; |
2416 | oid o = 0; |
2417 | BATiter itertbl,iteratr,itertpe; |
2418 | mvc *m = NULL; |
2419 | BAT *b, *tbl, *atr, *tpe,*len,*scale; |
2420 | |
2421 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
2422 | return msg; |
2423 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2424 | return msg; |
2425 | bid = *getArgReference_bat(stk,pci,6); |
2426 | b = BATdescriptor(bid); |
2427 | if ( b == NULL) |
2428 | throw(MAL,"sql.resultset" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
2429 | res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 5), Q_TABLE, b); |
2430 | if (res < 0) |
2431 | msg = createException(SQL, "sql.resultSet" , SQLSTATE(45000) "Result table construction failed" ); |
2432 | BBPunfix(b->batCacheid); |
2433 | |
2434 | tbl = BATdescriptor(tblId); |
2435 | atr = BATdescriptor(atrId); |
2436 | tpe = BATdescriptor(tpeId); |
2437 | len = BATdescriptor(lenId); |
2438 | scale = BATdescriptor(scaleId); |
2439 | if( msg || tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL) |
2440 | goto wrapup_result_set; |
2441 | /* mimick the old rsColumn approach; */ |
2442 | itertbl = bat_iterator(tbl); |
2443 | iteratr = bat_iterator(atr); |
2444 | itertpe = bat_iterator(tpe); |
2445 | digits = (int*) Tloc(len,0); |
2446 | scaledigits = (int*) Tloc(scale,0); |
2447 | |
2448 | for( i = 6; msg == MAL_SUCCEED && i< pci->argc; i++, o++){ |
2449 | bid = *getArgReference_bat(stk,pci,i); |
2450 | tblname = BUNtvar(itertbl,o); |
2451 | colname = BUNtvar(iteratr,o); |
2452 | tpename = BUNtvar(itertpe,o); |
2453 | b = BATdescriptor(bid); |
2454 | if ( b == NULL) |
2455 | msg= createException(MAL,"sql.resultset" ,SQLSTATE(HY005) "Cannot access column descriptor " ); |
2456 | else if (mvc_result_column(m, tblname, colname, tpename, *digits++, *scaledigits++, b)) |
2457 | msg = createException(SQL, "sql.resultset" , SQLSTATE(42000) "Cannot access column descriptor %s.%s" ,tblname,colname); |
2458 | if( b) |
2459 | BBPunfix(bid); |
2460 | } |
2461 | /* now send it to the channel cntxt->fdout */ |
2462 | if (mvc_export_result(cntxt->sqlcontext, cntxt->fdout, res, true, mb->starttime, mb->optimize)) |
2463 | msg = createException(SQL, "sql.resultset" , SQLSTATE(45000) "Result set construction failed" ); |
2464 | mb->starttime = 0; |
2465 | mb->optimize = 0; |
2466 | wrapup_result_set: |
2467 | if( tbl) BBPunfix(tblId); |
2468 | if( atr) BBPunfix(atrId); |
2469 | if( tpe) BBPunfix(tpeId); |
2470 | if( len) BBPunfix(lenId); |
2471 | if( scale) BBPunfix(scaleId); |
2472 | return msg; |
2473 | } |
2474 | |
2475 | /* Copy the result set into a CSV file */ |
2476 | str |
2477 | mvc_export_table_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2478 | { |
2479 | int *res_id =getArgReference_int(stk,pci,0); |
2480 | const char *filename = *getArgReference_str(stk,pci,1); |
2481 | const char *format = *getArgReference_str(stk,pci,2); |
2482 | const char *tsep = *getArgReference_str(stk, pci, 3); |
2483 | const char *rsep = *getArgReference_str(stk, pci, 4); |
2484 | const char *ssep = *getArgReference_str(stk, pci, 5); |
2485 | const char *ns = *getArgReference_str(stk, pci, 6); |
2486 | int onclient = *getArgReference_int(stk, pci, 7); |
2487 | |
2488 | bat tblId= *getArgReference_bat(stk, pci,8); |
2489 | bat atrId= *getArgReference_bat(stk, pci,9); |
2490 | bat tpeId= *getArgReference_bat(stk, pci,10); |
2491 | bat lenId= *getArgReference_bat(stk, pci,11); |
2492 | bat scaleId= *getArgReference_bat(stk, pci,12); |
2493 | stream *s; |
2494 | bat bid; |
2495 | int i,res; |
2496 | str tblname, colname, tpename, msg= MAL_SUCCEED; |
2497 | int *digits, *scaledigits; |
2498 | oid o = 0; |
2499 | BATiter itertbl,iteratr,itertpe; |
2500 | mvc *m = NULL; |
2501 | BAT *order = NULL, *b = NULL, *tbl = NULL, *atr = NULL, *tpe = NULL,*len = NULL,*scale = NULL; |
2502 | res_table *t = NULL; |
2503 | bool tostdout; |
2504 | char buf[80]; |
2505 | ssize_t sz; |
2506 | |
2507 | (void) format; |
2508 | |
2509 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
2510 | return msg; |
2511 | |
2512 | if (onclient && !cntxt->filetrans) { |
2513 | throw(MAL, "sql.resultSet" , "cannot transfer files to client" ); |
2514 | } |
2515 | |
2516 | bid = *getArgReference_bat(stk,pci,13); |
2517 | order = BATdescriptor(bid); |
2518 | if ( order == NULL) |
2519 | throw(MAL,"sql.resultset" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
2520 | res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 12), Q_TABLE, order); |
2521 | t = m->results; |
2522 | if (res < 0){ |
2523 | msg = createException(SQL, "sql.resultSet" , SQLSTATE(45000) "Result set construction failed" ); |
2524 | goto wrapup_result_set1; |
2525 | } |
2526 | |
2527 | t->tsep = tsep; |
2528 | t->rsep = rsep; |
2529 | t->ssep = ssep; |
2530 | t->ns = ns; |
2531 | |
2532 | tbl = BATdescriptor(tblId); |
2533 | atr = BATdescriptor(atrId); |
2534 | tpe = BATdescriptor(tpeId); |
2535 | len = BATdescriptor(lenId); |
2536 | scale = BATdescriptor(scaleId); |
2537 | if( tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL) |
2538 | goto wrapup_result_set1; |
2539 | /* mimick the old rsColumn approach; */ |
2540 | itertbl = bat_iterator(tbl); |
2541 | iteratr = bat_iterator(atr); |
2542 | itertpe = bat_iterator(tpe); |
2543 | digits = (int*) Tloc(len,0); |
2544 | scaledigits = (int*) Tloc(scale,0); |
2545 | |
2546 | for( i = 13; msg == MAL_SUCCEED && i< pci->argc; i++, o++){ |
2547 | bid = *getArgReference_bat(stk,pci,i); |
2548 | tblname = BUNtvar(itertbl,o); |
2549 | colname = BUNtvar(iteratr,o); |
2550 | tpename = BUNtvar(itertpe,o); |
2551 | b = BATdescriptor(bid); |
2552 | if ( b == NULL) |
2553 | msg= createException(MAL,"sql.resultset" ,SQLSTATE(HY005) "Cannot access column descriptor" ); |
2554 | else if (mvc_result_column(m, tblname, colname, tpename, *digits++, *scaledigits++, b)) |
2555 | msg = createException(SQL, "sql.resultset" , SQLSTATE(42000) "Cannot access column descriptor %s.%s" ,tblname,colname); |
2556 | if( b) |
2557 | BBPunfix(bid); |
2558 | } |
2559 | if ( msg ) |
2560 | goto wrapup_result_set1; |
2561 | |
2562 | /* now select the file channel */ |
2563 | if ((tostdout = strcmp(filename,"stdout" ) == 0)) { |
2564 | s = cntxt->fdout; |
2565 | } else if (!onclient) { |
2566 | if ((s = open_wastream(filename)) == NULL || mnstr_errnr(s)) { |
2567 | msg= createException(IO, "streams.open" , SQLSTATE(42000) "could not open file '%s': %s" , |
2568 | filename?filename:"stdout" , strerror(errno)); |
2569 | close_stream(s); |
2570 | goto wrapup_result_set1; |
2571 | } |
2572 | } else { |
2573 | while (!m->scanner.rs->eof) |
2574 | bstream_next(m->scanner.rs); |
2575 | s = m->scanner.ws; |
2576 | mnstr_write(s, PROMPT3, sizeof(PROMPT3) - 1, 1); |
2577 | mnstr_printf(s, "w %s\n" , filename); |
2578 | mnstr_flush(s); |
2579 | if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) { |
2580 | /* non-empty line indicates failure on client */ |
2581 | msg = createException(IO, "streams.open" , "%s" , buf); |
2582 | /* deal with ridiculously long response from client */ |
2583 | while (buf[sz - 1] != '\n' && |
2584 | (sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 0) |
2585 | ; |
2586 | goto wrapup_result_set1; |
2587 | } |
2588 | } |
2589 | if (mvc_export_result(cntxt->sqlcontext, s, res, tostdout, mb->starttime, mb->optimize)) |
2590 | msg = createException(SQL, "sql.resultset" , SQLSTATE(45000) "Result set construction failed" ); |
2591 | mb->starttime = 0; |
2592 | mb->optimize = 0; |
2593 | if (onclient) { |
2594 | mnstr_flush(s); |
2595 | if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) { |
2596 | msg = createException(IO, "streams.open" , "%s" , buf); |
2597 | } |
2598 | while (sz > 0) |
2599 | sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf)); |
2600 | } else if (!tostdout) { |
2601 | close_stream(s); |
2602 | } |
2603 | wrapup_result_set1: |
2604 | BBPunfix(order->batCacheid); |
2605 | if( tbl) BBPunfix(tblId); |
2606 | if( atr) BBPunfix(atrId); |
2607 | if( tpe) BBPunfix(tpeId); |
2608 | if( len) BBPunfix(lenId); |
2609 | if( scale) BBPunfix(scaleId); |
2610 | return msg; |
2611 | } |
2612 | |
2613 | /* unsafe pattern resultSet(tbl:bat[:str], attr:bat[:str], tpe:bat[:str], len:bat[:int],scale:bat[:int], cols:any...) :int */ |
2614 | str |
2615 | mvc_row_result_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2616 | { |
2617 | int *res_id= getArgReference_int(stk, pci,0); |
2618 | bat tblId= *getArgReference_bat(stk, pci,1); |
2619 | bat atrId= *getArgReference_bat(stk, pci,2); |
2620 | bat tpeId= *getArgReference_bat(stk, pci,3); |
2621 | bat lenId= *getArgReference_bat(stk, pci,4); |
2622 | bat scaleId= *getArgReference_bat(stk, pci,5); |
2623 | int i, res; |
2624 | str tblname, colname, tpename, msg= MAL_SUCCEED; |
2625 | int *digits, *scaledigits; |
2626 | oid o = 0; |
2627 | BATiter itertbl,iteratr,itertpe; |
2628 | mvc *m = NULL; |
2629 | ptr v; |
2630 | int mtype; |
2631 | BAT *tbl, *atr, *tpe,*len,*scale; |
2632 | |
2633 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
2634 | return msg; |
2635 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2636 | return msg; |
2637 | res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 5), Q_TABLE, NULL); |
2638 | if (res < 0) |
2639 | throw(SQL, "sql.resultset" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2640 | |
2641 | tbl = BATdescriptor(tblId); |
2642 | atr = BATdescriptor(atrId); |
2643 | tpe = BATdescriptor(tpeId); |
2644 | len = BATdescriptor(lenId); |
2645 | scale = BATdescriptor(scaleId); |
2646 | if( tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL) |
2647 | goto wrapup_result_set; |
2648 | /* mimick the old rsColumn approach; */ |
2649 | itertbl = bat_iterator(tbl); |
2650 | iteratr = bat_iterator(atr); |
2651 | itertpe = bat_iterator(tpe); |
2652 | digits = (int*) Tloc(len,0); |
2653 | scaledigits = (int*) Tloc(scale,0); |
2654 | |
2655 | for( i = 6; msg == MAL_SUCCEED && i< pci->argc; i++, o++){ |
2656 | tblname = BUNtvar(itertbl,o); |
2657 | colname = BUNtvar(iteratr,o); |
2658 | tpename = BUNtvar(itertpe,o); |
2659 | |
2660 | v = getArgReference(stk, pci, i); |
2661 | mtype = getArgType(mb, pci, i); |
2662 | if (ATOMextern(mtype)) |
2663 | v = *(ptr *) v; |
2664 | if (mvc_result_value(m, tblname, colname, tpename, *digits++, *scaledigits++, v, mtype)) |
2665 | throw(SQL, "sql.rsColumn" , SQLSTATE(45000) "Result set construction failed" ); |
2666 | } |
2667 | if (mvc_export_result(cntxt->sqlcontext, cntxt->fdout, res, true, mb->starttime, mb->optimize)) |
2668 | msg = createException(SQL, "sql.resultset" , SQLSTATE(45000) "Result set construction failed" ); |
2669 | mb->starttime = 0; |
2670 | mb->optimize = 0; |
2671 | wrapup_result_set: |
2672 | if( tbl) BBPunfix(tblId); |
2673 | if( atr) BBPunfix(atrId); |
2674 | if( tpe) BBPunfix(tpeId); |
2675 | if( len) BBPunfix(lenId); |
2676 | if( scale) BBPunfix(scaleId); |
2677 | return msg; |
2678 | } |
2679 | |
2680 | str |
2681 | mvc_export_row_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2682 | { |
2683 | int *res_id= getArgReference_int(stk, pci,0); |
2684 | str filename = * getArgReference_str(stk,pci,1); |
2685 | const char *format = *getArgReference_str(stk,pci,2); |
2686 | const char *tsep = *getArgReference_str(stk, pci, 3); |
2687 | const char *rsep = *getArgReference_str(stk, pci, 4); |
2688 | const char *ssep = *getArgReference_str(stk, pci, 5); |
2689 | const char *ns = *getArgReference_str(stk, pci, 6); |
2690 | int onclient = *getArgReference_int(stk, pci, 7); |
2691 | |
2692 | bat tblId= *getArgReference_bat(stk, pci,8); |
2693 | bat atrId= *getArgReference_bat(stk, pci,9); |
2694 | bat tpeId= *getArgReference_bat(stk, pci,10); |
2695 | bat lenId= *getArgReference_bat(stk, pci,11); |
2696 | bat scaleId= *getArgReference_bat(stk, pci,12); |
2697 | |
2698 | int i, res; |
2699 | stream *s; |
2700 | str tblname, colname, tpename, msg= MAL_SUCCEED; |
2701 | int *digits, *scaledigits; |
2702 | oid o = 0; |
2703 | BATiter itertbl,iteratr,itertpe; |
2704 | mvc *m = NULL; |
2705 | res_table *t = NULL; |
2706 | ptr v; |
2707 | int mtype; |
2708 | BAT *tbl = NULL, *atr = NULL, *tpe = NULL,*len = NULL,*scale = NULL; |
2709 | bool tostdout; |
2710 | char buf[80]; |
2711 | ssize_t sz; |
2712 | |
2713 | (void) format; |
2714 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
2715 | return msg; |
2716 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2717 | return msg; |
2718 | if (onclient && !cntxt->filetrans) { |
2719 | throw(MAL, "sql.resultSet" , "cannot transfer files to client" ); |
2720 | } |
2721 | |
2722 | res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 12), Q_TABLE, NULL); |
2723 | |
2724 | t = m->results; |
2725 | if (res < 0){ |
2726 | msg = createException(SQL, "sql.resultSet" , SQLSTATE(45000) "Result set construction failed" ); |
2727 | goto wrapup_result_set; |
2728 | } |
2729 | |
2730 | t->tsep = tsep; |
2731 | t->rsep = rsep; |
2732 | t->ssep = ssep; |
2733 | t->ns = ns; |
2734 | |
2735 | tbl = BATdescriptor(tblId); |
2736 | atr = BATdescriptor(atrId); |
2737 | tpe = BATdescriptor(tpeId); |
2738 | len = BATdescriptor(lenId); |
2739 | scale = BATdescriptor(scaleId); |
2740 | if( msg || tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL) |
2741 | goto wrapup_result_set; |
2742 | /* mimick the old rsColumn approach; */ |
2743 | itertbl = bat_iterator(tbl); |
2744 | iteratr = bat_iterator(atr); |
2745 | itertpe = bat_iterator(tpe); |
2746 | digits = (int*) Tloc(len,0); |
2747 | scaledigits = (int*) Tloc(scale,0); |
2748 | |
2749 | for( i = 13; msg == MAL_SUCCEED && i< pci->argc; i++, o++){ |
2750 | tblname = BUNtvar(itertbl,o); |
2751 | colname = BUNtvar(iteratr,o); |
2752 | tpename = BUNtvar(itertpe,o); |
2753 | |
2754 | v = getArgReference(stk, pci, i); |
2755 | mtype = getArgType(mb, pci, i); |
2756 | if (ATOMextern(mtype)) |
2757 | v = *(ptr *) v; |
2758 | if (mvc_result_value(m, tblname, colname, tpename, *digits++, *scaledigits++, v, mtype)) |
2759 | throw(SQL, "sql.rsColumn" , SQLSTATE(45000) "Result set construction failed" ); |
2760 | } |
2761 | /* now select the file channel */ |
2762 | if ((tostdout = strcmp(filename,"stdout" ) == 0)) { |
2763 | s = cntxt->fdout; |
2764 | } else if (!onclient) { |
2765 | if ((s = open_wastream(filename)) == NULL || mnstr_errnr(s)) { |
2766 | msg= createException(IO, "streams.open" , SQLSTATE(42000) "could not open file '%s': %s" , |
2767 | filename?filename:"stdout" , strerror(errno)); |
2768 | close_stream(s); |
2769 | goto wrapup_result_set; |
2770 | } |
2771 | } else { |
2772 | while (!m->scanner.rs->eof) |
2773 | bstream_next(m->scanner.rs); |
2774 | s = m->scanner.ws; |
2775 | mnstr_write(s, PROMPT3, sizeof(PROMPT3) - 1, 1); |
2776 | mnstr_printf(s, "w %s\n" , filename); |
2777 | mnstr_flush(s); |
2778 | if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) { |
2779 | /* non-empty line indicates failure on client */ |
2780 | msg = createException(IO, "streams.open" , "%s" , buf); |
2781 | /* deal with ridiculously long response from client */ |
2782 | while (buf[sz - 1] != '\n' && |
2783 | (sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 0) |
2784 | ; |
2785 | goto wrapup_result_set; |
2786 | } |
2787 | } |
2788 | if (mvc_export_result(cntxt->sqlcontext, s, res, strcmp(filename, "stdout" ) == 0, mb->starttime, mb->optimize)) |
2789 | msg = createException(SQL, "sql.resultset" , SQLSTATE(45000) "Result set construction failed" ); |
2790 | mb->starttime = 0; |
2791 | mb->optimize = 0; |
2792 | if (onclient) { |
2793 | mnstr_flush(s); |
2794 | if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) { |
2795 | msg = createException(IO, "streams.open" , "%s" , buf); |
2796 | } |
2797 | while (sz > 0) |
2798 | sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf)); |
2799 | } else if (!tostdout) { |
2800 | close_stream(s); |
2801 | } |
2802 | wrapup_result_set: |
2803 | if( tbl) BBPunfix(tblId); |
2804 | if( atr) BBPunfix(atrId); |
2805 | if( tpe) BBPunfix(tpeId); |
2806 | if( len) BBPunfix(lenId); |
2807 | if( scale) BBPunfix(scaleId); |
2808 | return msg; |
2809 | } |
2810 | |
2811 | str |
2812 | mvc_table_result_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2813 | { |
2814 | str res = MAL_SUCCEED; |
2815 | BAT *order; |
2816 | mvc *m = NULL; |
2817 | str msg; |
2818 | int *res_id; |
2819 | int nr_cols; |
2820 | sql_query_t qtype; |
2821 | bat order_bid; |
2822 | |
2823 | if ( pci->argc > 6) |
2824 | return mvc_result_set_wrap(cntxt,mb,stk,pci); |
2825 | |
2826 | res_id = getArgReference_int(stk, pci, 0); |
2827 | nr_cols = *getArgReference_int(stk, pci, 1); |
2828 | qtype = (sql_query_t) *getArgReference_int(stk, pci, 2); |
2829 | order_bid = *getArgReference_bat(stk, pci, 3); |
2830 | |
2831 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
2832 | return msg; |
2833 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2834 | return msg; |
2835 | if ((order = BATdescriptor(order_bid)) == NULL) { |
2836 | throw(SQL, "sql.resultSet" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
2837 | } |
2838 | *res_id = mvc_result_table(m, mb->tag, nr_cols, qtype, order); |
2839 | if (*res_id < 0) |
2840 | res = createException(SQL, "sql.resultSet" , SQLSTATE(45000) "Result set construction failed" ); |
2841 | BBPunfix(order->batCacheid); |
2842 | return res; |
2843 | } |
2844 | |
2845 | /* str mvc_affected_rows_wrap(int *m, int m, lng *nr, str *w); */ |
2846 | str |
2847 | mvc_affected_rows_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2848 | { |
2849 | backend *b = NULL; |
2850 | int *res = getArgReference_int(stk, pci, 0), error; |
2851 | #ifndef NDEBUG |
2852 | int mtype = getArgType(mb, pci, 2); |
2853 | #endif |
2854 | lng nr; |
2855 | str msg; |
2856 | |
2857 | (void) mb; /* NOT USED */ |
2858 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2859 | return msg; |
2860 | *res = 0; |
2861 | assert(mtype == TYPE_lng); |
2862 | nr = *getArgReference_lng(stk, pci, 2); |
2863 | b = cntxt->sqlcontext; |
2864 | error = mvc_export_affrows(b, b->out, nr, "" , mb->tag, mb->starttime, mb->optimize); |
2865 | mb->starttime = 0; |
2866 | mb->optimize = 0; |
2867 | if (error) |
2868 | throw(SQL, "sql.affectedRows" , SQLSTATE(45000) "Result set construction failed" ); |
2869 | return MAL_SUCCEED; |
2870 | } |
2871 | |
2872 | /* str mvc_export_head_wrap(int *ret, stream **s, int *res_id); */ |
2873 | str |
2874 | mvc_export_head_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2875 | { |
2876 | backend *b = NULL; |
2877 | stream **s = (stream **) getArgReference(stk, pci, 1); |
2878 | int res_id = *getArgReference_int(stk, pci, 2); |
2879 | str msg; |
2880 | |
2881 | (void) mb; /* NOT USED */ |
2882 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2883 | return msg; |
2884 | b = cntxt->sqlcontext; |
2885 | if (mvc_export_head(b, *s, res_id, FALSE, TRUE, mb->starttime, mb->optimize)) |
2886 | throw(SQL, "sql.exportHead" , SQLSTATE(45000) "Result set construction failed" ); |
2887 | mb->starttime = 0; |
2888 | mb->optimize = 0; |
2889 | return MAL_SUCCEED; |
2890 | } |
2891 | |
2892 | /* str mvc_export_result_wrap(int *ret, stream **s, int *res_id); */ |
2893 | str |
2894 | mvc_export_result_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2895 | { |
2896 | backend *b = NULL; |
2897 | stream **s = (stream **) getArgReference(stk, pci, 1); |
2898 | int res_id = *getArgReference_int(stk, pci, 2); |
2899 | str msg; |
2900 | |
2901 | (void) mb; /* NOT USED */ |
2902 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2903 | return msg; |
2904 | b = cntxt->sqlcontext; |
2905 | if( pci->argc > 5){ |
2906 | res_id = *getArgReference_int(stk, pci, 2); |
2907 | if (mvc_export_result(b, cntxt->fdout, res_id, true, mb->starttime, mb->optimize)) |
2908 | throw(SQL, "sql.exportResult" , SQLSTATE(45000) "Result set construction failed" ); |
2909 | } else if (mvc_export_result(b, *s, res_id, false, mb->starttime, mb->optimize)) |
2910 | throw(SQL, "sql.exportResult" , SQLSTATE(45000) "Result set construction failed" ); |
2911 | mb->starttime = 0; |
2912 | mb->optimize = 0; |
2913 | return MAL_SUCCEED; |
2914 | } |
2915 | |
2916 | /* str mvc_export_chunk_wrap(int *ret, stream **s, int *res_id, str *w); */ |
2917 | str |
2918 | mvc_export_chunk_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2919 | { |
2920 | backend *b = NULL; |
2921 | stream **s = (stream **) getArgReference(stk, pci, 1); |
2922 | int res_id = *getArgReference_int(stk, pci, 2); |
2923 | BUN offset = 0; |
2924 | BUN nr = 0; |
2925 | str msg; |
2926 | |
2927 | (void) mb; /* NOT USED */ |
2928 | if (pci->argc == 5) { |
2929 | offset = (BUN) *getArgReference_int(stk, pci, 3); |
2930 | nr = (BUN) *getArgReference_int(stk, pci, 4); |
2931 | } |
2932 | |
2933 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2934 | return msg; |
2935 | b = cntxt->sqlcontext; |
2936 | if (mvc_export_chunk(b, *s, res_id, offset, nr)) |
2937 | throw(SQL, "sql.exportChunk" , SQLSTATE(45000) "Result set construction failed" ); |
2938 | return NULL; |
2939 | } |
2940 | |
2941 | /* str mvc_export_operation_wrap(int *ret, str *w); */ |
2942 | str |
2943 | mvc_export_operation_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2944 | { |
2945 | backend *b = NULL; |
2946 | str msg; |
2947 | |
2948 | (void) stk; /* NOT USED */ |
2949 | (void) pci; /* NOT USED */ |
2950 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2951 | return msg; |
2952 | b = cntxt->sqlcontext; |
2953 | if (mvc_export_operation(b, b->out, "" , mb->starttime, mb->optimize)) |
2954 | throw(SQL, "sql.exportOperation" , SQLSTATE(45000) "Result set construction failed" ); |
2955 | mb->starttime = 0; |
2956 | mb->optimize = 0; |
2957 | return NULL; |
2958 | } |
2959 | |
2960 | str |
2961 | /*mvc_scalar_value_wrap(int *ret, int *qtype, str tn, str name, str type, int *digits, int *scale, int *eclass, ptr p, int mtype)*/ |
2962 | mvc_scalar_value_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
2963 | { |
2964 | const char *tn = *getArgReference_str(stk, pci, 1); |
2965 | const char *cn = *getArgReference_str(stk, pci, 2); |
2966 | const char *type = *getArgReference_str(stk, pci, 3); |
2967 | int digits = *getArgReference_int(stk, pci, 4); |
2968 | int scale = *getArgReference_int(stk, pci, 5); |
2969 | ptr p = getArgReference(stk, pci, 7); |
2970 | int mtype = getArgType(mb, pci, 7); |
2971 | str msg; |
2972 | backend *b = NULL; |
2973 | int res_id; |
2974 | (void) mb; /* NOT USED */ |
2975 | if ((msg = checkSQLContext(cntxt)) != NULL) |
2976 | return msg; |
2977 | b = cntxt->sqlcontext; |
2978 | if (ATOMextern(mtype)) |
2979 | p = *(ptr *) p; |
2980 | |
2981 | // scalar values are single-column result sets |
2982 | if ((res_id = mvc_result_table(b->mvc, mb->tag, 1, Q_TABLE, NULL)) < 0) |
2983 | throw(SQL, "sql.exportValue" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
2984 | if (mvc_result_value(b->mvc, tn, cn, type, digits, scale, p, mtype)) |
2985 | throw(SQL, "sql.exportValue" , SQLSTATE(45000) "Result set construction failed" ); |
2986 | if (b->output_format == OFMT_NONE) { |
2987 | return MAL_SUCCEED; |
2988 | } |
2989 | if (mvc_export_result(b, b->out, res_id, true, mb->starttime, mb->optimize) < 0) { |
2990 | throw(SQL, "sql.exportValue" , SQLSTATE(45000) "Result set construction failed" ); |
2991 | } |
2992 | mb->starttime = 0; |
2993 | mb->optimize = 0; |
2994 | return MAL_SUCCEED; |
2995 | } |
2996 | |
2997 | static void |
2998 | bat2return(MalStkPtr stk, InstrPtr pci, BAT **b) |
2999 | { |
3000 | int i; |
3001 | |
3002 | for (i = 0; i < pci->retc; i++) { |
3003 | *getArgReference_bat(stk, pci, i) = b[i]->batCacheid; |
3004 | BBPkeepref(b[i]->batCacheid); |
3005 | } |
3006 | } |
3007 | |
3008 | #ifdef WIN32 |
3009 | static void |
3010 | fix_windows_newline(unsigned char *s) |
3011 | { |
3012 | char *p = NULL; |
3013 | int c = '\r'; |
3014 | |
3015 | if (s && (p=strchr((char*)s, c)) != NULL && p[1] == '\n') { |
3016 | for(; p[1]; p++) |
3017 | p[0] = p[1]; |
3018 | p[0] = 0; |
3019 | } |
3020 | } |
3021 | #endif |
3022 | |
3023 | static char fwftsep[2] = {STREAM_FWF_FIELD_SEP, '\0'}; |
3024 | static char fwfrsep[2] = {STREAM_FWF_RECORD_SEP, '\0'}; |
3025 | |
3026 | /* str mvc_import_table_wrap(int *res, str *sname, str *tname, unsigned char* *T, unsigned char* *R, unsigned char* *S, unsigned char* *N, str *fname, lng *sz, lng *offset, int *locked, int *besteffort, str *fixed_width, int *onclient); */ |
3027 | str |
3028 | mvc_import_table_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3029 | { |
3030 | backend *be; |
3031 | BAT **b = NULL; |
3032 | ssize_t len = 0; |
3033 | sql_table *t = *(sql_table **) getArgReference(stk, pci, pci->retc + 0); |
3034 | const char *tsep = *getArgReference_str(stk, pci, pci->retc + 1); |
3035 | const char *rsep = *getArgReference_str(stk, pci, pci->retc + 2); |
3036 | const char *ssep = *getArgReference_str(stk, pci, pci->retc + 3); |
3037 | const char *ns = *getArgReference_str(stk, pci, pci->retc + 4); |
3038 | const char *fname = *getArgReference_str(stk, pci, pci->retc + 5); |
3039 | lng sz = *getArgReference_lng(stk, pci, pci->retc + 6); |
3040 | lng offset = *getArgReference_lng(stk, pci, pci->retc + 7); |
3041 | int locked = *getArgReference_int(stk, pci, pci->retc + 8); |
3042 | int besteffort = *getArgReference_int(stk, pci, pci->retc + 9); |
3043 | char *fixed_widths = *getArgReference_str(stk, pci, pci->retc + 10); |
3044 | int onclient = *getArgReference_int(stk, pci, pci->retc + 11); |
3045 | str msg = MAL_SUCCEED; |
3046 | bstream *s = NULL; |
3047 | stream *ss; |
3048 | |
3049 | (void) mb; /* NOT USED */ |
3050 | if ((msg = checkSQLContext(cntxt)) != NULL) |
3051 | return msg; |
3052 | if (onclient && !cntxt->filetrans) { |
3053 | throw(MAL, "sql.copy_from" , "cannot transfer files from client" ); |
3054 | } |
3055 | |
3056 | be = cntxt->sqlcontext; |
3057 | /* The CSV parser expects ssep to have the value 0 if the user does not |
3058 | * specify a quotation character |
3059 | */ |
3060 | if (*ssep == 0 || strcmp(ssep, str_nil) == 0) |
3061 | ssep = NULL; |
3062 | |
3063 | if (fname != NULL && strcmp(str_nil, fname) == 0) |
3064 | fname = NULL; |
3065 | if (fname == NULL) { |
3066 | msg = mvc_import_table(cntxt, &b, be->mvc, be->mvc->scanner.rs, t, tsep, rsep, ssep, ns, sz, offset, locked, besteffort, true); |
3067 | } else { |
3068 | if (onclient) { |
3069 | mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1); |
3070 | if (offset > 1 && rsep && rsep[0] == '\n' && rsep[1] == '\0') { |
3071 | /* only let client skip simple lines */ |
3072 | mnstr_printf(be->mvc->scanner.ws, "r " LLFMT " %s\n" , |
3073 | offset, fname); |
3074 | offset = 0; |
3075 | } else { |
3076 | mnstr_printf(be->mvc->scanner.ws, "r 0 %s\n" , fname); |
3077 | } |
3078 | msg = MAL_SUCCEED; |
3079 | mnstr_flush(be->mvc->scanner.ws); |
3080 | while (!be->mvc->scanner.rs->eof) |
3081 | bstream_next(be->mvc->scanner.rs); |
3082 | ss = be->mvc->scanner.rs->s; |
3083 | char buf[80]; |
3084 | if ((len = mnstr_readline(ss, buf, sizeof(buf))) > 1) { |
3085 | if (buf[0] == '!' && buf[6] == '!') |
3086 | msg = createException(IO, "sql.copy_from" , "%.7s%s: %s" , buf, fname, buf+7); |
3087 | else |
3088 | msg = createException(IO, "sql.copy_from" , "%s: %s" , fname, buf); |
3089 | while (buf[len - 1] != '\n' && |
3090 | (len = mnstr_readline(ss, buf, sizeof(buf))) > 0) |
3091 | ; |
3092 | /* read until flush marker */ |
3093 | while (mnstr_read(ss, buf, 1, sizeof(buf)) > 0) |
3094 | ; |
3095 | return msg; |
3096 | } |
3097 | } else { |
3098 | ss = open_rastream(fname); |
3099 | if (ss == NULL || mnstr_errnr(ss)) { |
3100 | msg = createException(IO, "sql.copy_from" , SQLSTATE(42000) "Cannot open file '%s': %s" , fname, strerror(errno)); |
3101 | close_stream(ss); |
3102 | return msg; |
3103 | } |
3104 | } |
3105 | |
3106 | if (fixed_widths && strcmp(fixed_widths, str_nil) != 0) { |
3107 | size_t ncol = 0, current_width_entry = 0, i; |
3108 | size_t *widths; |
3109 | char* val_start = fixed_widths; |
3110 | size_t width_len = strlen(fixed_widths); |
3111 | for (i = 0; i < width_len; i++) { |
3112 | if (fixed_widths[i] == '|') { |
3113 | ncol++; |
3114 | } |
3115 | } |
3116 | widths = malloc(sizeof(size_t) * ncol); |
3117 | if (!widths) { |
3118 | close_stream(ss); |
3119 | throw(MAL, "sql.copy_from" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3120 | } |
3121 | for (i = 0; i < width_len; i++) { |
3122 | if (fixed_widths[i] == STREAM_FWF_FIELD_SEP) { |
3123 | fixed_widths[i] = '\0'; |
3124 | widths[current_width_entry++] = (size_t) strtoll(val_start, NULL, 10); |
3125 | val_start = fixed_widths + i + 1; |
3126 | } |
3127 | } |
3128 | /* overwrite other delimiters to the ones the FWF stream uses */ |
3129 | tsep = fwftsep; |
3130 | rsep = fwfrsep; |
3131 | |
3132 | ss = stream_fwf_create(ss, ncol, widths, STREAM_FWF_FILLER); |
3133 | } |
3134 | #if SIZEOF_VOID_P == 4 |
3135 | s = bstream_create(ss, 0x20000); |
3136 | #else |
3137 | s = bstream_create(ss, 0x200000); |
3138 | #endif |
3139 | if (s != NULL) { |
3140 | msg = mvc_import_table(cntxt, &b, be->mvc, s, t, tsep, rsep, ssep, ns, sz, offset, locked, besteffort, false); |
3141 | if (onclient) { |
3142 | mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1); |
3143 | mnstr_flush(be->mvc->scanner.ws); |
3144 | be->mvc->scanner.rs->eof = s->eof; |
3145 | s->s = NULL; |
3146 | } |
3147 | bstream_destroy(s); |
3148 | } |
3149 | } |
3150 | if (fname && s == NULL) |
3151 | throw(IO, "bstreams.create" , SQLSTATE(42000) "Failed to create block stream" ); |
3152 | if (b == NULL) |
3153 | throw(SQL, "importTable" , SQLSTATE(42000) "Failed to import table '%s', %s" , t->base.name, be->mvc->errstr); |
3154 | bat2return(stk, pci, b); |
3155 | GDKfree(b); |
3156 | return msg; |
3157 | } |
3158 | |
3159 | static bool |
3160 | read_more(bstream *in, stream *out) |
3161 | { |
3162 | do { |
3163 | if (bstream_next(in) < 0) |
3164 | return false; |
3165 | if (in->eof) { |
3166 | if (mnstr_write(out, PROMPT2, sizeof(PROMPT2) - 1, 1) != 1 |
3167 | || mnstr_flush(out) < 0) |
3168 | return false; |
3169 | in->eof = false; |
3170 | if (bstream_next(in) <= 0) |
3171 | return false; |
3172 | } |
3173 | } while (in->len <= in->pos); |
3174 | return true; |
3175 | } |
3176 | |
3177 | static BAT * |
3178 | BATattach_bstream(int tt, bstream *in, stream *out, BUN size) |
3179 | { |
3180 | BAT *bn; |
3181 | size_t n; |
3182 | size_t asz = (size_t) ATOMsize(tt); |
3183 | |
3184 | bn = COLnew(0, tt, size, TRANSIENT); |
3185 | if (bn == NULL) |
3186 | return NULL; |
3187 | |
3188 | if (ATOMstorage(tt) < TYPE_str) { |
3189 | while (read_more(in, out)) { |
3190 | n = (in->len - in->pos) / asz; |
3191 | if (BATextend(bn, bn->batCount + n) != GDK_SUCCEED) { |
3192 | BBPreclaim(bn); |
3193 | return NULL; |
3194 | } |
3195 | memcpy(Tloc(bn, bn->batCount), in->buf + in->pos, n * asz); |
3196 | bn->batCount += (BUN) n; |
3197 | in->pos += n * asz; |
3198 | } |
3199 | BATsetcount(bn, bn->batCount); |
3200 | bn->tseqbase = oid_nil; |
3201 | bn->tnonil = bn->batCount == 0; |
3202 | bn->tnil = false; |
3203 | if (bn->batCount <= 1) { |
3204 | bn->tsorted = true; |
3205 | bn->trevsorted = true; |
3206 | bn->tkey = true; |
3207 | } else { |
3208 | bn->tsorted = false; |
3209 | bn->trevsorted = false; |
3210 | bn->tkey = false; |
3211 | } |
3212 | } else { |
3213 | assert(ATOMstorage(tt) == TYPE_str); |
3214 | while (read_more(in, out)) { |
3215 | int u; |
3216 | for (n = in->pos, u = 0; n < in->len; n++) { |
3217 | int c = in->buf[n]; |
3218 | if (u) { |
3219 | if ((c & 0xC0) == 0x80) |
3220 | u--; |
3221 | else |
3222 | goto bailout; |
3223 | } else if ((c & 0xF8) == 0xF0) { |
3224 | u = 3; |
3225 | } else if ((c & 0xF0) == 0xE0) { |
3226 | u = 2; |
3227 | } else if ((c & 0xE0) == 0xC0) { |
3228 | u = 1; |
3229 | } else if ((c & 0xC0) == 0x80) { |
3230 | goto bailout; |
3231 | } else if (c == '\r') { |
3232 | if (n + 1 < in->len |
3233 | && in->buf[n + 1] == '\n') { |
3234 | in->buf[n] = 0; |
3235 | if (BUNappend(bn, in->buf + in->pos, false) != GDK_SUCCEED) |
3236 | goto bailout; |
3237 | in->buf[n] = '\r'; |
3238 | in->pos = n + 2; |
3239 | n++; |
3240 | } |
3241 | } else if (c == '\n' || c == '\0') { |
3242 | in->buf[n] = 0; |
3243 | if (BUNappend(bn, in->buf + in->pos, false) != GDK_SUCCEED) |
3244 | goto bailout; |
3245 | in->buf[n] = c; |
3246 | in->pos = n + 1; |
3247 | } |
3248 | } |
3249 | } |
3250 | } |
3251 | return bn; |
3252 | |
3253 | bailout: |
3254 | BBPreclaim(bn); |
3255 | return NULL; |
3256 | } |
3257 | |
3258 | /* str mvc_bin_import_table_wrap(.., str *sname, str *tname, str *fname..); |
3259 | * binary attachment only works for simple binary types. |
3260 | * Non-simple types require each line to contain a valid ascii representation |
3261 | * of the text terminate by a new-line. These strings are passed to the corresponding |
3262 | * atom conversion routines to fill the column. |
3263 | */ |
3264 | str |
3265 | mvc_bin_import_table_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3266 | { |
3267 | mvc *m = NULL; |
3268 | str msg; |
3269 | BUN cnt = 0; |
3270 | bool init = false; |
3271 | int i; |
3272 | const char *sname = *getArgReference_str(stk, pci, 0 + pci->retc); |
3273 | const char *tname = *getArgReference_str(stk, pci, 1 + pci->retc); |
3274 | int onclient = *getArgReference_int(stk, pci, 2 + pci->retc); |
3275 | sql_schema *s; |
3276 | sql_table *t; |
3277 | node *n; |
3278 | |
3279 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
3280 | return msg; |
3281 | if ((msg = checkSQLContext(cntxt)) != NULL) |
3282 | return msg; |
3283 | |
3284 | if ((s = mvc_bind_schema(m, sname)) == NULL) |
3285 | throw(SQL, "sql.import_table" , SQLSTATE(3F000) "Schema missing %s" ,sname); |
3286 | t = mvc_bind_table(m, s, tname); |
3287 | if (!t) |
3288 | throw(SQL, "sql" , SQLSTATE(42S02) "Table missing %s" , tname); |
3289 | if (list_length(t->columns.set) != (pci->argc - (3 + pci->retc))) |
3290 | throw(SQL, "sql" , SQLSTATE(42000) "Not enough columns found in input file" ); |
3291 | if (2 * pci->retc + 3 != pci->argc) |
3292 | throw(SQL, "sql" , SQLSTATE(42000) "Not enough output values" ); |
3293 | |
3294 | if (onclient && !cntxt->filetrans) { |
3295 | throw(MAL, "sql.copy_from" , "cannot transfer files from client" ); |
3296 | } |
3297 | |
3298 | backend *be = cntxt->sqlcontext; |
3299 | |
3300 | for (i = 0; i < pci->retc; i++) |
3301 | *getArgReference_bat(stk, pci, i) = 0; |
3302 | |
3303 | for (i = pci->retc + 3, n = t->columns.set->h; i < pci->argc && n; i++, n = n->next) { |
3304 | sql_column *col = n->data; |
3305 | BAT *c = NULL; |
3306 | int tpe = col->type.type->localtype; |
3307 | const char *fname = *getArgReference_str(stk, pci, i); |
3308 | |
3309 | /* handle the various cases */ |
3310 | if (strcmp(fname, str_nil) == 0) { |
3311 | // no filename for this column, skip for now because we potentially don't know the count yet |
3312 | continue; |
3313 | } |
3314 | if (ATOMvarsized(tpe) && tpe != TYPE_str) { |
3315 | msg = createException(SQL, "sql" , SQLSTATE(42000) "Failed to attach file %s" , *getArgReference_str(stk, pci, i)); |
3316 | goto bailout; |
3317 | } |
3318 | |
3319 | if (tpe <= TYPE_str || tpe == TYPE_date || tpe == TYPE_daytime || tpe == TYPE_timestamp) { |
3320 | if (onclient) { |
3321 | mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1); |
3322 | mnstr_printf(be->mvc->scanner.ws, "rb %s\n" , fname); |
3323 | msg = MAL_SUCCEED; |
3324 | mnstr_flush(be->mvc->scanner.ws); |
3325 | while (!be->mvc->scanner.rs->eof) |
3326 | bstream_next(be->mvc->scanner.rs); |
3327 | stream *ss = be->mvc->scanner.rs->s; |
3328 | char buf[80]; |
3329 | if (mnstr_readline(ss, buf, sizeof(buf)) > 1) { |
3330 | msg = createException(IO, "sql.attach" , "%s" , buf); |
3331 | goto bailout; |
3332 | } |
3333 | bstream *s = bstream_create(ss, 1 << 20); |
3334 | |
3335 | c = BATattach_bstream(col->type.type->localtype, s, be->mvc->scanner.ws, cnt); |
3336 | mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1); |
3337 | mnstr_flush(be->mvc->scanner.ws); |
3338 | be->mvc->scanner.rs->eof = s->eof; |
3339 | s->s = NULL; |
3340 | bstream_destroy(s); |
3341 | } else if (tpe == TYPE_str) { |
3342 | /* get the BAT and fill it with the strings */ |
3343 | c = COLnew(0, TYPE_str, 0, TRANSIENT); |
3344 | if (c == NULL) { |
3345 | msg = createException(SQL, "sql" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3346 | goto bailout; |
3347 | } |
3348 | /* this code should be extended to |
3349 | * deal with larger text strings. */ |
3350 | FILE *f = fopen(fname, "r" ); |
3351 | if (f == NULL) { |
3352 | BBPreclaim(c); |
3353 | msg = createException(SQL, "sql" , SQLSTATE(42000) "Failed to re-open file %s" , fname); |
3354 | goto bailout; |
3355 | } |
3356 | |
3357 | #define bufsiz (128 * BLOCK) |
3358 | char *buf = GDKmalloc(bufsiz); |
3359 | if (buf == NULL) { |
3360 | fclose(f); |
3361 | BBPreclaim(c); |
3362 | msg = createException(SQL, "sql" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3363 | goto bailout; |
3364 | } |
3365 | while (fgets(buf, bufsiz, f) != NULL) { |
3366 | char *t = strrchr(buf, '\n'); |
3367 | if (t) |
3368 | *t = 0; |
3369 | if (BUNappend(c, buf, false) != GDK_SUCCEED) { |
3370 | BBPreclaim(c); |
3371 | fclose(f); |
3372 | msg = createException(SQL, "sql" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3373 | goto bailout; |
3374 | } |
3375 | } |
3376 | #undef bufsiz |
3377 | fclose(f); |
3378 | GDKfree(buf); |
3379 | } else { |
3380 | c = BATattach(tpe, fname, TRANSIENT); |
3381 | } |
3382 | if (c == NULL) { |
3383 | msg = createException(SQL, "sql" , SQLSTATE(42000) "Failed to attach file %s" , fname); |
3384 | goto bailout; |
3385 | } |
3386 | if (BATsetaccess(c, BAT_READ) != GDK_SUCCEED) { |
3387 | BBPreclaim(c); |
3388 | msg = createException(SQL, "sql" , SQLSTATE(42000) "Failed to set internal access while attaching file %s" , fname); |
3389 | goto bailout; |
3390 | } |
3391 | } else { |
3392 | msg = createException(SQL, "sql" , SQLSTATE(42000) "Failed to attach file %s" , fname); |
3393 | goto bailout; |
3394 | } |
3395 | if (init && cnt != BATcount(c)) { |
3396 | BBPunfix(c->batCacheid); |
3397 | msg = createException(SQL, "sql" , SQLSTATE(42000) "Binary files for table '%s' have inconsistent counts" , tname); |
3398 | goto bailout; |
3399 | } |
3400 | cnt = BATcount(c); |
3401 | init = true; |
3402 | *getArgReference_bat(stk, pci, i - (3 + pci->retc)) = c->batCacheid; |
3403 | BBPkeepref(c->batCacheid); |
3404 | } |
3405 | if (init) { |
3406 | for (i = pci->retc + 3, n = t->columns.set->h; i < pci->argc && n; i++, n = n->next) { |
3407 | // now that we know the BAT count, we can fill in the columns for which no parameters were passed |
3408 | sql_column *col = n->data; |
3409 | BAT *c = NULL; |
3410 | int tpe = col->type.type->localtype; |
3411 | |
3412 | const char *fname = *getArgReference_str(stk, pci, i); |
3413 | if (strcmp(fname, str_nil) == 0) { |
3414 | // fill the new BAT with NULL values |
3415 | c = BATconstant(0, tpe, ATOMnilptr(tpe), cnt, TRANSIENT); |
3416 | if (c == NULL) { |
3417 | msg = createException(SQL, "sql" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3418 | goto bailout; |
3419 | } |
3420 | *getArgReference_bat(stk, pci, i - (3 + pci->retc)) = c->batCacheid; |
3421 | BBPkeepref(c->batCacheid); |
3422 | } |
3423 | } |
3424 | } |
3425 | return MAL_SUCCEED; |
3426 | bailout: |
3427 | for (i = 0; i < pci->retc; i++) { |
3428 | bat bid; |
3429 | if ((bid = *getArgReference_bat(stk, pci, i)) != 0) { |
3430 | BBPrelease(bid); |
3431 | *getArgReference_bat(stk, pci, i) = 0; |
3432 | } |
3433 | } |
3434 | return msg; |
3435 | } |
3436 | |
3437 | str |
3438 | not_unique(bit *ret, const bat *bid) |
3439 | { |
3440 | BAT *b; |
3441 | |
3442 | if ((b = BATdescriptor(*bid)) == NULL) { |
3443 | throw(SQL, "not_unique" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
3444 | } |
3445 | |
3446 | *ret = FALSE; |
3447 | if (BATtkey(b) || BATtdense(b) || BATcount(b) <= 1) { |
3448 | BBPunfix(b->batCacheid); |
3449 | return MAL_SUCCEED; |
3450 | } else if (b->tsorted) { |
3451 | BUN p, q; |
3452 | oid c = *(oid *) Tloc(b, 0); |
3453 | |
3454 | for (p = 1, q = BUNlast(b); p < q; p++) { |
3455 | oid v = *(oid *) Tloc(b, p); |
3456 | if (v <= c) { |
3457 | *ret = TRUE; |
3458 | break; |
3459 | } |
3460 | c = v; |
3461 | } |
3462 | } else { |
3463 | BBPunfix(b->batCacheid); |
3464 | throw(SQL, "not_unique" , SQLSTATE(42000) "Input column should be sorted" ); |
3465 | } |
3466 | BBPunfix(b->batCacheid); |
3467 | return MAL_SUCCEED; |
3468 | } |
3469 | |
3470 | /* row case */ |
3471 | str |
3472 | SQLidentity(oid *ret, const void *i) |
3473 | { |
3474 | (void)i; |
3475 | *ret = 0; |
3476 | return MAL_SUCCEED; |
3477 | } |
3478 | |
3479 | str |
3480 | BATSQLidentity(bat *ret, const bat *bid) |
3481 | { |
3482 | return BKCmirror(ret, bid); |
3483 | } |
3484 | |
3485 | str |
3486 | PBATSQLidentity(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3487 | { |
3488 | bat *res = getArgReference_bat(stk, pci, 0); |
3489 | oid *ns = getArgReference_oid(stk, pci, 1); |
3490 | bat bid = *getArgReference_bat(stk, pci, 2); |
3491 | oid s = *getArgReference_oid(stk, pci, 3); |
3492 | BAT *b, *bn = NULL; |
3493 | |
3494 | (void) cntxt; |
3495 | (void) mb; |
3496 | if ((b = BATdescriptor(bid)) == NULL) { |
3497 | throw(MAL, "batcalc.identity" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
3498 | } |
3499 | bn = BATdense(b->hseqbase, s, BATcount(b)); |
3500 | if (bn != NULL) { |
3501 | *ns = s + BATcount(b); |
3502 | BBPunfix(b->batCacheid); |
3503 | BBPkeepref(*res = bn->batCacheid); |
3504 | return MAL_SUCCEED; |
3505 | } |
3506 | BBPunfix(b->batCacheid); |
3507 | throw(MAL, "batcalc.identity" , SQLSTATE(45001) "Internal error" ); |
3508 | |
3509 | } |
3510 | |
3511 | /* |
3512 | * The core modules of Monet provide just a limited set of |
3513 | * mathematical operators. The extensions required to support |
3514 | * SQL-99 are shown below. At some point they also should be |
3515 | * moved to module code base. |
3516 | */ |
3517 | |
3518 | str |
3519 | daytime_2time_daytime(daytime *res, const daytime *v, const int *digits) |
3520 | { |
3521 | int d = (*digits) ? *digits - 1 : 0; |
3522 | |
3523 | /* correct fraction */ |
3524 | *res = *v; |
3525 | if (!is_daytime_nil(*v) && d < 6) { |
3526 | #ifdef TRUNCATE_NUMBERS |
3527 | *res = (daytime) (*res / scales[6 - d]); |
3528 | #else |
3529 | *res = (daytime) ((*res + scales[5 - d]*5) / scales[6 - d]); |
3530 | #endif |
3531 | *res = (daytime) (*res * scales[6 - d]); |
3532 | } |
3533 | return MAL_SUCCEED; |
3534 | } |
3535 | |
3536 | str |
3537 | second_interval_2_daytime(daytime *res, const lng *s, const int *digits) |
3538 | { |
3539 | daytime d; |
3540 | d = daytime_add_usec(daytime_create(0, 0, 0, 0), *s * 1000); |
3541 | return daytime_2time_daytime(res, &d, digits); |
3542 | } |
3543 | |
3544 | str |
3545 | nil_2time_daytime(daytime *res, const void *v, const int *digits) |
3546 | { |
3547 | (void) digits; |
3548 | (void) v; |
3549 | *res = daytime_nil; |
3550 | return MAL_SUCCEED; |
3551 | } |
3552 | |
3553 | str |
3554 | str_2time_daytimetz(daytime *res, const str *v, const int *digits, int *tz) |
3555 | { |
3556 | size_t len = sizeof(daytime); |
3557 | ssize_t pos; |
3558 | |
3559 | if (!*v || strcmp(str_nil, *v) == 0) { |
3560 | *res = daytime_nil; |
3561 | return MAL_SUCCEED; |
3562 | } |
3563 | if (*tz) |
3564 | pos = daytime_tz_fromstr(*v, &len, &res, false); |
3565 | else |
3566 | pos = daytime_fromstr(*v, &len, &res, false); |
3567 | if (pos < (ssize_t) strlen(*v) || /* includes pos < 0 */ |
3568 | ATOMcmp(TYPE_daytime, res, ATOMnilptr(TYPE_daytime)) == 0) |
3569 | throw(SQL, "daytime" , SQLSTATE(22007) "Daytime (%s) has incorrect format" , *v); |
3570 | return daytime_2time_daytime(res, res, digits); |
3571 | } |
3572 | |
3573 | str |
3574 | str_2time_daytime(daytime *res, const str *v, const int *digits) |
3575 | { |
3576 | int zero = 0; |
3577 | return str_2time_daytimetz(res, v, digits, &zero); |
3578 | } |
3579 | |
3580 | str |
3581 | timestamp_2_daytime(daytime *res, const timestamp *v, const int *digits) |
3582 | { |
3583 | int d = (*digits) ? *digits - 1 : 0; |
3584 | daytime dt; |
3585 | |
3586 | dt = timestamp_daytime(*v); |
3587 | |
3588 | /* correct fraction */ |
3589 | if (!is_daytime_nil(dt) && d < 6) { |
3590 | #ifdef TRUNCATE_NUMBERS |
3591 | dt /= scales[6 - d]; |
3592 | #else |
3593 | dt = (dt + scales[5 - d]*5) / scales[6 - d]; |
3594 | #endif |
3595 | dt *= scales[6 - d]; |
3596 | } |
3597 | *res = dt; |
3598 | return MAL_SUCCEED; |
3599 | } |
3600 | |
3601 | str |
3602 | date_2_timestamp(timestamp *res, const date *v, const int *digits) |
3603 | { |
3604 | (void) digits; /* no precision needed */ |
3605 | *res = timestamp_fromdate(*v); |
3606 | return MAL_SUCCEED; |
3607 | } |
3608 | |
3609 | str |
3610 | timestamp_2time_timestamp(timestamp *res, const timestamp *v, const int *digits) |
3611 | { |
3612 | int d = (*digits) ? *digits - 1 : 0; |
3613 | date dt; |
3614 | daytime tm; |
3615 | |
3616 | dt = timestamp_date(*v); |
3617 | tm = timestamp_daytime(*v); |
3618 | /* correct fraction */ |
3619 | if (!is_daytime_nil(tm) && d < 6) { |
3620 | #ifdef TRUNCATE_NUMBERS |
3621 | tm /= scales[6 - d]; |
3622 | #else |
3623 | tm = (tm + scales[5 - d]*5) / scales[6 - d]; |
3624 | #endif |
3625 | tm *= scales[6 - d]; |
3626 | } |
3627 | *res = timestamp_create(dt, tm); |
3628 | return MAL_SUCCEED; |
3629 | } |
3630 | |
3631 | str |
3632 | nil_2time_timestamp(timestamp *res, const void *v, const int *digits) |
3633 | { |
3634 | (void) digits; |
3635 | (void) v; |
3636 | *res = timestamp_nil; |
3637 | return MAL_SUCCEED; |
3638 | } |
3639 | |
3640 | str |
3641 | str_2time_timestamptz(timestamp *res, const str *v, const int *digits, int *tz) |
3642 | { |
3643 | size_t len = sizeof(timestamp); |
3644 | ssize_t pos; |
3645 | |
3646 | if (!*v || strcmp(str_nil, *v) == 0) { |
3647 | *res = timestamp_nil; |
3648 | return MAL_SUCCEED; |
3649 | } |
3650 | if (*tz) |
3651 | pos = timestamp_tz_fromstr(*v, &len, &res, false); |
3652 | else |
3653 | pos = timestamp_fromstr(*v, &len, &res, false); |
3654 | if (!pos || pos < (ssize_t) strlen(*v) || ATOMcmp(TYPE_timestamp, res, ATOMnilptr(TYPE_timestamp)) == 0) |
3655 | throw(SQL, "timestamp" , SQLSTATE(22007) "Timestamp (%s) has incorrect format" , *v); |
3656 | return timestamp_2time_timestamp(res, res, digits); |
3657 | } |
3658 | |
3659 | str |
3660 | str_2time_timestamp(timestamp *res, const str *v, const int *digits) |
3661 | { |
3662 | int zero = 0; |
3663 | return str_2time_timestamptz(res, v, digits, &zero); |
3664 | } |
3665 | |
3666 | str |
3667 | SQLcst_alpha_cst(dbl *res, const dbl *decl, const dbl *theta) |
3668 | { |
3669 | dbl s, c1, c2; |
3670 | char *msg = MAL_SUCCEED; |
3671 | if (is_dbl_nil(*decl) || is_dbl_nil(*theta)) { |
3672 | *res = dbl_nil; |
3673 | } else if (fabs(*decl) + *theta > 89.9) { |
3674 | *res = 180.0; |
3675 | } else { |
3676 | s = sin(radians(*theta)); |
3677 | c1 = cos(radians(*decl - *theta)); |
3678 | c2 = cos(radians(*decl + *theta)); |
3679 | *res = degrees(fabs(atan(s / sqrt(fabs(c1 * c2))))); |
3680 | } |
3681 | return msg; |
3682 | } |
3683 | |
3684 | /* |
3685 | sql5_export str SQLcst_alpha_cst(dbl *res, dbl *decl, dbl *theta); |
3686 | sql5_export str SQLbat_alpha_cst(bat *res, bat *decl, dbl *theta); |
3687 | sql5_export str SQLcst_alpha_bat(bat *res, dbl *decl, bat *theta); |
3688 | */ |
3689 | str |
3690 | SQLbat_alpha_cst(bat *res, const bat *decl, const dbl *theta) |
3691 | { |
3692 | BAT *b, *bn; |
3693 | BUN p, q; |
3694 | dbl s, c1, c2, r; |
3695 | char *msg = NULL; |
3696 | |
3697 | if (is_dbl_nil(*theta)) { |
3698 | throw(SQL, "SQLbat_alpha" , SQLSTATE(42000) "Parameter theta should not be nil" ); |
3699 | } |
3700 | if ((b = BATdescriptor(*decl)) == NULL) { |
3701 | throw(SQL, "alpha" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
3702 | } |
3703 | bn = COLnew(b->hseqbase, TYPE_dbl, BATcount(b), TRANSIENT); |
3704 | if (bn == NULL) { |
3705 | BBPunfix(b->batCacheid); |
3706 | throw(SQL, "sql.alpha" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3707 | } |
3708 | s = sin(radians(*theta)); |
3709 | const dbl *vals = (const dbl *) Tloc(b, 0); |
3710 | BATloop(b, p, q) { |
3711 | dbl d = vals[p]; |
3712 | if (is_dbl_nil(d)) |
3713 | r = dbl_nil; |
3714 | else if (fabs(d) + *theta > 89.9) |
3715 | r = 180.0; |
3716 | else { |
3717 | c1 = cos(radians(d - *theta)); |
3718 | c2 = cos(radians(d + *theta)); |
3719 | r = degrees(fabs(atan(s / sqrt(fabs(c1 * c2))))); |
3720 | } |
3721 | if (BUNappend(bn, &r, false) != GDK_SUCCEED) { |
3722 | BBPreclaim(bn); |
3723 | throw(SQL, "sql.alpha" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3724 | } |
3725 | } |
3726 | *res = bn->batCacheid; |
3727 | BBPkeepref(bn->batCacheid); |
3728 | BBPunfix(b->batCacheid); |
3729 | return msg; |
3730 | } |
3731 | |
3732 | str |
3733 | SQLcst_alpha_bat(bat *res, const dbl *decl, const bat *thetabid) |
3734 | { |
3735 | BAT *b, *bn; |
3736 | BUN p, q; |
3737 | dbl s, c1, c2, r; |
3738 | char *msg = NULL; |
3739 | dbl *thetas; |
3740 | |
3741 | if ((b = BATdescriptor(*thetabid)) == NULL) { |
3742 | throw(SQL, "alpha" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
3743 | } |
3744 | thetas = (dbl *) Tloc(b, 0); |
3745 | bn = COLnew(b->hseqbase, TYPE_dbl, BATcount(b), TRANSIENT); |
3746 | if (bn == NULL) { |
3747 | BBPunfix(b->batCacheid); |
3748 | throw(SQL, "sql.alpha" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3749 | } |
3750 | BATloop(b, p, q) { |
3751 | dbl d = *decl; |
3752 | dbl theta = thetas[p]; |
3753 | |
3754 | if (is_dbl_nil(d)) |
3755 | r = dbl_nil; |
3756 | else if (fabs(d) + theta > 89.9) |
3757 | r = (dbl) 180.0; |
3758 | else { |
3759 | s = sin(radians(theta)); |
3760 | c1 = cos(radians(d - theta)); |
3761 | c2 = cos(radians(d + theta)); |
3762 | r = degrees(fabs(atan(s / sqrt(fabs(c1 * c2))))); |
3763 | } |
3764 | if (BUNappend(bn, &r, false) != GDK_SUCCEED) { |
3765 | BBPreclaim(bn); |
3766 | throw(SQL, "sql.alpha" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3767 | } |
3768 | } |
3769 | BBPkeepref(*res = bn->batCacheid); |
3770 | BBPunfix(b->batCacheid); |
3771 | return msg; |
3772 | } |
3773 | |
3774 | str |
3775 | month_interval_str(int *ret, const str *s, const int *d, const int *sk) |
3776 | { |
3777 | lng res; |
3778 | |
3779 | if (interval_from_str(*s, *d, *sk, &res) < 0) |
3780 | throw(SQL, "calc.month_interval" , SQLSTATE(42000) "Wrong format (%s)" , *s); |
3781 | assert((lng) GDK_int_min <= res && res <= (lng) GDK_int_max); |
3782 | *ret = (int) res; |
3783 | return MAL_SUCCEED; |
3784 | } |
3785 | |
3786 | str |
3787 | second_interval_str(lng *res, const str *s, const int *d, const int *sk) |
3788 | { |
3789 | if (interval_from_str(*s, *d, *sk, res) < 0) |
3790 | throw(SQL, "calc.second_interval" , SQLSTATE(42000) "Wrong format (%s)" , *s); |
3791 | return MAL_SUCCEED; |
3792 | } |
3793 | |
3794 | str |
3795 | month_interval(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3796 | { |
3797 | int *ret = getArgReference_int(stk, pci, 0); |
3798 | int k = digits2ek(*getArgReference_int(stk, pci, 2)); |
3799 | int r; |
3800 | |
3801 | (void) cntxt; |
3802 | (void) mb; |
3803 | switch (getArgType(mb, pci, 1)) { |
3804 | case TYPE_bte: |
3805 | r = stk->stk[getArg(pci, 1)].val.btval; |
3806 | break; |
3807 | case TYPE_sht: |
3808 | r = stk->stk[getArg(pci, 1)].val.shval; |
3809 | break; |
3810 | case TYPE_int: |
3811 | r = stk->stk[getArg(pci, 1)].val.ival; |
3812 | break; |
3813 | case TYPE_lng: |
3814 | r = (int) stk->stk[getArg(pci, 1)].val.lval; |
3815 | break; |
3816 | #ifdef HAVE_HGE |
3817 | case TYPE_hge: |
3818 | r = (int) stk->stk[getArg(pci, 1)].val.hval; |
3819 | break; |
3820 | #endif |
3821 | default: |
3822 | throw(ILLARG, "calc.month_interval" , SQLSTATE(42000) "Illegal argument" ); |
3823 | } |
3824 | switch (k) { |
3825 | case iyear: |
3826 | r *= 12; |
3827 | break; |
3828 | case imonth: |
3829 | break; |
3830 | default: |
3831 | throw(ILLARG, "calc.month_interval" , SQLSTATE(42000) "Illegal argument" ); |
3832 | } |
3833 | *ret = r; |
3834 | return MAL_SUCCEED; |
3835 | } |
3836 | |
3837 | str |
3838 | second_interval(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3839 | { |
3840 | lng *ret = getArgReference_lng(stk, pci, 0), r; |
3841 | int k = digits2ek(*getArgReference_int(stk, pci, 2)), scale = 0, isnil = 0; |
3842 | |
3843 | (void) cntxt; |
3844 | if (pci->argc > 3) |
3845 | scale = *getArgReference_int(stk, pci, 3); |
3846 | *ret = lng_nil; |
3847 | switch (getArgType(mb, pci, 1)) { |
3848 | case TYPE_bte: |
3849 | r = stk->stk[getArg(pci, 1)].val.btval; |
3850 | isnil = (stk->stk[getArg(pci, 1)].val.btval == bte_nil); |
3851 | break; |
3852 | case TYPE_sht: |
3853 | r = stk->stk[getArg(pci, 1)].val.shval; |
3854 | isnil = (stk->stk[getArg(pci, 1)].val.shval == sht_nil); |
3855 | break; |
3856 | case TYPE_int: |
3857 | r = stk->stk[getArg(pci, 1)].val.ival; |
3858 | isnil = (stk->stk[getArg(pci, 1)].val.ival == int_nil); |
3859 | break; |
3860 | case TYPE_lng: |
3861 | r = stk->stk[getArg(pci, 1)].val.lval; |
3862 | isnil = (stk->stk[getArg(pci, 1)].val.lval == lng_nil); |
3863 | break; |
3864 | #ifdef HAVE_HGE |
3865 | case TYPE_hge: |
3866 | r = (lng) stk->stk[getArg(pci, 1)].val.hval; |
3867 | isnil = (stk->stk[getArg(pci, 1)].val.hval == hge_nil); |
3868 | break; |
3869 | #endif |
3870 | default: |
3871 | throw(ILLARG, "calc.sec_interval" , SQLSTATE(42000) "Illegal argument in second interval" ); |
3872 | } |
3873 | if (isnil) |
3874 | return MAL_SUCCEED; |
3875 | switch (k) { |
3876 | case iday: |
3877 | r *= 24; |
3878 | /* fall through */ |
3879 | case ihour: |
3880 | r *= 60; |
3881 | /* fall through */ |
3882 | case imin: |
3883 | r *= 60; |
3884 | /* fall through */ |
3885 | case isec: |
3886 | r *= 1000; |
3887 | break; |
3888 | default: |
3889 | throw(ILLARG, "calc.sec_interval" , SQLSTATE(42000) "Illegal argument in second interval" ); |
3890 | } |
3891 | if (scale) { |
3892 | #ifndef TRUNCATE_NUMBERS |
3893 | r += 5*scales[scale-1]; |
3894 | #endif |
3895 | r /= scales[scale]; |
3896 | } |
3897 | *ret = r; |
3898 | return MAL_SUCCEED; |
3899 | } |
3900 | |
3901 | str |
3902 | second_interval_daytime(lng *res, const daytime *s, const int *d, const int *sk) |
3903 | { |
3904 | int k = digits2sk(*d); |
3905 | lng r = *(int *) s; |
3906 | |
3907 | (void) sk; |
3908 | if (is_daytime_nil(*s)) { |
3909 | *res = lng_nil; |
3910 | return MAL_SUCCEED; |
3911 | } |
3912 | switch (k) { |
3913 | case isec: |
3914 | break; |
3915 | case imin: |
3916 | r /= 60000; |
3917 | r *= 60000; |
3918 | break; |
3919 | case ihour: |
3920 | r /= 3600000; |
3921 | r *= 3600000; |
3922 | break; |
3923 | case iday: |
3924 | r /= (24 * 3600000); |
3925 | r *= (24 * 3600000); |
3926 | break; |
3927 | default: |
3928 | throw(ILLARG, "calc.second_interval" , SQLSTATE(42000) "Illegal argument in daytime interval" ); |
3929 | } |
3930 | *res = r; |
3931 | return MAL_SUCCEED; |
3932 | } |
3933 | |
3934 | str |
3935 | SQLcurrent_daytime(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3936 | { |
3937 | mvc *m = NULL; |
3938 | str msg; |
3939 | daytime *res = getArgReference_TYPE(stk, pci, 0, daytime); |
3940 | |
3941 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
3942 | return msg; |
3943 | |
3944 | *res = timestamp_daytime(timestamp_add_usec(timestamp_current(), |
3945 | m->timezone * LL_CONSTANT(1000))); |
3946 | return msg; |
3947 | } |
3948 | |
3949 | str |
3950 | SQLcurrent_timestamp(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3951 | { |
3952 | mvc *m = NULL; |
3953 | str msg; |
3954 | timestamp *res = getArgReference_TYPE(stk, pci, 0, timestamp); |
3955 | |
3956 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
3957 | return msg; |
3958 | |
3959 | *res = timestamp_add_usec(timestamp_current(), m->timezone * LL_CONSTANT(1000)); |
3960 | return msg; |
3961 | } |
3962 | |
3963 | /* str dump_cache(int *r); */ |
3964 | str |
3965 | dump_cache(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
3966 | { |
3967 | mvc *m = NULL; |
3968 | str msg; |
3969 | int cnt; |
3970 | cq *q = NULL; |
3971 | BAT *query, *count; |
3972 | bat *rquery = getArgReference_bat(stk, pci, 0); |
3973 | bat *rcount = getArgReference_bat(stk, pci, 1); |
3974 | |
3975 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
3976 | return msg; |
3977 | if ((msg = checkSQLContext(cntxt)) != NULL) |
3978 | return msg; |
3979 | cnt = m->qc->id; |
3980 | query = COLnew(0, TYPE_str, cnt, TRANSIENT); |
3981 | if (query == NULL) |
3982 | throw(SQL, "sql.dumpcache" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3983 | count = COLnew(0, TYPE_int, cnt, TRANSIENT); |
3984 | if (count == NULL) { |
3985 | BBPunfix(query->batCacheid); |
3986 | throw(SQL, "sql.dumpcache" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3987 | } |
3988 | |
3989 | for (q = m->qc->q; q; q = q->next) { |
3990 | if (!q->prepared) { |
3991 | if (BUNappend(query, q->codestring, false) != GDK_SUCCEED || |
3992 | BUNappend(count, &q->count, false) != GDK_SUCCEED) { |
3993 | BBPunfix(query->batCacheid); |
3994 | BBPunfix(count->batCacheid); |
3995 | throw(SQL, "sql.dumpcache" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
3996 | } |
3997 | } |
3998 | } |
3999 | *rquery = query->batCacheid; |
4000 | *rcount = count->batCacheid; |
4001 | BBPkeepref(*rquery); |
4002 | BBPkeepref(*rcount); |
4003 | return MAL_SUCCEED; |
4004 | } |
4005 | |
4006 | /* str dump_opt_stats(int *r); */ |
4007 | str |
4008 | dump_opt_stats(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4009 | { |
4010 | mvc *m = NULL; |
4011 | str msg; |
4012 | int cnt; |
4013 | BAT *rewrite, *count; |
4014 | bat *rrewrite = getArgReference_bat(stk, pci, 0); |
4015 | bat *rcount = getArgReference_bat(stk, pci, 1); |
4016 | |
4017 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL || |
4018 | (msg = checkSQLContext(cntxt)) != NULL) |
4019 | return msg; |
4020 | cnt = m->qc->id; |
4021 | rewrite = COLnew(0, TYPE_str, cnt, TRANSIENT); |
4022 | count = COLnew(0, TYPE_int, cnt, TRANSIENT); |
4023 | if (rewrite == NULL || count == NULL) { |
4024 | BBPreclaim(rewrite); |
4025 | BBPreclaim(count); |
4026 | throw(SQL, "sql.optstats" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4027 | } |
4028 | |
4029 | if (BUNappend(rewrite, "joinidx" , false) != GDK_SUCCEED || |
4030 | BUNappend(count, &m->opt_stats[0], false) != GDK_SUCCEED) { |
4031 | BBPreclaim(rewrite); |
4032 | BBPreclaim(count); |
4033 | throw(SQL, "sql.optstats" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4034 | } |
4035 | /* TODO add other rewrites */ |
4036 | |
4037 | *rrewrite = rewrite->batCacheid; |
4038 | *rcount = count->batCacheid; |
4039 | BBPkeepref(*rrewrite); |
4040 | BBPkeepref(*rcount); |
4041 | return MAL_SUCCEED; |
4042 | } |
4043 | |
4044 | /* str dump_opt_stats(int *r); */ |
4045 | str |
4046 | dump_trace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4047 | { |
4048 | int i; |
4049 | BAT *t[2]; |
4050 | bat id; |
4051 | |
4052 | (void) cntxt; |
4053 | (void) mb; |
4054 | if (TRACEtable(cntxt, t) != 2) |
4055 | throw(SQL, "sql.dump_trace" , SQLSTATE(3F000) "Profiler not started" ); |
4056 | for(i=0; i< 2; i++) |
4057 | if( t[i]){ |
4058 | id = t[i]->batCacheid; |
4059 | *getArgReference_bat(stk, pci, i) = id; |
4060 | BBPkeepref(id); |
4061 | } else |
4062 | throw(SQL,"dump_trace" , SQLSTATE(45000) "Missing trace BAT " ); |
4063 | return MAL_SUCCEED; |
4064 | } |
4065 | |
4066 | str |
4067 | sql_sessions_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4068 | { |
4069 | return CLTsessions(cntxt, mb, stk, pci); |
4070 | } |
4071 | |
4072 | str |
4073 | sql_rt_credentials_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4074 | { |
4075 | BAT *urib = NULL; |
4076 | BAT *unameb = NULL; |
4077 | BAT *hashb = NULL; |
4078 | bat *uri = getArgReference_bat(stk, pci, 0); |
4079 | bat *uname = getArgReference_bat(stk, pci, 1); |
4080 | bat *hash = getArgReference_bat(stk, pci, 2); |
4081 | str *table = getArgReference_str(stk, pci, 3); |
4082 | str uris; |
4083 | str unames; |
4084 | str hashs = NULL; |
4085 | str msg = MAL_SUCCEED; |
4086 | (void)mb; |
4087 | (void)cntxt; |
4088 | |
4089 | urib = COLnew(0, TYPE_str, 0, TRANSIENT); |
4090 | unameb = COLnew(0, TYPE_str, 0, TRANSIENT); |
4091 | hashb = COLnew(0, TYPE_str, 0, TRANSIENT); |
4092 | |
4093 | if (urib == NULL || unameb == NULL || hashb == NULL) { |
4094 | msg = createException(SQL, "sql.remote_table_credentials" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4095 | goto bailout; |
4096 | } |
4097 | |
4098 | if ((msg = AUTHgetRemoteTableCredentials(*table, &uris, &unames, &hashs)) != MAL_SUCCEED) |
4099 | goto bailout; |
4100 | |
4101 | MT_lock_set(&mal_contextLock); |
4102 | if (BUNappend(urib, uris, false) != GDK_SUCCEED) |
4103 | goto lbailout; |
4104 | if (BUNappend(unameb, unames, false) != GDK_SUCCEED) |
4105 | goto lbailout; |
4106 | if (BUNappend(hashb, hashs, false) != GDK_SUCCEED) |
4107 | goto lbailout; |
4108 | MT_lock_unset(&mal_contextLock); |
4109 | BBPkeepref(*uri = urib->batCacheid); |
4110 | BBPkeepref(*uname = unameb->batCacheid); |
4111 | BBPkeepref(*hash = hashb->batCacheid); |
4112 | |
4113 | if (hashs) GDKfree(hashs); |
4114 | return MAL_SUCCEED; |
4115 | |
4116 | lbailout: |
4117 | MT_lock_unset(&mal_contextLock); |
4118 | msg = createException(SQL, "sql.remote_table_credentials" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4119 | bailout: |
4120 | if (hashs) GDKfree(hashs); |
4121 | if (urib) BBPunfix(urib->batCacheid); |
4122 | if (unameb) BBPunfix(unameb->batCacheid); |
4123 | if (hashb) BBPunfix(hashb->batCacheid); |
4124 | return msg; |
4125 | } |
4126 | |
4127 | |
4128 | str |
4129 | sql_querylog_catalog(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4130 | { |
4131 | int i; |
4132 | BAT *t[8]; |
4133 | str msg; |
4134 | |
4135 | (void) cntxt; |
4136 | (void) mb; |
4137 | msg = QLOGcatalog(t); |
4138 | if( msg != MAL_SUCCEED) |
4139 | return msg; |
4140 | for (i = 0; i < 8; i++) |
4141 | if( t[i]){ |
4142 | bat id = t[i]->batCacheid; |
4143 | |
4144 | *getArgReference_bat(stk, pci, i) = id; |
4145 | BBPkeepref(id); |
4146 | } else |
4147 | throw(SQL,"sql.querylog" , SQLSTATE(45000) "Missing query catalog BAT" ); |
4148 | return MAL_SUCCEED; |
4149 | } |
4150 | |
4151 | str |
4152 | sql_querylog_calls(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4153 | { |
4154 | int i; |
4155 | BAT *t[10]; |
4156 | str msg; |
4157 | |
4158 | (void) cntxt; |
4159 | (void) mb; |
4160 | msg = QLOGcalls(t); |
4161 | if( msg != MAL_SUCCEED) |
4162 | return msg; |
4163 | for (i = 0; i < 9; i++) |
4164 | if( t[i]){ |
4165 | bat id = t[i]->batCacheid; |
4166 | |
4167 | *getArgReference_bat(stk, pci, i) = id; |
4168 | BBPkeepref(id); |
4169 | } else |
4170 | throw(SQL,"sql.querylog" , SQLSTATE(45000) "Missing query call BAT" ); |
4171 | return MAL_SUCCEED; |
4172 | } |
4173 | |
4174 | str |
4175 | sql_querylog_empty(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4176 | { |
4177 | (void) cntxt; |
4178 | (void) mb; |
4179 | (void) stk; |
4180 | (void) pci; |
4181 | return QLOGempty(NULL); |
4182 | } |
4183 | |
4184 | /* str sql_rowid(oid *rid, ptr v, str *sname, str *tname); */ |
4185 | str |
4186 | sql_rowid(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4187 | { |
4188 | BAT *b; |
4189 | mvc *m = NULL; |
4190 | str msg; |
4191 | sql_schema *s = NULL; |
4192 | sql_table *t = NULL; |
4193 | sql_column *c = NULL; |
4194 | sql_delta *d; |
4195 | oid *rid = getArgReference_oid(stk, pci, 0); |
4196 | const char *sname = *getArgReference_str(stk, pci, 2); |
4197 | const char *tname = *getArgReference_str(stk, pci, 3); |
4198 | |
4199 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
4200 | return msg; |
4201 | if ((msg = checkSQLContext(cntxt)) != NULL) |
4202 | return msg; |
4203 | s = mvc_bind_schema(m, sname); |
4204 | if (s == NULL) |
4205 | throw(SQL, "sql.rowid" , SQLSTATE(3F000) "Schema missing %s" , sname); |
4206 | t = mvc_bind_table(m, s, tname); |
4207 | if (t == NULL) |
4208 | throw(SQL, "sql.rowid" , SQLSTATE(42S02) "Table missing %s.%s" ,sname,tname); |
4209 | if (!s || !t || !t->columns.set->h) |
4210 | throw(SQL, "calc.rowid" , SQLSTATE(42S22) "Column missing %s.%s" ,sname,tname); |
4211 | c = t->columns.set->h->data; |
4212 | /* HACK, get insert bat */ |
4213 | b = store_funcs.bind_col(m->session->tr, c, RD_INS); |
4214 | if( b == NULL) |
4215 | throw(SQL,"sql.rowid" , SQLSTATE(HY005) "Canot access column descriptor" ); |
4216 | /* UGH (move into storage backends!!) */ |
4217 | d = c->data; |
4218 | *rid = d->ibase + BATcount(b); |
4219 | BBPunfix(b->batCacheid); |
4220 | return MAL_SUCCEED; |
4221 | } |
4222 | |
4223 | static str |
4224 | do_sql_rank_grp(bat *rid, const bat *bid, const bat *gid, int nrank, int dense, const char *name) |
4225 | { |
4226 | BAT *r, *b, *g; |
4227 | BUN p, q; |
4228 | BATiter bi, gi; |
4229 | int (*ocmp) (const void *, const void *); |
4230 | int (*gcmp) (const void *, const void *); |
4231 | const void *oc, *gc, *on, *gn; |
4232 | int rank = 1; |
4233 | int c; |
4234 | |
4235 | if ((b = BATdescriptor(*bid)) == NULL) |
4236 | throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor" ); |
4237 | if ((g = BATdescriptor(*gid)) == NULL) { |
4238 | BBPunfix(b->batCacheid); |
4239 | throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor" ); |
4240 | } |
4241 | bi = bat_iterator(b); |
4242 | gi = bat_iterator(g); |
4243 | ocmp = ATOMcompare(b->ttype); |
4244 | gcmp = ATOMcompare(g->ttype); |
4245 | oc = BUNtail(bi, 0); |
4246 | gc = BUNtail(gi, 0); |
4247 | if (!ALIGNsynced(b, g)) { |
4248 | BBPunfix(b->batCacheid); |
4249 | BBPunfix(g->batCacheid); |
4250 | throw(SQL, name, SQLSTATE(45000) "Internal error, columns not aligned" ); |
4251 | } |
4252 | /* |
4253 | if (!BATtordered(b)) { |
4254 | BBPunfix(b->batCacheid); |
4255 | BBPunfix(g->batCacheid); |
4256 | throw(SQL, name, SQLSTATE(45000) "Internal error, columns not sorted"); |
4257 | } |
4258 | */ |
4259 | r = COLnew(b->hseqbase, TYPE_int, BATcount(b), TRANSIENT); |
4260 | if (r == NULL) { |
4261 | BBPunfix(b->batCacheid); |
4262 | BBPunfix(g->batCacheid); |
4263 | throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4264 | } |
4265 | BATloop(b, p, q) { |
4266 | on = BUNtail(bi, p); |
4267 | gn = BUNtail(gi, p); |
4268 | |
4269 | if ((c = ocmp(on, oc)) != 0) |
4270 | rank = nrank; |
4271 | if (gcmp(gn, gc) != 0) |
4272 | c = rank = nrank = 1; |
4273 | oc = on; |
4274 | gc = gn; |
4275 | if (BUNappend(r, &rank, false) != GDK_SUCCEED) { |
4276 | BBPunfix(b->batCacheid); |
4277 | BBPunfix(g->batCacheid); |
4278 | BBPunfix(r->batCacheid); |
4279 | throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4280 | } |
4281 | nrank += !dense || c; |
4282 | } |
4283 | BBPunfix(b->batCacheid); |
4284 | BBPunfix(g->batCacheid); |
4285 | BBPkeepref(*rid = r->batCacheid); |
4286 | return MAL_SUCCEED; |
4287 | } |
4288 | |
4289 | static str |
4290 | do_sql_rank(bat *rid, const bat *bid, int nrank, int dense, const char *name) |
4291 | { |
4292 | BAT *r, *b; |
4293 | BATiter bi; |
4294 | int (*cmp) (const void *, const void *); |
4295 | const void *cur, *n; |
4296 | BUN p, q; |
4297 | int rank = 1; |
4298 | int c; |
4299 | |
4300 | if ((b = BATdescriptor(*bid)) == NULL) |
4301 | throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor" ); |
4302 | if (!BATtordered(b) && !BATtrevordered(b)) { |
4303 | BBPunfix(b->batCacheid); |
4304 | throw(SQL, name, SQLSTATE(45000) "Internal error, columns not sorted" ); |
4305 | } |
4306 | |
4307 | bi = bat_iterator(b); |
4308 | cmp = ATOMcompare(b->ttype); |
4309 | cur = BUNtail(bi, 0); |
4310 | r = COLnew(b->hseqbase, TYPE_int, BATcount(b), TRANSIENT); |
4311 | if (r == NULL) { |
4312 | BBPunfix(b->batCacheid); |
4313 | throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4314 | } |
4315 | if (BATtdense(b)) { |
4316 | BATloop(b, p, q) { |
4317 | if (BUNappend(r, &rank, false) != GDK_SUCCEED) |
4318 | goto bailout; |
4319 | rank++; |
4320 | } |
4321 | } else { |
4322 | BATloop(b, p, q) { |
4323 | n = BUNtail(bi, p); |
4324 | if ((c = cmp(n, cur)) != 0) |
4325 | rank = nrank; |
4326 | cur = n; |
4327 | if (BUNappend(r, &rank, false) != GDK_SUCCEED) |
4328 | goto bailout; |
4329 | nrank += !dense || c; |
4330 | } |
4331 | } |
4332 | BBPunfix(b->batCacheid); |
4333 | BBPkeepref(*rid = r->batCacheid); |
4334 | return MAL_SUCCEED; |
4335 | bailout: |
4336 | BBPunfix(b->batCacheid); |
4337 | BBPunfix(r->batCacheid); |
4338 | throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4339 | } |
4340 | |
4341 | str |
4342 | sql_rank_grp(bat *rid, const bat *bid, const bat *gid, const bat *gpe) |
4343 | { |
4344 | (void) gpe; |
4345 | return do_sql_rank_grp(rid, bid, gid, 1, 0, "sql.rank_grp" ); |
4346 | } |
4347 | |
4348 | str |
4349 | sql_dense_rank_grp(bat *rid, const bat *bid, const bat *gid, const bat *gpe) |
4350 | { |
4351 | (void) gpe; |
4352 | return do_sql_rank_grp(rid, bid, gid, 2, 1, "sql.dense_rank_grp" ); |
4353 | } |
4354 | |
4355 | str |
4356 | sql_rank(bat *rid, const bat *bid) |
4357 | { |
4358 | return do_sql_rank(rid, bid, 1, 0, "sql.rank" ); |
4359 | } |
4360 | |
4361 | str |
4362 | sql_dense_rank(bat *rid, const bat *bid) |
4363 | { |
4364 | return do_sql_rank(rid, bid, 2, 1, "sql.dense_rank" ); |
4365 | } |
4366 | |
4367 | str |
4368 | SQLargRecord(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4369 | { |
4370 | str s, t, *ret; |
4371 | |
4372 | (void) cntxt; |
4373 | ret = getArgReference_str(stk, pci, 0); |
4374 | s = instruction2str(mb, stk, getInstrPtr(mb, 0), LIST_MAL_ALL); |
4375 | if(s == NULL) |
4376 | throw(SQL, "sql.argRecord" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4377 | t = strchr(s, ' '); |
4378 | *ret = GDKstrdup(t ? t + 1 : s); |
4379 | GDKfree(s); |
4380 | if(*ret == NULL) |
4381 | throw(SQL, "sql.argRecord" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
4382 | return MAL_SUCCEED; |
4383 | } |
4384 | |
4385 | /* |
4386 | * Vacuum cleaning tables |
4387 | * Shrinking and re-using space to vacuum clean the holes in the relations. |
4388 | */ |
4389 | static str |
4390 | vacuum(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, str (*func) (bat *, const bat *, const bat *), const char *name) |
4391 | { |
4392 | const char *sch = *getArgReference_str(stk, pci, 1); |
4393 | const char *tbl = *getArgReference_str(stk, pci, 2); |
4394 | sql_trans *tr; |
4395 | sql_schema *s; |
4396 | sql_table *t; |
4397 | sql_column *c; |
4398 | mvc *m = NULL; |
4399 | str msg; |
4400 | bat bid; |
4401 | BAT *b, *del; |
4402 | node *o; |
4403 | int i, bids[2049]; |
4404 | |
4405 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
4406 | return msg; |
4407 | if ((msg = checkSQLContext(cntxt)) != NULL) |
4408 | return msg; |
4409 | s = mvc_bind_schema(m, sch); |
4410 | if (s == NULL) |
4411 | throw(SQL, name, SQLSTATE(3F000) "Schema missing %s" ,sch); |
4412 | t = mvc_bind_table(m, s, tbl); |
4413 | if (t == NULL) |
4414 | throw(SQL, name, SQLSTATE(42S02) "Table missing %s.%s" ,sch,tbl); |
4415 | |
4416 | if (m->user_id != USER_MONETDB) |
4417 | throw(SQL, name, SQLSTATE(42000) "Insufficient privileges" ); |
4418 | if ((!list_empty(t->idxs.set) || !list_empty(t->keys.set))) |
4419 | throw(SQL, name, SQLSTATE(42000) "%s not allowed on tables with indices" , name + 4); |
4420 | if (t->system) |
4421 | throw(SQL, name, SQLSTATE(42000) "%s not allowed on system tables" , name + 4); |
4422 | |
4423 | if (has_snapshots(m->session->tr)) |
4424 | throw(SQL, name, SQLSTATE(42000) "%s not allowed on snapshots" , name + 4); |
4425 | if (!m->session->auto_commit) |
4426 | throw(SQL, name, SQLSTATE(42000) "%s only allowed in auto commit mode" , name + 4); |
4427 | |
4428 | tr = m->session->tr; |
4429 | |
4430 | /* get the deletions BAT */ |
4431 | del = mvc_bind_dbat(m, sch, tbl, RD_INS); |
4432 | if (BATcount(del) == 0) { |
4433 | BBPunfix(del->batCacheid); |
4434 | return MAL_SUCCEED; |
4435 | } |
4436 | |
4437 | |
4438 | i = 0; |
4439 | bids[i] = 0; |
4440 | for (o = t->columns.set->h; o; o = o->next, i++) { |
4441 | c = o->data; |
4442 | b = store_funcs.bind_col(tr, c, RDONLY); |
4443 | if (b == NULL || (msg = (*func) (&bid, &b->batCacheid, &del->batCacheid)) != NULL) { |
4444 | for (i--; i >= 0; i--) |
4445 | BBPrelease(bids[i]); |
4446 | if (b) |
4447 | BBPunfix(b->batCacheid); |
4448 | BBPunfix(del->batCacheid); |
4449 | if (!msg) |
4450 | throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor" ); |
4451 | return msg; |
4452 | } |
4453 | BBPunfix(b->batCacheid); |
4454 | if (i < 2048) { |
4455 | bids[i] = bid; |
4456 | bids[i + 1] = 0; |
4457 | } |
4458 | } |
4459 | if (i >= 2048) { |
4460 | for (i--; i >= 0; i--) |
4461 | BBPrelease(bids[i]); |
4462 | throw(SQL, name, SQLSTATE(42000) "Too many columns to handle, use copy instead" ); |
4463 | } |
4464 | BBPunfix(del->batCacheid); |
4465 | |
4466 | mvc_clear_table(m, t); |
4467 | for (o = t->columns.set->h, i = 0; o; o = o->next, i++) { |
4468 | sql_column *c = o->data; |
4469 | BAT *ins = BATdescriptor(bids[i]); /* use the insert bat */ |
4470 | |
4471 | if( ins){ |
4472 | store_funcs.append_col(tr, c, ins, TYPE_bat); |
4473 | BBPunfix(ins->batCacheid); |
4474 | } |
4475 | BBPrelease(bids[i]); |
4476 | } |
4477 | /* TODO indices */ |
4478 | return MAL_SUCCEED; |
4479 | } |
4480 | |
4481 | str |
4482 | SQLshrink(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4483 | { |
4484 | return vacuum(cntxt, mb, stk, pci, BKCshrinkBAT, "sql.shrink" ); |
4485 | } |
4486 | |
4487 | str |
4488 | SQLreuse(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4489 | { |
4490 | return vacuum(cntxt, mb, stk, pci, BKCreuseBAT, "sql.reuse" ); |
4491 | } |
4492 | |
4493 | /* |
4494 | * The vacuum operation inspects the table for ordered properties and |
4495 | * will keep them. To avoid expensive shuffles, the reorganisation is |
4496 | * balanced by the number of outstanding deletions. |
4497 | */ |
4498 | str |
4499 | SQLvacuum(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4500 | { |
4501 | const char *sch = *getArgReference_str(stk, pci, 1); |
4502 | const char *tbl = *getArgReference_str(stk, pci, 2); |
4503 | sql_trans *tr; |
4504 | sql_schema *s; |
4505 | sql_table *t; |
4506 | sql_column *c; |
4507 | mvc *m = NULL; |
4508 | str msg; |
4509 | BAT *b, *del; |
4510 | node *o; |
4511 | int ordered = 0; |
4512 | BUN cnt = 0; |
4513 | BUN dcnt; |
4514 | |
4515 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
4516 | return msg; |
4517 | if ((msg = checkSQLContext(cntxt)) != NULL) |
4518 | return msg; |
4519 | s = mvc_bind_schema(m, sch); |
4520 | if (s == NULL) |
4521 | throw(SQL, "sql.vacuum" , SQLSTATE(3F000) "Schema missing %s" ,sch); |
4522 | t = mvc_bind_table(m, s, tbl); |
4523 | if (t == NULL) |
4524 | throw(SQL, "sql.vacuum" , SQLSTATE(42S02) "Table missing %s.%s" ,sch,tbl); |
4525 | |
4526 | if (m->user_id != USER_MONETDB) |
4527 | throw(SQL, "sql.vacuum" , SQLSTATE(42000) "insufficient privileges" ); |
4528 | if ((!list_empty(t->idxs.set) || !list_empty(t->keys.set))) |
4529 | throw(SQL, "sql.vacuum" , SQLSTATE(42000) "vacuum not allowed on tables with indices" ); |
4530 | if (t->system) |
4531 | throw(SQL, "sql.vacuum" , SQLSTATE(42000) "vacuum not allowed on system tables" ); |
4532 | |
4533 | if (has_snapshots(m->session->tr)) |
4534 | throw(SQL, "sql.vacuum" , SQLSTATE(42000) "vacuum not allowed on snapshots" ); |
4535 | |
4536 | if (!m->session->auto_commit) |
4537 | throw(SQL, "sql.vacuum" , SQLSTATE(42000) "vacuum only allowed in auto commit mode" ); |
4538 | tr = m->session->tr; |
4539 | |
4540 | for (o = t->columns.set->h; o && ordered == 0; o = o->next) { |
4541 | c = o->data; |
4542 | b = store_funcs.bind_col(tr, c, RDONLY); |
4543 | if (b == NULL) |
4544 | throw(SQL, "sql.vacuum" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
4545 | ordered |= BATtordered(b); |
4546 | cnt = BATcount(b); |
4547 | BBPunfix(b->batCacheid); |
4548 | } |
4549 | |
4550 | /* get the deletions BAT */ |
4551 | del = mvc_bind_dbat(m, sch, tbl, RD_INS); |
4552 | if( del == NULL) |
4553 | throw(SQL, "sql.vacuum" , SQLSTATE(HY005) "Cannot access deletion column" ); |
4554 | |
4555 | dcnt = BATcount(del); |
4556 | BBPunfix(del->batCacheid); |
4557 | if (dcnt > 0) { |
4558 | /* now decide on the algorithm */ |
4559 | if (ordered) { |
4560 | if (dcnt > cnt / 20) |
4561 | return SQLshrink(cntxt, mb, stk, pci); |
4562 | } else { |
4563 | return SQLreuse(cntxt, mb, stk, pci); |
4564 | } |
4565 | } |
4566 | return MAL_SUCCEED; |
4567 | } |
4568 | |
4569 | /* |
4570 | * The drop_hash operation cleans up any hash indices on any of the tables columns. |
4571 | */ |
4572 | str |
4573 | SQLdrop_hash(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4574 | { |
4575 | const char *sch = *getArgReference_str(stk, pci, 1); |
4576 | const char *tbl = *getArgReference_str(stk, pci, 2); |
4577 | sql_schema *s; |
4578 | sql_table *t; |
4579 | sql_column *c; |
4580 | mvc *m = NULL; |
4581 | str msg; |
4582 | BAT *b; |
4583 | node *o; |
4584 | |
4585 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
4586 | return msg; |
4587 | if ((msg = checkSQLContext(cntxt)) != NULL) |
4588 | return msg; |
4589 | s = mvc_bind_schema(m, sch); |
4590 | if (s == NULL) |
4591 | throw(SQL, "sql.drop_hash" , SQLSTATE(3F000) "Schema missing %s" ,sch); |
4592 | t = mvc_bind_table(m, s, tbl); |
4593 | if (t == NULL) |
4594 | throw(SQL, "sql.drop_hash" , SQLSTATE(42S02) "Table missing %s.%s" ,sch, tbl); |
4595 | |
4596 | for (o = t->columns.set->h; o; o = o->next) { |
4597 | c = o->data; |
4598 | b = store_funcs.bind_col(m->session->tr, c, RDONLY); |
4599 | if (b == NULL) |
4600 | throw(SQL, "sql.drop_hash" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
4601 | HASHdestroy(b); |
4602 | BBPunfix(b->batCacheid); |
4603 | } |
4604 | return MAL_SUCCEED; |
4605 | } |
4606 | |
4607 | |
4608 | /* after an update on the optimizer catalog, we have to change |
4609 | * the internal optimizer pipe line administration |
4610 | * The minimal and default pipelines may not be changed. |
4611 | */ |
4612 | str |
4613 | SQLoptimizersUpdate(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4614 | { |
4615 | mvc *m = NULL; |
4616 | str msg; |
4617 | |
4618 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
4619 | return msg; |
4620 | if ((msg = checkSQLContext(cntxt)) != NULL) |
4621 | return msg; |
4622 | /* find the optimizer pipeline */ |
4623 | (void) stk; |
4624 | (void) pci; |
4625 | throw(SQL, "updateOptimizer" , SQLSTATE(0A000) PROGRAM_NYI); |
4626 | } |
4627 | |
4628 | /* |
4629 | * Inspection of the actual storage footprint is a recurring question of users. |
4630 | * This is modelled as a generic SQL table producing function. |
4631 | * create function storage() |
4632 | * returns table ("schema" string, "table" string, "column" string, "type" string, "mode" string, location string, "count" bigint, width int, columnsize bigint, heapsize bigint indices bigint, sorted int) |
4633 | * external name sql.storage; |
4634 | */ |
4635 | str |
4636 | sql_storage(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
4637 | { |
4638 | BAT *sch, *tab, *col, *type, *loc, *cnt, *atom, *size, *heap, *indices, *phash, *sort, *imprints, *mode, *revsort, *key, *oidx; |
4639 | mvc *m = NULL; |
4640 | str msg; |
4641 | sql_trans *tr; |
4642 | node *nsch, *ntab, *ncol; |
4643 | int w; |
4644 | bit bitval; |
4645 | bat *rsch = getArgReference_bat(stk, pci, 0); |
4646 | bat *rtab = getArgReference_bat(stk, pci, 1); |
4647 | bat *rcol = getArgReference_bat(stk, pci, 2); |
4648 | bat *rtype = getArgReference_bat(stk, pci, 3); |
4649 | bat *rmode = getArgReference_bat(stk, pci, 4); |
4650 | bat *rloc = getArgReference_bat(stk, pci, 5); |
4651 | bat *rcnt = getArgReference_bat(stk, pci, 6); |
4652 | bat *ratom = getArgReference_bat(stk, pci, 7); |
4653 | bat *rsize = getArgReference_bat(stk, pci, 8); |
4654 | bat *rheap = getArgReference_bat(stk, pci, 9); |
4655 | bat *rindices = getArgReference_bat(stk, pci, 10); |
4656 | bat *rphash = getArgReference_bat(stk, pci, 11); |
4657 | bat *rimprints = getArgReference_bat(stk, pci, 12); |
4658 | bat *rsort = getArgReference_bat(stk, pci, 13); |
4659 | bat *rrevsort = getArgReference_bat(stk, pci, 14); |
4660 | bat *rkey = getArgReference_bat(stk, pci, 15); |
4661 | bat *roidx = getArgReference_bat(stk, pci, 16); |
4662 | str sname = 0; |
4663 | str tname = 0; |
4664 | str cname = 0; |
4665 | |
4666 | if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL) |
4667 | return msg; |
4668 | if ((msg = checkSQLContext(cntxt)) != NULL) |
4669 | return msg; |
4670 | |
4671 | tr = m->session->tr; |
4672 | sch = COLnew(0, TYPE_str, 0, TRANSIENT); |
4673 | tab = COLnew(0, TYPE_str, 0, TRANSIENT); |
4674 | col = COLnew(0, TYPE_str, 0, TRANSIENT); |
4675 | type = COLnew(0, TYPE_str, 0, TRANSIENT); |
4676 | mode = COLnew(0, TYPE_str, 0, TRANSIENT); |
4677 | loc = COLnew(0, TYPE_str, 0, TRANSIENT); |
4678 | cnt = COLnew(0, TYPE_lng, 0, TRANSIENT); |
4679 | atom = COLnew(0, TYPE_int, 0, TRANSIENT); |
4680 | size = COLnew(0, TYPE_lng, 0, TRANSIENT); |
4681 | heap = COLnew(0, TYPE_lng, 0, TRANSIENT); |
4682 | indices = COLnew(0, TYPE_lng, 0, TRANSIENT); |
4683 | phash = COLnew(0, TYPE_bit, 0, TRANSIENT); |
4684 | imprints = COLnew(0, TYPE_lng, 0, TRANSIENT); |
4685 | sort = COLnew(0, TYPE_bit, 0, TRANSIENT); |
4686 | revsort = COLnew(0, TYPE_bit, 0, TRANSIENT); |
4687 | key = COLnew(0, TYPE_bit, 0, TRANSIENT); |
4688 | oidx = COLnew(0, TYPE_lng, 0, TRANSIENT); |
4689 | |
4690 | if (sch == NULL || tab == NULL || col == NULL || type == NULL || mode == NULL || loc == NULL || imprints == NULL || |
4691 | sort == NULL || cnt == NULL || atom == NULL || size == NULL || heap == NULL || indices == NULL || phash == NULL || |
4692 | revsort == NULL || key == NULL || oidx == NULL) { |
4693 | goto bailout; |
4694 | } |
4695 | if( pci->argc - pci->retc >= 1) |
4696 | sname = *getArgReference_str(stk, pci, pci->retc); |
4697 | if( pci->argc - pci->retc >= 2) |
4698 | tname = *getArgReference_str(stk, pci, pci->retc + 1); |
4699 | if( pci->argc - pci->retc >= 3) |
4700 | cname = *getArgReference_str(stk, pci, pci->retc + 2); |
4701 | |
4702 | /* check for limited storage tables */ |
4703 | for (nsch = tr->schemas.set->h; nsch; nsch = nsch->next) { |
4704 | sql_base *b = nsch->data; |
4705 | sql_schema *s = (sql_schema *) nsch->data; |
4706 | if( sname && strcmp(b->name, sname) ) |
4707 | continue; |
4708 | if (isalpha((unsigned char) b->name[0])) |
4709 | if (s->tables.set) |
4710 | for (ntab = (s)->tables.set->h; ntab; ntab = ntab->next) { |
4711 | sql_base *bt = ntab->data; |
4712 | sql_table *t = (sql_table *) bt; |
4713 | if( tname && strcmp(bt->name, tname) ) |
4714 | continue; |
4715 | if (isTable(t)) |
4716 | if (t->columns.set) |
4717 | for (ncol = (t)->columns.set->h; ncol; ncol = ncol->next) { |
4718 | sql_base *bc = ncol->data; |
4719 | sql_column *c = (sql_column *) ncol->data; |
4720 | BAT *bn; |
4721 | lng sz; |
4722 | |
4723 | if( cname && strcmp(bc->name, cname) ) |
4724 | continue; |
4725 | bn = store_funcs.bind_col(tr, c, RDONLY); |
4726 | if (bn == NULL) |
4727 | throw(SQL, "sql.storage" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
4728 | |
4729 | /*printf("schema %s.%s.%s" , b->name, bt->name, bc->name); */ |
4730 | if (BUNappend(sch, b->name, false) != GDK_SUCCEED || |
4731 | BUNappend(tab, bt->name, false) != GDK_SUCCEED || |
4732 | BUNappend(col, bc->name, false) != GDK_SUCCEED) |
4733 | goto bailout; |
4734 | if (c->t->access == TABLE_WRITABLE) { |
4735 | if (BUNappend(mode, "writable" , false) != GDK_SUCCEED) |
4736 | goto bailout; |
4737 | } else if (c->t->access == TABLE_APPENDONLY) { |
4738 | if (BUNappend(mode, "appendonly" , false) != GDK_SUCCEED) |
4739 | goto bailout; |
4740 | } else if (c->t->access == TABLE_READONLY) { |
4741 | if (BUNappend(mode, "readonly" , false) != GDK_SUCCEED) |
4742 | goto bailout; |
4743 | } else { |
4744 | if (BUNappend(mode, str_nil, false) != GDK_SUCCEED) |
4745 | goto bailout; |
4746 | } |
4747 | if (BUNappend(type, c->type.type->sqlname, false) != GDK_SUCCEED) |
4748 | goto bailout; |
4749 | |
4750 | /*printf(" cnt "BUNFMT, BATcount(bn)); */ |
4751 | sz = BATcount(bn); |
4752 | if (BUNappend(cnt, &sz, false) != GDK_SUCCEED) |
4753 | goto bailout; |
4754 | |
4755 | /*printf(" loc %s", BBP_physical(bn->batCacheid)); */ |
4756 | if (BUNappend(loc, BBP_physical(bn->batCacheid), false) != GDK_SUCCEED) |
4757 | goto bailout; |
4758 | /*printf(" width %d", bn->twidth); */ |
4759 | w = bn->twidth; |
4760 | if (bn->ttype == TYPE_str) { |
4761 | BUN p, q; |
4762 | double sum = 0; |
4763 | BATiter bi = bat_iterator(bn); |
4764 | lng cnt1, cnt2 = cnt1 = (lng) BATcount(bn); |
4765 | |
4766 | /* just take a sample */ |
4767 | if (cnt1 > 512) |
4768 | cnt1 = cnt2 = 512; |
4769 | BATloop(bn, p, q) { |
4770 | str s = BUNtvar(bi, p); |
4771 | if (s != NULL && strcmp(s, str_nil)) |
4772 | sum += strlen(s); |
4773 | if (--cnt1 <= 0) |
4774 | break; |
4775 | } |
4776 | if (cnt2) |
4777 | w = (int) (sum / cnt2); |
4778 | } else if (ATOMvarsized(bn->ttype)) { |
4779 | sz = BATcount(bn); |
4780 | if (sz > 0) |
4781 | w = (int) ((bn->tvheap->free + sz / 2) / sz); |
4782 | else |
4783 | w = 0; |
4784 | } |
4785 | if (BUNappend(atom, &w, false) != GDK_SUCCEED) |
4786 | goto bailout; |
4787 | |
4788 | sz = BATcount(bn) * bn->twidth; |
4789 | if (BUNappend(size, &sz, false) != GDK_SUCCEED) |
4790 | goto bailout; |
4791 | |
4792 | sz = heapinfo(bn->tvheap, bn->batCacheid); |
4793 | if (BUNappend(heap, &sz, false) != GDK_SUCCEED) |
4794 | goto bailout; |
4795 | |
4796 | sz = hashinfo(bn->thash, bn->batCacheid); |
4797 | if (BUNappend(indices, &sz, false) != GDK_SUCCEED) |
4798 | goto bailout; |
4799 | |
4800 | bitval = 0; /* HASHispersistent(bn); */ |
4801 | if (BUNappend(phash, &bitval, false) != GDK_SUCCEED) |
4802 | goto bailout; |
4803 | |
4804 | sz = IMPSimprintsize(bn); |
4805 | if (BUNappend(imprints, &sz, false) != GDK_SUCCEED) |
4806 | goto bailout; |
4807 | /*printf(" indices "BUNFMT, bn->thash?bn->thash->heap.size:0); */ |
4808 | /*printf("\n"); */ |
4809 | |
4810 | bitval = BATtordered(bn); |
4811 | if (!bitval && bn->tnosorted == 0) |
4812 | bitval = bit_nil; |
4813 | if (BUNappend(sort, &bitval, false) != GDK_SUCCEED) |
4814 | goto bailout; |
4815 | |
4816 | bitval = BATtrevordered(bn); |
4817 | if (!bitval && bn->tnorevsorted == 0) |
4818 | bitval = bit_nil; |
4819 | if (BUNappend(revsort, &bitval, false) != GDK_SUCCEED) |
4820 | goto bailout; |
4821 | |
4822 | bitval = BATtkey(bn); |
4823 | if (!bitval && bn->tnokey[0] == 0 && bn->tnokey[1] == 0) |
4824 | bitval = bit_nil; |
4825 | if (BUNappend(key, &bitval, false) != GDK_SUCCEED) |
4826 | goto bailout; |
4827 | |
4828 | sz = bn->torderidx && bn->torderidx != (Heap *) 1 ? bn->torderidx->free : 0; |
4829 | if (BUNappend(oidx, &sz, false) != GDK_SUCCEED) |
4830 | goto bailout; |
4831 | BBPunfix(bn->batCacheid); |
4832 | } |
4833 | |
4834 | if (isTable(t)) |
4835 | if (t->idxs.set) |
4836 | for (ncol = (t)->idxs.set->h; ncol; ncol = ncol->next) { |
4837 | sql_base *bc = ncol->data; |
4838 | sql_idx *c = (sql_idx *) ncol->data; |
4839 | if (idx_has_column(c->type)) { |
4840 | BAT *bn = store_funcs.bind_idx(tr, c, RDONLY); |
4841 | lng sz; |
4842 | |
4843 | if (bn == NULL) |
4844 | throw(SQL, "sql.storage" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
4845 | if( cname && strcmp(bc->name, cname) ) |
4846 | continue; |
4847 | /*printf("schema %s.%s.%s" , b->name, bt->name, bc->name); */ |
4848 | if (BUNappend(sch, b->name, false) != GDK_SUCCEED || |
4849 | BUNappend(tab, bt->name, false) != GDK_SUCCEED || |
4850 | BUNappend(col, bc->name, false) != GDK_SUCCEED) |
4851 | goto bailout; |
4852 | if (c->t->access == TABLE_WRITABLE) { |
4853 | if (BUNappend(mode, "writable" , false) != GDK_SUCCEED) |
4854 | goto bailout; |
4855 | } else if (c->t->access == TABLE_APPENDONLY) { |
4856 | if (BUNappend(mode, "appendonly" , false) != GDK_SUCCEED) |
4857 | goto bailout; |
4858 | } else if (c->t->access == TABLE_READONLY) { |
4859 | if (BUNappend(mode, "readonly" , false) != GDK_SUCCEED) |
4860 | goto bailout; |
4861 | } else { |
4862 | if (BUNappend(mode, str_nil, false) != GDK_SUCCEED) |
4863 | goto bailout; |
4864 | } |
4865 | if (BUNappend(type, "oid" , false) != GDK_SUCCEED) |
4866 | goto bailout; |
4867 | |
4868 | /*printf(" cnt "BUNFMT, BATcount(bn)); */ |
4869 | sz = BATcount(bn); |
4870 | if (BUNappend(cnt, &sz, false) != GDK_SUCCEED) |
4871 | goto bailout; |
4872 | |
4873 | /*printf(" loc %s", BBP_physical(bn->batCacheid)); */ |
4874 | if (BUNappend(loc, BBP_physical(bn->batCacheid), false) != GDK_SUCCEED) |
4875 | goto bailout; |
4876 | /*printf(" width %d", bn->twidth); */ |
4877 | w = bn->twidth; |
4878 | if (bn->ttype == TYPE_str) { |
4879 | BUN p, q; |
4880 | double sum = 0; |
4881 | BATiter bi = bat_iterator(bn); |
4882 | lng cnt1, cnt2 = cnt1 = BATcount(bn); |
4883 | |
4884 | /* just take a sample */ |
4885 | if (cnt1 > 512) |
4886 | cnt1 = cnt2 = 512; |
4887 | BATloop(bn, p, q) { |
4888 | str s = BUNtvar(bi, p); |
4889 | if (s != NULL && strcmp(s, str_nil)) |
4890 | sum += strlen(s); |
4891 | if (--cnt1 <= 0) |
4892 | break; |
4893 | } |
4894 | if (cnt2) |
4895 | w = (int) (sum / cnt2); |
4896 | } |
4897 | if (BUNappend(atom, &w, false) != GDK_SUCCEED) |
4898 | goto bailout; |
4899 | /*printf(" size "BUNFMT, tailsize(bn,BATcount(bn)) + (bn->tvheap? bn->tvheap->size:0)); */ |
4900 | sz = tailsize(bn, BATcount(bn)); |
4901 | if (BUNappend(size, &sz, false) != GDK_SUCCEED) |
4902 | goto bailout; |
4903 | |
4904 | sz = bn->tvheap ? bn->tvheap->size : 0; |
4905 | if (BUNappend(heap, &sz, false) != GDK_SUCCEED) |
4906 | goto bailout; |
4907 | |
4908 | sz = bn->thash && bn->thash != (Hash *) 1 ? bn->thash->heap.size : 0; /* HASHsize() */ |
4909 | if (BUNappend(indices, &sz, false) != GDK_SUCCEED) |
4910 | goto bailout; |
4911 | bitval = 0; /* HASHispersistent(bn); */ |
4912 | if (BUNappend(phash, &bitval, false) != GDK_SUCCEED) |
4913 | goto bailout; |
4914 | |
4915 | sz = IMPSimprintsize(bn); |
4916 | if (BUNappend(imprints, &sz, false) != GDK_SUCCEED) |
4917 | goto bailout; |
4918 | /*printf(" indices "BUNFMT, bn->thash?bn->thash->heap.size:0); */ |
4919 | /*printf("\n"); */ |
4920 | bitval = BATtordered(bn); |
4921 | if (!bitval && bn->tnosorted == 0) |
4922 | bitval = bit_nil; |
4923 | if (BUNappend(sort, &bitval, false) != GDK_SUCCEED) |
4924 | goto bailout; |
4925 | bitval = BATtrevordered(bn); |
4926 | if (!bitval && bn->tnorevsorted == 0) |
4927 | bitval = bit_nil; |
4928 | if (BUNappend(revsort, &bitval, false) != GDK_SUCCEED) |
4929 | goto bailout; |
4930 | bitval = BATtkey(bn); |
4931 | if (!bitval && bn->tnokey[0] == 0 && bn->tnokey[1] == 0) |
4932 | bitval = bit_nil; |
4933 | if (BUNappend(key, &bitval, false) != GDK_SUCCEED) |
4934 | goto bailout; |
4935 | sz = bn->torderidx && bn->torderidx != (Heap *) 1 ? bn->torderidx->free : 0; |
4936 | if (BUNappend(oidx, &sz, false) != GDK_SUCCEED) |
4937 | goto bailout; |
4938 | BBPunfix(bn->batCacheid); |
4939 | } |
4940 | } |
4941 | |
4942 | } |
4943 | } |
4944 | |
4945 | BBPkeepref(*rsch = sch->batCacheid); |
4946 | BBPkeepref(*rtab = tab->batCacheid); |
4947 | BBPkeepref(*rcol = col->batCacheid); |
4948 | BBPkeepref(*rmode = mode->batCacheid); |
4949 | BBPkeepref(*rloc = loc->batCacheid); |
4950 | BBPkeepref(*rtype = type->batCacheid); |
4951 | BBPkeepref(*rcnt = cnt->batCacheid); |
4952 | BBPkeepref(*ratom = atom->batCacheid); |
4953 | BBPkeepref(*rsize = size->batCacheid); |
4954 | BBPkeepref(*rheap = heap->batCacheid); |
4955 | BBPkeepref(*rindices = indices->batCacheid); |
4956 | BBPkeepref(*rphash = phash->batCacheid); |
4957 | BBPkeepref(*rimprints = imprints->batCacheid); |
4958 | BBPkeepref(*rsort = sort->batCacheid); |
4959 | BBPkeepref(*rrevsort = revsort->batCacheid); |
4960 | BBPkeepref(*rkey = key->batCacheid); |
4961 | BBPkeepref(*roidx = oidx->batCacheid); |
4962 | return MAL_SUCCEED; |
4963 | |
4964 | bailout: |
4965 | if (sch) |
4966 | BBPunfix(sch->batCacheid); |
4967 | if (tab) |
4968 | BBPunfix(tab->batCacheid); |
4969 | if (col) |
4970 | BBPunfix(col->batCacheid); |
4971 | if (mode) |
4972 | BBPunfix(mode->batCacheid); |
4973 | if (loc) |
4974 | BBPunfix(loc->batCacheid); |
4975 | if (cnt) |
4976 | BBPunfix(cnt->batCacheid); |
4977 | if (type) |
4978 | BBPunfix(type->batCacheid); |
4979 | if (atom) |
4980 | BBPunfix(atom->batCacheid); |
4981 | if (size) |
4982 | BBPunfix(size->batCacheid); |
4983 | if (heap) |
4984 | BBPunfix(heap->batCacheid); |
4985 | if (indices) |
4986 | BBPunfix(indices->batCacheid); |
4987 | if (phash) |
4988 | BBPunfix(phash->batCacheid); |
4989 | if (imprints) |
4990 | BBPunfix(imprints->batCacheid); |
4991 | if (sort) |
4992 | BBPunfix(sort->batCacheid); |
4993 | if (revsort) |
4994 | BBPunfix(revsort->batCacheid); |
4995 | if (key) |
4996 | BBPunfix(key->batCacheid); |
4997 | if (oidx) |
4998 | BBPunfix(oidx->batCacheid); |
4999 | throw(SQL, "sql.storage" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5000 | } |
5001 | |
5002 | void |
5003 | freeVariables(Client c, MalBlkPtr mb, MalStkPtr glb, int start) |
5004 | { |
5005 | int i; |
5006 | |
5007 | for (i = start; i < mb->vtop;) { |
5008 | if (glb) { |
5009 | if (isVarCleanup(mb, i)) |
5010 | garbageElement(c, &glb->stk[i]); |
5011 | /* clean stack entry */ |
5012 | glb->stk[i].vtype = TYPE_int; |
5013 | glb->stk[i].val.ival = 0; |
5014 | glb->stk[i].len = 0; |
5015 | } |
5016 | clearVariable(mb, i); |
5017 | i++; |
5018 | } |
5019 | mb->vtop = start; |
5020 | } |
5021 | |
5022 | /* if at least (2*SIZEOF_BUN), also store length (heaps are then |
5023 | * incompatible) */ |
5024 | #define ((SIZEOF_BUN + GDK_VARALIGN - 1) & ~(GDK_VARALIGN - 1)) |
5025 | |
5026 | str |
5027 | STRindex_int(int *i, const str *src, const bit *u) |
5028 | { |
5029 | (void)src; (void)u; |
5030 | *i = 0; |
5031 | return MAL_SUCCEED; |
5032 | } |
5033 | |
5034 | str |
5035 | BATSTRindex_int(bat *res, const bat *src, const bit *u) |
5036 | { |
5037 | BAT *s, *r; |
5038 | |
5039 | if ((s = BATdescriptor(*src)) == NULL) |
5040 | throw(SQL, "calc.index" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
5041 | |
5042 | if (*u) { |
5043 | Heap *h = s->tvheap; |
5044 | size_t pad, pos; |
5045 | const size_t = h->hashash ? EXTRALEN : 0; |
5046 | int v; |
5047 | |
5048 | r = COLnew(0, TYPE_int, 1024, TRANSIENT); |
5049 | if (r == NULL) { |
5050 | BBPunfix(s->batCacheid); |
5051 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5052 | } |
5053 | pos = GDK_STRHASHSIZE; |
5054 | while (pos < h->free) { |
5055 | const char *p; |
5056 | |
5057 | pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1)); |
5058 | if (pad < sizeof(stridx_t)) |
5059 | pad += GDK_VARALIGN; |
5060 | pos += pad + extralen; |
5061 | p = h->base + pos; |
5062 | v = (int) (pos - GDK_STRHASHSIZE); |
5063 | if (BUNappend(r, &v, false) != GDK_SUCCEED) { |
5064 | BBPreclaim(r); |
5065 | BBPunfix(s->batCacheid); |
5066 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5067 | } |
5068 | pos += GDK_STRLEN(p); |
5069 | } |
5070 | } else { |
5071 | r = VIEWcreate(s->hseqbase, s); |
5072 | if (r == NULL) { |
5073 | BBPunfix(s->batCacheid); |
5074 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5075 | } |
5076 | r->ttype = TYPE_int; |
5077 | r->tvarsized = false; |
5078 | r->tvheap = NULL; |
5079 | } |
5080 | BBPunfix(s->batCacheid); |
5081 | BBPkeepref((*res = r->batCacheid)); |
5082 | return MAL_SUCCEED; |
5083 | } |
5084 | |
5085 | str |
5086 | STRindex_sht(sht *i, const str *src, const bit *u) |
5087 | { |
5088 | (void)src; (void)u; |
5089 | *i = 0; |
5090 | return MAL_SUCCEED; |
5091 | } |
5092 | |
5093 | str |
5094 | BATSTRindex_sht(bat *res, const bat *src, const bit *u) |
5095 | { |
5096 | BAT *s, *r; |
5097 | |
5098 | if ((s = BATdescriptor(*src)) == NULL) |
5099 | throw(SQL, "calc.index" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
5100 | |
5101 | if (*u) { |
5102 | Heap *h = s->tvheap; |
5103 | size_t pad, pos; |
5104 | const size_t = h->hashash ? EXTRALEN : 0; |
5105 | sht v; |
5106 | |
5107 | r = COLnew(0, TYPE_sht, 1024, TRANSIENT); |
5108 | if (r == NULL) { |
5109 | BBPunfix(s->batCacheid); |
5110 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5111 | } |
5112 | pos = GDK_STRHASHSIZE; |
5113 | while (pos < h->free) { |
5114 | const char *s; |
5115 | |
5116 | pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1)); |
5117 | if (pad < sizeof(stridx_t)) |
5118 | pad += GDK_VARALIGN; |
5119 | pos += pad + extralen; |
5120 | s = h->base + pos; |
5121 | v = (sht) (pos - GDK_STRHASHSIZE); |
5122 | if (BUNappend(r, &v, false) != GDK_SUCCEED) { |
5123 | BBPreclaim(r); |
5124 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5125 | } |
5126 | pos += GDK_STRLEN(s); |
5127 | } |
5128 | } else { |
5129 | r = VIEWcreate(s->hseqbase, s); |
5130 | if (r == NULL) { |
5131 | BBPunfix(s->batCacheid); |
5132 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5133 | } |
5134 | r->ttype = TYPE_sht; |
5135 | r->tvarsized = false; |
5136 | r->tvheap = NULL; |
5137 | } |
5138 | BBPunfix(s->batCacheid); |
5139 | BBPkeepref((*res = r->batCacheid)); |
5140 | return MAL_SUCCEED; |
5141 | } |
5142 | |
5143 | str |
5144 | STRindex_bte(bte *i, const str *src, const bit *u) |
5145 | { |
5146 | (void)src; (void)u; |
5147 | *i = 0; |
5148 | return MAL_SUCCEED; |
5149 | } |
5150 | |
5151 | str |
5152 | BATSTRindex_bte(bat *res, const bat *src, const bit *u) |
5153 | { |
5154 | BAT *s, *r; |
5155 | |
5156 | if ((s = BATdescriptor(*src)) == NULL) |
5157 | throw(SQL, "calc.index" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
5158 | |
5159 | if (*u) { |
5160 | Heap *h = s->tvheap; |
5161 | size_t pad, pos; |
5162 | const size_t = h->hashash ? EXTRALEN : 0; |
5163 | bte v; |
5164 | |
5165 | r = COLnew(0, TYPE_bte, 64, TRANSIENT); |
5166 | if (r == NULL) { |
5167 | BBPunfix(s->batCacheid); |
5168 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5169 | } |
5170 | pos = GDK_STRHASHSIZE; |
5171 | while (pos < h->free) { |
5172 | const char *p; |
5173 | |
5174 | pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1)); |
5175 | if (pad < sizeof(stridx_t)) |
5176 | pad += GDK_VARALIGN; |
5177 | pos += pad + extralen; |
5178 | p = h->base + pos; |
5179 | v = (bte) (pos - GDK_STRHASHSIZE); |
5180 | if (BUNappend(r, &v, false) != GDK_SUCCEED) { |
5181 | BBPreclaim(r); |
5182 | BBPunfix(s->batCacheid); |
5183 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5184 | } |
5185 | pos += GDK_STRLEN(p); |
5186 | } |
5187 | } else { |
5188 | r = VIEWcreate(s->hseqbase, s); |
5189 | if (r == NULL) { |
5190 | BBPunfix(s->batCacheid); |
5191 | throw(SQL, "calc.index" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5192 | } |
5193 | r->ttype = TYPE_bte; |
5194 | r->tvarsized = false; |
5195 | r->tvheap = NULL; |
5196 | } |
5197 | BBPunfix(s->batCacheid); |
5198 | BBPkeepref((*res = r->batCacheid)); |
5199 | return MAL_SUCCEED; |
5200 | } |
5201 | |
5202 | str |
5203 | STRstrings(str *i, const str *src) |
5204 | { |
5205 | (void)src; |
5206 | *i = 0; |
5207 | return MAL_SUCCEED; |
5208 | } |
5209 | |
5210 | str |
5211 | BATSTRstrings(bat *res, const bat *src) |
5212 | { |
5213 | BAT *s, *r; |
5214 | Heap *h; |
5215 | size_t pad, pos; |
5216 | size_t ; |
5217 | |
5218 | if ((s = BATdescriptor(*src)) == NULL) |
5219 | throw(SQL, "calc.strings" , SQLSTATE(HY005) "Cannot access column descriptor" ); |
5220 | |
5221 | h = s->tvheap; |
5222 | extralen = h->hashash ? EXTRALEN : 0; |
5223 | r = COLnew(0, TYPE_str, 1024, TRANSIENT); |
5224 | if (r == NULL) { |
5225 | BBPunfix(s->batCacheid); |
5226 | throw(SQL, "calc.strings" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5227 | } |
5228 | pos = GDK_STRHASHSIZE; |
5229 | while (pos < h->free) { |
5230 | const char *p; |
5231 | |
5232 | pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1)); |
5233 | if (pad < sizeof(stridx_t)) |
5234 | pad += GDK_VARALIGN; |
5235 | pos += pad + extralen; |
5236 | p = h->base + pos; |
5237 | if (BUNappend(r, p, false) != GDK_SUCCEED) { |
5238 | BBPreclaim(r); |
5239 | BBPunfix(s->batCacheid); |
5240 | throw(SQL, "calc.strings" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
5241 | } |
5242 | pos += GDK_STRLEN(p); |
5243 | } |
5244 | BBPunfix(s->batCacheid); |
5245 | BBPkeepref((*res = r->batCacheid)); |
5246 | return MAL_SUCCEED; |
5247 | } |
5248 | |
5249 | str |
5250 | SQLflush_log(void *ret) |
5251 | { |
5252 | (void)ret; |
5253 | store_flush_log(); |
5254 | return MAL_SUCCEED; |
5255 | } |
5256 | |
5257 | str |
5258 | SQLresume_log_flushing(void *ret) |
5259 | { |
5260 | (void)ret; |
5261 | store_resume_log(); |
5262 | return MAL_SUCCEED; |
5263 | } |
5264 | |
5265 | str |
5266 | SQLsuspend_log_flushing(void *ret) |
5267 | { |
5268 | (void)ret; |
5269 | store_suspend_log(); |
5270 | return MAL_SUCCEED; |
5271 | } |
5272 | |
5273 | str |
5274 | SQLhot_snapshot(void *ret, const str *tarfile_arg) |
5275 | { |
5276 | (void)ret; |
5277 | char *tarfile = *tarfile_arg; |
5278 | lng result = store_hot_snapshot(tarfile); |
5279 | if (result) |
5280 | return MAL_SUCCEED; |
5281 | else |
5282 | throw(SQL, "sql.hot_snapshot" , GDK_EXCEPTION); |
5283 | } |
5284 | |