Update of /cvsroot/monetdb/sql/src/server
In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv5366/src/server
Modified Files:
Tag: Feb2009
rel_bin.mx rel_exp.mx rel_optimizer.mx rel_prop.mx
rel_select.mx rel_updates.mx rel_xml.mx sql_schema.mx
Log Message:
disabled mitosis (not ready for production/release)
fixed bugs
2585592 Serial with order by is not working properly
First order then project, added check for project with order)
2582389 subtraction between two columns
Disabled pushing sort down, this causes problems when the sorted
column is used in other selection/projection results)
2581617 cardinality of expression is wrong
When optimizing we sometimes have to fixup the cardinality of
expressions
2523442 IS NULL handled wrong in searched CASE
The case condition column needs its null's removed.
2513620 subquery returns a table crash
Properly detect unexpected table results in the selection
2499537 SQL: time to implement BINOP
Done
Optimizer now also pushes select under cross-product
fixed bug in alter add index
fixed bug in "OR" handling, with views. These require a distinct over
their "%TID%" columns. These TID columns are usualy not include in a
view, but when used now they are re-introduced.
U sql_schema.mx
Index: sql_schema.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/sql_schema.mx,v
retrieving revision 1.163
retrieving revision 1.163.2.1
diff -u -d -r1.163 -r1.163.2.1
--- sql_schema.mx 7 Jan 2009 14:19:29 -0000 1.163
+++ sql_schema.mx 11 Feb 2009 19:35:45 -0000 1.163.2.1
@@ -989,15 +989,13 @@
return stmt_none();
}
-stmt *
+static stmt *
sql_update_add_idx(mvc *sql, sql_table *t, sql_idx * idx)
{
list *exps;
sql_kc *ic = idx->columns->h->data;
sql_rel *updates, *update;
- if (isNew(ic->c)) /* column is just created, ie gets update by it self
*/
- return stmt_none();
exps = new_exp_list();
exps = append(exps,
exp_column(t->base.name, "%TID%", sql_bind_localtype("oid"),
CARD_MULTI, 0, 1));
U rel_select.mx
Index: rel_select.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_select.mx,v
retrieving revision 1.113.2.5
retrieving revision 1.113.2.6
diff -u -d -r1.113.2.5 -r1.113.2.6
--- rel_select.mx 6 Feb 2009 01:23:01 -0000 1.113.2.5
+++ rel_select.mx 11 Feb 2009 19:35:45 -0000 1.113.2.6
@@ -55,9 +55,9 @@
extern sql_rel *rel_push_join(sql_rel *rel, sql_exp *ls, sql_exp *rs, sql_exp
*e);
/* TODO rename to exp_check_type + move to rel_exp.mx */
extern sql_exp *rel_check_type(mvc *sql, sql_subtype *t, sql_exp *exp, int
tpe);
-extern sql_exp *rel_unop_(mvc *sql, sql_exp *e, sql_schema *s, char *fname);
-extern sql_exp *rel_binop_(mvc *sql, sql_exp *l, sql_exp *r, sql_schema *s,
char *fname);
-extern sql_exp *rel_nop_(mvc *sql, sql_exp *l, sql_exp *r, sql_exp *r2,
sql_exp *r3, sql_schema *s, char *fname);
+extern sql_exp *rel_unop_(mvc *sql, sql_exp *e, sql_schema *s, char *fname,
int table_func);
+extern sql_exp *rel_binop_(mvc *sql, sql_exp *l, sql_exp *r, sql_schema *s,
char *fname, int table_func);
+extern sql_exp *rel_nop_(mvc *sql, sql_exp *l, sql_exp *r, sql_exp *r2,
sql_exp *r3, sql_schema *s, char *fname, int table_func);
extern sql_rel *rel_dup(sql_rel *r);
@@ -1778,7 +1778,7 @@
exp_destroy(rs);
return NULL;
}
- e = rel_binop_(sql, ls, rs, NULL, compare_op);
+ e = rel_binop_(sql, ls, rs, NULL, compare_op, 0);
if (!e)
return NULL;
@@ -1895,9 +1895,9 @@
if (!ls || !rs)
return NULL;
if (sc->token == SQL_OR)
- return rel_binop_(sql, ls, rs, NULL, "or");
+ return rel_binop_(sql, ls, rs, NULL, "or", 0);
else
- return rel_binop_(sql, ls, rs, NULL, "and");
+ return rel_binop_(sql, ls, rs, NULL, "and", 0);
}
case SQL_COMPARE:
{
@@ -1922,7 +1922,7 @@
exp_destroy(rs);
return NULL;
}
- return rel_binop_(sql, ls, rs, NULL, compare_op);
+ return rel_binop_(sql, ls, rs, NULL, compare_op, 0);
} else {
/* first try without current relation, too see if there
are correlations with the outer relation */
@@ -1948,9 +1948,9 @@
/* For selection we need to convert
back into booleans */
ls = exp_dup(ls);
rel_join_add_exp(r, e);
- ls = rel_unop_(sql, ls, NULL, "isnull");
+ ls = rel_unop_(sql, ls, NULL, "isnull",
0);
rs = exp_atom_bool(0);
- return rel_binop_(sql, ls, rs, NULL,
"=");
+ return rel_binop_(sql, ls, rs, NULL,
"=", 0);
}
} else if (r) {
rel_setsubquery(r);
@@ -1973,7 +1973,7 @@
exp_destroy(rs);
return NULL;
}
- return rel_binop_(sql, ls, rs, NULL, compare_op);
+ return rel_binop_(sql, ls, rs, NULL, compare_op, 0);
}
}
/* Set Member ship */
@@ -1998,18 +1998,7 @@
if (!left)
left = *rel;
-/*
- if (f >= sql_sel) {
- if (left && is_project(left->op)) {
- p = left;
- left = left->l;
- }
- if (left && is_groupby(left->op)) {
- p = left;
- left = left->l;
- }
- }
-*/
+
if (!left || !left->l) {
needproj = (left != NULL);
left = rel_project_exp(l);
@@ -2057,9 +2046,9 @@
if (right->card == CARD_ATOM) {
if (sc->token == SQL_NOT_IN)
- e = rel_binop_(sql, l, r, NULL, "!=");
+ e = rel_binop_(sql, l, r, NULL, "!=",
0);
else
- e = rel_binop_(sql, l, r, NULL, "=");
+ e = rel_binop_(sql, l, r, NULL, "=", 0);
return e;
}
r = rel_lastexp(sql, right);
@@ -2083,13 +2072,13 @@
else
*rel = left;
}
- e = rel_binop_(sql, l, r, NULL, "=");
- l = rel_unop_(sql, e, NULL, "isnull");
+ e = rel_binop_(sql, l, r, NULL, "=", 0);
+ l = rel_unop_(sql, e, NULL, "isnull", 0);
if (sc->token == SQL_NOT_IN)
r = exp_atom_bool(1);
else
r = exp_atom_bool(0);
- return rel_binop_(sql, l, r, NULL, "=");
+ return rel_binop_(sql, l, r, NULL, "=", 0);
}
return NULL;
}
@@ -2132,12 +2121,12 @@
}
if (sc->token == SQL_LIKE) {
if (ee)
- return rel_nop_(sql, le, re, ee, NULL, NULL,
"like");
- return rel_binop_(sql, le, re, NULL, "like");
+ return rel_nop_(sql, le, re, ee, NULL, NULL,
"like", 0);
+ return rel_binop_(sql, le, re, NULL, "like", 0);
} else {
if (ee)
- return rel_nop_(sql, le, re, ee, NULL, NULL,
"not_like");
- return rel_binop_(sql, le, re, NULL, "not_like");
+ return rel_nop_(sql, le, re, ee, NULL, NULL,
"not_like", 0);
+ return rel_binop_(sql, le, re, NULL, "not_like", 0);
}
}
case SQL_BETWEEN:
@@ -2185,18 +2174,18 @@
}
if (sc->token == SQL_NOT_BETWEEN) {
- e1 = rel_binop_(sql, le, re1, NULL, "<");
- e2 = rel_binop_(sql, exp_dup(le), re2, NULL, ">");
+ e1 = rel_binop_(sql, le, re1, NULL, "<", 0);
+ e2 = rel_binop_(sql, exp_dup(le), re2, NULL, ">", 0);
} else {
- e1 = rel_binop_(sql, le, re1, NULL, ">=");
- e2 = rel_binop_(sql, exp_dup(le), re2, NULL, "<=");
+ e1 = rel_binop_(sql, le, re1, NULL, ">=", 0);
+ e2 = rel_binop_(sql, exp_dup(le), re2, NULL, "<=", 0);
}
if (!e1 || !e2)
return NULL;
if (sc->token == SQL_NOT_BETWEEN) {
- return rel_binop_(sql, e1, e2, NULL, "or");
+ return rel_binop_(sql, e1, e2, NULL, "or", 0);
} else {
- return rel_binop_(sql, e1, e2, NULL, "and");
+ return rel_binop_(sql, e1, e2, NULL, "and", 0);
}
}
case SQL_IS_NULL:
@@ -2207,14 +2196,14 @@
if (!le)
return NULL;
- le = rel_unop_(sql, le, NULL, "isnull");
+ le = rel_unop_(sql, le, NULL, "isnull", 0);
if (sc->token != SQL_IS_NULL)
- le = rel_unop_(sql, le, NULL, "not");
+ le = rel_unop_(sql, le, NULL, "not", 0);
return le;
}
case SQL_NOT: {
sql_exp *le = rel_logical_value_exp(sql, rel, sc->data.sym, f);
- return rel_unop_(sql, le, NULL, "not");
+ return rel_unop_(sql, le, NULL, "not", 0);
}
case SQL_ATOM: {
/* TRUE or FALSE */
@@ -2254,7 +2243,7 @@
return rel;
}
rel = rel_project(rel, rel_projections(sql, rel, NULL, 1, 1));
- e = rel_unop_(sql, exp_dup(rel->exps->h->data), NULL, "identity");
+ e = rel_unop_(sql, exp_dup(rel->exps->h->data), NULL, "identity", 0);
set_intern(e);
rel_project_add_exp(sql, rel, e);
*exp = e = exp_label(e, ++sql->label);
@@ -2319,7 +2308,7 @@
symbol *lo = dl->h->data.sym;
dnode *n = dl->h->next;
sql_rel *left = NULL, *right = NULL, *outer = rel;
- sql_exp *l = rel_value_exp(sql, &left, lo, f, ek), *e;
+ sql_exp *l = rel_value_exp(sql, &left, lo, f, ek), *e, *r =
NULL;
int correlated = 0;
int l_is_value = 1;
@@ -2339,7 +2328,7 @@
ek.card = card_set;
/* first remove the NULLs */
if (sc->token == SQL_NOT_IN && l->card != CARD_ATOM &&
has_nil(l)) {
- e = rel_unop_(sql, exp_dup(l), NULL, "isnull");
+ e = rel_unop_(sql, exp_dup(l), NULL, "isnull", 0);
e = exp_compare( e, exp_atom_bool(0), cmp_equal);
if (!is_select(rel->op))
left = rel = rel_select(rel, e);
@@ -2357,9 +2346,9 @@
symbol *sval = n->data.sym;
/* without correlation first */
sql_rel *z = NULL;
- sql_exp *r = rel_value_exp(sql, &z, sval, f,
ek);
sql_rel *rl;
+ r = rel_value_exp(sql, &z, sval, f, ek);
if (!r) {
/* reset error */
sql->session->status = 0;
@@ -2401,8 +2390,22 @@
return sql_error(sql, 02, "IN: missing inner query");
}
if (right) {
- sql_exp *r = NULL;
-
+ if (right->card == CARD_ATOM && !correlated) {
+ if (rel_convert_types(sql, &l, &r, 1,
type_equal) < 0) {
+ exp_destroy(l);
+ exp_destroy(r);
+ return NULL;
+ }
+ if (sc->token == SQL_NOT_IN)
+ e = exp_compare( l, r, cmp_notequal);
+ else
+ e = exp_compare( l, r, cmp_equal);
+ if (!is_select(rel->op))
+ rel = rel_select(rel, e);
+ else
+ rel_select_add_exp(rel, e);
+ return rel;
+ }
r = rel_lastexp(sql, right);
rel_setsubquery(right);
rel = rel_crossproduct(left, right, op_join);
@@ -2417,7 +2420,7 @@
rel->op = (sc->token == SQL_IN)?op_semi:op_anti;
} else if (sc->token == SQL_NOT_IN) {
rel->op = op_left;
- e = rel_unop_(sql, exp_dup(r), NULL, "isnull");
+ e = rel_unop_(sql, exp_dup(r), NULL, "isnull",
0);
r = exp_atom_bool(1);
e = exp_compare( e, r, cmp_equal);
rel = rel_select(rel, e);
@@ -2581,7 +2584,7 @@
if (!le)
return NULL;
- le = rel_unop_(sql, le, NULL, "isnull");
+ le = rel_unop_(sql, le, NULL, "isnull", 0);
if (sc->token == SQL_IS_NULL)
re = exp_atom_bool(1);
else
@@ -2594,7 +2597,7 @@
if (!le)
return NULL;
- le = rel_unop_(sql, le, NULL, "not");
+ le = rel_unop_(sql, le, NULL, "not", 0);
re = exp_atom_bool(1);
le = exp_compare( le, re, cmp_equal);
return rel_select(rel, le);
@@ -2634,7 +2637,7 @@
}
static sql_exp *
-rel_op(mvc *sql, symbol *se )
+rel_op(mvc *sql, symbol *se, exp_kind ek )
{
dnode *l = se->data.lval->h;
sql_subfunc *f = NULL;
@@ -2645,7 +2648,7 @@
if (sname)
s = mvc_bind_schema(sql, sname);
f = sql_bind_func(s, fname, NULL, NULL);
- if (f) {
+ if (f && (ek.card == card_relation || !f->res.comp_type)) {
return exp_op(NULL, f);
} else {
return sql_error(sql, 02,
@@ -2654,7 +2657,7 @@
}
sql_exp *
-rel_unop_(mvc *sql, sql_exp *e, sql_schema *s, char *fname)
+rel_unop_(mvc *sql, sql_exp *e, sql_schema *s, char *fname, int table_func)
{
sql_subfunc *f = NULL;
sql_subtype *t = NULL;
@@ -2666,7 +2669,9 @@
/* try to find the function without a type, and convert
* the value to the type needed by this function!
*/
- if (!f && (f = sql_find_func(s, fname, 1)) != NULL) {
+ if (!f &&
+ (f = sql_find_func(s, fname, 1)) != NULL &&
+ (table_func || !f->res.comp_type)) {
sql_arg *a = f->func->ops->h->data;
e = rel_check_type(sql, &a->type, e, type_equal);
@@ -2675,7 +2680,7 @@
f = NULL;
}
}
- if (f) {
+ if (f && (table_func || !f->res.comp_type)) {
if (f->func->res.scale == INOUT) {
f->res.digits = t->digits;
f->res.scale = t->scale;
@@ -2691,25 +2696,25 @@
}
static sql_exp *
-rel_unop(mvc *sql, sql_rel **rel, symbol *se, int fs)
+rel_unop(mvc *sql, sql_rel **rel, symbol *se, int fs, exp_kind ek)
{
dnode *l = se->data.lval->h;
char *fname = qname_fname(l->data.lval);
char *sname = qname_schema(l->data.lval);
sql_schema *s = sql->session->schema;
- exp_kind ek = {type_value, card_column, FALSE};
- sql_exp *e = rel_value_exp(sql, rel, l->next->data.sym, fs, ek);
+ exp_kind iek = {type_value, card_column, FALSE};
+ sql_exp *e = rel_value_exp(sql, rel, l->next->data.sym, fs, iek);
if (!e)
return NULL;
if (sname)
s = mvc_bind_schema(sql, sname);
- return rel_unop_(sql, e, s, fname);
+ return rel_unop_(sql, e, s, fname, (ek.card == card_relation));
}
sql_exp *
-rel_binop_(mvc *sql, sql_exp *l, sql_exp *r, sql_schema *s, char *fname)
+rel_binop_(mvc *sql, sql_exp *l, sql_exp *r, sql_schema *s, char *fname, int
table_func)
{
sql_exp *res = NULL;
sql_subtype *t1, *t2;
@@ -2723,7 +2728,7 @@
f = sql_bind_func(s, fname, t1, t2);
if (!f && is_commutative(fname)) {
f = sql_bind_func(s, fname, t2, t1);
- if (f) {
+ if (f && (table_func || !f->res.comp_type)) {
sql_subtype *tmp = t1;
t1 = t2;
t2 = tmp;
@@ -2732,7 +2737,7 @@
r = res;
}
}
- if (f) {
+ if (f && (table_func || !f->res.comp_type)) {
if (f->func->fix_scale == SCALE_FIX) {
l = exp_fix_scale(sql, t2, l, 0, 0);
r = exp_fix_scale(sql, t1, r, 0, 0);
@@ -2750,7 +2755,8 @@
sql_exp *or = exp_dup(r);
if (!EC_NUMBER(t1->type->eclass) &&
- (f = sql_bind_member(s, fname, t1, 2)) != NULL) {
+ (f = sql_bind_member(s, fname, t1, 2)) != NULL &&
+ (table_func || !f->res.comp_type)) {
/* try finding function based on first argument */
node *m = f->func->ops->h;
sql_arg *a = m->data;
@@ -2782,7 +2788,7 @@
t1 = exp_subtype(l);
t2 = exp_subtype(r);
f = sql_bind_func(s, fname, t1, t2);
- if (f) {
+ if (f && (table_func || !f->res.comp_type)) {
if (f->func->fix_scale == SCALE_FIX) {
l = exp_fix_scale(sql, t2, l, 0, 0);
r = exp_fix_scale(sql, t1, r, 0, 0);
@@ -2812,7 +2818,8 @@
or = exp_dup(r);
/* everything failed, fall back to bind on function name only */
- if ((f = sql_find_func(s, fname, 2)) != NULL) {
+ if ((f = sql_find_func(s, fname, 2)) != NULL &&
+ (table_func || !f->res.comp_type)) {
node *m = f->func->ops->h;
sql_arg *a = m->data;
@@ -2835,17 +2842,17 @@
#define SQLMAXDEPTH ((THREAD_STACK_SIZE/4096))
static sql_exp *
-rel_binop(mvc *sql, sql_rel **rel, symbol *se, int f)
+rel_binop(mvc *sql, sql_rel **rel, symbol *se, int f, exp_kind ek)
{
dnode *dl = se->data.lval->h;
sql_exp *l, *r;
char *fname = qname_fname(dl->data.lval);
char *sname = qname_schema(dl->data.lval);
sql_schema *s = sql->session->schema;
- exp_kind ek = {type_value, card_column, FALSE};
+ exp_kind iek = {type_value, card_column, FALSE};
- l = rel_value_exp(sql, rel, dl->next->data.sym, f, ek);
- r = rel_value_exp(sql, rel, dl->next->next->data.sym, f, ek);
+ l = rel_value_exp(sql, rel, dl->next->data.sym, f, iek);
+ r = rel_value_exp(sql, rel, dl->next->next->data.sym, f, iek);
if (!l || !r) {
if (l)
@@ -2857,11 +2864,11 @@
if (sname)
s = mvc_bind_schema(sql, sname);
- return rel_binop_(sql, l, r, s, fname);
+ return rel_binop_(sql, l, r, s, fname, (ek.card == card_relation));
}
sql_exp *
-rel_nop_(mvc *sql, sql_exp *a1, sql_exp *a2, sql_exp *a3, sql_exp *a4,
sql_schema *s, char *fname)
+rel_nop_(mvc *sql, sql_exp *a1, sql_exp *a2, sql_exp *a3, sql_exp *a4,
sql_schema *s, char *fname, int table_func)
{
list *tl = list_create(NULL);
sql_subfunc *f = NULL;
@@ -2876,15 +2883,15 @@
s = sql->session->schema;
f = sql_bind_func_(s, fname, tl);
list_destroy(tl);
- if (f && !a4)
+ if (!f || (table_func || f->res.comp_type))
+ return sql_error(sql, 02, "SELECT: no such operator '%s'",
fname);
+ if (!a4)
return exp_op3(a1,a2,a3,f);
- if (f && a4)
- return exp_op4(a1,a2,a3,a4,f);
- return sql_error(sql, 02, "SELECT: no such operator '%s'", fname);
+ return exp_op4(a1,a2,a3,a4,f);
}
static sql_exp *
-rel_nop(mvc *sql, sql_rel **rel, symbol *se, int fs)
+rel_nop(mvc *sql, sql_rel **rel, symbol *se, int fs, exp_kind ek)
{
int nr_args = 0;
dnode *l = se->data.lval->h;
@@ -2896,10 +2903,11 @@
char *fname = qname_fname(l->data.lval);
char *sname = qname_schema(l->data.lval);
sql_schema *s = sql->session->schema;
- exp_kind ek = {type_value, card_column, FALSE};
+ exp_kind iek = {type_value, card_column, FALSE};
+ int table_func = (ek.card == card_relation);
for (; ops; ops = ops->next, nr_args++) {
- sql_exp *e = rel_value_exp(sql, rel, ops->data.sym, fs, ek);
+ sql_exp *e = rel_value_exp(sql, rel, ops->data.sym, fs, iek);
sql_subtype *tpe;
if (!e) {
@@ -2918,8 +2926,9 @@
list_destroy(tl);
if (f) {
return exp_op(exps, f);
- } else if ((f = sql_bind_member(s, fname, obj_type, nr_args)) != NULL ||
- (f = sql_find_func(s, fname, nr_args)) != NULL) {
+ } else if (((f = sql_bind_member(s, fname, obj_type, nr_args)) != NULL
||
+ (f = sql_find_func(s, fname, nr_args)) != NULL) &&
+ (table_func || !f->res.comp_type)) {
node *n, *m;
list *nexps = new_exp_list();
@@ -3048,7 +3057,7 @@
e1 = rel_value_exp(sql, rel, dn->data.sym, f, ek);
e2 = rel_value_exp(sql, rel, dn->next->data.sym, f, ek);
if (e1 && e2) {
- cond = rel_binop_(sql, exp_dup(e1), e2, NULL,
"=");
+ cond = rel_binop_(sql, exp_dup(e1), e2, NULL,
"=", 0);
result = exp_atom(atom_general(exp_subtype(e1),
NULL, 0));
else_exp = e1; /* ELSE case */
} else {
@@ -3064,7 +3073,7 @@
if (cond) {
result = exp_dup(cond);
- cond = rel_unop_(sql, rel_unop_(sql, cond,
NULL, "isnull"), NULL, "not");
+ cond = rel_unop_(sql, rel_unop_(sql, cond,
NULL, "isnull", 0), NULL, "not", 0);
}
} else {
dlist *when = dn->data.sym->data.lval;
@@ -3077,7 +3086,7 @@
exp_destroy(r);
return NULL;
}
- cond = rel_binop_(sql, l, r, NULL, "=");
+ cond = rel_binop_(sql, l, r, NULL, "=", 0);
} else {
cond = rel_logical_value_exp(sql, rel,
when->h->data.sym, sql_sel);
}
@@ -3112,7 +3121,7 @@
if (cond) {
result = exp_dup(cond);
- cond = rel_unop_(sql, rel_unop_(sql, cond,
NULL, "isnull"), NULL, "not");
+ cond = rel_unop_(sql, rel_unop_(sql, cond,
NULL, "isnull", 0), NULL, "not", 0);
}
} else {
dlist *when = dn->data.sym->data.lval;
@@ -3125,7 +3134,7 @@
exp_destroy(r);
return NULL;
}
- cond = rel_binop_(sql, l, r, NULL, "=");
+ cond = rel_binop_(sql, l, r, NULL, "=", 0);
} else {
cond = rel_logical_value_exp(sql, rel,
when->h->data.sym, sql_sel);
}
@@ -3198,7 +3207,12 @@
return NULL;
}
- res = rel_nop_(sql, cond, result, res, NULL, NULL, "ifthenelse"
);
+ /* remove any null's in the condition */
+ if (has_nil(cond)) {
+ sql_exp *condnil = rel_unop_(sql, exp_dup(cond), NULL,
"isnull", 0);
+ cond = rel_nop_(sql, condnil, exp_atom_bool(0), cond,
NULL, NULL, "ifthenelse", 0);
+ }
+ res = rel_nop_(sql, cond, result, res, NULL, NULL,
"ifthenelse", 0);
if (!res) {
list_destroy(conds);
list_destroy(results);
@@ -3494,13 +3508,13 @@
switch (se->token) {
case SQL_OP:
- return rel_op(sql, se );
+ return rel_op(sql, se, ek);
case SQL_UNOP:
- return rel_unop(sql, rel, se, f);
+ return rel_unop(sql, rel, se, f, ek);
case SQL_BINOP:
- return rel_binop(sql, rel, se, f);
+ return rel_binop(sql, rel, se, f, ek);
case SQL_NOP:
- return rel_nop(sql, rel, se, f);
+ return rel_nop(sql, rel, se, f, ek);
case SQL_AGGR:
return rel_aggr(sql, rel, se, f);
case SQL_RANK:
@@ -3661,6 +3675,8 @@
static list *
rel_table_exp(mvc *sql, sql_rel *rel, symbol *column_e )
{
+ if (column_e->token == SQL_OP)
+ printf("SQL_OP\n");
if (column_e->token == SQL_TABLE) {
char *tname = column_e->data.lval->h->data.sval;
list *exps = rel_table_projections(sql, rel, tname);
@@ -3755,8 +3771,8 @@
rel = rel_compare_exp(sql, rel, exp_dup(le),
exp_dup(re), "=", NULL, sql_where);
if (full) {
sql_exp *cond;
- cond = rel_unop_(sql, exp_dup(le), NULL,
"isnull");
- le = rel_nop_(sql, cond, exp_dup(re),
exp_dup(le), NULL, NULL, "ifthenelse");
+ cond = rel_unop_(sql, exp_dup(le), NULL,
"isnull", 0);
+ le = rel_nop_(sql, cond, exp_dup(re),
exp_dup(le), NULL, NULL, "ifthenelse", 0);
}
exp_setname(le, nme, nm = _strdup(nm));
_DELETE(nm);
@@ -3826,6 +3842,22 @@
}
}
+static void
+rel_add_intern(mvc *sql, sql_rel *rel)
+{
+ if (rel->op == op_project && rel->l && rel->exps &&
!need_distinct(rel)) {
+ list *prjs = rel_projections(sql, rel->l, NULL, 1, 1);
+ node *n;
+
+ for(n=prjs->h; n; n = n->next) {
+ sql_exp *e = n->data;
+
+ if (is_intern(e))
+ append(rel->exps, e);
+ }
+ }
+}
+
static sql_rel *
rel_select_exp(mvc *sql, sql_rel *rel, sql_rel *outer, SelectNode *sn,
exp_kind ek)
{
@@ -3888,7 +3920,7 @@
outer_gbexps = rel_projections(sql,
outer, NULL, 1, 1);
if (!is_project(outer->op))
rel->l = outer =
rel_project(outer, rel_projections(sql, outer, NULL, 1, 1));
- e = rel_unop_(sql,
exp_dup(outer->exps->h->data), NULL, "identity");
+ e = rel_unop_(sql,
exp_dup(outer->exps->h->data), NULL, "identity", 0);
rel_project_add_exp(sql, outer, e);
set_processed(outer);
e = rel_lastexp(sql, outer);
@@ -4323,8 +4355,8 @@
return NULL;
}
rel = rel_compare_exp(sql, rel, exp_dup(ls),
exp_dup(rs), "=", NULL, sql_where);
- cond = rel_unop_(sql, exp_dup(ls), NULL, "isnull");
- ls = rel_nop_(sql, cond, exp_dup(rs), exp_dup(ls),
NULL, NULL, "ifthenelse");
+ cond = rel_unop_(sql, exp_dup(ls), NULL, "isnull", 0);
+ ls = rel_nop_(sql, cond, exp_dup(rs), exp_dup(ls),
NULL, NULL, "ifthenelse", 0);
exp_setname(ls, rnme, nm);
append(outexps, ls);
if (!rel) {
@@ -4507,6 +4539,12 @@
exp_setname(n, NULL, cname);
list_append(l, n);
}
+ /* skip any intern columns */
+ for (; m; m = m->next) {
+ sql_exp *e = m->data;
+ if (!is_intern(e))
+ break;
+ }
if (n || m) {
list_destroy(l);
return sql_error(sql, 02, "Column lists do not match");
@@ -4553,10 +4591,6 @@
return sql_error(sql, 01, "CREATE VIEW: ORDER
BY not supported");
}
- /*if (!instantiate)
- sql->emode = m_instantiate;*/
- /*if (instantiate) we also need the other views instantiated
- sql->emode = 0;*/
if (create) /* for subtable we only need direct dependencies */
sql->emode = m_deps;
sq = rel_selects(sql, query);
@@ -4564,6 +4598,9 @@
if (!sq)
return NULL;
+ if (!create)
+ rel_add_intern(sql, sq);
+
if (create) {
t = mvc_create_view(sql, s, name, q, 0);
as_subquery( sql, t, sq, column_spec );
U rel_optimizer.mx
Index: rel_optimizer.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_optimizer.mx,v
retrieving revision 1.37.2.1
retrieving revision 1.37.2.2
diff -u -d -r1.37.2.1 -r1.37.2.2
--- rel_optimizer.mx 29 Jan 2009 21:33:55 -0000 1.37.2.1
+++ rel_optimizer.mx 11 Feb 2009 19:35:44 -0000 1.37.2.2
@@ -165,6 +165,102 @@
}
static void
+exp_properties(sql_rel *rel, sql_exp *e)
+{
+ sql_exp *ne = NULL;
+
+ switch(e->type) {
+ case e_column:
+ ne = rel_find_exp(rel, e);
+ break;
+ case e_convert:
+ exp_properties(rel, e->l);
+ break;
+ case e_aggr:
+ case e_func:
+ if (e->l) {
+ list *l = e->l;
+ node *n = l->h;
+
+ for (;n != NULL; n = n->next)
+ exp_properties(rel, n->data);
+ }
+ /* rank operators have a second list of arguments */
+ if (e->r) {
+ list *l = e->r;
+ node *n = l->h;
+
+ for (;n != NULL; n = n->next)
+ exp_properties(rel, n->data);
+ }
+ break;
+ case e_cmp:
+ exp_properties(rel, e->l);
+ exp_properties(rel, e->r);
+ if (e->f)
+ exp_properties(rel, e->f);
+ break;
+ case e_atom:
+ /* atoms are used in e_cmp */
+ e->p = prop_create(PROP_USED, e->p);
+ break;
+ }
+ if (ne)
+ ne->p = prop_create(PROP_USED, ne->p);
+}
+
+static void
+exps_properties(sql_rel *rel, sql_rel *subrel)
+{
+ if (rel->exps) {
+ node *n;
+ for (n=rel->exps->h; n; n = n->next) {
+ sql_exp *e = n->data;
+
+ exp_properties(subrel, e);
+ }
+ }
+ if (rel->r && (rel->op == op_project || rel->op == op_groupby)) {
+ list *l = rel->r;
+ node *n;
+
+ for (n=l->h; n; n = n->next) {
+ sql_exp *e = n->data;
+
+ exp_properties(rel, e);
+ /* possibly project/groupby uses columns from the inner
*/
+ exp_properties(subrel, e);
+ }
+ }
+}
+
+static void
+exps_used(list *l)
+{
+ node *n;
+
+ if (l) {
+ for (n = l->h; n; n = n->next) {
+ sql_exp *e = n->data;
+
+ e->p = prop_create(PROP_USED, e->p);
+ }
+ }
+}
+
+static void
+rel_used(sql_rel *rel)
+{
+ if (is_topn(rel->op))
+ rel = rel->l;
+ if (rel->exps) {
+ exps_used(rel->exps);
+ if (rel->r && (rel->op == op_project || rel->op == op_groupby))
+ exps_used(rel->r);
+ }
+}
+
+static void
rel_properties(mvc *sql, global_props *gp, sql_rel *rel)
{
gp->cnt[(int)rel->op]++;
@@ -185,19 +281,37 @@
case op_except:
rel_properties(sql, gp, rel->l);
rel_properties(sql, gp, rel->r);
+ exps_properties(rel, rel->l);
+ exps_properties(rel, rel->r);
+
+ /* right hand expressions of set ops are used */
+ if (is_set(rel->op) && rel->r) {
+ sql_rel *r = rel->r;
+ /* setops have no clear dependency relation */
+ if (r->exps)
+ exps_used(r->exps);
+ }
break;
case op_project:
case op_select:
case op_groupby:
case op_topn:
- if (rel->l)
+ if (rel->l) {
rel_properties(sql, gp, rel->l);
+ exps_properties(rel, rel->l);
+ }
break;
case op_insert:
case op_update:
case op_delete:
- if (rel->r)
- rel_properties(sql, gp, rel->r);
+ if (rel->r) {
+ sql_rel *r = rel->r;
+
+ rel_properties(sql, gp, r);
+ /* updates have no clear dependency relation */
+ if (r->exps)
+ exps_used(r->exps);
+ }
break;
}
@@ -1070,6 +1184,37 @@
}
exps = rel->exps;
+ /* push select through join */
+ if (rel->op == op_select && r && r->op == op_join && !(rel_is_ref(r))) {
+ rel->exps = new_exp_list();
+ for (n = exps->h; n; n = n->next) {
+ sql_exp *e = exp_dup(n->data);
+ if (e->type == e_cmp) {
+ sql_exp *re = e->r;
+
+ if (re->card >= CARD_AGGR) {
+ list_append(rel->exps, e);
+ } else {
+ rel->l = rel_push_select(r, e->l, e);
+ /* only pushed down selects are counted
*/
+ if (r == rel->l)
+ (*changes)++;
+ r = rel->l;
+ }
+ } else {
+ list_append(rel->exps, e);
+ }
+ }
+ list_destroy(exps);
+ if (!list_length(rel->exps)) {
+ r = rel->l;
+ rel->l = NULL;
+ rel_destroy(rel);
+ return r;
+ }
+ return rel;
+ }
+
/* push select through set */
if (rel->op == op_select && r && is_set(r->op) && !(rel_is_ref(r))) {
rel->exps = new_exp_list();
@@ -1459,6 +1604,24 @@
return rel;
}
+/* when pushing projections up we may introduce new projects around
+ * operators with lower cardinality then before. So we need to fix
+ * the cardinality of these expressions (to atleast match that of the
+ * inner relation).
+ */
+static void
+exps_fix_card( list *exps, int card)
+{
+ node *n;
+
+ for (n = exps->h; n; n = n->next) {
+ sql_exp *e = n->data;
+
+ if (e->card > card)
+ e->card = card;
+ }
+}
+
/* Pushing projects up the tree. Done very early in the optimizer.
* Makes later steps easier.
*/
@@ -1590,6 +1753,7 @@
rel_destroy(r);
}
/* Done, ie introduce new project */
+ exps_fix_card(exps, rel->card);
rel = rel_project(rel, exps);
*changes = 1;
return rel;
@@ -1597,6 +1761,37 @@
return rel;
}
+sql_rel *
+rel_dce(int *changes, mvc *sql, sql_rel *rel)
+{
+ (void)sql;
+ if (is_project(rel->op) || rel->op == op_basetable) {
+ if (rel->exps) {
+ node *n;
+ list *exps = new_exp_list();
+
+ for(n=rel->exps->h; n; n = n->next) {
+ sql_exp *e = n->data;
+ if (find_prop(e->p, PROP_USED) ||
+ is_intern(e))
+ append(exps, exp_dup(e));
+ }
+ list_destroy(rel->exps);
+ rel->exps = exps;
+ if (list_length(exps) == 0) {
+ sql_rel *r = rel->l;
+
+ rel->l = NULL;
+ rel_destroy(rel);
+ *changes = 1;
+ return r;
+ }
+ }
+ return rel;
+ }
+ return rel;
+}
+
static int
index_exp(sql_exp *e, sql_idx *i)
{
@@ -1870,6 +2065,113 @@
return rel;
}
+/*
+ Rewrite if the expressions c and z are equal
+ REF
+ R()
+ union(
+ select(REF, [x, y, z]),
+ select(REF, [a, b, c])
+ )
+ into
+ REF
+ select(R(), c)
+ union(
+ select(REF, [x, y]),
+ select(REF, [a, b])
+ )
+ */
+
+
+static int
+exps_intern(list *exps)
+{
+ node *n;
+
+ for (n=exps->h; n; n = n->next) {
+ sql_exp *e = n->data;
+
+ if (is_intern(e))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+exps_distinct( sql_rel *l, list *l_exps, sql_rel *r, list *r_exps)
+{
+ (void)l;
+ (void)l_exps;
+ (void)r;
+ (void)r_exps;
+ return 1;
+}
+
+static int
+rels_are_distinct(sql_rel *l, sql_rel *r)
+{
+ if (l->op != r->op) /* different operators, not sure */
+ return 0;
+ switch(l->op) {
+ case op_basetable:
+ return 0;
+ case op_table:
+ return exps_distinct(l, l->exps, r, r->exps);
+ case op_join:
+ case op_left:
+ case op_right:
+ case op_full:
+ case op_semi:
+ case op_anti:
+ return (rels_are_distinct(l->l, r->l) ||
+ rels_are_distinct(l->r, r->r));
+ case op_union:
+ case op_inter:
+ case op_except:
+ return need_distinct(((sql_rel*)l->l)) &&
+ need_distinct(((sql_rel*)r->l));
+ case op_topn:
+ case op_project:
+ case op_groupby:
+ return (rels_are_distinct(l->l, r->l));
+ case op_select:
+ return (rels_are_distinct(l->l, r->l) ||
+ exps_distinct(l, l->exps, r, r->exps));
+ case op_insert:
+ case op_update:
+ case op_delete:
+ return 0;
+ }
+ return 0;
+}
+
+static sql_rel *
+rel_remove_distinct(int *changes, mvc *sql, sql_rel *rel)
+{
+ (void)sql;
+ (void)changes;
+ if (is_union(rel->op)) {
+ sql_rel *l = rel->l;
+ sql_rel *r = rel->r;
+
+ if (l == r)
+ set_nodistinct(rel);
+
+ if (rel->exps && exps_intern(rel->exps)) {
+ /* the union is a result of an or expression */
+
+ /* lets walk the trees and find the non matching
+ select/join expressions
+ */
+ if (rels_are_distinct(rel->l, rel->r))
+ set_nodistinct(rel);
+ return rel;
+ }
+ return rel;
+ }
+ return rel;
+}
+
static sql_rel *
rewrite(mvc *sql, sql_rel *rel, rewrite_fptr rewriter)
{
@@ -1941,6 +2243,7 @@
memset(&gp, 0, sizeof(global_props));
rel_properties(sql, &gp, rel);
+ rel_used(rel);
#ifdef DEBUG
{
@@ -1955,14 +2258,15 @@
#ifdef DEBUG
rel_print(sql, rel, 0);
#endif
-
/* TODO cleanup rel_optimzer.mx (reorder code, remove unused etc) */
+ /* Remove unused expressions */
+ if (gp.cnt[op_project])
+ rel = rewrite(sql, rel, &rel_dce);
+
/* TODO add optimizer which removes unions
(for example common rels, with only one different expression) */
- /* TODO remove distinct if its not needed */
-
/* TODO common sub relation/expression optimizer */
/* push (simple renaming) projections up */
@@ -1980,6 +2284,11 @@
the 'unique/primary (right hand side)' done before the (fake)-join
and the selections on the foreign
part done after. */
+ /* TODO remove distinct if its not needed */
+
+ if (gp.cnt[op_union])
+ rel = rewrite(sql, rel, &rel_remove_distinct);
+
if (gp.cnt[op_join] && gp.cnt[op_groupby])
rel = rewrite(sql, rel, &rel_push_join_down);
U rel_exp.mx
Index: rel_exp.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_exp.mx,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -d -r1.22 -r1.22.2.1
--- rel_exp.mx 13 Jan 2009 14:47:54 -0000 1.22
+++ rel_exp.mx 11 Feb 2009 19:35:44 -0000 1.22.2.1
@@ -509,16 +509,17 @@
case e_convert:
return rel_find_exp_(rel, e->l);
case e_aggr:
- case e_func: {
- list *l = e->l;
- node *n = l->h;
-
- while (ne == NULL && n != NULL) {
- ne = rel_find_exp_(rel, n->data);
- n = n->next;
+ case e_func:
+ if (e->l) {
+ list *l = e->l;
+ node *n = l->h;
+
+ while (ne == NULL && n != NULL) {
+ ne = rel_find_exp_(rel, n->data);
+ n = n->next;
+ }
+ return ne;
}
- return ne;
- }
case e_cmp:
return NULL;
case e_atom:
U rel_prop.mx
Index: rel_prop.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_prop.mx,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -d -r1.4 -r1.4.2.1
--- rel_prop.mx 7 Jan 2009 14:19:29 -0000 1.4
+++ rel_prop.mx 11 Feb 2009 19:35:45 -0000 1.4.2.1
@@ -34,6 +34,7 @@
#define PROP_JOINIDX 1 /* could use join idx */
#define PROP_HASHIDX 2 /* could use hash idx */
#define PROP_SORTIDX 3 /* could use sortedness */
+#define PROP_USED 10 /* number of times exp is used */
#define prop_list() list_create((fdestroy)&prop_destroy)
U rel_updates.mx
Index: rel_updates.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_updates.mx,v
retrieving revision 1.2.2.1
retrieving revision 1.2.2.2
diff -u -d -r1.2.2.1 -r1.2.2.2
--- rel_updates.mx 1 Feb 2009 09:57:12 -0000 1.2.2.1
+++ rel_updates.mx 11 Feb 2009 19:35:45 -0000 1.2.2.2
@@ -192,7 +192,9 @@
if (!r)
return NULL;
- if (r->op != op_project || need_distinct(r))
+ /* In case of missing project, order by or distinct, we need to add
+ and projection */
+ if (r->op != op_project || r->r || need_distinct(r))
r = rel_project(r, rel_projections(sql, r, NULL, 0, 0));
if ((r->exps && list_length(r->exps) != list_length(collist)) ||
(!r->exps && collist))
U rel_xml.mx
Index: rel_xml.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_xml.mx,v
retrieving revision 1.8
retrieving revision 1.8.2.1
diff -u -d -r1.8 -r1.8.2.1
--- rel_xml.mx 7 Jan 2009 14:19:29 -0000 1.8
+++ rel_xml.mx 11 Feb 2009 19:35:45 -0000 1.8.2.1
@@ -79,7 +79,7 @@
/* lets glue the xml content together */
if (res) {
- res = rel_binop_(sql, res, c_st, NULL,
"concat");
+ res = rel_binop_(sql, res, c_st, NULL,
"concat", 0);
} else {
res = c_st;
}
@@ -110,7 +110,7 @@
exp_destroy(res);
return NULL;
}
- return rel_nop_(sql, exp_atom_clob(tag), ns_st, attr_st, res, NULL,
"element");
+ return rel_nop_(sql, exp_atom_clob(tag), ns_st, attr_st, res, NULL,
"element", 0);
}
static sql_exp *
@@ -165,10 +165,10 @@
} else {
tag = _strdup(tag);
}
- c_st = rel_nop_(sql, exp_atom_clob(tag),
exp_dup(ns_st), exp_dup(attr_st), c_st, NULL, "element");
+ c_st = rel_nop_(sql, exp_atom_clob(tag),
exp_dup(ns_st), exp_dup(attr_st), c_st, NULL, "element", 0);
/* lets glue the xml content together */
if (res) {
- res = rel_binop_(sql, res, c_st, NULL,
"concat");
+ res = rel_binop_(sql, res, c_st, NULL,
"concat", 0);
} else {
res = c_st;
}
@@ -189,7 +189,7 @@
comment_st = rel_value_exp(sql, rel, comment, f, knd);
if (!comment_st)
return NULL;
- return rel_unop_(sql, comment_st, NULL, "comment");
+ return rel_unop_(sql, comment_st, NULL, "comment", 0);
}
static sql_exp *
@@ -208,7 +208,7 @@
attr_name = exp_name(attr_st);
}
attr_name_st = exp_atom_str(attr_name, &str_type);
- return rel_binop_(sql, attr_name_st, attr_st, NULL, "attribute");
+ return rel_binop_(sql, attr_name_st, attr_st, NULL, "attribute", 0);
}
@@ -227,7 +227,7 @@
return NULL;
}
if (res)
- res = rel_binop_(sql, res, concat_st, NULL, "concat");
+ res = rel_binop_(sql, res, concat_st, NULL, "concat",
0);
else
res = concat_st;
}
@@ -244,7 +244,7 @@
val_st = rel_value_exp(sql, rel, val, f, knd);
if (!val_st)
return NULL;
- return rel_unop_(sql, val_st, NULL, "document");
+ return rel_unop_(sql, val_st, NULL, "document", 0);
}
static sql_exp *
@@ -264,7 +264,7 @@
exp_destroy(target_st);
return NULL;
}
- return rel_binop_(sql, target_st, val_st, NULL, "pi");
+ return rel_binop_(sql, target_st, val_st, NULL, "pi", 0);
}
/* cast string too xml */
U rel_bin.mx
Index: rel_bin.mx
===================================================================
RCS file: /cvsroot/monetdb/sql/src/server/rel_bin.mx,v
retrieving revision 1.70
retrieving revision 1.70.2.1
diff -u -d -r1.70 -r1.70.2.1
--- rel_bin.mx 18 Jan 2009 12:30:28 -0000 1.70
+++ rel_bin.mx 11 Feb 2009 19:35:44 -0000 1.70.2.1
@@ -1245,6 +1245,47 @@
}
static stmt *
+find_order(stmt *s)
+{
+ if (s->type == st_limit)
+ assert(s->op1.stval->type == st_order || s->op1.stval->type ==
st_reorder);
+ else
+ assert(s->type == st_order || s->type == st_reorder);
+
+ while(s->type == st_reorder)
+ s = s->op1.stval;
+ return s;
+}
+
+static stmt *
+sql_reorder(stmt *order, stmt *s)
+{
+ list *l = create_stmt_list();
+ node *n;
+ /* we need to keep the order by column, to propagate the sort property*/
+ stmt *o = find_order(order);
+ stmt *x = o->op1.stval;
+
+ order = stmt_mark(stmt_reverse(order), 0);
+ for (n = s->op1.lval->h; n; n = n->next) {
+ stmt *sc = n->data;
+ char *cname = column_name(sc);
+ char *tname = table_name(sc);
+
+ if (sc != x)
+ sc =
stmt_reverse(stmt_order(stmt_reverse(stmt_join(stmt_dup(order), stmt_dup(sc),
cmp_equal)), 1));
+ else /* first order by column */
+ sc = stmt_mark(stmt_dup(o), 0);
+ sc = stmt_alias(sc, tname, cname );
+ list_append(l, sc);
+
+ }
+ stmt_destroy(s);
+ stmt_destroy(order);
+ return stmt_list(l);
+}
+
+static stmt *
rel2bin_project( mvc *sql, sql_rel *rel, list *refs)
{
list *l;
@@ -1260,7 +1301,13 @@
assert(0);
return NULL;
}
+ if (sub->type == st_ordered) {
+ stmt *n = sql_reorder(stmt_dup(sub->op1.stval),
stmt_dup(sub->op2.stval));
+ stmt_destroy(sub);
+ sub = n;
+ }
}
+
l = create_stmt_list();
for( en = rel->exps->h; en; en = en->next ) {
sql_exp *exp = en->data;
@@ -1604,7 +1651,7 @@
/* reduce pivot */
j = find_projection_join(limit);
- if (j) {
+ if (j && 0) {
p = find_pivot(j);
if (lmt < 0)
p = stmt_diff(stmt_dup(p), stmt_dup(limit));
@@ -1648,47 +1695,6 @@
}
static stmt *
-find_order(stmt *s)
-{
- if (s->type == st_limit)
- assert(s->op1.stval->type == st_order || s->op1.stval->type ==
st_reorder);
- else
- assert(s->type == st_order || s->type == st_reorder);
-
- while(s->type == st_reorder)
- s = s->op1.stval;
- return s;
-}
-
-static stmt *
-sql_reorder(stmt *order, stmt *s)
-{
- list *l = create_stmt_list();
- node *n;
- /* we need to keep the order by column, to propagate the sort property*/
- stmt *o = find_order(order);
- stmt *x = o->op1.stval;
-
- order = stmt_mark(stmt_reverse(order), 0);
- for (n = s->op1.lval->h; n; n = n->next) {
- stmt *sc = n->data;
- char *cname = column_name(sc);
- char *tname = table_name(sc);
-
- if (sc != x)
- sc =
stmt_reverse(stmt_order(stmt_reverse(stmt_join(stmt_dup(order), stmt_dup(sc),
cmp_equal)), 1));
- else /* first order by column */
- sc = stmt_mark(stmt_dup(o), 0);
- sc = stmt_alias(sc, tname, cname );
- list_append(l, sc);
-
- }
- stmt_destroy(s);
- stmt_destroy(order);
- return stmt_list(l);
-}
-
-static stmt *
nth( list *l, int n)
{
int i;
------------------------------------------------------------------------------
Create and Deploy Rich Internet Apps outside the browser with Adobe(R)AIR(TM)
software. With Adobe AIR, Ajax developers can use existing skills and code to
build responsive, highly engaging applications that combine the power of local
resources and data with the reach of the web. Download the Adobe AIR SDK and
Ajax docs to start building applications today-http://p.sf.net/sfu/adobe-com
_______________________________________________
Monetdb-sql-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-sql-checkins