bug fix on select into
This commit is contained in:
+11
-4
@@ -232,9 +232,9 @@ def ext (fx):
|
|||||||
|
|
||||||
|
|
||||||
# operator call behavior
|
# operator call behavior
|
||||||
def binary_op_behavior(op:OperatorBase, c_code, x, y):
|
def binary_op_behavior(op:OperatorBase, c_code, *xs):
|
||||||
name = op.cname if c_code else op.sqlname
|
name = op.cname if c_code else op.sqlname
|
||||||
return f'({x} {name} {y})'
|
return f'({f" {name} ".join(xs)})'
|
||||||
|
|
||||||
def unary_op_behavior(op:OperatorBase, c_code, x):
|
def unary_op_behavior(op:OperatorBase, c_code, x):
|
||||||
name = op.cname if c_code else op.sqlname
|
name = op.cname if c_code else op.sqlname
|
||||||
@@ -248,10 +248,16 @@ def count_behavior(op:OperatorBase, c_code, x, distinct = False):
|
|||||||
if not c_code:
|
if not c_code:
|
||||||
return f'{op.sqlname}({"distinct " if distinct else ""}{x})'
|
return f'{op.sqlname}({"distinct " if distinct else ""}{x})'
|
||||||
elif distinct:
|
elif distinct:
|
||||||
return '({x}).distinct_size()'
|
return f'({x}).distinct_size()'
|
||||||
else:
|
else:
|
||||||
return '{count()}'
|
return '{count()}'
|
||||||
|
|
||||||
|
def distinct_behavior(op:OperatorBase, c_code, x):
|
||||||
|
if not c_code:
|
||||||
|
return f'{op.sqlname}({x})'
|
||||||
|
else:
|
||||||
|
return f'({x}).distinct()'
|
||||||
|
|
||||||
def windowed_fn_behavor(op: OperatorBase, c_code, *x):
|
def windowed_fn_behavor(op: OperatorBase, c_code, *x):
|
||||||
if not c_code:
|
if not c_code:
|
||||||
return f'{op.sqlname}({", ".join([f"{xx}" for xx in x])})'
|
return f'{op.sqlname}({", ".join([f"{xx}" for xx in x])})'
|
||||||
@@ -277,6 +283,7 @@ oplte = OperatorBase('lte', 2, logical, cname = '<=', sqlname = '<=', call = bin
|
|||||||
opneq = OperatorBase('neq', 2, logical, cname = '!=', sqlname = '!=', call = binary_op_behavior)
|
opneq = OperatorBase('neq', 2, logical, cname = '!=', sqlname = '!=', call = binary_op_behavior)
|
||||||
opeq = OperatorBase('eq', 2, logical, cname = '==', sqlname = '=', call = binary_op_behavior)
|
opeq = OperatorBase('eq', 2, logical, cname = '==', sqlname = '=', call = binary_op_behavior)
|
||||||
opnot = OperatorBase('not', 1, logical, cname = '!', sqlname = 'NOT', call = unary_op_behavior)
|
opnot = OperatorBase('not', 1, logical, cname = '!', sqlname = 'NOT', call = unary_op_behavior)
|
||||||
|
opdistinct = OperatorBase('distinct', 1, as_is, cname = '.distinct()', sqlname = 'distinct', call = distinct_behavior)
|
||||||
# functional
|
# functional
|
||||||
fnmax = OperatorBase('max', 1, as_is, cname = 'max', sqlname = 'MAX', call = fn_behavior)
|
fnmax = OperatorBase('max', 1, as_is, cname = 'max', sqlname = 'MAX', call = fn_behavior)
|
||||||
fnmin = OperatorBase('min', 1, as_is, cname = 'min', sqlname = 'MIN', call = fn_behavior)
|
fnmin = OperatorBase('min', 1, as_is, cname = 'min', sqlname = 'MIN', call = fn_behavior)
|
||||||
@@ -315,7 +322,7 @@ builtin_binary_arith = _op_make_dict(opadd, opdiv, opmul, opsub, opmod)
|
|||||||
builtin_binary_logical = _op_make_dict(opand, opor, opxor, opgt, oplt, opge, oplte, opneq, opeq)
|
builtin_binary_logical = _op_make_dict(opand, opor, opxor, opgt, oplt, opge, oplte, opneq, opeq)
|
||||||
builtin_unary_logical = _op_make_dict(opnot)
|
builtin_unary_logical = _op_make_dict(opnot)
|
||||||
builtin_unary_arith = _op_make_dict(opneg)
|
builtin_unary_arith = _op_make_dict(opneg)
|
||||||
builtin_unary_special = _op_make_dict(spnull)
|
builtin_unary_special = _op_make_dict(spnull, opdistinct)
|
||||||
builtin_cstdlib = _op_make_dict(fnsqrt, fnlog, fnsin, fncos, fntan, fnpow)
|
builtin_cstdlib = _op_make_dict(fnsqrt, fnlog, fnsin, fncos, fntan, fnpow)
|
||||||
builtin_func = _op_make_dict(fnmax, fnmin, fnsum, fnavg, fnmaxs, fnmins, fndeltas, fnlast, fnsums, fnavgs, fncnt)
|
builtin_func = _op_make_dict(fnmax, fnmin, fnsum, fnavg, fnmaxs, fnmins, fndeltas, fnlast, fnsums, fnavgs, fncnt)
|
||||||
user_module_func = {}
|
user_module_func = {}
|
||||||
|
|||||||
+47
-1
@@ -1,3 +1,5 @@
|
|||||||
|
from collections import OrderedDict
|
||||||
|
from collections.abc import MutableMapping, Mapping
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
lower_alp = 'abcdefghijklmnopqrstuvwxyz'
|
lower_alp = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
@@ -7,6 +9,50 @@ base62alp = nums + lower_alp + upper_alp
|
|||||||
|
|
||||||
reserved_monet = ['month']
|
reserved_monet = ['month']
|
||||||
|
|
||||||
|
|
||||||
|
class CaseInsensitiveDict(MutableMapping):
|
||||||
|
def __init__(self, data=None, **kwargs):
|
||||||
|
self._store = OrderedDict()
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
self.update(data, **kwargs)
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
# Use the lowercased key for lookups, but store the actual
|
||||||
|
# key alongside the value.
|
||||||
|
self._store[key.lower()] = (key, value)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._store[key.lower()][1]
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
del self._store[key.lower()]
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (casedkey for casedkey, mappedvalue in self._store.values())
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._store)
|
||||||
|
|
||||||
|
def lower_items(self):
|
||||||
|
"""Like iteritems(), but with all lowercase keys."""
|
||||||
|
return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items())
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, Mapping):
|
||||||
|
other = CaseInsensitiveDict(other)
|
||||||
|
else:
|
||||||
|
return NotImplemented
|
||||||
|
# Compare insensitively
|
||||||
|
return dict(self.lower_items()) == dict(other.lower_items())
|
||||||
|
|
||||||
|
# Copy is required
|
||||||
|
def copy(self):
|
||||||
|
return CaseInsensitiveDict(self._store.values())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(dict(self.items()))
|
||||||
|
|
||||||
def base62uuid(crop=8):
|
def base62uuid(crop=8):
|
||||||
_id = uuid.uuid4().int
|
_id = uuid.uuid4().int
|
||||||
ret = ''
|
ret = ''
|
||||||
@@ -60,7 +106,7 @@ def defval(val, default):
|
|||||||
return default if val is None else val
|
return default if val is None else val
|
||||||
|
|
||||||
# escape must be readonly
|
# escape must be readonly
|
||||||
from typing import Set
|
from typing import Mapping, Set
|
||||||
def remove_last(pattern : str, string : str, escape : Set[str] = set()) -> str:
|
def remove_last(pattern : str, string : str, escape : Set[str] = set()) -> str:
|
||||||
idx = string.rfind(pattern)
|
idx = string.rfind(pattern)
|
||||||
if idx == -1:
|
if idx == -1:
|
||||||
|
|||||||
+86
-39
@@ -61,9 +61,16 @@ class projection(ast_node):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def produce(self, node):
|
def produce(self, node):
|
||||||
p = node['select']
|
|
||||||
self.projections = p if type(p) is list else [p]
|
|
||||||
self.add('SELECT')
|
self.add('SELECT')
|
||||||
|
self.has_postproc = False
|
||||||
|
if 'select' in node:
|
||||||
|
p = node['select']
|
||||||
|
self.distinct = False
|
||||||
|
elif 'select_distinct' in node:
|
||||||
|
p = node['select_distinct']
|
||||||
|
self.distinct = True
|
||||||
|
|
||||||
|
self.projections = p if type(p) is list else [p]
|
||||||
if self.parent is None:
|
if self.parent is None:
|
||||||
self.context.sql_begin()
|
self.context.sql_begin()
|
||||||
self.postproc_fname = 'dll_' + base62uuid(6)
|
self.postproc_fname = 'dll_' + base62uuid(6)
|
||||||
@@ -75,8 +82,8 @@ class projection(ast_node):
|
|||||||
if 'from' in node:
|
if 'from' in node:
|
||||||
from_clause = node['from']['table_source']
|
from_clause = node['from']['table_source']
|
||||||
self.datasource = join(self, from_clause)
|
self.datasource = join(self, from_clause)
|
||||||
if 'assumptions' in from_clause:
|
if 'assumptions' in node['from']:
|
||||||
self.assumptions = enlist(from_clause['assumptions'])
|
self.assumptions = enlist(node['from']['assumptions'])
|
||||||
|
|
||||||
if self.datasource is not None:
|
if self.datasource is not None:
|
||||||
self.datasource_changed = True
|
self.datasource_changed = True
|
||||||
@@ -109,61 +116,82 @@ class projection(ast_node):
|
|||||||
proj_map : Dict[int, List[Union[Types, int, str, expr]]]= dict()
|
proj_map : Dict[int, List[Union[Types, int, str, expr]]]= dict()
|
||||||
self.var_table = dict()
|
self.var_table = dict()
|
||||||
# self.sp_refs = set()
|
# self.sp_refs = set()
|
||||||
for i, proj in enumerate(self.projections):
|
i = 0
|
||||||
|
for proj in self.projections:
|
||||||
compound = False
|
compound = False
|
||||||
self.datasource.rec = set()
|
self.datasource.rec = set()
|
||||||
name = ''
|
name = ''
|
||||||
this_type = AnyT
|
this_type = AnyT
|
||||||
if type(proj) is dict:
|
if type(proj) is dict or proj == '*':
|
||||||
if 'value' in proj:
|
if 'value' in proj:
|
||||||
e = proj['value']
|
e = proj['value']
|
||||||
proj_expr = expr(self, e)
|
elif proj == '*':
|
||||||
this_type = proj_expr.type
|
e = '*'
|
||||||
name = proj_expr.sql
|
else:
|
||||||
compound = True # compound column
|
print('unknown projection', proj)
|
||||||
proj_expr.cols_mentioned = self.datasource.rec
|
proj_expr = expr(self, e)
|
||||||
alias = ''
|
sql_expr = expr(self, e, c_code=False)
|
||||||
if 'name' in proj: # renaming column by AS keyword
|
this_type = proj_expr.type
|
||||||
alias = proj['name']
|
name = proj_expr.sql
|
||||||
|
compound = True # compound column
|
||||||
|
proj_expr.cols_mentioned = self.datasource.rec
|
||||||
|
alias = ''
|
||||||
|
if 'name' in proj: # renaming column by AS keyword
|
||||||
|
alias = proj['name']
|
||||||
|
|
||||||
if not proj_expr.is_special:
|
if not proj_expr.is_special:
|
||||||
|
if proj_expr.node == '*':
|
||||||
|
name = [c.get_full_name() for c in self.datasource.rec]
|
||||||
|
else:
|
||||||
y = lambda x:x
|
y = lambda x:x
|
||||||
name = eval('f\'' + name + '\'')
|
count = lambda : 'count(*)'
|
||||||
|
name = enlist(sql_expr.eval(False, y, count=count))
|
||||||
|
for n in name:
|
||||||
offset = len(col_exprs)
|
offset = len(col_exprs)
|
||||||
if name not in self.var_table:
|
if n not in self.var_table:
|
||||||
self.var_table[name] = offset
|
self.var_table[n] = offset
|
||||||
if proj_expr.is_ColExpr and type(proj_expr.raw_col) is ColRef:
|
if proj_expr.is_ColExpr and type(proj_expr.raw_col) is ColRef:
|
||||||
for n in (proj_expr.raw_col.table.alias):
|
for _alias in (proj_expr.raw_col.table.alias):
|
||||||
self.var_table[f'{n}.'+name] = offset
|
self.var_table[f'{_alias}.'+n] = offset
|
||||||
proj_map[i] = [this_type, offset, proj_expr]
|
proj_map[i] = [this_type, offset, proj_expr]
|
||||||
col_expr = name + ' AS ' + alias if alias else name
|
col_expr = n + ' AS ' + alias if alias else n
|
||||||
if alias:
|
if alias:
|
||||||
self.var_table[alias] = offset
|
self.var_table[alias] = offset
|
||||||
|
|
||||||
col_exprs.append((col_expr, proj_expr.type))
|
col_exprs.append((col_expr, proj_expr.type))
|
||||||
else:
|
i += 1
|
||||||
self.context.headers.add('"./server/aggregations.h"')
|
else:
|
||||||
if self.datasource.rec is not None:
|
self.context.headers.add('"./server/aggregations.h"')
|
||||||
self.col_ext = self.col_ext.union(self.datasource.rec)
|
self.has_postproc = True
|
||||||
proj_map[i] = [this_type, proj_expr.sql, proj_expr]
|
if self.datasource.rec is not None:
|
||||||
|
self.col_ext = self.col_ext.union(self.datasource.rec)
|
||||||
disp_name = get_legal_name(alias if alias else name)
|
proj_map[i] = [this_type, proj_expr.sql, proj_expr]
|
||||||
|
i += 1
|
||||||
|
name = enlist(name)
|
||||||
|
disp_name = [get_legal_name(alias if alias else n) for n in name]
|
||||||
|
|
||||||
elif type(proj) is str:
|
elif type(proj) is str:
|
||||||
col = self.datasource.get_col(proj)
|
col = self.datasource.get_col(proj)
|
||||||
this_type = col.type
|
this_type = col.type
|
||||||
|
disp_name = proj
|
||||||
|
print('Unknown behavior:', proj, 'is str')
|
||||||
# name = col.name
|
# name = col.name
|
||||||
self.datasource.rec = None
|
self.datasource.rec = None
|
||||||
# TODO: Type deduction in Python
|
# TODO: Type deduction in Python
|
||||||
cols.append(ColRef(this_type, self.out_table, None, disp_name, i, compound=compound))
|
for n in disp_name:
|
||||||
|
cols.append(ColRef(this_type, self.out_table, None, n, len(cols), compound=compound))
|
||||||
|
|
||||||
self.out_table.add_cols(cols, new = False)
|
self.out_table.add_cols(cols, new = False)
|
||||||
|
|
||||||
if 'groupby' in node:
|
if 'groupby' in node:
|
||||||
self.group_node = groupby(self, node['groupby'])
|
self.group_node = groupby(self, node['groupby'])
|
||||||
|
if self.group_node.use_sp_gb:
|
||||||
|
self.has_postproc = True
|
||||||
else:
|
else:
|
||||||
self.group_node = None
|
self.group_node = None
|
||||||
|
|
||||||
|
if not self.has_postproc and self.distinct:
|
||||||
|
self.add('DISTINCT')
|
||||||
self.col_ext = [c for c in self.col_ext if c.name not in self.var_table] # remove duplicates in self.var_table
|
self.col_ext = [c for c in self.col_ext if c.name not in self.var_table] # remove duplicates in self.var_table
|
||||||
col_ext_names = [c.name for c in self.col_ext]
|
col_ext_names = [c.name for c in self.col_ext]
|
||||||
self.add(', '.join([c[0] for c in col_exprs] + col_ext_names))
|
self.add(', '.join([c[0] for c in col_exprs] + col_ext_names))
|
||||||
@@ -249,7 +277,7 @@ class projection(ast_node):
|
|||||||
self.group_node and
|
self.group_node and
|
||||||
(self.group_node.use_sp_gb and
|
(self.group_node.use_sp_gb and
|
||||||
val[2].cols_mentioned.intersection(
|
val[2].cols_mentioned.intersection(
|
||||||
self.datasource.all_cols.difference(self.group_node.refs))
|
self.datasource.all_cols().difference(self.group_node.refs))
|
||||||
) and val[2].is_compound # compound val not in key
|
) and val[2].is_compound # compound val not in key
|
||||||
# or
|
# or
|
||||||
# (not self.group_node and val[2].is_compound)
|
# (not self.group_node and val[2].is_compound)
|
||||||
@@ -282,25 +310,37 @@ class projection(ast_node):
|
|||||||
# for funcs evaluate f_i(x, ...)
|
# for funcs evaluate f_i(x, ...)
|
||||||
self.context.emitc(f'{self.out_table.contextname_cpp}->get_col<{key}>() = {val[1]};')
|
self.context.emitc(f'{self.out_table.contextname_cpp}->get_col<{key}>() = {val[1]};')
|
||||||
# print out col_is
|
# print out col_is
|
||||||
self.context.emitc(f'print(*{self.out_table.contextname_cpp});')
|
if 'into' not in node:
|
||||||
|
self.context.emitc(f'print(*{self.out_table.contextname_cpp});')
|
||||||
|
|
||||||
if self.outfile:
|
if self.outfile:
|
||||||
self.outfile.finalize()
|
self.outfile.finalize()
|
||||||
|
|
||||||
if 'into' in node:
|
if 'into' in node:
|
||||||
self.context.emitc(select_into(self, node['into']).ccode)
|
self.context.emitc(select_into(self, node['into']).ccode)
|
||||||
|
if not self.distinct:
|
||||||
|
self.finalize()
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
self.context.emitc(f'puts("done.");')
|
self.context.emitc(f'puts("done.");')
|
||||||
|
|
||||||
if self.parent is None:
|
if self.parent is None:
|
||||||
self.context.sql_end()
|
self.context.sql_end()
|
||||||
self.context.postproc_end(self.postproc_fname)
|
self.context.postproc_end(self.postproc_fname)
|
||||||
|
|
||||||
|
class select_distinct(projection):
|
||||||
|
first_order = 'select_distinct'
|
||||||
|
def consume(self, node):
|
||||||
|
super().consume(node)
|
||||||
|
if self.has_postproc:
|
||||||
|
self.context.emitc(
|
||||||
|
f'{self.out_table.table_name}->distinct();'
|
||||||
|
)
|
||||||
|
self.finalize()
|
||||||
|
|
||||||
class select_into(ast_node):
|
class select_into(ast_node):
|
||||||
def init(self, node):
|
def init(self, node):
|
||||||
if type(self.parent) is projection:
|
if isinstance(self.parent, projection):
|
||||||
if self.context.has_dll:
|
if self.context.has_dll:
|
||||||
# has postproc put back to monetdb
|
# has postproc put back to monetdb
|
||||||
self.produce = self.produce_cpp
|
self.produce = self.produce_cpp
|
||||||
@@ -308,8 +348,8 @@ class select_into(ast_node):
|
|||||||
self.produce = self.produce_sql
|
self.produce = self.produce_sql
|
||||||
else:
|
else:
|
||||||
raise ValueError('parent must be projection')
|
raise ValueError('parent must be projection')
|
||||||
|
|
||||||
def produce_cpp(self, node):
|
def produce_cpp(self, node):
|
||||||
assert(type(self.parent) is projection)
|
|
||||||
if not hasattr(self.parent, 'out_table'):
|
if not hasattr(self.parent, 'out_table'):
|
||||||
raise Exception('No out_table found.')
|
raise Exception('No out_table found.')
|
||||||
else:
|
else:
|
||||||
@@ -508,7 +548,7 @@ class groupby(ast_node):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def produce(self, node):
|
def produce(self, node):
|
||||||
if type(self.parent) is not projection:
|
if not isinstance(self.parent, projection):
|
||||||
raise ValueError('groupby can only be used in projection')
|
raise ValueError('groupby can only be used in projection')
|
||||||
|
|
||||||
node = enlist(node)
|
node = enlist(node)
|
||||||
@@ -554,7 +594,7 @@ class join(ast_node):
|
|||||||
self.tables : List[TableInfo] = []
|
self.tables : List[TableInfo] = []
|
||||||
self.tables_dir = dict()
|
self.tables_dir = dict()
|
||||||
self.rec = None
|
self.rec = None
|
||||||
self.top_level = self.parent and type(self.parent) is projection
|
self.top_level = self.parent and isinstance(self.parent, projection)
|
||||||
self.have_sep = False
|
self.have_sep = False
|
||||||
# self.tmp_name = 'join_' + base62uuid(4)
|
# self.tmp_name = 'join_' + base62uuid(4)
|
||||||
# self.datasource = TableInfo(self.tmp_name, [], self.context)
|
# self.datasource = TableInfo(self.tmp_name, [], self.context)
|
||||||
@@ -636,9 +676,16 @@ class join(ast_node):
|
|||||||
datasource.rec = None
|
datasource.rec = None
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@property
|
# @property
|
||||||
def all_cols(self):
|
def all_cols(self):
|
||||||
return set([c for t in self.tables for c in t.columns])
|
ret = set()
|
||||||
|
for table in self.tables:
|
||||||
|
rec = table.rec
|
||||||
|
table.rec = self.rec
|
||||||
|
ret.update(table.all_cols())
|
||||||
|
table.rec = rec
|
||||||
|
return ret
|
||||||
|
|
||||||
def consume(self, node):
|
def consume(self, node):
|
||||||
self.sql = ''
|
self.sql = ''
|
||||||
for j in self.joins:
|
for j in self.joins:
|
||||||
@@ -787,7 +834,7 @@ class outfile(ast_node):
|
|||||||
self.sql = sql if sql else ''
|
self.sql = sql if sql else ''
|
||||||
|
|
||||||
def init(self, _):
|
def init(self, _):
|
||||||
assert(type(self.parent) is projection)
|
assert(isinstance(self.parent, projection))
|
||||||
if not self.parent.use_postproc:
|
if not self.parent.use_postproc:
|
||||||
if self.context.dialect == 'MonetDB':
|
if self.context.dialect == 'MonetDB':
|
||||||
self.produce = self.produce_monetdb
|
self.produce = self.produce_monetdb
|
||||||
|
|||||||
+17
-9
@@ -1,4 +1,4 @@
|
|||||||
from typing import Optional
|
from typing import Optional, Set
|
||||||
from reconstruct.ast import ast_node
|
from reconstruct.ast import ast_node
|
||||||
from reconstruct.storage import ColRef, Context
|
from reconstruct.storage import ColRef, Context
|
||||||
from engine.types import *
|
from engine.types import *
|
||||||
@@ -199,11 +199,8 @@ class expr(ast_node):
|
|||||||
self.udf_decltypecall = ex_vname.sql
|
self.udf_decltypecall = ex_vname.sql
|
||||||
else:
|
else:
|
||||||
print(f'Undefined expr: {key}{val}')
|
print(f'Undefined expr: {key}{val}')
|
||||||
if 'distinct' in val and key != count:
|
|
||||||
if self.c_code:
|
|
||||||
self.sql = 'distinct ' + self.sql
|
|
||||||
elif self.is_compound:
|
|
||||||
self.sql = '(' + self.sql + ').distinct()'
|
|
||||||
if type(node) is str:
|
if type(node) is str:
|
||||||
if self.is_udfexpr:
|
if self.is_udfexpr:
|
||||||
curr_udf : udf = self.root.udf
|
curr_udf : udf = self.root.udf
|
||||||
@@ -235,8 +232,13 @@ class expr(ast_node):
|
|||||||
# get the column from the datasource in SQL context
|
# get the column from the datasource in SQL context
|
||||||
else:
|
else:
|
||||||
if self.datasource is not None:
|
if self.datasource is not None:
|
||||||
self.raw_col = self.datasource.parse_col_names(node)
|
if (node == '*' and
|
||||||
self.raw_col = self.raw_col if type(self.raw_col) is ColRef else None
|
not (type(self.parent) is expr
|
||||||
|
and 'count' in self.parent.node)):
|
||||||
|
self.datasource.all_cols()
|
||||||
|
else:
|
||||||
|
self.raw_col = self.datasource.parse_col_names(node)
|
||||||
|
self.raw_col = self.raw_col if type(self.raw_col) is ColRef else None
|
||||||
if self.raw_col is not None:
|
if self.raw_col is not None:
|
||||||
self.is_ColExpr = True
|
self.is_ColExpr = True
|
||||||
table_name = ''
|
table_name = ''
|
||||||
@@ -259,10 +261,16 @@ class expr(ast_node):
|
|||||||
self.is_compound = True
|
self.is_compound = True
|
||||||
self.opname = self.raw_col
|
self.opname = self.raw_col
|
||||||
else:
|
else:
|
||||||
self.sql = '\'' + node + '\''
|
self.sql = '\'' + node + '\'' if node != '*' else '*'
|
||||||
self.type = StrT
|
self.type = StrT
|
||||||
self.opname = self.sql
|
self.opname = self.sql
|
||||||
if self.c_code and self.datasource is not None:
|
if self.c_code and self.datasource is not None:
|
||||||
|
if (type(self.parent) is expr and
|
||||||
|
'distinct' in self.parent.node and
|
||||||
|
not self.is_special):
|
||||||
|
# this node is executed by monetdb
|
||||||
|
# gb condition, not special
|
||||||
|
self.sql = f'distinct({self.sql})'
|
||||||
self.sql = f'{{y(\"{self.sql}\")}}'
|
self.sql = f'{{y(\"{self.sql}\")}}'
|
||||||
elif type(node) is bool:
|
elif type(node) is bool:
|
||||||
self.type = BoolT
|
self.type = BoolT
|
||||||
|
|||||||
+18
-2
@@ -1,5 +1,5 @@
|
|||||||
from engine.types import *
|
from engine.types import *
|
||||||
from engine.utils import base62uuid, enlist
|
from engine.utils import CaseInsensitiveDict, base62uuid, enlist
|
||||||
from typing import List, Dict, Set
|
from typing import List, Dict, Set
|
||||||
|
|
||||||
class ColRef:
|
class ColRef:
|
||||||
@@ -20,6 +20,18 @@ class ColRef:
|
|||||||
# e.g. order by, group by, filter by expressions
|
# e.g. order by, group by, filter by expressions
|
||||||
|
|
||||||
self.__arr__ = (_ty, cobj, table, name, id)
|
self.__arr__ = (_ty, cobj, table, name, id)
|
||||||
|
|
||||||
|
def get_full_name(self):
|
||||||
|
table_name = self.table.table_name
|
||||||
|
it_alias = iter(self.table.alias)
|
||||||
|
alias = next(it_alias, table_name)
|
||||||
|
try:
|
||||||
|
while alias == table_name:
|
||||||
|
alias = next(it_alias)
|
||||||
|
except StopIteration:
|
||||||
|
alias = table_name
|
||||||
|
return f'{alias}.{self.name}'
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if type(key) is str:
|
if type(key) is str:
|
||||||
return getattr(self, key)
|
return getattr(self, key)
|
||||||
@@ -35,7 +47,7 @@ class TableInfo:
|
|||||||
self.table_name : str = table_name
|
self.table_name : str = table_name
|
||||||
self.contextname_cpp : str = ''
|
self.contextname_cpp : str = ''
|
||||||
self.alias : Set[str] = set([table_name])
|
self.alias : Set[str] = set([table_name])
|
||||||
self.columns_byname : Dict[str, ColRef] = dict() # column_name, type
|
self.columns_byname : Dict[str, ColRef] = CaseInsensitiveDict() # column_name, type
|
||||||
self.columns : List[ColRef] = []
|
self.columns : List[ColRef] = []
|
||||||
self.cxt = cxt
|
self.cxt = cxt
|
||||||
# keep track of temp vars
|
# keep track of temp vars
|
||||||
@@ -86,6 +98,10 @@ class TableInfo:
|
|||||||
else:
|
else:
|
||||||
return datasource.parse_col_names(parsedColExpr[1])
|
return datasource.parse_col_names(parsedColExpr[1])
|
||||||
|
|
||||||
|
def all_cols(self):
|
||||||
|
if type(self.rec) is set:
|
||||||
|
self.rec.update(self.columns)
|
||||||
|
return set(self.columns)
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
def new(self):
|
def new(self):
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
example:
|
example:
|
||||||
g++-9 -shared -fPIC example.cpp aquery_mem.cpp -fno-semantic-interposition -Ofast -march=native -flto --std=c++1z -o ../test.so
|
$(CXX) -shared -fPIC example.cpp aquery_mem.cpp -fno-semantic-interposition -Ofast -march=native -flto --std=c++1z -o ../test.so
|
||||||
|
|
||||||
all: example
|
all: example
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ extern void register_memory(void* ptr, deallocator_t deallocator);
|
|||||||
__AQEXPORT__(void) init_session(Context* cxt);
|
__AQEXPORT__(void) init_session(Context* cxt);
|
||||||
|
|
||||||
#define __AQ_NO_SESSION__ __AQEXPORT__(void) init_session(Context*) {}
|
#define __AQ_NO_SESSION__ __AQEXPORT__(void) init_session(Context*) {}
|
||||||
void* memcpy(void*, void*, unsigned long long);
|
void* memcpy(void*, const void*, unsigned long long);
|
||||||
struct ColRef_storage {
|
struct ColRef_storage {
|
||||||
void* container;
|
void* container;
|
||||||
unsigned int capacity, size;
|
unsigned int capacity, size;
|
||||||
|
|||||||
@@ -117,9 +117,9 @@ decayed_t<VT, types::GetLongType<T>> sums(const VT<T>& arr) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
template<class T, template<typename ...> class VT>
|
template<class T, template<typename ...> class VT>
|
||||||
decayed_t<VT, types::GetFPType<T>> avgs(const VT<T>& arr) {
|
decayed_t<VT, types::GetFPType<types::GetLongType<T>>> avgs(const VT<T>& arr) {
|
||||||
const uint32_t& len = arr.size;
|
const uint32_t& len = arr.size;
|
||||||
typedef types::GetFPType<T> FPType;
|
typedef types::GetFPType<types::GetLongType<T>> FPType;
|
||||||
decayed_t<VT, FPType> ret(len);
|
decayed_t<VT, FPType> ret(len);
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
types::GetLongType<T> s;
|
types::GetLongType<T> s;
|
||||||
|
|||||||
+67
-14
@@ -26,6 +26,21 @@ namespace types {
|
|||||||
struct Coercion;
|
struct Coercion;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
template <template <class...> class VT, class T>
|
||||||
|
std::ostream& operator<<(std::ostream& os, const VT<T>& v)
|
||||||
|
{
|
||||||
|
v.out();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __AQ__HAS__INT128__
|
||||||
|
std::ostream& operator<<(std::ostream& os, __int128 & v);
|
||||||
|
std::ostream& operator<<(std::ostream& os, __uint128_t & v);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, types::date_t & v);
|
||||||
|
std::ostream& operator<<(std::ostream& os, types::time_t & v);
|
||||||
|
std::ostream& operator<<(std::ostream& os, types::timestamp_t & v);
|
||||||
template<typename _Ty>
|
template<typename _Ty>
|
||||||
class ColView;
|
class ColView;
|
||||||
template<typename _Ty>
|
template<typename _Ty>
|
||||||
@@ -200,19 +215,7 @@ public:
|
|||||||
}
|
}
|
||||||
inline ColRef<_Ty> subvec(uint32_t start = 0) { return subvec_deep(start, size); }
|
inline ColRef<_Ty> subvec(uint32_t start = 0) { return subvec_deep(start, size); }
|
||||||
};
|
};
|
||||||
template <template <class...> class VT, class T>
|
|
||||||
std::ostream& operator<<(std::ostream& os, const VT<T>& v)
|
|
||||||
{
|
|
||||||
v.out();
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
std::ostream& operator<<(std::ostream& os, types::date_t & v);
|
|
||||||
std::ostream& operator<<(std::ostream& os, types::time_t & v);
|
|
||||||
std::ostream& operator<<(std::ostream& os, types::timestamp_t & v);
|
|
||||||
#ifdef __AQ__HAS__INT128__
|
|
||||||
std::ostream& operator<<(std::ostream& os, __int128 & v);
|
|
||||||
std::ostream& operator<<(std::ostream& os, __uint128_t & v);
|
|
||||||
#endif
|
|
||||||
template <class Type>
|
template <class Type>
|
||||||
struct decayed_impl<ColView, Type> { typedef ColRef<Type> type; };
|
struct decayed_impl<ColView, Type> { typedef ColRef<Type> type; };
|
||||||
|
|
||||||
@@ -433,7 +436,10 @@ struct TableInfo {
|
|||||||
template <size_t ...Is>
|
template <size_t ...Is>
|
||||||
void inline
|
void inline
|
||||||
reserve(std::index_sequence<Is...>, uint32_t size) {
|
reserve(std::index_sequence<Is...>, uint32_t size) {
|
||||||
const auto& assign_sz = [&size](auto& col){ col.size = size;};
|
const auto& assign_sz = [&size](auto& col){
|
||||||
|
col.size = size;
|
||||||
|
col.grow();
|
||||||
|
};
|
||||||
(assign_sz(get_col<Is>()), ...);
|
(assign_sz(get_col<Is>()), ...);
|
||||||
}
|
}
|
||||||
template <size_t ...Is>
|
template <size_t ...Is>
|
||||||
@@ -481,6 +487,53 @@ struct TableView {
|
|||||||
template <size_t j = 0>
|
template <size_t j = 0>
|
||||||
typename std::enable_if < j < sizeof...(Types) - 1, void>::type print_impl(const uint32_t& i, const char* __restrict sep = " ") const;
|
typename std::enable_if < j < sizeof...(Types) - 1, void>::type print_impl(const uint32_t& i, const char* __restrict sep = " ") const;
|
||||||
|
|
||||||
|
template <size_t ...Is>
|
||||||
|
decltype(auto) inline
|
||||||
|
get_record(std::index_sequence<Is...>, uint32_t i) {
|
||||||
|
return std::forward_as_tuple(info.template get_col<Is>()[idxs[i]] ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableInfo<Types ...>* get_tableinfo(const char* name = nullptr, const char** names = nullptr) {
|
||||||
|
if (name == nullptr)
|
||||||
|
name = info.name;
|
||||||
|
|
||||||
|
const char* info_names[sizeof...(Types)];
|
||||||
|
if (name == nullptr) {
|
||||||
|
for(uint32_t i = 0; i < sizeof...(Types); ++i)
|
||||||
|
info_names[i] = info.colrefs[i].name;
|
||||||
|
names = info_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TableInfo<Types ...>(name, names);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableInfo<Types ...>* materialize(const char* name = nullptr, const char** names = nullptr) {
|
||||||
|
std::make_index_sequence<sizeof...(Types)> seq;
|
||||||
|
auto table = get_tableinfo(name, names);
|
||||||
|
table->reserve(seq, idxs->size);
|
||||||
|
for (uint32_t i = 0; i < idxs->size; ++i) {
|
||||||
|
table->set_record(get_record(i));
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableInfo<Types ...>* distinct(const char* name = nullptr, const char** names = nullptr) {
|
||||||
|
std::unordered_set<tuple_type> d_records;
|
||||||
|
std::make_index_sequence<sizeof...(Types)> seq;
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < idxs->size; ++j) {
|
||||||
|
d_records.insert(get_record(seq, j));
|
||||||
|
}
|
||||||
|
|
||||||
|
TableInfo<Types ...>* ret = get_tableinfo(name, names);
|
||||||
|
ret->reserve(seq, d_records.size());
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (const auto& dr : d_records) {
|
||||||
|
ret->set_record(seq, dr, i++);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
~TableView() {
|
~TableView() {
|
||||||
delete idxs;
|
delete idxs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "monetdbe.h"
|
#include "monetdbe.h"
|
||||||
|
|
||||||
inline constexpr monetdbe_types AQType_2_monetdbe[] = {
|
inline constexpr monetdbe_types AQType_2_monetdbe[] = {
|
||||||
monetdbe_int32_t, monetdbe_float, monetdbe_str, monetdbe_double, monetdbe_int64_t,
|
monetdbe_int32_t, monetdbe_float, monetdbe_str, monetdbe_double, monetdbe_double, monetdbe_int64_t,
|
||||||
#ifdef HAVE_HGE
|
#ifdef HAVE_HGE
|
||||||
monetdbe_int128_t,
|
monetdbe_int128_t,
|
||||||
#else
|
#else
|
||||||
@@ -22,7 +22,8 @@ inline constexpr monetdbe_types AQType_2_monetdbe[] = {
|
|||||||
#else
|
#else
|
||||||
monetdbe_int64_t,
|
monetdbe_int64_t,
|
||||||
#endif
|
#endif
|
||||||
monetdbe_int16_t, monetdbe_int8_t, monetdbe_bool, monetdbe_int64_t, monetdbe_int64_t, monetdbe_int64_t
|
monetdbe_int16_t, monetdbe_int8_t, monetdbe_bool, monetdbe_int64_t,
|
||||||
|
monetdbe_timestamp, monetdbe_int64_t, monetdbe_int64_t
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class ...Ts>
|
template<class ...Ts>
|
||||||
@@ -34,23 +35,33 @@ void TableInfo<Ts ...>::monetdb_append_table(void* srv, const char* alt_name) {
|
|||||||
monetdbe_column** monetdbe_cols = new monetdbe_column * [sizeof...(Ts)];
|
monetdbe_column** monetdbe_cols = new monetdbe_column * [sizeof...(Ts)];
|
||||||
|
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
const auto get_col = [&monetdbe_cols, &i](auto v) {
|
puts("getcols...");
|
||||||
|
const auto get_col = [&monetdbe_cols, &i, *this](auto v) {
|
||||||
|
printf("%d %d\n", i, (ColRef<void>*)v - colrefs);
|
||||||
monetdbe_cols[i++] = (monetdbe_column*)v->monetdb_get_col();
|
monetdbe_cols[i++] = (monetdbe_column*)v->monetdb_get_col();
|
||||||
};
|
};
|
||||||
(get_col((ColRef<Ts>*)(colrefs + i)), ...);
|
(get_col((ColRef<Ts>*)(colrefs + i)), ...);
|
||||||
|
puts("getcols done");
|
||||||
|
for(int i = 0; i < sizeof...(Ts); ++i)
|
||||||
|
{
|
||||||
|
printf("no:%d name: %s count:%d data: %p \n",
|
||||||
|
i, monetdbe_cols[i]->name, monetdbe_cols[i]->count, monetdbe_cols[i]->data);
|
||||||
|
}
|
||||||
std::string create_table_str = "CREATE TABLE ";
|
std::string create_table_str = "CREATE TABLE ";
|
||||||
create_table_str += alt_name;
|
create_table_str += alt_name;
|
||||||
create_table_str += " (";
|
create_table_str += " (";
|
||||||
i = 0;
|
i = 0;
|
||||||
const auto get_name_type = [&i, *this]() {
|
const auto get_name_type = [&i, *this, &create_table_str](auto v) {
|
||||||
return std::string(colrefs[i++].name) + ' ';
|
create_table_str+= std::string(colrefs[i++].name) + ' ' +
|
||||||
|
std::string(types::SQL_Type[types::Types<std::remove_pointer_t<decltype(v)>>::getType()]) + ", ";
|
||||||
};
|
};
|
||||||
create_table_str += ((get_name_type() + types::SQL_Type[types::Types<Ts>::getType()] + ", ") + ... + std::string(""));
|
(get_name_type((Ts*)(0)), ...);
|
||||||
auto last_comma = create_table_str.find_last_of(',');
|
auto last_comma = create_table_str.find_last_of(',');
|
||||||
if (last_comma != static_cast<decltype(last_comma)>(-1)) {
|
if (last_comma != static_cast<decltype(last_comma)>(-1)) {
|
||||||
create_table_str[last_comma] = ')';
|
create_table_str[last_comma] = ')';
|
||||||
Server* server = (Server*)srv;
|
Server* server = (Server*)srv;
|
||||||
|
puts("create table...");
|
||||||
|
puts(create_table_str.c_str());
|
||||||
server->exec(create_table_str.c_str());
|
server->exec(create_table_str.c_str());
|
||||||
if (!server->last_error) {
|
if (!server->last_error) {
|
||||||
auto err = monetdbe_append(*((monetdbe_database*)server->server), "sys", alt_name, monetdbe_cols, sizeof...(Ts));
|
auto err = monetdbe_append(*((monetdbe_database*)server->server), "sys", alt_name, monetdbe_cols, sizeof...(Ts));
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ namespace types {
|
|||||||
};
|
};
|
||||||
static constexpr const char* printf_str[] = { "%d", "%f", "%s", "%lf", "%Lf", "%ld", "%d", "%hi", "%s", "%s", "%c",
|
static constexpr const char* printf_str[] = { "%d", "%f", "%s", "%lf", "%Lf", "%ld", "%d", "%hi", "%s", "%s", "%c",
|
||||||
"%u", "%lu", "%s", "%hu", "%hhu", "%s", "%s", "Vector<%s>", "%s", "NULL", "ERROR" };
|
"%u", "%lu", "%s", "%hu", "%hhu", "%s", "%s", "Vector<%s>", "%s", "NULL", "ERROR" };
|
||||||
static constexpr const char* SQL_Type[] = { "INT", "REAL", "TEXT", "DOUBLE", "DOUBLE", "BIGINT", "HUGEINT", "SMALLINT", "DATE", "TIME", "TINYINT",
|
static constexpr const char* SQL_Type[] = { "INT", "REAL", "VARCHAR(15)", "DOUBLE", "DOUBLE", "BIGINT", "HUGEINT", "SMALLINT", "DATE", "TIME", "TINYINT",
|
||||||
"INT", "BIGINT", "HUGEINT", "SMALLINT", "TINYINT", "BIGINT", "BOOL", "BIGINT", "TIMESTAMP", "NULL", "ERROR"};
|
"INT", "BIGINT", "HUGEINT", "SMALLINT", "TINYINT", "BIGINT", "BOOL", "BIGINT", "TIMESTAMP", "NULL", "ERROR"};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+28
-22
@@ -1,27 +1,27 @@
|
|||||||
-- please run datagen.get_stock_data() to generate data/stock.csv first
|
-- please run datagen.get_stock_data() to generate data/stock.csv first
|
||||||
|
|
||||||
-- create table ticks(ID varchar(10), timestamp int, tradeDate date, price int);
|
create table ticks(ID varchar(10), timestamp int, tradeDate date, price int);
|
||||||
|
|
||||||
-- LOAD DATA INFILE "data/stock.csv"
|
LOAD DATA INFILE "data/stock.csv"
|
||||||
-- INTO TABLE ticks
|
INTO TABLE ticks
|
||||||
-- FIELDS TERMINATED BY ","
|
FIELDS TERMINATED BY ","
|
||||||
|
|
||||||
-- SELECT max(price-mins(price))
|
SELECT max(price-mins(price))
|
||||||
-- FROM ticks ASSUMING ASC timestamp
|
FROM ticks ASSUMING ASC timestamp
|
||||||
-- WHERE ID="S"
|
WHERE ID="S"
|
||||||
-- AND tradeDate='2003-01-10'
|
AND tradeDate='2003-01-10'
|
||||||
|
|
||||||
-- create table base(ID varchar(10), name varchar(10));
|
create table base(ID varchar(10), name varchar(10));
|
||||||
|
|
||||||
-- LOAD DATA INFILE "data/base.csv"
|
LOAD DATA INFILE "data/base.csv"
|
||||||
-- INTO TABLE base
|
INTO TABLE base
|
||||||
-- FIELDS TERMINATED BY ","
|
FIELDS TERMINATED BY ","
|
||||||
|
|
||||||
-- SELECT last(price)
|
SELECT last(price)
|
||||||
-- FROM ticks t, base b
|
FROM ticks t, base b
|
||||||
-- ASSUMING ASC name, ASC timestamp
|
ASSUMING ASC name, ASC timestamp
|
||||||
-- WHERE t.ID=b.ID
|
WHERE t.ID=b.ID
|
||||||
-- AND name="x"
|
AND name="x"
|
||||||
|
|
||||||
create table TradedStocks(ID varchar(15), SeqNo int, TradeDate date, TimeStamp time, Type varchar(5));
|
create table TradedStocks(ID varchar(15), SeqNo int, TradeDate date, TimeStamp time, Type varchar(5));
|
||||||
create table HistoricQuotes(ID varchar(15), TradeDate date, HighPrice real, LowPrice real, ClosePrice real, OpenPrice real, volume bigint);
|
create table HistoricQuotes(ID varchar(15), TradeDate date, HighPrice real, LowPrice real, ClosePrice real, OpenPrice real, volume bigint);
|
||||||
@@ -33,9 +33,15 @@ LOAD DATA INFILE "data/hist-price-file.csv"
|
|||||||
INTO TABLE HistoricQuotes
|
INTO TABLE HistoricQuotes
|
||||||
FIELDS TERMINATED BY "|"
|
FIELDS TERMINATED BY "|"
|
||||||
|
|
||||||
|
select distinct ID, TradeDate
|
||||||
|
into td
|
||||||
|
from TradedStocks
|
||||||
|
-- -- Monetdb wont recognize right table when
|
||||||
|
-- -- doing a natural join
|
||||||
|
|
||||||
SELECT ts.ID, avgs(10, hq.ClosePrice)
|
SELECT ID, avgs(10, ClosePrice)
|
||||||
FROM TradedStocks AS ts NATURAL JOIN
|
FROM td NATURAL JOIN
|
||||||
HistoricQuotes AS hq
|
HistoricQuotes
|
||||||
ASSUMING ASC hq.TradeDate
|
ASSUMING ASC TradeDate
|
||||||
GROUP BY ts.ID
|
GROUP BY ID
|
||||||
|
ORDER BY ID
|
||||||
Reference in New Issue
Block a user