Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mindsdb_sql_parser/ast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
from .drop import *
from .create import *
from .variable import *
from .table import Table

from .mindsdb.latest import Latest
73 changes: 73 additions & 0 deletions mindsdb_sql_parser/ast/table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from typing import Optional, List, Any

from mindsdb_sql_parser.ast.base import ASTNode


class Table(ASTNode):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

table a is the same as select * from a, why to not parse it as CreateTable?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you mean Select.
Indeed, select a and select * from a are equivalent. I prefer to have separate Table class because Select and Table are separate statements. However, it would be much easier to render this statement to different dialects if it will be Select, so i changed it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I meant Select

"""AST node representing a TABLE statement with optional ORDER BY, LIMIT, and OFFSET clauses.
https://dev.mysql.com/doc/refman/8.4/en/table.html

Args:
name: The name of the table (Identifier).
order_by: Optional list of ORDER BY terms.
limit: Optional LIMIT value (Constant).
offset: Optional OFFSET value (Constant).
*args: Additional positional arguments for ASTNode.
**kwargs: Additional keyword arguments for ASTNode.
"""
def __init__(
self,
name: Any,
order_by: Optional[List[Any]] = None,
limit: Optional[Any] = None,
offset: Optional[Any] = None,
*args,
**kwargs
):
super().__init__(*args, **kwargs)
self.name = name
self.order_by = order_by
self.limit = limit
self.offset = offset

def to_tree(self, *args, level: int = 0, **kwargs) -> str:
"""Returns a string representation of the AST tree for this node.

Args:
level: Indentation level for pretty printing.
*args: Additional positional arguments.
**kwargs: Additional keyword arguments.

Returns:
str: The tree representation of the node.
"""
ind = ' ' * level
out = f'{ind}Table(\n'
out += f'{ind} name={self.name},\n'
if self.order_by:
out += f'{ind} order_by={self.order_by},\n'
if self.limit:
out += f'{ind} limit={self.limit},\n'
if self.offset:
out += f'{ind} offset={self.offset},\n'
out += f'{ind})'
return out

def to_string(self, *args, **kwargs) -> str:
"""Returns a SQL string representation of the TABLE statement.

Args:
*args: Additional positional arguments.
**kwargs: Additional keyword arguments.

Returns:
str: The SQL string representation.
"""
s = f'TABLE {self.name}'
if self.order_by:
s += ' ORDER BY ' + ', '.join([o.to_string() for o in self.order_by])
if self.limit:
s += f' LIMIT {self.limit.to_string()}'
if self.offset:
s += f' OFFSET {self.offset.to_string()}'
return s
37 changes: 37 additions & 0 deletions mindsdb_sql_parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class MindsDBParser(Parser):
'update_agent',
'create_index',
'drop_index',
'table',
)
def query(self, p):
return p[0]
Expand Down Expand Up @@ -2083,3 +2084,39 @@ def error(self, p, expected_tokens=None):
)
# don't raise exception
return

# region TABLE https://dev.mysql.com/doc/refman/8.4/en/table.html
@_('TABLE identifier table_opt_order_by table_opt_limit table_opt_offset')
def table(self, p):
from mindsdb_sql_parser.ast.table import Table
return Table(
name=p.identifier,
order_by=p.table_opt_order_by,
limit=p.table_opt_limit,
offset=p.table_opt_offset
)

@_('empty')
def table_opt_order_by(self, p):
return None

@_('ORDER_BY ordering_terms')
def table_opt_order_by(self, p):
return p.ordering_terms

@_('empty')
def table_opt_limit(self, p):
return None

@_('LIMIT constant')
def table_opt_limit(self, p):
return p.constant

@_('empty')
def table_opt_offset(self, p):
return None

@_('OFFSET constant')
def table_opt_offset(self, p):
return p.constant
# endregion
8 changes: 8 additions & 0 deletions tests/test_base_sql/test_misc_sql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ def test_autocommit(self):
assert ast.to_tree() == expected_ast.to_tree()
assert str(ast) == str(expected_ast)

def test_table_with_order_by_limit_offset(self):
sql = "TABLE my_table ORDER BY my_column LIMIT 10 OFFSET 5"
ast = parse_sql(sql)
assert isinstance(ast, Table)
assert ast.name.to_string() == 'my_table'
assert ast.order_by[0].field.to_string() == 'my_column'
assert ast.limit.value == 10
assert ast.offset.value == 5


class TestMiscQueriesNoSqlite:
Expand Down