Line data Source code
1 : /*
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 : *
6 : * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
7 : */
8 :
9 : /*
10 : * Martin Kersten
11 : * Multiple association tables
12 : * A MAT is a convenient way to deal represent horizontal fragmented
13 : * tables. It combines the definitions of several, type compatible
14 : * BATs under a single name.
15 : * It is produced by the mitosis optimizer and the operations
16 : * are the target of the mergetable optimizer.
17 : *
18 : * The MAT is materialized when the operations
19 : * can not deal with the components individually,
20 : * or the incremental operation is not supported.
21 : * Normally all mat.new() operations are removed by the
22 : * mergetable optimizer.
23 : * In case a mat.new() is retained in the code, then it will
24 : * behave as a mat.pack();
25 : *
26 : * The primitives below are chosen to accomodate the SQL
27 : * front-end to produce reasonable efficient code.
28 : */
29 : #include "monetdb_config.h"
30 : #include "mal_resolve.h"
31 : #include "mal_exception.h"
32 : #include "mal_interpreter.h"
33 :
34 : /*
35 : * The pack is an ordinary multi BAT insert. Oid synchronistion
36 : * between pieces should be ensured by the code generators.
37 : * The pack operation could be quite expensive, because it
38 : * may create a really large BAT.
39 : * The slice over a mat helps to avoid constructing intermediates
40 : * that are subsequently reduced.
41 : * Contrary to most operations, NIL arguments are skipped and
42 : * do not produce RUNTIME_OBJECT_MISSING.
43 : */
44 : static str
45 754 : MATpackInternal(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
46 : {
47 : int i;
48 754 : bat *ret = getArgReference_bat(stk,p,0);
49 : BAT *b, *bn;
50 : BUN cap = 0;
51 : int tt = TYPE_any;
52 754 : int rt = getArgType(mb, p, 0), unmask = 0;
53 : (void) cntxt;
54 :
55 3711 : for (i = 1; i < p->argc; i++) {
56 2958 : bat bid = stk->stk[getArg(p,i)].val.bval;
57 2958 : b = BBPquickdesc(bid);
58 2957 : if( b ){
59 2957 : if (tt == TYPE_any)
60 754 : tt = b->ttype;
61 2957 : if ((tt != TYPE_void && b->ttype != TYPE_void && b->ttype != TYPE_msk) && tt != b->ttype)
62 0 : throw(MAL, "mat.pack", "incompatible arguments");
63 2957 : cap += BATcount(b);
64 : }
65 : }
66 753 : if (tt == TYPE_any){
67 0 : *ret = bat_nil;
68 0 : return MAL_SUCCEED;
69 : }
70 :
71 753 : if (tt == TYPE_msk && rt == newBatType(TYPE_oid)) {
72 : tt = TYPE_oid;
73 : unmask = 1;
74 : }
75 753 : bn = COLnew(0, tt, cap, TRANSIENT);
76 754 : if (bn == NULL)
77 0 : throw(MAL, "mat.pack", SQLSTATE(HY013) MAL_MALLOC_FAIL);
78 :
79 3720 : for (i = 1; i < p->argc; i++) {
80 2966 : if (!(b = BATdescriptor(stk->stk[getArg(p,i)].val.ival))) {
81 0 : BBPreclaim(bn);
82 0 : throw(MAL, "mat.pack", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
83 : }
84 2966 : if ((unmask && b->ttype == TYPE_msk) || mask_cand(b)) {
85 : BAT *ob = b;
86 0 : b = BATunmask(b);
87 0 : BBPunfix(ob->batCacheid);
88 0 : if (!b) {
89 0 : BBPreclaim(bn);
90 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
91 : }
92 : }
93 2966 : if (BATcount(bn) == 0) {
94 753 : BAThseqbase(bn, b->hseqbase);
95 754 : BATtseqbase(bn, b->tseqbase);
96 : }
97 2966 : if (BATappend(bn, b, NULL, false) != GDK_SUCCEED) {
98 0 : BBPreclaim(bn);
99 0 : BBPunfix(b->batCacheid);
100 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
101 : }
102 2968 : BBPunfix(b->batCacheid);
103 : }
104 754 : if (bn->tnil && bn->tnonil) {
105 0 : BBPreclaim(bn);
106 0 : throw(MAL, "mat.pack", "INTERNAL ERROR" "bn->tnil or bn->tnonil fails ");
107 : }
108 754 : BBPkeepref(*ret = bn->batCacheid);
109 753 : return MAL_SUCCEED;
110 : }
111 :
112 : /*
113 : * Enable incremental packing. The SQL front-end requires
114 : * fixed oid sequences.
115 : */
116 : static str
117 860160 : MATpackIncrement(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
118 : {
119 860160 : bat *ret = getArgReference_bat(stk,p,0);
120 : int pieces;
121 : BAT *b, *bb, *bn;
122 : size_t newsize;
123 :
124 : (void) cntxt;
125 860160 : b = BATdescriptor( stk->stk[getArg(p,1)].val.ival);
126 860024 : if ( b == NULL)
127 0 : throw(MAL, "mat.pack", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
128 :
129 860024 : if ( getArgType(mb,p,2) == TYPE_int){
130 : /* first step, estimate with some slack */
131 215914 : pieces = stk->stk[getArg(p,2)].val.ival;
132 215914 : int tt = ATOMtype(b->ttype);
133 215914 : if (b->ttype == TYPE_msk)
134 : tt = TYPE_oid;
135 215914 : bn = COLnew(b->hseqbase, tt, (BUN)(1.2 * BATcount(b) * pieces), TRANSIENT);
136 215922 : if (bn == NULL) {
137 0 : BBPunfix(b->batCacheid);
138 0 : throw(MAL, "mat.pack", SQLSTATE(HY013) MAL_MALLOC_FAIL);
139 : }
140 : /* allocate enough space for the vheap, but not for strings,
141 : * since BATappend does clever things for strings */
142 215922 : if ( b->tvheap && bn->tvheap && ATOMstorage(b->ttype) != TYPE_str){
143 47 : newsize = b->tvheap->size * pieces;
144 47 : if (HEAPextend(bn->tvheap, newsize, true) != GDK_SUCCEED) {
145 0 : BBPunfix(b->batCacheid);
146 0 : BBPreclaim(bn);
147 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
148 : }
149 : }
150 215922 : BATtseqbase(bn, b->tseqbase);
151 215924 : if (b->ttype == TYPE_msk || mask_cand(b)) {
152 : BAT *ob = b;
153 0 : b = BATunmask(b);
154 0 : BBPunfix(ob->batCacheid);
155 0 : if (!b) {
156 0 : BBPreclaim(bn);
157 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
158 : }
159 : }
160 215924 : if (BATappend(bn, b, NULL, false) != GDK_SUCCEED) {
161 0 : BBPreclaim(bn);
162 0 : BBPunfix(b->batCacheid);
163 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
164 : }
165 215924 : bn->unused = (pieces-1); /* misuse "unused" field */
166 215924 : BATsettrivprop(bn);
167 215912 : BBPunfix(b->batCacheid);
168 215918 : if (bn->tnil && bn->tnonil) {
169 0 : BBPreclaim(bn);
170 0 : throw(MAL, "mat.pack", "INTERNAL ERROR" " bn->tnil %d bn->tnonil %d", bn->tnil, bn->tnonil);
171 : }
172 215918 : *ret = bn->batCacheid;
173 215918 : BBPretain(bn->batCacheid);
174 215913 : BBPunfix(bn->batCacheid);
175 : } else {
176 : /* remaining steps */
177 644110 : if (!(bb = BATdescriptor(stk->stk[getArg(p,2)].val.ival))) {
178 0 : BBPunfix(b->batCacheid);
179 0 : throw(MAL, "mat.pack", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
180 : }
181 644217 : if (bb->ttype == TYPE_msk || mask_cand(bb)) {
182 : BAT *obb = bb;
183 0 : bb = BATunmask(bb);
184 0 : BBPunfix(obb->batCacheid);
185 0 : if (!bb) {
186 0 : BBPunfix(b->batCacheid);
187 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
188 : }
189 : }
190 644217 : if (BATcount(b) == 0) {
191 415792 : BAThseqbase(b, bb->hseqbase);
192 415790 : BATtseqbase(b, bb->tseqbase);
193 : }
194 644133 : if (BATappend(b, bb, NULL, false) != GDK_SUCCEED) {
195 0 : BBPunfix(bb->batCacheid);
196 0 : BBPunfix(b->batCacheid);
197 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
198 : }
199 644206 : BBPunfix(bb->batCacheid);
200 644001 : b->unused--;
201 644001 : if (b->unused == 0 && (b = BATsetaccess(b, BAT_READ)) == NULL)
202 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
203 644004 : if (b->tnil && b->tnonil) {
204 0 : BBPunfix(b->batCacheid);
205 0 : throw(MAL, "mat.pack", "INTERNAL ERROR" " b->tnil or b->tnonil fails ");
206 : }
207 644004 : *ret = b->batCacheid;
208 644004 : BATsettrivprop(b);
209 643874 : BBPretain(b->batCacheid);
210 644175 : BBPunfix(b->batCacheid);
211 : }
212 : return MAL_SUCCEED;
213 : }
214 :
215 : static str
216 754 : MATpack(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
217 : {
218 754 : return MATpackInternal(cntxt,mb,stk,p);
219 : }
220 :
221 : static str
222 233823 : MATpackValues(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
223 : {
224 : int i, type, first = 1;
225 : bat *ret;
226 : BAT *bn;
227 :
228 : (void) cntxt;
229 233823 : type = getArgType(mb,p,first);
230 233823 : bn = COLnew(0, type, p->argc, TRANSIENT);
231 233836 : if( bn == NULL)
232 0 : throw(MAL, "mat.pack", SQLSTATE(HY013) MAL_MALLOC_FAIL);
233 :
234 233836 : if (ATOMextern(type)) {
235 737274 : for(i = first; i < p->argc; i++)
236 598456 : if (BUNappend(bn, stk->stk[getArg(p,i)].val.pval, false) != GDK_SUCCEED)
237 0 : goto bailout;
238 : } else {
239 505857 : for(i = first; i < p->argc; i++)
240 410984 : if (BUNappend(bn, getArgReference(stk, p, i), false) != GDK_SUCCEED)
241 0 : goto bailout;
242 : }
243 233691 : ret= getArgReference_bat(stk,p,0);
244 233691 : BBPkeepref(*ret = bn->batCacheid);
245 233718 : return MAL_SUCCEED;
246 0 : bailout:
247 0 : BBPreclaim(bn);
248 0 : throw(MAL, "mat.pack", GDK_EXCEPTION);
249 : }
250 :
251 : #include "mel.h"
252 : mel_func mat_init_funcs[] = {
253 : pattern("mat", "new", MATpack, false, "Define a Merge Association Table (MAT). Fall back to the pack operation\nwhen this is called ", args(1,2, batargany("",2),batvarargany("b",2))),
254 : pattern("bat", "pack", MATpackValues, false, "Materialize the values into a BAT. Avoiding a clash with mat.pack() in mergetable", args(1,2, batargany("",2),varargany("",2))),
255 : pattern("mat", "pack", MATpackValues, false, "Materialize the MAT (of values) into a BAT", args(1,2, batargany("",2),varargany("",2))),
256 : pattern("mat", "pack", MATpack, false, "Materialize the MAT into a BAT", args(1,2, batargany("",2),batvarargany("b",2))),
257 : pattern("mat", "packIncrement", MATpackIncrement, false, "Prepare incremental mat pack", args(1,3, batargany("",2),batargany("b",2),arg("pieces",int))),
258 : pattern("mat", "packIncrement", MATpackIncrement, false, "Prepare incremental mat pack", args(1,3, batargany("",2),batargany("b",2),batargany("c",2))),
259 : { .imp=NULL }
260 : };
261 : #include "mal_import.h"
262 : #ifdef _MSC_VER
263 : #undef read
264 : #pragma section(".CRT$XCU",read)
265 : #endif
266 257 : LIB_STARTUP_FUNC(init_mat_mal)
267 257 : { mal_module("mat", NULL, mat_init_funcs); }
|