/* Set a name (alias) for the expression, such that we can refer to this expression by this simple name. */ void exp_setname(sql_allocator *sa, sql_exp *e, char *rname, char *name ) { if (name) e->name = sa_strdup(sa, name); e->rname = (rname)?sa_strdup(sa, rname):NULL; }
sql_exp * exp_convert(sql_allocator *sa, sql_exp *exp, sql_subtype *fromtype, sql_subtype *totype ) { sql_exp *e = exp_create(sa, e_convert); e->card = exp->card; e->l = exp; totype = dup_subtype(sa, totype); e->r = append(append(sa_list(sa), dup_subtype(sa, fromtype)),totype); e->tpe = *totype; if (exp->name) e->name = sa_strdup(sa, exp->name); if (exp->rname) e->rname = sa_strdup(sa, exp->rname); return e; }
static ValPtr SA_VALcopy(sql_allocator *sa, ValPtr d, ValPtr s) { if (!ATOMextern(s->vtype)) { *d = *s; } else if (s->val.pval == 0) { d->val.pval = ATOMnil(s->vtype); d->vtype = s->vtype; } else if (s->vtype == TYPE_str) { d->vtype = TYPE_str; d->val.sval = sa_strdup(sa, s->val.sval); d->len = strLen(d->val.sval); } else if (s->vtype == TYPE_bit) { d->vtype = s->vtype; d->len = 1; d->val.btval = s->val.btval; } else { ptr p = s->val.pval; d->vtype = s->vtype; d->len = ATOMlen(d->vtype, p); d->val.pval = sa_alloc(sa, d->len); memcpy(d->val.pval, p, d->len); } return d; }
static sql_exp * rel_psm_declare_table(mvc *sql, dnode *n) { sql_rel *rel = NULL, *baset = NULL; dlist *qname = n->next->data.lval; const char *name = qname_table(qname); const char *sname = qname_schema(qname); sql_table *t; if (sname) /* not allowed here */ return sql_error(sql, 02, SQLSTATE(42000) "DECLARE TABLE: qualified name not allowed"); if (frame_find_var(sql, name)) return sql_error(sql, 01, SQLSTATE(42000) "Variable '%s' already declared", name); assert(n->next->next->next->type == type_int); rel = rel_create_table(sql, cur_schema(sql), SQL_DECLARED_TABLE, NULL, name, n->next->next->data.sym, n->next->next->next->data.i_val, NULL, NULL, NULL, false, NULL, 0); if (!rel) return NULL; if(rel->op == op_ddl) { baset = rel; } else if(rel->op == op_insert) { baset = rel->l; } else { return NULL; } if(baset->flag != DDL_CREATE_TABLE) return NULL; t = (sql_table*)((atom*)((sql_exp*)baset->exps->t->data)->l)->data.val.pval; if(!stack_push_table(sql, name, baset, t)) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); return exp_table(sql->sa, sa_strdup(sql->sa, name), t, sql->frame); }
static list * rel_psm_declare(mvc *sql, dnode *n) { list *l = sa_list(sql->sa); while(n) { /* list of 'identfiers with type' */ dnode *ids = n->data.sym->data.lval->h->data.lval->h; sql_subtype *ctype = &n->data.sym->data.lval->h->next->data.typeval; while(ids) { char *name = ids->data.sval; sql_exp *r = NULL; /* check if we overwrite a scope local variable declare x; declare x; */ if (frame_find_var(sql, name)) { return sql_error(sql, 01, "Variable '%s' already declared", name); } /* variables are put on stack, * TODO make sure on plan/explain etc they only * exist during plan phase */ stack_push_var(sql, name, ctype); r = exp_var(sql->sa, sa_strdup(sql->sa, name), ctype, sql->frame); append(l, r); ids = ids->next; } n = n->next; } return l; }
static sql_exp * rel_psm_declare_table(mvc *sql, dnode *n) { sql_rel *rel = NULL; dlist *qname = n->next->data.lval; char *name = qname_table(qname); char *sname = qname_schema(qname); sql_table *t; if (sname) /* not allowed here */ return sql_error(sql, 02, "DECLARE TABLE: qualified name not allowed"); if (frame_find_var(sql, name)) return sql_error(sql, 01, "Variable '%s' already declared", name); assert(n->next->next->next->type == type_int); rel = rel_create_table(sql, cur_schema(sql), SQL_DECLARED_TABLE, NULL, name, n->next->next->data.sym, n->next->next->next->data.i_val, NULL); if (!rel || rel->op != op_ddl || rel->flag != DDL_CREATE_TABLE) return NULL; t = (sql_table*)((atom*)((sql_exp*)rel->exps->t->data)->l)->data.val.pval; stack_push_table(sql, name, rel, t); return exp_table(sql->sa, sa_strdup(sql->sa, name), t, sql->frame); }
sql_exp * exp_atom_clob(sql_allocator *sa, str s) { sql_subtype clob; sql_find_subtype(&clob, "clob", 0, 0); return exp_atom(sa, atom_string(sa, &clob, s?sa_strdup(sa, s):NULL)); }
sql_exp* exp_label(sql_allocator *sa, sql_exp *e, int nr) { char name[16], *nme; nme = number2name(name, 16, nr); e->name = sa_strdup(sa, nme); return e; }
sql_exp * exp_column(sql_allocator *sa, char *rname, char *cname, sql_subtype *t, int card, int has_nils, int intern) { sql_exp *e = exp_create(sa, e_column); assert(cname); e->card = card; e->name = sa_strdup(sa, cname); e->l = (rname)?sa_strdup(sa, rname):NULL; e->r = sa_strdup(sa, cname); if (t) e->tpe = *t; if (!has_nils) set_has_no_nil(e); if (intern) set_intern(e); return e; }
sql_exp * exp_alias(sql_allocator *sa, char *arname, char *acname, char *org_rname, char *org_cname, sql_subtype *t, int card, int has_nils, int intern) { sql_exp *e = exp_create(sa, e_column); assert(acname && org_cname); e->card = card; e->rname = (arname)?sa_strdup(sa, arname):(org_rname)?sa_strdup(sa, org_rname):NULL; e->name = sa_strdup(sa, acname); e->l = (org_rname)?sa_strdup(sa, org_rname):NULL; e->r = sa_strdup(sa, org_cname); if (t) e->tpe = *t; if (!has_nils) set_has_no_nil(e); if (intern) set_intern(e); return e; }
sql_exp * exp_param(sql_allocator *sa, char *name, sql_subtype *tpe, int frame) { sql_exp *e = exp_create(sa, e_atom); e->r = sa_strdup(sa, name); e->card = CARD_ATOM; e->flag = frame; if (tpe) e->tpe = *tpe; return e; }
sql_column * mvc_storage(mvc *m, sql_column *col, char *storage) { if (mvc_debug) fprintf(stderr, "#mvc_storage %s %s\n", col->base.name, storage); if (col->t->persistence == SQL_DECLARED_TABLE) { col->storage_type = storage?sa_strdup(m->sa, storage):NULL; return col; } else { return sql_trans_alter_storage(m->session->tr, col, storage); } }
sql_column * mvc_default(mvc *m, sql_column *col, char *val) { if (mvc_debug) fprintf(stderr, "#mvc_default %s %s\n", col->base.name, val); if (col->t->persistence == SQL_DECLARED_TABLE) { col->def = val?sa_strdup(m->sa, val):NULL; return col; } else { return sql_trans_alter_default(m->session->tr, col, val); } }
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; }
/* mapiuri_uri prefix including database name */ const char * mapiuri_uri( const char *uri, sql_allocator *sa) { const char *p = uri, *b = uri, *e; p = strchr(p, '/')+1; p++; e = p = strchr(p, '/'); e = strchr(p+1, '/'); if (e) return sa_strndup(sa, b, e - b); else return sa_strdup(sa, b); }
const char * mapiuri_table( const char *uri, sql_allocator *sa, const char *fallback) { const char *p = uri, *b; p = strchr(p, '/')+1; p = strchr(p+1, '/'); p = strchr(p+1, '/'); if (!p) return fallback; p = strchr(p+1, '/'); if (!p) return fallback; b = ++p; return sa_strdup(sa, b); }
const char * mapiuri_database( const char *uri, sql_allocator *sa) { const char *p = uri, *b, *e; p = strchr(p, '/')+1; p++; b = p = strchr(p, '/')+1; e = strchr(p, '/'); if (e) { return sa_strndup(sa, b, e - b); } else { return sa_strdup(sa, b); } }
sql_table * mvc_create_remote(mvc *m, sql_schema *s, const char *name, int persistence, const char *loc) { sql_table *t = NULL; if (mvc_debug) fprintf(stderr, "#mvc_create_remote %s %s %s\n", s->base.name, name, loc); if (persistence == SQL_DECLARED_TABLE) { t = create_sql_table(m->sa, name, tt_remote, 0, persistence, 0); t->s = s; t->query = sa_strdup(m->sa, loc); } else { t = sql_trans_create_table(m->session->tr, s, name, loc, tt_remote, 0, SQL_REMOTE, 0, 0); } return t; }
sql_table * mvc_create_view(mvc *m, sql_schema *s, const char *name, int persistence, const char *sql, bit system) { sql_table *t = NULL; if (mvc_debug) fprintf(stderr, "#mvc_create_view %s %s %s\n", s->base.name, name, sql); if (persistence == SQL_DECLARED_TABLE) { t = create_sql_table(m->sa, name, tt_view, system, persistence, 0); t->s = s; t->query = sa_strdup(m->sa, sql); } else { t = sql_trans_create_table(m->session->tr, s, name, sql, tt_view, system, SQL_PERSIST, 0, 0); } return t; }
const char * mapiuri_schema( const char *uri, sql_allocator *sa, const char *fallback) { const char *p = uri, *b, *e; p = strchr(p, '/')+1; p = strchr(p+1, '/'); p = strchr(p+1, '/'); if (!p) return fallback; b = ++p; e = strchr(p, '/'); if (e) { return sa_strndup(sa, b, e - b); } else { return sa_strdup(sa, b); } }
/* return val; */ static list * rel_psm_return( mvc *sql, sql_subtype *restype, list *restypelist, symbol *return_sym ) { exp_kind ek = {type_value, card_value, FALSE}; sql_exp *res; sql_rel *rel = NULL; int is_last = 0; list *l = sa_list(sql->sa); if (restypelist) ek.card = card_relation; res = rel_value_exp2(sql, &rel, return_sym, sql_sel, ek, &is_last); if (!res) return NULL; if (ek.card != card_relation && (!res || (res = rel_check_type(sql, restype, res, type_equal)) == NULL)) return NULL; else if (ek.card == card_relation && !rel) return NULL; if (rel && ek.card != card_relation) append(l, exp_rel(sql, rel)); else if (rel && !is_ddl(rel->op)) { list *exps = sa_list(sql->sa); node *n, *m; int isproject = (rel->op == op_project); list *oexps = rel->exps; sql_rel *l = rel->l; if (is_topn(rel->op)) oexps = l->exps; for (n = oexps->h, m = restypelist->h; n && m; n = n->next, m = m->next) { sql_exp *e = n->data; sql_arg *ce = m->data; char *cname = exp_name(e); char name[16]; if (!cname) cname = sa_strdup(sql->sa, number2name(name, 16, ++sql->label)); if (!isproject) e = exp_column(sql->sa, exp_relname(e), cname, exp_subtype(e), exp_card(e), has_nil(e), is_intern(e)); e = rel_check_type(sql, &ce->type, e, type_equal); if (!e) return NULL; append(exps, e); } if (isproject) rel -> exps = exps; else rel = rel_project(sql->sa, rel, exps); res = exp_rel(sql, rel); } else if (rel && restypelist){ /* handle return table-var */ list *exps = sa_list(sql->sa); sql_table *t = rel_ddl_table_get(rel); node *n, *m; char *tname = t->base.name; if (cs_size(&t->columns) != list_length(restypelist)) return sql_error(sql, 02, "RETURN: number of columns do not match"); for (n = t->columns.set->h, m = restypelist->h; n && m; n = n->next, m = m->next) { sql_column *c = n->data; sql_arg *ce = m->data; sql_exp *e = exp_alias(sql->sa, tname, c->base.name, tname, c->base.name, &c->type, CARD_MULTI, c->null, 0); e = rel_check_type(sql, &ce->type, e, type_equal); if (!e) return NULL; append(exps, e); } rel = rel_project(sql->sa, rel, exps); res = exp_rel(sql, rel); } append(l, exp_return(sql->sa, res, stack_nr_of_declared_tables(sql))); return l; }
char * atom2string(sql_allocator *sa, atom *a) { char buf[BUFSIZ], *p = NULL; void *v; if (a->isnull) return sa_strdup(sa, "NULL"); switch (a->data.vtype) { #ifdef HAVE_HGE case TYPE_hge: { char *_buf = buf; int _bufsiz = BUFSIZ; hgeToStr(&_buf, &_bufsiz, &a->data.val.hval); break; } #endif case TYPE_lng: sprintf(buf, LLFMT, a->data.val.lval); break; case TYPE_wrd: sprintf(buf, SSZFMT, a->data.val.wval); break; case TYPE_oid: sprintf(buf, OIDFMT "@0", a->data.val.oval); break; case TYPE_int: sprintf(buf, "%d", a->data.val.ival); break; case TYPE_sht: sprintf(buf, "%d", a->data.val.shval); break; case TYPE_bte: sprintf(buf, "%d", a->data.val.btval); break; case TYPE_bit: if (a->data.val.btval) return sa_strdup(sa, "true"); return sa_strdup(sa, "false"); case TYPE_flt: sprintf(buf, "%f", a->data.val.fval); break; case TYPE_dbl: sprintf(buf, "%f", a->data.val.dval); break; case TYPE_str: if (a->data.val.sval) return sa_strdup(sa, a->data.val.sval); else sprintf(buf, "NULL"); break; default: v = &a->data.val.ival; if (ATOMvarsized(a->data.vtype)) v = a->data.val.pval; if (ATOMformat(a->data.vtype, v, &p) < 0) { snprintf(buf, BUFSIZ, "atom2string(TYPE_%d) not implemented", a->data.vtype); } else { char *r = sa_strdup(sa, p); _DELETE(p); return r; } } return sa_strdup(sa, buf); }
sql_exp * exp_atom_str(sql_allocator *sa, str s, sql_subtype *st) { return exp_atom(sa, atom_string(sa, st, s?sa_strdup(sa, s):NULL)); }
struct term_t term_create(const char* str, int reparse) { struct term_t term = term_construct(); term.string = sa_strdup(str); term.reparse = reparse; return term; }
static sql_rel * rel_create_func(mvc *sql, dlist *qname, dlist *params, symbol *res, dlist *ext_name, dlist *body, int type, int lang, int replace) { const char *fname = qname_table(qname); const char *sname = qname_schema(qname); sql_schema *s = NULL; sql_func *f = NULL; sql_subfunc *sf; dnode *n; list *type_list = NULL, *restype = NULL; int instantiate = (sql->emode == m_instantiate); int deps = (sql->emode == m_deps); int create = (!instantiate && !deps); bit vararg = FALSE; char is_table = (res && res->token == SQL_TABLE); char is_aggr = (type == F_AGGR); char is_func = (type != F_PROC); char is_loader = (type == F_LOADER); char *F = is_loader?"LOADER":(is_aggr?"AGGREGATE":(is_func?"FUNCTION":"PROCEDURE")); char *fn = is_loader?"loader":(is_aggr ? "aggregate" : (is_func ? "function" : "procedure")); char *KF = type==F_FILT?"FILTER ": type==F_UNION?"UNION ": ""; char *kf = type == F_FILT ? "filter " : type == F_UNION ? "union " : ""; assert(res || type == F_PROC || type == F_FILT || type == F_LOADER); if (is_table) type = F_UNION; if (STORE_READONLY && create) return sql_error(sql, 06, SQLSTATE(42000) "Schema statements cannot be executed on a readonly database."); if (sname && !(s = mvc_bind_schema(sql, sname))) return sql_error(sql, 02, SQLSTATE(3F000) "CREATE %s%s: no such schema '%s'", KF, F, sname); if (s == NULL) s = cur_schema(sql); type_list = create_type_list(sql, params, 1); if ((sf = sql_bind_func_(sql->sa, s, fname, type_list, type)) != NULL && create) { if (replace) { sql_func *func = sf->func; int action = 0; if (!mvc_schema_privs(sql, s)) { return sql_error(sql, 02, SQLSTATE(42000) "CREATE OR REPLACE %s%s: access denied for %s to schema ;'%s'", KF, F, stack_get_string(sql, "current_user"), s->base.name); } if (mvc_check_dependency(sql, func->base.id, !IS_PROC(func) ? FUNC_DEPENDENCY : PROC_DEPENDENCY, NULL)) return sql_error(sql, 02, SQLSTATE(42000) "CREATE OR REPLACE %s%s: there are database objects dependent on %s%s %s;", KF, F, kf, fn, func->base.name); if (!func->s) { return sql_error(sql, 02, SQLSTATE(42000) "CREATE OR REPLACE %s%s: not allowed to replace system %s%s %s;", KF, F, kf, fn, func->base.name); } if(mvc_drop_func(sql, s, func, action)) return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL); sf = NULL; } else { if (params) { char *arg_list = NULL; node *n; for (n = type_list->h; n; n = n->next) { char *tpe = subtype2string((sql_subtype *) n->data); if (arg_list) { char *t = arg_list; arg_list = sql_message("%s, %s", arg_list, tpe); _DELETE(t); _DELETE(tpe); } else { arg_list = tpe; } } (void)sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: name '%s' (%s) already in use", KF, F, fname, arg_list); _DELETE(arg_list); list_destroy(type_list); return NULL; } else { list_destroy(type_list); return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: name '%s' already in use", KF, F, fname); } } } list_destroy(type_list); if (create && !mvc_schema_privs(sql, s)) { return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s%s: insufficient privileges " "for user '%s' in schema '%s'", KF, F, stack_get_string(sql, "current_user"), s->base.name); } else { char *q = QUERY(sql->scanner); list *l = NULL; if (params) { for (n = params->h; n; n = n->next) { dnode *an = n->data.lval->h; sql_add_param(sql, an->data.sval, &an->next->data.typeval); } l = sql->params; if (l && list_length(l) == 1) { sql_arg *a = l->h->data; if (strcmp(a->name, "*") == 0) { l = NULL; vararg = TRUE; } } } if (!l) l = sa_list(sql->sa); if (res) { restype = result_type(sql, res); if (!restype) return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: failed to get restype", KF, F); } if (body && lang > FUNC_LANG_SQL) { char *lang_body = body->h->data.sval; char *mod = (lang == FUNC_LANG_R)?"rapi": (lang == FUNC_LANG_C || lang == FUNC_LANG_CPP)?"capi": (lang == FUNC_LANG_J)?"japi": (lang == FUNC_LANG_PY)?"pyapi": (lang == FUNC_LANG_MAP_PY)?"pyapimap":"unknown"; sql->params = NULL; if (create) { f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, mod, fname, lang_body, (type == F_LOADER)?TRUE:FALSE, vararg, FALSE); } else if (!sf) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: R function %s.%s not bound", KF, F, s->base.name, fname ); } /*else { sql_func *f = sf->func; f->mod = _STRDUP("rapi"); f->imp = _STRDUP("eval"); if (res && restype) f->res = restype; f->sql = 0; f->lang = FUNC_LANG_INT; }*/ } else if (body) { sql_arg *ra = (restype && !is_table)?restype->h->data:NULL; list *b = NULL; sql_schema *old_schema = cur_schema(sql); if (create) { /* needed for recursive functions */ q = query_cleaned(q); sql->forward = f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, "user", q, q, FALSE, vararg, FALSE); GDKfree(q); } sql->session->schema = s; b = sequential_block(sql, (ra)?&ra->type:NULL, ra?NULL:restype, body, NULL, is_func); sql->forward = NULL; sql->session->schema = old_schema; sql->params = NULL; if (!b) return NULL; /* check if we have a return statement */ if (is_func && restype && !has_return(b)) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: missing return statement", KF, F); } if (!is_func && !restype && has_return(b)) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: procedures " "cannot have return statements", KF, F); } /* in execute mode we instantiate the function */ if (instantiate || deps) { return rel_psm_block(sql->sa, b); } } else { char *fmod = qname_module(ext_name); char *fnme = qname_fname(ext_name); if (!fmod || !fnme) return NULL; sql->params = NULL; if (create) { q = query_cleaned(q); f = mvc_create_func(sql, sql->sa, s, fname, l, restype, type, lang, fmod, fnme, q, FALSE, vararg, FALSE); GDKfree(q); } else if (!sf) { return sql_error(sql, 01, SQLSTATE(42000) "CREATE %s%s: external name %s.%s not bound (%s.%s)", KF, F, fmod, fnme, s->base.name, fname ); } else { sql_func *f = sf->func; if (!f->mod || strcmp(f->mod, fmod)) f->mod = _STRDUP(fmod); if (!f->imp || strcmp(f->imp, fnme)) f->imp = (f->sa)?sa_strdup(f->sa, fnme):_STRDUP(fnme); if(!f->mod || !f->imp) { _DELETE(f->mod); _DELETE(f->imp); return sql_error(sql, 02, SQLSTATE(HY001) "CREATE %s%s: could not allocate space", KF, F); } f->sql = 0; /* native */ f->lang = FUNC_LANG_INT; } } } return rel_create_function(sql->sa, s->base.name, f); }