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 1307751 : base_key( sql_base *b )
21 : {
22 1307751 : return hash_key(b->name);
23 : }
24 :
25 : void
26 525207 : trans_add(sql_trans *tr, sql_base *b, void *data, tc_cleanup_fptr cleanup, tc_commit_fptr commit, tc_log_fptr log)
27 : {
28 525207 : sql_change *change = MNEW(sql_change);
29 :
30 525202 : *change = (sql_change) {
31 : .obj = b,
32 : .data = data,
33 : .cleanup = cleanup,
34 : .commit = commit,
35 : .log = log,
36 : };
37 525202 : MT_lock_set(&tr->lock);
38 525182 : tr->changes = list_add(tr->changes, change);
39 525198 : if (log)
40 237353 : tr->logchanges++;
41 525198 : MT_lock_unset(&tr->lock);
42 525172 : }
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 4644 : tr_version_of_parent(sql_trans *tr, ulng ts)
62 : {
63 9014 : for( tr = tr->parent; tr; tr = tr->parent)
64 6293 : 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 833 : list_find_id(list *l, sqlid id)
106 : {
107 833 : if (l) {
108 831 : node *n;
109 10418 : for (n = l->h; n; n = n->next) {
110 :
111 : /* check if ids match */
112 9596 : if (id == *(sqlid *) n->data) {
113 9 : 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 7059 : schema_find_key(sql_trans *tr, sql_schema *s, const char *name)
160 : {
161 7059 : sql_base *b = os_find_name(s->keys, tr, name);
162 :
163 7059 : 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 10879 : find_sql_idx(sql_table *t, const char *iname)
178 : {
179 10879 : node *n = ol_find_name(t->idxs, iname);
180 10879 : if (n)
181 4130 : 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 19546 : schema_find_idx(sql_trans *tr, sql_schema *s, const char *name)
201 : {
202 19546 : sql_base *b = os_find_name(s->idxs, tr, name);
203 :
204 19545 : if (!b && tr->tmp == s) {
205 304 : struct os_iter oi;
206 304 : os_iterator(&oi, tr->localtmps, tr, NULL);
207 1079 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
208 810 : sql_table *t = (sql_table *) b;
209 810 : sql_idx *o = find_sql_idx(t, name);
210 810 : if (o)
211 35 : return o;
212 : }
213 : }
214 : return (sql_idx*)b;
215 : }
216 :
217 : sql_idx *
218 1172 : schema_find_idx_id(sql_trans *tr, sql_schema *s, sqlid id)
219 : {
220 1172 : sql_base *b = os_find_id(s->idxs, tr, id);
221 :
222 1172 : 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 9143724 : find_sql_column(sql_table *t, const char *cname)
238 : {
239 9143724 : node *n = ol_find_name(t->columns, cname);
240 9143289 : if (n)
241 8881701 : return n->data;
242 : return NULL;
243 : }
244 :
245 : sql_table *
246 6627565 : find_sql_table(sql_trans *tr, sql_schema *s, const char *tname)
247 : {
248 6627565 : sql_table *t = (sql_table*)os_find_name(s->tables, tr, tname);
249 :
250 6627133 : if (!t && tr->tmp == s) {
251 210964 : t = (sql_table*) os_find_name(tr->localtmps, tr, tname);
252 210964 : return t;
253 : }
254 :
255 6352406 : if (t && isTempTable(t) && tr->tmp == s) {
256 65981 : assert(isGlobal(t));
257 :
258 65981 : sql_table* lt = (sql_table*) os_find_name(tr->localtmps, tr, tname);
259 65986 : if (lt)
260 : return lt;
261 :
262 4315 : t = globaltmp_instantiate(tr, t);
263 4315 : return t;
264 : }
265 :
266 : return t;
267 : }
268 :
269 : sql_table *
270 38122 : find_sql_table_id(sql_trans *tr, sql_schema *s, sqlid id)
271 : {
272 38122 : sql_table *t = (sql_table*)os_find_id(s->tables, tr, id);
273 38122 : if (!t && tr->tmp == s) {
274 59 : t = (sql_table*) os_find_id(tr->localtmps, tr, id);
275 59 : return t;
276 : }
277 :
278 38063 : 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 231 : sql_trans_find_table(sql_trans *tr, sqlid id)
293 : {
294 231 : struct os_iter oi;
295 231 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
296 385 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
297 385 : sql_schema *s = (sql_schema*)b;
298 385 : sql_base *bt = os_find_id(s->tables, tr, id);
299 385 : if (bt)
300 231 : return (sql_table*)bt;
301 : }
302 : return NULL;
303 : }
304 :
305 : sql_sequence *
306 3606 : find_sql_sequence(sql_trans *tr, sql_schema *s, const char *sname)
307 : {
308 3606 : return (sql_sequence*)os_find_name(s->seqs, tr, sname);
309 : }
310 :
311 : sql_schema *
312 9758581 : find_sql_schema(sql_trans *tr, const char *sname)
313 : {
314 9758581 : if (tr->tmp && strcmp(sname, "tmp")==0)
315 : return tr->tmp;
316 9070303 : return (sql_schema*)os_find_name(tr->cat->schemas, tr, sname);
317 : }
318 :
319 : sql_schema *
320 1734 : find_sql_schema_id(sql_trans *tr, sqlid id)
321 : {
322 1734 : if (tr->tmp && tr->tmp->base.id == id)
323 : return tr->tmp;
324 1399 : return (sql_schema*)os_find_id(tr->cat->schemas, tr, id);
325 : }
326 :
327 : sql_type *
328 61187 : find_sql_type(sql_trans *tr, sql_schema *s, const char *tname)
329 : {
330 61187 : return (sql_type*)os_find_name(s->types, tr, tname);
331 : }
332 :
333 : sql_type *
334 49390 : sql_trans_bind_type(sql_trans *tr, sql_schema *c, const char *name)
335 : {
336 49390 : struct os_iter oi;
337 49390 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
338 50937 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
339 50716 : sql_schema *s = (sql_schema*)b;
340 50716 : sql_type *t = find_sql_type(tr, s, name);
341 50716 : if (t)
342 49169 : 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 395 : sql_trans_find_func(sql_trans *tr, sqlid id)
371 : {
372 395 : struct os_iter oi;
373 395 : os_iterator(&oi, tr->cat->schemas, tr, NULL);
374 534 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
375 529 : sql_schema *s = (sql_schema*)b;
376 529 : sql_base *bf = os_find_id(s->funcs, tr, id);
377 529 : if (bf)
378 390 : return (sql_func*)bf;
379 : }
380 : return NULL;
381 : }
382 :
383 : static sql_trigger *
384 90 : find_sql_trigger(sql_table *t, const char *tname)
385 : {
386 90 : node *n = ol_find_name(t->triggers, tname);
387 90 : 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 926 : schema_find_trigger(sql_trans *tr, sql_schema *s, const char *name)
408 : {
409 926 : sql_base *b = os_find_name(s->triggers, tr, name);
410 :
411 926 : if (!b && tr->tmp == s) {
412 92 : struct os_iter oi;
413 92 : os_iterator(&oi, tr->localtmps, tr, NULL);
414 182 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
415 90 : sql_table *t = (sql_table *) b;
416 90 : sql_trigger *o = find_sql_trigger(t, name);
417 90 : if (o)
418 0 : return o;
419 : }
420 : }
421 : return (sql_trigger*)b;
422 : }
423 :
424 : void*
425 179 : sql_values_list_element_validate_and_insert(void *v1, void *v2, void *tpe, int* res)
426 : {
427 179 : sql_part_value* pt = (sql_part_value*) v1, *newp = (sql_part_value*) v2;
428 179 : sql_subtype *tp = (sql_subtype *) tpe;
429 :
430 179 : *res = ATOMcmp(tp->type->localtype, newp->value, pt->value);
431 179 : return *res == 0 ? pt : NULL;
432 : }
433 :
434 : void*
435 123 : sql_range_part_validate_and_insert(void *v1, void *v2, void *type)
436 : {
437 123 : sql_part* pt = (sql_part*) v1, *newp = (sql_part*) v2;
438 123 : int res1, res2, tpe = *(int*)type;
439 123 : const void *nil = ATOMnilptr(tpe);
440 123 : 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 123 : if (pt == newp) /* same pointer, skip (used in updates) */
443 : return NULL;
444 :
445 120 : 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 116 : if (newp->with_nills && pt->with_nills) /* only one partition at most has null values */
448 : return pt;
449 :
450 110 : pt_down_all = !ATOMcmp(tpe, nil, pt->part.range.minvalue);
451 110 : pt_upper_all = !ATOMcmp(tpe, nil, pt->part.range.maxvalue);
452 110 : newp_down_all = !ATOMcmp(tpe, nil, newp->part.range.minvalue);
453 110 : 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 110 : 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 96 : if ((pt_down_all && pt_upper_all && !pt->with_nills) || (newp_down_all && newp_upper_all && !newp->with_nills))
460 : return pt;
461 :
462 92 : pt_min_max_same = !ATOMcmp(tpe, pt->part.range.maxvalue, pt->part.range.minvalue);
463 92 : newp_min_max_same = !ATOMcmp(tpe, newp->part.range.maxvalue, newp->part.range.minvalue);
464 :
465 92 : if (pt_down_all) { /* from range min value until a value */
466 19 : res1 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
467 19 : if (newp_down_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
468 : return pt;
469 : return NULL;
470 : }
471 73 : 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 64 : 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 62 : if (newp_upper_all) { /* from value until range max value */
484 13 : res1 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
485 13 : 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 38 : sql_values_part_validate_and_insert(void *v1, void *v2, void *type)
501 : {
502 38 : sql_part* pt = (sql_part*) v1, *newp = (sql_part*) v2;
503 38 : list* b1 = pt->part.values, *b2 = newp->part.values;
504 38 : node *n1 = b1->h, *n2 = b2->h;
505 38 : int res, tpe = *(int*)type;
506 :
507 38 : if (pt == newp) /* same pointer, skip (used in updates) */
508 : return NULL;
509 :
510 36 : if (newp->with_nills && pt->with_nills)
511 : return pt; /* check for nulls first */
512 :
513 121 : while (n1 && n2) {
514 90 : sql_part_value *p1 = (sql_part_value *) n1->data, *p2 = (sql_part_value *) n2->data;
515 90 : res = ATOMcmp(tpe, p1->value, p2->value);
516 90 : if (!res) { /* overlap -> same value in both partitions */
517 : return pt;
518 86 : } else if (res < 0) {
519 83 : n1 = n1->next;
520 : } else {
521 3 : n2 = n2->next;
522 : }
523 : }
524 : return NULL;
525 : }
526 :
527 : sql_part *
528 727786 : partition_find_part(sql_trans *tr, sql_table *pt, sql_part *pp)
529 : {
530 727786 : struct os_iter oi;
531 :
532 727786 : if (!pt->s) /* declared table */
533 : return NULL;
534 727777 : os_iterator(&oi, pt->s->parts, tr, NULL);
535 790001 : for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
536 65211 : sql_part *p = (sql_part*)b;
537 :
538 65211 : if (pp) {
539 61 : if (p == pp)
540 16 : pp = NULL;
541 61 : continue;
542 : }
543 65150 : if (p->member == pt->base.id)
544 2996 : return p;
545 : }
546 : return NULL;
547 : }
548 :
549 : node *
550 907 : members_find_child_id(list *l, sqlid id)
551 : {
552 907 : if (l) {
553 907 : node *n;
554 1280 : for (n = l->h; n; n = n->next) {
555 742 : sql_part *p = n->data;
556 :
557 742 : if (id == p->member)
558 369 : return n;
559 : }
560 : }
561 : return NULL;
562 : }
563 :
564 : int
565 541 : nested_mergetable(sql_trans *tr, sql_table *mt, const char *sname, const char *tname)
566 : {
567 541 : 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 555 : for( sql_part *parent = partition_find_part(tr, mt, NULL); parent; parent = partition_find_part(tr, mt, parent)) {
571 19 : if (nested_mergetable(tr, parent->t, sname, tname))
572 : return 1;
573 : }
574 : return 0;
575 : }
576 :
577 : bool
578 3829750 : is_column_unique(sql_column *c)
579 : {
580 : /* is it a primary key column itself? */
581 3829750 : if (c->t->pkey && list_length(c->t->pkey->k.columns) == 1 && ((sql_kc*)c->t->pkey->k.columns->h->data)->c->base.id == c->base.id)
582 : return true;
583 : /* is it a unique key itself */
584 3691991 : return c->unique == 2;
585 : }
586 :
587 : ValPtr
588 3218496 : SA_VALcopy(sql_allocator *sa, ValPtr d, const ValRecord *s)
589 : {
590 3218496 : if (sa == NULL)
591 1470 : return VALcopy(d, s);
592 3217026 : if (!ATOMextern(s->vtype)) {
593 2232983 : *d = *s;
594 984043 : } else if (s->val.pval == 0) {
595 0 : const void *p = ATOMnilptr(s->vtype);
596 0 : d->vtype = s->vtype;
597 0 : d->len = ATOMlen(d->vtype, p);
598 0 : d->val.pval = sa_alloc(sa, d->len);
599 0 : if (d->val.pval == NULL)
600 : return NULL;
601 0 : memcpy(d->val.pval, p, d->len);
602 984043 : } else if (s->vtype == TYPE_str) {
603 983752 : const char *p = s->val.sval;
604 983752 : d->vtype = TYPE_str;
605 983752 : d->len = strLen(p);
606 983752 : d->val.sval = sa_alloc(sa, d->len);
607 983752 : if (d->val.sval == NULL)
608 : return NULL;
609 983752 : memcpy(d->val.sval, p, d->len);
610 : } else {
611 291 : const void *p = s->val.pval;
612 291 : d->vtype = s->vtype;
613 291 : d->len = ATOMlen(d->vtype, p);
614 291 : d->val.pval = sa_alloc(sa, d->len);
615 291 : if (d->val.pval == NULL)
616 : return NULL;
617 291 : memcpy(d->val.pval, p, d->len);
618 : }
619 : return d;
620 : }
621 :
622 : atom *
623 348421 : atom_copy(sql_allocator *sa, atom *a)
624 : {
625 348421 : atom *r = sa ?SA_NEW(sa, atom):MNEW(atom);
626 348421 : if (!r)
627 : return NULL;
628 :
629 348421 : *r = (atom) {
630 348421 : .isnull = a->isnull,
631 348421 : .tpe = a->tpe,
632 : .data = (ValRecord) {.vtype = TYPE_void,},
633 : };
634 348421 : if (!a->isnull)
635 347365 : SA_VALcopy(sa, &r->data, &a->data);
636 : return r;
637 : }
638 :
639 :
640 : sql_table*
641 0 : find_sys_table(sql_trans *tr, const char* tbl_name)
642 : {
643 0 : sql_schema *sys = find_sql_schema(tr, "sys");
644 0 : return find_sql_table(tr, sys, tbl_name);
645 : }
|