<commit_before>/*
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.monetdb.org/Legal/MonetDBLicense
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is the MonetDB Database System.
 *
 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
 * Copyright August 2008-2014 MonetDB B.V.
 * All Rights Reserved.
 */

#include <monetdb_config.h>
#include "sql_semantic.h"
#include "rel_semantic.h"
#include "rel_exp.h"
#include "rel_psm.h"
#include "rel_prop.h" /* for prop_copy() */
#include "rel_optimizer.h"

static sql_exp * 
exp_create(sql_allocator *sa, int type ) 
{
	sql_exp *e = SA_NEW(sa, sql_exp);

	e->name = NULL;
	e->rname = NULL;
	e->card = 0;
	e->flag = 0;
	e->l = e->r = NULL;
	e->type = (expression_type)type;
	e->f = NULL;
	e->p = NULL;
	e->used = 0;
	e->tpe.type = NULL;
	e->tpe.comp_type = NULL;
	e->tpe.digits = e->tpe.scale = 0;
	return e;
}

sql_exp * 
exp_compare(sql_allocator *sa, sql_exp *l, sql_exp *r, int cmptype) 
{
	sql_exp *e = exp_create(sa, e_cmp);
	e->card = l->card;
	if (e->card == CARD_ATOM && !exp_is_atom(l))
		e->card = CARD_AGGR;
	e->l = l;
	e->r = r;
	e->flag = cmptype;
	return e;
}

sql_exp * 
exp_compare2(sql_allocator *sa, sql_exp *l, sql_exp *r, sql_exp *h, int cmptype) 
{
	sql_exp *e = exp_create(sa, e_cmp);
	e->card = l->card;
	if (e->card == CARD_ATOM && !exp_is_atom(l))
		e->card = CARD_AGGR;
	e->l = l;
	e->r = r;
	if (h)
		e->f = h;
	e->flag = cmptype;
	return e;
}

sql_exp *
exp_filter(sql_allocator *sa, sql_exp *l, list *r, sql_subfunc *f, int anti) 
{
	sql_exp *e = exp_create(sa, e_cmp);

	e->card = l->card;
	if (e->card == CARD_ATOM && !exp_is_atom(l))
		e->card = CARD_AGGR;
	e->l = l;
	e->r = r;
	e->f = f;
	e->flag = cmp_filter;
	if (anti)
		set_anti(e);
	return e;
}

sql_exp *
exp_filter2(sql_allocator *sa, sql_exp *l, sql_exp *r1, sql_exp *r2, sql_subfunc *f, int anti) 
{
	list *r = sa_list(sa);

	append(r, r1);
	if (r2)
		append(r, r2);
	return exp_filter(sa, l, r, f, anti);
}

sql_exp *
exp_or(sql_allocator *sa, list *l, list *r)
{
	sql_exp *f = NULL;
	sql_exp *e = exp_create(sa, e_cmp);
	
	f = l->h?l->h->data:r->h?r->h->data:NULL;
	e->card = l->h?exps_card(l):exps_card(r);
	e->l = l;
	e->r = r;
	assert(f);
	e->f = f;
	e->flag = cmp_or;
	return e;
}

sql_exp *
exp_in(sql_allocator *sa, sql_exp *l, list *r, int cmptype)
{
	sql_exp *e = exp_create(sa, e_cmp);
	
	e->card = l->card;
	e->l = l;
	e->r = r;
	assert( cmptype == cmp_in || cmptype == cmp_notin);
	e->flag = cmptype;
	return e;
}


static sql_subtype*
dup_subtype(sql_allocator *sa, sql_subtype *st)
{
	sql_subtype *res = SA_NEW(sa, sql_subtype);

	*res = *st;
	return res;
}

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 = exp->name;
	if (exp->rname)
		e->rname = exp->rname;
	return e;
}

sql_exp * 
exp_op( sql_allocator *sa, list *l, sql_subfunc *f )
{
	sql_exp *e = exp_create(sa, e_func);
	e->card = exps_card(l);
	if (!l || list_length(l) == 0)
		e->card = CARD_ATOM; /* unop returns a single atom */
	e->l = l;
	e->f = f; 
	return e;
}

sql_exp * 
exp_aggr( sql_allocator *sa, list *l, sql_subaggr *a, int distinct, int no_nils, int card, int has_nils )
{
	sql_exp *e = exp_create(sa, e_aggr);
	e->card = card;
	e->l = l;
	e->f = a; 
	if (distinct)
		set_distinct(e);
	if (no_nils)
		set_no_nil(e);
	if (!has_nils)
		set_has_no_nil(e);
	return e;
}

