Skip to content

Commit

Permalink
refactored SET command
Browse files Browse the repository at this point in the history
  • Loading branch information
ea-rus committed Jan 11, 2024
1 parent 921b610 commit 6f8d1b0
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 220 deletions.
166 changes: 96 additions & 70 deletions mindsdb_sql/parser/ast/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,94 +6,120 @@
class Set(ASTNode):
def __init__(self,
category=None,
arg=None,
name=None,
value=None,
scope=None,
params=None,
set_list=None,
*args, **kwargs):
super().__init__(*args, **kwargs)
self.category = category
self.arg = arg
self.params = params or {}

def to_tree(self, *args, level=0, **kwargs):
ind = indent(level)
category_str = f'category={self.category}, '
arg_str = f'arg={self.arg.to_tree()},' if self.arg else ''
if self.params:
param_str = 'param=' + ', '.join([f'{k}:{v}' for k,v in self.params.items()])
else:
param_str = ''
out_str = f'{ind}Set(' \
f'{category_str}' \
f'{arg_str} ' \
f'{param_str}' \
f')'
return out_str
# names / charset / transactions
self.category = category

def get_string(self, *args, **kwargs):
if self.params:
param_str = ' ' + ' '.join([f'{k} {v}' for k, v in self.params.items()])
else:
param_str = ''

if isinstance(self.arg, Tuple):
arg_str = ', '.join([str(i) for i in self.arg.items])
else:
arg_str = f' {str(self.arg)}' if self.arg else ''
return f'SET {self.category if self.category else ""}{arg_str}{param_str}'
# name for variable assigment. category is None it this case
self.name = name

self.value = value
self.params = params or {}

class SetTransaction(ASTNode):
def __init__(self,
isolation_level=None,
access_mode=None,
scope=None,
*args, **kwargs):
super().__init__(*args, **kwargs)
# global / session / ...
self.scope = scope

if isolation_level is not None:
isolation_level = isolation_level.upper()
if access_mode is not None:
access_mode = access_mode.upper()
if scope is not None:
scope = scope.upper()
# contents all set subcommands
self.set_list = set_list

self.scope = scope
self.access_mode = access_mode
self.isolation_level = isolation_level

def to_tree(self, *args, level=0, **kwargs):
ind = indent(level)
if self.scope is None:
scope_str = ''
if self.set_list is not None:
items = [set.render() for set in self.set_list]
else:
scope_str = f'scope={self.scope}, '
items = self.render()

properties = []
if self.isolation_level is not None:
properties.append('ISOLATION LEVEL ' + self.isolation_level)
if self.access_mode is not None:
properties.append(self.access_mode)
prop_str = ', '.join(properties)
ind = indent(level)

out_str = f'{ind}SetTransaction(' \
f'{scope_str}' \
f'properties=[{prop_str}]' \
f'\n{ind})'
return out_str
return f'{ind}Set(items={items})'

def get_string(self, *args, **kwargs):
properties = []
if self.isolation_level is not None:
properties.append('ISOLATION LEVEL ' + self.isolation_level)
if self.access_mode is not None:
properties.append(self.access_mode)
return 'SET ' + self.render()

prop_str = ', '.join(properties)
def render(self):
if self.set_list is not None:
render_list = [set.render() for set in self.set_list]
return ', '.join(render_list)

if self.scope is None:
scope_str = ''
if self.params:
param_str = ' ' + ' '.join([f'{k} {v}' for k, v in self.params.items()])
else:
scope_str = self.scope + ' '
param_str = ''

return f'SET {scope_str}TRANSACTION {prop_str}'
if self.name is not None:
# category should be empty
content = f'{self.name.to_string()}={self.value.to_string()}'
elif self.value is not None:
content = f'{self.category} {self.value.to_string()}'
else:
content = f'{self.category}'

scope = ''
if self.scope is not None:
scope = f'{self.scope} '

return f'{scope}{content}{param_str}'


# class SetTransaction(ASTNode):
# def __init__(self,
# isolation_level=None,
# access_mode=None,
# scope=None,
# *args, **kwargs):
# super().__init__(*args, **kwargs)
#
# if isolation_level is not None:
# isolation_level = isolation_level.upper()
# if access_mode is not None:
# access_mode = access_mode.upper()
# if scope is not None:
# scope = scope.upper()
#
# self.scope = scope
# self.access_mode = access_mode
# self.isolation_level = isolation_level
#
# def to_tree(self, *args, level=0, **kwargs):
# ind = indent(level)
# if self.scope is None:
# scope_str = ''
# else:
# scope_str = f'scope={self.scope}, '
#
# properties = []
# if self.isolation_level is not None:
# properties.append('ISOLATION LEVEL ' + self.isolation_level)
# if self.access_mode is not None:
# properties.append(self.access_mode)
# prop_str = ', '.join(properties)
#
# out_str = f'{ind}SetTransaction(' \
# f'{scope_str}' \
# f'properties=[{prop_str}]' \
# f'\n{ind})'
# return out_str
#
# def get_string(self, *args, **kwargs):
# properties = []
# if self.isolation_level is not None:
# properties.append('ISOLATION LEVEL ' + self.isolation_level)
# if self.access_mode is not None:
# properties.append(self.access_mode)
#
# prop_str = ', '.join(properties)
#
# if self.scope is None:
# scope_str = ''
# else:
# scope_str = self.scope + ' '
#
# return f'SET {scope_str}TRANSACTION {prop_str}'

