提交 f7563e97 编写于 作者: M Michael Meskes

Synced parser.

Made ecpg parser use backend provided keyword list.
Changed whenever test so exit value is 0.
上级 1ac1bea0
......@@ -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.
......
......@@ -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
......
......@@ -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);
}
......@@ -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 <ctype.h>
#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);
}
/* $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 <errno.h>
#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);
......
/*-------------------------------------------------------------------------
*
* 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 <ctype.h>
#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);
}
......@@ -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;
......
/* $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 <str> ConstraintElem key_actions ColQualList cluster_index_specification
%type <str> target_list target_el alias_clause type_func_name_keyword
%type <str> qualified_name database_name alter_using type_function_name
%type <str> access_method attr_name index_name name func_name
%type <str> access_method attr_name index_name name func_name opt_restart_seqs
%type <str> file_name AexprConst c_expr ConstTypename var_list
%type <str> a_expr b_expr TruncateStmt CommentStmt OnCommitOption opt_by
%type <str> 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
{
$<action>$.code = W_NOTHING;
$<action>$.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"); }
......
/*
* $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 */
......@@ -2,68 +2,68 @@
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ECPGconnect: opening database connectdb on <DEFAULT> port <DEFAULT>
[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 <DEFAULT>
[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 <DEFAULT> on localhost port <DEFAULT> 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 <REGRESSION_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 <DEFAULT> on localhost port <REGRESSION_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 <DEFAULT> port <REGRESSION_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 <DEFAULT> on <DEFAULT> port <REGRESSION_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 <REGRESSION_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 <DEFAULT> on localhost port <REGRESSION_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 <REGRESSION_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 <DEFAULT> port <REGRESSION_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 <DEFAULT> port <REGRESSION_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 <REGRESSION_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 <REGRESSION_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 <DEFAULT> port <REGRESSION_PORT> for user connectuser
[NO_PID]: sqlca: code: 0, state: 00000
......@@ -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);
}
......@@ -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
......@@ -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);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册