| 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 | |