sql_exp * 
exp_atom(sql_allocator *sa, atom *a) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->card = CARD_ATOM;
	e->tpe = a->tpe;
	e->l = a;
	return e;
}

sql_exp *
exp_atom_bool(sql_allocator *sa, int b) 
{
	sql_subtype bt; 

	sql_find_subtype(&bt, "boolean", 0, 0);
	if (b) 
		return exp_atom(sa, atom_bool(sa, &bt, TRUE ));
	else
		return exp_atom(sa, atom_bool(sa, &bt, FALSE ));
}

sql_exp *
exp_atom_int(sql_allocator *sa, int i) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "int", 9, 0);
	return exp_atom(sa, atom_int(sa, &it, i ));
}

sql_exp *
exp_atom_lng(sql_allocator *sa, lng i) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "bigint", 19, 0);
	return exp_atom(sa, atom_int(sa, &it, (lng)i ));
}

sql_exp *
exp_atom_wrd(sql_allocator *sa, wrd w) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "wrd", 19, 0);
	return exp_atom(sa, atom_int(sa, &it, (lng)w ));
}

sql_exp *
exp_atom_flt(sql_allocator *sa, flt f) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "double", 24, 0);
	return exp_atom(sa, atom_float(sa, &it, (dbl)f ));
}

sql_exp *
exp_atom_dbl(sql_allocator *sa, dbl f) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "double", 53, 0);
	return exp_atom(sa, atom_float(sa, &it, (dbl)f ));
}

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));
}

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_atom_ptr(sql_allocator *sa, void *s) 
{
	sql_subtype *t = sql_bind_localtype("ptr");
	return exp_atom(sa, atom_ptr(sa, t, s));
}

sql_exp * 
exp_atom_ref(sql_allocator *sa, int i, sql_subtype *tpe) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->card = CARD_ATOM;
	e->flag = i;
	if (tpe)
		e->tpe = *tpe;
	return e;
}

atom *
exp_value(sql_exp *e, atom **args, int maxarg)
{
	if (!e || e->type != e_atom)
		return NULL; 
	if (e->l) {	   /* literal */
		return e->l;
	} else if (e->r) { /* param (ie not set) */
		return NULL; 
	} else if (e->flag < maxarg) {
		return args[e->flag]; 
	}
	return NULL; 
}

sql_exp * 
exp_param(sql_allocator *sa, char *name, sql_subtype *tpe, int frame) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->r = name;
	e->card = CARD_ATOM;
	e->flag = frame;
	if (tpe)
		e->tpe = *tpe;
	return e;
}

sql_exp * 
exp_values(sql_allocator *sa, list *exps) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->card = CARD_MULTI;
	e->f = exps;
	return e;
}

list * 
exp_types(sql_allocator *sa, list *exps) 
{
	list *l = sa_list(sa);
	node *n;

	for ( n = exps->h; n; n = n->next)
		append(l, exp_subtype(n->data));
	return l;
}

int
have_nil(list *exps)
{
	int has_nil = 0;
	node *n;

	for ( n = exps->h; n && !has_nil; n = n->next) {
		sql_exp *e = n->data;
		has_nil |= has_nil(e);
	}
	return has_nil;
}

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)?arname:org_rname;
	e->name = acname;
	e->l = org_rname;
	e->r = 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_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 = cname;
	e->rname = rname;
	e->r = e->name;
	e->l = e->rname;
	if (t)
		e->tpe = *t;
	if (!has_nils)
		set_has_no_nil(e);
	if (intern)
		set_intern(e);
	return e;
}

sql_exp *
exp_set(sql_allocator *sa, char *name, sql_exp *val, int level)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->name = name;
	e->l = val;
	e->flag = PSM_SET + SET_PSM_LEVEL(level);
	return e;
}

sql_exp * 
exp_var(sql_allocator *sa, char *name, sql_subtype *type, int level)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->name = name;
	e->tpe = *type;
	e->flag = PSM_VAR + SET_PSM_LEVEL(level);
	return e;
}

sql_exp *
exp_return(sql_allocator *sa, sql_exp *val, int level)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->l = val;
	e->flag = PSM_RETURN + SET_PSM_LEVEL(level);
	return e;
}

sql_exp * 
exp_while(sql_allocator *sa, sql_exp *cond, list *stmts)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->l = cond;
	e->r = stmts;
	e->flag = PSM_WHILE;
	return e;
}

