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
9from sqlparse import tokens as T
10
11
12class OutputFilter:
13 varname_prefix = ''
14
15 def __init__(self, varname='sql'):
16 self.varname = self.varname_prefix + varname
17 self.count = 0
18
19 def _process(self, stream, varname, has_nl):
20 raise NotImplementedError
21
22 def process(self, stmt):
23 self.count += 1
24 if self.count > 1:
25 varname = f'{self.varname}{self.count}'
26 else:
27 varname = self.varname
28
29 has_nl = len(str(stmt).strip().splitlines()) > 1
30 stmt.tokens = self._process(stmt.tokens, varname, has_nl)
31 return stmt
32
33
34class OutputPythonFilter(OutputFilter):
35 def _process(self, stream, varname, has_nl):
36 # SQL query assignation to varname
37 if self.count > 1:
38 yield sql.Token(T.Whitespace, '\n')
39 yield sql.Token(T.Name, varname)
40 yield sql.Token(T.Whitespace, ' ')
41 yield sql.Token(T.Operator, '=')
42 yield sql.Token(T.Whitespace, ' ')
43 if has_nl:
44 yield sql.Token(T.Operator, '(')
45 yield sql.Token(T.Text, "'")
46
47 # Print the tokens on the quote
48 for token in stream:
49 # Token is a new line separator
50 if token.is_whitespace and '\n' in token.value:
51 # Close quote and add a new line
52 yield sql.Token(T.Text, " '")
53 yield sql.Token(T.Whitespace, '\n')
54
55 # Quote header on secondary lines
56 yield sql.Token(T.Whitespace, ' ' * (len(varname) + 4))
57 yield sql.Token(T.Text, "'")
58
59 # Indentation
60 after_lb = token.value.split('\n', 1)[1]
61 if after_lb:
62 yield sql.Token(T.Whitespace, after_lb)
63 continue
64
65 # Escape backslashes before quotes so a backslash preceding a
66 # quote cannot break out of the generated string literal
67 # (GHSA-3496-9g83-7v6x).
68 else:
69 token.value = token.value.replace('\\', '\\\\').replace("'", "\\'")
70
71 # Put the token
72 yield sql.Token(T.Text, token.value)
73
74 # Close quote
75 yield sql.Token(T.Text, "'")
76 if has_nl:
77 yield sql.Token(T.Operator, ')')
78
79
80class OutputPHPFilter(OutputFilter):
81 varname_prefix = '$'
82
83 def _process(self, stream, varname, has_nl):
84 # SQL query assignation to varname (quote header)
85 if self.count > 1:
86 yield sql.Token(T.Whitespace, '\n')
87 yield sql.Token(T.Name, varname)
88 yield sql.Token(T.Whitespace, ' ')
89 if has_nl:
90 yield sql.Token(T.Whitespace, ' ')
91 yield sql.Token(T.Operator, '=')
92 yield sql.Token(T.Whitespace, ' ')
93 yield sql.Token(T.Text, '"')
94
95 # Print the tokens on the quote
96 for token in stream:
97 # Token is a new line separator
98 if token.is_whitespace and '\n' in token.value:
99 # Close quote and add a new line
100 yield sql.Token(T.Text, ' ";')
101 yield sql.Token(T.Whitespace, '\n')
102
103 # Quote header on secondary lines
104 yield sql.Token(T.Name, varname)
105 yield sql.Token(T.Whitespace, ' ')
106 yield sql.Token(T.Operator, '.=')
107 yield sql.Token(T.Whitespace, ' ')
108 yield sql.Token(T.Text, '"')
109
110 # Indentation
111 after_lb = token.value.split('\n', 1)[1]
112 if after_lb:
113 yield sql.Token(T.Whitespace, after_lb)
114 continue
115
116 # Escape backslashes before quotes so a backslash preceding a
117 # quote cannot break out of the generated string literal
118 # (GHSA-3496-9g83-7v6x).
119 else:
120 token.value = token.value.replace('\\', '\\\\').replace('"', '\\"')
121
122 # Put the token
123 yield sql.Token(T.Text, token.value)
124
125 # Close quote
126 yield sql.Token(T.Text, '"')
127 yield sql.Token(T.Punctuation, ';')