read complex data from csv

This commit is contained in:
2022-10-20 06:00:57 +08:00
parent 818ab3b2e5
commit 6478deb7da
13 changed files with 200 additions and 59 deletions
+1
View File
@@ -1,4 +1,5 @@
from reconstruct.ast import Context, ast_node
saved_cxt = None
def initialize(cxt = None, keep = False):
+66 -8
View File
@@ -1,12 +1,13 @@
from copy import deepcopy
from dataclasses import dataclass
from enum import Enum, auto
from typing import Set, Tuple, Dict, Union, List, Optional
from typing import Dict, List, Optional, Set, Tuple, Union
from engine.types import *
from engine.utils import enlist, base62uuid, base62alp, get_legal_name
from reconstruct.storage import Context, TableInfo, ColRef
from engine.utils import base62alp, base62uuid, enlist, get_legal_name
from reconstruct.storage import ColRef, Context, TableInfo
class ast_node:
header = []
types = dict()
@@ -70,7 +71,11 @@ class projection(ast_node):
elif 'select_distinct' in node:
p = node['select_distinct']
self.distinct = True
if 'with' in node:
self.with_clause = projection(self, node['value'])
else:
self.with_clause = None
self.projections = p if type(p) is list else [p]
if self.parent is None:
self.context.sql_begin()
@@ -951,6 +956,9 @@ class load(ast_node):
if node['load']['file_type'] == 'module':
self.produce = self.produce_module
self.module = True
elif 'complex' in node['load']:
self.produce = self.produce_cpp
self.consume = lambda *_: None
elif self.context.dialect == 'MonetDB':
self.produce = self.produce_monetdb
else:
@@ -1019,7 +1027,56 @@ class load(ast_node):
self.sql = f'{s1} \'{p}\' {s2} '
if 'term' in node:
self.sql += f' {s3} \'{node["term"]["literal"]}\''
def produce_cpp(self, node):
self.context.has_dll = True
self.context.headers.add('"csv.h"')
node = node['load']
self.postproc_fname = 'ld_' + base62uuid(5)
self.context.postproc_begin(self.postproc_fname)
table:TableInfo = self.context.tables_byname[node['table']]
self.sql = F"SELECT {', '.join([c.name for c in table.columns])} FROM {table.table_name};"
self.emit(self.sql+';\n')
self.context.sql_end()
length_name = 'len_' + base62uuid(6)
self.context.emitc(f'auto {length_name} = server->cnt;')
out_typenames = [t.type.cname for t in table.columns]
outtable_col_nameslist = ', '.join([f'"{c.name}"' for c in table.columns])
self.outtable_col_names = 'names_' + base62uuid(4)
self.context.emitc(f'const char* {self.outtable_col_names}[] = {{{outtable_col_nameslist}}};')
self.out_table = 'tbl_' + base62uuid(4)
self.context.emitc(f'auto {self.out_table} = new TableInfo<{",".join(out_typenames)}>("{table.table_name}", {self.outtable_col_names});')
for i, c in enumerate(table.columns):
c.cxt_name = 'c_' + base62uuid(6)
self.context.emitc(f'decltype(auto) {c.cxt_name} = {self.out_table}->get_col<{i}>();')
self.context.emitc(f'{c.cxt_name}.initfrom({length_name}, server->getCol({i}), "{table.columns[i].name}");')
csv_reader_name = 'csv_reader_' + base62uuid(6)
col_types = [c.type.cname for c in table.columns]
col_tmp_names = ['tmp_'+base62uuid(8) for _ in range(len(table.columns))]
#col_names = ','.join([f'"{c.name}"' for c in table.columns])
term_field = ',' if 'term' not in node else node['term']['literal']
term_ele = ';' if 'ele' not in node else node['ele']['literal']
self.context.emitc(f'AQCSVReader<{len(col_types)}, \'{term_field.strip()[0]}\', \'{term_ele.strip()[0]}\'> {csv_reader_name}("{node["file"]["literal"]}");')
# self.context.emitc(f'{csv_reader_name}.read_header(io::ignore_extra_column, {col_names});')
self.context.emitc(f'{csv_reader_name}.next_line();')
for t, n in zip(col_types, col_tmp_names):
self.context.emitc(f'{t} {n};')
self.context.emitc(f'while({csv_reader_name}.read_row({",".join(col_tmp_names)})) {{ \n')
for i, c in enumerate(table.columns):
self.context.emitc(f'print({col_tmp_names[i]});')
self.context.emitc(f'{c.cxt_name}.emplace_back({col_tmp_names[i]});')
self.context.emitc('}')
self.context.emitc(f'print(*{self.out_table});')
self.context.emitc(f'{self.out_table}->monetdb_append_table(cxt->alt_server, "{table.table_name}");')
self.context.postproc_end(self.postproc_fname)
class outfile(ast_node):
name="_outfile"
def __init__(self, parent, node, context = None, *, sql = None):
@@ -1121,7 +1178,7 @@ class udf(ast_node):
def produce(self, node):
from engine.utils import get_legal_name, check_legal_name
from engine.utils import check_legal_name, get_legal_name
node = node[self.name]
# register udf
self.agg = 'Agg' in node
@@ -1216,7 +1273,7 @@ class udf(ast_node):
def consume(self, node):
from engine.utils import get_legal_name, check_legal_name
from engine.utils import check_legal_name, get_legal_name
node = node[self.name]
if 'params' in node:
@@ -1339,4 +1396,5 @@ def include(objs):
import sys
include(sys.modules[__name__])
+4 -2
View File
@@ -1,7 +1,8 @@
from typing import Optional, Set
from engine.types import *
from reconstruct.ast import ast_node
from reconstruct.storage import ColRef, Context
from engine.types import *
# TODO: Decouple expr and upgrade architecture
# C_CODE : get ccode/sql code?
@@ -31,6 +32,7 @@ class expr(ast_node):
def __init__(self, parent, node, *, c_code = None, supress_undefined = False):
from reconstruct.ast import projection, udf
# gen2 expr have multi-passes
# first pass parse json into expr tree
# generate target code in later passes upon need
@@ -78,7 +80,7 @@ class expr(ast_node):
ast_node.__init__(self, parent, node, None)
def init(self, _):
from reconstruct.ast import projection, _tmp_join_union
from reconstruct.ast import _tmp_join_union, projection
parent = self.parent
self.is_compound = parent.is_compound if type(parent) is expr else False
if type(parent) in [projection, expr, _tmp_join_union]:
+5 -2
View File
@@ -1,12 +1,14 @@
from typing import Dict, List, Set
from engine.types import *
from engine.utils import CaseInsensitiveDict, base62uuid, enlist
from typing import List, Dict, Set
class ColRef:
def __init__(self, _ty, cobj, table:'TableInfo', name, id, compound = False, _ty_args = None):
self.type : Types = AnyT
if type(_ty) is str:
self.type = builtin_types[_ty.lower()]
self.type = Types.decode(_ty)
if _ty_args:
self.type = self.type(enlist(_ty_args))
elif type(_ty) is Types:
@@ -17,6 +19,7 @@ class ColRef:
self.alias = set()
self.id = id # position in table
self.compound = compound # compound field (list as a field)
self.cxt_name = ''
# e.g. order by, group by, filter by expressions
self.__arr__ = (_ty, cobj, table, name, id)