| 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 - 2019 MonetDB B.V. |
| 7 | */ |
| 8 | |
| 9 | #include "monetdb_config.h" |
| 10 | #include "opt_pushselect.h" |
| 11 | #include "mal_interpreter.h" /* for showErrors() */ |
| 12 | |
| 13 | static InstrPtr |
| 14 | PushArgument(MalBlkPtr mb, InstrPtr p, int arg, int pos) |
| 15 | { |
| 16 | int i; |
| 17 | |
| 18 | p = pushArgument(mb, p, arg); /* push at end */ |
| 19 | for (i = p->argc-1; i > pos; i--) |
| 20 | getArg(p, i) = getArg(p, i-1); |
| 21 | getArg(p, pos) = arg; |
| 22 | return p; |
| 23 | } |
| 24 | |
| 25 | static InstrPtr |
| 26 | PushNil(MalBlkPtr mb, InstrPtr p, int pos, int tpe) |
| 27 | { |
| 28 | int i, arg; |
| 29 | |
| 30 | p = pushNil(mb, p, tpe); /* push at end */ |
| 31 | arg = getArg(p, p->argc-1); |
| 32 | for (i = p->argc-1; i > pos; i--) |
| 33 | getArg(p, i) = getArg(p, i-1); |
| 34 | getArg(p, pos) = arg; |
| 35 | return p; |
| 36 | } |
| 37 | |
| 38 | static InstrPtr |
| 39 | ReplaceWithNil(MalBlkPtr mb, InstrPtr p, int pos, int tpe) |
| 40 | { |
| 41 | p = pushNil(mb, p, tpe); /* push at end */ |
| 42 | getArg(p, pos) = getArg(p, p->argc-1); |
| 43 | p->argc--; |
| 44 | return p; |
| 45 | } |
| 46 | |
| 47 | |
| 48 | #define MAX_TABLES 64 |
| 49 | |
| 50 | typedef struct subselect_t { |
| 51 | int nr; |
| 52 | int tid[MAX_TABLES]; |
| 53 | int subselect[MAX_TABLES]; |
| 54 | } subselect_t; |
| 55 | |
| 56 | static int |
| 57 | subselect_add( subselect_t *subselects, int tid, int subselect ) |
| 58 | { |
| 59 | int i; |
| 60 | |
| 61 | for (i = 0; i<subselects->nr; i++) { |
| 62 | if (subselects->tid[i] == tid) { |
| 63 | if (subselects->subselect[i] == subselect) |
| 64 | return i; |
| 65 | else |
| 66 | return -1; |
| 67 | } |
| 68 | } |
| 69 | if (i >= MAX_TABLES) |
| 70 | return -1; |
| 71 | subselects->nr++; |
| 72 | subselects->tid[i] = tid; |
| 73 | subselects->subselect[i] = subselect; |
| 74 | return i; |
| 75 | } |
| 76 | |
| 77 | static int |
| 78 | subselect_find_tids( subselect_t *subselects, int subselect) |
| 79 | { |
| 80 | int i; |
| 81 | |
| 82 | for (i = 0; i<subselects->nr; i++) { |
| 83 | if (subselects->subselect[i] == subselect) { |
| 84 | return subselects->tid[i]; |
| 85 | } |
| 86 | } |
| 87 | return -1; |
| 88 | } |
| 89 | |
| 90 | static int |
| 91 | subselect_find_subselect( subselect_t *subselects, int tid) |
| 92 | { |
| 93 | int i; |
| 94 | |
| 95 | for (i = 0; i<subselects->nr; i++) { |
| 96 | if (subselects->tid[i] == tid) { |
| 97 | return subselects->subselect[i]; |
| 98 | } |
| 99 | } |
| 100 | return -1; |
| 101 | } |
| 102 | |
| 103 | static int |
| 104 | lastbat_arg(MalBlkPtr mb, InstrPtr p) |
| 105 | { |
| 106 | int i = 0; |
| 107 | for (i=p->retc; i<p->argc; i++) { |
| 108 | int type = getArgType(mb, p, i); |
| 109 | if (!isaBatType(type) && type != TYPE_bat) |
| 110 | break; |
| 111 | } |
| 112 | if (i < p->argc) |
| 113 | return i-1; |
| 114 | return 0; |
| 115 | } |
| 116 | |
| 117 | /* check for updates inbetween assignment to variables newv and oldv */ |
| 118 | static int |
| 119 | no_updates(InstrPtr *old, int *vars, int oldv, int newv) |
| 120 | { |
| 121 | while(newv > oldv) { |
| 122 | InstrPtr q = old[vars[newv]]; |
| 123 | |
| 124 | if (isUpdateInstruction(q)) |
| 125 | return 0; |
| 126 | newv = getArg(q, 1); |
| 127 | } |
| 128 | return 1; |
| 129 | } |
| 130 | |
| 131 | str |
| 132 | OPTpushselectImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
| 133 | { |
| 134 | int i, j, limit, slimit, actions=0, *vars, *nvars = NULL, *slices = NULL, push_down_delta = 0, nr_topn = 0, nr_likes = 0; |
| 135 | char *rslices = NULL, *oclean = NULL; |
| 136 | InstrPtr p, *old; |
| 137 | subselect_t subselects; |
| 138 | char buf[256]; |
| 139 | lng usec = GDKusec(); |
| 140 | |
| 141 | subselects = (subselect_t) {0}; |
| 142 | if( mb->errors) |
| 143 | return MAL_SUCCEED; |
| 144 | |
| 145 | (void) stk; |
| 146 | (void) pci; |
| 147 | vars= (int*) GDKzalloc(sizeof(int)* mb->vtop); |
| 148 | if( vars == NULL) |
| 149 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 150 | |
| 151 | limit = mb->stop; |
| 152 | slimit= mb->ssize; |
| 153 | old = mb->stmt; |
| 154 | |
| 155 | /* check for bailout conditions */ |
| 156 | for (i = 1; i < limit; i++) { |
| 157 | int lastbat; |
| 158 | p = old[i]; |
| 159 | |
| 160 | for (j = 0; j<p->retc; j++) { |
| 161 | int res = getArg(p, j); |
| 162 | vars[res] = i; |
| 163 | } |
| 164 | |
| 165 | if (getModuleId(p) == algebraRef && |
| 166 | (getFunctionId(p) == intersectRef || |
| 167 | getFunctionId(p) == differenceRef)) { |
| 168 | GDKfree(vars); |
| 169 | goto wrapup; |
| 170 | } |
| 171 | |
| 172 | if (isSlice(p)) |
| 173 | nr_topn++; |
| 174 | |
| 175 | if (isLikeOp(p)) |
| 176 | nr_likes++; |
| 177 | |
| 178 | if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef) |
| 179 | push_down_delta++; |
| 180 | |
| 181 | if (/* DISABLES CODE */ (0) && getModuleId(p) == sqlRef && getFunctionId(p) == tidRef) { /* rewrite equal table ids */ |
| 182 | int sname = getArg(p, 2), tname = getArg(p, 3), s; |
| 183 | |
| 184 | for (s = 0; s < subselects.nr; s++) { |
| 185 | InstrPtr q = old[vars[subselects.tid[s]]]; |
| 186 | int Qsname = getArg(q, 2), Qtname = getArg(q, 3); |
| 187 | |
| 188 | if (no_updates(old, vars, getArg(q,1), getArg(p,1)) && |
| 189 | ((sname == Qsname && tname == Qtname) || |
| 190 | (/* DISABLES CODE */ (0) && strcmp(getVarConstant(mb, sname).val.sval, getVarConstant(mb, Qsname).val.sval) == 0 && |
| 191 | strcmp(getVarConstant(mb, tname).val.sval, getVarConstant(mb, Qtname).val.sval) == 0))) { |
| 192 | clrFunction(p); |
| 193 | p->retc = 1; |
| 194 | p->argc = 2; |
| 195 | getArg(p, 1) = getArg(q, 0); |
| 196 | break; |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | lastbat = lastbat_arg(mb, p); |
| 201 | if (isSelect(p) && p->retc == 1 && |
| 202 | /* no cand list */ getArgType(mb, p, lastbat) != newBatType(TYPE_oid)) { |
| 203 | int i1 = getArg(p, 1), tid = 0; |
| 204 | InstrPtr q = old[vars[i1]]; |
| 205 | |
| 206 | /* find the table ids */ |
| 207 | while(!tid) { |
| 208 | if (getModuleId(q) == algebraRef && getFunctionId(q) == projectionRef) { |
| 209 | int i1 = getArg(q, 1); |
| 210 | InstrPtr s = old[vars[i1]]; |
| 211 | |
| 212 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
| 213 | tid = getArg(q, 1); |
| 214 | if (s->argc == 2 && s->retc == 1) { |
| 215 | int i1 = getArg(s, 1); |
| 216 | InstrPtr s = old[vars[i1]]; |
| 217 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
| 218 | tid = getArg(q, 1); |
| 219 | } |
| 220 | break; |
| 221 | } else if (isMapOp(q) && q->retc == 1 && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { |
| 222 | int i1 = getArg(q, 1); |
| 223 | q = old[vars[i1]]; |
| 224 | } else if (isMapOp(q) && q->retc == 1 && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { |
| 225 | int i2 = getArg(q, 2); |
| 226 | q = old[vars[i2]]; |
| 227 | } else { |
| 228 | break; |
| 229 | } |
| 230 | } |
| 231 | if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { |
| 232 | GDKfree(vars); |
| 233 | goto wrapup; |
| 234 | } |
| 235 | } |
| 236 | /* left hand side */ |
| 237 | if ( (GDKdebug & (1<<15)) && |
| 238 | isMatJoinOp(p) && p->retc == 2) { |
| 239 | int i1 = getArg(p, 2), tid = 0; |
| 240 | InstrPtr q = old[vars[i1]]; |
| 241 | |
| 242 | /* find the table ids */ |
| 243 | while(!tid) { |
| 244 | if (getModuleId(q) == algebraRef && getFunctionId(q) == projectionRef) { |
| 245 | int i1 = getArg(q, 1); |
| 246 | InstrPtr s = old[vars[i1]]; |
| 247 | |
| 248 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
| 249 | tid = getArg(q, 1); |
| 250 | break; |
| 251 | } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { |
| 252 | int i1 = getArg(q, 1); |
| 253 | q = old[vars[i1]]; |
| 254 | } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { |
| 255 | int i2 = getArg(q, 2); |
| 256 | q = old[vars[i2]]; |
| 257 | } else { |
| 258 | break; |
| 259 | } |
| 260 | } |
| 261 | if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { |
| 262 | GDKfree(vars); |
| 263 | goto wrapup; |
| 264 | } |
| 265 | } |
| 266 | /* right hand side */ |
| 267 | if ( (GDKdebug & (1<<15)) && |
| 268 | isMatJoinOp(p) && p->retc == 2) { |
| 269 | int i1 = getArg(p, 3), tid = 0; |
| 270 | InstrPtr q = old[vars[i1]]; |
| 271 | |
| 272 | /* find the table ids */ |
| 273 | while(!tid) { |
| 274 | if (getModuleId(q) == algebraRef && getFunctionId(q) == projectionRef) { |
| 275 | int i1 = getArg(q, 1); |
| 276 | InstrPtr s = old[vars[i1]]; |
| 277 | |
| 278 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
| 279 | tid = getArg(q, 1); |
| 280 | break; |
| 281 | } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { |
| 282 | int i1 = getArg(q, 1); |
| 283 | q = old[vars[i1]]; |
| 284 | } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { |
| 285 | int i2 = getArg(q, 2); |
| 286 | q = old[vars[i2]]; |
| 287 | } else { |
| 288 | break; |
| 289 | } |
| 290 | } |
| 291 | if (tid && subselect_add(&subselects, tid, getArg(p, 1)) < 0) { |
| 292 | GDKfree(vars); |
| 293 | goto wrapup; |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | if ((!subselects.nr && !nr_topn && !nr_likes) || newMalBlkStmt(mb, mb->ssize) <0 ) { |
| 299 | GDKfree(vars); |
| 300 | goto wrapup; |
| 301 | } |
| 302 | pushInstruction(mb,old[0]); |
| 303 | |
| 304 | for (i = 1; i < limit; i++) { |
| 305 | p = old[i]; |
| 306 | |
| 307 | /* rewrite batalgebra.like + select -> likeselect */ |
| 308 | if (getModuleId(p) == algebraRef && p->retc == 1 && getFunctionId(p) == selectRef) { |
| 309 | int var = getArg(p, 1); |
| 310 | InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ |
| 311 | |
| 312 | if (isLikeOp(q)) { /* TODO check if getArg(p, 3) value == TRUE */ |
| 313 | InstrPtr r = newInstruction(mb, algebraRef, likeselectRef); |
| 314 | int has_cand = (getArgType(mb, p, 2) == newBatType(TYPE_oid)); |
| 315 | int a, anti = (getFunctionId(q)[0] == 'n'), ignore_case = (getFunctionId(q)[anti?4:0] == 'i'); |
| 316 | |
| 317 | getArg(r,0) = getArg(p,0); |
| 318 | r = pushArgument(mb, r, getArg(q, 1)); |
| 319 | if (has_cand) |
| 320 | r = pushArgument(mb, r, getArg(p, 2)); |
| 321 | for(a = 2; a<q->argc; a++) |
| 322 | r = pushArgument(mb, r, getArg(q, a)); |
| 323 | if (r->argc < (4+has_cand)) |
| 324 | r = pushStr(mb, r, "" ); /* default esc */ |
| 325 | if (r->argc < (5+has_cand)) |
| 326 | r = pushBit(mb, r, ignore_case); |
| 327 | if (r->argc < (6+has_cand)) |
| 328 | r = pushBit(mb, r, anti); |
| 329 | freeInstruction(p); |
| 330 | p = r; |
| 331 | actions++; |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /* inject table ids into subselect |
| 336 | * s = subselect(c, C1..) => subselect(c, t, C1..) |
| 337 | */ |
| 338 | if (isSelect(p) && p->retc == 1) { |
| 339 | int tid = 0; |
| 340 | |
| 341 | if ((tid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { |
| 342 | int lastbat = lastbat_arg(mb, p); |
| 343 | if (getArgType(mb, p, lastbat) == TYPE_bat) /* empty candidate list bat_nil */ |
| 344 | getArg(p, lastbat) = tid; |
| 345 | else |
| 346 | p = PushArgument(mb, p, tid, lastbat+1); |
| 347 | /* make sure to resolve again */ |
| 348 | p->token = ASSIGNsymbol; |
| 349 | p->typechk = TYPE_UNKNOWN; |
| 350 | p->fcn = NULL; |
| 351 | p->blk = NULL; |
| 352 | actions++; |
| 353 | } |
| 354 | } |
| 355 | else if ( (GDKdebug & (1<<15)) && |
| 356 | isMatJoinOp(p) && p->retc == 2 |
| 357 | ) { |
| 358 | int ltid = 0, rtid = 0, done = 0; |
| 359 | int range = 0; |
| 360 | |
| 361 | if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0 && |
| 362 | (rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { |
| 363 | p = PushArgument(mb, p, ltid, 4+range); |
| 364 | p = PushArgument(mb, p, rtid, 5+range); |
| 365 | done = 1; |
| 366 | } else if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { |
| 367 | p = PushArgument(mb, p, ltid, 4+range); |
| 368 | p = PushNil(mb, p, 5+range, TYPE_bat); |
| 369 | done = 1; |
| 370 | } else if ((rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { |
| 371 | p = PushNil(mb, p, 4+range, TYPE_bat); |
| 372 | p = PushArgument(mb, p, rtid, 5+range); |
| 373 | done = 1; |
| 374 | } |
| 375 | if (done) { |
| 376 | p = pushBit(mb, p, FALSE); /* do not match nils */ |
| 377 | p = pushNil(mb, p, TYPE_lng); /* no estimate */ |
| 378 | |
| 379 | /* make sure to resolve again */ |
| 380 | p->token = ASSIGNsymbol; |
| 381 | p->typechk = TYPE_UNKNOWN; |
| 382 | p->fcn = NULL; |
| 383 | p->blk = NULL; |
| 384 | actions++; |
| 385 | } |
| 386 | } |
| 387 | /* Leftfetchjoins involving rewriten table ids need to be flattend |
| 388 | * l = projection(t, c); => l = c; |
| 389 | * and |
| 390 | * l = projection(s, ntids); => l = s; |
| 391 | */ |
| 392 | else if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) { |
| 393 | int var = getArg(p, 1); |
| 394 | |
| 395 | if (subselect_find_subselect(&subselects, var) > 0) { |
| 396 | InstrPtr q = newAssignment(mb); |
| 397 | |
| 398 | getArg(q, 0) = getArg(p, 0); |
| 399 | (void) pushArgument(mb, q, getArg(p, 2)); |
| 400 | actions++; |
| 401 | freeInstruction(p); |
| 402 | continue; |
| 403 | } else { /* deletes/updates use table ids */ |
| 404 | int var = getArg(p, 2); |
| 405 | InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ |
| 406 | |
| 407 | if (q->token == ASSIGNsymbol) { |
| 408 | var = getArg(q, 1); |
| 409 | q = mb->stmt[vars[var]]; |
| 410 | } |
| 411 | if (subselect_find_subselect(&subselects, var) > 0) { |
| 412 | InstrPtr qq = newAssignment(mb); |
| 413 | /* TODO: check result */ |
| 414 | |
| 415 | getArg(qq, 0) = getArg(p, 0); |
| 416 | (void) pushArgument(mb, qq, getArg(p, 1)); |
| 417 | actions++; |
| 418 | freeInstruction(p); |
| 419 | continue; |
| 420 | } |
| 421 | /* c = sql.delta(b,uid,uval,ins); |
| 422 | * l = projection(x, c); |
| 423 | * into |
| 424 | * l = sql.projectdelta(x,b,uid,uval,ins); |
| 425 | */ |
| 426 | else if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef && q->argc == 5) { |
| 427 | q = copyInstruction(q); |
| 428 | if( q == NULL){ |
| 429 | for (; i<limit; i++) |
| 430 | if (old[i]) |
| 431 | pushInstruction(mb,old[i]); |
| 432 | GDKfree(slices); |
| 433 | GDKfree(rslices); |
| 434 | GDKfree(old); |
| 435 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 436 | } |
| 437 | |
| 438 | setFunctionId(q, projectdeltaRef); |
| 439 | getArg(q, 0) = getArg(p, 0); |
| 440 | q = PushArgument(mb, q, getArg(p, 1), 1); |
| 441 | freeInstruction(p); |
| 442 | p = q; |
| 443 | actions++; |
| 444 | } |
| 445 | } |
| 446 | } |
| 447 | pushInstruction(mb,p); |
| 448 | } |
| 449 | for (; i<limit; i++) |
| 450 | if (old[i]) |
| 451 | pushInstruction(mb,old[i]); |
| 452 | for (; i<slimit; i++) |
| 453 | if (old[i]) |
| 454 | freeInstruction(old[i]); |
| 455 | GDKfree(old); |
| 456 | if (!push_down_delta) { |
| 457 | GDKfree(vars); |
| 458 | goto wrapup; |
| 459 | } |
| 460 | |
| 461 | /* now push selects through delta's */ |
| 462 | limit = mb->stop; |
| 463 | slimit= mb->ssize; |
| 464 | old = mb->stmt; |
| 465 | |
| 466 | nvars = (int*) GDKzalloc(sizeof(int)* mb->vtop); |
| 467 | slices = (int*) GDKzalloc(sizeof(int)* mb->vtop); |
| 468 | rslices = (char*) GDKzalloc(sizeof(char)* mb->vtop); |
| 469 | oclean = (char*) GDKzalloc(sizeof(char)* mb->vtop); |
| 470 | if (!nvars || !slices || !rslices || !oclean || newMalBlkStmt(mb, mb->stop+(5*push_down_delta)) <0 ) { |
| 471 | mb->stmt = old; |
| 472 | GDKfree(vars); |
| 473 | GDKfree(nvars); |
| 474 | GDKfree(slices); |
| 475 | GDKfree(rslices); |
| 476 | GDKfree(oclean); |
| 477 | goto wrapup; |
| 478 | } |
| 479 | pushInstruction(mb,old[0]); |
| 480 | |
| 481 | for (i = 1; i < limit; i++) { |
| 482 | int lastbat; |
| 483 | p = old[i]; |
| 484 | |
| 485 | for (j = 0; j<p->retc; j++) { |
| 486 | int res = getArg(p, j); |
| 487 | vars[res] = i; |
| 488 | } |
| 489 | |
| 490 | /* push subslice under projectdelta */ |
| 491 | if (isSlice(p) && p->retc == 1) { |
| 492 | int var = getArg(p, 1); |
| 493 | InstrPtr q = old[vars[var]]; |
| 494 | if (q && getModuleId(q) == sqlRef && getFunctionId(q) == projectdeltaRef) { |
| 495 | InstrPtr r = copyInstruction(p); |
| 496 | InstrPtr s = copyInstruction(q); |
| 497 | |
| 498 | rslices[getArg(q,0)] = 1; /* mark projectdelta as rewriten */ |
| 499 | rslices[getArg(p,0)] = 1; /* mark slice as rewriten */ |
| 500 | |
| 501 | if (r == NULL || s == NULL){ |
| 502 | GDKfree(vars); |
| 503 | GDKfree(nvars); |
| 504 | GDKfree(slices); |
| 505 | GDKfree(rslices); |
| 506 | GDKfree(oclean); |
| 507 | GDKfree(old); |
| 508 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 509 | } |
| 510 | |
| 511 | /* slice the candidates */ |
| 512 | setFunctionId(r, sliceRef); |
| 513 | nvars[getArg(p,0)] = getArg(r, 0) = |
| 514 | newTmpVariable(mb, getArgType(mb, r, 0)); |
| 515 | slices[getArg(q, 1)] = getArg(p, 0); |
| 516 | |
| 517 | setVarCList(mb,getArg(r,0)); |
| 518 | getArg(r, 1) = getArg(s, 1); |
| 519 | pushInstruction(mb,r); |
| 520 | |
| 521 | nvars[getArg(q,0)] = getArg(s, 0) = |
| 522 | newTmpVariable(mb, getArgType(mb, s, 0)); |
| 523 | getArg(s, 1) = getArg(r, 0); /* use result of slice */ |
| 524 | pushInstruction(mb, s); |
| 525 | oclean[i] = 1; |
| 526 | actions++; |
| 527 | continue; |
| 528 | } |
| 529 | } |
| 530 | /* Leftfetchjoins involving rewriten sliced candidates ids need to be flattend |
| 531 | * l = projection(t, c); => l = c; |
| 532 | * and |
| 533 | * l = projection(s, ntids); => l = s; |
| 534 | */ |
| 535 | else if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) { |
| 536 | int var = getArg(p, 1); |
| 537 | InstrPtr r = old[vars[var]], q; |
| 538 | |
| 539 | if (r && isSlice(r) && rslices[var] && getArg(r, 0) == getArg(p, 1)) { |
| 540 | int col = getArg(p, 2); |
| 541 | |
| 542 | if (!rslices[col]) { /* was the deltaproject rewriten (sliced) */ |
| 543 | InstrPtr s = old[vars[col]], u = NULL; |
| 544 | |
| 545 | if (s && getModuleId(s) == algebraRef && getFunctionId(s) == projectRef) { |
| 546 | col = getArg(s, 1); |
| 547 | u = s; |
| 548 | s = old[vars[col]]; |
| 549 | } |
| 550 | if (s && getModuleId(s) == sqlRef && getFunctionId(s) == projectdeltaRef) { |
| 551 | InstrPtr t = copyInstruction(s); |
| 552 | if (t == NULL){ |
| 553 | GDKfree(vars); |
| 554 | GDKfree(nvars); |
| 555 | GDKfree(slices); |
| 556 | GDKfree(rslices); |
| 557 | GDKfree(oclean); |
| 558 | GDKfree(old); |
| 559 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 560 | } |
| 561 | |
| 562 | getArg(t, 1) = nvars[getArg(r, 0)]; /* use result of slice */ |
| 563 | rslices[col] = 1; |
| 564 | nvars[getArg(s,0)] = getArg(t, 0) = |
| 565 | newTmpVariable(mb, getArgType(mb, t, 0)); |
| 566 | pushInstruction(mb, t); |
| 567 | if (u) { /* add again */ |
| 568 | if((t = copyInstruction(u)) == NULL) { |
| 569 | GDKfree(vars); |
| 570 | GDKfree(nvars); |
| 571 | GDKfree(slices); |
| 572 | GDKfree(rslices); |
| 573 | GDKfree(oclean); |
| 574 | GDKfree(old); |
| 575 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 576 | } |
| 577 | getArg(t, 1) = nvars[getArg(t,1)]; |
| 578 | pushInstruction(mb, t); |
| 579 | } |
| 580 | } |
| 581 | } |
| 582 | q = newAssignment(mb); |
| 583 | getArg(q, 0) = getArg(p, 0); |
| 584 | (void) pushArgument(mb, q, getArg(p, 2)); |
| 585 | if (nvars[getArg(p, 2)] > 0) |
| 586 | getArg(q, 1) = nvars[getArg(p, 2)]; |
| 587 | oclean[i] = 1; |
| 588 | actions++; |
| 589 | continue; |
| 590 | } |
| 591 | } else if (p->argc >= 2 && slices[getArg(p, 1)] != 0) { |
| 592 | /* use new slice candidate list */ |
| 593 | assert(slices[getArg(p,1)] == nvars[getArg(p,1)]); |
| 594 | getArg(p, 1) = slices[getArg(p, 1)]; |
| 595 | } |
| 596 | /* remap */ |
| 597 | for (j = p->retc; j<p->argc; j++) { |
| 598 | int var = getArg(p, j); |
| 599 | if (nvars[var] > 0) { |
| 600 | getArg(p, j) = nvars[var]; |
| 601 | } |
| 602 | } |
| 603 | |
| 604 | /* c = delta(b, uid, uvl, ins) |
| 605 | * s = select(c, C1..) |
| 606 | * |
| 607 | * nc = select(b, C1..) |
| 608 | * ni = select(ins, C1..) |
| 609 | * nu = select(uvl, C1..) |
| 610 | * s = subdelta(nc, uid, nu, ni); |
| 611 | * |
| 612 | * doesn't handle Xselect(x, .. z, C1.. cases) ie multicolumn selects |
| 613 | */ |
| 614 | lastbat = lastbat_arg(mb, p); |
| 615 | if (isSelect(p) && p->retc == 1 && lastbat == 2) { |
| 616 | int var = getArg(p, 1); |
| 617 | InstrPtr q = old[vars[var]]; |
| 618 | |
| 619 | if (q && q->token == ASSIGNsymbol) { |
| 620 | var = getArg(q, 1); |
| 621 | q = old[vars[var]]; |
| 622 | } |
| 623 | if (q && getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef) { |
| 624 | InstrPtr r = copyInstruction(p); |
| 625 | InstrPtr s = copyInstruction(p); |
| 626 | InstrPtr t = copyInstruction(p); |
| 627 | InstrPtr u = copyInstruction(q); |
| 628 | |
| 629 | if( r == NULL || s == NULL || t== NULL ||u == NULL){ |
| 630 | freeInstruction(r); |
| 631 | freeInstruction(s); |
| 632 | freeInstruction(t); |
| 633 | freeInstruction(u); |
| 634 | GDKfree(vars); |
| 635 | GDKfree(nvars); |
| 636 | GDKfree(slices); |
| 637 | GDKfree(rslices); |
| 638 | GDKfree(oclean); |
| 639 | GDKfree(old); |
| 640 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 641 | } |
| 642 | getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid)); |
| 643 | setVarCList(mb,getArg(r,0)); |
| 644 | getArg(r, 1) = getArg(q, 1); /* column */ |
| 645 | r->typechk = TYPE_UNKNOWN; |
| 646 | pushInstruction(mb,r); |
| 647 | getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid)); |
| 648 | setVarCList(mb,getArg(s,0)); |
| 649 | getArg(s, 1) = getArg(q, 3); /* updates */ |
| 650 | s = ReplaceWithNil(mb, s, 2, TYPE_bat); /* no candidate list */ |
| 651 | setArgType(mb, s, 2, newBatType(TYPE_oid)); |
| 652 | /* make sure to resolve again */ |
| 653 | s->token = ASSIGNsymbol; |
| 654 | s->typechk = TYPE_UNKNOWN; |
| 655 | s->fcn = NULL; |
| 656 | s->blk = NULL; |
| 657 | pushInstruction(mb,s); |
| 658 | getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_oid)); |
| 659 | setVarCList(mb,getArg(t,0)); |
| 660 | getArg(t, 1) = getArg(q, 4); /* inserts */ |
| 661 | pushInstruction(mb,t); |
| 662 | |
| 663 | setFunctionId(u, subdeltaRef); |
| 664 | getArg(u, 0) = getArg(p,0); |
| 665 | getArg(u, 1) = getArg(r,0); |
| 666 | getArg(u, 2) = getArg(p,2); /* pre-cands */ |
| 667 | getArg(u, 3) = getArg(q,2); /* update ids */ |
| 668 | getArg(u, 4) = getArg(s,0); |
| 669 | u = pushArgument(mb, u, getArg(t,0)); |
| 670 | u->typechk = TYPE_UNKNOWN; |
| 671 | pushInstruction(mb,u); |
| 672 | oclean[i] = 1; |
| 673 | continue; |
| 674 | } |
| 675 | } |
| 676 | pushInstruction(mb,p); |
| 677 | } |
| 678 | for (j=1; j<i; j++) |
| 679 | if (old[j] && oclean[j]) |
| 680 | freeInstruction(old[j]); |
| 681 | for (; i<limit; i++) |
| 682 | if (old[i]) |
| 683 | freeInstruction(old[i]); |
| 684 | //pushInstruction(mb,old[i]); |
| 685 | GDKfree(vars); |
| 686 | GDKfree(nvars); |
| 687 | GDKfree(slices); |
| 688 | GDKfree(rslices); |
| 689 | GDKfree(oclean); |
| 690 | GDKfree(old); |
| 691 | |
| 692 | /* Defense line against incorrect plans */ |
| 693 | if( actions > 0){ |
| 694 | chkTypes(cntxt->usermodule, mb, FALSE); |
| 695 | chkFlow(mb); |
| 696 | chkDeclarations(mb); |
| 697 | } |
| 698 | wrapup: |
| 699 | /* keep all actions taken as a post block comment */ |
| 700 | usec = GDKusec()- usec; |
| 701 | snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec" ,"pushselect" ,actions, usec); |
| 702 | newComment(mb,buf); |
| 703 | if( actions >= 0) |
| 704 | addtoMalBlkHistory(mb); |
| 705 | |
| 706 | if( OPTdebug & OPTpushselect){ |
| 707 | fprintf(stderr, "#PUSHSELECT optimizer exit\n" ); |
| 708 | fprintFunction(stderr, mb, 0, LIST_MAL_ALL); |
| 709 | } |
| 710 | return MAL_SUCCEED; |
| 711 | } |
| 712 | |