Skip to content

Commit 4dc9466

Browse files
committed
update version of sqlparse
1 parent e19ef39 commit 4dc9466

File tree

14 files changed

+3307
-0
lines changed

14 files changed

+3307
-0
lines changed

sqlparse/__init__.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com
2+
#
3+
# This module is part of python-sqlparse and is released under
4+
# the BSD License: http://www.opensource.org/licenses/bsd-license.php.
5+
6+
"""Parse SQL statements."""
7+
8+
9+
__version__ = '0.1.11-dev'
10+
11+
12+
# Setup namespace
13+
from sqlparse import engine
14+
from sqlparse import filters
15+
from sqlparse import formatter
16+
17+
# Deprecated in 0.1.5. Will be removed in 0.2.0
18+
from sqlparse.exceptions import SQLParseError
19+
20+
21+
def parse(sql, encoding=None):
22+
"""Parse sql and return a list of statements.
23+
24+
:param sql: A string containting one or more SQL statements.
25+
:param encoding: The encoding of the statement (optional).
26+
:returns: A tuple of :class:`~sqlparse.sql.Statement` instances.
27+
"""
28+
return tuple(parsestream(sql, encoding))
29+
30+
31+
def parsestream(stream, encoding=None):
32+
"""Parses sql statements from file-like object.
33+
34+
:param stream: A file-like object.
35+
:param encoding: The encoding of the stream contents (optional).
36+
:returns: A generator of :class:`~sqlparse.sql.Statement` instances.
37+
"""
38+
stack = engine.FilterStack()
39+
stack.full_analyze()
40+
return stack.run(stream, encoding)
41+
42+
43+
def format(sql, **options):
44+
"""Format *sql* according to *options*.
45+
46+
Available options are documented in :ref:`formatting`.
47+
48+
In addition to the formatting options this function accepts the
49+
keyword "encoding" which determines the encoding of the statement.
50+
51+
:returns: The formatted SQL statement as string.
52+
"""
53+
encoding = options.pop('encoding', None)
54+
stack = engine.FilterStack()
55+
options = formatter.validate_options(options)
56+
stack = formatter.build_filter_stack(stack, options)
57+
stack.postprocess.append(filters.SerializerUnicode())
58+
return ''.join(stack.run(sql, encoding))
59+
60+
61+
def split(sql, encoding=None):
62+
"""Split *sql* into single statements.
63+
64+
:param sql: A string containting one or more SQL statements.
65+
:param encoding: The encoding of the statement (optional).
66+
:returns: A list of strings.
67+
"""
68+
stack = engine.FilterStack()
69+
stack.split_statements = True
70+
return [unicode(stmt).strip() for stmt in stack.run(sql, encoding)]
71+
72+
73+
from sqlparse.engine.filter import StatementFilter
74+
75+
76+
def split2(stream):
77+
splitter = StatementFilter()
78+
return list(splitter.process(None, stream))

sqlparse/engine/__init__.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com
2+
#
3+
# This module is part of python-sqlparse and is released under
4+
# the BSD License: http://www.opensource.org/licenses/bsd-license.php.
5+
6+
"""filter"""
7+
8+
from sqlparse import lexer
9+
from sqlparse.engine import grouping
10+
from sqlparse.engine.filter import StatementFilter
11+
12+
# XXX remove this when cleanup is complete
13+
Filter = object
14+
15+
16+
class FilterStack(object):
17+
18+
def __init__(self):
19+
self.preprocess = []
20+
self.stmtprocess = []
21+
self.postprocess = []
22+
self.split_statements = False
23+
self._grouping = False
24+
25+
def _flatten(self, stream):
26+
for token in stream:
27+
if token.is_group():
28+
for t in self._flatten(token.tokens):
29+
yield t
30+
else:
31+
yield token
32+
33+
def enable_grouping(self):
34+
self._grouping = True
35+
36+
def full_analyze(self):
37+
self.enable_grouping()
38+
39+
def run(self, sql, encoding=None):
40+
stream = lexer.tokenize(sql, encoding)
41+
# Process token stream
42+
if self.preprocess:
43+
for filter_ in self.preprocess:
44+
stream = filter_.process(self, stream)
45+
46+
if (self.stmtprocess or self.postprocess or self.split_statements
47+
or self._grouping):
48+
splitter = StatementFilter()
49+
stream = splitter.process(self, stream)
50+
51+
if self._grouping:
52+
53+
def _group(stream):
54+
for stmt in stream:
55+
grouping.group(stmt)
56+
yield stmt
57+
stream = _group(stream)
58+
59+
if self.stmtprocess:
60+
61+
def _run1(stream):
62+
ret = []
63+
for stmt in stream:
64+
for filter_ in self.stmtprocess:
65+
filter_.process(self, stmt)
66+
ret.append(stmt)
67+
return ret
68+
stream = _run1(stream)
69+
70+
if self.postprocess:
71+
72+
def _run2(stream):
73+
for stmt in stream:
74+
stmt.tokens = list(self._flatten(stmt.tokens))
75+
for filter_ in self.postprocess:
76+
stmt = filter_.process(self, stmt)
77+
yield stmt
78+
stream = _run2(stream)
79+
80+
return stream

