diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 0572925d08..1b3d619017 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -2351,6 +2351,13 @@ Mon, 12 May 2008 18:19:08 +0200 - Check for non-existant connection in prepare statement handling. - Do not close files that weren't opened. + +Tue, 20 May 2008 17:31:01 +0200 + + - Synced parser. + - Made ecpg parser use backend provided keyword list. One less file to + sync manually. + - Changed whenever test so exit value is 0. - Set pgtypes library version to 3.1. - Set compat library version to 3.1. - Set ecpg library version to 6.2. diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index f03e69fa1d..6dd0fa6266 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 1998-2008, PostgreSQL Global Development Group # -# $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/Makefile,v 1.132 2008/03/18 17:46:23 petere Exp $ +# $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/Makefile,v 1.133 2008/05/20 23:17:32 meskes Exp $ # #------------------------------------------------------------------------- @@ -25,7 +25,7 @@ override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \ override CFLAGS += $(PTHREAD_CFLAGS) OBJS= preproc.o type.o ecpg.o output.o parser.o \ - keywords.o c_keywords.o ../ecpglib/typename.o descriptor.o variable.o \ + keywords.o c_keywords.o ecpg_keywords.o ../ecpglib/typename.o descriptor.o variable.o \ $(WIN32RES) all: submake-libpgport ecpg @@ -56,6 +56,11 @@ endif c_keywords.o keywords.o preproc.o parser.o: preproc.h +# instead of maintaining our own list, take the one from the backend +# we cannot just link it in, but must copy and make some minor changes +keywords.c: % : $(top_srcdir)/src/backend/parser/% + sed -e 's/#include "parser\/parse.h"/#include "preproc.h"/' $< > $@ + distprep: $(srcdir)/preproc.c $(srcdir)/preproc.h $(srcdir)/pgc.c install: all installdirs @@ -68,7 +73,7 @@ uninstall: rm -f '$(DESTDIR)$(bindir)/ecpg$(X)' clean distclean: - rm -f *.o ecpg$(X) + rm -f keywords.c *.o ecpg$(X) # garbage from partial builds @rm -f y.tab.c y.tab.h # garbage from development diff --git a/src/interfaces/ecpg/preproc/c_keywords.c b/src/interfaces/ecpg/preproc/c_keywords.c index bd76ac15e6..3ab4f0ed95 100644 --- a/src/interfaces/ecpg/preproc/c_keywords.c +++ b/src/interfaces/ecpg/preproc/c_keywords.c @@ -3,7 +3,7 @@ * keywords.c * lexical token lookup for reserved words in postgres embedded SQL * - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/c_keywords.c,v 1.21 2007/08/22 08:20:58 meskes Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/c_keywords.c,v 1.22 2008/05/20 23:17:32 meskes Exp $ * ยง *------------------------------------------------------------------------- */ @@ -21,37 +21,39 @@ * search is used to locate entries. */ static const ScanKeyword ScanCKeywords[] = { - /* name value */ - {"VARCHAR", VARCHAR}, - {"auto", S_AUTO}, - {"bool", SQL_BOOL}, - {"char", CHAR_P}, - {"const", S_CONST}, - {"enum", ENUM_P}, - {"extern", S_EXTERN}, - {"float", FLOAT_P}, - {"hour", HOUR_P}, - {"int", INT_P}, - {"long", SQL_LONG}, - {"minute", MINUTE_P}, - {"month", MONTH_P}, - {"register", S_REGISTER}, - {"second", SECOND_P}, - {"short", SQL_SHORT}, - {"signed", SQL_SIGNED}, - {"static", S_STATIC}, - {"struct", SQL_STRUCT}, - {"to", TO}, - {"typedef", S_TYPEDEF}, - {"union", UNION}, - {"unsigned", SQL_UNSIGNED}, - {"varchar", VARCHAR}, - {"volatile", S_VOLATILE}, - {"year", YEAR_P}, + /* name, value, category */ + /* category is not needed in ecpg, it is only here so we can share + * the data structure with the backend */ + {"VARCHAR", VARCHAR, 0}, + {"auto", S_AUTO, 0}, + {"bool", SQL_BOOL, 0}, + {"char", CHAR_P, 0}, + {"const", S_CONST, 0}, + {"enum", ENUM_P, 0}, + {"extern", S_EXTERN, 0}, + {"float", FLOAT_P, 0}, + {"hour", HOUR_P, 0}, + {"int", INT_P, 0}, + {"long", SQL_LONG, 0}, + {"minute", MINUTE_P, 0}, + {"month", MONTH_P, 0}, + {"register", S_REGISTER, 0}, + {"second", SECOND_P, 0}, + {"short", SQL_SHORT, 0}, + {"signed", SQL_SIGNED, 0}, + {"static", S_STATIC, 0}, + {"struct", SQL_STRUCT, 0}, + {"to", TO, 0}, + {"typedef", S_TYPEDEF, 0}, + {"union", UNION, 0}, + {"unsigned", SQL_UNSIGNED, 0}, + {"varchar", VARCHAR, 0}, + {"volatile", S_VOLATILE, 0}, + {"year", YEAR_P, 0}, }; const ScanKeyword * -ScanCKeywordLookup(char *text) +ScanCKeywordLookup(const char *text) { return DoLookup(text, &ScanCKeywords[0], endof(ScanCKeywords) - 1); } diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c index 98179fe39f..3d8db40537 100644 --- a/src/interfaces/ecpg/preproc/ecpg_keywords.c +++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c @@ -4,11 +4,18 @@ * lexical token lookup for reserved words in postgres embedded SQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg_keywords.c,v 1.37 2007/11/15 21:14:45 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg_keywords.c,v 1.38 2008/05/20 23:17:32 meskes Exp $ * *------------------------------------------------------------------------- */ +#include "postgres_fe.h" + +#include + +#include "extern.h" +#include "preproc.h" + /* * List of (keyword-name, keyword-token-value) pairs. * @@ -16,50 +23,129 @@ * search is used to locate entries. */ static const ScanKeyword ScanECPGKeywords[] = { - /* name value */ - {"allocate", SQL_ALLOCATE}, - {"autocommit", SQL_AUTOCOMMIT}, - {"bool", SQL_BOOL}, - {"break", SQL_BREAK}, - {"call", SQL_CALL}, - {"cardinality", SQL_CARDINALITY}, - {"connect", SQL_CONNECT}, - {"continue", SQL_CONTINUE}, - {"count", SQL_COUNT}, - {"data", SQL_DATA}, - {"datetime_interval_code", SQL_DATETIME_INTERVAL_CODE}, - {"datetime_interval_precision", SQL_DATETIME_INTERVAL_PRECISION}, - {"describe", SQL_DESCRIBE}, - {"descriptor", SQL_DESCRIPTOR}, - {"disconnect", SQL_DISCONNECT}, - {"found", SQL_FOUND}, - {"free", SQL_FREE}, - {"go", SQL_GO}, - {"goto", SQL_GOTO}, - {"identified", SQL_IDENTIFIED}, - {"indicator", SQL_INDICATOR}, - {"key_member", SQL_KEY_MEMBER}, - {"length", SQL_LENGTH}, - {"long", SQL_LONG}, - {"nullable", SQL_NULLABLE}, - {"octet_length", SQL_OCTET_LENGTH}, - {"open", SQL_OPEN}, - {"output", SQL_OUTPUT}, - {"reference", SQL_REFERENCE}, - {"returned_length", SQL_RETURNED_LENGTH}, - {"returned_octet_length", SQL_RETURNED_OCTET_LENGTH}, - {"scale", SQL_SCALE}, - {"section", SQL_SECTION}, - {"short", SQL_SHORT}, - {"signed", SQL_SIGNED}, - {"sql", SQL_SQL}, /* strange thing, used for into sql descriptor + /* name, value, category */ + /* category is not needed in ecpg, it is only here so we can share + * the data structure with the backend */ + {"allocate", SQL_ALLOCATE, 0}, + {"autocommit", SQL_AUTOCOMMIT, 0}, + {"bool", SQL_BOOL, 0}, + {"break", SQL_BREAK, 0}, + {"call", SQL_CALL, 0}, + {"cardinality", SQL_CARDINALITY, 0}, + {"connect", SQL_CONNECT, 0}, + {"count", SQL_COUNT, 0}, + {"data", SQL_DATA, 0}, + {"datetime_interval_code", SQL_DATETIME_INTERVAL_CODE, 0}, + {"datetime_interval_precision", SQL_DATETIME_INTERVAL_PRECISION, 0}, + {"describe", SQL_DESCRIBE, 0}, + {"descriptor", SQL_DESCRIPTOR, 0}, + {"disconnect", SQL_DISCONNECT, 0}, + {"found", SQL_FOUND, 0}, + {"free", SQL_FREE, 0}, + {"get", SQL_GET, 0}, + {"go", SQL_GO, 0}, + {"goto", SQL_GOTO, 0}, + {"identified", SQL_IDENTIFIED, 0}, + {"indicator", SQL_INDICATOR, 0}, + {"key_member", SQL_KEY_MEMBER, 0}, + {"length", SQL_LENGTH, 0}, + {"long", SQL_LONG, 0}, + {"nullable", SQL_NULLABLE, 0}, + {"octet_length", SQL_OCTET_LENGTH, 0}, + {"open", SQL_OPEN, 0}, + {"output", SQL_OUTPUT, 0}, + {"reference", SQL_REFERENCE, 0}, + {"returned_length", SQL_RETURNED_LENGTH, 0}, + {"returned_octet_length", SQL_RETURNED_OCTET_LENGTH, 0}, + {"scale", SQL_SCALE, 0}, + {"section", SQL_SECTION, 0}, + {"short", SQL_SHORT, 0}, + {"signed", SQL_SIGNED, 0}, + {"sql", SQL_SQL, 0}, /* strange thing, used for into sql descriptor * MYDESC; */ - {"sqlerror", SQL_SQLERROR}, - {"sqlprint", SQL_SQLPRINT}, - {"sqlwarning", SQL_SQLWARNING}, - {"stop", SQL_STOP}, - {"struct", SQL_STRUCT}, - {"unsigned", SQL_UNSIGNED}, - {"var", SQL_VAR}, - {"whenever", SQL_WHENEVER}, + {"sqlerror", SQL_SQLERROR, 0}, + {"sqlprint", SQL_SQLPRINT, 0}, + {"sqlwarning", SQL_SQLWARNING, 0}, + {"stop", SQL_STOP, 0}, + {"struct", SQL_STRUCT, 0}, + {"unsigned", SQL_UNSIGNED, 0}, + {"var", SQL_VAR, 0}, + {"whenever", SQL_WHENEVER, 0}, }; + +/* This is all taken from src/backend/parser/keyword.c and adjusted for our needs. */ +/* + * Do a binary search using plain strcmp() comparison. + */ +const ScanKeyword * +DoLookup(const char *word, const ScanKeyword *low, const ScanKeyword *high) +{ + while (low <= high) + { + const ScanKeyword *middle; + int difference; + + middle = low + (high - low) / 2; + difference = strcmp(middle->name, word); + if (difference == 0) + return middle; + else if (difference < 0) + low = middle + 1; + else + high = middle - 1; + } + + return NULL; +} + +/* + * ScanECPGKeywordLookup - see if a given word is a keyword + * + * Returns a pointer to the ScanKeyword table entry, or NULL if no match. + * + * The match is done case-insensitively. Note that we deliberately use a + * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z', + * even if we are in a locale where tolower() would produce more or different + * translations. This is to conform to the SQL99 spec, which says that + * keywords are to be matched in this way even though non-keyword identifiers + * receive a different case-normalization mapping. + */ +const ScanKeyword * +ScanECPGKeywordLookup(const char *text) +{ + int len, + i; + char word[NAMEDATALEN]; + const ScanKeyword *res; + + /* First check SQL symbols defined by the backend. */ + + res = ScanKeywordLookup(text); + if (res) + return res; + + len = strlen(text); + /* We assume all keywords are shorter than NAMEDATALEN. */ + if (len >= NAMEDATALEN) + return NULL; + + /* + * Apply an ASCII-only downcasing. We must not use tolower() since it may + * produce the wrong translation in some locales (eg, Turkish). + */ + for (i = 0; i < len; i++) + { + char ch = text[i]; + + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + word[i] = ch; + } + word[len] = '\0'; + + /* + * Now do a binary search using plain strcmp() comparison. + */ + + return DoLookup(word, &ScanECPGKeywords[0], endof(ScanECPGKeywords) - 1); +} diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index c9097c87ee..7f55441da3 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -1,9 +1,10 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/extern.h,v 1.70 2007/11/15 21:14:45 momjian Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/extern.h,v 1.71 2008/05/20 23:17:32 meskes Exp $ */ #ifndef _ECPG_PREPROC_EXTERN_H #define _ECPG_PREPROC_EXTERN_H #include "type.h" +#include "parser/keywords.h" #include #ifndef CHAR_BIT @@ -74,7 +75,6 @@ extern void base_yyerror(const char *); extern void *mm_alloc(size_t), *mm_realloc(void *, size_t); extern char *mm_strdup(const char *); extern void mmerror(int, enum errortype, char *,...); -extern const ScanKeyword *ScanCKeywordLookup(char *); extern void output_get_descr_header(char *); extern void output_get_descr(char *, char *); extern void output_set_descr_header(char *); @@ -96,8 +96,9 @@ extern void check_indicator(struct ECPGtype *); extern void remove_typedefs(int); extern void remove_variables(int); extern struct variable *new_variable(const char *, struct ECPGtype *, int); -extern const ScanKeyword *ScanKeywordLookup(char *text); -extern const ScanKeyword *DoLookup(char *, const ScanKeyword *, const ScanKeyword *); +extern const ScanKeyword *ScanCKeywordLookup(const char *); +extern const ScanKeyword *ScanECPGKeywordLookup(const char *text); +extern const ScanKeyword *DoLookup(const char *, const ScanKeyword *, const ScanKeyword *); extern void scanner_init(const char *); extern void parser_init(void); extern void scanner_finish(void); diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c deleted file mode 100644 index 8a92bdf5c4..0000000000 --- a/src/interfaces/ecpg/preproc/keywords.c +++ /dev/null @@ -1,476 +0,0 @@ -/*------------------------------------------------------------------------- - * - * keywords.c - * lexical token lookup for reserved words in PostgreSQL - * - * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.85 2008/01/01 19:45:59 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include - -#include "extern.h" -#include "preproc.h" - -/* compile both keyword lists in one file because they are always scanned together */ -#include "ecpg_keywords.c" - -/* - * List of (keyword-name, keyword-token-value) pairs. - * - * !!WARNING!!: This list must be sorted, because binary - * search is used to locate entries. - */ -static const ScanKeyword ScanPGSQLKeywords[] = { - /* name, value */ - {"abort", ABORT_P}, - {"absolute", ABSOLUTE_P}, - {"access", ACCESS}, - {"action", ACTION}, - {"add", ADD_P}, - {"admin", ADMIN}, - {"after", AFTER}, - {"aggregate", AGGREGATE}, - {"all", ALL}, - {"also", ALSO}, - {"alter", ALTER}, - {"always", ALWAYS}, - {"analyse", ANALYSE}, /* British spelling */ - {"analyze", ANALYZE}, - {"and", AND}, - {"any", ANY}, - {"array", ARRAY}, - {"as", AS}, - {"asc", ASC}, - {"assertion", ASSERTION}, - {"assignment", ASSIGNMENT}, - {"asymmetric", ASYMMETRIC}, - {"at", AT}, - {"authorization", AUTHORIZATION}, - {"backward", BACKWARD}, - {"before", BEFORE}, - {"begin", BEGIN_P}, - {"between", BETWEEN}, - {"bigint", BIGINT}, - {"binary", BINARY}, - {"bit", BIT}, - {"boolean", BOOLEAN_P}, - {"both", BOTH}, - {"by", BY}, - {"cache", CACHE}, - {"called", CALLED}, - {"cascade", CASCADE}, - {"cascaded", CASCADED}, - {"case", CASE}, - {"cast", CAST}, - {"chain", CHAIN}, - {"char", CHAR_P}, - {"character", CHARACTER}, - {"characteristics", CHARACTERISTICS}, - {"check", CHECK}, - {"checkpoint", CHECKPOINT}, - {"class", CLASS}, - {"close", CLOSE}, - {"cluster", CLUSTER}, - {"coalesce", COALESCE}, - {"collate", COLLATE}, - {"column", COLUMN}, - {"comment", COMMENT}, - {"commit", COMMIT}, - {"committed", COMMITTED}, - {"concurrently", CONCURRENTLY}, - {"configuration", CONFIGURATION}, - {"connection", CONNECTION}, - {"constraint", CONSTRAINT}, - {"constraints", CONSTRAINTS}, - {"content", CONTENT_P}, - {"conversion", CONVERSION_P}, - {"copy", COPY}, - {"cost", COST}, - {"create", CREATE}, - {"createdb", CREATEDB}, - {"createrole", CREATEROLE}, - {"createuser", CREATEUSER}, - {"cross", CROSS}, - {"csv", CSV}, - {"current", CURRENT_P}, - {"current_date", CURRENT_DATE}, - {"current_role", CURRENT_ROLE}, - {"current_time", CURRENT_TIME}, - {"current_timestamp", CURRENT_TIMESTAMP}, - {"cursor", CURSOR}, - {"cycle", CYCLE}, - {"database", DATABASE}, - {"day", DAY_P}, - {"deallocate", DEALLOCATE}, - {"dec", DEC}, - {"decimal", DECIMAL_P}, - {"declare", DECLARE}, - {"default", DEFAULT}, - {"defaults", DEFAULTS}, - {"deferrable", DEFERRABLE}, - {"deferred", DEFERRED}, - {"definer", DEFINER}, - {"delete", DELETE_P}, - {"delimiter", DELIMITER}, - {"delimiters", DELIMITERS}, - {"desc", DESC}, - {"dictionary", DICTIONARY}, - {"disable", DISABLE_P}, - {"discard", DISCARD}, - {"distinct", DISTINCT}, - {"do", DO}, - {"document", DOCUMENT_P}, - {"domain", DOMAIN_P}, - {"double", DOUBLE_P}, - {"drop", DROP}, - {"each", EACH}, - {"else", ELSE}, - {"enable", ENABLE_P}, - {"encoding", ENCODING}, - {"encrypted", ENCRYPTED}, - {"end", END_P}, - {"enum", ENUM_P}, - {"escape", ESCAPE}, - {"except", EXCEPT}, - {"excluding", EXCLUDING}, - {"exclusive", EXCLUSIVE}, - {"execute", EXECUTE}, - {"exists", EXISTS}, - {"explain", EXPLAIN}, - {"external", EXTERNAL}, - {"extract", EXTRACT}, - {"false", FALSE_P}, - {"family", FAMILY}, - {"fetch", FETCH}, - {"first", FIRST_P}, - {"float", FLOAT_P}, - {"for", FOR}, - {"force", FORCE}, - {"foreign", FOREIGN}, - {"forward", FORWARD}, - {"freeze", FREEZE}, - {"from", FROM}, - {"full", FULL}, - {"function", FUNCTION}, - {"get", GET}, - {"global", GLOBAL}, - {"grant", GRANT}, - {"granted", GRANTED}, - {"greatest", GREATEST}, - {"group", GROUP_P}, - {"handler", HANDLER}, - {"having", HAVING}, - {"header", HEADER_P}, - {"hold", HOLD}, - {"hour", HOUR_P}, - {"if", IF_P}, - {"ilike", ILIKE}, - {"immediate", IMMEDIATE}, - {"immutable", IMMUTABLE}, - {"implicit", IMPLICIT_P}, - {"in", IN_P}, - {"including", INCLUDING}, - {"increment", INCREMENT}, - {"index", INDEX}, - {"indexes", INDEXES}, - {"inherit", INHERIT}, - {"inherits", INHERITS}, - {"initially", INITIALLY}, - {"inner", INNER_P}, - {"inout", INOUT}, - {"input", INPUT_P}, - {"insensitive", INSENSITIVE}, - {"insert", INSERT}, - {"instead", INSTEAD}, - {"int", INT_P}, - {"integer", INTEGER}, - {"intersect", INTERSECT}, - {"interval", INTERVAL}, - {"into", INTO}, - {"invoker", INVOKER}, - {"is", IS}, - {"isnull", ISNULL}, - {"isolation", ISOLATION}, - {"join", JOIN}, - {"key", KEY}, - {"lancompiler", LANCOMPILER}, - {"language", LANGUAGE}, - {"large", LARGE_P}, - {"last", LAST_P}, - {"leading", LEADING}, - {"least", LEAST}, - {"left", LEFT}, - {"level", LEVEL}, - {"like", LIKE}, - {"limit", LIMIT}, - {"listen", LISTEN}, - {"load", LOAD}, - {"local", LOCAL}, - {"location", LOCATION}, - {"lock", LOCK_P}, - {"login", LOGIN_P}, - {"mapping", MAPPING}, - {"match", MATCH}, - {"maxvalue", MAXVALUE}, - {"minute", MINUTE_P}, - {"minvalue", MINVALUE}, - {"mode", MODE}, - {"month", MONTH_P}, - {"move", MOVE}, - {"name", NAME_P}, - {"names", NAMES}, - {"national", NATIONAL}, - {"natural", NATURAL}, - {"nchar", NCHAR}, - {"new", NEW}, - {"next", NEXT}, - {"no", NO}, - {"nocreatedb", NOCREATEDB}, - {"nocreaterole", NOCREATEROLE}, - {"nocreateuser", NOCREATEUSER}, - {"noinherit", NOINHERIT}, - {"nologin", NOLOGIN_P}, - {"none", NONE}, - {"nosuperuser", NOSUPERUSER}, - {"not", NOT}, - {"nothing", NOTHING}, - {"notify", NOTIFY}, - {"notnull", NOTNULL}, - {"nowait", NOWAIT}, - {"null", NULL_P}, - {"nullif", NULLIF}, - {"nulls", NULLS_P}, - {"numeric", NUMERIC}, - {"object", OBJECT_P}, - {"of", OF}, - {"off", OFF}, - {"offset", OFFSET}, - {"oids", OIDS}, - {"old", OLD}, - {"on", ON}, - {"only", ONLY}, - {"operator", OPERATOR}, - {"option", OPTION}, - {"or", OR}, - {"order", ORDER}, - {"out", OUT_P}, - {"outer", OUTER_P}, - {"overlaps", OVERLAPS}, - {"owned", OWNED}, - {"owner", OWNER}, - {"parser", PARSER}, - {"partial", PARTIAL}, - {"password", PASSWORD}, - {"placing", PLACING}, - {"plans", PLANS}, - {"position", POSITION}, - {"precision", PRECISION}, - {"prepare", PREPARE}, - {"prepared", PREPARED}, - {"preserve", PRESERVE}, - {"primary", PRIMARY}, - {"prior", PRIOR}, - {"privileges", PRIVILEGES}, - {"procedural", PROCEDURAL}, - {"procedure", PROCEDURE}, - {"quote", QUOTE}, - {"read", READ}, - {"real", REAL}, - {"reassign", REASSIGN}, - {"recheck", RECHECK}, - {"references", REFERENCES}, - {"reindex", REINDEX}, - {"relative", RELATIVE_P}, - {"release", RELEASE}, - {"rename", RENAME}, - {"repeatable", REPEATABLE}, - {"replace", REPLACE}, - {"replica", REPLICA}, - {"reset", RESET}, - {"restart", RESTART}, - {"restrict", RESTRICT}, - {"returning", RETURNING}, - {"returns", RETURNS}, - {"revoke", REVOKE}, - {"right", RIGHT}, - {"role", ROLE}, - {"rollback", ROLLBACK}, - {"row", ROW}, - {"rows", ROWS}, - {"rule", RULE}, - {"savepoint", SAVEPOINT}, - {"schema", SCHEMA}, - {"scroll", SCROLL}, - {"search", SEARCH}, - {"second", SECOND_P}, - {"security", SECURITY}, - {"select", SELECT}, - {"sequence", SEQUENCE}, - {"serializable", SERIALIZABLE}, - {"session", SESSION}, - {"session_user", SESSION_USER}, - {"set", SET}, - {"setof", SETOF}, - {"share", SHARE}, - {"show", SHOW}, - {"similar", SIMILAR}, - {"simple", SIMPLE}, - {"smallint", SMALLINT}, - {"some", SOME}, - {"stable", STABLE}, - {"standalone", STANDALONE_P}, - {"start", START}, - {"statement", STATEMENT}, - {"statistics", STATISTICS}, - {"stdin", STDIN}, - {"stdout", STDOUT}, - {"storage", STORAGE}, - {"strict", STRICT_P}, - {"strip", STRIP_P}, - {"substring", SUBSTRING}, - {"superuser", SUPERUSER_P}, - {"symmetric", SYMMETRIC}, - {"sysid", SYSID}, - {"system", SYSTEM_P}, - {"table", TABLE}, - {"tablespace", TABLESPACE}, - {"temp", TEMP}, - {"template", TEMPLATE}, - {"temporary", TEMPORARY}, - {"text", TEXT_P}, - {"then", THEN}, - {"time", TIME}, - {"timestamp", TIMESTAMP}, - {"to", TO}, - {"trailing", TRAILING}, - {"transaction", TRANSACTION}, - {"treat", TREAT}, - {"trigger", TRIGGER}, - {"trim", TRIM}, - {"true", TRUE_P}, - {"truncate", TRUNCATE}, - {"trusted", TRUSTED}, - {"type", TYPE_P}, - {"uncommitted", UNCOMMITTED}, - {"unencrypted", UNENCRYPTED}, - {"union", UNION}, - {"unique", UNIQUE}, - {"unknown", UNKNOWN}, - {"unlisten", UNLISTEN}, - {"until", UNTIL}, - {"update", UPDATE}, - {"user", USER}, - {"using", USING}, - {"vacuum", VACUUM}, - {"valid", VALID}, - {"validator", VALIDATOR}, - {"value", VALUE_P}, - {"values", VALUES}, - {"varchar", VARCHAR}, - {"varying", VARYING}, - {"verbose", VERBOSE}, - {"version", VERSION_P}, - {"view", VIEW}, - {"volatile", VOLATILE}, - {"when", WHEN}, - {"where", WHERE}, - {"whitespace", WHITESPACE_P}, - {"with", WITH}, - {"without", WITHOUT}, - {"work", WORK}, - {"write", WRITE}, - {"xml", XML_P}, - {"xmlattributes", XMLATTRIBUTES}, - {"xmlconcat", XMLCONCAT}, - {"xmlelement", XMLELEMENT}, - {"xmlforest", XMLFOREST}, - {"xmlparse", XMLPARSE}, - {"xmlpi", XMLPI}, - {"xmlroot", XMLROOT}, - {"xmlserialize", XMLSERIALIZE}, - {"year", YEAR_P}, - {"yes", YES_P}, - {"zone", ZONE}, -}; - - -/* - * Now do a binary search using plain strcmp() comparison. - */ -const ScanKeyword * -DoLookup(char *word, const ScanKeyword *low, const ScanKeyword *high) -{ - while (low <= high) - { - const ScanKeyword *middle; - int difference; - - middle = low + (high - low) / 2; - difference = strcmp(middle->name, word); - if (difference == 0) - return middle; - else if (difference < 0) - low = middle + 1; - else - high = middle - 1; - } - - return NULL; -} - -/* - * ScanKeywordLookup - see if a given word is a keyword - * - * Returns a pointer to the ScanKeyword table entry, or NULL if no match. - * - * The match is done case-insensitively. Note that we deliberately use a - * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z', - * even if we are in a locale where tolower() would produce more or different - * translations. This is to conform to the SQL99 spec, which says that - * keywords are to be matched in this way even though non-keyword identifiers - * receive a different case-normalization mapping. - */ -const ScanKeyword * -ScanKeywordLookup(char *text) -{ - int len, - i; - char word[NAMEDATALEN]; - const ScanKeyword *res; - - len = strlen(text); - /* We assume all keywords are shorter than NAMEDATALEN. */ - if (len >= NAMEDATALEN) - return NULL; - - /* - * Apply an ASCII-only downcasing. We must not use tolower() since it may - * produce the wrong translation in some locales (eg, Turkish). - */ - for (i = 0; i < len; i++) - { - char ch = text[i]; - - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; - word[i] = ch; - } - word[len] = '\0'; - - /* - * Now do a binary search using plain strcmp() comparison. - */ - res = DoLookup(word, &ScanPGSQLKeywords[0], endof(ScanPGSQLKeywords) - 1); - if (res) - return res; - - return DoLookup(word, &ScanECPGKeywords[0], endof(ScanECPGKeywords) - 1); -} diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index be6f7b0d14..a08eb8e203 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.165 2008/05/16 15:20:04 petere Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.166 2008/05/20 23:17:32 meskes Exp $ * *------------------------------------------------------------------------- */ @@ -680,7 +680,7 @@ cppline {space}*#(.*\\{space})*.*{newline} if (!isdefine()) { /* Is it an SQL/ECPG keyword? */ - keyword = ScanKeywordLookup(yytext); + keyword = ScanECPGKeywordLookup(yytext); if (keyword != NULL) return keyword->value; diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 49acea7640..3d39b74580 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.365 2008/05/16 15:20:04 petere Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.366 2008/05/20 23:17:32 meskes Exp $ */ /* Copyright comment */ %{ @@ -392,11 +392,11 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu /* special embedded SQL token */ %token SQL_ALLOCATE SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK SQL_CALL SQL_CARDINALITY SQL_CONNECT - SQL_CONTINUE SQL_COUNT SQL_DATA + SQL_COUNT SQL_DATA SQL_DATETIME_INTERVAL_CODE SQL_DATETIME_INTERVAL_PRECISION SQL_DESCRIBE SQL_DESCRIPTOR SQL_DISCONNECT SQL_FOUND - SQL_FREE SQL_GO SQL_GOTO SQL_IDENTIFIED + SQL_FREE SQL_GET SQL_GO SQL_GOTO SQL_IDENTIFIED SQL_INDICATOR SQL_KEY_MEMBER SQL_LENGTH SQL_LONG SQL_NULLABLE SQL_OCTET_LENGTH SQL_OPEN SQL_OUTPUT SQL_REFERENCE @@ -427,7 +427,7 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS - CONTENT_P CONVERSION_P COPY COST CREATE CREATEDB + CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE @@ -441,14 +441,14 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD FREEZE FROM FULL FUNCTION - GET GLOBAL GRANT GRANTED GREATEST GROUP_P + GLOBAL GRANT GRANTED GREATEST GROUP_P HANDLER HAVING HEADER_P HOLD HOUR_P - IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT - INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P - INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT - INTERVAL INTO INVOKER IS ISNULL ISOLATION + IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P + INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY + INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER + INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION JOIN @@ -555,7 +555,7 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu %type ConstraintElem key_actions ColQualList cluster_index_specification %type target_list target_el alias_clause type_func_name_keyword %type qualified_name database_name alter_using type_function_name -%type access_method attr_name index_name name func_name +%type access_method attr_name index_name name func_name opt_restart_seqs %type file_name AexprConst c_expr ConstTypename var_list %type a_expr b_expr TruncateStmt CommentStmt OnCommitOption opt_by %type opt_indirection expr_list extract_list extract_arg @@ -1862,6 +1862,8 @@ OptSeqElem: CACHE NumConst { $$ = cat2_str(make_str("owned by"), $3); } | START opt_with NumConst { $$ = cat_str(3, make_str("start"), $2, $3); } + | RESTART + { $$ = make_str("restart"); } | RESTART opt_with NumConst { $$ = cat_str(3, make_str("restart"), $2, $3); } ; @@ -2179,7 +2181,10 @@ opt_opfamily: FAMILY any_name { $$ = cat2_str(make_str("family"), $2); } | /*EMPTY*/ { $$ = EMPTY; } ; -opt_recheck: RECHECK { $$ = make_str("recheck"); } +opt_recheck: RECHECK { + mmerror(PARSE_ERROR, ET_WARNING, "no longer supported RECHECK OPTION will be passed to backend"); + $$ = make_str("recheck"); + } | /*EMPTY*/ { $$ = EMPTY; } ; @@ -2282,10 +2287,16 @@ attrs: '.' attr_name { $$ = cat2_str(make_str("."), $2); } * truncate table relname1, relname2, .... * *****************************************************************************/ -TruncateStmt: TRUNCATE opt_table qualified_name_list opt_drop_behavior - { $$ = cat_str(4, make_str("truncate table"), $2, $3, $4); } +TruncateStmt: TRUNCATE opt_table qualified_name_list opt_restart_seqs opt_drop_behavior + { $$ = cat_str(5, make_str("truncate table"), $2, $3, $4, $5); } ; +opt_restart_seqs: + CONTINUE_P IDENTITY_P { $$ = cat2_str(make_str("continue"), make_str("identity")); } + | RESTART IDENTITY_P { $$ = cat2_str(make_str("restart"), make_str("identity")); } + | /* EMPTY */ { $$ = EMPTY; } + ; + /***************************************************************************** * * QUERY: @@ -2852,6 +2863,8 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name { $$ = cat_str(4, make_str("alter text search template"), $5, make_str("rename to"), $8); } | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("rename to"), $8); } + | ALTER TYPE_P any_name RENAME TO name + { $$ = cat_str(4, make_str("alter type"), $3, make_str("rename to"), $6); } ; opt_column: COLUMN { $$ = make_str("column"); } @@ -2960,6 +2973,7 @@ event: SELECT { $$ = make_str("select"); } | UPDATE { $$ = make_str("update"); } | DELETE_P { $$ = make_str("delete"); } | INSERT { $$ = make_str("insert"); } + | TRUNCATE { $$ = make_str("truncate"); } ; opt_instead: INSTEAD { $$ = make_str("instead"); } @@ -4538,29 +4552,26 @@ expr_list: a_expr { $$ = cat_str(3, $1, make_str(","), $3); } ; -extract_list: extract_arg FROM a_expr - { $$ = cat_str(3, $1, make_str("from"), $3); } - | /* EMPTY */ - { $$ = EMPTY; } - ; - type_list: Typename { $$ = $1; } | type_list ',' Typename { $$ = cat_str(3, $1, ',', $3); } ; +array_expr: '[' expr_list ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } + | '[' array_expr_list ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } + | '[' ']' { $$ = make_str("[]"); } + ; + array_expr_list: array_expr { $$ = $1; } | array_expr_list ',' array_expr { $$ = cat_str(3, $1, make_str(","), $3); } ; - -array_expr: '[' expr_list ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } - | '[' array_expr_list ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } +extract_list: extract_arg FROM a_expr + { $$ = cat_str(3, $1, make_str("from"), $3); } + | /* EMPTY */ + { $$ = EMPTY; } ; -/* Allow delimited string SCONST in extract_arg as an SQL extension. - * - thomas 2001-04-12 - */ extract_arg: ident { $$ = $1; } | YEAR_P { $$ = make_str("year"); } @@ -4703,6 +4714,14 @@ target_list: target_list ',' target_el target_el: a_expr AS ColLabel { $$ = cat_str(3, $1, make_str("as"), $3); } + /* + * We support omitting AS only for column labels that aren't + * any known keyword. There is an ambiguity against postfix + * operators: is "a ! b" an infix expression, or a postfix + * expression and a column label? We prefer to resolve this + * as an infix expression, which we accomplish by assigning + * IDENT a precedence higher than POSTFIXOP. + */ | a_expr IDENT { $$ = cat_str(3, $1, make_str("as"), $2); } | a_expr @@ -5999,7 +6018,7 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar * manipulate a descriptor header */ -ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems +ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems { $$ = $3; } ; @@ -6034,7 +6053,7 @@ desc_header_item: SQL_COUNT { $$ = ECPGd_count; } * manipulate a descriptor */ -ECPGGetDescriptor: GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems +ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems { $$.str = $5; $$.name = $3; } ; @@ -6214,7 +6233,7 @@ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action } ; -action : SQL_CONTINUE +action : CONTINUE_P { $$.code = W_NOTHING; $$.command = NULL; @@ -6280,7 +6299,6 @@ ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } ECPGKeywords_vanames: SQL_BREAK { $$ = make_str("break"); } | SQL_CALL { $$ = make_str("call"); } | SQL_CARDINALITY { $$ = make_str("cardinality"); } - | SQL_CONTINUE { $$ = make_str("continue"); } | SQL_COUNT { $$ = make_str("count"); } | SQL_DATA { $$ = make_str("data"); } | SQL_DATETIME_INTERVAL_CODE { $$ = make_str("datetime_interval_code"); } @@ -6467,6 +6485,7 @@ ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); } /* | CONNECTION { $$ = make_str("connection"); }*/ | CONSTRAINTS { $$ = make_str("constraints"); } | CONTENT_P { $$ = make_str("content"); } + | CONTINUE_P { $$ = make_str("continue"); } | CONVERSION_P { $$ = make_str("conversion"); } | COPY { $$ = make_str("copy"); } | COST { $$ = make_str("cost"); } @@ -6515,6 +6534,7 @@ ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); } | HEADER_P { $$ = make_str("header"); } | HOLD { $$ = make_str("hold"); } /* | HOUR_P { $$ = make_str("hour"); }*/ + | IDENTITY_P { $$ = make_str("identity"); } | IF_P { $$ = make_str("if"); } | IMMEDIATE { $$ = make_str("immediate"); } | IMMUTABLE { $$ = make_str("immutable"); } diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h index 89195077ba..28cbbe62d7 100644 --- a/src/interfaces/ecpg/preproc/type.h +++ b/src/interfaces/ecpg/preproc/type.h @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/type.h,v 1.49 2008/05/17 01:28:25 adunstan Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/type.h,v 1.50 2008/05/20 23:17:32 meskes Exp $ */ #ifndef _ECPG_PREPROC_TYPE_H #define _ECPG_PREPROC_TYPE_H @@ -190,10 +190,4 @@ struct fetch_desc char *name; }; -typedef struct ScanKeyword -{ - char *name; - int value; -} ScanKeyword; - #endif /* _ECPG_PREPROC_TYPE_H */ diff --git a/src/interfaces/ecpg/test/expected/connect-test1.stderr b/src/interfaces/ecpg/test/expected/connect-test1.stderr index 30ebfac607..3737d5c681 100644 --- a/src/interfaces/ecpg/test/expected/connect-test1.stderr +++ b/src/interfaces/ecpg/test/expected/connect-test1.stderr @@ -2,68 +2,68 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on port [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute line 23: QUERY: alter user connectuser encrypted password 'connectpw' with 0 parameter on connection main +[NO_PID]: ecpg_execute on line 23: query: alter user connectuser encrypted password 'connectpw'; with 0 parameter(s) on connection main [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute line 23: using PQexec +[NO_PID]: ecpg_execute on line 23: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute line 23 Ok: ALTER ROLE +[NO_PID]: ecpg_execute on line 23: OK: ALTER ROLE [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on localhost port [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user connectdb [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on localhost port [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user connectdb [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on port [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on port for user connectdb [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection main closed. +[NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on localhost port for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection connectdb closed. +[NO_PID]: ecpg_finish: connection connectdb closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user connectdb [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection (null) closed. +[NO_PID]: ecpg_finish: connection (null) closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on localhost port for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection connectdb closed. +[NO_PID]: ecpg_finish: connection connectdb closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on port for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection connectdb closed. +[NO_PID]: ecpg_finish: connection connectdb closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database connectdb on port with options connect_timeout=14 for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection connectdb closed. +[NO_PID]: ecpg_finish: connection connectdb closed [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database nonexistant on localhost port for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: could not open database: FATAL: database "nonexistant" does not exist [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection nonexistant closed. +[NO_PID]: ecpg_finish: connection nonexistant closed [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: raising sqlcode -402 in line 62, 'Could not connect to database nonexistant in line 62.'. +[NO_PID]: raising sqlcode -402 on line 62: could not connect to database "nonexistant" on line 62 [NO_PID]: sqlca: code: -402, state: 08001 -[NO_PID]: raising sqlcode -220 in line 63, 'No such connection CURRENT in line 63.'. +[NO_PID]: raising sqlcode -220 on line 63: no such connection CURRENT on line 63 [NO_PID]: sqlca: code: -220, state: 08003 [NO_PID]: ECPGconnect: opening database connectdb on localhost port for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 @@ -72,9 +72,9 @@ TCP/IP connections on port 20? [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_finish: Connection connectdb closed. +[NO_PID]: ecpg_finish: connection connectdb closed [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: raising sqlcode -402 in line 66, 'Could not connect to database connectdb in line 66.'. +[NO_PID]: raising sqlcode -402 on line 66: could not connect to database "connectdb" on line 66 [NO_PID]: sqlca: code: -402, state: 08001 [NO_PID]: ECPGconnect: opening database connectdb on port for user connectuser [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/expected/preproc-whenever.c b/src/interfaces/ecpg/test/expected/preproc-whenever.c index c345920537..9f15b7708b 100644 --- a/src/interfaces/ecpg/test/expected/preproc-whenever.c +++ b/src/interfaces/ecpg/test/expected/preproc-whenever.c @@ -220,25 +220,27 @@ if (sqlca.sqlcode < 0) goto error;} /* exec sql whenever sqlerror stop ; */ #line 61 "whenever.pgc" - { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select * from nonexistant ", ECPGt_EOIT, + /* This cannot fail, thus we don't get an exit value not equal 0. */ + /* However, it still test the precompiler output. */ + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select 1 ", ECPGt_EOIT, ECPGt_int,&(i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); -#line 62 "whenever.pgc" +#line 64 "whenever.pgc" if (sqlca.sqlwarn[0] == 'W') warn ( ); -#line 62 "whenever.pgc" +#line 64 "whenever.pgc" if (sqlca.sqlcode < 0) exit (1);} -#line 62 "whenever.pgc" +#line 64 "whenever.pgc" { ECPGtrans(__LINE__, NULL, "rollback"); -#line 63 "whenever.pgc" +#line 65 "whenever.pgc" if (sqlca.sqlwarn[0] == 'W') warn ( ); -#line 63 "whenever.pgc" +#line 65 "whenever.pgc" if (sqlca.sqlcode < 0) exit (1);} -#line 63 "whenever.pgc" +#line 65 "whenever.pgc" exit (0); } diff --git a/src/interfaces/ecpg/test/expected/preproc-whenever.stderr b/src/interfaces/ecpg/test/expected/preproc-whenever.stderr index 519cd8f684..207e5fa766 100644 --- a/src/interfaces/ecpg/test/expected/preproc-whenever.stderr +++ b/src/interfaces/ecpg/test/expected/preproc-whenever.stderr @@ -82,11 +82,13 @@ sql error: relation "nonexistant" does not exist on line 47 [NO_PID]: sqlca: code: -400, state: 42P01 [NO_PID]: ECPGtrans on line 59: action "rollback"; connection "regress1" [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 62: query: select * from nonexistant ; with 0 parameter(s) on connection regress1 +[NO_PID]: ecpg_execute on line 64: query: select 1 ; with 0 parameter(s) on connection regress1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 62: using PQexec +[NO_PID]: ecpg_execute on line 64: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_check_PQresult on line 62: ERROR: relation "nonexistant" does not exist +[NO_PID]: ecpg_execute on line 64: correctly got 1 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 64: RESULT: 1 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGtrans on line 65: action "rollback"; connection "regress1" [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: raising sqlstate 42P01 (sqlcode -400) on line 62: relation "nonexistant" does not exist on line 62 -[NO_PID]: sqlca: code: -400, state: 42P01 diff --git a/src/interfaces/ecpg/test/preproc/whenever.pgc b/src/interfaces/ecpg/test/preproc/whenever.pgc index ad56327804..bba78ee023 100644 --- a/src/interfaces/ecpg/test/preproc/whenever.pgc +++ b/src/interfaces/ecpg/test/preproc/whenever.pgc @@ -59,7 +59,9 @@ int main(void) exec sql rollback; exec sql whenever sqlerror stop; - exec sql select * into :i from nonexistant; + /* This cannot fail, thus we don't get an exit value not equal 0. */ + /* However, it still test the precompiler output. */ + exec sql select 1 into :i; exec sql rollback; exit (0); }