sql_exp * 
exp_if(sql_allocator *sa, sql_exp *cond, list *if_stmts, list *else_stmts)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->l = cond;
	e->r = if_stmts;
	e->f = else_stmts;
	e->flag = PSM_IF;
	return e;
}

sql_exp * 
exp_rel(mvc *sql, sql_rel *rel)
{
	sql_exp *e = exp_create(sql->sa, e_psm);

	rel = rel_optimizer(sql, rel);
	e->l = rel;
	e->flag = PSM_REL;
	return e;
}

/* 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;
}

void 
noninternexp_setname(sql_allocator *sa, sql_exp *e, char *rname, char *name )
{
	if (!is_intern(e))
		exp_setname(sa, e, rname, name);
}

str
number2name(str s, int len, int i)
{
	s[--len] = 0;
	while(i>0) {
		s[--len] = '0' + (i & 7);
		i >>= 3;
	}
	s[--len] = 'L';
	return s + len;
}

void 
exp_setrelname(sql_allocator *sa, sql_exp *e, int nr)
{
	char name[16], *nme;

	nme = number2name(name, 16, nr);
	e->rname = sa_strdup(sa, nme);
}

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);
	e->rname = sa_strdup(sa, nme);
	return e;
}

void
exp_swap( sql_exp *e ) 
{
	sql_exp *s = e->l;

	e->l = e->r;
	e->r = s;
	e->flag = swap_compare((comp_type)e->flag);
}

sql_subtype *
exp_subtype( sql_exp *e )
{
	switch(e->type) {
	case e_atom: {
		if (e->l) {
			atom *a = e->l;
			return atom_type(a);
		} else if (e->tpe.type) { /* atom reference */
			return &e->tpe;
		}
		break;
	}
	case e_convert:
	case e_column:
		if (e->tpe.type)
			return &e->tpe;
		break;
	case e_aggr: {
		sql_subaggr *a = e->f;
		return &a->res;
	}
	case e_func: {
		if (e->f) {
			sql_subfunc *f = e->f;
			return &f->res;
		}
		return NULL;
	}
	case e_cmp:
		/* return bit */
	default:
		return NULL;
	}
	return NULL;
}

char *
exp_name( sql_exp *e )
{
	if (e->name)
		return e->name;
	if (e->type == e_convert && e->l)
		return exp_name(e->l);
	return NULL;
}

char *
exp_relname( sql_exp *e )
{
	if (e->rname)
		return e->rname;
	if (e->type == e_column && e->l)
		return e->l;
	return NULL;
}

char *
exp_find_rel_name(sql_exp *e)
{
	if (e->rname)
		return e->rname;
	switch(e->type) {
	case e_column:
		if (e->l)
			return e->l;
		break;
	case e_convert:
		return exp_find_rel_name(e->l);
	default:
		return NULL;
	}
	return NULL;
}

int
exp_card( sql_exp *e )
{
	return e->card;
}

char *
exp_func_name( sql_exp *e )
{
	if (e->type == e_func && e->f) {
		sql_subfunc *f = e->f;
		return f->func->base.name;
	}
	if (e->name)
		return e->name;
	if (e->type == e_convert && e->l)
		return exp_name(e->l);
	return NULL;
}

int 
exp_cmp( sql_exp *e1, sql_exp *e2)
{
	return (e1 == e2)?0:-1;
}

int 
exp_match( sql_exp *e1, sql_exp *e2)
{
	if (exp_cmp(e1, e2) == 0)
		return 1;
	if (e1->type == e2->type && e1->type == e_column) {
		if (!e1->l || !e2->l || strcmp(e1->l, e2->l) != 0) 
			return 0;
		if (!e1->r || !e2->r || strcmp(e1->r, e2->r) != 0)
			return 0;
		return 1;
	}
	return 0;
}

int 
exp_refers( sql_exp *c, sql_exp *p)
{
	if (c->type == e_column) {
		if (!p->name || !c->r || strcmp(p->name, c->r) != 0)
			return 0;
		if (!c->l || (p->rname && strcmp(p->rname, c->l) != 0) || (!p->rname && strcmp(p->l, c->l) != 0))
			return 0;
		return 1;
	}
	return 0;
}<commit_msg>fixed bug in exp_match which caused range optimization to fail<commit_after>/*
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.monetdb.org/Legal/MonetDBLicense
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is the MonetDB Database System.
 *
 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
 * Copyright August 2008-2014 MonetDB B.V.
 * All Rights Reserved.
 */