3 changes: 1 addition & 2 deletions mindsdb_sql/parser/dialects/mindsdb/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class MindsDBLexer(Lexer):
VARIABLES, SESSION, STATUS,
GLOBAL, PROCEDURE, FUNCTION, INDEX, WARNINGS,
ENGINES, CHARSET, COLLATION, PLUGINS, CHARACTER,
PERSIST, PERSIST_ONLY, DEFAULT,
PERSIST, PERSIST_ONLY,
IF_EXISTS, IF_NOT_EXISTS, COLUMNS, FIELDS, COLLATE, SEARCH_PATH,
VARIABLE, SYSTEM_VARIABLE,

Expand Down Expand Up @@ -172,7 +172,6 @@ class MindsDBLexer(Lexer):
PLUGINS = r'\bPLUGINS\b'
PERSIST = r'\bPERSIST\b'
PERSIST_ONLY = r'\bPERSIST_ONLY\b'
DEFAULT = r'\bDEFAULT\b'
IF_EXISTS = r'\bIF[\s]+EXISTS\b'
IF_NOT_EXISTS = r'\bIF[\s]+NOT[\s]+EXISTS\b'
COLUMNS = r'\bCOLUMNS\b'
Expand Down
111 changes: 63 additions & 48 deletions mindsdb_sql/parser/dialects/mindsdb/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,42 +334,57 @@ def commit_transaction(self, p):
def rollback_transaction(self, p):
return RollbackTransaction()

# Set

@_('SET id identifier',
'SET id identifier COLLATE constant',
'SET id identifier COLLATE DEFAULT',
'SET id constant',
'SET id constant COLLATE constant',
'SET id constant COLLATE DEFAULT')
# --- Set ---
@_('SET set_item_list')
def set(self, p):
if not p.id.lower() == 'names':
raise ParsingException(f'Expected "SET names", got "SET {p.id}"')
if isinstance(p[2], Constant):
arg = Identifier(p[2].value)
set_list = p[1]
if len(set_list) == 1:
return set_list[0]
return Set(set_list=set_list)

@_('set_item',
'set_item_list COMMA set_item')
def set_item_list(self, p):
arr = getattr(p, 'set_item_list', [])
arr.append(p.set_item)
return arr

# set names
@_('id id',
'id constant',
'id id COLLATE constant',
'id id COLLATE id',
'id constant COLLATE constant',
'id constant COLLATE id')
def set_item(self, p):
category = p[0]
if category.lower() != 'names':
raise ParsingException(f'Expected "SET names", got "SET {category}"')
if isinstance(p[1], Constant):
value = p[1]
else:
# is identifier
arg = p[2]
# is id
value = Constant(p[1], with_quotes=False)

params = {}
if hasattr(p, 'COLLATE'):
if isinstance(p[4], Constant):
val = p[4]
if isinstance(p[3], Constant):
val = p[3]
else:
val = Constant(p[4], with_quotes=False)
val = Constant(p[3], with_quotes=False)
params['COLLATE'] = val

return Set(category=p.id.lower(), arg=arg, params=params)
return Set(category=category, value=value, params=params)

# set charset
@_('SET charset constant',
'SET charset DEFAULT')
def set(self, p):
@_('charset constant',
'charset id')
def set_item(self, p):
if hasattr(p, 'id'):
arg = Constant(p.id, with_quotes=False)
else:
arg = p.constant
return Set(category='CHARSET', arg=arg)
return Set(category='CHARSET', value=arg)

@_('CHARACTER SET',
'CHARSET',
Expand All @@ -378,29 +393,30 @@ def charset(self, p):
return p[0]

# set transaction
@_('SET transact_scope TRANSACTION transact_property_list',
'SET TRANSACTION transact_property_list')
def set(self, p):
@_('set_scope TRANSACTION transact_property_list',
'TRANSACTION transact_property_list')
def set_item(self, p):
isolation_level = None
access_mode = None
transact_scope = getattr(p, 'transact_scope', None)
transact_scope = getattr(p, 'set_scope', None)
for prop in p.transact_property_list:
if prop['type'] == 'iso_level':
isolation_level = prop['value']
else:
access_mode = prop['value']

return SetTransaction(
isolation_level=isolation_level,
access_mode=access_mode,
params = {}
if isolation_level is not None:
params['isolation_level'] = isolation_level
if access_mode is not None:
params['access_mode'] = access_mode

return Set(
category='TRANSACTION',
scope=transact_scope,
params=params
)

@_('GLOBAL',
'SESSION')
def transact_scope(self, p):
return p[0]

@_('transact_property_list COMMA transact_property')
def transact_property_list(self, p):
return p.transact_property_list + [p.transact_property]
Expand Down Expand Up @@ -429,30 +445,29 @@ def transact_level(self, p):
def transact_access_mode(self, p):
return ' '.join([x for x in p])

@_('SET expr_list',
'SET set_modifier expr_list')
def set(self, p):
if len(p.expr_list) == 1:
arg = p.expr_list[0]
else:
arg = Tuple(items=p.expr_list)
@_('identifier EQUALS expr',
'set_scope identifier EQUALS expr',
'variable EQUALS expr',
'set_scope variable EQUALS expr')
def set_item(self, p):

if hasattr(p, 'set_modifier'):
category = p.set_modifier
else:
category = None
scope = None
name = p[0]
if hasattr(p, 'set_scope'):
scope = p.set_scope
name=p[1]

return Set(category=category, arg=arg)
return Set(name=name, value=p.expr, scope=scope)

@_('GLOBAL',
'PERSIST',
'PERSIST_ONLY',
'SESSION',
)
def set_modifier(self, p):
def set_scope(self, p):
return p[0]

# Show
# --- Show ---
@_('show WHERE expr')
def show(self, p):
command = p.show
Expand Down
Loading

0 comments on commit 6f8d1b0

Please sign in to comment.