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

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 

7 

8from sqlparse import sql, tokens as T 

9 

10 

11class StatementSplitter: 

12 """Filter that split stream at individual statements""" 

13 

14 def __init__(self): 

15 self._reset() 

16 

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 

22 

23 self.consume_ws = False 

24 self.tokens = [] 

25 self.level = 0 

26 

27 def _change_splitlevel(self, ttype, value): 

28 """Get the new split level (increase, decrease or remain equal)""" 

29 

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 

37 

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() 

42 

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 

48 

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 

53 

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 

60 

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 

68 

69 if (unified in ('IF', 'FOR', 'WHILE', 'CASE') 

70 and self._is_create and self._begin_depth > 0): 

71 return 1 

72 

73 if unified in ('END IF', 'END FOR', 'END WHILE'): 

74 return -1 

75 

76 # Default 

77 return 0 

78 

79 def process(self, stream): 

80 """Process the stream""" 

81 EOS_TTYPE = T.Whitespace, T.Comment.Single 

82 

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) 

91 

92 # Reset filter and prepare to process next statement 

93 self._reset() 

94 

95 # Change current split level (increase, decrease or remain equal) 

96 self.level += self._change_splitlevel(ttype, value) 

97 

98 # Append the token to the current statement 

99 self.tokens.append(sql.Token(ttype, value)) 

100 

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 

104 

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)