CUBRID Engine  latest
set_object.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 
20 /*
21  * set_object.c - controls the allocation and access of set objects which
22  * can be used as attribute values in database objects.
23  */
24 
25 #ident "$Id$"
26 
27 #include "config.h"
28 
29 #include <stdio.h>
30 #include <assert.h>
31 
32 #include "area_alloc.h"
33 #if !defined (SERVER_MODE)
34 #include "authenticate.h"
35 #endif // not SERVER_MODE
36 #include "db_value_printer.hpp"
37 #include "dbtype.h"
38 #include "error_manager.h"
39 #include "object_primitive.h"
40 #include "object_representation.h"
41 #include "set_object.h"
42 
43 #if !defined(SERVER_MODE)
44 #include "locator_cl.h"
45 #include "object_accessor.h"
46 #include "transaction_cl.h"
47 #include "virtual_object.h"
48 #include "parser.h"
49 #else /* !SERVER_MODE */
50 #endif
51 
52 
53 /* If this is the server stub out ws_pin.
54  * The other client-side functions will be completely commented out but unfortunately,
55  * ws_pin appears in lots of places and its easier to define a stub.
56  */
57 
58 #if !defined(SERVER_MODE)
59 extern unsigned int db_on_server;
60 #endif /* !SERVER_MODE */
61 
62 /*
63  * COL_ARRAY_SIZE
64  * return: size of the value indirection array
65  * size(in) : desired collection size
66  *
67  * Note :
68  *
69  * This converts a collection size into the number of indirection
70  * array elements necessary to hold the value blocks for this collection.
71  * Its a basic ceiling divide operation based on the COL_BLOCK_SIZE
72  * value.
73  *
74  */
75 
76 #define COL_ARRAY_SIZE(size) ((size + (COL_BLOCK_SIZE - 1)) / COL_BLOCK_SIZE)
77 
78 #define SET_AREA_COUNT (1024)
79 
80 typedef struct collect_block
81 {
83  long count;
85 } COL_BLOCK;
86 
87 typedef int (*SETOBJ_SORT_CMP_FUNC) (const void *, const void *);
88 typedef int (*SETOBJ_OP) (COL * set1, COL * set2, COL * result);
89 
90 static long col_init = 0;
91 static int debug_level = 0;
92 
93 static long collection_quick_offset = 0; /* inited by col_initialize */
94 
95 /* Area for allocation of set reference structures */
97 /* Area for allocation of set object structures */
99 
100 #define CHECKNULL_ERR(thing) \
101  if ((thing) == NULL) \
102  { \
103  er_set(ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0); \
104  return(ER_OBJ_INVALID_ARGUMENTS); \
105  }
106 
107 static void col_debug (COL * col);
108 static void col_initialize (void);
109 
110 static DB_VALUE *new_block (long n);
111 static DB_VALUE *realloc_block (DB_VALUE * in_block, long n);
112 
113 static void col_merge_run (COL * col, DB_VALUE ** runs, long run1start, long run1stop, long run2start, long run2stop);
114 static void col_merge_runs (COL * col, DB_VALUE ** runs, long runsize, long top);
115 static int col_successive_merge (COL * col, long top);
116 static long col_move_nulls (COL * col);
117 
118 static int col_expand_array (COL * col, long blockindex);
119 static void col_null_values (COL * col, long bottomvalue, long topvalue);
120 static int col_expand_blocks (COL * col, long blockindex, long blockoffset);
121 
122 static long non_null_index (COL * col, long lower, long upper);
123 static long col_bsearch (COL * col, long lower, long upper, long *found, DB_VALUE * val, int do_coerce);
124 #if defined(ENABLE_UNUSED_FUNCTION)
125 static int col_is_all_null (COL * col);
126 #endif
127 static void free_set_reference (DB_COLLECTION * ref);
128 
129 #if !defined(SERVER_MODE)
130 static void merge_set_references (COL * set, DB_COLLECTION * ref);
131 #endif
132 
133 static int set_op (DB_COLLECTION * collection1, DB_COLLECTION * collection2, DB_COLLECTION ** result,
134  DB_DOMAIN * domain, SETOBJ_OP op);
135 
136 static SET_ITERATOR *make_iterator (void);
137 static void free_iterator (SET_ITERATOR * it);
138 
139 static int assign_set_value (COL * set, DB_VALUE * src, DB_VALUE * dest, bool implicit_coercion);
140 static int check_set_object (DB_VALUE * var, int *removed_ptr);
141 
142 
143 /*
144  * set_area_init() - Initialize the areas used for set storage
145  * return: NO_ERROR or error code
146  *
147  */
148 int
150 {
151  /* we need to add safe guard to prevent any client from calling */
152  /* this initialize function several times during the client's life time */
153 
154  if (Set_Ref_Area == NULL)
155  {
156  Set_Ref_Area = area_create ("Set references", sizeof (DB_COLLECTION), SET_AREA_COUNT);
157  if (Set_Ref_Area == NULL)
158  {
159  goto error;
160  }
161  }
162 
163  if (Set_Obj_Area == NULL)
164  {
165  Set_Obj_Area = area_create ("Set objects", sizeof (COL), SET_AREA_COUNT);
166  if (Set_Obj_Area == NULL)
167  {
168  goto error;
169  }
170  }
171 
172  col_initialize ();
173 
174  return NO_ERROR;
175 
176 error:
177  set_area_final ();
178 
179  assert (er_errid () != NO_ERROR);
180 
181  return er_errid ();
182 }
183 
184 /*
185  * set_area_final() - Finalize the areas used for set storage
186  * return: none
187  */
188 void
190 {
191  if (Set_Ref_Area != NULL)
192  {
193  area_destroy (Set_Ref_Area);
194  Set_Ref_Area = NULL;
195  }
196 
197  if (Set_Obj_Area != NULL)
198  {
199  area_destroy (Set_Obj_Area);
200  Set_Obj_Area = NULL;
201  }
202 }
203 
204 void
206 {
207  Set_Ref_Area = Set_Obj_Area = NULL;
208 }
209 
210 /* VALUE BLOCK RESOURCE */
211 
212 /* SET STRUCTURE ALLOCATION/DEALLOCATION */
213 
214 /*
215  * new_block() - This allocates a db_value block, using a block from a free list
216  * if its available
217  * return: DB_VALUE *
218  * n(in) : The top indexable offset (total size less one)
219  *
220  */
221 
222 
223 static DB_VALUE *
224 new_block (long n)
225 {
226  COL_BLOCK *block;
227 
228  block = (COL_BLOCK *) db_private_alloc (NULL, COLBLOCKSIZE (n));
229  if (block)
230  {
231  block->count = n;
232  block->next = NULL;
233  return &(block->val[0]);
234  }
235  return NULL;
236 }
237 
238 /*
239  * realloc_block() - This re-allocates a db_value block
240  * return: DB_VALUE *
241  * in_block(in) : The block being reallocated
242  * n(in) : The top indexable offset (total size less one)
243  *
244  */
245 
246 static DB_VALUE *
247 realloc_block (DB_VALUE * in_block, long n)
248 {
249  COL_BLOCK *block;
250 
251  if (in_block)
252  {
253  block = BLOCK_START (in_block);
254  block = (COL_BLOCK *) db_private_realloc (NULL, block, COLBLOCKSIZE (n));
255  }
256  else
257  {
258  return new_block (n);
259  }
260  if (block)
261  {
262  block->count = n;
263  block->next = NULL;
264  return &(block->val[0]);
265  }
266  return NULL;
267 }
268 
269 /*
270  * set_free_block() - This frees a db_value block, maintaining a free list
271  * for future use
272  * return: none
273  * in_block(in) : db_value pointer to beginning of block
274  *
275  */
276 
277 void
279 {
280  struct collect_block *freeblock;
281 
282  if (in_block)
283  {
284  /* back up to beginning of block */
285  freeblock = BLOCK_START (in_block);
286  db_private_free_and_init (NULL, freeblock);
287  }
288 }
289 
290 /*
291  * set_final() -
292  * return: none
293  *
294  */
295 
296 void
297 set_final (void)
298 {
299  col_init = 0;
300 }
301 
302 /*
303  * col_value_compare() - total order compare of two collection
304  * values (for qsort)
305  * return:
306  * a(in) : first value
307  * b(in) : second value
308  *
309  */
310 
311 int
313 {
314  /* note that the coerce flag is OFF */
315  return tp_value_compare (a, b, 0, 1);
316 }
317 
318 /*
319  * col_merge_run() - merges two sorted runs into 1 sorted run
320  * return: none
321  * col(in) :
322  * runs(in) :
323  * run1start(in) :
324  * run1stop(in) :
325  * run2start(in) :
326  * run2stop(in) :
327  *
328  * Note :
329  * source set with start/end indexes of two runs to merge,
330  * and a temporary array to hold the result
331  */
332 
333 static void
334 col_merge_run (COL * col, DB_VALUE ** runs, long run1start, long run1stop, long run2start, long run2stop)
335 {
336  DB_VALUE block1[COL_BLOCK_SIZE], block2[COL_BLOCK_SIZE];
337  DB_VALUE *thisblock, *secondblock;
338  long secondblockfull;
339  long tempindex;
340  long freeblocksindex;
341  long runsindex;
342  long smallest;
343 
344  thisblock = block1;
345  secondblockfull = 0;
346  freeblocksindex = 0;
347  runsindex = 0;
348  runs[freeblocksindex] = NULL;
349  tempindex = 0;
350 
351  while (run1start <= run1stop || run2start <= run2stop)
352  {
353 
354  /* pick the smallest value, and copy it to the temporary block */
355  if (run1start > run1stop)
356  {
357  smallest = run2start++;
358  }
359  else if (run2start > run2stop)
360  {
361  smallest = run1start++;
362  }
363  else if (col_value_compare (INDEX (col, run1start), INDEX (col, run2start)) <= 0)
364  {
365  smallest = run1start++;
366  }
367  else
368  {
369  smallest = run2start++;
370  }
371  thisblock[tempindex++] = *INDEX (col, smallest);
372 
373  /* if we have emptied a block, add it to our free runs space */
374  if (BLOCK (smallest + 1) != BLOCK (smallest))
375  {
376  /* we have just finished emptying a block. add it to the available runs blocks */
377  runs[freeblocksindex++] = col->array[BLOCK (smallest)];
378  }
379 
380  /* if we have filled this block, switch to the alternate block */
381  if (tempindex >= COL_BLOCK_SIZE)
382  {
383  if (thisblock == block1)
384  {
385  thisblock = block2;
386  }
387  else
388  {
389  thisblock = block1;
390  }
391 
392  if (secondblockfull)
393  {
394  memcpy (runs[runsindex++], thisblock, COL_BLOCK_SIZE * sizeof (DB_VALUE));
395  }
396  /* from now on, the second block is always full */
397  secondblockfull = 1;
398 
399  /* restart filling this temp block at the beginning */
400  tempindex = 0;
401  }
402  }
403  if (BLOCK (run2start) == BLOCK (run2stop))
404  {
405  /* we need to free the last short block */
406  runs[freeblocksindex++] = col->array[BLOCK (run2stop)];
407  }
408 
409  /* Now all the incoming space must be free */
410  /* copy the temporary stuff to the free space */
411  if (secondblockfull)
412  {
413  /* if the second block is full, copy it */
414  secondblock = (thisblock == block1) ? block2 : block1;
415  memcpy (runs[runsindex++], secondblock, COL_BLOCK_SIZE * sizeof (DB_VALUE));
416  }
417  if (tempindex > 0)
418  {
419  /* copy the remains of this block */
420  memcpy (runs[runsindex++], thisblock, tempindex * sizeof (DB_VALUE));
421  }
422 
423  if (debug_level > 0)
424  {
425  if (runsindex != freeblocksindex)
426  {
427  printf ("set_object.c: col_merge_run internal error\n");
428  }
429  }
430 }
431 
432 /*
433  * col_merge_runs() - merges the n block runs into 2n block runs
434  * return: none
435  * col(in) : source set with n block runs
436  * runs(in) :
437  * runsize(in) :
438  * top(in) :
439  *
440  */
441 
442 
443 static void
444 col_merge_runs (COL * col, DB_VALUE ** runs, long runsize, long top)
445 {
446  long in1start, in1stop, in2start, in2stop, inblock, topblock;
447 
448  in1start = 0;
449  in1stop = (COL_BLOCK_SIZE * runsize) - 1;
450  topblock = 0;
451 
452  while (in1stop < top)
453  {
454  in2start = in1stop + 1;
455  in2stop = in2start + (COL_BLOCK_SIZE * runsize) - 1;
456 
457  /* this handles case 2 and 3 above */
458  if (in2stop > top)
459  {
460  in2stop = top;
461  }
462  col_merge_run (col, &runs[BLOCK (in1start)], in1start, in1stop, in2start, in2stop);
463  /* last block merged */
464  topblock = BLOCK (in2stop);
465  in1start = in2stop + 1;
466  in1stop = in1start + (COL_BLOCK_SIZE * runsize) - 1;
467  }
468 
469  /* Last, reset the block array of the collection from the temporary runs array. */
470 
471  /* This handles case 1 above, by not copying over the unmerged run */
472  inblock = 0;
473  while (inblock <= topblock)
474  {
475  col->array[inblock] = runs[inblock];
476  inblock++;
477  }
478 }
479 
480 /*
481  * col_successive_merge() - sorts set by successive merges
482  * return: int
483  * col(in) : source set with 1 run per block
484  * top(in) :
485  *
486  */
487 
488 static int
489 col_successive_merge (COL * col, long top)
490 {
491  DB_VALUE **runs;
492  long nblocks, runsize;
493 
494  nblocks = BLOCK (top) + 1;
495  runs = (DB_VALUE **) db_private_alloc (NULL, nblocks * sizeof (DB_VALUE *));
496 
497  if (runs == NULL)
498  {
499  assert (er_errid () != NO_ERROR);
500  return er_errid ();
501  }
502  runsize = 1;
503 
504  while (runsize < nblocks)
505  {
506  col_merge_runs (col, runs, runsize, top);
507  runsize = 2 * runsize;
508  }
509 
511 
512  return NO_ERROR;
513 }
514 
515 /*
516  * col_move_nulls() - moves all NULL db_values to the end of the collection.
517  * NULL's associated type, if any is preserved.
518  * return: returns the top most non-NULL index
519  * col(in) : unordered source set
520  * (in) :
521  * (in) :
522  * (in) :
523  *
524  */
525 
526 static long
528 {
529  long top, bottom;
530  DB_VALUE temp;
531 
532  bottom = 0;
533  top = col->size - 1;
534 
535  while (bottom < top)
536  {
537  while (top >= 0 && DB_IS_NULL (INDEX (col, top)))
538  {
539  top--;
540  }
541  while (bottom < top && !DB_IS_NULL (INDEX (col, bottom)))
542  {
543  bottom++;
544  }
545  /* here we must satisfy the loop exit condition, or bottom indexes a NULL, and top does not. If that is the case,
546  * we switch bottom and top values. */
547  if (bottom < top)
548  {
549  temp = *INDEX (col, top);
550  *INDEX (col, top) = *INDEX (col, bottom);
551  *INDEX (col, bottom) = temp;
552  top--;
553  bottom++;
554  }
555  }
556 
557  return top;
558 }
559 
560 /*
561  * col_sort() - This sorts an unsorted collection. This is useful to convert
562  * sequences to sets, or to sort sets unordered due to having
563  * temporary oids in them.
564  * return: sorts set
565  * col(in) : source set
566  *
567  */
568 
569 int
570 col_sort (COL * col)
571 {
572  long i, top, topblock;
573  int error;
574 
575  if (!col || !col->size)
576  {
577  return NO_ERROR;
578  }
579 
580  top = col_move_nulls (col);
581  col->sorted = 1;
582 
583  /* If the collection is all nulls, then its sorted */
584  if (top < 0)
585  {
586  return NO_ERROR;
587  }
588 
589  topblock = BLOCK (top);
590 
591  /* first sort each contigous block */
592  for (i = 0; i < topblock; i++)
593  {
595  }
596  qsort (col->array[topblock], OFFSET (top) + 1, sizeof (DB_VALUE), (SETOBJ_SORT_CMP_FUNC) col_value_compare);
597 
598  /* now each block is a sorted run. We can sort the rest be successively merging runs until we have one run left */
599  error = col_successive_merge (col, top);
600 
601  if (debug_level > 1)
602  {
603  printf ("col_sort: ");
604  col_debug (col);
605  }
606 
607  return error;
608 }
609 
610 /*
611  * col_expand_array() -
612  * return: int
613  * col(in) :
614  * blockindex(in) :
615  *
616  * Note :
617  * expands db_value block indirection array to include the given
618  * maximum array index.
619  *
620  */
621 
622 static int
623 col_expand_array (COL * col, long blockindex)
624 {
625  long i;
626 
627  if (blockindex <= col->arraytop)
628  {
629  return NO_ERROR;
630  }
631 
632  if (col->array)
633  {
634  col->array = (DB_VALUE **) db_private_realloc (NULL, col->array, EXPAND (blockindex) * sizeof (DB_VALUE *));
635  }
636  else
637  {
638  col->array = (DB_VALUE **) db_private_alloc (NULL, EXPAND (blockindex) * sizeof (DB_VALUE *));
639  }
640  if (!col->array)
641  {
642  return ER_GENERIC_ERROR; /* error set by memory system */
643  }
644  for (i = col->topblock + 1; i < EXPAND (blockindex); i++)
645  {
646  col->array[i] = NULL;
647  }
648  col->arraytop = EXPAND (blockindex) - 1;
649  return NO_ERROR;
650 }
651 
652 /*
653  * col_null_values()
654  * return: none
655  * col(in) :
656  * bottomvalue(in) :
657  * topvalue(in) :
658  *
659  */
660 
661 static void
662 col_null_values (COL * col, long bottomvalue, long topvalue)
663 {
664  if (col)
665  {
666  for (; bottomvalue <= topvalue; bottomvalue++)
667  {
668  PRIM_SET_NULL (INDEX (col, bottomvalue));
669  }
670  }
671  return;
672 }
673 
674 /*
675  * col_expand_blocks() - populates the db_value blocks in
676  * the collection structure up to maximum block index
677  * return: int
678  * col(in) :
679  * blockindex(in) :
680  * blockoffset(in) :
681  *
682  */
683 
684 static int
685 col_expand_blocks (COL * col, long blockindex, long blockoffset)
686 {
687  DB_VALUE *block;
688  int err;
689  long topfullblock;
690 
691  err = col_expand_array (col, blockindex);
692  if (err < 0)
693  {
694  return err;
695  }
696 
697  if (blockindex > col->topblock)
698  {
699  /* If the old top block was less than a full block, allocate a full block for it. Note its unfilled db_values
700  * will still be initialized below. */
701  if (col->topblockcount < BLOCKING_LESS1 && col->topblock >= 0)
702  {
703  block = realloc_block (col->array[col->topblock], BLOCKING_LESS1);
704  if (block == NULL)
705  {
706  assert (er_errid () != NO_ERROR);
707  return er_errid ();
708  }
709  col->array[col->topblock] = block;
710  /* The next statment is just maintaining the invariant that topblockcount is the size of the top block.
711  * Immediately below, we will reset both topblock and topblockcount. */
713  }
714 
715  if (blockoffset > collection_quick_offset)
716  {
717  topfullblock = blockindex;
719  }
720  else
721  {
722  /* want to allocate a new short block to conserve space */
723  topfullblock = blockindex - 1;
724  col->topblockcount = blockoffset;
725  block = realloc_block (col->array[blockindex], blockoffset);
726  if (block == NULL)
727  {
728  assert (er_errid () != NO_ERROR);
729  return er_errid ();
730  }
731  col->array[blockindex] = block;
732  }
733  for (; col->topblock < topfullblock; col->topblock++)
734  {
735  block = new_block (BLOCKING_LESS1);
736  if (block == NULL)
737  {
738  assert (er_errid () != NO_ERROR);
739  return er_errid ();
740  }
741  col->array[col->topblock + 1] = block;
742  }
743  col->topblock = blockindex;
744  }
745  else if (blockindex == col->topblock && (blockoffset > col->topblockcount))
746  {
747  /* want to re-allocate a short block to conserve space */
748  topfullblock = blockindex - 1;
749  col->topblockcount = blockoffset;
750  block = realloc_block (col->array[blockindex], blockoffset);
751  if (block == NULL)
752  {
753  assert (er_errid () != NO_ERROR);
754  return er_errid ();
755  }
756  col->array[blockindex] = block;
757  }
758 
759  col_null_values (col, col->size, VALUETOP (col));
760 
761  return NO_ERROR;
762 }
763 
764 /*
765  * col_expand() - expands the collection size to at the given logical
766  * maximum collection index. New values added are set to NULL.
767  * return: int
768  * col(in) :
769  * i(in) :
770  *
771  */
772 
773 int
774 col_expand (COL * col, long i)
775 {
776  int err = NO_ERROR;
777 
778  if (col)
779  {
780  if (i > VALUETOP (col))
781  {
782  err = col_expand_blocks (col, BLOCK (i), OFFSET (i));
783  }
784  if (!(err < 0) && i >= col->size)
785  {
786  col->size = i + 1;
787  }
788  }
789  else
790  {
791  /* err = bad args */
792  }
793  return err;
794 }
795 
796 /*
797  * col_new() - new initialized collection header structure
798  * return: returns a new initialized collection header structure
799  * size(in) : number of items in the collection
800  * settype(in) : set, multiset or sequence
801  *
802  */
803 
804 COL *
805 col_new (long size, int settype)
806 {
807  COL *col;
808  int err;
809 
810  if (Set_Obj_Area == NULL)
811  {
812  err = set_area_init ();
813  if (err != NO_ERROR)
814  {
815  return NULL;
816  }
817  }
818 
819  col = (COL *) area_alloc (Set_Obj_Area);
820  if (col)
821  {
822  /* maintain original structure members */
823  col->domain = NULL;
824  col->references = NULL;
825 
826  /* newer structure members */
827  col->coltype = (DB_TYPE) settype;
828  col->arraytop = -1;
829  col->topblock = -1;
830  col->topblockcount = -1;
831  col->size = 0;
832  col->lastinsert = 0;
833  col->array = NULL;
834  col->sorted = 1; /* start off assuming sort */
835  col->may_have_temporary_oids = 0;
836 
837  /* Pre-allocate arrays when size is available, this is particularly important for sequences. When pre-allocating
838  * sets & multisets, must set the size back down as the elements do not logically exist yet */
839  err = col_expand (col, size - 1);
840  if (err)
841  {
842  setobj_free (col);
843  return NULL;
844  }
845  col->size = 0;
846 
847  /* initialize the domain with one of the built in domain structures */
848  if (col)
849  {
850  switch (settype)
851  {
852  case DB_TYPE_SET:
853  col->domain = &tp_Set_domain;
854  break;
855  case DB_TYPE_MULTISET:
856  col->domain = &tp_Multiset_domain;
857  break;
858  case DB_TYPE_SEQUENCE:
859  col->domain = &tp_Sequence_domain;
860  break;
861  case DB_TYPE_VOBJ:
862  col->domain = &tp_Vobj_domain;
863  break;
864  default:
866  setobj_free (col);
867  col = NULL;
868  break;
869  }
870  }
871  }
872  return col;
873 }
874 
875 /*
876  * non_null_index() - search for the greatest index between a lower and
877  * upper bound which has a non NULL db_value.
878  * return: long
879  * col(in) :
880  * lower(in) :
881  * upper(in) :
882  *
883  */
884 
885 static long
886 non_null_index (COL * col, long lower, long upper)
887 {
888  long lowblock, highblock, midblock, offset;
889 
890  if (!col)
891  {
892  return lower - 1; /* guard against NULL */
893  }
894 
895  /* optimize for this most likely case */
896  if (!DB_IS_NULL (INDEX (col, upper)))
897  {
898  return upper;
899  }
900 
901  /* handle case where all collection values NULL */
902  if (DB_IS_NULL (INDEX (col, lower)))
903  {
904  return lower - 1;
905  }
906 
907  lowblock = BLOCK (lower);
908  highblock = BLOCK (upper);
909  while (lowblock < highblock)
910  {
911  midblock = (lowblock + highblock) / 2;
912  if (DB_IS_NULL (&col->array[midblock][0]))
913  {
914  /* lowest entry in midbloack is NULL. Look to the low side */
915  highblock = midblock - 1;
916  }
917  else if (!DB_IS_NULL (&col->array[midblock][BLOCKING_LESS1]))
918  {
919  /* highest entry in mid is non-NULL, look to the high side */
920  lowblock = midblock + 1;
921  }
922  else
923  {
924  /* the non-NULL to NULL transition is on this block */
925  lowblock = highblock = midblock;
926  }
927  }
928  /* here lowblock should point to a block containing one of the end points of the non-NULL to NULL transitions. If the
929  * first value is NULL, the non-null index is one less than the index of that value. (could be -1). */
930  offset = 0;
931  while (offset < COL_BLOCK_SIZE && !DB_IS_NULL (&col->array[lowblock][offset]))
932  {
933  offset++;
934  }
935  /* offset is first NULL value. return one less */
936 
937  return (lowblock * COL_BLOCK_SIZE) + offset - 1;
938 }
939 
940 /*
941  * col_bsearch() -
942  * return: long
943  * col(in) :
944  * lower(in) :
945  * upper(in) :
946  * found(in) :
947  * val(in) :
948  * do_coerce(in) :
949  *
950  * Note:
951  * search for the index between a lower and upper bound which
952  * is greater than or equal to a db_value, and the index one less is less
953  * than the value.
954  *
955  * If the value is equal, also flag the parameter *found as true.
956  *
957  * Requires ALL of val, INDEX(col,lower), index(col,upper)
958  * BE NON-NULL, and all values bewteen lower and upper
959  * sorted in ascending order.
960  */
961 
962 static long
963 col_bsearch (COL * col, long lower, long upper, long *found, DB_VALUE * val, int do_coerce)
964 {
965  long lowblock, highblock, midblock, offset, midoffset, compare;
966 
967  if (!col || !found || !val)
968  {
969  return lower - 1; /* guard against NULL */
970  }
971  *found = 0;
972 
973  lowblock = BLOCK (lower);
974  highblock = BLOCK (upper);
975  while (lowblock < highblock)
976  {
977  midblock = (lowblock + highblock) / 2;
978  if (tp_value_compare (val, &col->array[midblock][0], do_coerce, 1) < 0)
979  {
980  /* value is left of/lower than the middle block */
981  highblock = midblock - 1;
982  }
983  else if (tp_value_compare (val, &col->array[midblock][BLOCKING_LESS1], do_coerce, 1) > 0)
984  {
985  /* value is right of/higher than middle block */
986  lowblock = midblock + 1;
987  }
988  else
989  {
990  /* value's position falls on midblock, or first on the next block or we have a whole string of equal values
991  * in midblock that are equal to val, so it does not really much matter which we pick */
992  lowblock = highblock = midblock;
993  }
994  }
995  /* here lowblock should point to a block containing the largest value less than the passed in value. Determine the
996  * offset of an equal or the first greater value. of that value. (could be -1). */
997  offset = 0;
998  compare = 1;
999  if (lowblock == BLOCK (upper))
1000  {
1001  midoffset = OFFSET (upper);
1002  }
1003  else
1004  {
1005  midoffset = BLOCKING_LESS1;
1006  }
1007 
1008  while (offset <= midoffset && compare > 0)
1009  {
1010  compare = tp_value_compare (val, &col->array[lowblock][offset], do_coerce, 1);
1011  if (compare > 0)
1012  {
1013  offset++; /* have not found position yet */
1014  }
1015  }
1016  if (compare == 0)
1017  {
1018  *found = 1;
1019  }
1020 
1021  return (lowblock * COL_BLOCK_SIZE) + offset;
1022 }
1023 
1024 /*
1025  * col_has_null() - It returns a boolean indicating whether or not
1026  * the collection has a null in it
1027  * return: long
1028  * col(in) :
1029  *
1030  */
1031 
1032 int
1034 {
1035  long i;
1036 
1037  if (!col || col->size == 0)
1038  {
1039  return 0;
1040  }
1041 
1042  /* in ordered collections, NULL's are at the end */
1043  if (col->sorted && (col->coltype == DB_TYPE_SET || col->coltype == DB_TYPE_MULTISET))
1044  {
1045  return DB_IS_NULL (INDEX (col, col->size - 1));
1046  }
1047 
1048  /* unordered collections, must be exhaustively scanned */
1049  for (i = 0; i < col->size; i++)
1050  {
1051  if (DB_IS_NULL (INDEX (col, i)))
1052  {
1053  return 1;
1054  }
1055  }
1056 
1057  return 0;
1058 }
1059 
1060 #if defined(ENABLE_UNUSED_FUNCTION)
1061 /*
1062  * col_is_all_null() -
1063  * return:
1064  * col(in) :
1065  *
1066  * Note :
1067  * It returns a boolean indicating whether or not the collection contains
1068  * all nulls. This is being written so that multi-column index keys
1069  * can be tested for NULL's but the function is general enough
1070  * to support other collection types as well.
1071  */
1072 
1073 static int
1074 col_is_all_null (COL * col)
1075 {
1076  long i;
1077 
1078  /*
1079  * The collection pointer should be verified before this function is
1080  * called. But, just in case it isn't well say that a NULL collection
1081  * or a collection of size o is all NULL's.
1082  */
1083  if (!col || col->size == 0)
1084  {
1085  return 1;
1086  }
1087 
1088  /*
1089  * In ordered collections, NULL's are at the end. So if the first
1090  * element is NULL, all of them must be.
1091  */
1092  if (col->sorted && (col->coltype == DB_TYPE_SET || col->coltype == DB_TYPE_MULTISET))
1093  {
1094  return DB_IS_NULL (INDEX (col, 0));
1095  }
1096 
1097  /* unordered collections, must be exhaustively scanned */
1098  for (i = 0; i < col->size; i++)
1099  {
1100  if (!DB_IS_NULL (INDEX (col, i)))
1101  {
1102  return 0;
1103  }
1104  }
1105 
1106  return 1;
1107 }
1108 #endif
1109 
1110 /*
1111  * col_find() -
1112  * return: long
1113  * col(in) :
1114  * found(in) :
1115  * val(in) :
1116  * do_coerce(in) :
1117  *
1118  * Note:
1119  * function serves dual purpose.
1120  *
1121  * It returns a boolean indicating whether or not
1122  * the collection has an equal value in it.
1123  *
1124  * Whether or not its found, it returns the index the
1125  * new value would be inserted at.
1126  *
1127  * do_coerce flag should only be on if this is a DB_TYPE_SET, this
1128  * is what determines "coercibly" the same which we're apparently
1129  * treating as if it were a duplicate in a heterogenous set.
1130  *
1131  */
1132 
1133 long
1134 col_find (COL * col, long *found, DB_VALUE * val, int do_coerce)
1135 {
1136  long insertindex, rightindex, temp;
1137  long compare;
1138 
1139  if (col && found)
1140  {
1141  *found = 0;
1142  if (DB_IS_NULL (val) || col->size == 0)
1143  {
1144  /* append to end */
1145  /* ANSI puts NULLs at end of set collections for comparison */
1146  /*
1147  * since NULL is not equal to NULL, the insertion index
1148  * returned for sequences might as well be at the end where
1149  * its checp to insert.
1150  */
1151  insertindex = col->size;
1152  }
1153  else
1154  {
1155  /*
1156  * hack, if the collection contains temporary OIDs, we're forced to
1157  * use a linear search as the numeric OID can change without warning.
1158  * Unfortunate but not very easy to perform effeciently without segmenting
1159  * the collection into sorted and unsorted regions.
1160  * Once the set is assured to contain only permanent OID's, the sort
1161  * can be performed reliably.
1162  *
1163  */
1164 #if !defined(SERVER_MODE)
1165  if (col->sorted && col->coltype != DB_TYPE_SEQUENCE && DB_VALUE_TYPE (val) == DB_TYPE_OBJECT)
1166  {
1167 
1168  DB_OBJECT *obj = db_get_object (val);
1169  if (obj != NULL && OBJECT_HAS_TEMP_OID (obj))
1170  {
1171  /* we're inserting a temp OID, must force the collection to become unsorted */
1172  col->sorted = 0;
1173  }
1174  }
1175 #endif
1176 
1177  /*
1178  * Unsorted sets were introduced to deal with temporary/permanent
1179  * oids on the client, but are now also used as an optimization for
1180  * multisets, which are now sorted only on demand. Sorting them
1181  * on demand yields logarithmic instead of quadratic behavior.
1182  *
1183  */
1184 
1185  if (col->coltype != DB_TYPE_SEQUENCE && col->sorted)
1186  {
1187  /* Start point for ordered search */
1188  insertindex = non_null_index (col, 0, col->lastinsert);
1189  if (insertindex < 0)
1190  {
1191  /*
1192  * all set values were NULL. Will not find val.
1193  * insert at beginning.
1194  */
1195  insertindex = 0;
1196  }
1197  else
1198  {
1199  /* determine which side of last insertion index to search from. */
1200  compare = tp_value_compare (val, INDEX (col, insertindex), do_coerce, 1);
1201  if (compare == DB_UNK)
1202  {
1203  insertindex = ER_GENERIC_ERROR;
1204  }
1205  else if (compare > 0)
1206  {
1207  rightindex = non_null_index (col, insertindex, col->size - 1);
1208  if (rightindex == insertindex)
1209  {
1210  /* the insertion point is after all non-null values the value is NOT found. just return the
1211  * next index */
1212  insertindex++;
1213  }
1214  else
1215  {
1216  insertindex = col_bsearch (col, insertindex, rightindex, found, val, do_coerce);
1217  }
1218  }
1219  else if (compare < 0)
1220  {
1221  /* value falls before current insert index. Look for it on the left (between 0 and index). */
1222  insertindex = col_bsearch (col, 0, insertindex, found, val, do_coerce);
1223  }
1224  else
1225  {
1226  /* compare must == 0, we are done lookin, and we found the value */
1227  *found = 1;
1228  if (col->coltype == DB_TYPE_MULTISET)
1229  {
1230  /* may find a long sequence of equal values. for efficient insertsion/deletion, choose the
1231  * last in such a sequence. This is done by a binary search for the left most larger
1232  * (unequal) value. */
1233  rightindex = non_null_index (col, insertindex, col->size - 1);
1234  while (insertindex < rightindex - 1)
1235  {
1236  temp = (insertindex + rightindex) / 2;
1237  compare = tp_value_compare (val, INDEX (col, temp), do_coerce, 1);
1238  if (compare == 0)
1239  {
1240  insertindex = temp;
1241  }
1242  else
1243  {
1244  rightindex = temp;
1245  }
1246  }
1247  }
1248  }
1249  }
1250  }
1251  else
1252  {
1253  insertindex = 0;
1254  /* sequence of unordered values. Must do sequential search */
1255  while (insertindex < col->size)
1256  {
1257  if (tp_value_compare (val, INDEX (col, insertindex), do_coerce, 1) == 0)
1258  {
1259  *found = 1;
1260  break;
1261  }
1262  insertindex++;
1263  }
1264  }
1265  }
1266  }
1267  else
1268  {
1269  /* bad args */
1270  insertindex = ER_GENERIC_ERROR;
1271  }
1272 
1273  return insertindex;
1274 }
1275 
1276 /*
1277  * col_put() - set the ith value of col to val overwriting the old ith value
1278  * return: int
1279  * col(in) :
1280  * colindex(in) :
1281  * val(in) :
1282  *
1283  */
1284 
1285 int
1286 col_put (COL * col, long colindex, DB_VALUE * val)
1287 {
1288  long offset, blockindex;
1289  int error;
1290 
1291  if (!col || colindex < 0 || !val)
1292  {
1293  /* invalid args */
1294  error = ER_GENERIC_ERROR;
1295  return error;
1296  }
1297 
1298  error = col_expand (col, colindex);
1299 
1300  if (!(error < 0))
1301  {
1302  if (!DB_IS_NULL (val))
1303  {
1304  col->lastinsert = colindex;
1305  }
1306  blockindex = BLOCK (colindex);
1307  offset = OFFSET (colindex);
1308 
1309  /* check for temporary OIDs, isn't this where we should be clearing the sorted flag too ? */
1310  if (col->coltype != DB_TYPE_SEQUENCE && DB_VALUE_TYPE (val) == DB_TYPE_OBJECT)
1311  {
1312 #if defined (SERVER_MODE)
1313  assert_release (false);
1314  return ER_FAILED;
1315 #else /* !defined (SERVER_MODE) */
1316  DB_OBJECT *obj = db_get_object (val);
1317  if (obj != NULL && OBJECT_HAS_TEMP_OID (obj))
1318  {
1319  col->may_have_temporary_oids = 1;
1320  }
1321 #endif /* !defined (SERVER_MODE) */
1322  }
1323 
1324  /* If this should be cloned, the caller should do it. This primitive just allows the assignment to the right
1325  * location in the collection */
1326  col->array[blockindex][offset] = *val;
1327  }
1328 
1329  return error;
1330 }
1331 
1332 /*
1333  * col_initialize() -
1334  * return: none
1335  *
1336  */
1337 
1338 static void
1340 {
1341  if (col_init)
1342  {
1343  return;
1344  }
1345 
1346 #if defined(CUBRID_DEBUG)
1347  debug_level = 1;
1348 #endif
1349 
1350  /* Calculate the largest collect_block offset that will fit in the workspace "quick" size. */
1351 #define WS_MAX_QUICK_SIZE 1024
1352 
1353  collection_quick_offset = 1 + (WS_MAX_QUICK_SIZE - (sizeof (struct collect_block))) / sizeof (DB_VALUE);
1354 
1355  /* make sure that collection quick offset is smaller than COL_BLOCK_SIZE. Otherwise, it will disable the more
1356  * efficient block handling. */
1358  {
1360  }
1361 
1362  col_init = 1;
1363 }
1364 
1365 /*
1366  * col_insert() - create a new ith value, setting it to val,
1367  * moving the old ith thru nth values to i+1 to n+1
1368  * return: int
1369  * col(in) :
1370  * colindex(in) :
1371  * val(in) :
1372  *
1373  * Note :
1374  *
1375  * CALLER must call db_value_clone if desired.
1376  * This routine copies the db_valeu passed in,
1377  * changing "ownership" of any referenced memory to
1378  * the collection.
1379  *
1380  */
1381 
1382 int
1383 col_insert (COL * col, long colindex, DB_VALUE * val)
1384 {
1385  long offset, blockindex, topblock, topblockcount, topoffset, fillblock;
1386  int error;
1387 
1388  if (!col_init)
1389  {
1390  col_initialize ();
1391  }
1392 
1393  if (!col || colindex < 0 || !val)
1394  {
1395  error = ER_GENERIC_ERROR;
1396  return error;
1397  }
1398 
1399  if (colindex > col->size)
1400  {
1401  /* expand to include the new index */
1402  error = col_expand (col, colindex);
1403  }
1404  else
1405  {
1406  /* otherwise expand 1 element */
1407  error = col_expand (col, col->size);
1408  }
1409 
1410  if (!(error < 0))
1411  {
1412  blockindex = BLOCK (colindex);
1413  offset = OFFSET (colindex);
1414  topblock = col->topblock;
1415  topblockcount = col->topblockcount;
1416 
1417  /* Before shifting, decrement topblock down to our fill pointer, there is no need to move pre-allocated NULL
1418  * values around */
1419  fillblock = BLOCK (col->size - 1);
1420  if (fillblock < topblock)
1421  {
1422  topblock = fillblock;
1423  topblockcount = BLOCKING_LESS1;
1424  }
1425 
1426  if (topblock > blockindex)
1427  {
1428  /* for all the blocks greater than the insertion block, we must move all the db_values UP one space. */
1429  while (topblock > blockindex)
1430  {
1431  memmove (&col->array[topblock][1], &col->array[topblock][0], topblockcount * sizeof (DB_VALUE));
1432  col->array[topblock][0] = col->array[topblock - 1][BLOCKING_LESS1];
1433  topblock--;
1434  topblockcount = BLOCKING_LESS1;
1435  }
1436  topoffset = BLOCKING_LESS1;
1437  }
1438  else
1439  {
1440  topoffset = OFFSET (col->size - 1);
1441  }
1442  /* shift the values from this block up one. */
1443  while (topoffset > offset)
1444  {
1445  col->array[blockindex][topoffset] = col->array[blockindex][topoffset - 1];
1446  topoffset--;
1447  }
1448 
1449  /* check for temporary OIDs, isn't this where we should be clearing the sorted flag too ? */
1450  if (col->coltype != DB_TYPE_SEQUENCE && DB_VALUE_TYPE (val) == DB_TYPE_OBJECT)
1451  {
1452 #if defined (SERVER_MODE)
1453  assert_release (false);
1454  return ER_FAILED;
1455 #else /* !defined (SERVER_MODE) */
1456  DB_OBJECT *obj = db_get_object (val);
1457  if (obj != NULL && OBJECT_HAS_TEMP_OID (obj))
1458  {
1459  col->may_have_temporary_oids = 1;
1460  }
1461 #endif /* !defined (SERVER_MODE)s */
1462  }
1463 
1464  /* If this should be cloned, the caller should do it. This primitive just allows the assignment to the right
1465  * location in the collection */
1466  col->array[blockindex][offset] = *val;
1467  PRIM_SET_NULL (val);
1468  col->lastinsert = colindex;
1469  }
1470 
1471  return error;
1472 }
1473 
1474 /*
1475  * col_delete() - delete the ith value of the collection
1476  * moving the old ith+1 thru nth values to i to n-1
1477  * return: int
1478  * col(in) :
1479  * colindex(in) :
1480  *
1481  */
1482 
1483 int
1484 col_delete (COL * col, long colindex)
1485 {
1486  long offset, blockindex, topblock, topblockcount, topoffset, fillblock;
1487  int error = NO_ERROR;
1488 
1489  if (!col_init)
1490  {
1491  col_initialize ();
1492  }
1493 
1494  if (!col || colindex < 0)
1495  {
1496  error = ER_GENERIC_ERROR;
1497  return error;
1498  }
1499 
1500  blockindex = BLOCK (colindex);
1501  offset = OFFSET (colindex);
1502  (void) pr_clear_value (&col->array[blockindex][offset]);
1503 
1504  topblock = col->topblock;
1505  fillblock = BLOCK (col->size - 1);
1506 
1507  if (blockindex < topblock)
1508  {
1509  topoffset = BLOCKING_LESS1;
1510  }
1511  else
1512  {
1513  topoffset = OFFSET (col->size - 1);
1514  }
1515  while (offset < topoffset)
1516  {
1517  col->array[blockindex][offset] = col->array[blockindex][offset + 1];
1518  offset++;
1519  }
1520 
1521  if (fillblock > blockindex)
1522  {
1523  /* for all the blocks greater than the insertion block, we must move all the db_values DOWN one space. */
1524  while (blockindex < fillblock)
1525  {
1526  col->array[blockindex][BLOCKING_LESS1] = col->array[blockindex + 1][0];
1527  blockindex++;
1528  if (blockindex < topblock)
1529  {
1530  topblockcount = BLOCKING_LESS1;
1531  }
1532  else
1533  {
1534  topblockcount = col->topblockcount;
1535  }
1536  memmove (&col->array[blockindex][0], &col->array[blockindex][1], topblockcount * sizeof (DB_VALUE));
1537  }
1538  }
1539 
1540  /* Now that we're finished shifting the DB_VALUES down by one, we need to NULL the un-used DB_VALUE at the end so
1541  * that we know that it's available for use later (i.e. we don't want to run pr_clear_value() on it later because it
1542  * may contain pointers to data which was copied to other DB_VALUEs during the shift operations).
1543  *
1544  * Also, just in case the DB_VALUE pointed to an object, set the object pointer to NULL so that the GC doesn't get
1545  * confused. - JB */
1546  PRIM_SET_NULL (INDEX (col, (col->size - 1)));
1547  INDEX (col, (col->size - 1))->data.op = NULL;
1548 
1549  col->size--;
1550  if (col->lastinsert >= col->size)
1551  {
1552  col->lastinsert = col->size - 1;
1553  }
1554 
1555  if (BLOCK (col->size) < topblock)
1556  {
1557  set_free_block (col->array[topblock]);
1558  col->array[topblock] = NULL;
1559  col->topblock--;
1560  if (col->topblock >= 0)
1561  {
1563  }
1564  else
1565  {
1566  col->topblockcount = -1;
1567  }
1568  }
1569 
1570  return error;
1571 }
1572 
1573 /*
1574  * col_add() - add val to col
1575  * if its a set - use set union.
1576  * if its a multiset - use multiset union.
1577  * if its a sequence - append.
1578  * return: int
1579  * col(in) :
1580  * val(in) :
1581  *
1582  * Note :
1583  * CALLER is responsible for cloning, if necessary.
1584  * That makes this function eligible to cheaply move stack
1585  * variables into a collection.
1586  *
1587  * when attempting to insert a duplicate value in a SET
1588  * returns SET_DUPLICATE_VALUE which is > 0
1589  *
1590  */
1591 
1592 int
1594 {
1595  int error = NO_ERROR;
1596  long i, found;
1597 
1598  if (!col)
1599  {
1600  error = ER_GENERIC_ERROR;
1601  return error;
1602  }
1603  switch (col->coltype)
1604  {
1605  case DB_TYPE_SET:
1606  i = col_find (col, &found, val, 1);
1607  /* a SET- insert it if we did not find it */
1608  if (i < 0)
1609  {
1610  error = i;
1611  return error;
1612  }
1613  if (found)
1614  {
1615  error = SET_DUPLICATE_VALUE;
1616  return error;
1617  }
1618 
1619  if (i < col->size - COL_BLOCK_SIZE)
1620  {
1621  /* heuristic to avoid quadratic set creation. if we are moving more than a block, its likely we are entering
1622  * quadratic behavior. Simply insert at the end, and mark the set unsorted. It will be sorted later on demand
1623  * if need be, and this sort will be logarithmic instead of quadratic. */
1624  i = col->size;
1625  col->sorted = 0;
1626  }
1627  error = col_insert (col, i, val);
1628 
1629  break;
1630  case DB_TYPE_MULTISET:
1631  /* if the collection is not sorted, put the new one at the cheapest position, the end. */
1632  found = 0;
1633  /* note that do_coerce is NOT on for multisets, important to preserve order in random heterogenous multisets. */
1634 
1635  if (col->sorted)
1636  {
1637  i = col_find (col, &found, val, 0);
1638  }
1639  else
1640  {
1641  i = col->size;
1642  }
1643 
1644  if (i < 0)
1645  {
1646  error = i;
1647  return error;
1648  }
1649  /* a MULTISET- insert it whether found or not */
1650  if (found)
1651  {
1652  i++; /* insert at next index after last found */
1653  }
1654 
1655  if (i < col->size - COL_BLOCK_SIZE)
1656  {
1657  /* heuristic to avoid quadratic multiset creation. if we are moving more than a block, its likely we are
1658  * entering quadratic behavior. Simply insert at the end, and mark the multiset unsorted. It will be sorted
1659  * later on demand if need be, and this sort will be logarithmic instead of quadratic. */
1660  i = col->size;
1661  col->sorted = 0;
1662  }
1663  error = col_insert (col, i, val);
1664  break;
1665  case DB_TYPE_SEQUENCE:
1666  case DB_TYPE_VOBJ:
1667  error = col_put (col, col->size, val);
1668  break;
1669  default:
1670  /* bad args */
1671  error = ER_GENERIC_ERROR;
1672  break;
1673  }
1674  return error;
1675 }
1676 
1677 /*
1678  * col_drop() - drop val to col
1679  * return: int
1680  * col(in) :
1681  * val(in) :
1682  *
1683  * Note :
1684  * if its a set - use set difference.
1685  * if its a multiset - use multiset difference.
1686  * if its a sequence - find one and set it to NULL
1687  */
1688 
1689 int
1691 {
1692  int error = NO_ERROR;
1693  long i, found, do_coerce;
1694 
1695  if (!col || !val)
1696  {
1697  error = ER_GENERIC_ERROR; /* bad args */
1698  return error;
1699  }
1700 
1701  do_coerce = (col->coltype == DB_TYPE_SET);
1702  i = col_find (col, &found, val, do_coerce);
1703  if (i < 0)
1704  {
1705  error = i;
1706  return error;
1707  }
1708  if (found)
1709  {
1710  if (col->coltype == DB_TYPE_SEQUENCE)
1711  {
1712  PRIM_SET_NULL (INDEX (col, i));
1713  }
1714  else
1715  {
1716  error = col_delete (col, i);
1717  }
1718  }
1719  return error;
1720 }
1721 
1722 /*
1723  * col_drop_nulls() - drop all nulls calues in col
1724  * return: int
1725  * col(in) :
1726  *
1727  */
1728 
1729 int
1731 {
1732  int error = NO_ERROR;
1733  long i;
1734 
1735  if (!col)
1736  {
1737  error = ER_GENERIC_ERROR; /* bad args */
1738  return error;
1739  }
1740 
1741  /* In ordered collections, NULLs are at the end. So delete until we find one that isn't NULL. */
1742  if (col->sorted && (col->coltype == DB_TYPE_SET || col->coltype == DB_TYPE_MULTISET))
1743  {
1744  for (i = col->size - 1; i >= 0; i--)
1745  {
1746  if (DB_IS_NULL (INDEX (col, i)))
1747  {
1748  error = col_delete (col, i);
1749  }
1750  else
1751  {
1752  break;
1753  }
1754  }
1755  }
1756 
1757  /* Unsorted collections must be scanned entirely. */
1758  else
1759  {
1760  for (i = col->size - 1; i >= 0; i--)
1761  {
1762  if (DB_IS_NULL (INDEX (col, i)))
1763  {
1764  error = col_delete (col, i);
1765  }
1766  }
1767  }
1768  return error;
1769 }
1770 
1771 /*
1772  * col_permanent_oids() - assign all oid's in a collection permamenent values
1773  * return: int
1774  * col(in) :
1775  *
1776  */
1777 
1778 int
1780 {
1781  int error = NO_ERROR;
1782 #if !defined(SERVER_MODE)
1783  int tcount, i;
1784  LC_OIDSET *oidset;
1785  LC_OIDMAP *oidmap;
1786  DB_VALUE *val;
1787  DB_OBJECT *obj;
1788 
1789  if (col->may_have_temporary_oids)
1790  {
1791  oidset = locator_make_oid_set ();
1792  if (oidset == NULL)
1793  {
1794  assert (er_errid () != NO_ERROR);
1795  error = er_errid ();
1796  }
1797  else
1798  {
1799  /* Whip through the elements building a lockset for any temporary objects. If none are found, there's nothing
1800  * to do. */
1801  tcount = 0;
1802 
1803  for (i = 0; i < col->size && !error; i++)
1804  {
1805  val = INDEX (col, i);
1806  if (DB_IS_NULL (val))
1807  {
1808  continue;
1809  }
1810 
1811  if (DB_VALUE_DOMAIN_TYPE (val) == DB_TYPE_OBJECT)
1812  {
1813  obj = db_get_object (val);
1814  if (obj != NULL && OBJECT_HAS_TEMP_OID (obj))
1815  {
1816  tcount++;
1817  oidmap = locator_add_oidset_object (oidset, obj);
1818  if (oidmap == NULL)
1819  {
1820  assert (er_errid () != NO_ERROR);
1821  error = er_errid ();
1822  }
1823  }
1824  }
1826  {
1827  /* recurse and make sure any nested set is also assigned permanent oids and sorted */
1828  set_optimize (db_get_set (val));
1829  }
1830  }
1831 
1832  /* tcount has the number of unqiue OIDs in the oidset */
1833  if (!error && tcount)
1834  {
1835  error = locator_assign_oidset (oidset, NULL);
1836  }
1837 
1838  locator_free_oid_set (NULL, oidset);
1839  }
1840 
1841  /* we can now turn this off */
1842  if (!error)
1843  {
1844  col->may_have_temporary_oids = 0;
1845  }
1846  }
1847 #endif
1848 
1849  return error;
1850 }
1851 
1852 /* INTERNAL SET UTILITIES */
1853 
1854 /*
1855  * setvobj_compare() - Compare the values of two VOBJs
1856  * return: DB_EQ or DB_NE
1857  * set1(in) :
1858  * set2(in) :
1859  * do_coercion(in) :
1860  * total_order(in) :
1861  *
1862  * Note :
1863  * We don't compare the vclass, but the proxyclass and
1864  * the keys are compared.
1865  *
1866  * There must be a total order on VOBJS since they can be used in merge
1867  * joins as the join column and he can't deal with DB_UNK. To accomplish
1868  * this total order, we do a lexigraphical sort on proxyclass and keys.
1869  *
1870  * We will return DB_UNK if the VOBJ is malformed.
1871  */
1872 
1874 setvobj_compare (COL * set1, COL * set2, int do_coercion, int total_order)
1875 {
1877 
1878  if ((set1->size == 3) && (set2->size == 3) && (set1->coltype == DB_TYPE_SEQUENCE || set1->coltype == DB_TYPE_VOBJ)
1879  && (set2->coltype == DB_TYPE_SEQUENCE || set2->coltype == DB_TYPE_VOBJ))
1880  {
1881  cmp = DB_EQ;
1882  if (DB_VALUE_DOMAIN_TYPE (&set1->array[0][2]) != DB_TYPE_OID)
1883  {
1884  cmp = tp_value_compare (&set1->array[0][1], &set2->array[0][1], do_coercion, 1);
1885  }
1886  if (cmp == DB_EQ)
1887  {
1888  cmp = tp_value_compare (&set1->array[0][2], &set2->array[0][2], do_coercion, total_order);
1889  }
1890  else
1891  {
1892  if (cmp == DB_UNK)
1893  {
1894  /* one of set1->array[0][1] or set2->array[0][2] must be NULL. */
1895  cmp = DB_IS_NULL (&set1->array[0][1]) ? DB_LT : DB_GT;
1896  }
1897  }
1898  }
1899  else if (debug_level > 0)
1900  {
1902  printf ("Malformed VOBJ(s) sent to setvobj_compare in set_object.c\n");
1903  }
1904 
1905  return cmp;
1906 }
1907 
1908 /* DEBUGGING FUNCTIONS */
1909 
1910 /*
1911  * col_debug() - Print a description of the set
1912  * return: none
1913  * col(in) :
1914  *
1915  */
1916 
1917 static void
1919 {
1920  setobj_print (stdout, col);
1921 }
1922 
1923 /* SET REFERENCE MAINTENANCE */
1924 
1925 /*
1926  * set_make_reference() - set reference structure
1927  * return:
1928  *
1929  * Note :
1930  * Builds a set reference structure for the application layer.
1931  * These must not be allocated in the workspace because the reference
1932  * owner field must serve as a root for the garbage collector.
1933  */
1934 
1935 DB_COLLECTION *
1937 {
1938  DB_COLLECTION *ref;
1939 
1940  if (Set_Ref_Area == NULL)
1941  {
1942  if (set_area_init () != NO_ERROR)
1943  {
1944  return NULL;
1945  }
1946  }
1947 
1948  ref = (DB_COLLECTION *) area_alloc (Set_Ref_Area);
1949  if (ref != NULL)
1950  {
1951  ref->owner = NULL;
1952  ref->attribute = -1;
1953  ref->ref_link = ref; /* circular list of one */
1954  ref->set = NULL;
1955  ref->ref_count = 1; /* when this goes to zero, we can free */
1956  ref->disk_set = NULL;
1957  ref->disk_size = 0;
1958  ref->need_clear = false;
1959  ref->disk_domain = NULL;
1960  }
1961 
1962  return (ref);
1963 }
1964 
1965 /*
1966  * free_set_reference() - Frees storage for a reference structure
1967  * return: none
1968  * ref(in) : set reference structure
1969  *
1970  * Note :
1971  * Make sure the MOP fields are NULL before freeing so they
1972  * don't serve as GC roots.
1973  * Removes the reference from the chain it there is more than one.
1974  * If this is the only reference in the chain, it will free the
1975  * associated set object as well.
1976  * If there are other references in the chain, and the referenced set
1977  * points to this reference, adjust the set so that it points to one
1978  * of the other references in the chain.
1979  */
1980 
1981 static void
1983 {
1984  DB_COLLECTION *r;
1985 
1986  /* if refcount has become so large that the int goes negative, don't bother to free it, there is probably something
1987  * wrong in the application anyway */
1988  if (ref == NULL)
1989  {
1990  return;
1991  }
1992 
1993  if (ref->ref_count <= 0)
1994  {
1995  return;
1996  }
1997 
1998  ref->ref_count--;
1999 
2000  if (ref->ref_count != 0)
2001  {
2002  return;
2003  }
2004  /* search for the previous reference in the chain */
2005  for (r = ref; r != NULL && r->ref_link != ref; r = r->ref_link);
2006 
2007  if (r == ref)
2008  {
2009  /* we're the only one in the list, and this is an unconnected set, free the set object too */
2010  if (ref->set)
2011  {
2012  /* always NULL the reference cache in the set */
2013  ref->set->references = NULL;
2014  /* if the set is unconnected, free it */
2015  if (ref->owner == NULL)
2016  {
2017  setobj_free (ref->set);
2018  ref->set = NULL;
2019  }
2020  }
2021  }
2022  else
2023  {
2024  /* make sure the set object points to a real reference */
2025  if (ref->set != NULL && ref->set->references == ref)
2026  {
2027  ref->set->references = r;
2028  }
2029 
2030  /* take it out of the chain */
2031  if (r != NULL)
2032  {
2033  r->ref_link = ref->ref_link;
2034  }
2035  }
2036 
2037  /* free any disk set */
2038  if (ref->disk_set && ref->need_clear)
2039  {
2041  }
2042  ref->disk_set = NULL;
2043  ref->need_clear = false;
2044  ref->disk_size = 0;
2045  ref->disk_domain = NULL;
2046 
2047  /* NULL this field so it doesn't serve as a GC root */
2048  ref->owner = NULL;
2049  (void) area_free (Set_Ref_Area, ref);
2050 }
2051 
2052 #if !defined(SERVER_MODE)
2053 
2054 /*
2055  * merge_set_references() - Merges two set reference chains
2056  * return: none
2057  * set(in) : set object
2058  * ref(in) : new reference
2059  *
2060  * Note :
2061  * This is necessary in cases where there is a lot of swapping and
2062  * applications keep set references cached in their memory for long
2063  * periods of time.
2064  * In these cases it is possible for a set to be swapped out making
2065  * the reference unbound. If the set is swapped in later, it does
2066  * not know that there were previous references to it until those
2067  * references are used. If after the set is swapped in another request
2068  * is made, a new reference is created because the system doesn't know
2069  * about the old one. Later when the old reference is used, the system
2070  * detects that there is already a reference chain for the set and it
2071  * must merge them together.
2072  * This could be avoided if set references were interned like MOPs,
2073  * the search key would be the owning object, attribute id pair.
2074  * This would however add overhead to the creation of set references
2075  * and/or the fetching of objects.
2076  */
2077 
2078 static void
2080 {
2081  DB_COLLECTION *r;
2082 
2083  if (set != NULL && ref != NULL)
2084  {
2085  /* make all new references point to the set */
2086  r = ref;
2087  do
2088  {
2089  r->set = set;
2090  r = r->ref_link;
2091  }
2092  while (r != ref);
2093 
2094  /* merge the lists */
2095  if (set->references == NULL)
2096  {
2097  set->references = ref;
2098  }
2099  else
2100  {
2101  r = set->references->ref_link;
2102  set->references->ref_link = ref->ref_link;
2103  ref->ref_link = r;
2104  }
2105  }
2106 }
2107 #endif
2108 
2109 /*
2110  * set_tform_disk_set() - This gets the set object associated with a set reference
2111  * return: COL *
2112  * ref(in) : set refernce
2113  * setptr(in) :
2114  *
2115  * Note :
2116  * It may need to transform the disk_set image to the memory image.
2117  * The rule is this: if the reference has a non-NULL disk_set field,
2118  * then the set must be transformed. After tranformation the disk_set
2119  * must be freed and the disk_set, disk_size cleared.
2120  */
2121 
2122 int
2124 {
2125  OR_BUF buf;
2126 
2127  if (ref->disk_set)
2128  {
2129  or_init (&buf, ref->disk_set, 0);
2130  ref->set = or_get_set (&buf, ref->disk_domain);
2131  if (ref->set == NULL)
2132  {
2133  assert (er_errid () != NO_ERROR);
2134  return er_errid ();
2135  }
2136  *setptr = ref->set;
2137 
2138  /* free/clear the disk_set */
2139  if (ref->need_clear)
2140  {
2142  }
2143  ref->disk_set = NULL;
2144  ref->disk_size = 0;
2145  ref->need_clear = false;
2146  ref->disk_domain = NULL;
2147  }
2148  else
2149  {
2150  *setptr = ref->set; /* already been unpacked */
2151  }
2152 
2153  return NO_ERROR;
2154 
2155 } /* set_tform_disk_set */
2156 
2157 /*
2158  * set_get_setobj() - This gets the set object associated with a set reference
2159  * return: error code
2160  * ref(in) : set refernce
2161  * setptr(out) : returned pointer to set object
2162  * for_write(in) : indicates intention
2163  *
2164  * Note :
2165  * If the set is swapped out, it will be brought back in from
2166  * disk. The for_write flag is used so that if the object needs
2167  * to be fetched, the appropriate lock will be aquired early.
2168  * This is a dangerous function, the object had better be pinned
2169  * immediately upon return from this function. Absolutely do not
2170  * call any function that allocates storage before pinning the owning
2171  * object.
2172  */
2173 
2174 int
2175 set_get_setobj (DB_COLLECTION * ref, COL ** setptr, int for_write)
2176 {
2177  int error = NO_ERROR;
2178  COL *set = NULL;
2179 
2180  if (ref != NULL)
2181  {
2182  if (set_tform_disk_set (ref, &set) != NO_ERROR)
2183  {
2184  /* an error (like "out of memory") should have already been set */
2185  *setptr = NULL;
2186 
2187  assert (er_errid () != NO_ERROR);
2188  return er_errid ();
2189  }
2190 #if !defined(SERVER_MODE)
2191  {
2192  char *mem;
2193  if (set == NULL && ref->owner != NULL)
2194  {
2195  error = obj_locate_attribute (ref->owner, ref->attribute, for_write, &mem, NULL);
2196  if (error == NO_ERROR && mem != NULL)
2197  {
2198  /* this should be a PRIM level accessor */
2199  set = *(COL **) mem;
2200  merge_set_references (set, ref);
2201  }
2202  }
2203  }
2204 #endif
2205  }
2206  *setptr = set;
2207  return (error);
2208 }
2209 
2210 /*
2211  * set_connect() - This establishes ownership of a set
2212  * return: error
2213  * ref(in) : set reference
2214  * owner(in) : pointer to the owning object
2215  * attid(in) : attribute id
2216  * domain(in) : attribute domain
2217  *
2218  * Note :
2219  * It is called when a set is assigned as the value of an attribute.
2220  * The classobj and attid information is placed in the set reference
2221  * structure so the set can be retrieved if it is swapped out.
2222  * The domain information is cached in the set structure itself so that
2223  * each set doesn't have to carry around an independent domain which
2224  * wastes space. The domain structure comes from the class and will
2225  * not be swapped out before all objects (including their sets) have
2226  * been swapped. Its ok therefore to treat this as if it were a static
2227  * domain.
2228  */
2229 
2230 int
2231 set_connect (DB_COLLECTION * ref, MOP owner, int attid, TP_DOMAIN * domain)
2232 {
2233  DB_COLLECTION *r;
2234 
2235  if (ref == NULL)
2236  {
2237  return NO_ERROR;
2238  }
2239  /* must make sure ALL reference structures are properly tagged */
2240  r = ref;
2241  do
2242  {
2243  r->owner = owner;
2244  r->attribute = attid;
2245  r = r->ref_link;
2246  }
2247  while (r != ref);
2248 
2249  /* if this is NULL, is it an error ? */
2250  if (ref->set != NULL)
2251  {
2252  ref->set->domain = domain;
2253  }
2254  return (NO_ERROR);
2255 }
2256 
2257 /*
2258  * set_disconnect() - This is used to remove ownership from a set
2259  * return: error
2260  * ref(in) : set reference
2261  *
2262  * Note :
2263  * The owner fields in the reference structure are cleared
2264  *
2265  */
2266 
2267 int
2269 {
2270  int error = NO_ERROR;
2271  DB_COLLECTION *r;
2272 
2273  if (ref == NULL)
2274  {
2275  return error;
2276  }
2277  /* disconnect the references */
2278  r = ref;
2279 
2280  do
2281  {
2282  r->owner = NULL;
2283  r->attribute = -1;
2284  r = r->ref_link;
2285  }
2286  while (r != ref);
2287  return (error);
2288 }
2289 
2290 /*
2291  * set_change_owner() -
2292  * return: set reference (NULL if error)
2293  * ref(in) : set reference
2294  * owner(in) : new owner
2295  * attid(in) : attribute id
2296  * domain(in) : set domain
2297  *
2298  * Note :
2299  * This is simiar to set_connect except that it handles the case
2300  * where the set is already owned by another object and must
2301  * be copied.
2302  * If NULL is returned, it indicates some kind of error.
2303  * The domain is provided for connection only, semantic checking
2304  * of domain validity is assumed to have already been done.
2305  */
2306 
2307 DB_COLLECTION *
2308 set_change_owner (DB_COLLECTION * ref, MOP owner, int attid, TP_DOMAIN * domain)
2309 {
2310  DB_COLLECTION *new_ = NULL;
2311 #if !defined(SERVER_MODE)
2312  COL *current, *newset;
2313  int pin;
2314 
2315  /* fetch set of interest */
2316  if (set_get_setobj (ref, &current, 0) != NO_ERROR)
2317  {
2318  return NULL;
2319  }
2320 
2321  if (ref == NULL || current == NULL)
2322  {
2323  /* this indicates an unbound set reference with no owner, shouldn't happen, probably should have better error
2324  * here */
2326  }
2327  else
2328  {
2329  pin = ws_pin (ref->owner, 1);
2330 
2331  if (ref->owner == NULL || (ws_is_same_object (ref->owner, owner) && ref->attribute == attid))
2332  {
2333  new_ = ref;
2334  }
2335  else
2336  {
2337  /* must make a copy */
2338  newset = setobj_copy (current);
2339  if (newset != NULL)
2340  {
2341  new_ = setobj_get_reference (newset);
2342  if (new_ == NULL)
2343  {
2344  setobj_free (newset);
2345  }
2346  }
2347  }
2348  if (new_ != NULL)
2349  {
2350  set_connect (new_, owner, attid, domain);
2351  }
2352 
2353  (void) ws_pin (ref->owner, pin);
2354  }
2355 #endif
2356  return (new_);
2357 }
2358 
2359 /* SET REFERENCE SHELLS */
2360 /* These are shell functions that resolve a set reference through a
2361  DB_COLLECTION structure and make a corresponding call to a COL structure
2362  with the referenced set.
2363 */
2364 /*
2365  * set_create() -
2366  * return: DB_COLLECTION *
2367  * type(in) :
2368  * initial_size(in) :
2369  *
2370  */
2371 
2372 DB_COLLECTION *
2373 set_create (DB_TYPE type, int initial_size)
2374 {
2375  DB_COLLECTION *col;
2376  COL *setobj;
2377 
2378  col = NULL;
2379  setobj = setobj_create (type, initial_size);
2380 
2381  if (setobj == NULL)
2382  {
2383  return col;
2384  }
2385 
2386  col = set_make_reference ();
2387 
2388  if (col == NULL)
2389  {
2390  setobj_free (setobj);
2391  }
2392  else
2393  {
2394  col->set = setobj;
2395  setobj->references = col;
2396  }
2397  return col;
2398 }
2399 
2400 /*
2401  * set_create_basic()
2402  * return: DB_COLLECTION *
2403  *
2404  */
2405 
2406 DB_COLLECTION *
2408 {
2409  return set_create (DB_TYPE_SET, 1);
2410 }
2411 
2412 /*
2413  * set_create_multi()
2414  * return: DB_COLLECTION *
2415  *
2416  */
2417 
2418 DB_COLLECTION *
2420 {
2421  return set_create (DB_TYPE_MULTISET, 1);
2422 }
2423 
2424 /*
2425  * set_create_sequence()
2426  * return: DB_COLLECTION *
2427  * size(in) :
2428  *
2429  */
2430 
2431 DB_COLLECTION *
2433 {
2434  return set_create (DB_TYPE_SEQUENCE, size);
2435 }
2436 
2437 DB_COLLECTION *
2438 set_create_with_domain (TP_DOMAIN * domain, int initial_size)
2439 {
2440  DB_COLLECTION *col;
2441  COL *setobj;
2442 
2443  col = NULL;
2444  setobj = setobj_create_with_domain (domain, initial_size);
2445  if (setobj == NULL)
2446  {
2447  return (col);
2448  }
2449 
2450  col = set_make_reference ();
2451 
2452  if (col == NULL)
2453  {
2454  setobj_free (setobj);
2455  }
2456  else
2457  {
2458  col->set = setobj;
2459  setobj->references = col;
2460  }
2461  return (col);
2462 }
2463 
2464 /*
2465  * set_copy() -
2466  * return: DB_COLLECTION *
2467  * set(in) :
2468  *
2469  */
2470 
2471 
2472 DB_COLLECTION *
2474 {
2475  COL *srcobj, *newobj;
2476  DB_COLLECTION *new_;
2477 #if !defined(SERVER_MODE)
2478  int pin;
2479 #endif
2480 
2481  new_ = NULL;
2482  if (set_get_setobj (set, &srcobj, 0) != NO_ERROR)
2483  {
2484  return new_;
2485  }
2486 
2487  if (set != NULL && srcobj != NULL)
2488  {
2489 #if !defined(SERVER_MODE)
2490  pin = ws_pin (set->owner, 1);
2491 #endif
2492  newobj = setobj_copy (srcobj);
2493  if (newobj != NULL)
2494  {
2495  new_ = set_make_reference ();
2496  if (new_ != NULL)
2497  {
2498  new_->set = newobj;
2499  newobj->references = new_;
2500  }
2501  else
2502  {
2503  setobj_free (newobj);
2504  }
2505  }
2506 #if !defined(SERVER_MODE)
2507  (void) ws_pin (set->owner, pin);
2508 #endif
2509  }
2510  return (new_);
2511 }
2512 
2513 /*
2514  * set_clear() -
2515  * return: int
2516  * set(in) :
2517  *
2518  */
2519 
2520 #if defined (ENABLE_UNUSED_FUNCTION)
2521 int
2522 set_clear (DB_COLLECTION * set)
2523 {
2524  int error;
2525  COL *obj;
2526 #if !defined(SERVER_MODE)
2527  int pin;
2528 #endif
2529 
2530  error = set_get_setobj (set, &obj, 1);
2531  if (error != NO_ERROR)
2532  {
2533  return error;
2534  }
2535 
2536  if (set == NULL || obj == NULL)
2537  {
2538  return error;
2539  }
2540 
2541 #if !defined(SERVER_MODE)
2542  pin = ws_pin (set->owner, 1);
2543 #endif
2544  setobj_clear (obj);
2545 #if !defined(SERVER_MODE)
2546  (void) ws_pin (set->owner, pin);
2547 #endif
2548  return (error);
2549 }
2550 #endif /* ENABLE_UNUSED_FUNCTION */
2551 
2552 /*
2553  * set_free() -
2554  * return: none
2555  * set(in) :
2556  *
2557  */
2558 
2559 void
2561 {
2562  free_set_reference (set);
2563 }
2564 
2565 /*
2566  * set_get_element() -
2567  * return: int
2568  * set(in) :
2569  * index(in) :
2570  * value(in) :
2571  *
2572  */
2573 
2574 int
2576 {
2577  int error;
2578  COL *obj;
2579 #if !defined(SERVER_MODE)
2580  int pin;
2581 #endif
2582 
2583  error = set_get_setobj (set, &obj, 0);
2584  if (error != NO_ERROR)
2585  {
2586  return error;
2587  }
2588 
2589  if (set == NULL || obj == NULL)
2590  {
2591  return error;
2592  }
2593 #if !defined(SERVER_MODE)
2594  pin = ws_pin (set->owner, 1);
2595 #endif
2596  error = setobj_get_element (obj, index, value);
2597 #if !defined(SERVER_MODE)
2598  (void) ws_pin (set->owner, pin);
2599 #endif
2600  return (error);
2601 }
2602 
2603 /*
2604  * set_get_element_nocopy() -
2605  * return: error code
2606  * set(in) : set to examine
2607  * index(in) : element index
2608  * value(out) : value to put result in
2609  *
2610  * Note :
2611  * Hack to optimize iteration over the property list sets used for
2612  * the storage of index and constraint information.
2613  */
2614 
2615 int
2617 {
2618  int error;
2619  DB_VALUE *valptr;
2620 
2621  /* set contents can't be swapped out here */
2622  error = setobj_get_element_ptr (set->set, index, &valptr);
2623 
2624  if (!error)
2625  {
2626  *value = *valptr;
2627  }
2628 
2629  return error;
2630 }
2631 
2632 /*
2633  * set_add_element() -
2634  * return: error code
2635  * set(in) :
2636  * value(out) :
2637  *
2638  */
2639 
2640 int
2642 {
2643  int error;
2644  COL *obj;
2645 #if !defined(SERVER_MODE)
2646  int pin;
2647 #endif
2648 
2649  error = set_get_setobj (set, &obj, 1);
2650  if (error == NO_ERROR)
2651  {
2652  if (set != NULL && obj != NULL)
2653  {
2654 #if !defined(SERVER_MODE)
2655  pin = ws_pin (set->owner, 1);
2656 #endif
2657  if (set->owner == NULL)
2658  {
2659  error = setobj_add_element (obj, value);
2660  }
2661 
2662 #if !defined(SERVER_MODE)
2663  /* get write lock on owner and mark as dirty */
2664  else
2665  {
2666 #if !defined (NDEBUG)
2667  MOP class_mop = NULL;
2668 
2669  class_mop = ws_class_mop (set->owner);
2670  assert (ws_get_lock (set->owner) == X_LOCK
2671  || (class_mop != NULL
2672  && (ws_get_lock (class_mop) == X_LOCK || ws_get_lock (class_mop) == SCH_M_LOCK)));
2673 #endif
2674  /* the caller should have holden a lock already we need write lock here */
2675  error = obj_lock (set->owner, 1);
2676  if (error == NO_ERROR)
2677  {
2678  error = setobj_add_element (obj, value);
2679  }
2680  }
2681 #endif
2682 
2683 #if !defined(SERVER_MODE)
2684  (void) ws_pin (set->owner, pin);
2685 #endif
2686  }
2687  }
2688  return (error);
2689 }
2690 
2691 /* call this when you know the elements are ok */
2692 
2693 #if defined (ENABLE_UNUSED_FUNCTION)
2694 /*
2695  * set_add_element_quick() -
2696  * return: error code
2697  * set(in) :
2698  * value(out) :
2699  *
2700  */
2701 
2702 int
2703 set_add_element_quick (DB_COLLECTION * set, DB_VALUE * value)
2704 {
2705  return set_add_element (set, value);
2706 }
2707 #endif /* ENABLE_UNUSED_FUNCTION */
2708 
2709 /*
2710  * set_add_element_quick() -
2711  * return: error code
2712  * set(in) :
2713  * index(in) :
2714  * value(out) :
2715  *
2716  */
2717 
2718 int
2720 {
2721  int error;
2722  COL *obj;
2723 #if !defined(SERVER_MODE)
2724  int pin;
2725 #endif
2726  error = set_get_setobj (set, &obj, 1);
2727  if (error != NO_ERROR)
2728  {
2729  return error;
2730  }
2731 
2732  if (set != NULL && obj != NULL)
2733  {
2734 #if !defined(SERVER_MODE)
2735  pin = ws_pin (set->owner, 1);
2736 #endif
2737  if (set->owner == NULL)
2738  {
2739  error = setobj_put_element (obj, index, value);
2740  }
2741 
2742 #if !defined(SERVER_MODE)
2743  /* get write lock on owner and mark as dirty */
2744  else
2745  {
2746 #if !defined (NDEBUG)
2747  MOP class_mop = NULL;
2748 
2749  class_mop = ws_class_mop (set->owner);
2750  assert (ws_get_lock (set->owner) == X_LOCK
2751  || (class_mop != NULL
2752  && (ws_get_lock (class_mop) == X_LOCK || ws_get_lock (class_mop) == SCH_M_LOCK)));
2753 #endif
2754  /* the caller should have holden a lock already we need write lock here */
2755  error = obj_lock (set->owner, 1);
2756  if (error == NO_ERROR)
2757  {
2758  error = setobj_put_element (obj, index, value);
2759  }
2760  }
2761 #endif
2762 
2763 #if !defined(SERVER_MODE)
2764  (void) ws_pin (set->owner, pin);
2765 #endif
2766  }
2767 
2768  return (error);
2769 }
2770 
2771 /*
2772  * set_insert_element() -
2773  * return: error code
2774  * set(in) :
2775  * index(in) :
2776  * value(out) :
2777  *
2778  */
2779 
2780 int
2782 {
2783  int error;
2784  COL *obj;
2785 #if !defined(SERVER_MODE)
2786  int pin;
2787 #endif
2788 
2789  error = set_get_setobj (set, &obj, 1);
2790  if (error != NO_ERROR)
2791  {
2792  return error;
2793  }
2794 
2795  if (set != NULL && obj != NULL)
2796  {
2797 #if !defined(SERVER_MODE)
2798  pin = ws_pin (set->owner, 1);
2799 #endif
2800  if (set->owner == NULL)
2801  {
2802  error = setobj_insert_element (obj, index, value);
2803  }
2804 
2805 #if !defined(SERVER_MODE)
2806  else
2807  {
2808 #if !defined (NDEBUG)
2809  MOP class_mop = NULL;
2810 
2811  class_mop = ws_class_mop (set->owner);
2812  assert (ws_get_lock (set->owner) == X_LOCK
2813  || (class_mop != NULL
2814  && (ws_get_lock (class_mop) == X_LOCK || ws_get_lock (class_mop) == SCH_M_LOCK)));
2815 #endif
2816  /* the caller should have holden a lock already we need write lock here */
2817  error = obj_lock (set->owner, 1);
2818  if (error == NO_ERROR)
2819  {
2820  error = setobj_insert_element (obj, index, value);
2821  }
2822  }
2823 #endif
2824 
2825 #if !defined(SERVER_MODE)
2826  (void) ws_pin (set->owner, pin);
2827 #endif
2828  }
2829  return (error);
2830 }
2831 
2832 /*
2833  * set_drop_element() -
2834  * return:
2835  * set(in) :
2836  * value(out) :
2837  * match_nulls(in) :
2838  *
2839  */
2840 
2841 int
2842 set_drop_element (DB_COLLECTION * set, DB_VALUE * value, bool match_nulls)
2843 {
2844  int error;
2845  COL *obj;
2846 #if !defined(SERVER_MODE)
2847  int pin;
2848 #endif
2849 
2850  error = set_get_setobj (set, &obj, 1);
2851  if (error != NO_ERROR)
2852  {
2853  return error;
2854  }
2855  if (set != NULL && obj != NULL)
2856  {
2857 #if !defined(SERVER_MODE)
2858  pin = ws_pin (set->owner, 1);
2859 #endif
2860  if (set->owner == NULL)
2861  {
2862  error = setobj_drop_element (obj, value, match_nulls);
2863  }
2864 
2865 #if !defined(SERVER_MODE)
2866  else
2867  {
2868 #if !defined (NDEBUG)
2869  MOP class_mop = NULL;
2870 
2871  class_mop = ws_class_mop (set->owner);
2872  assert (ws_get_lock (set->owner) == X_LOCK
2873  || (class_mop != NULL
2874  && (ws_get_lock (class_mop) == X_LOCK || ws_get_lock (class_mop) == SCH_M_LOCK)));
2875 #endif
2876  /* the caller should have holden a lock already we need write lock here */
2877  error = obj_lock (set->owner, 1);
2878  if (error == NO_ERROR)
2879  {
2880  error = setobj_drop_element (obj, value, match_nulls);
2881  }
2882  }
2883 #endif
2884 
2885 #if !defined(SERVER_MODE)
2886  (void) ws_pin (set->owner, pin);
2887 #endif
2888  }
2889  return (error);
2890 }
2891 
2892 /*
2893  * set_drop_seq_element() -
2894  * return:
2895  * set(out) :
2896  * index(in) :
2897  *
2898  */
2899 
2900 
2901 int
2903 {
2904  int error = NO_ERROR;
2905  COL *obj;
2906 #if !defined(SERVER_MODE)
2907  int pin;
2908 #endif
2909 
2910  error = set_get_setobj (set, &obj, 1);
2911  if (error != NO_ERROR)
2912  {
2913  return error;
2914  }
2915  if (set != NULL && obj != NULL)
2916  {
2917 #if !defined(SERVER_MODE)
2918  pin = ws_pin (set->owner, 1);
2919 #endif
2920  if (set->owner == NULL)
2921  {
2922  error = setobj_drop_seq_element (obj, index);
2923  }
2924 
2925 #if !defined(SERVER_MODE)
2926  else
2927  {
2928 #if !defined (NDEBUG)
2929  MOP class_mop = NULL;
2930 
2931  class_mop = ws_class_mop (set->owner);
2932  assert (ws_get_lock (set->owner) == X_LOCK
2933  || (class_mop != NULL
2934  && (ws_get_lock (class_mop) == X_LOCK || ws_get_lock (class_mop) == SCH_M_LOCK)));
2935 #endif
2936  /* the caller should have holden a lock already we need write lock here */
2937  error = obj_lock (set->owner, 1);
2938  if (error == NO_ERROR)
2939  {
2940  error = setobj_drop_seq_element (obj, index);
2941  }
2942  }
2943 #endif
2944 
2945 #if !defined(SERVER_MODE)
2946  (void) ws_pin (set->owner, pin);
2947 #endif
2948  }
2949  return (error);
2950 }
2951 
2952 /*
2953  * set_find_seq_element() -
2954  * return: int
2955  * set(in) :
2956  * value(in) :
2957  * index(in) :
2958  *
2959  */
2960 
2961 int
2963 {
2964  COL *obj;
2965  int psn = -1;
2966  int error = NO_ERROR;
2967 #if !defined(SERVER_MODE)
2968  int pin;
2969 #endif
2970 
2971  error = set_get_setobj (set, &obj, 1);
2972  if (error != NO_ERROR)
2973  {
2974  return (psn);
2975  }
2976 
2977  if (set != NULL && obj != NULL)
2978  {
2979 #if !defined(SERVER_MODE)
2980  pin = ws_pin (set->owner, 1);
2981 #endif
2982  psn = setobj_find_seq_element (obj, value, index);
2983 #if !defined(SERVER_MODE)
2984  (void) ws_pin (set->owner, pin);
2985 #endif
2986  }
2987 
2988  return (psn);
2989 }
2990 
2991 /*
2992  * set_cardinality() -
2993  * return: int
2994  * set(in) :
2995  *
2996  */
2997 
2998 int
3000 {
3001  COL *obj;
3002  int length;
3003  int error = NO_ERROR;
3004 #if !defined(SERVER_MODE)
3005  int pin;
3006 #endif
3007  error = set_get_setobj (set, &obj, 0);
3008  if (error != NO_ERROR)
3009  {
3010  return -1;
3011  }
3012 
3013  if (set == NULL || obj == NULL)
3014  {
3015  return 0;
3016  }
3017 
3018 #if !defined(SERVER_MODE)
3019  pin = ws_pin (set->owner, 1);
3020 #endif
3021  length = setobj_cardinality (obj);
3022 #if !defined(SERVER_MODE)
3023  (void) ws_pin (set->owner, pin);
3024 #endif
3025  return (length);
3026 }
3027 
3028 /*
3029  * set_size() -
3030  * return:
3031  * set(in) : int
3032  *
3033  */
3034 
3035 int
3037 {
3038  COL *obj;
3039  int length;
3040  int error = NO_ERROR;
3041 #if !defined(SERVER_MODE)
3042  int pin;
3043 #endif
3044 
3045  error = set_get_setobj (set, &obj, 0);
3046  if (error != NO_ERROR)
3047  {
3048  return -1;
3049  }
3050 
3051  if (set == NULL || obj == NULL)
3052  {
3053  return 0;
3054  }
3055 
3056 #if !defined(SERVER_MODE)
3057  pin = ws_pin (set->owner, 1);
3058 #endif
3059  length = setobj_size (obj);
3060 #if !defined(SERVER_MODE)
3061  (void) ws_pin (set->owner, pin);
3062 #endif
3063  return (length);
3064 }
3065 
3066 /*
3067  * set_isempty() -
3068  * return: bool
3069  * set(in) :
3070  *
3071  */
3072 
3073 bool
3075 {
3076  COL *obj;
3077  bool isempty = true;
3078  int error = NO_ERROR;
3079 #if !defined(SERVER_MODE)
3080  int pin;
3081 #endif
3082 
3083  error = set_get_setobj (set, &obj, 0);
3084  if (error != NO_ERROR)
3085  {
3086  return isempty;
3087  }
3088 
3089  if (set == NULL || obj == NULL)
3090  {
3091  return isempty;
3092  }
3093 #if !defined(SERVER_MODE)
3094  pin = ws_pin (set->owner, 1);
3095 #endif
3096  isempty = setobj_isempty (obj);
3097 #if !defined(SERVER_MODE)
3098  (void) ws_pin (set->owner, pin);
3099 #endif
3100 
3101  return (isempty);
3102 }
3103 
3104 #if defined(ENABLE_UNUSED_FUNCTION)
3105 /*
3106  * set_is_all_null() -
3107  * return: Boolean value.
3108  * true if the sequence contains all NULL's and
3109  * false otherwise.
3110  * set(in) : set pointer
3111  *
3112  * Note :
3113  * Check the contents of the collection and return true if the
3114  * contents contain nothing but NULL values. Return false otherwise.
3115  * This function is used by seq_key_is_null() to look for NULL
3116  * multi-column index keys.
3117  */
3118 
3119 bool
3120 set_is_all_null (DB_COLLECTION * set)
3121 {
3122  COL *obj;
3123  bool isallnull = true;
3124  int error = NO_ERROR;
3125 #if !defined(SERVER_MODE)
3126  int pin;
3127 #endif
3128 
3129  error = set_get_setobj (set, &obj, 0);
3130  if (error != NO_ERROR)
3131  {
3132  return isallnull;
3133  }
3134 
3135  if (set == NULL || obj == NULL)
3136  {
3137  return isallnull;
3138  }
3139 
3140 #if !defined(SERVER_MODE)
3141  pin = ws_pin (set->owner, 1);
3142 #endif
3143  isallnull = col_is_all_null (obj);
3144 #if !defined(SERVER_MODE)
3145  (void) ws_pin (set->owner, pin);
3146 #endif
3147 
3148  return (isallnull);
3149 }
3150 #endif /* ENABLE_UNUSED_FUNCTION */
3151 
3152 /*
3153  * set_has_null() -
3154  * return: bool
3155  * set(in) :
3156  *
3157  */
3158 
3159 bool
3161 {
3162  COL *obj;
3163  bool hasnull = true;
3164  int error = NO_ERROR;
3165 #if !defined(SERVER_MODE)
3166  int pin;
3167 #endif
3168 
3169  error = set_get_setobj (set, &obj, 0);
3170  if (error != NO_ERROR)
3171  {
3172  return hasnull;
3173  }
3174 
3175  if (set == NULL || obj == NULL)
3176  {
3177  return hasnull;
3178  }
3179 
3180 #if !defined(SERVER_MODE)
3181  pin = ws_pin (set->owner, 1);
3182 #endif
3183  hasnull = col_has_null (obj);
3184 #if !defined(SERVER_MODE)
3185  (void) ws_pin (set->owner, pin);
3186 #endif
3187  return (hasnull);
3188 }
3189 
3190 /*
3191  * set_ismember() -
3192  * return: bool
3193  * set(in) :
3194  * value(out) :
3195  *
3196  */
3197 
3198 bool
3200 {
3201  COL *obj;
3202  bool ismember = false;
3203  int error = NO_ERROR;
3204 #if !defined(SERVER_MODE)
3205  int pin;
3206 #endif
3207 
3208  error = set_get_setobj (set, &obj, 0);
3209  if (error != NO_ERROR)
3210  {
3211  return ismember;
3212  }
3213 
3214  if (set == NULL || obj == NULL)
3215  {
3216  return ismember;
3217  }
3218 
3219 #if !defined(SERVER_MODE)
3220  pin = ws_pin (set->owner, 1);
3221 #endif
3222  ismember = setobj_ismember (obj, value, 0);
3223 #if !defined(SERVER_MODE)
3224  (void) ws_pin (set->owner, pin);
3225 #endif
3226  return (ismember);
3227 }
3228 
3229 #if !defined (SERVER_MODE)
3230 /*
3231  * set_issome() -
3232  * return: int
3233  * value(in) :
3234  * set(in) :
3235  * op(in) :
3236  * do_coercion(in) :
3237  *
3238  */
3239 int
3240 set_issome (DB_VALUE * value, DB_COLLECTION * set, PT_OP_TYPE op, int do_coercion)
3241 {
3242  COL *obj;
3243  int issome = -1;
3244  int error = NO_ERROR;
3245  int pin;
3246 
3247  error = set_get_setobj (set, &obj, 0);
3248  if (error != NO_ERROR)
3249  {
3250  return issome;
3251  }
3252 
3253  if (set == NULL || obj == NULL)
3254  {
3255  return issome;
3256  }
3257 
3258  pin = ws_pin (set->owner, 1);
3259  issome = setobj_issome (value, obj, op, do_coercion);
3260  (void) ws_pin (set->owner, pin);
3261  return (issome);
3262 }
3263 #endif /* !defined (SERVER_MODE) */
3264 
3265 /*
3266  * set_convert_oids_to_objects() -
3267  * return: error code
3268  * set(in) :
3269  *
3270  */
3271 
3272 int
3274 {
3275  int error = NO_ERROR;
3276  COL *obj;
3277 #if !defined(SERVER_MODE)
3278  int pin;
3279 #endif
3280 
3281  error = set_get_setobj (set, &obj, 1);
3282  if (error != NO_ERROR)
3283  {
3284  return error;
3285  }
3286 
3287  if (set != NULL && obj != NULL)
3288  {
3289 #if !defined(SERVER_MODE)
3290  pin = ws_pin (set->owner, 1);
3291 #endif
3292  if (set->owner == NULL)
3293  {
3294  error = setobj_convert_oids_to_objects (obj);
3295  }
3296 #if !defined(SERVER_MODE)
3297  else if ((error = obj_lock (set->owner, 1)) == NO_ERROR)
3298  {
3299  error = setobj_convert_oids_to_objects (obj);
3300  }
3301 #endif
3302 
3303 #if !defined(SERVER_MODE)
3304  (void) ws_pin (set->owner, pin);
3305 #endif
3306  }
3307 
3308  return (error);
3309 }
3310 
3311 /*
3312  * set_get_domain() -
3313  * return: TP_DOMAIN *
3314  * set(in) :
3315  *
3316  */
3317 
3318 TP_DOMAIN *
3320 {
3321  COL *obj;
3322  TP_DOMAIN *domain = NULL;
3323  int error = NO_ERROR;
3324 #if !defined(SERVER_MODE)
3325  int pin;
3326 #endif
3327 
3328  error = set_get_setobj (set, &obj, 0);
3329  if (error != NO_ERROR)
3330  {
3331  return domain;
3332  }
3333 
3334  if (set == NULL || obj == NULL)
3335  {
3336  return domain;
3337  }
3338 
3339 #if !defined(SERVER_MODE)
3340  pin = ws_pin (set->owner, 1);
3341 #endif
3342  domain = setobj_get_domain (obj);
3343 #if !defined(SERVER_MODE)
3344  (void) ws_pin (set->owner, pin);
3345 #endif
3346  return (domain);
3347 }
3348 
3349 /*
3350  * set_compare_order() -
3351  * return:
3352  * set1(in) :
3353  * set2(in) :
3354  * do_coercion(in) :
3355  * total_order(in) :
3356  *
3357  */
3359 set_compare_order (DB_COLLECTION * set1, DB_COLLECTION * set2, int do_coercion, int total_order)
3360 {
3361  COL *obj1, *obj2;
3363  int error = NO_ERROR;
3364 #if !defined(SERVER_MODE)
3365  int pin1, pin2;
3366 #endif
3367 
3368  error = set_get_setobj (set1, &obj1, 0);
3369  if (error != NO_ERROR)
3370  {
3371  return status;
3372  }
3373 
3374  if (set1 == NULL || obj1 == NULL)
3375  {
3376  return status;
3377  }
3378 #if !defined(SERVER_MODE)
3379  pin1 = ws_pin (set1->owner, 1);
3380 #endif
3381  if (set_get_setobj (set2, &obj2, 0) == NO_ERROR)
3382  {
3383  if (set2 != NULL && obj2 != NULL)
3384  {
3385 #if !defined(SERVER_MODE)
3386  pin2 = ws_pin (set2->owner, 1);
3387 #endif
3388 
3389  status = setobj_compare_order (obj1, obj2, do_coercion, total_order);
3390 
3391 #if !defined(SERVER_MODE)
3392  (void) ws_pin (set2->owner, pin2);
3393 #endif
3394  }
3395  }
3396 #if !defined(SERVER_MODE)
3397  (void) ws_pin (set1->owner, pin1);
3398 #endif
3399  return (status);
3400 }
3401 
3402 /*
3403  * set_compare() -
3404  * return:
3405  * set1(in) :
3406  * set2(in) :
3407  * do_coercion(in) :
3408  *
3409  */
3411 set_compare (DB_COLLECTION * set1, DB_COLLECTION * set2, int do_coercion)
3412 {
3413  COL *obj1, *obj2;
3415  int error = NO_ERROR;
3416 #if !defined(SERVER_MODE)
3417  int pin1, pin2;
3418 #endif
3419 
3420  error = set_get_setobj (set1, &obj1, 0);
3421  if (error != NO_ERROR)
3422  {
3423  return status;
3424  }
3425 
3426  if (set1 == NULL || obj1 == NULL)
3427  {
3428  return status;
3429  }
3430 #if !defined(SERVER_MODE)
3431  pin1 = ws_pin (set1->owner, 1);
3432 #endif
3433  if (set_get_setobj (set2, &obj2, 0) == NO_ERROR)
3434  {
3435  if (set2 != NULL && obj2 != NULL)
3436  {
3437 #if !defined(SERVER_MODE)
3438  pin2 = ws_pin (set2->owner, 1);
3439 #endif
3440 
3441  status = setobj_compare (obj1, obj2, do_coercion);
3442 
3443 #if !defined(SERVER_MODE)
3444  (void) ws_pin (set2->owner, pin2);
3445 #endif
3446  }
3447  }
3448 #if !defined(SERVER_MODE)
3449  (void) ws_pin (set1->owner, pin1);
3450 #endif
3451  return (status);
3452 }
3453 
3454 /*
3455  * set_seq_compare() -
3456  * return: int
3457  * set1(in) :
3458  * set2(in) :
3459  * do_coercion(in) :
3460  * total_order(in) :
3461  *
3462  */
3464 set_seq_compare (DB_COLLECTION * set1, DB_COLLECTION * set2, int do_coercion, int total_order)
3465 {
3466  COL *obj1, *obj2;
3468  int error = NO_ERROR;
3469 #if !defined(SERVER_MODE)
3470  int pin1, pin2;
3471 #endif
3472 
3473  error = set_get_setobj (set1, &obj1, 0);
3474 
3475  if (error != NO_ERROR)
3476  {
3477  return status;
3478  }
3479  if (set1 == NULL || obj1 == NULL)
3480  {
3481  return status;
3482  }
3483 #if !defined(SERVER_MODE)
3484  pin1 = ws_pin (set1->owner, 1);
3485 #endif
3486  if (set_get_setobj (set2, &obj2, 0) == NO_ERROR)
3487  {
3488  if (set2 != NULL && obj2 != NULL)
3489  {
3490 #if !defined(SERVER_MODE)
3491  pin2 = ws_pin (set2->owner, 1);
3492 #endif
3493  status = setobj_compare_order (obj1, obj2, do_coercion, total_order);
3494 
3495 #if !defined(SERVER_MODE)
3496  (void) ws_pin (set2->owner, pin2);
3497 #endif
3498  }
3499  }
3500 #if !defined(SERVER_MODE)
3501  (void) ws_pin (set1->owner, pin1);
3502 #endif
3503  return (status);
3504 }
3505 
3506 /*
3507  * vobj_compare() -
3508  * return: int
3509  * set1(in) :
3510  * set2(in) :
3511  * do_coercion(in) :
3512  * total_order(in) :
3513  *
3514  */
3515 
3517 vobj_compare (DB_COLLECTION * set1, DB_COLLECTION * set2, int do_coercion, int total_order)
3518 {
3519  COL *obj1, *obj2;
3521  int error = NO_ERROR;
3522 
3523 #if !defined(SERVER_MODE)
3524  int pin1, pin2;
3525 #endif
3526 
3527  error = set_get_setobj (set1, &obj1, 0);
3528  if (error != NO_ERROR)
3529  {
3530  return status;
3531  }
3532  if (set1 == NULL || obj1 == NULL)
3533  {
3534  return status;
3535  }
3536 #if !defined(SERVER_MODE)
3537  pin1 = ws_pin (set1->owner, 1);
3538 #endif
3539  if (set_get_setobj (set2, &obj2, 0) == NO_ERROR)
3540  {
3541  if (set2 != NULL && obj2 != NULL)
3542  {
3543 #if !defined(SERVER_MODE)
3544  pin2 = ws_pin (set2->owner, 1);
3545 #endif
3546  status = setvobj_compare (obj1, obj2, do_coercion, total_order);
3547 #if !defined(SERVER_MODE)
3548  (void) ws_pin (set2->owner, pin2);
3549 #endif
3550  }
3551  }
3552 #if !defined(SERVER_MODE)
3553  (void) ws_pin (set1->owner, pin1);
3554 #endif
3555  return (status);
3556 }
3557 
3558 /*
3559  * set_get_type() -
3560  * return: DB_TYPE
3561  * set(in) :
3562  *
3563  */
3564 
3565 DB_TYPE
3567 {
3568  COL *obj;
3569  DB_TYPE stype = DB_TYPE_NULL;
3570  int error = NO_ERROR;
3571 
3572 #if !defined(SERVER_MODE)
3573  int pin;
3574 #endif
3575 
3576  error = set_get_setobj (set, &obj, 0);
3577  if (error != NO_ERROR)
3578  {
3579  return stype;
3580  }
3581  if (set == NULL || obj == NULL)
3582  {
3583  return stype;
3584  }
3585 #if !defined(SERVER_MODE)
3586  pin = ws_pin (set->owner, 1);
3587 #endif
3588  stype = obj->coltype;
3589 #if !defined(SERVER_MODE)
3590  (void) ws_pin (set->owner, pin);
3591 #endif
3592  return (stype);
3593 }
3594 
3595 /*
3596  * set_check_domain() -
3597  * return: TP_DOMAIN_STATUS
3598  * set(in) :
3599  * domain(in) :
3600  *
3601  */
3602 
3605 {
3606  TP_DOMAIN_STATUS status;
3607  COL *obj;
3608  int error = NO_ERROR;
3609 
3610 #if !defined(SERVER_MODE)
3611  int pin;
3612 #endif
3613 
3614  error = set_get_setobj (set, &obj, 0);
3615  if (error != NO_ERROR)
3616  {
3617  status = DOMAIN_ERROR;
3618  return status;
3619  }
3620  if (set == NULL || obj == NULL)
3621  {
3622  status = DOMAIN_INCOMPATIBLE;
3623  return status;
3624  }
3625 #if !defined(SERVER_MODE)
3626  pin = ws_pin (set->owner, 1);
3627 #endif
3628  status = setobj_check_domain (obj, domain);
3629 #if !defined(SERVER_MODE)
3630  (void) ws_pin (set->owner, pin);
3631 #endif
3632  return (status);
3633 }
3634 
3635 /*
3636  * set_coerce() -
3637  * return: DB_COLLECTION *
3638  * set(in) :
3639  * domain(in) :
3640  * implicit_coercion(in) :
3641  *
3642  */
3643 
3644 DB_COLLECTION *
3645 set_coerce (DB_COLLECTION * set, TP_DOMAIN * domain, bool implicit_coercion)
3646 {
3647  COL *srcobj, *newobj;
3648  DB_COLLECTION *new_;
3649  int error = NO_ERROR;
3650 #if !defined(SERVER_MODE)
3651  int pin;
3652 #endif
3653 
3654  new_ = NULL;
3655  error = set_get_setobj (set, &srcobj, 0);
3656  if (error != NO_ERROR)
3657  {
3658  return new_;
3659  }
3660  if (set == NULL || srcobj == NULL)
3661  {
3662  return new_;
3663  }
3664 #if !defined(SERVER_MODE)
3665  pin = ws_pin (set->owner, 1);
3666 #endif
3667  newobj = setobj_coerce (srcobj, domain, implicit_coercion);
3668  if (newobj != NULL)
3669  {
3670  new_ = set_make_reference ();
3671  if (new_ != NULL)
3672  {
3673  new_->set = newobj;
3674  newobj->references = new_;
3675  }
3676  else
3677  {
3678  setobj_free (newobj);
3679  }
3680  }
3681 #if !defined(SERVER_MODE)
3682  (void) ws_pin (set->owner, pin);
3683 #endif
3684  return (new_);
3685 }
3686 
3687 /*
3688  * set_fprint() -
3689  * return: none
3690  * fp(in) :
3691  * set(in) :
3692  *
3693  */
3694 
3695 void
3696 set_fprint (FILE * fp, DB_COLLECTION * set)
3697 {
3698  COL *obj;
3699  int error = NO_ERROR;
3700 
3701 #if !defined(SERVER_MODE)
3702  int pin;
3703 #endif
3704 
3705  error = set_get_setobj (set, &obj, 0);
3706  if (error != NO_ERROR)
3707  {
3708  return;
3709  }
3710  if (set == NULL || obj == NULL)
3711  {
3712  return;
3713  }
3714 #if !defined(SERVER_MODE)
3715  pin = ws_pin (set->owner, 1);
3716 #endif
3717  setobj_print (fp, obj);
3718 #if !defined(SERVER_MODE)
3719  (void) ws_pin (set->owner, pin);
3720 #endif
3721 }
3722 
3723 /*
3724  * set_print() -
3725  * return: none
3726  * set(in) :
3727  *
3728  */
3729 
3730 void
3732 {
3733  set_fprint (stdout, set);
3734 }
3735 
3736 /*
3737  * set_filter() -
3738  * return: error code
3739  * set(in) :
3740  *
3741  */
3742 
3743 int
3745 {
3746  int error;
3747  COL *obj;
3748 #if !defined(SERVER_MODE)
3749  int pin;
3750 #endif
3751 
3752  error = set_get_setobj (set, &obj, 0);
3753  if (error != NO_ERROR)
3754  {
3755  return error;
3756  }
3757 
3758  if (set == NULL || obj == NULL)
3759  {
3760  return error;
3761  }
3762 #if !defined(SERVER_MODE)
3763  pin = ws_pin (set->owner, 1);
3764 #endif
3765  error = setobj_filter (obj, 1, NULL);
3766 
3767 #if !defined(SERVER_MODE)
3768  (void) ws_pin (set->owner, pin);
3769 #endif
3770  return (error);
3771 }
3772 
3773 
3774 /*
3775  * set_op() -
3776  * return:
3777  * collection1(in) : input collections
3778  * collection2(in) : input collections
3779  * result(in) : output set or multiset
3780  * domain(in) : desired result domain
3781  * op(in) :
3782  *
3783  * Note :
3784  * takes the set difference of two collections
3785  * If either argument is a sequence, it is
3786  * first corced to the result domain, which must be
3787  * a multiset or set.
3788  *
3789  */
3790 
3791 static int
3792 set_op (DB_COLLECTION * collection1, DB_COLLECTION * collection2, DB_COLLECTION ** result, DB_DOMAIN * domain,
3793  SETOBJ_OP op)
3794 {
3795  COL *col1, *col2;
3796  int error = NO_ERROR;
3797 #if !defined(SERVER_MODE)
3798  int pin1, pin2;
3799 #endif
3800 
3801  CHECKNULL_ERR (collection1);
3802  CHECKNULL_ERR (collection2);
3803  CHECKNULL_ERR (result);
3804  CHECKNULL_ERR (domain);
3805  CHECKNULL_ERR (domain->type);
3806 
3807  error = set_get_setobj (collection1, &col1, 0);
3808  if (error != NO_ERROR || col1 == NULL)
3809  {
3810  return ER_FAILED;
3811  }
3812  error = set_get_setobj (collection2, &col2, 0);
3813  if (error != NO_ERROR || col2 == NULL)
3814  {
3815  return ER_FAILED;
3816  }
3817 
3818 #if !defined(SERVER_MODE)
3819  pin1 = ws_pin (collection1->owner, 1);
3820  pin2 = ws_pin (collection2->owner, 1);
3821 #endif
3822 
3823  /* build result in the correct domain */
3824  *result = set_create_with_domain (domain, 0);
3825  if (*result == NULL)
3826  {
3827  assert (er_errid () != NO_ERROR);
3828  error = er_errid ();
3829  goto error_exit;
3830  }
3831 
3832  /* if the result type is a set type, we must have both arguments coerced to a set type so we can count on ascending
3833  * value order */
3834  if (col1->coltype != DB_TYPE_SET && col1->coltype != DB_TYPE_MULTISET
3835  && (TP_DOMAIN_TYPE (domain) == DB_TYPE_SET || TP_DOMAIN_TYPE (domain) == DB_TYPE_MULTISET))
3836  {
3837  col1 = setobj_coerce (col1, domain, IMPLICIT);
3838  if (!col1)
3839  {
3840  assert (er_errid () != NO_ERROR);
3841  error = er_errid ();
3842  goto error_exit;
3843  }
3844  }
3845 
3846  if (col2->coltype != DB_TYPE_SET && col2->coltype != DB_TYPE_MULTISET
3847  && (TP_DOMAIN_TYPE (domain) == DB_TYPE_SET || TP_DOMAIN_TYPE (domain) == DB_TYPE_MULTISET))
3848  {
3849  /* we have a slightly weaker test for differences second argument than complete domain compatibility. It is
3850  * sufficient to coerce it to a multiset. */
3851  col2 = setobj_coerce (col2, op == setobj_difference ? &tp_Multiset_domain : domain, IMPLICIT);
3852  if (!col2)
3853  {
3854  assert (er_errid () != NO_ERROR);
3855  error = er_errid ();
3856  goto error_exit;
3857  }
3858  }
3859  /* At this point, we know we have two sorted collections. and a result of the correct domain. */
3860 
3861  error = (*op) (col1, col2, (*result)->set);
3862 
3863 error_exit:
3864 #if !defined(SERVER_MODE)
3865  (void) ws_pin (collection1->owner, pin1);
3866  (void) ws_pin (collection2->owner, pin2);
3867 #endif
3868 
3869  /* check to see if we had to coerce (copy) the input argumanets. If so, free them. */
3870  if (col1 != collection1->set)
3871  {
3872  setobj_free (col1);
3873  }
3874  if (col2 != collection2->set)
3875  {
3876  setobj_free (col2);
3877  }
3878  if (error < 0 && *result)
3879  {
3880  set_free (*result);
3881  *result = NULL;
3882  }
3883  return error;
3884 }
3885 
3886 
3887 /*
3888  * set_difference() -
3889  * return: error code
3890  * collection1(in) : input collections
3891  * collection2(in) : input collections
3892  * result(in) : output set or multiset
3893  * domain(in) : desired result domain
3894  * op(in) :
3895  *
3896  * Note :
3897  * takes the set difference of two collections
3898  * If either argument is a sequence, it is
3899  * first corced to the result domain, which must be
3900  * a multiset or set.
3901  *
3902  */
3903 
3904 int
3905 set_difference (DB_COLLECTION * collection1, DB_COLLECTION * collection2, DB_COLLECTION ** result, DB_DOMAIN * domain)
3906 {
3907  return set_op (collection1, collection2, result, domain, setobj_difference);
3908 }
3909 
3910 /*
3911  * set_union() -
3912  * return: error code
3913  * collection1(in) : input collections
3914  * collection2(in) : input collections
3915  * result(in) : output set or multiset
3916  * domain(in) : desired result domain
3917  * op(in) :
3918  *
3919  * Note :
3920  * takes the set difference of two collections
3921  * If either argument is a sequence, it is
3922  * first corced to the result domain, which must be
3923  * a multiset or set.
3924  *
3925  */
3926 
3927 int
3928 set_union (DB_COLLECTION * collection1, DB_COLLECTION * collection2, DB_COLLECTION ** result, DB_DOMAIN * domain)
3929 {
3930  return set_op (collection1, collection2, result, domain, setobj_union);
3931 }
3932 
3933 /*
3934  * set_intersection() -
3935  * return: error code
3936  * collection1(in) : input collections
3937  * collection2(in) : input collections
3938  * result(in) : output set or multiset
3939  * domain(in) : desired result domain
3940  * op(in) :
3941  *
3942  * Note :
3943  * takes the set difference of two collections
3944  * If either argument is a sequence, it is
3945  * first corced to the result domain, which must be
3946  * a multiset or set.
3947  *
3948  */
3949 
3950 int
3951 set_intersection (DB_COLLECTION * collection1, DB_COLLECTION * collection2, DB_COLLECTION ** result, DB_DOMAIN * domain)
3952 {
3953  return set_op (collection1, collection2, result, domain, setobj_intersection);
3954 }
3955 
3956 /*
3957  * set_make_collection() -
3958  * return: none
3959  * value(in) :
3960  * col(in) :
3961  *
3962  */
3963 
3964 void
3966 {
3967  if (value && col)
3968  {
3969  value->domain.general_info.type = setobj_type (col->set);
3970  value->data.set = col;
3971  value->domain.general_info.is_null = 0;
3972  }
3973 }
3974 
3975 /*
3976  * set_new_element() - This is an internal function, intended for use
3977  * currently only by loaddb
3978  * return: internal DB_VALUE pointer
3979  * ref(in) : set to groe
3980  *
3981  * Note :
3982  *
3983  * It will add a new element to a set or multiset and return a pointer
3984  * to the DB_VALUE that was added. This allows the set to grow
3985  * and the value can be filled in later. This may not be necessary but
3986  * loaddb is currently structured this way due to its old use of the
3987  * DESC_SET structures which are now gone. Possibly could change this
3988  * to find out the value first and then call the usual set_add() function
3989  * but this is easiest for now.
3990  *
3991  * It is the same as adding a new NULL element to the end of the set,
3992  * note that if this is a set, rather than a multiset, this may result
3993  * in an error. It would seem that loaddb does not check for
3994  * duplicates in sets that it populates, true ?
3995  *
3996  * -bk Ditto. As near as I can tell, this will allow construction of
3997  * invalid sets
3998  */
3999 
4000 DB_VALUE *
4002 {
4003  COL *col;
4004  int error = NO_ERROR;
4005 #if !defined(SERVER_MODE)
4006  int pin;
4007 #endif /* !SERVER_MODE */
4008  DB_VALUE *new_ = NULL;
4009 
4010  error = set_get_setobj (ref, &col, 1);
4011  if (error != NO_ERROR)
4012  {
4013  return new_;
4014  }
4015  if (ref == NULL || col == NULL)
4016  {
4017  return new_;
4018  }
4019 #if !defined(SERVER_MODE)
4020  pin = ws_pin (ref->owner, 1);
4021 #endif
4022  /* adds one element to collection by expanding to new index */
4023  /* note: indexes run from 0 to size - 1 */
4024  col_expand (col, col->size);
4025  new_ = INDEX (col, col->size - 1);
4026 #if !defined(SERVER_MODE)
4027  (void) ws_pin (ref->owner, pin);
4028 #endif
4029 
4030  return new_;
4031 }
4032 
4033 /*
4034  * set_optimize() -
4035  * return: error code
4036  * ref(in) :
4037  *
4038  * Note :
4039  * Hack introduced to offset the fact that sets containing temporary OIDs
4040  * end up unsorted and if nothing is done to correct this,
4041  * we sort them every time the set gets loaded from disk.
4042  *
4043  * If the set contains any temporaty OIDs we will force them to become
4044  * permanent using the new bulk OID assigner. After that, we then re-sort
4045  * the set to order it according to the permanent OIDs.
4046  */
4047 
4048 int
4050 {
4051 #ifdef SERVER_MODE
4052  return NO_ERROR;
4053 #else
4054  int error;
4055  COL *col;
4056  int pin;
4057 
4058  error = NO_ERROR;
4059 
4060  /* If the set is decached, then its too late, it will already have been flushed. If its in the workspace, then we
4061  * only need to do something if this is an unsorted set or multiset. */
4062  if (ref && ref->set != NULL && !ref->set->sorted)
4063  {
4064 
4065  /* Might want to avoid marking the object dirty if there's nothing we can do with the set. */
4066  error = set_get_setobj (ref, &col, 1);
4067  if (error != NO_ERROR)
4068  {
4069  return error;
4070  }
4071  if (ref == NULL || col == NULL)
4072  {
4073  return error;
4074  }
4075  pin = ws_pin (ref->owner, 1);
4076 
4077  error = setobj_sort (col);
4078 
4079  (void) ws_pin (ref->owner, pin);
4080 
4081  }
4082  return error;
4083 #endif
4084 }
4085 
4086 /* SET ITERATORS */
4087 /*
4088  * This is something new, added initially only to support some of the
4089  * migration utilities but can be generalized to be used in more places.
4090  * I've been wanting to do something like this for some time.
4091  * This allows you to iterate over the elements of a set, quickly, without
4092  * worring about the physical representation of the set.
4093  * This should be the preferred way to perform iterations, internally at
4094  * least and possibly through the API as well.
4095  *
4096  * This isn't general enough yet, in particular it needs to be able to
4097  * understand multiple iterator state on the set and allow the
4098  * iteration state to become invalid if the set changes.
4099  *
4100  */
4101 
4102 /*
4103  * make_iterator() -
4104  * return: SET_ITERATOR *
4105  *
4106  */
4107 
4108 static SET_ITERATOR *
4110 {
4111  SET_ITERATOR *it;
4112 
4113  it = (SET_ITERATOR *) db_private_alloc (NULL, sizeof (SET_ITERATOR));
4114  if (it != NULL)
4115  {
4116  it->next = NULL;
4117  it->set = NULL;
4118  it->position = 0;
4119  it->value = NULL;
4120  it->element = NULL;
4121  }
4122  return it;
4123 }
4124 
4125 /*
4126  * free_iterator() -
4127  * return: none
4128  * it(in) :
4129  *
4130  */
4131 
4132 static void
4134 {
4136 }
4137 
4138 /*
4139  * set_iterate() -
4140  * return: SET_ITERATOR *
4141  * set(in) :
4142  *
4143  */
4144 
4145 SET_ITERATOR *
4147 {
4148  SET_ITERATOR *it;
4149  int error = NO_ERROR;
4150 
4151  /* pain in the ass, can't iterate on attached objects yet until we figure out how to pin them reliably, and more
4152  * importantly, how to release the pin ! */
4153  if (set == NULL || set->owner != NULL)
4154  {
4156  return NULL;
4157  }
4158 
4159  it = make_iterator ();
4160  if (it == NULL)
4161  {
4162  return it;
4163  }
4164  it->ref = set;
4165  error = set_get_setobj (set, &it->set, 1);
4166  if (error != NO_ERROR || it->set == NULL)
4167  {
4169  free_iterator (it);
4170  return NULL;
4171  }
4172 
4173  if (it->set->size != 0)
4174  {
4175  it->value = INDEX (it->set, 0);
4176  }
4177  return it;
4178 }
4179 
4180 /*
4181  * set_iterator_free() -
4182  * return: none
4183  * it(in) :
4184  *
4185  */
4186 
4187 void
4189 {
4190  free_iterator (it);
4191 }
4192 
4193 /*
4194  * set_iterator_value() -
4195  * return: DB_VALUE *
4196  * it(in) :
4197  *
4198  */
4199 
4200 DB_VALUE *
4202 {
4203  if (it != NULL)
4204  {
4205  return it->value;
4206  }
4207  else
4208  {
4209  return NULL;
4210  }
4211 }
4212 
4213 #if defined(ENABLE_UNUSED_FUNCTION)
4214 /*
4215  * set_iterator_finished() -
4216  * return: int
4217  * it(in) :
4218  *
4219  */
4220 
4221 int
4222 set_iterator_finished (SET_ITERATOR * it)
4223 {
4224  return (it == NULL) || (it->value == NULL);
4225 }
4226 #endif /* ENABLE_UNUSED_FUNCTION */
4227 
4228 /*
4229  * set_iterator_next() -
4230  * return: int
4231  * it(in) :
4232  *
4233  */
4234 
4235 int
4237 {
4238  if (it == NULL || it->value == NULL)
4239  {
4240  return 0;
4241  }
4242 
4243  it->position++;
4244  if (it->position < setobj_size (it->set))
4245  {
4246  it->value = INDEX (it->set, it->position);
4247  }
4248  else
4249  {
4250  it->value = NULL;
4251  }
4252 
4253  return (it->value != NULL);
4254 }
4255 
4256 /*
4257  * setobj_create_with_domain() - This creates a set of the appropriate type
4258  * and assigns it an initial domain
4259  * return: new set, multiset, or sequence
4260  * domain(in) : desired domain
4261  * initial_size(in) : starting size for sequences, ignored otherwise
4262  *
4263  * Note :
4264  * If NULL is returned, an error condition will have been set
4265  */
4266 
4267 COL *
4268 setobj_create_with_domain (TP_DOMAIN * domain, int initial_size)
4269 {
4270  COL *new_ = NULL;
4271 
4272  new_ = setobj_create (TP_DOMAIN_TYPE (domain), initial_size);
4273  if (new_ != NULL)
4274  {
4275  new_->domain = domain;
4276  }
4277  return (new_);
4278 }
4279 
4280 /*
4281  * setobj_create() - create a collectio object, or sets an error
4282  * return: COL *
4283  * collection_type(in) : what kind of collection
4284  * size(in) : initial size of the sequence
4285  *
4286  */
4287 
4288 COL *
4289 setobj_create (DB_TYPE collection_type, int size)
4290 {
4291  if (!TP_IS_SET_TYPE (collection_type) && collection_type != DB_TYPE_VOBJ)
4292  {
4294  return (NULL);
4295  }
4296  return col_new (size, collection_type);
4297 }
4298 
4299 /*
4300  * setobj_clear() - Remove all elements from a set
4301  * return: none
4302  * col(in) : collection object
4303  *
4304  */
4305 
4306 void
4308 {
4309  int i;
4310 
4311  if (col == NULL)
4312  {
4313  return;
4314  }
4315 
4316  for (i = 0; i < col->size; i++)
4317  {
4318  (void) pr_clear_value (INDEX (col, i));
4319  }
4320  for (i = 0; i <= col->topblock; i++)
4321  {
4322  set_free_block (col->array[i]);
4323  col->array[i] = NULL;
4324  }
4325  col->topblock = -1;
4326  col->topblockcount = -1;
4327  col->size = 0;
4328 }
4329 
4330 /*
4331  * setobj_free() - Free a set object and all of its elements
4332  * return: none
4333  * col(in) : collection object
4334  *
4335  */
4336 
4337 void
4339 {
4340  DB_COLLECTION *start, *r;
4341 
4342  if (col == NULL)
4343  {
4344  return;
4345  }
4346  setobj_clear (col);
4347 
4348  if (col->array != NULL)
4349  {
4351  col->array = NULL;
4352  }
4353 
4354  start = r = col->references;
4355  if (start)
4356  {
4357  do
4358  {
4359  r->set = NULL;
4360  r = r->ref_link;
4361  }
4362  while (r != start);
4363  }
4364 
4365  (void) area_free (Set_Obj_Area, col);
4366 }
4367 
4368 /*
4369  * setobj_copy() - Copy a set object and all of its elements
4370  * return: new set
4371  * col(in) : collection object
4372  *
4373  */
4374 
4375 COL *
4377 {
4378  COL *new_;
4379  int i;
4380  int error;
4381 
4382  if (col == NULL)
4383  {
4385  return (NULL);
4386  }
4387 
4388  new_ = col_new (col->size, col->coltype);
4389  if (new_ == NULL)
4390  {
4391  return (NULL);
4392  }
4393 
4394  /* must retain this ! */
4395  new_->sorted = col->sorted;
4397 
4398  if (new_ != NULL)
4399  {
4400  error = col_expand (new_, col->size - 1);
4401  if (error < 0)
4402  {
4403  setobj_free (new_);
4404  new_ = NULL;
4405  }
4406  }
4407 
4408  if (new_ == NULL)
4409  {
4410  return new_;
4411  }
4412 
4413  for (i = 0; i < col->size && new_; i++)
4414  {
4415  error = pr_clone_value (INDEX (col, i), INDEX (new_, i));
4416  if (error < 0)
4417  {
4418  setobj_free (new_);
4419  new_ = NULL;
4420  }
4421  }
4422  return (new_);
4423 }
4424 
4425 /*
4426  * setobj_sort() - Destructively sorts a collection
4427  * return: error status
4428  * col(in) : collection to sort
4429  * Note :
4430  * Used in the implementation of set_optimize but might be useful in
4431  * other circumstances.
4432  *
4433  */
4434 
4435 
4436 int
4438 {
4439  int error = NO_ERROR;
4440 
4441  /* if this is a sequence or already sorted, there's nothing to do */
4442  if (!col || col->sorted)
4443  {
4444  return NO_ERROR;
4445  }
4446 
4447  if (col->coltype != DB_TYPE_SET && col->coltype != DB_TYPE_MULTISET)
4448  {
4449  col->sorted = 1;
4450  return NO_ERROR;
4451  }
4452 
4453  error = col_permanent_oids (col);
4454 
4455  if (error >= 0)
4456  {
4457  error = col_sort (col);
4458  }
4459 
4460  return error;
4461 }
4462 
4463 
4464 #if !defined(SERVER_MODE)
4465 #if defined(ENABLE_UNUSED_FUNCTION)
4466 /*
4467  * setobj_find_temporary_oids() -
4468  * return: error
4469  * col(in) : collection
4470  * oidset(in) : oidset to populate
4471  *
4472  * Note :
4473  * This maps over the collection looking for temporary OIDs and when
4474  * found, adds them to the oidset. This is a recursive operation that
4475  * will handle nested collections.
4476  * It is intended to be used by tf_find_temporary_oids and perhaps others,
4477  * it is by definition a client only function.
4478  */
4479 
4480 int
4481 setobj_find_temporary_oids (setobj * col, LC_OIDSET * oidset)
4482 {
4483  int error;
4484  DB_VALUE *val;
4485  DB_TYPE type;
4486  DB_OBJECT *obj;
4487  SETREF *ref;
4488  int i, tempoids;
4489 
4490  error = NO_ERROR;
4491 
4492  /* Can this collection have any temporary OIDs in it ? */
4493  if (col && col->may_have_temporary_oids)
4494  {
4495 
4496  tempoids = 0;
4497  for (i = 0; i < col->size && !error; i++)
4498  {
4499  val = INDEX (col, i);
4500  type = DB_VALUE_TYPE (val);
4501  if (type == DB_TYPE_OBJECT)
4502  {
4503  obj = db_get_object (val);
4504  if (obj != NULL && OBJECT_HAS_TEMP_OID (obj))
4505  {
4506  tempoids++;
4507  if (locator_add_oidset_object (oidset, obj) == NULL)
4508  {
4509  assert (er_errid () != NO_ERROR);
4510  error = er_errid ();
4511  }
4512  }
4513  }
4514  else if (TP_IS_SET_TYPE (type))
4515  {
4516  /* its a nested set, recurse, since we must already be pinned don't have to worry about pinning the
4517  * nested set. */
4518  ref = db_get_set (val);
4519  if (ref && ref->set != NULL)
4520  {
4521  error = setobj_find_temporary_oids (ref->set, oidset);
4522  if (ref->set->may_have_temporary_oids)
4523  {
4524  tempoids++;
4525  }
4526  }
4527  }
4528  }
4529 
4530  /* if we made it through a traversal and didn't encounter any temporary oids, then we can turn this flag off. */
4531  if (tempoids == 0)
4532  {
4533  col->may_have_temporary_oids = 0;
4534  }
4535  }
4536 
4537  return error;
4538 }
4539 #endif /* ENABLE_UNUSED_FUNCTION */
4540 #endif /* !SERVER_MODE */
4541 
4542 /* SET DOMAIN MAINTENANCE */
4543 /*
4544  * setobj_check_domain() -
4545  * return: error code
4546  * col(in) : collection object
4547  * domain(in) : domain structure
4548  * Note:
4549  * This is used to see if the contents of a set conforms to a particular
4550  * domain specification.
4551  * It calls tp_domain_check to do the work, basically this only
4552  * provides the infrastructure to map over the set elements.
4553  *
4554  * Note that we use "exact" matches on the set elements here rather than
4555  * tolerance matches. This is because the "setval" function used to
4556  * assign the element values does not have enough information to perform
4557  * deferred coercion (for the CHAR) types and we will have to perform
4558  * coercion to make sure that the set gets re-formatted exactly like
4559  * its domain wants. This isn't especially effecient but optimizing
4560  * set copying is going to require a rather long look at the life of
4561  * set literals.
4562  *
4563  * This is only called from tp_value_select which is used to check
4564  * to see if coercion is necessary. Think about cleaning up the
4565  * various coercion checking logic we have scattered about.
4566  *
4567  */
4568 
4571 {
4572  TP_DOMAIN_STATUS status;
4573  int i;
4574 
4575  status = DOMAIN_COMPATIBLE;
4576 
4577  /* if any of these conditions are true, the domains are compatible */
4578  /* -bk, I don't understand the above comment. Presumably "false" is meant, since the code will return compatible if
4579  * any of the tests is false. However, that appears to be broken as well, since a NULL domain by no means guarantees
4580  * compatibility. Perhaps this should start with setobj_get_domain? Anyway, I'm not so sure of this to change the
4581  * logic now, and am leaving the test as I found it. */
4582  if (col->domain != NULL && col->domain != domain && !tp_domain_compatible (col->domain, domain))
4583  {
4584 
4585  /* couldn't do it simply, have to look at each element */
4586  for (i = 0; i < col->size && status == DOMAIN_COMPATIBLE; i++)
4587  {
4588  status = tp_domain_check (domain->setdomain, INDEX (col, i), TP_EXACT_MATCH);
4589  }
4590  }
4591 
4592  return status;
4593 }
4594 
4595 /*
4596  * setobj_get_domain() - This is used to get a description of a set's domain
4597  * return: copy of the set's domain
4598  * set(in) : collection object
4599  * Note :
4600  * If NULL is returned, it indicates a memory allocation failure
4601  * or an access failure on the owning object.
4602  */
4603 
4604 TP_DOMAIN *
4606 {
4607  if (set->domain != NULL)
4608  {
4609  return set->domain;
4610  }
4611  /* Set without an owner and without a domain, this isn't supposed to happen any more. Slam in one of the built-in
4612  * domains. */
4613  switch (set->coltype)
4614  {
4615  case DB_TYPE_SET:
4616  set->domain = &tp_Set_domain;
4617  break;
4618  case DB_TYPE_MULTISET:
4619  set->domain = &tp_Multiset_domain;
4620  break;
4621  case DB_TYPE_SEQUENCE:
4622  set->domain = &tp_Sequence_domain;
4623  break;
4624  case DB_TYPE_VOBJ:
4625  set->domain = &tp_Vobj_domain;
4626  break;
4627  default:
4628  /* what is it? must be a structure error */
4629  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SET_INVALID_DOMAIN, 1, "NULL set domain");
4630  break;
4631  }
4632 
4633  return set->domain;
4634 }
4635 
4636 /*
4637  * swizzle_value() - This converts a value containing an OID into one
4638  * containing a DB_OBJECT*
4639  * return: none
4640  * val(in) : value to convert
4641  * input(in) :
4642  * Note :
4643  * This process is commonly known in the literature as "swizzling" a
4644  * database pointer.
4645  * Note that this does not change the "domain" of a value. DB_TYPE_OBJECT
4646  * and DB_TYPE_OID are used to tag two different physical representations
4647  * of the same domain. DB_TYPE_OBJECT is a domain type, DB_TYPE_OID is
4648  * not, though it carries a lot of the same type handler baggage.
4649  *
4650  * With the set_ module, this is called as objects are put into the set,
4651  * and as objects are extracted from the set.
4652  * Note that the lowest level set builders bypass swizzling so sets
4653  * can always have DB_TYPE_OID elements in them if they haven't
4654  * been touched by set_get_element() or some other function that
4655  * maps over the set elements.
4656  */
4657 
4658 void
4660 {
4661  OID *oid;
4662 
4663 
4664  if (DB_VALUE_TYPE (val) != DB_TYPE_OID)
4665  {
4666  return;
4667  }
4668  /* We always convert incoming "NULL oid" references into a NULL value. This makes set elements consistent with OIDs
4669  * assigned to attribute values and is very important for proper comparison of VOBJ sets. */
4670  oid = db_get_oid (val);
4671  if (oid == NULL)
4672  {
4673  return;
4674  }
4675 
4676  if ((oid)->pageid == NULL_PAGEID)
4677  {
4678  db_value_put_null (val);
4679  }
4680  else
4681  {
4682 #if !defined(SERVER_MODE)
4683  /* If we're on the client, and this is a value being extracted, convert it to a DB_OBJECT* reference. We could do
4684  * this on input too in order to get better type checking. Since this only happens in the internal functions for
4685  * building VOBJ sequences and those sequences have the wildcard domain, we don't really need to swizzle the OIDs
4686  * or do type checking. */
4687  if (!db_on_server && !input)
4688  {
4689  DB_OBJECT *mop;
4690  mop = ws_mop (oid, NULL);
4692  db_make_object (val, mop);
4693  }
4694 #endif /* !SERVER_MODE */
4695  }
4696 }
4697 
4698 /*
4699  * assign_set_value() -
4700  * return: error code
4701  * set(in) : set containing element
4702  * src(in) : source value
4703  * dest(in) : destination value
4704  * implicit_coercion(in) :
4705  *
4706  * Note :
4707  * This is the main function the handles the assignment of values
4708  * into sets. All element assignment function will end up
4709  * here. This encapsulates the domain checking and coercion rules.
4710  * Note that for set assignment, setobj_ismember has already performed
4711  * the coercion yet we do it again here. It might be nice
4712  * to restructure this a bit to avoid the extra coercion.
4713  */
4714 
4715 static int
4716 assign_set_value (COL * set, DB_VALUE * src, DB_VALUE * dest, bool implicit_coercion)
4717 {
4718 #if !defined (SERVER_MODE)
4719  int is_ref = 0;
4720 #endif /* !SERVER_MODE */
4721  int error = NO_ERROR;
4722  TP_DOMAIN_STATUS status;
4723  TP_DOMAIN *domain;
4724  DB_VALUE temp;
4725 
4726  /* On the client, always swizzle incoming OID's so we can properly check their domains. On the server, we'll have to
4727  * trust it until tp_domain_check understands how to do domain verification using just OIDs. Do this into a temp
4728  * buffer so we can leave the input value constant. This will only change for OID-OBJECT conversion which don't have
4729  * to be freed. */
4730  temp = *src;
4731  swizzle_value (&temp, 1);
4732 
4733 #if !defined(SERVER_MODE)
4734  is_ref = pt_is_reference_to_reusable_oid (&temp);
4735  if (is_ref < 0)
4736  {
4737  return is_ref;
4738  }
4739  if (is_ref > 0)
4740  {
4743  }
4744 #endif
4745 
4746  domain = setobj_get_domain (set);
4747 
4748  /* quickly handle the wildcard cases */
4749  if (domain == NULL || domain->setdomain == NULL)
4750  {
4751  error = pr_clone_value (&temp, dest);
4752  }
4753  else
4754  {
4755  /* Request an exact match so we know if there is any coercion to be performed. This is especially important for
4756  * set elements since we use "setval" to assign the value and this doesn't have enough information to perform
4757  * deferred coercion if that's what we need. */
4758  status = tp_domain_check (domain->setdomain, &temp, TP_EXACT_MATCH);
4759  if (status == DOMAIN_COMPATIBLE)
4760  {
4761  error = pr_clone_value (&temp, dest);
4762  }
4763  else
4764  {
4765  /* try coercion */
4766  status = tp_value_cast (&temp, dest, domain->setdomain, implicit_coercion);
4767  if (status != DOMAIN_COMPATIBLE)
4768  {
4769  /* handle all non-compatible states as a domain failure */
4770  error = ER_SET_DOMAIN_CONFLICT;
4772  }
4773  }
4774  }
4775  return (error);
4776 }
4777 
4778 /* INTERNAL SET UTILITIES */
4779 
4780 /*
4781  * check_set_object() -
4782  * return: non-zero if the element was deleted
4783  * var(in) : value container to check
4784  * removed_ptr(in) :
4785  * Note :
4786  * This checks a set element value to see if it contains a reference
4787  * to an object that has been deleted. If the object has been deleted,
4788  * the set element is changed to NULL.
4789  * This is rather ugly and expensive, not sure it should always be the
4790  * responsibility of sets to detect these references.
4791  *
4792  */
4793 
4794 static int
4795 check_set_object (DB_VALUE * var, int *removed_ptr)
4796 {
4797  int error = NO_ERROR;
4798  int removed = 0;
4799 #if !defined(SERVER_MODE)
4800  MOP mop;
4801  int status;
4802 
4803  if (db_on_server)
4804  {
4805  goto end;
4806  }
4807  swizzle_value (var, 0);
4808 
4809  if (DB_VALUE_TYPE (var) != DB_TYPE_OBJECT)
4810  {
4811  goto end;
4812  }
4813  mop = db_get_object (var);
4814  if (mop == NULL)
4815  {
4816  goto end;
4817  }
4818 
4819  if (!WS_IS_DELETED (mop))
4820  {
4821  if (mop->is_vid)
4822  {
4824  if (error != NO_ERROR)
4825  {
4826  WS_SET_DELETED (mop);
4827  }
4828  }
4829  else
4830  {
4831  status = locator_does_exist_object (mop, DB_FETCH_READ);
4832  if (status == LC_DOESNOT_EXIST)
4833  {
4834  WS_SET_DELETED (mop);
4835  }
4836  else if (status == LC_ERROR)
4837  {
4838  ASSERT_ERROR_AND_SET (error);
4839  }
4840  }
4841  goto end;
4842  }
4843 
4844  removed = 1;
4845  db_make_null (var);
4846 
4847 end:
4848 #endif /* !SERVER_MODE */
4849 
4850  if (error == NO_ERROR && removed_ptr != NULL)
4851  {
4852  *removed_ptr = removed;
4853  }
4854 
4855  return (error);
4856 }
4857 
4858 /*
4859  * setobj_filter()
4860  * return: error code
4861  * col(in) : set to filter
4862  * filter(in) : non-zero if elements are to be filtered
4863  * cardptr(out) : cardinality variable pointer (returned)
4864  *
4865  * Note :
4866  * This function can be used for two purposes.
4867  * If the filter flag is zero, it calculates the cardinality of the
4868  * set by counting the number of non-NULL elements.
4869  * If the filter flag is non-zero it calculates the cardinality AND
4870  * filters out pointers to deleted objects.
4871  */
4872 
4873 int
4874 setobj_filter (COL * col, int filter, int *cardptr)
4875 {
4876  int error = NO_ERROR;
4877  DB_VALUE *var;
4878  int i, card, removed = 0;
4879 
4880  card = 0;
4881 
4882  /* We need to loop backwards here since we may be deleting values and everything after that value will be shift down
4883  * one index */
4884  for (i = col->size - 1; i >= 0; i--)
4885  {
4886  var = INDEX (col, i);
4887  if (filter)
4888  {
4889  swizzle_value (var, 0);
4890  }
4891  if (filter && DB_VALUE_TYPE (var) == DB_TYPE_OBJECT)
4892  {
4893  error = check_set_object (var, &removed);
4894  if (error < 0)
4895  {
4896  break;
4897  }
4898  if (!removed)
4899  {
4900  card++;
4901  }
4902  else
4903  {
4904  if (col->coltype != DB_TYPE_SEQUENCE)
4905  {
4906  col_delete (col, i);
4907  }
4908  }
4909  }
4910  else if (!db_value_is_null (var))
4911  {
4912  card++;
4913  }
4914  }
4915  if (cardptr == NULL)
4916  {
4917  return error;
4918  }
4919 
4920  if (error < 0)
4921  {
4922  *cardptr = 0;
4923  }
4924  else
4925  {
4926  *cardptr = card;
4927  }
4928  return (error);
4929 }
4930 
4931 /* SET INFORMATION FUNCTIONS */
4932 
4933 /*
4934  * setobj_size() - This returns the number of elements in a set
4935  * return: number of elements in the set
4936  * col(in) : collection object
4937  * Note :
4938  * For sets and multisets, this is the length of the element list and
4939  * does not include checking for NULL elements or filtering out
4940  * deleted references.
4941  * For sequences, this is the length of the used portion of the array.
4942  * This should not be used as the iteration count for sets and multi
4943  * sets. This should be used for the iteration counts of sequences since
4944  * elements can legally be NULL.
4945  */
4946 
4947 int
4949 {
4950  if (col == NULL)
4951  {
4953  return (ER_OBJ_INVALID_ARGUMENTS);
4954  }
4955 
4956  return col->size;
4957 }
4958 
4959 /*
4960  * setobj_cardinality() - This returns the number of non-null elements in a set
4961  * return: number of non-null elements
4962  * col(in) : collection object
4963  *
4964  * Note :
4965  * This should be used as the length for iterating over sets and multi sets.
4966  * This should NOT be used for iterating over sequences.
4967  */
4968 
4969 int
4971 {
4972  int error;
4973  int card;
4974 
4975  if (col == NULL)
4976  {
4978  return (ER_OBJ_INVALID_ARGUMENTS);
4979  }
4980 
4981  error = setobj_filter (col, 0, &card);
4982  /* should be passing the error back up ! */
4983 
4984  return (card);
4985 }
4986 
4987 /*
4988  * setobj_isempty() - Returns the number of elements, including null elements,
4989  * in the collection
4990  * return: non-zero if the set is empty
4991  * col(in) : collection object
4992  *
4993  */
4994 
4995 bool
4997 {
4998  if (setobj_size (col) == 0)
4999  {
5000  return true;
5001  }
5002  else
5003  {
5004  return false;
5005  }
5006 }
5007 
5008 /*
5009  * setobj_ismember() - Check to see if a value is in a set
5010  * return: non-zero of the value was found in the set
5011  * col(in) : set object
5012  * proposed_value(in) : value to search for
5013  * check_null(in) : non-zero if we want to perform true comparisons on NULL
5014  *
5015  * Note :
5016  * Checks up front to see if the value is within the domain of the set
5017  * before searching.
5018  *
5019  */
5020 
5021 bool
5022 setobj_ismember (COL * col, DB_VALUE * proposed_value, int check_null)
5023 {
5024  DB_VALUE coerced_value, *value;
5025  DB_DOMAIN *domain;
5026  TP_DOMAIN_STATUS status;
5027  long found, coerce;
5028 
5029  /* guard against bad arguments. No error return possible */
5030  if (!col || !proposed_value)
5031  {
5032  return false;
5033  }
5034 
5035  if (DB_IS_NULL (proposed_value))
5036  {
5037  /* handle NULL quickly */
5038  if (!check_null)
5039  {
5040  return false;
5041  }
5042  else
5043  {
5044  return col_has_null (col);
5045  }
5046  }
5047 
5048  found = false;
5049  value = proposed_value;
5050  domain = setobj_get_domain (col);
5051 
5052  /* validate the value against the domain of the col, coerce if necessary */
5053  if (domain && domain->setdomain != NULL)
5054  {
5055  status = tp_domain_check (domain->setdomain, value, TP_EXACT_MATCH);
5056  if (status != DOMAIN_COMPATIBLE)
5057  {
5058  value = &coerced_value;
5059  status = tp_value_coerce (proposed_value, value, domain->setdomain);
5060  if (status != DOMAIN_COMPATIBLE)
5061  {
5062  return false;
5063  }
5064  }
5065  }
5066 
5067 
5068  if (domain && domain->setdomain && !domain->setdomain->next)
5069  {
5070  /* exactly one domain, no need to coerce */
5071  coerce = 0;
5072  }
5073  else
5074  {
5075  /* unknown or multiple domains */
5076  coerce = 1;
5077  }
5078 
5079  if (!col->sorted)
5080  {
5081  (void) setobj_sort (col);
5082  }
5083 
5084  (void) col_find (col, &found, value, coerce);
5085 
5086  if (found > 0)
5087  {
5088  return true;
5089  }
5090 
5091  return false;
5092 }
5093 
5094 /*
5095  * setobj_compare()
5096  * return: DB_SUBSET if set1 is a strict subset of set2,
5097  * DB_SUPERSET if set1 is a strict superset of set2
5098  * DB_EQ if set1 and set2 are equal
5099  * DB_NE if they are not equal and not subsets
5100  * DB_UNK if the result is unknown
5101  * set1(in) : set object
5102  * set2(in) : set object
5103  * db_coercion(in) :
5104  *
5105  * Note :
5106  * set1 and set2 to be of a set or multiset type.
5107  */
5109 setobj_compare (COL * set1, COL * set2, int do_coercion)
5110 {
5111  DB_VALUE_COMPARE_RESULT status, rc;
5112  long set1_could_be_subset, set2_could_be_subset;
5113  long index1, index2;
5114  int error = NO_ERROR;
5115 
5116  if (set1 == NULL || set2 == NULL)
5117  {
5118  assert_release (false);
5119  return DB_UNK;
5120  }
5121 
5122  status = DB_EQ;
5123  if (set1->size > 0 || set2->size > 0)
5124  {
5125  if (set1->size == 0)
5126  {
5127  status = DB_SUBSET;
5128  }
5129  else if (set2->size == 0)
5130  {
5131  status = DB_SUPERSET;
5132  }
5133  else
5134  {
5135  /* next, guarantee sorted preconditions. */
5136  if (!set1->sorted)
5137  {
5138  error = setobj_sort (set1);
5139  }
5140  if (!error && !set2->sorted)
5141  {
5142  error = setobj_sort (set2);
5143  }
5144 
5145  if (error < 0)
5146  {
5147  status = DB_UNK;
5148  }
5149  else
5150  {
5151  set1_could_be_subset = 1;
5152  set2_could_be_subset = 1;
5153  index1 = 0;
5154  index2 = 0;
5155  while (index1 < set1->size && index2 < set2->size && (set1_could_be_subset || set2_could_be_subset)
5156  && status == DB_EQ)
5157  {
5158  rc = tp_value_compare (INDEX (set1, index1), INDEX (set2, index2), do_coercion, 0);
5159  switch (rc)
5160  {
5161  case DB_EQ: /* element appears in both sets */
5162  index1++;
5163  index2++;
5164  break;
5165  case DB_LT: /* element of first set not in second */
5166  index1++;
5167  set1_could_be_subset = 0;
5168  break;
5169  case DB_GT: /* element of second set not in first */
5170  index2++;
5171  set2_could_be_subset = 0;
5172  break;
5173  case DB_UNK: /* a NULL encountered (also unexpected results) */
5174  default:
5175  status = DB_UNK;
5176  break;
5177  }
5178  }
5179  if (index1 < set1->size)
5180  {
5181  /* set1 contains some elements greater than any in set2 */
5182  set1_could_be_subset = 0;
5183  }
5184  if (index2 < set2->size)
5185  {
5186  /* set2 contains some elements greater than any in set1 */
5187  set2_could_be_subset = 0;
5188  }
5189  if (status == DB_EQ)
5190  {
5191  /* test subset eligibilty */
5192  if (set1_could_be_subset && set2_could_be_subset)
5193  {
5194  status = DB_EQ;
5195  }
5196  else if (set1_could_be_subset)
5197  {
5198  status = DB_SUBSET;
5199  }
5200  else if (set2_could_be_subset)
5201  {
5202  status = DB_SUPERSET;
5203  }
5204  else
5205  {
5206  status = DB_NE;
5207  }
5208  }
5209  }
5210  }
5211  }
5212 
5213  return status;
5214 }
5215 
5216 /*
5217  * setobj_compare_order() - Compare the values of the sets to deteremine
5218  * their order. If total order is asked for,
5219  * DB_UNK will not be returned
5220  * return: DB_EQ, DB_LT, DB_GT, DB_UNK
5221  * set1(in) : set object
5222  * set2(in) : set object
5223  * do_coercion(in) :
5224  * total_order(in) :
5225  *
5226  */
5228 setobj_compare_order (COL * set1, COL * set2, int do_coercion, int total_order)
5229 {
5231  int i;
5232  int error = NO_ERROR;
5233 
5234  if (set1->size < set2->size)
5235  {
5236  return DB_LT;
5237  }
5238  else if (set1->size > set2->size)
5239  {
5240  return DB_GT;
5241  }
5242 
5243  if (set1 == set2)
5244  {
5245  /* optimize comparison to self */
5246  if (total_order)
5247  {
5248  return DB_EQ;
5249  }
5250  if (col_has_null (set1))
5251  {
5252  return DB_UNK;
5253  }
5254  return DB_EQ;
5255  }
5256 
5257  /* guarantee sorted preconditions. */
5258  if (!set1->sorted)
5259  {
5260  error = setobj_sort (set1);
5261  }
5262  if (!error && !set2->sorted)
5263  {
5264  error = setobj_sort (set2);
5265  }
5266 
5267  if (error < 0)
5268  {
5269  return DB_UNK;
5270  }
5271 
5272  /* same size, compare elements until order is determined */
5273  for (i = 0; i < set1->size; i++)
5274  {
5275  rc = tp_value_compare (INDEX (set1, i), INDEX (set2, i), do_coercion, total_order);
5276  if (rc != DB_EQ)
5277  {
5278  return rc;
5279  }
5280  }
5281 
5282  return DB_EQ;
5283 }
5284 
5285 /*
5286  * setobj_difference() -
5287  * return: result which is the set difference (set1-set2)
5288  * set1(in) : set object
5289  * set2(in) : set objeccollection objectsult(in) : result set object
5290  *
5291  */
5292 
5293 int
5294 setobj_difference (COL * set1, COL * set2, COL * result)
5295 {
5296  int rc;
5297  int error = NO_ERROR;
5298  int index1, index2;
5299  DB_VALUE *val1, *val2;
5300 
5301  if (!set1->sorted)
5302  {
5303  error = setobj_sort (set1);
5304  }
5305  if (!error && !set2->sorted)
5306  {
5307  error = setobj_sort (set2);
5308  }
5309 
5310  /* compare elements in ascending order */
5311  index1 = 0;
5312  index2 = 0;
5313  while (index1 < set1->size && index2 < set2->size && !(error < NO_ERROR))
5314  {
5315  val1 = INDEX (set1, index1);
5316  val2 = INDEX (set2, index2);
5317  if (DB_IS_NULL (val1) || DB_IS_NULL (val2))
5318  {
5319  error = setobj_add_element (result, val1);
5320  index1++;
5321  }
5322  else
5323  {
5324  rc = tp_value_compare (val1, val2, 1, 0);
5325 
5326  switch (rc)
5327  {
5328  case DB_EQ: /* element appears in both sets */
5329  index1++; /* should NOT be in result */
5330  index2++;
5331  break;
5332  case DB_GT: /* element of second set not in first */
5333  index2++; /* should NOT be in result */
5334  break;
5335  case DB_LT: /* element of first set not in second */
5336  index1++; /* SHOULD be in result */
5337  error = setobj_add_element (result, val1);
5338  break;
5339  case DB_UNK: /* a NULL encountered (also unexpected results) */
5340  default: /* NULL's are not equal to nulls. so {NULL} - {NULL} is = {NULL} ie, the first value
5341  * result SHOULD be added to the result. */
5342  /* At least one of these must be a collection with an embedded NULL, we need to increment to the next
5343  * pair of values, but must check again to see which index to increase for total ordering. */
5344  rc = tp_value_compare (val1, val2, 1, 1);
5345  if (rc == DB_GT)
5346  {
5347  index2++;
5348  }
5349  else
5350  {
5351  index1++;
5352  error = setobj_add_element (result, val1);
5353  }
5354  }
5355  }
5356  }
5357  /* we have exhausted set1 or set2. Append the remains of set1 if any */
5358  while (index1 < set1->size && !(error < NO_ERROR))
5359  {
5360  val1 = INDEX (set1, index1);
5361  error = setobj_add_element (result, val1);
5362  index1++;
5363  }
5364  return error;
5365 }
5366 
5367 /*
5368  * setobj_union()
5369  * return: result which is the set union (set1 + set2)
5370  * set1(in) : set object
5371  * set2(in) : set object
5372  * result(in) : result set object
5373  *
5374  * Note :
5375  * Work through each set in ascending order. This
5376  * allows the result set to be built in ascending order,
5377  * without causing any insertions, which are more expensive
5378  * than appending.
5379  */
5380 
5381 int
5382 setobj_union (COL * set1, COL * set2, COL * result)
5383 {
5384  int rc;
5385  int error = NO_ERROR;
5386  int index1, index2;
5387  DB_VALUE *val1, *val2;
5388 
5389  if (!set1->sorted)
5390  {
5391  error = setobj_sort (set1);
5392  }
5393  if (!error && !set2->sorted)
5394  {
5395  error = setobj_sort (set2);
5396  }
5397 
5398  if (result->coltype == DB_TYPE_SEQUENCE)
5399  {
5400  /* append sequences */
5401  for (index1 = 0; index1 < set1->size && !(error < NO_ERROR); index1++)
5402  {
5403  val1 = INDEX (set1, index1);
5404  error = setobj_add_element (result, val1);
5405  }
5406  for (index2 = 0; index2 < set2->size && !(error < NO_ERROR); index2++)
5407  {
5408  val2 = INDEX (set2, index2);
5409  error = setobj_add_element (result, val2);
5410  }
5411  }
5412  else
5413  {
5414  /* compare elements in ascending order */
5415  index1 = 0;
5416  index2 = 0;
5417  while (index1 < set1->size && index2 < set2->size && !(error < NO_ERROR))
5418  {
5419  val1 = INDEX (set1, index1);
5420  val2 = INDEX (set2, index2);
5421  if (DB_IS_NULL (val1))
5422  {
5423  error = setobj_add_element (result, val1);
5424  index1++;
5425  }
5426  else if (DB_IS_NULL (val2))
5427  {
5428  error = setobj_add_element (result, val2);
5429  index2++;
5430  }
5431  else
5432  {
5433  rc = tp_value_compare (val1, val2, 1, 0);
5434 
5435  switch (rc)
5436  {
5437  case DB_UNK: /* a NULL encountered (also unexpected results) */
5438  default: /* NULL's are not equal to nulls. so {NULL} + {NULL} is = {NULL, NULL} even with sets.
5439  * ie. both should be added to the result. */
5440  case DB_EQ: /* element appears in both sets */
5441  index1++; /* both should be in result */
5442  index2++;
5443  error = setobj_add_element (result, val1);
5444  error = setobj_add_element (result, val2);
5445  break;
5446  case DB_GT: /* element of second set not in first */
5447  index2++; /* should be in result */
5448  error = setobj_add_element (result, val2);
5449  break;
5450  case DB_LT: /* element of first set not in second */
5451  index1++; /* SHOULD be in result */
5452  error = setobj_add_element (result, val1);
5453  break;
5454  }
5455  }
5456  }
5457  /* we have exhausted set1 or set2. Append the remains of set1 if any */
5458  while (index1 < set1->size && !(error < NO_ERROR))
5459  {
5460  val1 = INDEX (set1, index1);
5461  error = setobj_add_element (result, val1);
5462  index1++;
5463  }
5464  /* we have exhausted set1. Append the remains of set2 */
5465  while (index2 < set2->size && !(error < NO_ERROR))
5466  {
5467  val2 = INDEX (set2, index2);
5468  error = setobj_add_element (result, val2);
5469  index2++;
5470  }
5471  }
5472  return error;
5473 }
5474 
5475 /*
5476  * setobj_intersection() -
5477  * return: result which is the set intersection (set1*set2)
5478  * set1(in) : set object
5479  * set2(in) : set object
5480  * result(in) : result set object
5481  *
5482  */
5483 
5484 int
5485 setobj_intersection (COL * set1, COL * set2, COL * result)
5486 {
5487  int rc;
5488  int error = NO_ERROR;
5489  int index1, index2;
5490  DB_VALUE *val1, *val2;
5491 
5492  if (!set1->sorted)
5493  {
5494  error = setobj_sort (set1);
5495  }
5496  if (!error && !set2->sorted)
5497  {
5498  error = setobj_sort (set2);
5499  }
5500 
5501  /* compare elements in ascending order */
5502  index1 = 0;
5503  index2 = 0;
5504  while (index1 < set1->size && index2 < set2->size && !(error < NO_ERROR))
5505  {
5506  val1 = INDEX (set1, index1);
5507  val2 = INDEX (set2, index2);
5508  if (DB_IS_NULL (val1) || DB_IS_NULL (val2))
5509  {
5510  /* NULL never equals NULL, so {NULL} * {NULL} = {} */
5511  /* NULLs are at the end, so once we have hit one from either collection, we will never get another equality
5512  * match, and can bail out. */
5513  break;
5514  }
5515  else
5516  {
5517  rc = tp_value_compare (val1, val2, 1, 0);
5518 
5519  switch (rc)
5520  {
5521  case DB_EQ: /* element appears in both sets */
5522  index1++; /* SHOULD be in result */
5523  index2++;
5524  error = setobj_add_element (result, val1);
5525  break;
5526  case DB_GT: /* element of second set not in first */
5527  index2++; /* should NOT be in result */
5528  break;
5529  case DB_LT: /* element of first set not in second */
5530  index1++; /* should NOT be in result */
5531  break;
5532  case DB_UNK: /* a NULL encountered (also unexpected results) */
5533  default: /* NULL's are not equal to nulls. so {NULL} * {NULL} is = {} ie, the value should NOT
5534  * be added to the result. */
5535  /* At least one of these must be a collection with an embedded NULL, we need to increment to the next
5536  * pair of values, but must check again to see which side to increase for total ordering. */
5537  rc = tp_value_compare (val1, val2, 1, 1);
5538  if (rc == DB_GT)
5539  {
5540  index2++;
5541  }
5542  else
5543  {
5544  index1++;
5545  }
5546  break;
5547  }
5548  }
5549  }
5550  return error;
5551 }
5552 
5553 #if !defined (SERVER_MODE)
5554 /*
5555  * setobj_issome()
5556  * return: 1 if value compares successfully using op to some element
5557  * in set, -1 if unknown, othersize 0
5558  * value(in) : a value
5559  * set(in) : set object
5560  * op(in) : op code
5561  * do_coercion(in) :
5562  *
5563  * Note :
5564  * Compares value to the members of set using op.
5565  * If any member compares favorably, returns 1
5566  */
5567 int
5568 setobj_issome (DB_VALUE * value, COL * set, PT_OP_TYPE op, int do_coercion)
5569 {
5570  int status;
5571  int i;
5572  int has_null = 0;
5573 
5574  if (DB_IS_NULL (value))
5575  {
5576  return -1;
5577  }
5578 
5579  for (i = 0; i < set->size; i++)
5580  {
5581  status = tp_value_compare (value, INDEX (set, i), do_coercion, 0);
5582  if (status == DB_UNK)
5583  {
5584  has_null = 1;
5585  continue;
5586  }
5587  switch (op)
5588  {
5589  case PT_EQ_SOME:
5590  if (status == DB_EQ)
5591  {
5592  return 1;
5593  }
5594  break;
5595  case PT_NE_SOME:
5596  if (status != DB_EQ)
5597  {
5598  return 1;
5599  }
5600  break;
5601  case PT_GE_SOME:
5602  if ((status == DB_EQ) || (status == DB_GT))
5603  {
5604  return 1;
5605  }
5606  break;
5607  case PT_GT_SOME:
5608  if (status == DB_GT)
5609  {
5610  return 1;
5611  }
5612  break;
5613  case PT_LT_SOME:
5614  if (status == DB_LT)
5615  {
5616  return 1;
5617  }
5618  break;
5619  case PT_LE_SOME:
5620  if ((status == DB_EQ) || (status == DB_LT))
5621  {
5622  return 1;
5623  }
5624  break;
5625  default:
5626  break;
5627  }
5628  }
5629  if (col_has_null (set))
5630  {
5631  return -1;
5632  }
5633  else
5634  {
5635  return 0;
5636  }
5637 }
5638 #endif /* !defined (SERVER_MODE) */
5639 
5640 /*
5641  * setobj_convert_oids_to_objects() - This will convert all OID and VOBJ
5642  * elements to OBJECT elements
5643  * return: error code
5644  * col(in) : collection object
5645  *
5646  */
5647 
5648 int
5650 {
5651  int error = NO_ERROR;
5652 #if !defined(SERVER_MODE)
5653  DB_VALUE *var;
5654  int i;
5655  DB_TYPE typ;
5656  DB_OBJECT *mop;
5657 
5658  if (col == NULL)
5659  {
5660  return NO_ERROR;
5661  }
5662 
5663  for (i = 0; i < col->size && !(error < NO_ERROR); i++)
5664  {
5665  var = INDEX (col, i);
5666  typ = DB_VALUE_DOMAIN_TYPE (var);
5667  switch (typ)
5668  {
5669  case DB_TYPE_OID:
5670  swizzle_value (var, 0);
5671  break;
5672  case DB_TYPE_VOBJ:
5673  error = vid_vobj_to_object (var, &mop);
5674  if (!(error < 0))
5675  {
5676  pr_clear_value (var);
5678  db_make_object (var, mop);
5679  }
5680  break;
5681  case DB_TYPE_SET:
5682  case DB_TYPE_MULTISET:
5683  case DB_TYPE_SEQUENCE:
5684  error = set_convert_oids_to_objects (db_get_set (var));
5685  break;
5686  default:
5687  break;
5688  }
5689  }
5690 #endif
5691 
5692  return (error);
5693 }
5694 
5695 /* SET ELEMENT ACCESS FUNCTIONS */
5696 
5697 /*
5698  * setobj_get_element_ptr() - This is used in controlled conditions to
5699  * get a direct pointer to a set element value.
5700  * return: error code
5701  * col(in) : collection object
5702  * index(in) : element index
5703  * result(in) : pointer to pointer to value (returned)
5704  *
5705  */
5706 
5707 int
5708 setobj_get_element_ptr (COL * col, int index, DB_VALUE ** result)
5709 {
5710  int error;
5711 
5712  CHECKNULL_ERR (col);
5713  CHECKNULL_ERR (result);
5714 
5715  if (index >= 0 && index < col->size)
5716  {
5717  *result = INDEX (col, index);
5718  error = NO_ERROR;
5719  }
5720  else
5721  {
5722  *result = NULL;
5723  error = ER_SET_INVALID_INDEX;
5724  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, index);
5725  }
5726 
5727  return error;
5728 }
5729 
5730 /*
5731  * setobj_get_element() - Get the value of a set element.
5732  * An error code is returned if the index is beyond
5733  * the length of the set
5734  * return: error code
5735  * set(in) : set object
5736  * index(in) : element index
5737  * value(in) : return value container
5738  *
5739  */
5740 
5741 int
5742 setobj_get_element (COL * set, int index, DB_VALUE * value)
5743 {
5744  int error = NO_ERROR;
5745  DB_VALUE *element;
5746  DB_TYPE db_type;
5747 
5748  /* should this be pr_clear_value instead? */
5749  db_make_null (value);
5750 
5751  error = setobj_get_element_ptr (set, index, &element);
5752 
5753  if (element)
5754  {
5755  swizzle_value (element, 0);
5756  error = pr_clone_value (element, value);
5757  /* kludge, should be part of pr_ level */
5758 
5759  db_type = DB_VALUE_TYPE (value);
5760  if ((db_type == DB_TYPE_STRING && db_get_string (value) == NULL)
5761  || (TP_IS_SET_TYPE (db_type) && db_get_set (value) == NULL)
5762  || (db_type == DB_TYPE_OBJECT && db_get_object (value) == NULL)
5763  || (db_type == DB_TYPE_BLOB && db_get_elo (value) == NULL)
5764  || (db_type == DB_TYPE_CLOB && db_get_elo (value) == NULL)
5765  || (db_type == DB_TYPE_ELO && db_get_elo (value) == NULL))
5766  {
5767  db_make_null (value);
5768  }
5769  }
5770 
5771  return error;
5772 }
5773 
5774 /*
5775  * setobj_add_element() - Add an element to a set
5776  * return: error code
5777  * col(in) : collection object
5778  * value(in) : value to add
5779  *
5780  * Note :
5781  * For basic sets, the set is first checked to see if the element
5782  * already exists. For basic & multi sets, the element is added
5783  * to the head of the list. For sequences, the element is appended
5784  * to the end of the sequence.
5785  */
5786 
5787 int
5789 {
5790  DB_VALUE temp;
5791  int error = NO_ERROR;
5792 
5793  db_make_null (&temp);
5794  CHECKNULL_ERR (col);
5795  CHECKNULL_ERR (value);
5796 
5797  error = assign_set_value (col, value, &temp, IMPLICIT);
5798  if (error != NO_ERROR)
5799  {
5800  return error;
5801  }
5802  /* assign_set_value has done the necessary cloning */
5803  error = col_add (col, &temp);
5804 
5805  if (error != NO_ERROR)
5806  {
5807  pr_clear_value (&temp);
5808 
5809  /* to keep the interface consistent, attempting to add a duplicate value will not be considered an error */
5810  if (error == SET_DUPLICATE_VALUE)
5811  {
5812  error = NO_ERROR;
5813  }
5814  }
5815 
5816  return error;
5817 }
5818 
5819 /*
5820  * setobj_put_element() - This is used to overwrite an element of a sequence
5821  * with another value
5822  * return: error code
5823  * col(in) : collection object
5824  * index(in) : element index
5825  * value(in) : value to put in sequence
5826  *
5827  */
5828 
5829 int
5830 setobj_put_element (COL * col, int index, DB_VALUE * value)
5831 {
5832  int error = NO_ERROR;
5833  DB_VALUE temp;
5834 
5835  db_make_null (&temp);
5836  CHECKNULL_ERR (col);
5837  CHECKNULL_ERR (value);
5838 
5839  if (index < 0)
5840  {
5841  error = ER_SET_INVALID_INDEX;
5843  return error;
5844  }
5845 
5846  error = assign_set_value (col, value, &temp, IMPLICIT);
5847  if (error != NO_ERROR)
5848  {
5849  return error;
5850  }
5851 
5852  if (index < col->size)
5853  {
5854  /* clear existing value */
5855  pr_clear_value (INDEX (col, index));
5856  }
5857 
5858  /* temp contains the new value, just blast it in */
5859  col_put (col, index, &temp);
5860 
5861  return (error);
5862 }
5863 
5864 /*
5865  * setobj_insert_element() -
5866  * return: error code
5867  * col(in) : collection
5868  * index(in) : element position
5869  * value(in) : value to insert
5870  *
5871  * Note :
5872  * This will insert a value into a sequence and shift existing
5873  * values down to make room for the element. If the index is beyond
5874  * the length of the sequence, no shifting will ocurr and the sequence
5875  * will grow to accomodate the indexed element.
5876  */
5877 
5878 int
5880 {
5881  int error = NO_ERROR;
5882  DB_VALUE temp;
5883 
5884  CHECKNULL_ERR (col);
5885  CHECKNULL_ERR (value);
5886 
5887  if (index < 0)
5888  {
5889  error = ER_SET_INVALID_INDEX;
5891  return error;
5892  }
5893 
5894  error = assign_set_value (col, value, &temp, IMPLICIT);
5895  if (error == NO_ERROR)
5896  {
5897  /* assign_set_value has done the necessary cloning */
5898  col_insert (col, index, &temp);
5899  }
5900 
5901  return (error);
5902 }
5903 
5904 /*
5905  * setobj_drop_element() - This will remove values from a set or sequence
5906  * return: error code
5907  * col(in) : collection object
5908  * value(in) : value to drop
5909  * match_nulls(in) : drop NULL values?
5910  *
5911  * Note :
5912  * For basic & multisets, the matching elements are removed from the list.
5913  * For sequences the elements are made NULL.
5914  * If match_nulls is true and we have a NULL db_value, then we'll
5915  * drop all of the NULL values from the set, multi-set, or sequence.
5916  * To be more consistent with the CSQL language, this has been
5917  * changed so that it will only drop the FIRST occurrence of
5918  * the value. This is mostly an issue for multisets.
5919  *
5920  */
5921 
5922 int
5923 setobj_drop_element (COL * col, DB_VALUE * value, bool match_nulls)
5924 {
5925  int error = NO_ERROR;
5926 
5927  CHECKNULL_ERR (col);
5928  CHECKNULL_ERR (value);
5929 
5930  /* Minor enhancement: if the value is NULL and we aren't matching NULLs, col_drop() won't drop anything, so don't
5931  * call it. */
5932 
5933  if (DB_IS_NULL (value))
5934  {
5935  if (match_nulls)
5936  {
5937  error = col_drop_nulls (col);
5938  }
5939  }
5940  else
5941  {
5942  error = col_drop (col, value);
5943  }
5944  return (error);
5945 }
5946 
5947 /*
5948  * setobj_drop_seq_element() - This will completely remove an element
5949  * from a sequence and shift the subsequent
5950  * elements up to fill in the empty space
5951  * return: error code
5952  * col(in) : collection object
5953  * index(in) : element index
5954  *
5955  */
5956 
5957 int
5959 {
5960  int error = NO_ERROR;
5961 
5962  CHECKNULL_ERR (col);
5963 
5964  if (index < 0 || index >= col->size)
5965  {
5966  error = ER_SET_INVALID_INDEX;
5967  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, index);
5968  }
5969  else
5970  {
5971  error = col_delete (col, index);
5972  }
5973  return (error);
5974 }
5975 
5976 /*
5977  * setobj_find_seq_element() -
5978  * return: the index of the element or error code if not found
5979  * col(in) : sequence descriptor
5980  * value(in) : value to search for
5981  * index(in) : starting index (zero if starting from the beginning)
5982  *
5983  * Note :
5984  * This can be used to sequentially search for elements in a
5985  * sequence matching a particular value. Do search for duplicate elements
5986  * call this function multiple times and set the "index" parameter to
5987  * 1+ the number returned by the previous call to this function.
5988  * Errors are defined to be negative integers to you can check to see
5989  * if this function failed to find a value by testing for a negative
5990  * return value. The specific error to test for is
5991  * ER_SET_ELEMENT_NOT_FOUND. A error code other than this one may indicate
5992  * an authorization failure.
5993  */
5994 
5995 int
5997 {
5998  int result;
5999  DB_VALUE *valp;
6000  long found;
6001 
6002  if (index >= col->size || index < 0)
6003  {
6004  result = ER_SEQ_OUT_OF_BOUNDS;
6006  }
6007  else
6008  {
6009  for (found = -1; index < col->size && found == -1; index++)
6010  {
6011  valp = INDEX (col, index);
6012  if (tp_value_equal (valp, value, 1))
6013  {
6014  found = index;
6015  }
6016  }
6017  if (found == -1)
6018  {
6019  result = ER_SEQ_ELEMENT_NOT_FOUND;
6021  }
6022  else
6023  {
6024  result = found;
6025  }
6026  }
6027 
6028  return result;
6029 }
6030 
6031 /*
6032  * setobj_coerce() - This coerces a set from one domain into another if possible
6033  * return: coerced set
6034  * col(in) : source set
6035  * domain(in) : desired domain
6036  * implicit_coercion(in) :
6037  *
6038  * Note :
6039  * If all of the elements can be coerced into a compatible
6040  * domain, a new set is returned. Otherwise NULL is returned.
6041  * This could be made faster if necessary but not worth the trouble
6042  * right now.
6043  */
6044 
6045 COL *
6046 setobj_coerce (COL * col, TP_DOMAIN * domain, bool implicit_coercion)
6047 {
6048  COL *new_;
6049  DB_VALUE *val, temp;
6050  int error;
6051  int i;
6052 
6053  new_ = setobj_create_with_domain (domain, col->size);
6054 
6055  if (new_ == NULL)
6056  {
6057  return NULL;
6058  }
6059  /* first copy the values over in the order they appear, coercing domains as we go. */
6060  for (i = 0; i < col->size && new_ != NULL; i++)
6061  {
6062  val = INDEX (col, i);
6063  error = assign_set_value (new_, val, &temp, implicit_coercion);
6064  if (error == NO_ERROR)
6065  {
6066  /* assign_set_value has done the necessary cloning */
6067  error = col_put (new_, new_->size, &temp);
6068  }
6069  if (error != NO_ERROR)
6070  {
6071  setobj_free (new_);
6072  new_ = NULL;
6073  }
6074  }
6075  /* next, if we are coercing to a set, sort the set. This is done in two steps, because sorting each element as its
6076  * inserted is quadratic, but sorting in place is N*log2 N. */
6077  if (new_ == NULL)
6078  {
6079  return NULL;
6080  }
6081  /* if the destination is a set, and the source is not a set or is not sorted, then "new" must get sorted. */
6082  if ((new_->coltype == DB_TYPE_SET || new_->coltype == DB_TYPE_MULTISET)
6083  && (!col->sorted || (col->coltype != DB_TYPE_SET && col->coltype != DB_TYPE_MULTISET)))
6084  {
6085  new_->sorted = 0;
6086  setobj_sort (new_);
6087  }
6088 
6089  if (new_->coltype == DB_TYPE_SET)
6090  {
6091  /* make a pass to remove duplicates */
6092  /* going backwards helps reduce quadratic behavior when deleting lots of identical values */
6093  i = new_->size - 1;
6094  while (i > 0)
6095  {
6096  val = INDEX (new_, i);
6097  if (!DB_IS_NULL (val) && col_value_compare (val, INDEX (new_, i - 1)) == 0)
6098  {
6099  col_delete (new_, i);
6100  }
6101  i--;
6102  }
6103  }
6104  return (new_);
6105 }
6106 
6107 /* DEBUGGING FUNCTIONS */
6108 
6109 /*
6110  * setobj_print() - Print a description of the set. For debugging only
6111  * return: none
6112  * fp(in) :
6113  * col(in) :
6114  *
6115  */
6116 
6117 void
6118 setobj_print (FILE * fp, COL * col)
6119 {
6120  int i;
6121 
6122  if (col == NULL)
6123  {
6124  return;
6125  }
6126  if (col->coltype == DB_TYPE_SET)
6127  {
6128  fprintf (fp, "set");
6129  }
6130  if (col->coltype == DB_TYPE_MULTISET)
6131  {
6132  fprintf (fp, "multiset");
6133  }
6134  fprintf (fp, "{");
6135  for (i = 0; i < col->size; i++)
6136  {
6137  db_fprint_value (fp, INDEX (col, i));
6138  if (i < col->size - 1)
6139  {
6140  fprintf (fp, ", ");
6141  }
6142  }
6143  fprintf (fp, "}\n");
6144 }
6145 
6146 /* SET REFERENCE MAINTENANCE */
6147 
6148 /*
6149  * setobj_type() - Returns the type of setobj is passed in
6150  * return: DB_TYPE
6151  * set(in) : set object
6152  *
6153  * NOTE: setobj_type is special; it is declared in dbtype.h because dbtype_function.i requires it and it is exposed
6154  * to other libraries/executable (e.g. cas/cub_cas) and to C-compiled unit csql_grammar.c.
6155  * therefore, struct setobj is used instead of SETOBJ/COL aliases.
6156  */
6157 DB_TYPE
6158 setobj_type (struct setobj *set)
6159 {
6160  if (set)
6161  {
6162  return set->coltype;
6163  }
6164  return DB_TYPE_NULL;
6165 }
6166 
6167 /*
6168  * setobj_domain() - Returns domain of setobj is passed in
6169  * return: TP_DOMAIN
6170  * set(in) : set object
6171  *
6172  */
6173 
6174 TP_DOMAIN *
6176 {
6177  if (set)
6178  {
6179  return set->domain;
6180  }
6181  return NULL;
6182 }
6183 
6184 /*
6185  * setobj_put_domain() - sets domain in setobj structure
6186  * return: none
6187  * set(in) : set object
6188  * domain(in) :
6189  *
6190  */
6191 
6192 void
6194 {
6195  if (set)
6196  {
6197  set->domain = domain;
6198  }
6199 }
6200 
6201 /*
6202  * setobj_put_value() -
6203  * return: error code
6204  * col(in) : collection
6205  * index(in) :
6206  * value(in) :
6207  *
6208  */
6209 
6210 int
6211 setobj_put_value (COL * col, int index, DB_VALUE * value)
6212 {
6213  int error;
6214 
6215  if (col->coltype == DB_TYPE_SET || col->coltype == DB_TYPE_MULTISET)
6216  {
6217  error = col_add (col, value);
6218  }
6219  else
6220  {
6221  error = col_put (col, index, value);
6222  }
6223 
6224  /* if the value was added successfully, make sure caller does not inadvertantly clear or use this value container */
6225  if (error == NO_ERROR)
6226  {
6227  PRIM_SET_NULL (value);
6228  }
6229 
6230  return error;
6231 }
6232 
6233 /*
6234  * setobj_get_reference() - This constructs a set reference for a set object
6235  * return: set reference structure
6236  * set(in) : set object
6237  *
6238  * Note :
6239  * If references already exist, one is used, otherwise a new one
6240  * is created.
6241  *
6242  * The reference count IS INCREMENTED. If this is a brand new reference
6243  * structure, the reference count will be initialized to 1.
6244  */
6245 
6246 DB_COLLECTION *
6248 {
6249  DB_COLLECTION *ref = NULL;
6250 
6251  if (set == NULL)
6252  {
6253  return NULL;
6254  }
6255 
6256  if (set->references != NULL)
6257  {
6258  ref = set->references; /* use the first one on the list */
6259  ref->ref_count++;
6260  }
6261  else
6262  {
6263  ref = set_make_reference ();
6264  if (ref != NULL)
6265  {
6266  ref->set = set;
6267  set->references = ref;
6268  }
6269  }
6270  return (ref);
6271 }
6272 
6273 /*
6274  * setobj_release() -
6275  * return: error code
6276  * set(in) : set object
6277  *
6278  * Note :
6279  * This is used to disconnect a set object directly. It should
6280  * be called only by the low leve instance memory handler since this
6281  * is the only thing that deals with set pointers directly.
6282  * It functions basically the same as set_disconnect except that if there
6283  * are no references to the set, it is ok to free all the storage
6284  * for the set.
6285  *
6286  */
6287 
6288 int
6290 {
6291  int error = NO_ERROR;
6292 
6293  if (set->references == NULL)
6294  {
6295  setobj_free (set); /* no references, free it */
6296  }
6297  else
6298  {
6299  error = set_disconnect (set->references); /* disconnect references */
6300  }
6301 
6302  return (error);
6303 }
6304 
6305 /*
6306  * setobj_build_domain_from_col() - builds a set domain (a chained list of
6307  * domains) from a collection object
6308  * return: new domain constructed from the domains in the collection or NULL
6309  * if the domain couldn't be build
6310  * col(in): input collection
6311  * set_domain(in/out): set domain to be build, requires an already created
6312  * domain
6313  */
6314 int
6316 {
6317  int i;
6318  int error_status = NO_ERROR;
6319 
6320  if (col->domain != NULL && set_domain != NULL)
6321  {
6322  for (i = 0; i < col->size; i++)
6323  {
6324  DB_VALUE *curr_value = INDEX (col, i);
6325  /* force copy of component set domains: domains are chained by next in the set domain, so cached/primary
6326  * domain should not be included in this chain; component domain is not cached - it should be freed when
6327  * collection domain is freed */
6328  TP_DOMAIN *curr_domain = tp_domain_copy (tp_domain_resolve_value (curr_value, NULL),
6329  false);
6330 
6331  error_status = tp_domain_add (set_domain, curr_domain);
6332  if (error_status != NO_ERROR)
6333  {
6334  return error_status;
6335  }
6336  }
6337  }
6338 
6339  return error_status;
6340 }
DB_DOMAIN * disk_domain
Definition: db_set.h:45
static int col_expand_array(COL *col, long blockindex)
Definition: set_object.c:623
int set_tform_disk_set(DB_COLLECTION *ref, COL **setptr)
Definition: set_object.c:2123
DB_VALUE_COMPARE_RESULT set_compare_order(DB_COLLECTION *set1, DB_COLLECTION *set2, int do_coercion, int total_order)
Definition: set_object.c:3359
AREA * Set_Ref_Area
Definition: set_object.c:96
int set_difference(DB_COLLECTION *collection1, DB_COLLECTION *collection2, DB_COLLECTION **result, DB_DOMAIN *domain)
Definition: set_object.c:3905
int set_area_init(void)
Definition: set_object.c:149
static long collection_quick_offset
Definition: set_object.c:93
TP_DOMAIN_STATUS tp_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain)
DB_COLLECTION * set_create(DB_TYPE type, int initial_size)
Definition: set_object.c:2373
DB_COLLECTION * set_create_multi(void)
Definition: set_object.c:2419
#define WS_IS_DELETED(mop)
Definition: work_space.h:284
#define NO_ERROR
Definition: error_code.h:46
int set_get_element_nocopy(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2616
int db_value_put_null(DB_VALUE *value)
Definition: db_macro.c:122
int set_drop_seq_element(DB_COLLECTION *set, int index)
Definition: set_object.c:2902
int col_put(COL *col, long colindex, DB_VALUE *val)
Definition: set_object.c:1286
DB_COLLECTION * db_get_set(const DB_VALUE *value)
int(* SETOBJ_SORT_CMP_FUNC)(const void *, const void *)
Definition: set_object.c:87
TP_DOMAIN_STATUS setobj_check_domain(COL *col, TP_DOMAIN *domain)
Definition: set_object.c:4570
TP_DOMAIN_STATUS tp_domain_check(const TP_DOMAIN *domain, const DB_VALUE *value, TP_MATCH exact_match)
int topblock
Definition: set_object.h:75
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
int tp_domain_compatible(const TP_DOMAIN *src, const TP_DOMAIN *dest)
int disk_size
Definition: db_set.h:48
MOP ws_mop(const OID *oid, MOP class_mop)
Definition: work_space.c:614
#define VALUETOP(col)
Definition: set_object.h:56
int lastinsert
Definition: set_object.h:74
void area_destroy(AREA *area)
Definition: area_alloc.c:247
int col_add(COL *col, DB_VALUE *val)
Definition: set_object.c:1593
int set_issome(DB_VALUE *value, DB_COLLECTION *set, PT_OP_TYPE op, int do_coercion)
Definition: set_object.c:3240
void swizzle_value(DB_VALUE *val, int input)
Definition: set_object.c:4659
#define TP_IS_SET_TYPE(typenum)
void set_free(DB_COLLECTION *set)
Definition: set_object.c:2560
COL * setobj_create_with_domain(TP_DOMAIN *domain, int initial_size)
Definition: set_object.c:4268
int setobj_put_element(COL *col, int index, DB_VALUE *value)
Definition: set_object.c:5830
#define LC_DOESNOT_EXIST
#define ER_REFERENCE_TO_NON_REFERABLE_NOT_ALLOWED
Definition: error_code.h:1231
DB_TYPE
Definition: dbtype_def.h:670
int tp_value_equal(const DB_VALUE *value1, const DB_VALUE *value2, int do_coercion)
#define ER_FAILED
Definition: error_code.h:47
#define BLOCK(collection_index)
Definition: set_object.h:52
AREA * Set_Obj_Area
Definition: set_object.c:98
void set_iterator_free(SET_ITERATOR *it)
Definition: set_object.c:4188
DB_COLLECTION * set_copy(DB_COLLECTION *set)
Definition: set_object.c:2473
struct tp_domain * setdomain
Definition: object_domain.h:82
#define ER_SET_DOMAIN_CONFLICT
Definition: error_code.h:381
bool setobj_ismember(COL *col, DB_VALUE *proposed_value, int check_null)
Definition: set_object.c:5022
#define LC_ERROR
static long col_move_nulls(COL *col)
Definition: set_object.c:527
struct tp_domain * domain
Definition: set_object.h:85
void set_make_collection(DB_VALUE *value, DB_COLLECTION *col)
Definition: set_object.c:3965
COL * setobj_coerce(COL *col, TP_DOMAIN *domain, bool implicit_coercion)
Definition: set_object.c:6046
struct setobj * set
Definition: db_set.h:43
#define ASSERT_ERROR_AND_SET(error_code)
#define assert_release(e)
Definition: error_manager.h:96
int db_make_object(DB_VALUE *value, DB_C_OBJECT *obj)
DB_TYPE coltype
Definition: set_object.h:71
DB_COLLECTION * set_create_sequence(int size)
Definition: set_object.c:2432
DB_VALUE * value
Definition: set_object.h:105
unsigned may_have_temporary_oids
Definition: set_object.h:94
int setobj_get_element_ptr(COL *col, int index, DB_VALUE **result)
Definition: set_object.c:5708
DB_COLLECTION * setobj_get_reference(COL *set)
Definition: set_object.c:6247
DB_VALUE val[1]
Definition: set_object.c:84
static void col_initialize(void)
Definition: set_object.c:1339
void setobj_put_domain(COL *set, TP_DOMAIN *domain)
Definition: set_object.c:6193
DB_SET * ref
Definition: set_object.h:102
COL * setobj_copy(COL *col)
Definition: set_object.c:4376
static void free_set_reference(DB_COLLECTION *ref)
Definition: set_object.c:1982
int setobj_get_element(COL *set, int index, DB_VALUE *value)
Definition: set_object.c:5742
static DB_VALUE * realloc_block(DB_VALUE *in_block, long n)
Definition: set_object.c:247
int setobj_drop_element(COL *col, DB_VALUE *value, bool match_nulls)
Definition: set_object.c:5923
struct collect_block * next
Definition: set_object.c:82
int col_drop(COL *col, DB_VALUE *val)
Definition: set_object.c:1690
TP_DOMAIN * tp_domain_resolve_value(const DB_VALUE *val, TP_DOMAIN *dbuf)
int set_iterator_next(SET_ITERATOR *it)
Definition: set_object.c:4236
TP_DOMAIN * tp_domain_copy(const TP_DOMAIN *domain, bool check_cache)
long col_find(COL *col, long *found, DB_VALUE *val, int do_coerce)
Definition: set_object.c:1134
int col_delete(COL *col, long colindex)
Definition: set_object.c:1484
int er_errid(void)
void set_free_block(DB_VALUE *in_block)
Definition: set_object.c:278
int setobj_cardinality(COL *col)
Definition: set_object.c:4970
DB_VALUE_COMPARE_RESULT set_seq_compare(DB_COLLECTION *set1, DB_COLLECTION *set2, int do_coercion, int total_order)
Definition: set_object.c:3464
DB_COLLECTION * set_create_with_domain(TP_DOMAIN *domain, int initial_size)
Definition: set_object.c:2438
int set_size(DB_COLLECTION *set)
Definition: set_object.c:3036
enum tp_domain_status TP_DOMAIN_STATUS
int col_drop_nulls(COL *col)
Definition: set_object.c:1730
int setobj_filter(COL *col, int filter, int *cardptr)
Definition: set_object.c:4874
bool ws_is_same_object(MOP mop1, MOP mop2)
Definition: work_space.c:5065
int setobj_build_domain_from_col(COL *col, TP_DOMAIN **set_domain)
Definition: set_object.c:6315
static int check_set_object(DB_VALUE *var, int *removed_ptr)
Definition: set_object.c:4795
AREA * area_create(const char *name, size_t element_size, size_t alloc_count)
Definition: area_alloc.c:146
#define COL_BLOCK_SIZE
Definition: set_object.h:43
DB_DOMAIN_INFO domain
Definition: dbtype_def.h:1082
DB_ELO * db_get_elo(const DB_VALUE *value)
LC_OIDMAP * locator_add_oidset_object(LC_OIDSET *oidset, MOP obj_mop)
Definition: locator_cl.c:6629
#define ER_SEQ_ELEMENT_NOT_FOUND
Definition: error_code.h:384
struct db_object * owner
Definition: db_set.h:41
#define NULL_PAGEID
TP_DOMAIN * setobj_get_domain(COL *set)
Definition: set_object.c:4605
#define OFFSET(collection_index)
Definition: set_object.h:53
bool set_ismember(DB_COLLECTION *set, DB_VALUE *value)
Definition: set_object.c:3199
#define EXPAND(blockindex)
Definition: set_object.h:50
int size
Definition: set_object.h:72
static long col_init
Definition: set_object.c:90
#define BLOCK_START(block)
Definition: set_object.h:58
DB_DATA data
Definition: dbtype_def.h:1083
int setobj_find_seq_element(COL *col, DB_VALUE *value, int index)
Definition: set_object.c:5996
int ref_count
Definition: db_set.h:47
int set_union(DB_COLLECTION *collection1, DB_COLLECTION *collection2, DB_COLLECTION **result, DB_DOMAIN *domain)
Definition: set_object.c:3928
DB_COLLECTION * set_coerce(DB_COLLECTION *set, TP_DOMAIN *domain, bool implicit_coercion)
Definition: set_object.c:3645
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
Definition: db_set.h:35
struct set_iterator * next
Definition: set_object.h:100
DB_TYPE setobj_type(struct setobj *set)
Definition: set_object.c:6158
TP_DOMAIN tp_Vobj_domain
SETOBJ * set
Definition: set_object.h:103
#define assert(x)
int set_get_setobj(DB_COLLECTION *ref, COL **setptr, int for_write)
Definition: set_object.c:2175
int set_add_element(DB_COLLECTION *set, DB_VALUE *value)
Definition: set_object.c:2641
int set_filter(DB_COLLECTION *set)
Definition: set_object.c:3744
static int input()
Definition: cnvlex.c:1661
struct collect_block COL_BLOCK
#define ER_GENERIC_ERROR
Definition: error_code.h:49
bool setobj_isempty(COL *col)
Definition: set_object.c:4996
int setobj_sort(COL *col)
Definition: set_object.c:4437
int obj_lock(MOP op, int for_write)
int ws_pin(MOP mop, int pin)
Definition: work_space.c:2989
static void col_null_values(COL *col, long bottomvalue, long topvalue)
Definition: set_object.c:662
int arraytop
Definition: set_object.h:78
void set_area_reset()
Definition: set_object.c:205
static int set_op(DB_COLLECTION *collection1, DB_COLLECTION *collection2, DB_COLLECTION **result, DB_DOMAIN *domain, SETOBJ_OP op)
Definition: set_object.c:3792
TP_DOMAIN * setobj_domain(COL *set)
Definition: set_object.c:6175
int setobj_insert_element(COL *col, int index, DB_VALUE *value)
Definition: set_object.c:5879
COL * setobj_create(DB_TYPE collection_type, int size)
Definition: set_object.c:4289
need_clear_type need_clear
Definition: db_set.h:49
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
static int col_successive_merge(COL *col, long top)
Definition: set_object.c:489
int col_has_null(COL *col)
Definition: set_object.c:1033
#define WS_MAX_QUICK_SIZE
#define CHECKNULL_ERR(thing)
Definition: set_object.c:100
TP_DOMAIN tp_Set_domain
unsigned int db_on_server
int col_permanent_oids(COL *col)
Definition: set_object.c:1779
DB_VALUE_COMPARE_RESULT setobj_compare(COL *set1, COL *set2, int do_coercion)
Definition: set_object.c:5109
int col_sort(COL *col)
Definition: set_object.c:570
DB_OBJECT * db_get_object(const DB_VALUE *value)
MOP ws_class_mop(MOP mop)
Definition: work_space.c:2907
static void merge_set_references(COL *set, DB_COLLECTION *ref)
Definition: set_object.c:2079
TP_DOMAIN_STATUS tp_value_cast(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain, bool implicit_coercion)
static void col_merge_runs(COL *col, DB_VALUE **runs, long runsize, long top)
Definition: set_object.c:444
#define TP_DOMAIN_TYPE(dom)
#define WS_SET_DELETED(mop)
Definition: work_space.h:286
int locator_assign_oidset(LC_OIDSET *oidset, LC_OIDMAP_CALLBACK callback)
Definition: locator_cl.c:6687
#define NULL
Definition: freelistheap.h:34
LOCK ws_get_lock(MOP mop)
Definition: work_space.c:2942
struct pr_type * type
Definition: object_domain.h:76
const char * pr_type_name(DB_TYPE id)
#define ER_SEQ_OUT_OF_BOUNDS
Definition: error_code.h:378
struct db_set * ref_link
Definition: db_set.h:42
int setobj_put_value(COL *col, int index, DB_VALUE *value)
Definition: set_object.c:6211
int pt_is_reference_to_reusable_oid(DB_VALUE *val)
void setobj_free(COL *col)
Definition: set_object.c:4338
#define err(fd,...)
Definition: porting.h:431
DB_COLLECTION * set_change_owner(DB_COLLECTION *ref, MOP owner, int attid, TP_DOMAIN *domain)
Definition: set_object.c:2308
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
void PRIM_SET_NULL(DB_VALUE *value)
static long non_null_index(COL *col, long lower, long upper)
Definition: set_object.c:886
#define TM_TRAN_READ_FETCH_VERSION()
LC_OIDSET * locator_make_oid_set(void)
Definition: locator.c:2116
DB_VALUE_COMPARE_RESULT set_compare(DB_COLLECTION *set1, DB_COLLECTION *set2, int do_coercion)
Definition: set_object.c:3411
void or_init(OR_BUF *buf, char *data, int length)
unsigned sorted
Definition: set_object.h:91
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
#define ER_SET_INVALID_DOMAIN
Definition: error_code.h:385
int set_connect(DB_COLLECTION *ref, MOP owner, int attid, TP_DOMAIN *domain)
Definition: set_object.c:2231
int set_get_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2575
int tp_domain_add(TP_DOMAIN **dlist, TP_DOMAIN *domain)
#define COLBLOCKSIZE(n)
Definition: set_object.h:57
#define cmp
Definition: mprec.h:351
int pr_clear_value(DB_VALUE *value)
int topblockcount
Definition: set_object.h:80
int vid_vobj_to_object(const DB_VALUE *vobj, DB_OBJECT **mop)
void locator_free_oid_set(THREAD_ENTRY *thread_p, LC_OIDSET *oidset)
Definition: locator.c:2227
void set_fprint(FILE *fp, DB_COLLECTION *set)
Definition: set_object.c:3696
setobj * or_get_set(OR_BUF *buf, struct tp_domain *domain)
#define DB_DEFAULT_SCALE
Definition: dbtype_def.h:561
#define ER_SET_INVALID_INDEX
Definition: error_code.h:382
void set_area_final(void)
Definition: set_object.c:189
void set_final(void)
Definition: set_object.c:297
struct db_domain_info::general_info general_info
int col_value_compare(DB_VALUE *a, DB_VALUE *b)
Definition: set_object.c:312
#define INDEX(collection, index)
Definition: set_object.h:54
static int assign_set_value(COL *set, DB_VALUE *src, DB_VALUE *dest, bool implicit_coercion)
Definition: set_object.c:4716
int set_cardinality(DB_COLLECTION *set)
Definition: set_object.c:2999
int attribute
Definition: db_set.h:46
int set_put_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2719
static void error(const char *msg)
Definition: gencat.c:331
static void free_iterator(SET_ITERATOR *it)
Definition: set_object.c:4133
static DB_VALUE * new_block(long n)
Definition: set_object.c:224
TP_DOMAIN * set_get_domain(DB_COLLECTION *set)
Definition: set_object.c:3319
int setobj_add_element(COL *col, DB_VALUE *value)
Definition: set_object.c:5788
#define OBJECT_HAS_TEMP_OID(obj)
Definition: set_object.h:64
static int rc
Definition: serial.c:50
#define DB_DEFAULT_PRECISION
Definition: dbtype_def.h:558
int locator_does_exist_object(MOP mop, DB_FETCH_MODE purpose)
Definition: locator_cl.c:3242
bool db_value_is_null(const DB_VALUE *value)
DB_VALUE_COMPARE_RESULT setvobj_compare(COL *set1, COL *set2, int do_coercion, int total_order)
Definition: set_object.c:1874
#define AU_SELECT
Definition: authenticate.h:69
int obj_locate_attribute(MOP op, int attid, int for_write, char **memp, SM_ATTRIBUTE **attp)
#define ARG_FILE_LINE
Definition: error_manager.h:44
#define SET_DUPLICATE_VALUE
Definition: set_object.h:40
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
OID * db_get_oid(const DB_VALUE *value)
#define IMPLICIT
Definition: set_object.h:41
DB_VALUE_LIST * element
Definition: set_object.h:104
bool set_isempty(DB_COLLECTION *set)
Definition: set_object.c:3074
TP_DOMAIN_STATUS set_check_domain(DB_COLLECTION *set, TP_DOMAIN *domain)
Definition: set_object.c:3604
void db_fprint_value(FILE *fp, const db_value *value)
int setobj_union(COL *set1, COL *set2, COL *result)
Definition: set_object.c:5382
DB_VALUE_COMPARE_RESULT setobj_compare_order(COL *set1, COL *set2, int do_coercion, int total_order)
Definition: set_object.c:5228
#define ER_OBJ_INVALID_ARGUMENTS
Definition: error_code.h:275
PT_OP_TYPE
Definition: parse_tree.h:1320
int setobj_release(COL *set)
Definition: set_object.c:6289
DB_COLLECTION * set_make_reference(void)
Definition: set_object.c:1936
void set_print(DB_COLLECTION *set)
Definition: set_object.c:3731
char * disk_set
Definition: db_set.h:44
void * area_alloc(AREA *area)
Definition: area_alloc.c:360
int area_free(AREA *area, void *ptr)
Definition: area_alloc.c:514
int set_intersection(DB_COLLECTION *collection1, DB_COLLECTION *collection2, DB_COLLECTION **result, DB_DOMAIN *domain)
Definition: set_object.c:3951
int col_insert(COL *col, long colindex, DB_VALUE *val)
Definition: set_object.c:1383
DB_VALUE * set_iterator_value(SET_ITERATOR *it)
Definition: set_object.c:4201
bool set_has_null(DB_COLLECTION *set)
Definition: set_object.c:3160
int set_optimize(DB_COLLECTION *ref)
Definition: set_object.c:4049
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
int i
Definition: dynamic_load.c:954
int db_make_null(DB_VALUE *value)
DB_VALUE ** array
Definition: set_object.h:82
#define DB_IS_NULL(value)
Definition: dbtype.h:63
COL * col_new(long size, int settype)
Definition: set_object.c:805
int col_expand(COL *col, long i)
Definition: set_object.c:774
struct tp_domain * next
Definition: object_domain.h:74
int setobj_intersection(COL *set1, COL *set2, COL *result)
Definition: set_object.c:5485
DB_COLLECTION * set
Definition: dbtype_def.h:1063
int set_find_seq_element(DB_COLLECTION *set, DB_VALUE *value, int index)
Definition: set_object.c:2962
TP_DOMAIN tp_Sequence_domain
int au_fetch_instance(MOP op, MOBJ *obj_ptr, AU_FETCHMODE mode, LC_FETCH_VERSION_TYPE fetch_version_type, DB_AUTH type)
int set_disconnect(DB_COLLECTION *ref)
Definition: set_object.c:2268
DB_TYPE set_get_type(DB_COLLECTION *set)
Definition: set_object.c:3566
DB_VALUE * set_new_element(DB_COLLECTION *ref)
Definition: set_object.c:4001
int set_insert_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2781
static void col_merge_run(COL *col, DB_VALUE **runs, long run1start, long run1stop, long run2start, long run2stop)
Definition: set_object.c:334
int setobj_drop_seq_element(COL *col, int index)
Definition: set_object.c:5958
DB_COLLECTION * references
Definition: set_object.h:88
int(* SETOBJ_OP)(COL *set1, COL *set2, COL *result)
Definition: set_object.c:88
DB_VALUE_COMPARE_RESULT
Definition: dbtype_def.h:199
int setobj_convert_oids_to_objects(COL *col)
Definition: set_object.c:5649
static SET_ITERATOR * make_iterator(void)
Definition: set_object.c:4109
#define db_private_realloc(thrd, ptr, size)
Definition: memory_alloc.h:231
DB_VALUE_COMPARE_RESULT vobj_compare(DB_COLLECTION *set1, DB_COLLECTION *set2, int do_coercion, int total_order)
Definition: set_object.c:3517
int setobj_size(COL *col)
Definition: set_object.c:4948
void setobj_clear(COL *col)
Definition: set_object.c:4307
static void col_debug(COL *col)
Definition: set_object.c:1918
int set_convert_oids_to_objects(DB_COLLECTION *set)
Definition: set_object.c:3273
static int col_expand_blocks(COL *col, long blockindex, long blockoffset)
Definition: set_object.c:685
#define SET_AREA_COUNT
Definition: set_object.c:78
TP_DOMAIN tp_Multiset_domain
static long col_bsearch(COL *col, long lower, long upper, long *found, DB_VALUE *val, int do_coerce)
Definition: set_object.c:963
SET_ITERATOR * set_iterate(DB_COLLECTION *set)
Definition: set_object.c:4146
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
int set_drop_element(DB_COLLECTION *set, DB_VALUE *value, bool match_nulls)
Definition: set_object.c:2842
int setobj_difference(COL *set1, COL *set2, COL *result)
Definition: set_object.c:5294
int db_value_domain_init(DB_VALUE *value, const DB_TYPE type, const int precision, const int scale)
Definition: db_macro.c:153
void setobj_print(FILE *fp, COL *col)
Definition: set_object.c:6118
unsigned is_vid
Definition: work_space.h:148
DB_COLLECTION * set_create_basic(void)
Definition: set_object.c:2407
#define BLOCKING_LESS1
Definition: set_object.h:55
static int debug_level
Definition: set_object.c:91
int setobj_issome(DB_VALUE *value, COL *set, PT_OP_TYPE op, int do_coercion)
Definition: set_object.c:5568