LCOV - code coverage report
Current view: top level - sql/storage - sql_catalog.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 209 249 83.9 %
Date: 2021-10-13 02:24:04 Functions: 31 33 93.9 %

          Line data    Source code
       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 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "sql_catalog.h"
      11             : #include "sql_storage.h"
      12             : 
      13             : const char *TID = "%TID%";
      14             : 
      15             : inline int
      16      841491 : base_key( sql_base *b )
      17             : {
      18      841491 :         return hash_key(b->name);
      19             : }
      20             : 
      21             : static void *
      22      102198 : _list_find_name(list *l, const char *name)
      23             : {
      24             :         node *n;
      25             : 
      26      102198 :         if (l) {
      27        1449 :                 MT_lock_set(&l->ht_lock);
      28        1449 :                 if ((!l->ht || l->ht->size*16 < list_length(l)) && list_length(l) > HASH_MIN_SIZE && l->sa) {
      29           0 :                         l->ht = hash_new(l->sa, list_length(l), (fkeyvalue)&base_key);
      30           0 :                         if (l->ht == NULL) {
      31           0 :                                 MT_lock_unset(&l->ht_lock);
      32           0 :                                 return NULL;
      33             :                         }
      34             : 
      35           0 :                         for (n = l->h; n; n = n->next ) {
      36           0 :                                 sql_base *b = n->data;
      37             :                                 int key = base_key(b);
      38             : 
      39           0 :                                 if (hash_add(l->ht, key, b) == NULL) {
      40           0 :                                         MT_lock_unset(&l->ht_lock);
      41           0 :                                         return NULL;
      42             :                                 }
      43             :                         }
      44             :                 }
      45        1449 :                 if (l->ht) {
      46           0 :                         int key = hash_key(name);
      47           0 :                         sql_hash_e *he = l->ht->buckets[key&(l->ht->size-1)];
      48             : 
      49           0 :                         for (; he; he = he->chain) {
      50           0 :                                 sql_base *b = he->value;
      51             : 
      52           0 :                                 if (b->name && strcmp(b->name, name) == 0) {
      53           0 :                                         MT_lock_unset(&l->ht_lock);
      54           0 :                                         return b;
      55             :                                 }
      56             :                         }
      57           0 :                         MT_lock_unset(&l->ht_lock);
      58           0 :                         return NULL;
      59             :                 }
      60        1449 :                 MT_lock_unset(&l->ht_lock);
      61        1633 :                 for (n = l->h; n; n = n->next) {
      62        1010 :                         sql_base *b = n->data;
      63             : 
      64             :                         /* check if names match */
      65        1010 :                         if (name[0] == b->name[0] && strcmp(name, b->name) == 0) {
      66         826 :                                 return b;
      67             :                         }
      68             :                 }
      69             :         }
      70             :         return NULL;
      71             : }
      72             : 
      73             : void
      74      275208 : trans_add(sql_trans *tr, sql_base *b, void *data, tc_cleanup_fptr cleanup, tc_commit_fptr commit, tc_log_fptr log)
      75             : {
      76      275208 :         sql_change *change = SA_NEW(tr->sa, sql_change);
      77             : 
      78      275208 :         *change = (sql_change) {
      79             :                 .obj = b,
      80             :                 .data = data,
      81             :                 .cleanup = cleanup,
      82             :                 .commit = commit,
      83             :                 .log = log,
      84             :         };
      85      275208 :         MT_lock_set(&tr->lock);
      86      275208 :         tr->changes = sa_list_append(tr->sa, tr->changes, change);
      87      275208 :         if (log)
      88       57480 :                 tr->logchanges++;
      89      275208 :         MT_lock_unset(&tr->lock);
      90      275208 : }
      91             : 
      92             : int
      93        2227 : tr_version_of_parent(sql_trans *tr, ulng ts)
      94             : {
      95        4521 :         for( tr = tr->parent; tr; tr = tr->parent)
      96        2917 :                 if (tr->tid == ts)
      97             :                         return 1;
      98             :         return 0;
      99             : }
     100             : 
     101             : node *
     102         104 : list_find_name(list *l, const char *name)
     103             : {
     104             :         node *n;
     105             : 
     106         104 :         if (l)
     107         319 :                 for (n = l->h; n; n = n->next) {
     108         313 :                         sql_base *b = n->data;
     109             : 
     110             :                         /* check if names match */
     111         313 :                         if (name[0] == b->name[0] && strcmp(name, b->name) == 0) {
     112          98 :                                 return n;
     113             :                         }
     114             :                 }
     115             :         return NULL;
     116             : }
     117             : 
     118             : node *
     119          34 : cs_find_id(changeset * cs, sqlid id)
     120             : {
     121             :         node *n;
     122          34 :         list *l = cs->set;
     123             : 
     124          34 :         if (l)
     125          35 :                 for (n = l->h; n; n = n->next) {
     126          35 :                         sql_base *b = n->data;
     127             : 
     128             :                         /* check if names match */
     129          35 :                         if (b->id == id) {
     130          34 :                                 return n;
     131             :                         }
     132             :                 }
     133             :         return NULL;
     134             : }
     135             : 
     136             : node *
     137         819 : list_find_id(list *l, sqlid id)
     138             : {
     139         819 :         if (l) {
     140             :                 node *n;
     141       10197 :                 for (n = l->h; n; n = n->next) {
     142             : 
     143             :                         /* check if ids match */
     144        9389 :                         if (id == *(sqlid *) n->data) {
     145           9 :                                 return n;
     146             :                         }
     147             :                 }
     148             :         }
     149             :         return NULL;
     150             : }
     151             : 
     152             : node *
     153           0 : list_find_base_id(list *l, sqlid id)
     154             : {
     155           0 :         if (l) {
     156             :                 node *n;
     157           0 :                 for (n = l->h; n; n = n->next) {
     158           0 :                         sql_base *b = n->data;
     159             : 
     160           0 :                         if (id == b->id)
     161           0 :                                 return n;
     162             :                 }
     163             :         }
     164             :         return NULL;
     165             : }
     166             : 
     167             : sql_key *
     168           0 : find_sql_key(sql_table *t, const char *kname)
     169             : {
     170           0 :         node *n = ol_find_name(t->keys, kname);
     171           0 :         if (n)
     172           0 :                 return n->data;
     173             :         return NULL;
     174             : }
     175             : 
     176             : sql_key *
     177         278 : sql_trans_find_key(sql_trans *tr, sqlid id)
     178             : {
     179             :         struct os_iter oi;
     180         278 :         os_iterator(&oi, tr->cat->schemas, tr, NULL);
     181         278 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     182             :                 sql_schema *s = (sql_schema*)b;
     183         278 :                 sql_base *bk = os_find_id(s->keys, tr, id);
     184         278 :                 if (bk)
     185         278 :                                 return (sql_key*)bk;
     186             :         }
     187             :         return NULL;
     188             : }
     189             : 
     190             : sql_idx *
     191        9635 : find_sql_idx(sql_table *t, const char *iname)
     192             : {
     193        9635 :         node *n = ol_find_name(t->idxs, iname);
     194        9635 :         if (n)
     195        4027 :                 return n->data;
     196             :         return NULL;
     197             : }
     198             : 
     199             : sql_idx *
     200           5 : sql_trans_find_idx(sql_trans *tr, sqlid id)
     201             : {
     202             :         struct os_iter oi;
     203           5 :         os_iterator(&oi, tr->cat->schemas, tr, NULL);
     204           5 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     205             :                 sql_schema *s = (sql_schema*)b;
     206           5 :                 sql_base *bi = os_find_id(s->idxs, tr, id);
     207           5 :                 if (bi)
     208           5 :                         return (sql_idx*)bi;
     209             :         }
     210             :         return NULL;
     211             : }
     212             : 
     213             : sql_column *
     214     8728906 : find_sql_column(sql_table *t, const char *cname)
     215             : {
     216     8728906 :         node *n = ol_find_name(t->columns, cname);
     217     8727118 :         if (n)
     218     8563622 :                 return n->data;
     219             :         return NULL;
     220             : }
     221             : 
     222             : sql_table *
     223     7179738 : find_sql_table(sql_trans *tr, sql_schema *s, const char *tname)
     224             : {
     225     7179738 :         sql_table *t = (sql_table*)os_find_name(s->tables, tr, tname);
     226     7179457 :         if (!t && tr->tmp == s)
     227      102198 :                 t = (sql_table*)_list_find_name(tr->localtmps.set, tname);
     228     7179457 :         return t;
     229             : }
     230             : 
     231             : sql_table *
     232         858 : find_sql_table_id(sql_trans *tr, sql_schema *s, sqlid id)
     233             : {
     234         858 :         sql_table *t = (sql_table*)os_find_id(s->tables, tr, id);
     235         858 :         if (!t && tr->tmp == s) {
     236           4 :                 node *n = cs_find_id(&tr->localtmps, id);
     237           4 :                 if (n)
     238           4 :                         return (sql_table*)n->data;
     239             :         }
     240             :         return t;
     241             : }
     242             : 
     243             : sql_table *
     244          30 : sql_trans_find_table(sql_trans *tr, sqlid id)
     245             : {
     246             :         struct os_iter oi;
     247          30 :         os_iterator(&oi, tr->cat->schemas, tr, NULL);
     248         142 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     249             :                 sql_schema *s = (sql_schema*)b;
     250         142 :                 sql_base *bt = os_find_id(s->tables, tr, id);
     251         142 :                 if (bt)
     252          30 :                         return (sql_table*)bt;
     253             :         }
     254             :         return NULL;
     255             : }
     256             : 
     257             : sql_sequence *
     258        3348 : find_sql_sequence(sql_trans *tr, sql_schema *s, const char *sname)
     259             : {
     260        3348 :         return (sql_sequence*)os_find_name(s->seqs, tr, sname);
     261             : }
     262             : 
     263             : sql_schema *
     264     9663341 : find_sql_schema(sql_trans *tr, const char *sname)
     265             : {
     266     9663341 :         if (tr->tmp && strcmp(sname, "tmp")==0)
     267             :                 return tr->tmp;
     268     9005247 :         return (sql_schema*)os_find_name(tr->cat->schemas, tr, sname);
     269             : }
     270             : 
     271             : sql_schema *
     272        1599 : find_sql_schema_id(sql_trans *tr, sqlid id)
     273             : {
     274        1599 :         if (tr->tmp && tr->tmp->base.id == id)
     275             :                 return tr->tmp;
     276        1334 :         return (sql_schema*)os_find_id(tr->cat->schemas, tr, id);
     277             : }
     278             : 
     279             : sql_type *
     280       50699 : find_sql_type(sql_trans *tr, sql_schema *s, const char *tname)
     281             : {
     282       50699 :         return (sql_type*)os_find_name(s->types, tr, tname);
     283             : }
     284             : 
     285             : sql_type *
     286       40424 : sql_trans_bind_type(sql_trans *tr, sql_schema *c, const char *name)
     287             : {
     288             :         struct os_iter oi;
     289       40424 :         os_iterator(&oi, tr->cat->schemas, tr, NULL);
     290       42192 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     291             :                 sql_schema *s = (sql_schema*)b;
     292       41971 :                 sql_type *t = find_sql_type(tr, s, name);
     293       41971 :                 if (t)
     294       40203 :                         return t;
     295             :         }
     296         221 :         if (c)
     297           0 :                 return find_sql_type(tr, c, name);
     298             :         return NULL;
     299             : }
     300             : 
     301             : sql_type *
     302           1 : sql_trans_find_type(sql_trans *tr, sql_schema *s, sqlid id)
     303             : {
     304           1 :         if (s) {
     305           1 :                 sql_base *b = os_find_id(s->types, tr, id);
     306           1 :                 if (b)
     307           1 :                         return (sql_type*)b;
     308             :         } else {
     309             :                 struct os_iter oi;
     310           0 :                 os_iterator(&oi, tr->cat->schemas, tr, NULL);
     311           0 :                 for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     312             :                         sql_schema *s = (sql_schema*)b;
     313           0 :                         sql_base *bt = os_find_id(s->types, tr, id);
     314           0 :                         if (bt)
     315           0 :                                 return (sql_type*)bt;
     316             :                 }
     317             :         }
     318             :         return NULL;
     319             : }
     320             : 
     321             : sql_func *
     322          10 : sql_trans_find_func(sql_trans *tr, sqlid id)
     323             : {
     324             :         struct os_iter oi;
     325          10 :         os_iterator(&oi, tr->cat->schemas, tr, NULL);
     326          10 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     327             :                 sql_schema *s = (sql_schema*)b;
     328          10 :                 sql_base *bf = os_find_id(s->funcs, tr, id);
     329          10 :                 if (bf)
     330          10 :                         return (sql_func*)bf;
     331             :         }
     332             :         return NULL;
     333             : }
     334             : 
     335             : sql_trigger *
     336           2 : sql_trans_find_trigger(sql_trans *tr, sqlid id)
     337             : {
     338             :         struct os_iter oi;
     339           2 :         os_iterator(&oi, tr->cat->schemas, tr, NULL);
     340           2 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     341             :                 sql_schema *s = (sql_schema*)b;
     342           2 :                 sql_base *bt = os_find_id(s->triggers, tr, id);
     343           2 :                 if (bt)
     344           2 :                         return (sql_trigger*)bt;
     345             :         }
     346             :         return NULL;
     347             : }
     348             : 
     349             : void*
     350         188 : sql_values_list_element_validate_and_insert(void *v1, void *v2, void *tpe, int* res)
     351             : {
     352             :         sql_part_value* pt = (sql_part_value*) v1, *newp = (sql_part_value*) v2;
     353             :         sql_subtype *tp = (sql_subtype *) tpe;
     354             : 
     355         188 :         *res = ATOMcmp(tp->type->localtype, newp->value, pt->value);
     356         188 :         return *res == 0 ? pt : NULL;
     357             : }
     358             : 
     359             : void*
     360         133 : sql_range_part_validate_and_insert(void *v1, void *v2, void *type)
     361             : {
     362             :         sql_part* pt = (sql_part*) v1, *newp = (sql_part*) v2;
     363         133 :         int res1, res2, tpe = *(int*)type;
     364         133 :         const void *nil = ATOMnilptr(tpe);
     365             :         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;
     366             : 
     367         133 :         if (pt == newp) /* same pointer, skip (used in updates) */
     368             :                 return NULL;
     369             : 
     370         128 :         if (is_bit_nil(pt->with_nills) || is_bit_nil(newp->with_nills)) /* if one partition holds all including nills, then conflicts */
     371             :                 return pt;
     372         124 :         if (newp->with_nills && pt->with_nills) /* only one partition at most has null values */
     373             :                 return pt;
     374             : 
     375         118 :         pt_down_all = !ATOMcmp(tpe, nil, pt->part.range.minvalue);
     376         118 :         pt_upper_all = !ATOMcmp(tpe, nil, pt->part.range.maxvalue);
     377         118 :         newp_down_all = !ATOMcmp(tpe, nil, newp->part.range.minvalue);
     378         118 :         newp_upper_all = !ATOMcmp(tpe, nil, newp->part.range.maxvalue);
     379             : 
     380             :         /* if one partition just holds NULL values, then there's no conflict */
     381         118 :         if ((newp_down_all && newp_upper_all && newp->with_nills) || (pt_down_all && pt_upper_all && pt->with_nills))
     382             :                 return NULL;
     383             :          /* holds all range, will always conflict */
     384         104 :         if ((pt_down_all && pt_upper_all && !pt->with_nills) || (newp_down_all && newp_upper_all && !newp->with_nills))
     385             :                 return pt;
     386             : 
     387          97 :         pt_min_max_same = !ATOMcmp(tpe, pt->part.range.maxvalue, pt->part.range.minvalue);
     388          97 :         newp_min_max_same = !ATOMcmp(tpe, newp->part.range.maxvalue, newp->part.range.minvalue);
     389             : 
     390          97 :         if (pt_down_all) { /* from range min value until a value */
     391          22 :                 res1 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
     392          22 :                 if (newp_down_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
     393             :                         return pt;
     394          15 :                 return NULL;
     395             :         }
     396          75 :         if (pt_upper_all) { /* from value until range max value */
     397          10 :                 res1 = ATOMcmp(tpe, newp->part.range.maxvalue, pt->part.range.minvalue);
     398          10 :                 if (newp_upper_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
     399             :                         return pt;
     400           4 :                 return NULL;
     401             :         }
     402          65 :         if (newp_down_all) { /* from range min value until a value */
     403           2 :                 res1 = ATOMcmp(tpe, newp->part.range.maxvalue, pt->part.range.minvalue);
     404           2 :                 if (pt_down_all || (!newp_min_max_same && res1 > 0) || (newp_min_max_same && res1 >= 0))
     405             :                         return pt;
     406           2 :                 return NULL;
     407             :         }
     408          63 :         if (newp_upper_all) { /* from value until range max value */
     409          13 :                 res1 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
     410          13 :                 if (pt_upper_all || (!pt_min_max_same && res1 > 0) || (pt_min_max_same && res1 >= 0))
     411             :                         return pt;
     412          11 :                 return NULL;
     413             :         }
     414             : 
     415             :         /* Fallback into normal cases */
     416          50 :         res1 = ATOMcmp(tpe, newp->part.range.maxvalue, pt->part.range.minvalue);
     417          50 :         res2 = ATOMcmp(tpe, pt->part.range.maxvalue, newp->part.range.minvalue);
     418             :         /* overlap: y2 > x1 && x2 > y1 */
     419          50 :         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)))
     420          12 :                 return pt;
     421             :         return NULL;
     422             : }
     423             : 
     424             : void*
     425          41 : sql_values_part_validate_and_insert(void *v1, void *v2, void *type)
     426             : {
     427             :         sql_part* pt = (sql_part*) v1, *newp = (sql_part*) v2;
     428          41 :         list* b1 = pt->part.values, *b2 = newp->part.values;
     429          41 :         node *n1 = b1->h, *n2 = b2->h;
     430          41 :         int res, tpe = *(int*)type;
     431             : 
     432          41 :         if (pt == newp) /* same pointer, skip (used in updates) */
     433             :                 return NULL;
     434             : 
     435          38 :         if (newp->with_nills && pt->with_nills)
     436             :                 return pt; /* check for nulls first */
     437             : 
     438         130 :         while (n1 && n2) {
     439          97 :                 sql_part_value *p1 = (sql_part_value *) n1->data, *p2 = (sql_part_value *) n2->data;
     440          97 :                 res = ATOMcmp(tpe, p1->value, p2->value);
     441          97 :                 if (!res) { /* overlap -> same value in both partitions */
     442             :                         return pt;
     443          93 :                 } else if (res < 0) {
     444          86 :                         n1 = n1->next;
     445             :                 } else {
     446           7 :                         n2 = n2->next;
     447             :                 }
     448             :         }
     449             :         return NULL;
     450             : }
     451             : 
     452             : sql_part *
     453     2015805 : partition_find_part(sql_trans *tr, sql_table *pt, sql_part *pp)
     454             : {
     455             :         struct os_iter oi;
     456             : 
     457     2015805 :         if (!pt->s) /* declared table */
     458             :                 return NULL;
     459     2015796 :         os_iterator(&oi, pt->s->parts, tr, NULL);
     460     2081349 :         for (sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
     461             :                 sql_part *p = (sql_part*)b;
     462             : 
     463       69550 :                 if (pp) {
     464          41 :                         if (p == pp)
     465             :                                 pp = NULL;
     466          41 :                         continue;
     467             :                 }
     468       69509 :                 if (p->member == pt->base.id)
     469        3997 :                         return p;
     470             :         }
     471             :         return NULL;
     472             : }
     473             : 
     474             : node *
     475         753 : members_find_child_id(list *l, sqlid id)
     476             : {
     477         753 :         if (l) {
     478             :                 node *n;
     479        1066 :                 for (n = l->h; n; n = n->next) {
     480         617 :                         sql_part *p = n->data;
     481             : 
     482         617 :                         if (id == p->member)
     483         304 :                                 return n;
     484             :                 }
     485             :         }
     486             :         return NULL;
     487             : }
     488             : 
     489             : int
     490         450 : nested_mergetable(sql_trans *tr, sql_table *mt, const char *sname, const char *tname)
     491             : {
     492         450 :         if (strcmp(mt->s->base.name, sname) == 0 && strcmp(mt->base.name, tname) == 0)
     493             :                 return 1;
     494             :         /* try if this is also a partition */
     495         462 :         for( sql_part *parent = partition_find_part(tr, mt, NULL); parent; parent = partition_find_part(tr, mt, parent)) {
     496          17 :                 if (nested_mergetable(tr, parent->t, sname, tname))
     497             :                         return 1;
     498             :         }
     499             :         return 0;
     500             : }
     501             : 
     502             : bool
     503     3997275 : is_column_unique(sql_column *c)
     504             : {
     505             :         /* is it a primary key column itself? */
     506     3997275 :         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)
     507             :                 return true;
     508             :         /* is it a unique key itself */
     509     3838236 :         return c->unique == 2;
     510             : }
     511             : 
     512             : ValPtr
     513     5359250 : SA_VALcopy(sql_allocator *sa, ValPtr d, const ValRecord *s)
     514             : {
     515     5359250 :         if (sa == NULL)
     516         506 :                 return VALcopy(d, s);
     517     5358744 :         if (!ATOMextern(s->vtype)) {
     518     3365339 :                 *d = *s;
     519     1993405 :         } else if (s->val.pval == 0) {
     520           0 :                 const void *p = ATOMnilptr(s->vtype);
     521           0 :                 d->vtype = s->vtype;
     522           0 :                 d->len = ATOMlen(d->vtype, p);
     523           0 :                 d->val.pval = sa_alloc(sa, d->len);
     524           0 :                 if (d->val.pval == NULL)
     525             :                         return NULL;
     526           0 :                 memcpy(d->val.pval, p, d->len);
     527     1993405 :         } else if (s->vtype == TYPE_str) {
     528             :                 const char *p = s->val.sval;
     529     1992467 :                 d->vtype = TYPE_str;
     530     1992467 :                 d->len = strLen(p);
     531     1992467 :                 d->val.sval = sa_alloc(sa, d->len);
     532     1992467 :                 if (d->val.sval == NULL)
     533             :                         return NULL;
     534     1992467 :                 memcpy(d->val.sval, p, d->len);
     535             :         } else {
     536             :                 const void *p = s->val.pval;
     537         938 :                 d->vtype = s->vtype;
     538         938 :                 d->len = ATOMlen(d->vtype, p);
     539         938 :                 d->val.pval = sa_alloc(sa, d->len);
     540         938 :                 if (d->val.pval == NULL)
     541             :                         return NULL;
     542         938 :                 memcpy(d->val.pval, p, d->len);
     543             :         }
     544             :         return d;
     545             : }
     546             : 
     547             : atom *
     548     5416446 : atom_dup(sql_allocator *sa, atom *a)
     549             : {
     550     5416446 :         atom *r = sa ?SA_NEW(sa, atom):MNEW(atom);
     551     5416446 :         if (!r)
     552             :                 return NULL;
     553             : 
     554     5416446 :         *r = *a;
     555     5416446 :         r->tpe = a->tpe;
     556     5416446 :         if (!a->isnull)
     557     5350464 :                 SA_VALcopy(sa, &r->data, &a->data);
     558             :         return r;
     559             : }

Generated by: LCOV version 1.14