/* returns table rids, for the given select ranges */ static rids * rids_select( sql_trans *tr, sql_column *key, void *key_value_low, void *key_value_high, ...) { va_list va; BAT *b = NULL, *s = NULL, *d = NULL; sql_column *nc; void *nvl, *nvh; rids *rs = ZNEW(rids); sql_dbat *bat = key->t->data; /* special case, key_value_low and high NULL, ie return all */ if (bat->dbid) d = store_funcs.bind_del(tr, key->t, RDONLY); if (key_value_low || key_value_high) { va_start(va, key_value_high); while ((nc = va_arg(va, sql_column *)) != NULL) { nvl = va_arg(va, void *); nvh = va_arg(va, void *); b = full_column(key, d, s); if (s) bat_destroy(s); if (!key_value_low) key_value_low = ATOMnilptr(b->ttype); if (!key_value_high) key_value_high = ATOMnilptr(b->ttype); s = BATselect(b, key_value_low, key_value_high); bat_destroy(b); key = nc; key_value_low = nvl; key_value_high = nvh; } va_end(va); }
void GDKqsort_rev(void *h, void *t, const void *base, size_t n, int hs, int ts, int tpe) { struct qsort_t buf; assert(hs > 0); assert(ts >= 0); assert(tpe != TYPE_void); buf.hs = (unsigned int) hs; buf.ts = (unsigned int) ts; buf.cmp = BATatoms[tpe].atomCmp; buf.base = base; if (ATOMvarsized(tpe)) { assert(base != NULL); GDKqsort_impl_var_rev(&buf, h, t, n); return; } if (base) tpe = TYPE_str; /* we need the default case */ if (tpe != ATOMstorage(tpe) && ATOMnilptr(ATOMstorage(tpe)) == ATOMnilptr(tpe) && BATatoms[ATOMstorage(tpe)].atomCmp == BATatoms[tpe].atomCmp) tpe = ATOMstorage(tpe); switch (tpe) { case TYPE_bte: GDKqsort_impl_bte_rev(&buf, h, t, n); break; case TYPE_sht: GDKqsort_impl_sht_rev(&buf, h, t, n); break; case TYPE_int: GDKqsort_impl_int_rev(&buf, h, t, n); break; case TYPE_lng: GDKqsort_impl_lng_rev(&buf, h, t, n); break; #ifdef HAVE_HGE case TYPE_hge: GDKqsort_impl_hge_rev(&buf, h, t, n); break; #endif case TYPE_flt: GDKqsort_impl_flt_rev(&buf, h, t, n); break; case TYPE_dbl: GDKqsort_impl_dbl_rev(&buf, h, t, n); break; default: GDKqsort_impl_any_rev(&buf, h, t, n); break; } }
atom * atom_general(sql_allocator *sa, sql_subtype *tpe, char *val) { atom *a; ptr p = NULL; if (atom_debug) fprintf(stderr, "atom_general(%s,%s)\n", tpe->type->sqlname, val); if (tpe->type->localtype == TYPE_str) return atom_string(sa, tpe, val); a = atom_create(sa); a->tpe = *tpe; a->data.val.pval = NULL; a->data.vtype = tpe->type->localtype; a->data.len = 0; assert(a->data.vtype >= 0); if (val) { int type = a->data.vtype; a->isnull = 0; if (ATOMstorage(type) == TYPE_str) { a->isnull = 0; a->data.val.sval = sql2str(sa_strdup(sa, val)); a->data.len = (int)strlen(a->data.val.sval); } else { int res = ATOMfromstr(type, &p, &a->data.len, val); /* no result or nil means error (SQL has NULL not nil) */ if (res < 0 || !p || ATOMcmp(type, p, ATOMnilptr(type)) == 0) { /*_DELETE(val);*/ if (p) GDKfree(p); return NULL; } VALset(&a->data, a->data.vtype, p); SA_VALcopy(sa, &a->data, &a->data); if (p && ATOMextern(a->data.vtype) == 0) GDKfree(p); /*_DELETE(val);*/ } } else { p = ATOMnilptr(a->data.vtype); VALset(&a->data, a->data.vtype, p); a->isnull = 1; } return a; }
/* Return TRUE if the value in V is NIL. */ int VALisnil(const ValRecord *v) { switch (v->vtype) { case TYPE_void: return 1; case TYPE_bte: return v->val.btval == bte_nil; case TYPE_sht: return v->val.shval == sht_nil; case TYPE_int: return v->val.ival == int_nil; case TYPE_wrd: return v->val.wval == wrd_nil; case TYPE_lng: return v->val.lval == lng_nil; #ifdef HAVE_HGE case TYPE_hge: return v->val.hval == hge_nil; #endif case TYPE_flt: return v->val.fval == flt_nil; case TYPE_dbl: return v->val.dval == dbl_nil; case TYPE_oid: return v->val.oval == oid_nil; case TYPE_bat: return v->val.bval == bat_nil || v->val.bval == 0; default: break; } return (*ATOMcompare(v->vtype))(VALptr(v), ATOMnilptr(v->vtype)) == 0; }
int VALcmp(const ValRecord *p, const ValRecord *q) { int (*cmp)(const void *, const void *); int tpe; const void *nilptr, *pp, *pq; if (p == 0 || q == 0) return -1; if ((tpe = p->vtype) != q->vtype) return -1; if (tpe == TYPE_ptr) return 0; /* ignore comparing C pointers */ cmp = BATatoms[tpe].atomCmp; nilptr = ATOMnilptr(tpe); pp = VALptr(p); pq = VALptr(q); if ((*cmp)(pp, nilptr) == 0 && (*cmp)(pq, nilptr) == 0) return 0; /* eq nil val */ if ((*cmp)(pp, nilptr) == 0 || (*cmp)(pq, nilptr) == 0) return -1; return (*cmp)(pp, pq); }
/* Return TRUE if the value in V is NIL. */ int VALisnil(const ValRecord *v) { switch (v->vtype) { case TYPE_void: return 1; case TYPE_bte: return is_bte_nil(v->val.btval); case TYPE_sht: return is_sht_nil(v->val.shval); case TYPE_int: return is_int_nil(v->val.ival); case TYPE_lng: return is_lng_nil(v->val.lval); #ifdef HAVE_HGE case TYPE_hge: return is_hge_nil(v->val.hval); #endif case TYPE_flt: return is_flt_nil(v->val.fval); case TYPE_dbl: return is_dbl_nil(v->val.dval); case TYPE_oid: return is_oid_nil(v->val.oval); case TYPE_bat: return is_bat_nil(v->val.bval); default: break; } return (*ATOMcompare(v->vtype))(VALptr(v), ATOMnilptr(v->vtype)) == 0; }
int VALisnil(const ValRecord *v) { switch (v->vtype) { case TYPE_void: return 1; case TYPE_bte: return v->val.btval == bte_nil; case TYPE_sht: return v->val.shval == sht_nil; case TYPE_int: case TYPE_bat: return v->val.ival == int_nil; case TYPE_lng: return v->val.lval == lng_nil; #ifdef HAVE_HGE case TYPE_hge: return v->val.hval == hge_nil; #endif case TYPE_flt: return v->val.fval == flt_nil; case TYPE_dbl: return v->val.dval == dbl_nil; default: break; } return (*BATatoms[v->vtype].atomCmp)(VALptr(v), ATOMnilptr(v->vtype)) == 0; }
/* Clear V to an empty value (type void, value nil), freeing any * memory allocated for external types. See VALempty for when V does * not yet contain a value. */ void VALclear(ValPtr v) { if (ATOMextern(v->vtype)) { if (v->val.pval && v->val.pval != ATOMnilptr(v->vtype)) GDKfree(v->val.pval); } VALempty(v); }
ptr ATOMnil(int t) { const void *src = ATOMnilptr(t); size_t len = ATOMlen(ATOMtype(t), src); ptr dst = GDKmalloc(len); if (dst) memcpy(dst, src, len); return dst; }
str str_2_timestamp(timestamp *res, const str *val) { ptr p = NULL; int len = 0; int e; char buf[BUFSIZ]; e = ATOMfromstr(TYPE_timestamp, &p, &len, *val); if (e < 0 || !p || (ATOMcmp(TYPE_timestamp, p, ATOMnilptr(TYPE_timestamp)) == 0 && ATOMcmp(TYPE_str, *val, ATOMnilptr(TYPE_str)) != 0)) { if (p) GDKfree(p); snprintf(buf, BUFSIZ, "conversion of string '%s' failed", *val? *val:""); throw(SQL, "timestamp", "%s", buf); } *res = *(timestamp *) p; if (!ATOMextern(TYPE_timestamp)) { if (p) GDKfree(p); } return MAL_SUCCEED; }
/* variable management */ static void stack_set(mvc *sql, int var, const char *name, sql_subtype *type, sql_rel *rel, sql_table *t, int view, int frame) { sql_var *v; if (var == sql->sizevars) { sql->sizevars <<= 1; sql->vars = RENEW_ARRAY(sql_var,sql->vars,sql->sizevars); } v = sql->vars+var; v->name = NULL; v->value.vtype = 0; v->rel = rel; v->t = t; v->view = view; v->frame = frame; v->type.type = NULL; if (type) { int tpe = type->type->localtype; VALinit(&sql->vars[var].value, tpe, ATOMnilptr(tpe)); v->type = *type; } if (name) v->name = _STRDUP(name); }
str MKEYbathash(bat *res, const bat *bid) { BAT *b, *dst; wrd *r; BUN n; if ((b = BATdescriptor(*bid)) == NULL) throw(SQL, "mkey.bathash", RUNTIME_OBJECT_MISSING); assert(BAThvoid(b) || BAThrestricted(b)); n = BATcount(b); dst = BATnew(TYPE_void, TYPE_wrd, n, TRANSIENT); if (dst == NULL) { BBPunfix(b->batCacheid); throw(SQL, "mkey.bathash", MAL_MALLOC_FAIL); } BATseqbase(dst, b->hseqbase); BATsetcount(dst, n); r = (wrd *) Tloc(dst, BUNfirst(dst)); switch (ATOMstorage(b->ttype)) { case TYPE_void: { oid o = b->tseqbase; if (o == oid_nil) while (n-- > 0) *r++ = wrd_nil; else while (n-- > 0) *r++ = (wrd) o++; break; } case TYPE_bte: { bte *v = (bte *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_bte(v); v++; } break; } case TYPE_sht: { sht *v = (sht *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_sht(v); v++; } break; } case TYPE_int: case TYPE_flt: { int *v = (int *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_int(v); v++; } break; } case TYPE_lng: case TYPE_dbl: { lng *v = (lng *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_lng(v); v++; } break; } #ifdef HAVE_HGE case TYPE_hge: { hge *v = (hge *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_hge(v); v++; } break; } #endif default: { BATiter bi = bat_iterator(b); BUN (*hash)(const void *) = BATatoms[b->ttype].atomHash; int (*cmp)(const void *, const void *) = ATOMcompare(b->ttype); void *nil = ATOMnilptr(b->ttype); BUN i; const void *v; BATloop(b, i, n) { v = BUNtail(bi, i); if ((*cmp)(v, nil) == 0) *r++ = wrd_nil; else *r++ = (wrd) (*hash)(v); } break; } }
/* returns table rids, for the given select ranges */ static rids * rids_select( sql_trans *tr, sql_column *key, const void *key_value_low, const void *key_value_high, ...) { va_list va; BAT *b = NULL, *r = NULL, *s = NULL; rids *rs = ZNEW(rids); const void *kvl = key_value_low, *kvh = key_value_high; /* if pointers are equal, make it an inclusive select */ bool hi = key_value_low == key_value_high; if(!rs) return NULL; s = delta_cands(tr, key->t); if (s == NULL) { GDKfree(rs); return NULL; } b = full_column(tr, key); if (b == NULL) { bat_destroy(s); GDKfree(rs); return NULL; } if (!kvl) kvl = ATOMnilptr(b->ttype); if (!kvh && kvl != ATOMnilptr(b->ttype)) kvh = ATOMnilptr(b->ttype); if (key_value_low) { BAThash(b); r = BATselect(b, s, kvl, kvh, true, hi, false); bat_destroy(s); s = r; } full_destroy(key, b); if (s == NULL) { GDKfree(rs); return NULL; } if (key_value_low || key_value_high) { va_start(va, key_value_high); while ((key = va_arg(va, sql_column *)) != NULL) { kvl = va_arg(va, void *); kvh = va_arg(va, void *); b = full_column(tr, key); if (!kvl) kvl = ATOMnilptr(b->ttype); if (!kvh && kvl != ATOMnilptr(b->ttype)) kvh = ATOMnilptr(b->ttype); assert(kvh); r = BATselect(b, s, kvl, kvh, true, hi, false); bat_destroy(s); s = r; full_destroy(key, b); if (s == NULL) { GDKfree(rs); va_end(va); return NULL; } } va_end(va); }
static ssize_t numFromStr(const char *src, size_t *len, void **dst, int tp, bool external) { const char *p = src; size_t sz = ATOMsize(tp); #ifdef HAVE_HGE hge base = 0; #else lng base = 0; #endif int sign = 1; /* a valid number has the following syntax: * [-+]?[0-9]+([eE][0-9]+)?(LL)? -- PCRE syntax, or in other words * optional sign, one or more digits, optional exponent, optional LL * the exponent has the following syntax: * lower or upper case letter E, one or more digits * embedded spaces are not allowed * the optional LL at the end are only allowed for lng and hge * values */ atommem(sz); if (GDK_STRNIL(src)) { memcpy(*dst, ATOMnilptr(tp), sz); return 1; } while (GDKisspace(*p)) p++; if (!num10(*p)) { switch (*p) { case 'n': if (external) { memcpy(*dst, ATOMnilptr(tp), sz); if (p[1] == 'i' && p[2] == 'l') { p += 3; return (ssize_t) (p - src); } } GDKerror("not a number"); goto bailout; case '-': sign = -1; p++; break; case '+': p++; break; } if (!num10(*p)) { GDKerror("not a number"); goto bailout; } } do { int dig = base10(*p); if (base > maxdiv[1].maxval || (base == maxdiv[1].maxval && dig > maxmod10)) { /* overflow */ goto overflow; } base = 10 * base + dig; p++; } while (num10(*p)); if ((*p == 'e' || *p == 'E') && num10(p[1])) { p++; if (base == 0) { /* if base is 0, any exponent will do, the * result is still 0 */ while (num10(*p)) p++; } else { int exp = 0; do { /* this calculation cannot overflow */ exp = exp * 10 + base10(*p); if (exp >= (int) (sizeof(maxdiv) / sizeof(maxdiv[0]))) { /* overflow */ goto overflow; } p++; } while (num10(*p)); if (base > maxdiv[exp].maxval) { /* overflow */ goto overflow; } base *= maxdiv[exp].scale; } } base *= sign; switch (sz) { case 1: { bte **dstbte = (bte **) dst; if (base < GDK_bte_min || base > GDK_bte_max) { goto overflow; } **dstbte = (bte) base; break; } case 2: { sht **dstsht = (sht **) dst; if (base < GDK_sht_min || base > GDK_sht_max) { goto overflow; } **dstsht = (sht) base; break; } case 4: { int **dstint = (int **) dst; if (base < GDK_int_min || base > GDK_int_max) { goto overflow; } **dstint = (int) base; break; } case 8: { lng **dstlng = (lng **) dst; #ifdef HAVE_HGE if (base < GDK_lng_min || base > GDK_lng_max) { goto overflow; } #endif **dstlng = (lng) base; if (p[0] == 'L' && p[1] == 'L') p += 2; break; } #ifdef HAVE_HGE case 16: { hge **dsthge = (hge **) dst; **dsthge = (hge) base; if (p[0] == 'L' && p[1] == 'L') p += 2; break; } #endif } while (GDKisspace(*p)) p++; return (ssize_t) (p - src); overflow: while (num10(*p)) p++; GDKerror("overflow: \"%.*s\" does not fit in %s\n", (int) (p - src), src, ATOMname(tp)); bailout: memcpy(*dst, ATOMnilptr(tp), sz); return -1; }
str FITSloadTable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { mvc *m = NULL; sql_schema *sch; sql_table *fits_fl, *fits_tbl, *tbl = NULL; sql_column *col; sql_subtype tpe; fitsfile *fptr; str tname = *getArgReference_str(stk, pci, 1); str fname; str msg = MAL_SUCCEED; oid rid = oid_nil, frid = oid_nil; int status = 0, cnum = 0, *fid, *hdu, hdutype, j, anynull = 0, mtype; int *tpcode = NULL; long *rep = NULL, *wid = NULL, rows; /* type long used by fits library */ char keywrd[80], **cname, nm[FLEN_VALUE]; ptr nilptr; if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != MAL_SUCCEED) return msg; if ((msg = checkSQLContext(cntxt)) != MAL_SUCCEED) return msg; sch = mvc_bind_schema(m, "sys"); fits_tbl = mvc_bind_table(m, sch, "fits_tables"); if (fits_tbl == NULL) { msg = createException(MAL, "fits.loadtable", "FITS catalog is missing.\n"); return msg; } tbl = mvc_bind_table(m, sch, tname); if (tbl) { msg = createException(MAL, "fits.loadtable", "Table %s is already created.\n", tname); return msg; } col = mvc_bind_column(m, fits_tbl, "name"); rid = table_funcs.column_find_row(m->session->tr, col, tname, NULL); if (rid == oid_nil) { msg = createException(MAL, "fits.loadtable", "Table %s is unknown in FITS catalog. Attach first the containing file\n", tname); return msg; } /* Open FITS file and move to the table HDU */ col = mvc_bind_column(m, fits_tbl, "file_id"); fid = (int*)table_funcs.column_find_value(m->session->tr, col, rid); fits_fl = mvc_bind_table(m, sch, "fits_files"); col = mvc_bind_column(m, fits_fl, "id"); frid = table_funcs.column_find_row(m->session->tr, col, (void *)fid, NULL); GDKfree(fid); col = mvc_bind_column(m, fits_fl, "name"); fname = (char *)table_funcs.column_find_value(m->session->tr, col, frid); if (fits_open_file(&fptr, fname, READONLY, &status)) { msg = createException(MAL, "fits.loadtable", "Missing FITS file %s.\n", fname); GDKfree(fname); return msg; } GDKfree(fname); col = mvc_bind_column(m, fits_tbl, "hdu"); hdu = (int*)table_funcs.column_find_value(m->session->tr, col, rid); fits_movabs_hdu(fptr, *hdu, &hdutype, &status); if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) { msg = createException(MAL, "fits.loadtable", "HDU %d is not a table.\n", *hdu); GDKfree(hdu); fits_close_file(fptr, &status); return msg; } GDKfree(hdu); /* create a SQL table to hold the FITS table */ /* col = mvc_bind_column(m, fits_tbl, "columns"); cnum = *(int*) table_funcs.column_find_value(m->session->tr, col, rid); */ fits_get_num_cols(fptr, &cnum, &status); tbl = mvc_create_table(m, sch, tname, tt_table, 0, SQL_PERSIST, 0, cnum); tpcode = (int *)GDKzalloc(sizeof(int) * cnum); rep = (long *)GDKzalloc(sizeof(long) * cnum); wid = (long *)GDKzalloc(sizeof(long) * cnum); cname = (char **)GDKzalloc(sizeof(char *) * cnum); for (j = 1; j <= cnum; j++) { /* fits_get_acolparms(fptr, j, cname, &tbcol, tunit, tform, &tscal, &tzero, tnull, tdisp, &status); */ snprintf(keywrd, 80, "TTYPE%d", j); fits_read_key(fptr, TSTRING, keywrd, nm, NULL, &status); if (status) { snprintf(nm, FLEN_VALUE, "column_%d", j); status = 0; } cname[j - 1] = toLower(nm); fits_get_coltype(fptr, j, &tpcode[j - 1], &rep[j - 1], &wid[j - 1], &status); fits2subtype(&tpe, tpcode[j - 1], rep[j - 1], wid[j - 1]); /* fprintf(stderr,"#%d %ld %ld - M: %s\n", tpcode[j-1], rep[j-1], wid[j-1], tpe.type->sqlname); */ mvc_create_column(m, tbl, cname[j - 1], &tpe); } /* data load */ fits_get_num_rows(fptr, &rows, &status); fprintf(stderr,"#Loading %ld rows in table %s\n", rows, tname); for (j = 1; j <= cnum; j++) { BAT *tmp = NULL; int time0 = GDKms(); mtype = fits2mtype(tpcode[j - 1]); nilptr = ATOMnilptr(mtype); col = mvc_bind_column(m, tbl, cname[j - 1]); tmp = BATnew(TYPE_void, mtype, rows, TRANSIENT); if ( tmp == NULL){ GDKfree(tpcode); GDKfree(rep); GDKfree(wid); GDKfree(cname); throw(MAL,"fits.load", MAL_MALLOC_FAIL); } BATseqbase(tmp, 0); if (mtype != TYPE_str) { fits_read_col(fptr, tpcode[j - 1], j, 1, 1, rows, nilptr, (void *)BUNtloc(bat_iterator(tmp), BUNfirst(tmp)), &anynull, &status); BATsetcount(tmp, rows); tmp->tsorted = 0; tmp->trevsorted = 0; } else { /* char *v = GDKzalloc(wid[j-1]);*/ /* type long demanded by "rows", i.e., by fits library */ long bsize = 50, batch = bsize, k, i; int tm0, tloadtm = 0, tattachtm = 0; char **v = (char **) GDKzalloc(sizeof(char *) * bsize); for(i = 0; i < bsize; i++) v[i] = GDKzalloc(wid[j-1]); for(i = 0; i < rows; i += batch) { batch = rows - i < bsize ? rows - i: bsize; tm0 = GDKms(); fits_read_col(fptr, tpcode[j - 1], j, 1 + i, 1, batch, nilptr, (void *)v, &anynull, &status); tloadtm += GDKms() - tm0; tm0 = GDKms(); for(k = 0; k < batch ; k++) BUNappend(tmp, v[k], TRUE); tattachtm += GDKms() - tm0; } for(i = 0; i < bsize ; i++) GDKfree(v[i]); GDKfree(v); fprintf(stderr,"#String column load %d ms, BUNappend %d ms\n", tloadtm, tattachtm); } if (status) { char buf[FLEN_ERRMSG + 1]; fits_read_errmsg(buf); msg = createException(MAL, "fits.loadtable", "Cannot load column %s of %s table: %s.\n", cname[j - 1], tname, buf); break; } fprintf(stderr,"#Column %s loaded for %d ms\t", cname[j-1], GDKms() - time0); store_funcs.append_col(m->session->tr, col, tmp, TYPE_bat); fprintf(stderr,"#Total %d ms\n", GDKms() - time0); BBPunfix(tmp->batCacheid); } GDKfree(tpcode); GDKfree(rep); GDKfree(wid); GDKfree(cname); fits_close_file(fptr, &status); return msg; }
str CMDifthen(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { BAT *b = NULL, *b1 = NULL, *b2 = NULL, *bn; int tp0, tp1, tp2; bat *ret; BUN cnt = BUN_NONE; (void) cntxt; (void) mb; if (pci->argc != 4) throw(MAL, "batcalc.ifthen", "Operation not supported."); ret = getArgReference_bat(stk, pci, 0); tp0 = stk->stk[getArg(pci, 1)].vtype; tp1 = stk->stk[getArg(pci, 2)].vtype; tp2 = stk->stk[getArg(pci, 3)].vtype; if (tp0 == TYPE_bat || isaBatType(tp0)) { b = BATdescriptor(* getArgReference_bat(stk, pci, 1)); if (b == NULL) throw(MAL, "batcalc.ifthenelse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); cnt = BATcount(b); } if (tp1 == TYPE_bat || isaBatType(tp1)) { b1 = BATdescriptor(* getArgReference_bat(stk, pci, 2)); if (b1 == NULL) { if (b) BBPunfix(b->batCacheid); throw(MAL, "batcalc.ifthenelse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); } if (cnt == BUN_NONE) cnt = BATcount(b1); else if (BATcount(b1) != cnt) { BBPunfix(b->batCacheid); throw(MAL, "batcalc.ifthenelse", ILLEGAL_ARGUMENT); } } if (tp2 == TYPE_bat || isaBatType(tp2)) { b2 = BATdescriptor(* getArgReference_bat(stk, pci, 3)); if (b2 == NULL) { if (b) BBPunfix(b->batCacheid); if (b1) BBPunfix(b1->batCacheid); throw(MAL, "batcalc.ifthenelse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); } if (cnt == BUN_NONE) cnt = BATcount(b2); else if (BATcount(b2) != cnt) { if (b) BBPunfix(b->batCacheid); if (b1) BBPunfix(b1->batCacheid); throw(MAL, "batcalc.ifthenelse", ILLEGAL_ARGUMENT); } } if (b == NULL && b1 == NULL && b2 == NULL) { /* at least one BAT required */ throw(MAL, "batcalc.ifthenelse", ILLEGAL_ARGUMENT); } if (b != NULL) { if (b1 != NULL) { if (b2 != NULL) { bn = BATcalcifthenelse(b, b1, b2); } else { bn = BATcalcifthenelsecst(b, b1, &stk->stk[getArg(pci, 3)]); } } else { if (b2 != NULL) { bn = BATcalcifthencstelse(b, &stk->stk[getArg(pci, 2)], b2); } else { bn = BATcalcifthencstelsecst(b, &stk->stk[getArg(pci, 2)], &stk->stk[getArg(pci, 3)]); } } } else { bit v = *getArgReference_bit(stk, pci, 1); if (is_bit_nil(v)) { if (b1 != NULL) bn = BATconstant(b1->hseqbase, b1->ttype, ATOMnilptr(b1->ttype), BATcount(b1), TRANSIENT); else bn = BATconstant(b2->hseqbase, b2->ttype, ATOMnilptr(b2->ttype), BATcount(b2), TRANSIENT); } else if (v) { if (b1 != NULL) bn = COLcopy(b1, b1->ttype, 0, TRANSIENT); else bn = BATconstant(b2->hseqbase, b2->ttype, VALptr(&stk->stk[getArg(pci, 2)]), BATcount(b2), TRANSIENT); } else { if (b2 != NULL) bn = COLcopy(b2, b2->ttype, 0, TRANSIENT); else bn = BATconstant(b1->hseqbase, b1->ttype, VALptr(&stk->stk[getArg(pci, 3)]), BATcount(b1), TRANSIENT); } } if (b) BBPunfix(b->batCacheid); if (b1) BBPunfix(b1->batCacheid); if (b2) BBPunfix(b2->batCacheid); if (bn == NULL) { return mythrow(MAL, "batcalc.ifthenelse", OPERATION_FAILED); } BBPkeepref(*ret = bn->batCacheid); return MAL_SUCCEED; }
int OPTpushrangesImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i,j, limit,actions=0; InstrPtr p, *old; int x,y,z; Range range; if( mb->errors) return 0; range= (Range) GDKzalloc(mb->vtop * sizeof(RangeRec)); if (range == NULL) return 0; OPTDEBUGpushranges mnstr_printf(cntxt->fdout,"#Range select optimizer started\n"); (void) stk; (void) pci; limit = mb->stop; old = mb->stmt; /* * In phase I we collect information about constants */ for (i = 0; i < limit; i++) { p = old[i]; if( p->barrier) break; /* end of optimizer */ for(j=p->retc; j< p->argc; j++) range[getArg(p,j)].used++; for(j=0; j<p->retc; j++){ range[getArg(p,j)].lastupdate= i; if( range[getArg(p,j)].lastrange == 0) range[getArg(p,j)].lastrange= i; } if( getModuleId(p)== algebraRef && ( getFunctionId(p)== selectRef || getFunctionId(p)== uselectRef) ){ /* * The operation X:= algebra.select(Y,L,H,Li,Hi) is analysed. * First, we attempt to propagate the range known for Y onto the * requested range of X. This may lead to smaller range of * even the conclusion that X is necessarily empty. * Of course, only under the condition that Y has not been changed by a * side-effect since it was bound to X. */ x= getArg(p,1); y= getArg(p,2); if( range[x].lcst && isVarConstant(mb,y) ){ /* merge lowerbound */ if( ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,range[x].lcst)), VALptr( &getVarConstant(mb,y)) ) > 0){ getArg(p,2)= range[x].lcst; z= range[x].srcvar; if( getArg(p,1) == x && range[z].lastupdate == range[z].lastrange){ getArg(p,1) = z; actions++; } } y= getArg(p,3); /* merge higherbound */ if( ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,range[x].hcst)), VALptr( &getVarConstant(mb,y)) ) < 0 || ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,y)), ATOMnilptr(getVarType(mb,y)) ) == 0){ getArg(p,3)= range[x].hcst; z= range[x].srcvar; if( getArg(p,1) == x && range[z].lastupdate == range[z].lastrange){ getArg(p,1) = z; actions++; } } } /* * The second step is to assign the result of this exercise to the * result variable. */ x= getArg(p,0); if( isVarConstant(mb, getArg(p,2)) ){ range[x].lcst = getArg(p,2); range[x].srcvar= getArg(p,1); range[x].lastupdate= range[x].lastrange = i; } if( isVarConstant(mb, getArg(p,3)) ){ range[x].hcst = getArg(p,3); range[x].srcvar= getArg(p,1); range[x].lastupdate= range[x].lastrange = i; } /* * If both range bounds are constant, we can also detect empty results. * It is empty if L> H or when L=H and the bounds are !(true,true). */ x= getArg(p,2); y= getArg(p,3); if( isVarConstant(mb, x) && isVarConstant(mb, y) ){ z =ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,x)), VALptr( &getVarConstant(mb,y))); x= p->argc > 4; x= x && isVarConstant(mb,getArg(p,4)); x= x && isVarConstant(mb,getArg(p,5)); x= x && getVarConstant(mb,getArg(p,4)).val.btval; x= x && getVarConstant(mb,getArg(p,5)).val.btval; if( z > 0 || (z==0 && p->argc>4 && !x)) { int var = getArg(p, 0); wrd zero = 0; ValRecord v, *vp; vp = VALset(&v, TYPE_wrd, &zero); varSetProp(mb, var, rowsProp, op_eq, vp); /* create an empty replacement */ x = getArgType(mb, p, 1); p->argc=1; getModuleId(p)= batRef; getFunctionId(p)= newRef; p= pushArgument(mb,p, newTypeVariable(mb, getHeadType(x))); (void) pushArgument(mb,p, newTypeVariable(mb, getTailType(x))); actions++; } } } } OPTDEBUGpushranges for(j=0; j< mb->vtop; j++) if( range[j].used ) printRange(cntxt, mb,range,j); /* * Phase II, if we succeeded in pushing constants around and * changing instructions, we might as well try once more to perform * aliasRemoval, constantExpression, and pushranges. */ GDKfree(range); return actions; }