bug fix on select into

This commit is contained in:
2022-09-21 17:23:50 +08:00
parent 48beab441d
commit 34a9fe105c
12 changed files with 305 additions and 111 deletions
+11 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2 -2
View File
@@ -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
View File
@@ -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;
} }
+18 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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