bug fix on select into

dev
Bill 2 years ago
parent 48beab441d
commit 34a9fe105c

@ -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 = {}

@ -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:

@ -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
if not proj_expr.is_special: 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 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

@ -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

@ -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,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

@ -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;

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

@ -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"};

@ -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
SELECT ts.ID, avgs(10, hq.ClosePrice) into td
FROM TradedStocks AS ts NATURAL JOIN from TradedStocks
HistoricQuotes AS hq -- -- Monetdb wont recognize right table when
ASSUMING ASC hq.TradeDate -- -- doing a natural join
GROUP BY ts.ID
SELECT ID, avgs(10, ClosePrice)
FROM td NATURAL JOIN
HistoricQuotes
ASSUMING ASC TradeDate
GROUP BY ID
ORDER BY ID
Loading…
Cancel
Save