This commit is contained in:
2023-02-15 22:17:14 +08:00
parent c5bf4c46e4
commit acc610280e
7 changed files with 178 additions and 22 deletions
+2 -1
View File
@@ -18,10 +18,11 @@ def generate(ast, cxt):
if k in ast_node.types.keys():
ast_node.types[k](None, ast, cxt)
def exec(stmts, cxt = None, keep = False):
def exec(stmts, cxt = None, keep = False, parser = None):
if 'stmts' not in stmts:
return
cxt = initialize(cxt, keep)
cxt.parser = parser
stmts_stmts = stmts['stmts']
if type(stmts_stmts) is list:
for s in stmts_stmts:
+72 -5
View File
@@ -1081,7 +1081,62 @@ class create_table(ast_node):
self.sql += ')'
if self.context.use_columnstore:
self.sql += ' engine=ColumnStore'
class create_trigger(ast_node):
name = 'create_trigger'
first_order = name
class Type (Enum):
Interval = auto()
Callback = auto()
def produce(self, node):
from engine.utils import send_to_server, get_storedproc
node = node['create_trigger']
self.trigger_name = node['name']
self.action_name = node['action']
self.action = get_storedproc(self.action_name)
if self.trigger_name in self.context.triggers:
raise ValueError(f'trigger {self.trigger_name} exists')
elif self.action:
raise ValueError(f'Stored Procedure {self.action_name} do not exist')
if 'interval' in node: # executed periodically from server
self.type = self.Type.Interval
self.interval = node['interval']
send_to_server(f'TI{self.trigger_name}{self.action_name}{self.interval}')
else: # executed from sql backend
self.type = self.Type.Callback
self.query_name = node['query']
self.table_name = node['table']
self.procedure = get_storedproc(self.query_name)
if self.procedure and self.table_name in self.context.tables_byname:
self.table = self.context.tables_byname[self.table_name]
self.table.triggers.add(self)
else:
return
self.context.triggers[self.trigger_name] = self
# manually execute trigger
def register(self):
if self.type != self.Type.Callback:
self.context.triggers.pop(self.trigger_name)
raise ValueError(f'Trigger {self.trigger_name} is not a callback based trigger')
self.context.triggers_active.add(self)
def execute(self):
from engine.utils import send_to_server
send_to_server(f'TC{self.query_name}{self.action_name}')
def remove(self):
from engine.utils import send_to_server
send_to_server(f'TR{self.trigger_name}')
class drop_trigger(ast_node):
name = 'create_trigger'
first_order = name
def produce(self, node):
...
class drop(ast_node):
name = 'drop'
first_order = name
@@ -1111,9 +1166,11 @@ class insert(ast_node):
complex_query_kw = ['from', 'where', 'groupby', 'having', 'orderby', 'limit']
if any([kw in values for kw in complex_query_kw]):
values['into'] = node['insert']
proj_cls = (select_distinct
if 'select_distinct' in values
else projection)
proj_cls = (
select_distinct
if 'select_distinct' in values
else projection
)
proj_cls(None, values, self.context)
self.produce = lambda*_:None
self.spawn = lambda*_:None
@@ -1147,6 +1204,11 @@ class insert(ast_node):
keys = f'({", ".join(keys)})' if keys else ''
tbl = node['insert']
if tbl not in self.context.tables_byname:
print('Warning: {tbl} not registered in aquery compiler.')
tbl_obj = self.context.tables_byname[tbl]
for t in tbl_obj.triggers:
t.register()
self.sql = f'INSERT INTO {tbl}{keys} VALUES'
# if len(values) != table.n_cols:
# raise ValueError("Column Mismatch")
@@ -1161,7 +1223,7 @@ class insert(ast_node):
list_values.append(f"({', '.join(inner_list_values)})")
self.sql += ', '.join(list_values)
class delete_from(ast_node):
name = 'delete'
@@ -1624,6 +1686,11 @@ class passthru_sql(ast_node):
seprator = re.compile(r'''((?:[^;"']|"[^"]*"|'[^']*')+)''')
def __init__(self, _, node, context:Context):
sqls = passthru_sql.seprator.split(node['sql'])
try:
if callable(context.parser):
parsed = context.parser(node['sql'])
except BaseException:
parsed = None
for sql in sqls:
sq = sql.strip(' \t\n\r;')
if sq:
+18 -4
View File
@@ -64,12 +64,14 @@ class ColRef:
class TableInfo:
def __init__(self, table_name, cols, cxt:'Context'):
from reconstruct.ast import create_trigger
# statics
self.table_name : str = table_name
self.contextname_cpp : str = ''
self.alias : Set[str] = set([table_name])
self.columns_byname : CaseInsensitiveDict[str, ColRef] = CaseInsensitiveDict() # column_name, type
self.columns : List[ColRef] = []
self.triggers : Set[create_trigger] = set()
self.cxt = cxt
# keep track of temp vars
self.rec = None
@@ -83,7 +85,7 @@ class TableInfo:
def add_cols(self, cols, new = True):
for c in enlist(cols):
self.add_col(c, new)
def add_col(self, c, new = True):
_ty = c['type']
_ty_args = None
@@ -156,9 +158,11 @@ class Context:
self.module_init_loc = 0
self.special_gb = False
self.has_dll = False
self.triggers_active.clear()
def __init__(self):
self.tables_byname = dict()
from .ast import create_trigger
self.tables_byname : Dict[str, TableInfo] = dict()
self.col_byname = dict()
self.tables : Set[TableInfo] = set()
self.cols = []
@@ -174,6 +178,9 @@ class Context:
self.have_hge = False
self.Error = lambda *args: print(*args)
self.Info = lambda *_: None
self.triggers : Dict[str, create_trigger] = dict()
self.triggers_active = set()
self.stored_proceudres = dict()
# self.new() called everytime new query batch is started
def get_scan_var(self):
@@ -256,7 +263,14 @@ class Context:
limit = limit.to_bytes(4, 'little').decode('latin-1')
self.queries.append(
'O' + limit + sep + end)
def remove_trigger(self, name : str):
from reconstruct.ast import create_trigger
val = self.triggers.pop(name, None)
if val.type == create_trigger.Type.Callback:
val.table.triggers.remove(val)
val.remove()
def abandon_postproc(self):
self.ccode = ''
self.finalize_query()