#include <monetdb_config.h>
#include "sql_semantic.h"
#include "rel_semantic.h"
#include "rel_exp.h"
#include "rel_psm.h"
#include "rel_prop.h" /* for prop_copy() */
#include "rel_optimizer.h"

static sql_exp * 
exp_create(sql_allocator *sa, int type ) 
{
	sql_exp *e = SA_NEW(sa, sql_exp);

	e->name = NULL;
	e->rname = NULL;
	e->card = 0;
	e->flag = 0;
	e->l = e->r = NULL;
	e->type = (expression_type)type;
	e->f = NULL;
	e->p = NULL;
	e->used = 0;
	e->tpe.type = NULL;
	e->tpe.comp_type = NULL;
	e->tpe.digits = e->tpe.scale = 0;
	return e;
}

sql_exp * 
exp_compare(sql_allocator *sa, sql_exp *l, sql_exp *r, int cmptype) 
{
	sql_exp *e = exp_create(sa, e_cmp);
	e->card = l->card;
	if (e->card == CARD_ATOM && !exp_is_atom(l))
		e->card = CARD_AGGR;
	e->l = l;
	e->r = r;
	e->flag = cmptype;
	return e;
}

sql_exp * 
exp_compare2(sql_allocator *sa, sql_exp *l, sql_exp *r, sql_exp *h, int cmptype) 
{
	sql_exp *e = exp_create(sa, e_cmp);
	e->card = l->card;
	if (e->card == CARD_ATOM && !exp_is_atom(l))
		e->card = CARD_AGGR;
	e->l = l;
	e->r = r;
	if (h)
		e->f = h;
	e->flag = cmptype;
	return e;
}

sql_exp *
exp_filter(sql_allocator *sa, sql_exp *l, list *r, sql_subfunc *f, int anti) 
{
	sql_exp *e = exp_create(sa, e_cmp);

	e->card = l->card;
	if (e->card == CARD_ATOM && !exp_is_atom(l))
		e->card = CARD_AGGR;
	e->l = l;
	e->r = r;
	e->f = f;
	e->flag = cmp_filter;
	if (anti)
		set_anti(e);
	return e;
}

sql_exp *
exp_filter2(sql_allocator *sa, sql_exp *l, sql_exp *r1, sql_exp *r2, sql_subfunc *f, int anti) 
{
	list *r = sa_list(sa);

	append(r, r1);
	if (r2)
		append(r, r2);
	return exp_filter(sa, l, r, f, anti);
}

sql_exp *
exp_or(sql_allocator *sa, list *l, list *r)
{
	sql_exp *f = NULL;
	sql_exp *e = exp_create(sa, e_cmp);
	
	f = l->h?l->h->data:r->h?r->h->data:NULL;
	e->card = l->h?exps_card(l):exps_card(r);
	e->l = l;
	e->r = r;
	assert(f);
	e->f = f;
	e->flag = cmp_or;
	return e;
}

sql_exp *
exp_in(sql_allocator *sa, sql_exp *l, list *r, int cmptype)
{
	sql_exp *e = exp_create(sa, e_cmp);
	
	e->card = l->card;
	e->l = l;
	e->r = r;
	assert( cmptype == cmp_in || cmptype == cmp_notin);
	e->flag = cmptype;
	return e;
}


static sql_subtype*
dup_subtype(sql_allocator *sa, sql_subtype *st)
{
	sql_subtype *res = SA_NEW(sa, sql_subtype);

	*res = *st;
	return res;
}

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 = exp->name;
	if (exp->rname)
		e->rname = exp->rname;
	return e;
}

sql_exp * 
exp_op( sql_allocator *sa, list *l, sql_subfunc *f )
{
	sql_exp *e = exp_create(sa, e_func);
	e->card = exps_card(l);
	if (!l || list_length(l) == 0)
		e->card = CARD_ATOM; /* unop returns a single atom */
	e->l = l;
	e->f = f; 
	return e;
}

sql_exp * 
exp_aggr( sql_allocator *sa, list *l, sql_subaggr *a, int distinct, int no_nils, int card, int has_nils )
{
	sql_exp *e = exp_create(sa, e_aggr);
	e->card = card;
	e->l = l;
	e->f = a; 
	if (distinct)
		set_distinct(e);
	if (no_nils)
		set_no_nil(e);
	if (!has_nils)
		set_has_no_nil(e);
	return e;
}

sql_exp * 
exp_atom(sql_allocator *sa, atom *a) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->card = CARD_ATOM;
	e->tpe = a->tpe;
	e->l = a;
	return e;
}

