* Handle parsing errors and warnings
*/
void
-mmerror(enum errortype type, char * error)
+mmerror(int error_code, enum errortype type, char * error)
{
switch(type)
{
break;
case ET_ERROR:
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
- ret_value = PARSE_ERROR;
+ ret_value = error_code;
break;
case ET_FATAL:
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
- exit(PARSE_ERROR);
+ exit(error_code);
}
}
}
| ECPGConnect {
if (connection)
- mmerror(ET_ERROR, "no at option for connect statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement.\n");
fprintf(yyout, "{ ECPGconnect(__LINE__, %s, %d); ", $1, autocommit);
}
| ECPGDeallocate {
if (connection)
- mmerror(ET_ERROR, "no at option for connect statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement.\n");
fputc('{', yyout);
fputs($1, yyout);
}
| ECPGDisconnect {
if (connection)
- mmerror(ET_ERROR, "no at option for disconnect statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement.\n");
fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", $1);
whenever_action(2);
if (ptr == NULL)
{
sprintf(errortext, "trying to open undeclared cursor %s\n", $1);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
/* merge variables given in prepare statement with those given here */
}
| ECPGPrepare {
if (connection)
- mmerror(ET_ERROR, "no at option for set connection statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement.\n");
fprintf(yyout, "{ ECPGprepare(__LINE__, %s);", $1);
whenever_action(2);
}
| ECPGSetConnection {
if (connection)
- mmerror(ET_ERROR, "no at option for set connection statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement.\n");
fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1);
whenever_action(2);
}
| ECPGTypedef {
if (connection)
- mmerror(ET_ERROR, "no at option for typedef statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement.\n");
output_simple_statement($1);
}
| ECPGVar {
if (connection)
- mmerror(ET_ERROR, "no at option for var statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for var statement.\n");
output_simple_statement($1);
}
| ECPGWhenever {
if (connection)
- mmerror(ET_ERROR, "no at option for whenever statement.\n");
+ mmerror(PARSE_ERROR, ET_ERROR, "no at option for whenever statement.\n");
output_simple_statement($1);
}
| AllConst { $$ = $1; }
| name_list {
if (strlen($1) == 0)
- mmerror(ET_ERROR, "SET must have at least one argument.");
+ mmerror(PARSE_ERROR, ET_ERROR, "SET must have at least one argument.");
$$ = $1;
}
| LOCAL TEMPORARY { $$ = make_str("local temporary"); }
| LOCAL TEMP { $$ = make_str("local temp"); }
| GLOBAL TEMPORARY {
- mmerror(ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend");
$$ = make_str("global temporary");
}
| GLOBAL TEMP {
- mmerror(ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend");
$$ = make_str("global temp");
}
| /*EMPTY*/ { $$ = EMPTY; }
if (strlen($4) > 0)
{
sprintf(errortext, "Currently unsupported CREATE TABLE / COLLATE %s will be passed to backend", $4);
- mmerror(ET_NOTICE, errortext);
+ mmerror(PARSE_ERROR, ET_NOTICE, errortext);
}
$$ = cat_str(4, $1, $2, $3, $4);
}
}
| MATCH PARTIAL
{
- mmerror(ET_NOTICE, "Currently unsupported FOREIGN KEY/MATCH PARTIAL will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported FOREIGN KEY/MATCH PARTIAL will be passed to backend");
$$ = make_str("match partial");
}
| /*EMPTY*/
{ FoundInto = 0; } SelectStmt
{
if (FoundInto == 1)
- mmerror(ET_ERROR, "CREATE TABLE / AS SELECT may not specify INTO");
+ mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE / AS SELECT may not specify INTO");
$$ = cat_str(7, make_str("create"), $2, make_str("table"), $4, $5, make_str("as"), $8);
}
| ConstraintDeferrabilitySpec ConstraintTimeSpec
{
if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 )
- mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
+ mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
$$ = cat2_str($1, $2);
}
| ConstraintTimeSpec ConstraintDeferrabilitySpec
{
if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
- mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
+ mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
$$ = cat2_str($1, $2);
}
FetchStmt: FETCH direction fetch_how_many from_in name ecpg_into
{
if (strcmp($2, "relative") == 0 && atol($3) == 0L)
- mmerror(ET_ERROR, "FETCH/RELATIVE at current position is not supported");
+ mmerror(PARSE_ERROR, ET_ERROR, "FETCH/RELATIVE at current position is not supported");
$$ = cat_str(5, make_str("fetch"), $2, $3, $4, $5);
}
| BACKWARD { $$ = make_str("backward"); }
| RELATIVE { $$ = make_str("relative"); }
| ABSOLUTE {
- mmerror(ET_NOTICE, "Currently unsupported FETCH/ABSOLUTE will be passed to backend, backend will use RELATIVE");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported FETCH/ABSOLUTE will be passed to backend, backend will use RELATIVE");
$$ = make_str("absolute");
}
;
opt_with_grant: WITH GRANT OPTION
{
- mmerror(ET_NOTICE, "Currently unsupported GRANT/WITH GRANT OPTION will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported GRANT/WITH GRANT OPTION will be passed to backend");
$$ = make_str("with grant option");
}
| /*EMPTY*/ { $$ = EMPTY; }
opt_arg: IN { $$ = make_str("in"); }
| OUT {
- mmerror(ET_NOTICE, "Currently unsupported CREATE FUNCTION/OUT will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported CREATE FUNCTION/OUT will be passed to backend");
$$ = make_str("out");
}
| INOUT {
- mmerror(ET_NOTICE, "Currently unsupported CREATE FUNCTION/INOUT will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported CREATE FUNCTION/INOUT will be passed to backend");
$$ = make_str("inout");
}
oper_argtypes: Typename
{
- mmerror(ET_ERROR, "parser: argument type missing (use NONE for unary operators)");
+ mmerror(PARSE_ERROR, ET_ERROR, "parser: argument type missing (use NONE for unary operators)");
}
| Typename ',' Typename
{ $$ = cat_str(3, $1, make_str(","), $3); }
opt_chain: AND NO CHAIN { $$ = make_str("and no chain"); }
| AND CHAIN {
- mmerror(ET_NOTICE, "Currently unsupported COMMIT/CHAIN will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported COMMIT/CHAIN will be passed to backend");
$$ = make_str("and chain");
}
{
/* re-definition is a bug */
sprintf(errortext, "cursor %s already defined", $2);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
}
}
| GLOBAL TEMPORARY opt_table relation_name
{
- mmerror(ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend");
$$ = cat_str(3, make_str("global temporary"), $3, $4);
}
| GLOBAL TEMP opt_table relation_name
{
- mmerror(ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend");
+ mmerror(PARSE_ERROR, ET_NOTICE, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend");
$$ = cat_str(3, make_str("global temp"), $3, $4);
}
| TABLE relation_name
| LIMIT select_limit_value ',' select_offset_value
{ $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4); }
/* enable this in 7.3, bjm 2001-10-22
- { mmerror(ET_NOTICE, "No longer supported LIMIT #,# syntax passed to backend."); }
+ { mmerror(PARSE_ERROR, ET_NOTICE, "No longer supported LIMIT #,# syntax passed to backend."); }
*/
;
select_limit_value: PosIntConst {
if (atoi($1) < 0)
- mmerror(ET_ERROR, "LIMIT must not be negative");
+ mmerror(PARSE_ERROR, ET_ERROR, "LIMIT must not be negative");
$$ = $1;
}
| ALL { $$ = make_str("all"); }
select_offset_value: PosIntConst {
if (atoi($1) < 0)
- mmerror(ET_ERROR, "OFFSET must not be negative");
+ mmerror(PARSE_ERROR, ET_ERROR, "OFFSET must not be negative");
$$ = $1;
}
| PARAM { $$ = make_name(); }
}
| select_with_parens
{
- mmerror(ET_ERROR, "sub-SELECT in FROM must have an alias");
+ mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias");
}
| select_with_parens alias_clause
{
SpecialRuleRelation: OLD
{
if (!QueryIsRule)
- mmerror(ET_ERROR, "OLD used in non-rule query");
+ mmerror(PARSE_ERROR, ET_ERROR, "OLD used in non-rule query");
$$ = make_str("old");
}
| NEW
{
if (!QueryIsRule)
- mmerror(ET_ERROR, "NEW used in non-rule query");
+ mmerror(PARSE_ERROR, ET_ERROR, "NEW used in non-rule query");
$$ = make_str("new");
}
if (strlen($2) > 0 && *($2) != '@')
{
sprintf(errortext, "Expected '@', found '%s'", $2);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\""));
if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
{
sprintf(errortext, "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
if (strncmp($3, "//", strlen("//")) != 0)
{
sprintf(errortext, "Expected '://', found '%s'", $3);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
if (strncmp($1, "unix", strlen("unix")) == 0 &&
strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
{
sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6), $7, make_str("\"")));
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
{
sprintf(errortext, "Expected 'postgresql', found '%s'", $2);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
{
sprintf(errortext, "Illegal connection type %s", $1);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make3_str($1, make_str(":"), $2);
if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
{
sprintf(errortext, "Expected '@' or '://', found '%s'", $1);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make2_str($1, $2);
$$ = make2_str($1, make_str(".arr"));
break;
default:
- mmerror(ET_ERROR, "invalid datatype");
+ mmerror(PARSE_ERROR, ET_ERROR, "invalid datatype");
break;
}
}
opt_options: Op ColId
{
if (strlen($1) == 0)
- mmerror(ET_ERROR, "incomplete statement");
+ mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
if (strcmp($1, "?") != 0)
{
sprintf(errortext, "unrecognised token '%s'", $1);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make2_str(make_str("?"), $2);
{
/* re-definition is a bug */
sprintf(errortext, "cursor %s already defined", $2);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
}
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
- mmerror(ET_ERROR, "Too many levels in nested structure definition");
+ mmerror(PARSE_ERROR, ET_ERROR, "Too many levels in nested structure definition");
$$ = cat2_str(make_str("struct"), $2);
};
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
- mmerror(ET_ERROR, "Too many levels in nested structure definition");
+ mmerror(PARSE_ERROR, ET_ERROR, "Too many levels in nested structure definition");
$$ = cat2_str(make_str("union"), $2);
};
sprintf(ascii_len, "%d", length);
if (length == 0)
- mmerror(ET_ERROR, "pointer to varchar are not implemented");
+ mmerror(PARSE_ERROR, ET_ERROR, "pointer to varchar are not implemented");
if (dimension == 0)
$$ = cat_str(7, mm_strdup(actual_storage[struct_level]), make2_str(make_str(" struct varchar_"), mm_strdup($2)), make_str(" { int len; char arr["), mm_strdup(ascii_len), make_str("]; } *"), mm_strdup($2), $4);
ECPGRelease: TransactionStmt SQL_RELEASE
{
if (strcmp($1, "begin") == 0)
- mmerror(ET_ERROR, "RELEASE does not make sense when beginning a transaction");
+ mmerror(PARSE_ERROR, ET_ERROR, "RELEASE does not make sense when beginning a transaction");
fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");",
connection ? connection : "NULL", $1);
$5.type_enum == ECPGt_union) &&
initializer == 1)
{
- mmerror(ET_ERROR, "Initializer not allowed in EXEC SQL VAR command");
+ mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in EXEC SQL VAR command");
}
else
{
{
/* re-definition is a bug */
sprintf(errortext, "Type %s already defined", $3);
- mmerror(ET_ERROR, errortext);
+ mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
}
$5.type_enum != ECPGt_char &&
$5.type_enum != ECPGt_unsigned_char &&
this->type->type_index >= 0)
- mmerror(ET_ERROR, "No multi-dimensional array support for simple data types");
+ mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
types = this;
}
$5.type_enum == ECPGt_union) &&
initializer == 1)
{
- mmerror(ET_ERROR, "Initializer not allowed in EXEC SQL VAR command");
+ mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in EXEC SQL VAR command");
}
else
{
break;
default:
if (length >= 0)
- mmerror(ET_ERROR, "No multi-dimensional array support for simple data types");
+ mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
if (dimension < 0)
type = ECPGmake_simple_type($5.type_enum, 1);
civarind: cvariable indicator
{
if ($2 != NULL && (find_variable($2))->type->typ == ECPGt_array)
- mmerror(ET_ERROR, "arrays of indicators are not allowed on input");
+ mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2));
};
{ char buf[1024];
snprintf(buf,sizeof buf,"%s at or near \"%s\"",error,yytext);
buf[sizeof(buf)-1]=0;
- mmerror(ET_ERROR, buf);
+ mmerror(PARSE_ERROR, ET_ERROR, buf);
}
#include "extern.h"
+#define indicator_set ind_typ != NULL && ind_typ->typ != ECPGt_NO_INDICATOR
+
struct ECPGstruct_member struct_no_indicator = {"no_indicator", &ecpg_no_indicator, NULL};
/* malloc + error check */
void *ptr = malloc(size);
if (ptr == NULL)
- {
- fprintf(stderr, "Out of memory\n");
- exit(OUT_OF_MEMORY);
- }
+ mmerror(OUT_OF_MEMORY, ET_FATAL, "Out of memory\n");
return ptr;
}
char *new = strdup(string);
if (new == NULL)
- {
- fprintf(stderr, "Out of memory\n");
- exit(OUT_OF_MEMORY);
- }
-
+ mmerror(OUT_OF_MEMORY, ET_FATAL, "Out of memory\n");
+
return new;
}
static void ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, long arrsiz,
struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offset, const char *prefix, const char *ind_prefix);
-
void
ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *ind_name, struct ECPGtype * ind_typ, const char *prefix, const char *ind_prefix)
{
-/* if (ind_typ == NULL)
- {
- ind_typ = &ecpg_no_indicator;
- ind_name = "no_indicator";
- }*/
-
switch (typ->typ)
{
case ECPGt_array:
+ if (indicator_set && ind_typ->typ != ECPGt_array)
+ mmerror(INDICATOR_NOT_ARRAY, ET_FATAL, "Indicator for array/pointer has to be array/pointer.\n");
+
switch (typ->u.element->typ)
{
case ECPGt_array:
- yyerror("No nested arrays allowed (except strings)"); /* array of array */
+ mmerror(PARSE_ERROR, ET_ERROR, "No nested arrays allowed (except strings)"); /* array of array */
break;
case ECPGt_struct:
case ECPGt_union:
if (ind_typ->typ == ECPGt_NO_INDICATOR)
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
else
- {
- if (ind_typ->typ != ECPGt_array)
- {
- fprintf(stderr, "Indicator for an array has to be array too.\n");
- exit(INDICATOR_NOT_ARRAY);
- }
ECPGdump_a_simple(o, ind_name, ind_typ->u.element->typ,
ind_typ->u.element->size, ind_typ->size, NULL, prefix);
- }
}
}
break;
case ECPGt_struct:
+ if (indicator_set && ind_typ->typ != ECPGt_struct)
+ mmerror(INDICATOR_NOT_STRUCT, ET_FATAL, "Indicator for struct has to be struct.\n");
+
ECPGdump_a_struct(o, name, ind_name, 1, typ, ind_typ, NULL, prefix, ind_prefix);
break;
case ECPGt_union: /* cannot dump a complete union */
yyerror("Type of union has to be specified");
break;
case ECPGt_char_variable:
+ if (indicator_set && (ind_typ->typ == ECPGt_struct || ind_typ->typ == ECPGt_array))
+ mmerror(INDICATOR_NOT_SIMPLE, ET_FATAL, "Indicator for simple datatype has to be simple.\n");
+
ECPGdump_a_simple(o, name, typ->typ, 1, 1, NULL, prefix);
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
break;
case ECPGt_descriptor:
+ if (indicator_set && (ind_typ->typ == ECPGt_struct || ind_typ->typ == ECPGt_array))
+ mmerror(INDICATOR_NOT_SIMPLE, ET_FATAL, "Indicator for simple datatype has to be simple.\n");
+
ECPGdump_a_simple(o, name, typ->typ, 0, -1, NULL, prefix);
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
break;
default:
+ if (indicator_set && (ind_typ->typ == ECPGt_struct || ind_typ->typ == ECPGt_array))
+ mmerror(INDICATOR_NOT_SIMPLE, ET_FATAL, "Indicator for simple datatype has to be simple.\n");
+
ECPGdump_a_simple(o, name, typ->typ, typ->size, -1, NULL, prefix);
if (ind_typ != NULL)
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
struct ECPGstruct_member *p,
*ind_p = NULL;
char obuf[BUFSIZ];
- char pbuf[BUFSIZ*2],
+ char pbuf[BUFSIZ],
ind_pbuf[BUFSIZ];
const char *offset;