1/* src/interfaces/ecpg/preproc/output.c */
2
3#include "postgres_fe.h"
4
5#include "preproc_extern.h"
6
7static void output_escaped_str(char *cmd, bool quoted);
8
9void
10output_line_number(void)
11{
12 char *line = hashline_number();
13
14 fprintf(base_yyout, "%s", line);
15 free(line);
16}
17
18void
19output_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 */
32struct when when_error,
33 when_nf,
34 when_warn;
35
36static void
37print_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
65void
66whenever_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
93char *
94hashline_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
126static 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
135void
136output_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
172void
173output_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
187void
188output_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
208static void
209output_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