sql_exp *
exp_atom_bool(sql_allocator *sa, int b) 
{
	sql_subtype bt; 

	sql_find_subtype(&bt, "boolean", 0, 0);
	if (b) 
		return exp_atom(sa, atom_bool(sa, &bt, TRUE ));
	else
		return exp_atom(sa, atom_bool(sa, &bt, FALSE ));
}

sql_exp *
exp_atom_int(sql_allocator *sa, int i) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "int", 9, 0);
	return exp_atom(sa, atom_int(sa, &it, i ));
}

sql_exp *
exp_atom_lng(sql_allocator *sa, lng i) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "bigint", 19, 0);
	return exp_atom(sa, atom_int(sa, &it, (lng)i ));
}

sql_exp *
exp_atom_wrd(sql_allocator *sa, wrd w) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "wrd", 19, 0);
	return exp_atom(sa, atom_int(sa, &it, (lng)w ));
}

sql_exp *
exp_atom_flt(sql_allocator *sa, flt f) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "double", 24, 0);
	return exp_atom(sa, atom_float(sa, &it, (dbl)f ));
}

sql_exp *
exp_atom_dbl(sql_allocator *sa, dbl f) 
{
	sql_subtype it; 

	sql_find_subtype(&it, "double", 53, 0);
	return exp_atom(sa, atom_float(sa, &it, (dbl)f ));
}

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));
}

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_atom_ptr(sql_allocator *sa, void *s) 
{
	sql_subtype *t = sql_bind_localtype("ptr");
	return exp_atom(sa, atom_ptr(sa, t, s));
}

sql_exp * 
exp_atom_ref(sql_allocator *sa, int i, sql_subtype *tpe) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->card = CARD_ATOM;
	e->flag = i;
	if (tpe)
		e->tpe = *tpe;
	return e;
}

atom *
exp_value(sql_exp *e, atom **args, int maxarg)
{
	if (!e || e->type != e_atom)
		return NULL; 
	if (e->l) {	   /* literal */
		return e->l;
	} else if (e->r) { /* param (ie not set) */
		return NULL; 
	} else if (e->flag < maxarg) {
		return args[e->flag]; 
	}
	return NULL; 
}

sql_exp * 
exp_param(sql_allocator *sa, char *name, sql_subtype *tpe, int frame) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->r = name;
	e->card = CARD_ATOM;
	e->flag = frame;
	if (tpe)
		e->tpe = *tpe;
	return e;
}

sql_exp * 
exp_values(sql_allocator *sa, list *exps) 
{
	sql_exp *e = exp_create(sa, e_atom);
	e->card = CARD_MULTI;
	e->f = exps;
	return e;
}

list * 
exp_types(sql_allocator *sa, list *exps) 
{
	list *l = sa_list(sa);
	node *n;

	for ( n = exps->h; n; n = n->next)
		append(l, exp_subtype(n->data));
	return l;
}

int
have_nil(list *exps)
{
	int has_nil = 0;
	node *n;

	for ( n = exps->h; n && !has_nil; n = n->next) {
		sql_exp *e = n->data;
		has_nil |= has_nil(e);
	}
	return has_nil;
}

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)?arname:org_rname;
	e->name = acname;
	e->l = org_rname;
	e->r = 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_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 = cname;
	e->rname = rname;
	e->r = e->name;
	e->l = e->rname;
	if (t)
		e->tpe = *t;
	if (!has_nils)
		set_has_no_nil(e);
	if (intern)
		set_intern(e);
	return e;
}

sql_exp *
exp_set(sql_allocator *sa, char *name, sql_exp *val, int level)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->name = name;
	e->l = val;
	e->flag = PSM_SET + SET_PSM_LEVEL(level);
	return e;
}

sql_exp * 
exp_var(sql_allocator *sa, char *name, sql_subtype *type, int level)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->name = name;
	e->tpe = *type;
	e->flag = PSM_VAR + SET_PSM_LEVEL(level);
	return e;
}

sql_exp *
exp_return(sql_allocator *sa, sql_exp *val, int level)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->l = val;
	e->flag = PSM_RETURN + SET_PSM_LEVEL(level);
	return e;
}

sql_exp * 
exp_while(sql_allocator *sa, sql_exp *cond, list *stmts)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->l = cond;
	e->r = stmts;
	e->flag = PSM_WHILE;
	return e;
}

