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