1 | /* src/interfaces/ecpg/preproc/output.c */ |
2 | |
3 | #include "postgres_fe.h" |
4 | |
5 | #include "preproc_extern.h" |
6 | |
7 | static void output_escaped_str(char *cmd, bool quoted); |
8 | |
9 | void |
10 | output_line_number(void) |
11 | { |
12 | char *line = hashline_number(); |
13 | |
14 | fprintf(base_yyout, "%s" , line); |
15 | free(line); |
16 | } |
17 | |
18 | void |
19 | output_simple_statement(char *stmt, int whenever_mode) |
20 | { |
21 | output_escaped_str(stmt, false); |
22 | if (whenever_mode) |
23 | whenever_action(whenever_mode); |
24 | output_line_number(); |
25 | free(stmt); |
26 | } |
27 | |
28 | |
29 | /* |
30 | * store the whenever action here |
31 | */ |
32 | struct when when_error, |
33 | when_nf, |
34 | when_warn; |
35 | |
36 | static void |
37 | print_action(struct when *w) |
38 | { |
39 | switch (w->code) |
40 | { |
41 | case W_SQLPRINT: |
42 | fprintf(base_yyout, "sqlprint();" ); |
43 | break; |
44 | case W_GOTO: |
45 | fprintf(base_yyout, "goto %s;" , w->command); |
46 | break; |
47 | case W_DO: |
48 | fprintf(base_yyout, "%s;" , w->command); |
49 | break; |
50 | case W_STOP: |
51 | fprintf(base_yyout, "exit (1);" ); |
52 | break; |
53 | case W_BREAK: |
54 | fprintf(base_yyout, "break;" ); |
55 | break; |
56 | case W_CONTINUE: |
57 | fprintf(base_yyout, "continue;" ); |
58 | break; |
59 | default: |
60 | fprintf(base_yyout, "{/* %d not implemented yet */}" , w->code); |
61 | break; |
62 | } |
63 | } |
64 | |
65 | void |
66 | whenever_action(int mode) |
67 | { |
68 | if ((mode & 1) == 1 && when_nf.code != W_NOTHING) |
69 | { |
70 | output_line_number(); |
71 | fprintf(base_yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) " ); |
72 | print_action(&when_nf); |
73 | } |
74 | if (when_warn.code != W_NOTHING) |
75 | { |
76 | output_line_number(); |
77 | fprintf(base_yyout, "\nif (sqlca.sqlwarn[0] == 'W') " ); |
78 | print_action(&when_warn); |
79 | } |
80 | if (when_error.code != W_NOTHING) |
81 | { |
82 | output_line_number(); |
83 | fprintf(base_yyout, "\nif (sqlca.sqlcode < 0) " ); |
84 | print_action(&when_error); |
85 | } |
86 | |
87 | if ((mode & 2) == 2) |
88 | fputc('}', base_yyout); |
89 | |
90 | output_line_number(); |
91 | } |
92 | |
93 | char * |
94 | hashline_number(void) |
95 | { |
96 | /* do not print line numbers if we are in debug mode */ |
97 | if (input_filename |
98 | #ifdef YYDEBUG |
99 | && !base_yydebug |
100 | #endif |
101 | ) |
102 | { |
103 | /* "* 2" here is for escaping '\' and '"' below */ |
104 | char *line = mm_alloc(strlen("\n#line %d \"%s\"\n" ) + sizeof(int) * CHAR_BIT * 10 / 3 + strlen(input_filename) * 2); |
105 | char *src, |
106 | *dest; |
107 | |
108 | sprintf(line, "\n#line %d \"" , base_yylineno); |
109 | src = input_filename; |
110 | dest = line + strlen(line); |
111 | while (*src) |
112 | { |
113 | if (*src == '\\' || *src == '"') |
114 | *dest++ = '\\'; |
115 | *dest++ = *src++; |
116 | } |
117 | *dest = '\0'; |
118 | strcat(dest, "\"\n" ); |
119 | |
120 | return line; |
121 | } |
122 | |
123 | return EMPTY; |
124 | } |
125 | |
126 | static char *ecpg_statement_type_name[] = { |
127 | "ECPGst_normal" , |
128 | "ECPGst_execute" , |
129 | "ECPGst_exec_immediate" , |
130 | "ECPGst_prepnormal" , |
131 | "ECPGst_prepare" , |
132 | "ECPGst_exec_with_exprlist" |
133 | }; |
134 | |
135 | void |
136 | output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st) |
137 | { |
138 | fprintf(base_yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, " , compat, force_indicator, connection ? connection : "NULL" , questionmarks); |
139 | |
140 | if (st == ECPGst_prepnormal && !auto_prepare) |
141 | st = ECPGst_normal; |
142 | |
143 | /* |
144 | * In following cases, stmt is CSTRING or char_variable. They must be |
145 | * output directly. - prepared_name of EXECUTE without exprlist - |
146 | * execstring of EXECUTE IMMEDIATE |
147 | */ |
148 | fprintf(base_yyout, "%s, " , ecpg_statement_type_name[st]); |
149 | if (st == ECPGst_execute || st == ECPGst_exec_immediate) |
150 | fprintf(base_yyout, "%s, " , stmt); |
151 | else |
152 | { |
153 | fputs("\"" , base_yyout); |
154 | output_escaped_str(stmt, false); |
155 | fputs("\", " , base_yyout); |
156 | } |
157 | |
158 | /* dump variables to C file */ |
159 | dump_variables(argsinsert, 1); |
160 | fputs("ECPGt_EOIT, " , base_yyout); |
161 | dump_variables(argsresult, 1); |
162 | fputs("ECPGt_EORT);" , base_yyout); |
163 | reset_variables(); |
164 | |
165 | whenever_action(whenever_mode | 2); |
166 | free(stmt); |
167 | if (connection != NULL) |
168 | free(connection); |
169 | connection = NULL; |
170 | } |
171 | |
172 | void |
173 | output_prepare_statement(char *name, char *stmt) |
174 | { |
175 | fprintf(base_yyout, "{ ECPGprepare(__LINE__, %s, %d, " , connection ? connection : "NULL" , questionmarks); |
176 | output_escaped_str(name, true); |
177 | fputs(", " , base_yyout); |
178 | output_escaped_str(stmt, true); |
179 | fputs(");" , base_yyout); |
180 | whenever_action(2); |
181 | free(name); |
182 | if (connection != NULL) |
183 | free(connection); |
184 | connection = NULL; |
185 | } |
186 | |
187 | void |
188 | output_deallocate_prepare_statement(char *name) |
189 | { |
190 | const char *con = connection ? connection : "NULL" ; |
191 | |
192 | if (strcmp(name, "all" ) != 0) |
193 | { |
194 | fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, " , compat, con); |
195 | output_escaped_str(name, true); |
196 | fputs(");" , base_yyout); |
197 | } |
198 | else |
199 | fprintf(base_yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);" , compat, con); |
200 | |
201 | whenever_action(2); |
202 | free(name); |
203 | if (connection != NULL) |
204 | free(connection); |
205 | connection = NULL; |
206 | } |
207 | |
208 | static void |
209 | output_escaped_str(char *str, bool quoted) |
210 | { |
211 | int i = 0; |
212 | int len = strlen(str); |
213 | |
214 | if (quoted && str[0] == '"' && str[len - 1] == '"') /* do not escape quotes |
215 | * at beginning and end |
216 | * if quoted string */ |
217 | { |
218 | i = 1; |
219 | len--; |
220 | fputs("\"" , base_yyout); |
221 | } |
222 | |
223 | /* output this char by char as we have to filter " and \n */ |
224 | for (; i < len; i++) |
225 | { |
226 | if (str[i] == '"') |
227 | fputs("\\\"" , base_yyout); |
228 | else if (str[i] == '\n') |
229 | fputs("\\\n" , base_yyout); |
230 | else if (str[i] == '\\') |
231 | { |
232 | int j = i; |
233 | |
234 | /* |
235 | * check whether this is a continuation line if it is, do not |
236 | * output anything because newlines are escaped anyway |
237 | */ |
238 | |
239 | /* accept blanks after the '\' as some other compilers do too */ |
240 | do |
241 | { |
242 | j++; |
243 | } while (str[j] == ' ' || str[j] == '\t'); |
244 | |
245 | if ((str[j] != '\n') && (str[j] != '\r' || str[j + 1] != '\n')) /* not followed by a |
246 | * newline */ |
247 | fputs("\\\\" , base_yyout); |
248 | } |
249 | else if (str[i] == '\r' && str[i + 1] == '\n') |
250 | { |
251 | fputs("\\\r\n" , base_yyout); |
252 | i++; |
253 | } |
254 | else |
255 | fputc(str[i], base_yyout); |
256 | } |
257 | |
258 | if (quoted && str[0] == '"' && str[len] == '"') |
259 | fputs("\"" , base_yyout); |
260 | } |
261 | |