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