sqlparse/engine/filter.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from sqlparse.sql import Statement, Token
4+
from sqlparse import tokens as T
5+
6+
7+
class StatementFilter:
8+
"Filter that split stream at individual statements"
9+
10+
def __init__(self):
11+
self._in_declare = False
12+
self._in_dbldollar = False
13+
self._is_create = False
14+
self._begin_depth = 0
15+
16+
def _reset(self):
17+
"Set the filter attributes to its default values"
18+
self._in_declare = False
19+
self._in_dbldollar = False
20+
self._is_create = False
21+
self._begin_depth = 0
22+
23+
def _change_splitlevel(self, ttype, value):
24+
"Get the new split level (increase, decrease or remain equal)"
25+
# PostgreSQL
26+
if (ttype == T.Name.Builtin
27+
and value.startswith('$') and value.endswith('$')):
28+
if self._in_dbldollar:
29+
self._in_dbldollar = False
30+
return -1
31+
else:
32+
self._in_dbldollar = True
33+
return 1
34+
elif self._in_dbldollar:
35+
return 0
36+
37+
# ANSI
38+
if ttype not in T.Keyword:
39+
return 0
40+
41+
unified = value.upper()
42+
43+
if unified == 'DECLARE' and self._is_create:
44+
self._in_declare = True
45+
return 1
46+
47+
if unified == 'BEGIN':
48+
self._begin_depth += 1
49+
if self._in_declare or self._is_create:
50+
# FIXME(andi): This makes no sense.
51+
return 1
52+
return 0
53+
54+
if unified == 'END':
55+
# Should this respect a preceeding BEGIN?
56+
# In CASE ... WHEN ... END this results in a split level -1.
57+
self._begin_depth = max(0, self._begin_depth - 1)
58+
return -1
59+
60+
if ttype is T.Keyword.DDL and unified.startswith('CREATE'):
61+
self._is_create = True
62+
return 0
63+
64+
if (unified in ('IF', 'FOR')
65+
and self._is_create and self._begin_depth > 0):
66+
return 1
67+
68+
# Default
69+
return 0
70+
71+
def process(self, stack, stream):
72+
"Process the stream"
73+
consume_ws = False
74+
splitlevel = 0
75+
stmt = None
76+
stmt_tokens = []
77+
78+
# Run over all stream tokens
79+
for ttype, value in stream:
80+
# Yield token if we finished a statement and there's no whitespaces
81+
if consume_ws and ttype not in (T.Whitespace, T.Comment.Single):
82+
stmt.tokens = stmt_tokens
83+
yield stmt
84+
85+
# Reset filter and prepare to process next statement
86+
self._reset()
87+
consume_ws = False
88+
splitlevel = 0
89+
stmt = None
90+
91+
# Create a new statement if we are not currently in one of them
92+
if stmt is None:
93+
stmt = Statement()
94+
stmt_tokens = []
95+
96+
# Change current split level (increase, decrease or remain equal)
97+
splitlevel += self._change_splitlevel(ttype, value)
98+
99+
# Append the token to the current statement
100+
stmt_tokens.append(Token(ttype, value))
101+
102+
# Check if we get the end of a statement
103+
if splitlevel <= 0 and ttype is T.Punctuation and value == ';':
104+
consume_ws = True
105+
106+
# Yield pending statement (if any)
107+
if stmt is not None:
108+
stmt.tokens = stmt_tokens
109+
yield stmt

0 commit comments

Comments
 (0)