sql_exp * 
exp_if(sql_allocator *sa, sql_exp *cond, list *if_stmts, list *else_stmts)
{
	sql_exp *e = exp_create(sa, e_psm);

	e->l = cond;
	e->r = if_stmts;
	e->f = else_stmts;
	e->flag = PSM_IF;
	return e;
}

sql_exp * 
exp_rel(mvc *sql, sql_rel *rel)
{
	sql_exp *e = exp_create(sql->sa, e_psm);

	rel = rel_optimizer(sql, rel);
	e->l = rel;
	e->flag = PSM_REL;
	return e;
}

/* 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;
}

void 
noninternexp_setname(sql_allocator *sa, sql_exp *e, char *rname, char *name )
{
	if (!is_intern(e))
		exp_setname(sa, e, rname, name);
}

str
number2name(str s, int len, int i)
{
	s[--len] = 0;
	while(i>0) {
		s[--len] = '0' + (i & 7);
		i >>= 3;
	}
	s[--len] = 'L';
	return s + len;
}

void 
exp_setrelname(sql_allocator *sa, sql_exp *e, int nr)
{
	char name[16], *nme;

	nme = number2name(name, 16, nr);
	e->rname = sa_strdup(sa, nme);
}

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);
	e->rname = sa_strdup(sa, nme);
	return e;
}

void
exp_swap( sql_exp *e ) 
{
	sql_exp *s = e->l;

	e->l = e->r;
	e->r = s;
	e->flag = swap_compare((comp_type)e->flag);
}

sql_subtype *
exp_subtype( sql_exp *e )
{
	switch(e->type) {
	case e_atom: {
		if (e->l) {
			atom *a = e->l;
			return atom_type(a);
		} else if (e->tpe.type) { /* atom reference */
			return &e->tpe;
		}
		break;
	}
	case e_convert:
	case e_column:
		if (e->tpe.type)
			return &e->tpe;
		break;
	case e_aggr: {
		sql_subaggr *a = e->f;
		return &a->res;
	}
	case e_func: {
		if (e->f) {
			sql_subfunc *f = e->f;
			return &f->res;
		}
		return NULL;
	}
	case e_cmp:
		/* return bit */
	default:
		return NULL;
	}
	return NULL;
}

char *
exp_name( sql_exp *e )
{
	if (e->name)
		return e->name;
	if (e->type == e_convert && e->l)
		return exp_name(e->l);
	return NULL;
}

char *
exp_relname( sql_exp *e )
{
	if (e->rname)
		return e->rname;
	if (e->type == e_column && e->l)
		return e->l;
	return NULL;
}

char *
exp_find_rel_name(sql_exp *e)
{
	if (e->rname)
		return e->rname;
	switch(e->type) {
	case e_column:
		if (e->l)
			return e->l;
		break;
	case e_convert:
		return exp_find_rel_name(e->l);
	default:
		return NULL;
	}
	return NULL;
}

int
exp_card( sql_exp *e )
{
	return e->card;
}

char *
exp_func_name( sql_exp *e )
{
	if (e->type == e_func && e->f) {
		sql_subfunc *f = e->f;
		return f->func->base.name;
	}
	if (e->name)
		return e->name;
	if (e->type == e_convert && e->l)
		return exp_name(e->l);
	return NULL;
}

int 
exp_cmp( sql_exp *e1, sql_exp *e2)
{
	return (e1 == e2)?0:-1;
}

int 
exp_match( sql_exp *e1, sql_exp *e2)
{
	if (exp_cmp(e1, e2) == 0)
		return 1;
	if (e1->type == e2->type && e1->type == e_column) {
		if (e1->l != e2->l && (!e1->l || !e2->l || strcmp(e1->l, e2->l) != 0)) 
			return 0;
		if (!e1->r || !e2->r || strcmp(e1->r, e2->r) != 0)
			return 0;
		return 1;
	}
	return 0;
}

int 
exp_refers( sql_exp *c, sql_exp *p)
{
	if (c->type == e_column) {
		if (!p->name || !c->r || strcmp(p->name, c->r) != 0)
			return 0;
		if (!c->l || (p->rname && strcmp(p->rname, c->l) != 0) || (!p->rname && strcmp(p->l, c->l) != 0))
			return 0;
		return 1;
	}
	return 0;
}
{'fraction_non_alphanumeric': 0.1777889489338528, 'fraction_numerical': 0.008545934397385949, 'mean_word_length': 3.5854782942758354, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 417, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3584286', 'n_tokens_mistral': 11677, 'n_tokens_neox': 11285, 'n_words': 2665}