Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include "sql_catalog.h"
15 : #include "sql_storage.h"
16 :
17 : const char *TID = "%TID%";
18 :
19 : inline int
20 1273368 : base_key( sql_base *b )
21 : {
22 1273368 : return hash_key(b->name);
23 : }
24 :
25 : void
26 533253 : trans_add(sql_trans *tr, sql_base *b, void *data, tc_cleanup_fptr cleanup, tc_commit_fptr commit, tc_log_fptr log)
27 : {
28 533253 : sql_change *change = MNEW(sql_change);
29 :
30 533250 : *change = (sql_change) {
31 : .obj = b,
32 : .data = data,
33 : .cleanup = cleanup,
34 : .commit = commit,
35 : .log = log,
36 : };
37 533250 : MT_lock_set(&tr->lock);
38 533249 : tr->changes = list_add(tr->changes, change);
39 533166 : if (log)
40 236393 : tr->logchanges++;
41 533166 : MT_lock_unset(&tr->lock);
42 533235 : }
43 :
44 : void
45 7 : trans_del(sql_trans *tr, sql_base *b)
46 : {
47 7 : MT_lock_set(&tr->lock);
48 68 : for(node *n= tr->changes->h; n; n = n->next) {
49 61 : sql_change *c = n->data;
50 61 : if (c->obj == b) {
51 1 : if (c->log)
52 1 : tr->logchanges--;
53 1 : _DELETE(c);
54 1 : n = list_remove_node(tr->changes, NULL, n);
55 : }
56 : }
57 7 : MT_lock_unset(&tr->lock);
58 7 : }
59 :
60 : int
61 5964 : tr_version_of_parent(sql_trans *tr, ulng ts)
62 : {
63 11087 : for( tr = tr->parent; tr; tr = tr->parent)
64 7713 : if (tr->tid == ts)
65 : return 1;
66 : return 0;
67 : }
68 :
69 : node *
70 105 : list_find_name(list *l, const char *name)
71 : {
72 105 : node *n;
73 :
74 105 : if (l)
75 320 : for (n = l->h; n; n = n->next) {
76 314 : sql_base *b = n->data;
77 :
78 : /* check if names match */
79 314 : if (name[0] == b->name[0] && strcmp(name, b->name) == 0) {
80 99 : return n;
81 : }
82 : }
83 : return NULL;
84 : }
85 :
86 : node *
87 0 : cs_find_id(changeset * cs, sqlid id)
88 : {
89 0 : node *n;
90 0 : list *l = cs->set;
91 :
92 0 : if (l)
93 0 : for (n = l->h; n; n = n->next) {
94 0 : sql_base *b = n->data;
95 :
96 : /* check if names match */
97 0 : if (b->id == id) {
98 0 : return n;
99 : }
100 : }
101 : return NULL;
102 : }
103 :
104 : node *
105 823 : list_find_id(list *l, sqlid id)
106 : {
107 823 : if (l) {
108 821 : node *n;
109 10397 : for (n = l->h; n; n = n->next) {
110 :
111 : /* check if ids match */
112 9583 : if (id == *(sqlid *) n->data) {
113 7 : return n;
114 : }
115 : }
116 : }
117 : return NULL;
118 : }
119 :
120 : node *
121 0 : list_find_base_id(list *l, sqlid id)
122 : {
123 0 : if (l) {
124 0 : node *n;
125 0 : for (n = l->h; n; n = n->next) {
126 0 : sql_base *b = n->data;
127 :
128 0 : if (id == b->id)
129 0 : return n;
130 : }
131 : }
132 : return NULL;
133 : }
134 :
135 : sql_key *
136 483 : find_sql_key(sql_table *t, const char *kname)
137 : {
138 483 : node *n = ol_find_name(t->keys, kname);
139 483 : if (n)
140 0 : return n->data;
141 : return NULL;
142 : }
143 :
144 : sql_key *
145 278 : sql_trans_find_key(sql_trans *tr, sqlid id)
146 : {
147 278 : struct os_iter oi;
148 278 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
149 278 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
150 278 : sql_schema *s = (sql_schema*)b;
151 278 : sql_base *bk = os_find_id(s->keys, tr, id);
152 278 : if (bk)
153 278 : return (sql_key*)bk;
154 : }
155 : return NULL;
156 : }
157 :
158 : sql_key *
159 6953 : schema_find_key(sql_trans *tr, sql_schema *s, const char *name)
160 : {
161 6953 : sql_base *b = os_find_name(s->keys, tr, name);
162 :
163 6953 : if (!b && tr->tmp == s) {
164 92 : struct os_iter oi;
165 92 : os_iterator(&oi, tr->localtmps, tr, NULL);
166 575 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
167 483 : sql_table *t = (sql_table *) b;
168 483 : sql_key *o = find_sql_key(t, name);
169 483 : if (o)
170 0 : return o;
171 : }
172 : }
173 : return (sql_key*)b;
174 : }
175 :
176 : sql_idx *
177 11263 : find_sql_idx(sql_table *t, const char *iname)
178 : {
179 11263 : node *n = ol_find_name(t->idxs, iname);
180 11263 : if (n)
181 4101 : return n->data;
182 : return NULL;
183 : }
184 :
185 : sql_idx *
186 8 : sql_trans_find_idx(sql_trans *tr, sqlid id)
187 : {
188 8 : struct os_iter oi;
189 8 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
190 8 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
191 8 : sql_schema *s = (sql_schema*)b;
192 8 : sql_base *bi = os_find_id(s->idxs, tr, id);
193 8 : if (bi)
194 8 : return (sql_idx*)bi;
195 : }
196 : return NULL;
197 : }
198 :
199 : sql_idx *
200 20697 : schema_find_idx(sql_trans *tr, sql_schema *s, const char *name)
201 : {
202 20697 : sql_base *b = os_find_name(s->idxs, tr, name);
203 :
204 20805 : if (!b && tr->tmp == s) {
205 303 : struct os_iter oi;
206 303 : os_iterator(&oi, tr->localtmps, tr, NULL);
207 1074 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
208 806 : sql_table *t = (sql_table *) b;
209 806 : sql_idx *o = find_sql_idx(t, name);
210 806 : if (o)
211 35 : return o;
212 : }
213 : }
214 : return (sql_idx*)b;
215 : }
216 :
217 : sql_idx *
218 1162 : schema_find_idx_id(sql_trans *tr, sql_schema *s, sqlid id)
219 : {
220 1162 : sql_base *b = os_find_id(s->idxs, tr, id);
221 :
222 1162 : if (!b && tr->tmp == s) {
223 24 : struct os_iter oi;
224 24 : os_iterator(&oi, tr->localtmps, tr, NULL);
225 122 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
226 122 : sql_table *t = (sql_table *) b;
227 122 : node *o = ol_find_id(t->idxs, id);
228 122 : if (o)
229 24 : return (sql_idx*)o->data;
230 : }
231 : }
232 : return (sql_idx*)b;
233 : }
234 :
235 :
236 : sql_column *
237 10163101 : find_sql_column(sql_table *t, const char *cname)
238 : {
239 10163101 : node *n = ol_find_name(t->columns, cname);
240 10213289 : if (n)
241 9953591 : return n->data;
242 : return NULL;
243 : }
244 :
245 : sql_table *
246 7558445 : find_sql_table(sql_trans *tr, sql_schema *s, const char *tname)
247 : {
248 7558445 : sql_table *t = (sql_table*)os_find_name(s->tables, tr, tname);
249 :
250 7616538 : if (!t && tr->tmp == s) {
251 208020 : t = (sql_table*) os_find_name(tr->localtmps, tr, tname);
252 208020 : return t;
253 : }
254 :
255 7345501 : if (t && isTempTable(t) && tr->tmp == s) {
256 52346 : assert(isGlobal(t));
257 :
258 52346 : sql_table* lt = (sql_table*) os_find_name(tr->localtmps, tr, tname);
259 52394 : if (lt)
260 : return lt;
261 :
262 4150 : t = globaltmp_instantiate(tr, t);
263 4150 : return t;
264 : }
265 :
266 : return t;
267 : }
268 :
269 : sql_table *
270 37894 : find_sql_table_id(sql_trans *tr, sql_schema *s, sqlid id)
271 : {
272 37894 : sql_table *t = (sql_table*)os_find_id(s->tables, tr, id);
273 37894 : if (!t && tr->tmp == s) {
274 59 : t = (sql_table*) os_find_id(tr->localtmps, tr, id);
275 59 : return t;
276 : }
277 :
278 37835 : if (t && isTempTable(t) && tr->tmp == s) {
279 52 : assert(isGlobal(t));
280 :
281 52 : sql_table* lt = (sql_table*) os_find_id(tr->localtmps, tr, id);
282 52 : if (lt)
283 : return lt;
284 :
285 0 : t = globaltmp_instantiate(tr, t);
286 0 : return t;
287 : }
288 : return t;
289 : }
290 :
291 : sql_table *
292 223 : sql_trans_find_table(sql_trans *tr, sqlid id)
293 : {
294 223 : struct os_iter oi;
295 223 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
296 371 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
297 371 : sql_schema *s = (sql_schema*)b;
298 371 : sql_base *bt = os_find_id(s->tables, tr, id);
299 371 : if (bt)
300 223 : return (sql_table*)bt;
301 : }
302 : return NULL;
303 : }
304 :
305 : sql_sequence *
306 3630 : find_sql_sequence(sql_trans *tr, sql_schema *s, const char *sname)
307 : {
308 3630 : return (sql_sequence*)os_find_name(s->seqs, tr, sname);
309 : }
310 :
311 : sql_schema *
312 10385913 : find_sql_schema(sql_trans *tr, const char *sname)
313 : {
314 10385913 : if (tr->tmp && strcmp(sname, "tmp")==0)
315 : return tr->tmp;
316 9791950 : return (sql_schema*)os_find_name(tr->cat->schemas, tr, sname);
317 : }
318 :
319 : sql_schema *
320 1743 : find_sql_schema_id(sql_trans *tr, sqlid id)
321 : {
322 1743 : if (tr->tmp && tr->tmp->base.id == id)
323 : return tr->tmp;
324 1403 : return (sql_schema*)os_find_id(tr->cat->schemas, tr, id);
325 : }
326 :
327 : sql_type *
328 61121 : find_sql_type(sql_trans *tr, sql_schema *s, const char *tname)
329 : {
330 61121 : return (sql_type*)os_find_name(s->types, tr, tname);
331 : }
332 :
333 : sql_type *
334 49422 : sql_trans_bind_type(sql_trans *tr, sql_schema *c, const char *name)
335 : {
336 49422 : struct os_iter oi;
337 49422 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
338 50969 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
339 50748 : sql_schema *s = (sql_schema*)b;
340 50748 : sql_type *t = find_sql_type(tr, s, name);
341 50748 : if (t)
342 49201 : return t;
343 : }
344 221 : if (c)
345 0 : return find_sql_type(tr, c, name);
346 : return NULL;
347 : }
348 :
349 : sql_type *
350 3 : sql_trans_find_type(sql_trans *tr, sql_schema *s, sqlid id)
351 : {
352 3 : if (s) {
353 3 : sql_base *b = os_find_id(s->types, tr, id);
354 3 : if (b)
355 : return (sql_type*)b;
356 : } else {
357 0 : struct os_iter oi;
358 0 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
359 0 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
360 0 : sql_schema *s = (sql_schema*)b;
361 0 : sql_base *bt = os_find_id(s->types, tr, id);
362 0 : if (bt)
363 0 : return (sql_type*)bt;
364 : }
365 : }
366 : return NULL;
367 : }
368 :
369 : sql_func *
370 399 : sql_trans_find_func(sql_trans *tr, sqlid id)
371 : {
372 399 : struct os_iter oi;
373 399 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
374 611 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
375 606 : sql_schema *s = (sql_schema*)b;
376 606 : sql_base *bf = os_find_id(s->funcs, tr, id);
377 606 : if (bf)
378 394 : return (sql_func*)bf;
379 : }
380 : return NULL;
381 : }
382 :
383 : static sql_trigger *
384 89 : find_sql_trigger(sql_table *t, const char *tname)
385 : {
386 89 : node *n = ol_find_name(t->triggers, tname);
387 89 : if (n)
388 0 : return n->data;
389 : return NULL;
390 : }
391 :
392 : sql_trigger *
393 2 : sql_trans_find_trigger(sql_trans *tr, sqlid id)
394 : {
395 2 : struct os_iter oi;
396 2 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
397 2 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
398 2 : sql_schema *s = (sql_schema*)b;
399 2 : sql_base *bt = os_find_id(s->triggers, tr, id);
400 2 : if (bt)
401 2 : return (sql_trigger*)bt;
402 : }
403 : return NULL;
404 : }
405 :
406 : sql_trigger *
407 918 : schema_find_trigger(sql_trans *tr, sql_schema *s, const char *name)
408 : {
409 918 : sql_base *b = os_find_name(s->triggers, tr, name);
410 :
411 918 : if (!b && tr->tmp == s) {
412 91 : struct os_iter oi;
413 91 : os_iterator(&oi, tr->localtmps, tr, NULL);
414 180 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
415 89 : sql_table *t = (sql_table *) b;
416 89 : sql_trigger *o = find_sql_trigger(t, name);
417 89 : if (o)
418 0 : return o;
419 : }
420 : }
421 : return (sql_trigger*)b;
422 : }
423 :
424 : void*
425 194 : sql_values_list_element_validate_and_insert(void *v1, void *v2, void *tpe, int* res)
426 : {
427 194 : sql_part_value* pt = (sql_part_value*) v1, *newp = (sql_part_value*) v2;
428 194 : sql_subtype *tp = (sql_subtype *) tpe;
429 :
430 194 : *res = ATOMcmp(tp->type->localtype, newp->value, pt->value);
431 194 : return *res == 0 ? pt : NULL;
432 : }
433 :
434 : void*
435 131 : sql_range_part_validate_and_insert(void *v1, void *v2, void *type)
436 : {
437 131 : sql_part* pt = (sql_part*) v1, *newp = (sql_part*) v2;
438 131 : int res1, res2, tpe = *(int*)type;
439 131 : const void *nil = ATOMnilptr(tpe);
440 131 : bool pt_down_all = false, pt_upper_all = false, newp_down_all = false, newp_upper_all = false, pt_min_max_same = false, newp_min_max_same = false;
441 :
442 131 : if (pt == newp) /* same pointer, skip (used in updates) */
443 : return NULL;
444 :
445 128 : if (is_bit_nil(pt->with_nills) || is_bit_nil(newp->with_nills)) /* if one partition holds all including nills, then conflicts */
446 : return pt;
447 124 : if (newp->with_nills && pt->with_nills) /* only one partition at most has null values */
448 : return pt;
449 :
450 118 : pt_down_all = !ATOMcmp(tpe, nil, pt->part.range.minvalue);
451 118 : pt_upper_all = !ATOMcmp(tpe, nil, pt->part.range.maxvalue);
452 118 : newp_down_all = !ATOMcmp(tpe, nil, newp->part.range.minvalue);
453 118 : newp_upper_all = !ATOMcmp(tpe, nil, newp->part.range.maxvalue);
454 :
455 : /* if one partition just holds NULL values, then there's no conflict */
456 118 : if ((newp_down_all && newp_upper_all && newp->with_nills) || (pt_down_all && pt_upper_all && pt->with_nills))
457 : return NULL;
458 : /* holds all range, will always conflict */
459 102 : if ((pt_down_all && pt_upper_all && !pt->with_nills) || (newp_down_all && newp_upper_all && !newp->with_nills))
460 : return pt;
461 :
462 98 : pt_min_max_same = !ATOMcmp(tpe, pt->part.range.maxvalue, pt->part.range.minvalue);
463 98 : newp_min_max_same = !ATOMcmp(tpe, newp->part.range.maxvalue, newp->part.range.minvalue);
464 :
465 98 : if (pt_down_all) { /* from range min value until a value */
466 23 : res1 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
467 23 : if (newp_down_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
468 : return pt;
469 : return NULL;
470 : }
471 75 : if (pt_upper_all) { /* from value until range max value */
472 9 : res1 = ATOMcmp(tpe, newp->part.range.maxvalue, pt->part.range.minvalue);
473 9 : if (newp_upper_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
474 : return pt;
475 : return NULL;
476 : }
477 66 : if (newp_down_all) { /* from range min value until a value */
478 2 : res1 = ATOMcmp(tpe, newp->part.range.maxvalue, pt->part.range.minvalue);
479 2 : if (pt_down_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
480 : return pt;
481 : return NULL;
482 : }
483 64 : if (newp_upper_all) { /* from value until range max value */
484 15 : res1 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
485 15 : if (pt_upper_all || (!pt_min_max_same && res1 > 0) || (pt_min_max_same && res1 >= 0))
486 : return pt;
487 : return NULL;
488 : }
489 :
490 : /* Fallback into normal cases */
491 49 : res1 = ATOMcmp(tpe, newp->part.range.maxvalue, pt->part.range.minvalue);
492 49 : res2 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
493 : /* overlap: y2 > x1 && x2 > y1 */
494 49 : if (((!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0)) && ((!pt_min_max_same && res2 > 0) || (pt_min_max_same && res2 >= 0)))
495 : return pt;
496 : return NULL;
497 : }
498 :
499 : void*
500 44 : sql_values_part_validate_and_insert(void *v1, void *v2, void *type)
501 : {
502 44 : sql_part* pt = (sql_part*) v1, *newp = (sql_part*) v2;
503 44 : list* b1 = pt->part.values, *b2 = newp->part.values;
504 44 : node *n1 = b1->h, *n2 = b2->h;
505 44 : int res, tpe = *(int*)type;
506 :
507 44 : if (pt == newp) /* same pointer, skip (used in updates) */
508 : return NULL;
509 :
510 42 : if (newp->with_nills && pt->with_nills)
511 : return pt; /* check for nulls first */
512 :
513 145 : while (n1 && n2) {
514 108 : sql_part_value *p1 = (sql_part_value *) n1->data, *p2 = (sql_part_value *) n2->data;
515 108 : res = ATOMcmp(tpe, p1->value, p2->value);
516 108 : if (!res) { /* overlap -> same value in both partitions */
517 : return pt;
518 104 : } else if (res < 0) {
519 101 : n1 = n1->next;
520 : } else {
521 3 : n2 = n2->next;
522 : }
523 : }
524 : return NULL;
525 : }
526 :
527 : sql_part *
528 681192 : partition_find_part(sql_trans *tr, sql_table *pt, sql_part *pp)
529 : {
530 681192 : struct os_iter oi;
531 :
532 681192 : if (!pt->s) /* declared table */
533 : return NULL;
534 681183 : os_iterator(&oi, pt->s->parts, tr, NULL);
535 727750 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
536 48404 : sql_part *p = (sql_part*)b;
537 :
538 48404 : if (pp) {
539 78 : if (p == pp)
540 17 : pp = NULL;
541 78 : continue;
542 : }
543 48326 : if (p->member == pt->base.id)
544 2898 : return p;
545 : }
546 : return NULL;
547 : }
548 :
549 : node *
550 857 : members_find_child_id(list *l, sqlid id)
551 : {
552 857 : if (l) {
553 857 : node *n;
554 1222 : for (n = l->h; n; n = n->next) {
555 709 : sql_part *p = n->data;
556 :
557 709 : if (id == p->member)
558 344 : return n;
559 : }
560 : }
561 : return NULL;
562 : }
563 :
564 : int
565 522 : nested_mergetable(sql_trans *tr, sql_table *mt, const char *sname, const char *tname)
566 : {
567 522 : if (strcmp(mt->s->base.name, sname) == 0 && strcmp(mt->base.name, tname) == 0)
568 : return 1;
569 : /* try if this is also a partition */
570 537 : for( sql_part *parent = partition_find_part(tr, mt, NULL); parent; parent = partition_find_part(tr, mt, parent)) {
571 20 : if (nested_mergetable(tr, parent->t, sname, tname))
572 : return 1;
573 : }
574 : return 0;
575 : }
576 :
577 : bool
578 3881496 : is_column_unique(sql_column *c)
579 : {
580 : /* is it a primary key column itself? */
581 3881496 : if (c->t->pkey && list_length(c->t->pkey->k.columns) == 1 &&
582 392419 : ((sql_kc*)c->t->pkey->k.columns->h->data)->c->base.id == c->base.id)
583 : return true;
584 : /* is it a unique key itself */
585 3743631 : return c->unique == 2;
586 : }
587 :
588 : ValPtr
589 6070502 : SA_VALcopy(allocator *sa, ValPtr d, const ValRecord *s)
590 : {
591 6070502 : if (sa == NULL)
592 1800 : return VALcopy(d, s);
593 6068702 : if (!ATOMextern(s->vtype)) {
594 4381660 : *d = *s;
595 1687042 : } else if (s->val.pval == 0) {
596 0 : const void *p = ATOMnilptr(s->vtype);
597 0 : d->vtype = s->vtype;
598 0 : d->len = ATOMlen(d->vtype, p);
599 0 : d->val.pval = sa_alloc(sa, d->len);
600 0 : if (d->val.pval == NULL)
601 : return NULL;
602 0 : memcpy(d->val.pval, p, d->len);
603 1687042 : } else if (s->vtype == TYPE_str) {
604 1686748 : const char *p = s->val.sval;
605 1686748 : d->vtype = TYPE_str;
606 1686748 : d->len = strLen(p);
607 1686748 : d->val.sval = sa_alloc(sa, d->len);
608 1686748 : if (d->val.sval == NULL)
609 : return NULL;
610 1686748 : memcpy(d->val.sval, p, d->len);
611 : } else {
612 294 : const void *p = s->val.pval;
613 294 : d->vtype = s->vtype;
614 294 : d->len = ATOMlen(d->vtype, p);
615 294 : d->val.pval = sa_alloc(sa, d->len);
616 294 : if (d->val.pval == NULL)
617 : return NULL;
618 294 : memcpy(d->val.pval, p, d->len);
619 : }
620 : return d;
621 : }
622 :
623 : atom *
624 229032 : atom_copy(allocator *sa, atom *a)
625 : {
626 229032 : atom *r = sa ?SA_NEW(sa, atom):MNEW(atom);
627 229032 : if (!r)
628 : return NULL;
629 :
630 229032 : *r = (atom) {
631 229032 : .isnull = a->isnull,
632 229032 : .tpe = a->tpe,
633 : .data = (ValRecord) {.vtype = TYPE_void,},
634 : };
635 229032 : if (!a->isnull)
636 228295 : SA_VALcopy(sa, &r->data, &a->data);
637 : return r;
638 : }
639 :
640 :
641 : sql_table*
642 0 : find_sys_table(sql_trans *tr, const char* tbl_name)
643 : {
644 0 : sql_schema *sys = find_sql_schema(tr, "sys");
645 0 : return find_sql_table(tr, sys, tbl_name);
646 : }
|