Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/sqlparse/engine/statement_splitter.py: 10%
50 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1#
2# Copyright (C) 2009-2020 the sqlparse authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of python-sqlparse and is released under
6# the BSD License: https://opensource.org/licenses/BSD-3-Clause
8from sqlparse import sql, tokens as T
11class StatementSplitter:
12 """Filter that split stream at individual statements"""
14 def __init__(self):
15 self._reset()
17 def _reset(self):
18 """Set the filter attributes to its default values"""
19 self._in_declare = False
20 self._is_create = False
21 self._begin_depth = 0
23 self.consume_ws = False
24 self.tokens = []
25 self.level = 0
27 def _change_splitlevel(self, ttype, value):
28 """Get the new split level (increase, decrease or remain equal)"""
30 # parenthesis increase/decrease a level
31 if ttype is T.Punctuation and value == '(':
32 return 1
33 elif ttype is T.Punctuation and value == ')':
34 return -1
35 elif ttype not in T.Keyword: # if normal token return
36 return 0
38 # Everything after here is ttype = T.Keyword
39 # Also to note, once entered an If statement you are done and basically
40 # returning
41 unified = value.upper()
43 # three keywords begin with CREATE, but only one of them is DDL
44 # DDL Create though can contain more words such as "or replace"
45 if ttype is T.Keyword.DDL and unified.startswith('CREATE'):
46 self._is_create = True
47 return 0
49 # can have nested declare inside of being...
50 if unified == 'DECLARE' and self._is_create and self._begin_depth == 0:
51 self._in_declare = True
52 return 1
54 if unified == 'BEGIN':
55 self._begin_depth += 1
56 if self._is_create:
57 # FIXME(andi): This makes no sense.
58 return 1
59 return 0
61 # Should this respect a preceding BEGIN?
62 # In CASE ... WHEN ... END this results in a split level -1.
63 # Would having multiple CASE WHEN END and a Assignment Operator
64 # cause the statement to cut off prematurely?
65 if unified == 'END':
66 self._begin_depth = max(0, self._begin_depth - 1)
67 return -1
69 if (unified in ('IF', 'FOR', 'WHILE', 'CASE')
70 and self._is_create and self._begin_depth > 0):
71 return 1
73 if unified in ('END IF', 'END FOR', 'END WHILE'):
74 return -1
76 # Default
77 return 0
79 def process(self, stream):
80 """Process the stream"""
81 EOS_TTYPE = T.Whitespace, T.Comment.Single
83 # Run over all stream tokens
84 for ttype, value in stream:
85 # Yield token if we finished a statement and there's no whitespaces
86 # It will count newline token as a non whitespace. In this context
87 # whitespace ignores newlines.
88 # why don't multi line comments also count?
89 if self.consume_ws and ttype not in EOS_TTYPE:
90 yield sql.Statement(self.tokens)
92 # Reset filter and prepare to process next statement
93 self._reset()
95 # Change current split level (increase, decrease or remain equal)
96 self.level += self._change_splitlevel(ttype, value)
98 # Append the token to the current statement
99 self.tokens.append(sql.Token(ttype, value))
101 # Check if we get the end of a statement
102 if self.level <= 0 and ttype is T.Punctuation and value == ';':
103 self.consume_ws = True
105 # Yield pending statement (if any)
106 if self.tokens and not all(t.is_whitespace for t in self.tokens):
107 yield sql.Statement(self.tokens)