Thursday, July 24, 2008

Re: [PATCHES] pg_dump additional options for performance

Index: doc/src/sgml/ref/pg_dump.sgml
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/doc/src/sgml/ref/pg_dump.sgml,v
retrieving revision 1.103
diff -c -r1.103 pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml 20 Jul 2008 18:43:30 -0000 1.103
--- doc/src/sgml/ref/pg_dump.sgml 24 Jul 2008 07:30:19 -0000
***************
*** 133,139 ****
<para>
Include large objects in the dump. This is the default behavior
except when <option>--schema</>, <option>--table</>, or
! <option>--schema-only</> is specified, so the <option>-b</>
switch is only useful to add large objects to selective dumps.
</para>
</listitem>
--- 133,140 ----
<para>
Include large objects in the dump. This is the default behavior
except when <option>--schema</>, <option>--table</>, or
! <option>--schema-only</> or <option>--schema-before-data</> or
! <option>--schema-after-data</> is specified, so the <option>-b</>
switch is only useful to add large objects to selective dumps.
</para>
</listitem>
***************
*** 426,431 ****
--- 427,452 ----
</varlistentry>

<varlistentry>
+ <term><option>--schema-before-data</option></term>
+ <listitem>
+ <para>
+ Dump object definitions (schema) that occur before table data,
+ using the order produced by a full dump.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--schema-after-data</option></term>
+ <listitem>
+ <para>
+ Dump object definitions (schema) that occur after table data,
+ using the order produced by a full dump.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-S <replaceable class="parameter">username</replaceable></option></term>
<term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term>
<listitem>
***************
*** 790,795 ****
--- 811,844 ----
</para>

<para>
+ The output of <application>pg_dump</application> can be divided into three parts:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Before Data - objects output before data, which includes
+ <command>CREATE TABLE</command> statements and others.
+ This part can be requested using <option>--schema-before-data</>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Table Data - data can be requested using <option>--data-only</>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After Data - objects output after data, which includes
+ <command>CREATE INDEX</command> statements and others.
+ This part can be requested using <option>--schema-after-data</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ This allows us to work more easily with large data dump files when
+ there is some need to edit commands or resequence their execution for
+ performance.
+ </para>
+
+ <para>
Because <application>pg_dump</application> is used to transfer data
to newer versions of <productname>PostgreSQL</>, the output of
<application>pg_dump</application> can be loaded into
Index: doc/src/sgml/ref/pg_restore.sgml
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/doc/src/sgml/ref/pg_restore.sgml,v
retrieving revision 1.75
diff -c -r1.75 pg_restore.sgml
*** doc/src/sgml/ref/pg_restore.sgml 13 Apr 2008 03:49:21 -0000 1.75
--- doc/src/sgml/ref/pg_restore.sgml 24 Jul 2008 07:30:19 -0000
***************
*** 321,326 ****
--- 321,346 ----
</varlistentry>

<varlistentry>
+ <term><option>--schema-before-data</option></term>
+ <listitem>
+ <para>
+ Restore object definitions (schema) that occur before table data,
+ using the order produced by a full restore.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--schema-after-data</option></term>
+ <listitem>
+ <para>
+ Restore object definitions (schema) that occur after table data,
+ using the order produced by a full restore.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-S <replaceable class="parameter">username</replaceable></option></term>
<term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term>
<listitem>
***************
*** 572,577 ****
--- 592,626 ----
</para>

<para>
+ The actions of <application>pg_restore</application> can be
+ divided into three parts:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Before Data - objects output before data, which includes
+ <command>CREATE TABLE</command> statements and others.
+ This part can be requested using <option>--schema-before-data</>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Table Data - data can be requested using <option>--data-only</>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After Data - objects output after data, which includes
+ <command>CREATE INDEX</command> statements and others.
+ This part can be requested using <option>--schema-after-data</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ This allows us to work more easily with large data dump files when
+ there is some need to edit commands or resequence their execution for
+ performance.
+ </para>
+
+ <para>
The limitations of <application>pg_restore</application> are detailed below.

<itemizedlist>
Index: src/bin/pg_dump/pg_backup.h
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_backup.h,v
retrieving revision 1.47
diff -c -r1.47 pg_backup.h
*** src/bin/pg_dump/pg_backup.h 13 Apr 2008 03:49:21 -0000 1.47
--- src/bin/pg_dump/pg_backup.h 24 Jul 2008 07:30:19 -0000
***************
*** 89,95 ****
int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands
* instead of OWNER TO */
char *superuser; /* Username to use as superuser */
! int dataOnly;
int dropSchema;
char *filename;
int schemaOnly;
--- 89,95 ----
int use_setsessauth;/* Use SET SESSION AUTHORIZATION commands
* instead of OWNER TO */
char *superuser; /* Username to use as superuser */
! int dumpObjFlags; /* which objects types to dump */
int dropSchema;
char *filename;
int schemaOnly;
Index: src/bin/pg_dump/pg_backup_archiver.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v
retrieving revision 1.157
diff -c -r1.157 pg_backup_archiver.c
*** src/bin/pg_dump/pg_backup_archiver.c 4 May 2008 08:32:21 -0000 1.157
--- src/bin/pg_dump/pg_backup_archiver.c 24 Jul 2008 07:30:19 -0000
***************
*** 56,62 ****
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
! static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls);
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
--- 56,62 ----
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
! static int _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls);
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
***************
*** 129,135 ****
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
TocEntry *te;
! teReqs reqs;
OutputContext sav;
bool defnDumped;

--- 129,135 ----
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
TocEntry *te;
! int reqs;
OutputContext sav;
bool defnDumped;

***************
*** 175,193 ****
* Work out if we have an implied data-only restore. This can happen if
* the dump was data only or if the user has used a toc list to exclude
* all of the schema data. All we do is look for schema entries - if none
! * are found then we set the dataOnly flag.
*
! * We could scan for wanted TABLE entries, but that is not the same as
! * dataOnly. At this stage, it seems unnecessary (6-Mar-2001).
*/
! if (!ropt->dataOnly)
{
int impliedDataOnly = 1;

for (te = AH->toc->next; te != AH->toc; te = te->next)
{
reqs = _tocEntryRequired(te, ropt, true);
! if ((reqs & REQ_SCHEMA) != 0)
{ /* It's schema, and it's wanted */
impliedDataOnly = 0;
break;
--- 175,193 ----
* Work out if we have an implied data-only restore. This can happen if
* the dump was data only or if the user has used a toc list to exclude
* all of the schema data. All we do is look for schema entries - if none
! * are found then say we only want DATA type objects.
*
! * We could scan for wanted TABLE entries, but that is not the same.
! * At this stage, it seems unnecessary (6-Mar-2001).
*/
! if (!WANT_DATA(ropt->dumpObjFlags))
{
int impliedDataOnly = 1;

for (te = AH->toc->next; te != AH->toc; te = te->next)
{
reqs = _tocEntryRequired(te, ropt, true);
! if (WANT_SCHEMA_BEFORE_DATA(reqs) || WANT_SCHEMA_AFTER_DATA(reqs))
{ /* It's schema, and it's wanted */
impliedDataOnly = 0;
break;
***************
*** 195,201 ****
}
if (impliedDataOnly)
{
! ropt->dataOnly = impliedDataOnly;
ahlog(AH, 1, "implied data-only restore\n");
}
}
--- 195,201 ----
}
if (impliedDataOnly)
{
! ropt->dumpObjFlags = REQ_DATA;
ahlog(AH, 1, "implied data-only restore\n");
}
}
***************
*** 236,242 ****
AH->currentTE = te;

reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */ );
! if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
{
/* We want the schema */
ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
--- 236,242 ----
AH->currentTE = te;

reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */ );
! if (((reqs & REQ_SCHEMA_BEFORE_DATA) != 0) && te->dropStmt)
{
/* We want the schema */
ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
***************
*** 278,284 ****
/* Dump any relevant dump warnings to stderr */
if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
{
! if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
write_msg(modulename, "warning from original dump file: %s\n", te->defn);
else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0)
write_msg(modulename, "warning from original dump file: %s\n", te->copyStmt);
--- 278,284 ----
/* Dump any relevant dump warnings to stderr */
if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
{
! if (!WANT_DATA(ropt->dumpObjFlags) && te->defn != NULL && strlen(te->defn) != 0)
write_msg(modulename, "warning from original dump file: %s\n", te->defn);
else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0)
write_msg(modulename, "warning from original dump file: %s\n", te->copyStmt);
***************
*** 286,292 ****

defnDumped = false;

! if ((reqs & REQ_SCHEMA) != 0) /* We want the schema */
{
ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);

--- 286,293 ----

defnDumped = false;

! if ((WANT_SCHEMA_BEFORE_DATA(reqs) && WANT_SCHEMA_BEFORE_DATA(ropt->dumpObjFlags)) ||
! (WANT_SCHEMA_AFTER_DATA(reqs) && WANT_SCHEMA_AFTER_DATA(ropt->dumpObjFlags))) /* We want the schema */
{
ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);

***************
*** 331,337 ****
/*
* If we have a data component, then process it
*/
! if ((reqs & REQ_DATA) != 0)
{
/*
* hadDumper will be set if there is genuine data component for
--- 332,338 ----
/*
* If we have a data component, then process it
*/
! if (WANT_DATA(reqs))
{
/*
* hadDumper will be set if there is genuine data component for
***************
*** 343,349 ****
/*
* If we can output the data, then restore it.
*/
! if (AH->PrintTocDataPtr !=NULL && (reqs & REQ_DATA) != 0)
{
#ifndef HAVE_LIBZ
if (AH->compression != 0)
--- 344,350 ----
/*
* If we can output the data, then restore it.
*/
! if (AH->PrintTocDataPtr !=NULL && WANT_DATA(reqs))
{
#ifndef HAVE_LIBZ
if (AH->compression != 0)
***************
*** 415,421 ****
/* Work out what, if anything, we want from this entry */
reqs = _tocEntryRequired(te, ropt, true);

! if ((reqs & REQ_SCHEMA) != 0) /* We want the schema */
{
ahlog(AH, 1, "setting owner and privileges for %s %s\n",
te->desc, te->tag);
--- 416,422 ----
/* Work out what, if anything, we want from this entry */
reqs = _tocEntryRequired(te, ropt, true);

! if (WANT_SCHEMA_BEFORE_DATA(reqs)) /* We want the schema */
{
ahlog(AH, 1, "setting owner and privileges for %s %s\n",
te->desc, te->tag);
***************
*** 473,479 ****
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{
/* This hack is only needed in a data-only restore */
! if (!ropt->dataOnly || !ropt->disable_triggers)
return;

ahlog(AH, 1, "disabling triggers for %s\n", te->tag);
--- 474,480 ----
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{
/* This hack is only needed in a data-only restore */
! if (!WANT_DATA(ropt->dumpObjFlags) || !ropt->disable_triggers)
return;

ahlog(AH, 1, "disabling triggers for %s\n", te->tag);
***************
*** 499,505 ****
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{
/* This hack is only needed in a data-only restore */
! if (!ropt->dataOnly || !ropt->disable_triggers)
return;

ahlog(AH, 1, "enabling triggers for %s\n", te->tag);
--- 500,506 ----
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{
/* This hack is only needed in a data-only restore */
! if (!WANT_DATA(ropt->dumpObjFlags) || !ropt->disable_triggers)
return;

ahlog(AH, 1, "enabling triggers for %s\n", te->tag);
***************
*** 1321,1327 ****
return NULL;
}

! teReqs
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
{
TocEntry *te = getTocEntryByDumpId(AH, id);
--- 1322,1328 ----
return NULL;
}

! int
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
{
TocEntry *te = getTocEntryByDumpId(AH, id);
***************
*** 2026,2035 ****
te->defn);
}

! static teReqs
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
{
! teReqs res = REQ_ALL;

/* ENCODING and STDSTRINGS items are dumped specially, so always reject */
if (strcmp(te->desc, "ENCODING") == 0 ||
--- 2027,2036 ----
te->defn);
}

! static int
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
{
! int res = ropt->dumpObjFlags;

/* ENCODING and STDSTRINGS items are dumped specially, so always reject */
if (strcmp(te->desc, "ENCODING") == 0 ||
***************
*** 2109,2125 ****
if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
return 0;

- /* Mask it if we only want schema */
- if (ropt->schemaOnly)
- res = res & REQ_SCHEMA;
-
- /* Mask it we only want data */
- if (ropt->dataOnly)
- res = res & REQ_DATA;
-
/* Mask it if we don't have a schema contribution */
if (!te->defn || strlen(te->defn) == 0)
! res = res & ~REQ_SCHEMA;

/* Finally, if there's a per-ID filter, limit based on that as well */
if (ropt->idWanted && !ropt->idWanted[te->dumpId - 1])
--- 2110,2118 ----
if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
return 0;

/* Mask it if we don't have a schema contribution */
if (!te->defn || strlen(te->defn) == 0)
! res = res & ~(REQ_SCHEMA_BEFORE_DATA | REQ_SCHEMA_AFTER_DATA);

/* Finally, if there's a per-ID filter, limit based on that as well */
if (ropt->idWanted && !ropt->idWanted[te->dumpId - 1])
Index: src/bin/pg_dump/pg_backup_archiver.h
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v
retrieving revision 1.76
diff -c -r1.76 pg_backup_archiver.h
*** src/bin/pg_dump/pg_backup_archiver.h 7 Nov 2007 12:24:24 -0000 1.76
--- src/bin/pg_dump/pg_backup_archiver.h 24 Jul 2008 07:30:19 -0000
***************
*** 158,169 ****
STAGE_FINALIZING
} ArchiverStage;

! typedef enum
! {
! REQ_SCHEMA = 1,
! REQ_DATA = 2,
! REQ_ALL = REQ_SCHEMA + REQ_DATA
! } teReqs;

typedef struct _archiveHandle
{
--- 158,173 ----
STAGE_FINALIZING
} ArchiverStage;

! #define REQ_SCHEMA_BEFORE_DATA (1 << 0)
! #define REQ_DATA (1 << 1)
! #define REQ_SCHEMA_AFTER_DATA (1 << 2)
! #define REQ_ALL (REQ_SCHEMA_BEFORE_DATA + REQ_DATA + REQ_SCHEMA_AFTER_DATA)
!
! #define WANT_SCHEMA_BEFORE_DATA(req) ((req & REQ_SCHEMA_BEFORE_DATA) == REQ_SCHEMA_BEFORE_DATA)
! #define WANT_DATA(req) ((req & REQ_DATA) == REQ_DATA)
! #define WANT_SCHEMA_AFTER_DATA(req) ((req & REQ_SCHEMA_AFTER_DATA) == REQ_SCHEMA_AFTER_DATA)
! #define WANT_ALL(req) ((req & REQ_ALL) == REQ_ALL)
!

typedef struct _archiveHandle
{
***************
*** 317,323 ****
extern void ReadToc(ArchiveHandle *AH);
extern void WriteDataChunks(ArchiveHandle *AH);

! extern teReqs TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt);
extern bool checkSeek(FILE *fp);

#define appendStringLiteralAHX(buf,str,AH) \
--- 321,327 ----
extern void ReadToc(ArchiveHandle *AH);
extern void WriteDataChunks(ArchiveHandle *AH);

! extern int TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt);
extern bool checkSeek(FILE *fp);

#define appendStringLiteralAHX(buf,str,AH) \
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.497
diff -c -r1.497 pg_dump.c
*** src/bin/pg_dump/pg_dump.c 20 Jul 2008 18:43:30 -0000 1.497
--- src/bin/pg_dump/pg_dump.c 24 Jul 2008 07:35:28 -0000
***************
*** 73,78 ****
--- 73,82 ----
bool aclsSkip;
const char *lockWaitTimeout;

+ /* groups of objects: default is we dump all groups */
+
+ int dumpObjFlags;
+
/* subquery used to convert user ID (eg, datdba) to user name */
static const char *username_subquery;

***************
*** 227,232 ****
--- 231,238 ----
static int disable_triggers = 0;
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
+ static int schemaBeforeData;
+ static int schemaAfterData;

static struct option long_options[] = {
{"data-only", no_argument, NULL, 'a'},
***************
*** 267,272 ****
--- 273,280 ----
{"disable-triggers", no_argument, &disable_triggers, 1},
{"lock-wait-timeout", required_argument, NULL, 2},
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
+ {"schema-before-data", no_argument, &schemaBeforeData, 1},
+ {"schema-after-data", no_argument, &schemaAfterData, 1},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},

{NULL, 0, NULL, 0}
***************
*** 420,425 ****
--- 428,437 ----
disable_triggers = 1;
else if (strcmp(optarg, "no-tablespaces") == 0)
outputNoTablespaces = 1;
+ else if (strcmp(optarg, "schema-before-data") == 0)
+ schemaBeforeData = 1;
+ else if (strcmp(optarg, "schema-after-data") == 0)
+ schemaAfterData = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
else
***************
*** 464,474 ****
if (optind < argc)
dbname = argv[optind];

! if (dataOnly && schemaOnly)
{
! write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
exit(1);
}

if (dataOnly && outputClean)
{
--- 476,521 ----
if (optind < argc)
dbname = argv[optind];

! /*
! * Look for conflicting options relating to object groupings
! */
! if (schemaOnly && dataOnly)
! {
! write_msg(NULL, "options %s and %s cannot be used together\n",
! "-s/--schema-only", "-a/--data-only");
! exit(1);
! }
! else if ((schemaOnly || dataOnly) &&
! (schemaBeforeData || schemaAfterData))
{
! write_msg(NULL, "options %s and %s cannot be used together\n",
! schemaOnly ? "-s/--schema-only" : "-a/--data-only",
! schemaBeforeData ? "--schema-before-data" : "--schema-after-data");
exit(1);
}
+ else if (schemaBeforeData && schemaAfterData)
+ {
+ write_msg(NULL, "options %s and %s cannot be used together\n",
+ "--schema-before-data", "--schema-after-data");
+ exit(1);
+ }
+
+ /*
+ * Decide which of the object groups we will dump
+ */
+ dumpObjFlags = REQ_ALL;
+
+ if (dataOnly)
+ dumpObjFlags = REQ_DATA;
+
+ if (schemaBeforeData)
+ dumpObjFlags = REQ_SCHEMA_BEFORE_DATA;
+
+ if (schemaAfterData)
+ dumpObjFlags = REQ_SCHEMA_AFTER_DATA;
+
+ if (schemaOnly)
+ dumpObjFlags = (REQ_SCHEMA_BEFORE_DATA | REQ_SCHEMA_AFTER_DATA);

if (dataOnly && outputClean)
{
***************
*** 646,652 ****
* Dumping blobs is now default unless we saw an inclusion switch or -s
* ... but even if we did see one of these, -b turns it back on.
*/
! if (include_everything && !schemaOnly)
outputBlobs = true;

/*
--- 693,699 ----
* Dumping blobs is now default unless we saw an inclusion switch or -s
* ... but even if we did see one of these, -b turns it back on.
*/
! if (include_everything && WANT_DATA(dumpObjFlags))
outputBlobs = true;

/*
***************
*** 658,664 ****
if (g_fout->remoteVersion < 80400)
guessConstraintInheritance(tblinfo, numTables);

! if (!schemaOnly)
getTableData(tblinfo, numTables, oids);

if (outputBlobs && hasBlobs(g_fout))
--- 705,711 ----
if (g_fout->remoteVersion < 80400)
guessConstraintInheritance(tblinfo, numTables);

! if (WANT_DATA(dumpObjFlags))
getTableData(tblinfo, numTables, oids);

if (outputBlobs && hasBlobs(g_fout))
***************
*** 712,718 ****
dumpStdStrings(g_fout);

/* The database item is always next, unless we don't want it at all */
! if (include_everything && !dataOnly)
dumpDatabase(g_fout);

/* Now the rearrangeable objects. */
--- 759,765 ----
dumpStdStrings(g_fout);

/* The database item is always next, unless we don't want it at all */
! if (include_everything && WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
dumpDatabase(g_fout);

/* Now the rearrangeable objects. */
***************
*** 734,740 ****
ropt->noTablespace = outputNoTablespaces;
ropt->disable_triggers = disable_triggers;
ropt->use_setsessauth = use_setsessauth;
! ropt->dataOnly = dataOnly;

if (compressLevel == -1)
ropt->compression = 0;
--- 781,787 ----
ropt->noTablespace = outputNoTablespaces;
ropt->disable_triggers = disable_triggers;
ropt->use_setsessauth = use_setsessauth;
! ropt->dumpObjFlags = dumpObjFlags;

if (compressLevel == -1)
ropt->compression = 0;
***************
*** 792,797 ****
--- 839,846 ----
printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
+ printf(_(" --schema-before-data dump only the part of schema before table data\n"));
+ printf(_(" --schema-after-data dump only the part of schema after table data\n"));
printf(_(" --use-set-session-authorization\n"
" use SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
***************
*** 5165,5171 ****
int ncomments;

/* Comments are SCHEMA not data */
! if (dataOnly)
return;

/* Search for comments associated with catalogId, using table */
--- 5214,5220 ----
int ncomments;

/* Comments are SCHEMA not data */
! if (!WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/* Search for comments associated with catalogId, using table */
***************
*** 5216,5222 ****
PQExpBuffer target;

/* Comments are SCHEMA not data */
! if (dataOnly)
return;

/* Search for comments associated with relation, using table */
--- 5265,5271 ----
PQExpBuffer target;

/* Comments are SCHEMA not data */
! if (!WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/* Search for comments associated with relation, using table */
***************
*** 5568,5574 ****
char *qnspname;

/* Skip if not to be dumped */
! if (!nspinfo->dobj.dump || dataOnly)
return;

/* don't dump dummy namespace from pre-7.3 source */
--- 5617,5623 ----
char *qnspname;

/* Skip if not to be dumped */
! if (!nspinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/* don't dump dummy namespace from pre-7.3 source */
***************
*** 5617,5623 ****
dumpType(Archive *fout, TypeInfo *tinfo)
{
/* Skip if not to be dumped */
! if (!tinfo->dobj.dump || dataOnly)
return;

/* Dump out in proper style */
--- 5666,5672 ----
dumpType(Archive *fout, TypeInfo *tinfo)
{
/* Skip if not to be dumped */
! if (!tinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/* Dump out in proper style */
***************
*** 5646,5651 ****
--- 5695,5704 ----
i;
char *label;

+ /* Skip if not to be dumped */
+ if (!tinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
+ return;
+
/* Set proper schema search path so regproc references list correctly */
selectSourceSchema(tinfo->dobj.namespace->dobj.name);

***************
*** 6262,6268 ****
PQExpBuffer q;

/* Skip if not to be dumped */
! if (!stinfo->dobj.dump || dataOnly)
return;

q = createPQExpBuffer();
--- 6315,6321 ----
PQExpBuffer q;

/* Skip if not to be dumped */
! if (!stinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 6309,6315 ****
if (!include_everything)
return false;
/* And they're schema not data */
! if (dataOnly)
return false;
return true;
}
--- 6362,6368 ----
if (!include_everything)
return false;
/* And they're schema not data */
! if (!WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return false;
return true;
}
***************
*** 6330,6336 ****
FuncInfo *funcInfo;
FuncInfo *validatorInfo = NULL;

! if (dataOnly)
return;

/*
--- 6383,6389 ----
FuncInfo *funcInfo;
FuncInfo *validatorInfo = NULL;

! if (!WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/*
***************
*** 6590,6596 ****
int i;

/* Skip if not to be dumped */
! if (!finfo->dobj.dump || dataOnly)
return;

query = createPQExpBuffer();
--- 6643,6649 ----
int i;

/* Skip if not to be dumped */
! if (!finfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

query = createPQExpBuffer();
***************
*** 6985,6991 ****
TypeInfo *sourceInfo;
TypeInfo *targetInfo;

! if (dataOnly)
return;

if (OidIsValid(cast->castfunc))
--- 7038,7044 ----
TypeInfo *sourceInfo;
TypeInfo *targetInfo;

! if (!WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

if (OidIsValid(cast->castfunc))
***************
*** 7135,7141 ****
char *oprcanhash;

/* Skip if not to be dumped */
! if (!oprinfo->dobj.dump || dataOnly)
return;

/*
--- 7188,7194 ----
char *oprcanhash;

/* Skip if not to be dumped */
! if (!oprinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/*
***************
*** 7519,7525 ****
int i;

/* Skip if not to be dumped */
! if (!opcinfo->dobj.dump || dataOnly)
return;

/*
--- 7572,7578 ----
int i;

/* Skip if not to be dumped */
! if (!opcinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/*
***************
*** 7827,7833 ****
int i;

/* Skip if not to be dumped */
! if (!opfinfo->dobj.dump || dataOnly)
return;

/*
--- 7880,7886 ----
int i;

/* Skip if not to be dumped */
! if (!opfinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/*
***************
*** 8096,8102 ****
bool condefault;

/* Skip if not to be dumped */
! if (!convinfo->dobj.dump || dataOnly)
return;

query = createPQExpBuffer();
--- 8149,8155 ----
bool condefault;

/* Skip if not to be dumped */
! if (!convinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

query = createPQExpBuffer();
***************
*** 8250,8256 ****
bool convertok;

/* Skip if not to be dumped */
! if (!agginfo->aggfn.dobj.dump || dataOnly)
return;

query = createPQExpBuffer();
--- 8303,8309 ----
bool convertok;

/* Skip if not to be dumped */
! if (!agginfo->aggfn.dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

query = createPQExpBuffer();
***************
*** 8453,8459 ****
PQExpBuffer delq;

/* Skip if not to be dumped */
! if (!prsinfo->dobj.dump || dataOnly)
return;

q = createPQExpBuffer();
--- 8506,8512 ----
PQExpBuffer delq;

/* Skip if not to be dumped */
! if (!prsinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 8522,8528 ****
char *tmplname;

/* Skip if not to be dumped */
! if (!dictinfo->dobj.dump || dataOnly)
return;

q = createPQExpBuffer();
--- 8575,8581 ----
char *tmplname;

/* Skip if not to be dumped */
! if (!dictinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 8607,8613 ****
PQExpBuffer delq;

/* Skip if not to be dumped */
! if (!tmplinfo->dobj.dump || dataOnly)
return;

q = createPQExpBuffer();
--- 8660,8666 ----
PQExpBuffer delq;

/* Skip if not to be dumped */
! if (!tmplinfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 8673,8679 ****
int i_dictname;

/* Skip if not to be dumped */
! if (!cfginfo->dobj.dump || dataOnly)
return;

q = createPQExpBuffer();
--- 8726,8732 ----
int i_dictname;

/* Skip if not to be dumped */
! if (!cfginfo->dobj.dump || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 8809,8815 ****
PQExpBuffer sql;

/* Do nothing if ACL dump is not enabled */
! if (dataOnly || aclsSkip)
return;

sql = createPQExpBuffer();
--- 8862,8868 ----
PQExpBuffer sql;

/* Do nothing if ACL dump is not enabled */
! if (!WANT_SCHEMA_BEFORE_DATA(dumpObjFlags) || aclsSkip)
return;

sql = createPQExpBuffer();
***************
*** 8846,8852 ****
{
if (tbinfo->relkind == RELKIND_SEQUENCE)
dumpSequence(fout, tbinfo);
! else if (!dataOnly)
dumpTableSchema(fout, tbinfo);

/* Handle the ACL here */
--- 8899,8905 ----
{
if (tbinfo->relkind == RELKIND_SEQUENCE)
dumpSequence(fout, tbinfo);
! else if (WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
dumpTableSchema(fout, tbinfo);

/* Handle the ACL here */
***************
*** 9153,9159 ****
PQExpBuffer delq;

/* Only print it if "separate" mode is selected */
! if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
return;

/* Don't print inherited defaults, either */
--- 9206,9212 ----
PQExpBuffer delq;

/* Only print it if "separate" mode is selected */
! if (!tbinfo->dobj.dump || !adinfo->separate || !WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
return;

/* Don't print inherited defaults, either */
***************
*** 9238,9244 ****
PQExpBuffer q;
PQExpBuffer delq;

! if (dataOnly)
return;

q = createPQExpBuffer();
--- 9291,9297 ----
PQExpBuffer q;
PQExpBuffer delq;

! if (!WANT_SCHEMA_AFTER_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 9307,9313 ****
PQExpBuffer delq;

/* Skip if not to be dumped */
! if (!coninfo->dobj.dump || dataOnly)
return;

q = createPQExpBuffer();
--- 9360,9366 ----
PQExpBuffer delq;

/* Skip if not to be dumped */
! if (!coninfo->dobj.dump || !WANT_SCHEMA_AFTER_DATA(dumpObjFlags))
return;

q = createPQExpBuffer();
***************
*** 9700,9706 ****
*
* Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
*/
! if (!dataOnly)
{
resetPQExpBuffer(delqry);

--- 9753,9759 ----
*
* Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
*/
! if (WANT_SCHEMA_BEFORE_DATA(dumpObjFlags))
{
resetPQExpBuffer(delqry);

***************
*** 9803,9809 ****
tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}

! if (!schemaOnly)
{
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
--- 9856,9862 ----
tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}

! if (WANT_DATA(dumpObjFlags))
{
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
***************
*** 9836,9842 ****
const char *p;
int findx;

! if (dataOnly)
return;

query = createPQExpBuffer();
--- 9889,9895 ----
const char *p;
int findx;

! if (!WANT_SCHEMA_AFTER_DATA(dumpObjFlags))
return;

query = createPQExpBuffer();
***************
*** 10044,10050 ****
PGresult *res;

/* Skip if not to be dumped */
! if (!rinfo->dobj.dump || dataOnly)
return;

/*
--- 10097,10103 ----
PGresult *res;

/* Skip if not to be dumped */
! if (!rinfo->dobj.dump || !WANT_SCHEMA_AFTER_DATA(dumpObjFlags))
return;

/*
Index: src/bin/pg_dump/pg_restore.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_restore.c,v
retrieving revision 1.88
diff -c -r1.88 pg_restore.c
*** src/bin/pg_dump/pg_restore.c 13 Apr 2008 03:49:22 -0000 1.88
--- src/bin/pg_dump/pg_restore.c 24 Jul 2008 07:30:19 -0000
***************
*** 78,83 ****
--- 78,90 ----
static int no_data_for_failed_tables = 0;
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
+ bool dataOnly = false;
+ bool schemaOnly = false;
+
+ static int schemaBeforeData;
+ static int schemaAfterData;
+
+ int dumpObjFlags;

struct option cmdopts[] = {
{"clean", 0, NULL, 'c'},
***************
*** 114,119 ****
--- 121,128 ----
{"disable-triggers", no_argument, &disable_triggers, 1},
{"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1},
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
+ {"schema-before-data", no_argument, &schemaBeforeData, 1},
+ {"schema-after-data", no_argument, &schemaAfterData, 1},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},

{NULL, 0, NULL, 0}
***************
*** 145,151 ****
switch (c)
{
case 'a': /* Dump data only */
! opts->dataOnly = 1;
break;
case 'c': /* clean (i.e., drop) schema prior to create */
opts->dropSchema = 1;
--- 154,160 ----
switch (c)
{
case 'a': /* Dump data only */
! dataOnly = true;
break;
case 'c': /* clean (i.e., drop) schema prior to create */
opts->dropSchema = 1;
***************
*** 213,219 ****
opts->triggerNames = strdup(optarg);
break;
case 's': /* dump schema only */
! opts->schemaOnly = 1;
break;
case 'S': /* Superuser username */
if (strlen(optarg) != 0)
--- 222,228 ----
opts->triggerNames = strdup(optarg);
break;
case 's': /* dump schema only */
! schemaOnly = true;
break;
case 'S': /* Superuser username */
if (strlen(optarg) != 0)
***************
*** 249,254 ****
--- 258,267 ----
no_data_for_failed_tables = 1;
else if (strcmp(optarg, "no-tablespaces") == 0)
outputNoTablespaces = 1;
+ else if (strcmp(optarg, "schema-before-data") == 0)
+ schemaBeforeData = 1;
+ else if (strcmp(optarg, "schema-after-data") == 0)
+ schemaAfterData = 1;
else if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1;
else
***************
*** 295,300 ****
--- 308,354 ----
opts->useDB = 1;
}

+ /*
+ * Look for conflicting options relating to object groupings
+ */
+ if (schemaOnly && dataOnly)
+ {
+ write_msg(NULL, "options %s and %s cannot be used together\n",
+ "-s/--schema-only", "-a/--data-only");
+ exit(1);
+ }
+ else if ((schemaOnly || dataOnly) &&
+ (schemaBeforeData || schemaAfterData))
+ {
+ write_msg(NULL, "options %s and %s cannot be used together\n",
+ schemaOnly ? "-s/--schema-only" : "-a/--data-only",
+ schemaBeforeData ? "--schema-before-data" : "--schema-after-data");
+ exit(1);
+ }
+ else if (schemaBeforeData && schemaAfterData)
+ {
+ write_msg(NULL, "options %s and %s cannot be used together\n",
+ "--schema-before-data", "--schema-after-data");
+ exit(1);
+ }
+
+ /*
+ * Decide which of the object groups we will dump
+ */
+ dumpObjFlags = REQ_ALL;
+
+ if (dataOnly)
+ dumpObjFlags = REQ_DATA;
+
+ if (schemaBeforeData)
+ dumpObjFlags = REQ_SCHEMA_BEFORE_DATA;
+
+ if (schemaAfterData)
+ dumpObjFlags = REQ_SCHEMA_AFTER_DATA;
+
+ if (schemaOnly)
+ dumpObjFlags = (REQ_SCHEMA_BEFORE_DATA | REQ_SCHEMA_AFTER_DATA);
+
opts->disable_triggers = disable_triggers;
opts->noDataForFailedTables = no_data_for_failed_tables;
opts->noTablespace = outputNoTablespaces;
***************
*** 405,410 ****
--- 459,466 ----
" do not restore data of tables that could not be\n"
" created\n"));
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
+ printf(_(" --schema-before-data dump only the part of schema before table data\n"));
+ printf(_(" --schema-after-data dump only the part of schema after table data\n"));
printf(_(" --use-set-session-authorization\n"
" use SESSION AUTHORIZATION commands instead of\n"
" OWNER TO commands\n"));
Index: src/interfaces/ecpg/preproc/keywords.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/interfaces/ecpg/preproc/keywords.c,v
retrieving revision 1.85
diff -c -r1.85 keywords.c
*** src/interfaces/ecpg/preproc/keywords.c 1 Jan 2008 19:45:59 -0000 1.85
--- src/interfaces/ecpg/preproc/keywords.c 18 Jul 2008 08:50:27 -0000
***************
*** 1,430 ****
/*-------------------------------------------------------------------------
*
* 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.84 2007/11/15 21:14:45 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
--- 1,436 ----
/*-------------------------------------------------------------------------
*
* keywords.c
! * lexical token lookup for key words in PostgreSQL
! *
! * NB: This file is also used by pg_dump.
! *
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.198 2008/07/03 20:58:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/

! /* Use c.h so that this file can be built in either frontend or backend */
! #include "c.h"

! #include <ctype.h>

/*
! * This macro definition overrides the YYSTYPE union definition in parse.h.
! * We don't need that struct in this file, and including the real definition
! * would require sucking in some backend-only include files.
*/
! #define YYSTYPE int

+ #include "parser/keywords.h"
+ #ifndef ECPG_COMPILE
+ #include "parser/parse.h"
+ #else
+ #include "preproc.h"
+ #endif

/*
! * List of keyword (name, token-value, category) entries.
! *
! * !!WARNING!!: This list must be sorted by ASCII name, because binary
! * search is used to locate entries.
*/
! const ScanKeyword ScanKeywords[] = {
! /* name, value, category */
! {"abort", ABORT_P, UNRESERVED_KEYWORD},
! {"absolute", ABSOLUTE_P, UNRESERVED_KEYWORD},
! {"access", ACCESS, UNRESERVED_KEYWORD},
! {"action", ACTION, UNRESERVED_KEYWORD},
! {"add", ADD_P, UNRESERVED_KEYWORD},
! {"admin", ADMIN, UNRESERVED_KEYWORD},
! {"after", AFTER, UNRESERVED_KEYWORD},
! {"aggregate", AGGREGATE, UNRESERVED_KEYWORD},
! {"all", ALL, RESERVED_KEYWORD},
! {"also", ALSO, UNRESERVED_KEYWORD},
! {"alter", ALTER, UNRESERVED_KEYWORD},
! {"always", ALWAYS, UNRESERVED_KEYWORD},
! {"analyse", ANALYSE, RESERVED_KEYWORD}, /* British spelling */
! {"analyze", ANALYZE, RESERVED_KEYWORD},
! {"and", AND, RESERVED_KEYWORD},
! {"any", ANY, RESERVED_KEYWORD},
! {"array", ARRAY, RESERVED_KEYWORD},
! {"as", AS, RESERVED_KEYWORD},
! {"asc", ASC, RESERVED_KEYWORD},
! {"assertion", ASSERTION, UNRESERVED_KEYWORD},
! {"assignment", ASSIGNMENT, UNRESERVED_KEYWORD},
! {"asymmetric", ASYMMETRIC, RESERVED_KEYWORD},
! {"at", AT, UNRESERVED_KEYWORD},
! {"authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD},
! {"backward", BACKWARD, UNRESERVED_KEYWORD},
! {"before", BEFORE, UNRESERVED_KEYWORD},
! {"begin", BEGIN_P, UNRESERVED_KEYWORD},
! {"between", BETWEEN, TYPE_FUNC_NAME_KEYWORD},
! {"bigint", BIGINT, COL_NAME_KEYWORD},
! {"binary", BINARY, TYPE_FUNC_NAME_KEYWORD},
! {"bit", BIT, COL_NAME_KEYWORD},
! {"boolean", BOOLEAN_P, COL_NAME_KEYWORD},
! {"both", BOTH, RESERVED_KEYWORD},
! {"by", BY, UNRESERVED_KEYWORD},
! {"cache", CACHE, UNRESERVED_KEYWORD},
! {"called", CALLED, UNRESERVED_KEYWORD},
! {"cascade", CASCADE, UNRESERVED_KEYWORD},
! {"cascaded", CASCADED, UNRESERVED_KEYWORD},
! {"case", CASE, RESERVED_KEYWORD},
! {"cast", CAST, RESERVED_KEYWORD},
! {"chain", CHAIN, UNRESERVED_KEYWORD},
! {"char", CHAR_P, COL_NAME_KEYWORD},
! {"character", CHARACTER, COL_NAME_KEYWORD},
! {"characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD},
! {"check", CHECK, RESERVED_KEYWORD},
! {"checkpoint", CHECKPOINT, UNRESERVED_KEYWORD},
! {"class", CLASS, UNRESERVED_KEYWORD},
! {"close", CLOSE, UNRESERVED_KEYWORD},
! {"cluster", CLUSTER, UNRESERVED_KEYWORD},
! {"coalesce", COALESCE, COL_NAME_KEYWORD},
! {"collate", COLLATE, RESERVED_KEYWORD},
! {"column", COLUMN, RESERVED_KEYWORD},
! {"comment", COMMENT, UNRESERVED_KEYWORD},
! {"commit", COMMIT, UNRESERVED_KEYWORD},
! {"committed", COMMITTED, UNRESERVED_KEYWORD},
! {"concurrently", CONCURRENTLY, UNRESERVED_KEYWORD},
! {"configuration", CONFIGURATION, UNRESERVED_KEYWORD},
! {"connection", CONNECTION, UNRESERVED_KEYWORD},
! {"constraint", CONSTRAINT, RESERVED_KEYWORD},
! {"constraints", CONSTRAINTS, UNRESERVED_KEYWORD},
! {"content", CONTENT_P, UNRESERVED_KEYWORD},
! {"continue", CONTINUE_P, UNRESERVED_KEYWORD},
! {"conversion", CONVERSION_P, UNRESERVED_KEYWORD},
! {"copy", COPY, UNRESERVED_KEYWORD},
! {"cost", COST, UNRESERVED_KEYWORD},
! {"create", CREATE, RESERVED_KEYWORD},
! {"createdb", CREATEDB, UNRESERVED_KEYWORD},
! {"createrole", CREATEROLE, UNRESERVED_KEYWORD},
! {"createuser", CREATEUSER, UNRESERVED_KEYWORD},
! {"cross", CROSS, TYPE_FUNC_NAME_KEYWORD},
! {"csv", CSV, UNRESERVED_KEYWORD},
! {"current", CURRENT_P, UNRESERVED_KEYWORD},
! {"current_date", CURRENT_DATE, RESERVED_KEYWORD},
! {"current_role", CURRENT_ROLE, RESERVED_KEYWORD},
! {"current_time", CURRENT_TIME, RESERVED_KEYWORD},
! {"current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD},
! {"current_user", CURRENT_USER, RESERVED_KEYWORD},
! {"cursor", CURSOR, UNRESERVED_KEYWORD},
! {"cycle", CYCLE, UNRESERVED_KEYWORD},
! {"database", DATABASE, UNRESERVED_KEYWORD},
! {"day", DAY_P, UNRESERVED_KEYWORD},
! {"deallocate", DEALLOCATE, UNRESERVED_KEYWORD},
! {"dec", DEC, COL_NAME_KEYWORD},
! {"decimal", DECIMAL_P, COL_NAME_KEYWORD},
! {"declare", DECLARE, UNRESERVED_KEYWORD},
! {"default", DEFAULT, RESERVED_KEYWORD},
! {"defaults", DEFAULTS, UNRESERVED_KEYWORD},
! {"deferrable", DEFERRABLE, RESERVED_KEYWORD},
! {"deferred", DEFERRED, UNRESERVED_KEYWORD},
! {"definer", DEFINER, UNRESERVED_KEYWORD},
! {"delete", DELETE_P, UNRESERVED_KEYWORD},
! {"delimiter", DELIMITER, UNRESERVED_KEYWORD},
! {"delimiters", DELIMITERS, UNRESERVED_KEYWORD},
! {"desc", DESC, RESERVED_KEYWORD},
! {"dictionary", DICTIONARY, UNRESERVED_KEYWORD},
! {"disable", DISABLE_P, UNRESERVED_KEYWORD},
! {"discard", DISCARD, UNRESERVED_KEYWORD},
! {"distinct", DISTINCT, RESERVED_KEYWORD},
! {"do", DO, RESERVED_KEYWORD},
! {"document", DOCUMENT_P, UNRESERVED_KEYWORD},
! {"domain", DOMAIN_P, UNRESERVED_KEYWORD},
! {"double", DOUBLE_P, UNRESERVED_KEYWORD},
! {"drop", DROP, UNRESERVED_KEYWORD},
! {"each", EACH, UNRESERVED_KEYWORD},
! {"else", ELSE, RESERVED_KEYWORD},
! {"enable", ENABLE_P, UNRESERVED_KEYWORD},
! {"encoding", ENCODING, UNRESERVED_KEYWORD},
! {"encrypted", ENCRYPTED, UNRESERVED_KEYWORD},
! {"end", END_P, RESERVED_KEYWORD},
! {"enum", ENUM_P, UNRESERVED_KEYWORD},
! {"escape", ESCAPE, UNRESERVED_KEYWORD},
! {"except", EXCEPT, RESERVED_KEYWORD},
! {"excluding", EXCLUDING, UNRESERVED_KEYWORD},
! {"exclusive", EXCLUSIVE, UNRESERVED_KEYWORD},
! {"execute", EXECUTE, UNRESERVED_KEYWORD},
! {"exists", EXISTS, COL_NAME_KEYWORD},
! {"explain", EXPLAIN, UNRESERVED_KEYWORD},
! {"external", EXTERNAL, UNRESERVED_KEYWORD},
! {"extract", EXTRACT, COL_NAME_KEYWORD},
! {"false", FALSE_P, RESERVED_KEYWORD},
! {"family", FAMILY, UNRESERVED_KEYWORD},
! {"fetch", FETCH, UNRESERVED_KEYWORD},
! {"first", FIRST_P, UNRESERVED_KEYWORD},
! {"float", FLOAT_P, COL_NAME_KEYWORD},
! {"for", FOR, RESERVED_KEYWORD},
! {"force", FORCE, UNRESERVED_KEYWORD},
! {"foreign", FOREIGN, RESERVED_KEYWORD},
! {"forward", FORWARD, UNRESERVED_KEYWORD},
! {"freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD},
! {"from", FROM, RESERVED_KEYWORD},
! {"full", FULL, TYPE_FUNC_NAME_KEYWORD},
! {"function", FUNCTION, UNRESERVED_KEYWORD},
! {"global", GLOBAL, UNRESERVED_KEYWORD},
! {"grant", GRANT, RESERVED_KEYWORD},
! {"granted", GRANTED, UNRESERVED_KEYWORD},
! {"greatest", GREATEST, COL_NAME_KEYWORD},
! {"group", GROUP_P, RESERVED_KEYWORD},
! {"handler", HANDLER, UNRESERVED_KEYWORD},
! {"having", HAVING, RESERVED_KEYWORD},
! {"header", HEADER_P, UNRESERVED_KEYWORD},
! {"hold", HOLD, UNRESERVED_KEYWORD},
! {"hour", HOUR_P, UNRESERVED_KEYWORD},
! {"identity", IDENTITY_P, UNRESERVED_KEYWORD},
! {"if", IF_P, UNRESERVED_KEYWORD},
! {"ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD},
! {"immediate", IMMEDIATE, UNRESERVED_KEYWORD},
! {"immutable", IMMUTABLE, UNRESERVED_KEYWORD},
! {"implicit", IMPLICIT_P, UNRESERVED_KEYWORD},
! {"in", IN_P, RESERVED_KEYWORD},
! {"including", INCLUDING, UNRESERVED_KEYWORD},
! {"increment", INCREMENT, UNRESERVED_KEYWORD},
! {"index", INDEX, UNRESERVED_KEYWORD},
! {"indexes", INDEXES, UNRESERVED_KEYWORD},
! {"inherit", INHERIT, UNRESERVED_KEYWORD},
! {"inherits", INHERITS, UNRESERVED_KEYWORD},
! {"initially", INITIALLY, RESERVED_KEYWORD},
! {"inner", INNER_P, TYPE_FUNC_NAME_KEYWORD},
! {"inout", INOUT, COL_NAME_KEYWORD},
! {"input", INPUT_P, UNRESERVED_KEYWORD},
! {"insensitive", INSENSITIVE, UNRESERVED_KEYWORD},
! {"insert", INSERT, UNRESERVED_KEYWORD},
! {"instead", INSTEAD, UNRESERVED_KEYWORD},
! {"int", INT_P, COL_NAME_KEYWORD},
! {"integer", INTEGER, COL_NAME_KEYWORD},
! {"intersect", INTERSECT, RESERVED_KEYWORD},
! {"interval", INTERVAL, COL_NAME_KEYWORD},
! {"into", INTO, RESERVED_KEYWORD},
! {"invoker", INVOKER, UNRESERVED_KEYWORD},
! {"is", IS, TYPE_FUNC_NAME_KEYWORD},
! {"isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD},
! {"isolation", ISOLATION, UNRESERVED_KEYWORD},
! {"join", JOIN, TYPE_FUNC_NAME_KEYWORD},
! {"key", KEY, UNRESERVED_KEYWORD},
! {"lancompiler", LANCOMPILER, UNRESERVED_KEYWORD},
! {"language", LANGUAGE, UNRESERVED_KEYWORD},
! {"large", LARGE_P, UNRESERVED_KEYWORD},
! {"last", LAST_P, UNRESERVED_KEYWORD},
! {"leading", LEADING, RESERVED_KEYWORD},
! {"least", LEAST, COL_NAME_KEYWORD},
! {"left", LEFT, TYPE_FUNC_NAME_KEYWORD},
! {"level", LEVEL, UNRESERVED_KEYWORD},
! {"like", LIKE, TYPE_FUNC_NAME_KEYWORD},
! {"limit", LIMIT, RESERVED_KEYWORD},
! {"listen", LISTEN, UNRESERVED_KEYWORD},
! {"load", LOAD, UNRESERVED_KEYWORD},
! {"local", LOCAL, UNRESERVED_KEYWORD},
! {"localtime", LOCALTIME, RESERVED_KEYWORD},
! {"localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD},
! {"location", LOCATION, UNRESERVED_KEYWORD},
! {"lock", LOCK_P, UNRESERVED_KEYWORD},
! {"login", LOGIN_P, UNRESERVED_KEYWORD},
! {"mapping", MAPPING, UNRESERVED_KEYWORD},
! {"match", MATCH, UNRESERVED_KEYWORD},
! {"maxvalue", MAXVALUE, UNRESERVED_KEYWORD},
! {"minute", MINUTE_P, UNRESERVED_KEYWORD},
! {"minvalue", MINVALUE, UNRESERVED_KEYWORD},
! {"mode", MODE, UNRESERVED_KEYWORD},
! {"month", MONTH_P, UNRESERVED_KEYWORD},
! {"move", MOVE, UNRESERVED_KEYWORD},
! {"name", NAME_P, UNRESERVED_KEYWORD},
! {"names", NAMES, UNRESERVED_KEYWORD},
! {"national", NATIONAL, COL_NAME_KEYWORD},
! {"natural", NATURAL, TYPE_FUNC_NAME_KEYWORD},
! {"nchar", NCHAR, COL_NAME_KEYWORD},
! {"new", NEW, RESERVED_KEYWORD},
! {"next", NEXT, UNRESERVED_KEYWORD},
! {"no", NO, UNRESERVED_KEYWORD},
! {"nocreatedb", NOCREATEDB, UNRESERVED_KEYWORD},
! {"nocreaterole", NOCREATEROLE, UNRESERVED_KEYWORD},
! {"nocreateuser", NOCREATEUSER, UNRESERVED_KEYWORD},
! {"noinherit", NOINHERIT, UNRESERVED_KEYWORD},
! {"nologin", NOLOGIN_P, UNRESERVED_KEYWORD},
! {"none", NONE, COL_NAME_KEYWORD},
! {"nosuperuser", NOSUPERUSER, UNRESERVED_KEYWORD},
! {"not", NOT, RESERVED_KEYWORD},
! {"nothing", NOTHING, UNRESERVED_KEYWORD},
! {"notify", NOTIFY, UNRESERVED_KEYWORD},
! {"notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD},
! {"nowait", NOWAIT, UNRESERVED_KEYWORD},
! {"null", NULL_P, RESERVED_KEYWORD},
! {"nullif", NULLIF, COL_NAME_KEYWORD},
! {"nulls", NULLS_P, UNRESERVED_KEYWORD},
! {"numeric", NUMERIC, COL_NAME_KEYWORD},
! {"object", OBJECT_P, UNRESERVED_KEYWORD},
! {"of", OF, UNRESERVED_KEYWORD},
! {"off", OFF, RESERVED_KEYWORD},
! {"offset", OFFSET, RESERVED_KEYWORD},
! {"oids", OIDS, UNRESERVED_KEYWORD},
! {"old", OLD, RESERVED_KEYWORD},
! {"on", ON, RESERVED_KEYWORD},
! {"only", ONLY, RESERVED_KEYWORD},
! {"operator", OPERATOR, UNRESERVED_KEYWORD},
! {"option", OPTION, UNRESERVED_KEYWORD},
! {"or", OR, RESERVED_KEYWORD},
! {"order", ORDER, RESERVED_KEYWORD},
! {"out", OUT_P, COL_NAME_KEYWORD},
! {"outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD},
! {"overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD},
! {"overlay", OVERLAY, COL_NAME_KEYWORD},
! {"owned", OWNED, UNRESERVED_KEYWORD},
! {"owner", OWNER, UNRESERVED_KEYWORD},
! {"parser", PARSER, UNRESERVED_KEYWORD},
! {"partial", PARTIAL, UNRESERVED_KEYWORD},
! {"password", PASSWORD, UNRESERVED_KEYWORD},
! {"placing", PLACING, RESERVED_KEYWORD},
! {"plans", PLANS, UNRESERVED_KEYWORD},
! {"position", POSITION, COL_NAME_KEYWORD},
! {"precision", PRECISION, COL_NAME_KEYWORD},
! {"prepare", PREPARE, UNRESERVED_KEYWORD},
! {"prepared", PREPARED, UNRESERVED_KEYWORD},
! {"preserve", PRESERVE, UNRESERVED_KEYWORD},
! {"primary", PRIMARY, RESERVED_KEYWORD},
! {"prior", PRIOR, UNRESERVED_KEYWORD},
! {"privileges", PRIVILEGES, UNRESERVED_KEYWORD},
! {"procedural", PROCEDURAL, UNRESERVED_KEYWORD},
! {"procedure", PROCEDURE, UNRESERVED_KEYWORD},
! {"quote", QUOTE, UNRESERVED_KEYWORD},
! {"read", READ, UNRESERVED_KEYWORD},
! {"real", REAL, COL_NAME_KEYWORD},
! {"reassign", REASSIGN, UNRESERVED_KEYWORD},
! {"recheck", RECHECK, UNRESERVED_KEYWORD},
! {"references", REFERENCES, RESERVED_KEYWORD},
! {"reindex", REINDEX, UNRESERVED_KEYWORD},
! {"relative", RELATIVE_P, UNRESERVED_KEYWORD},
! {"release", RELEASE, UNRESERVED_KEYWORD},
! {"rename", RENAME, UNRESERVED_KEYWORD},
! {"repeatable", REPEATABLE, UNRESERVED_KEYWORD},
! {"replace", REPLACE, UNRESERVED_KEYWORD},
! {"replica", REPLICA, UNRESERVED_KEYWORD},
! {"reset", RESET, UNRESERVED_KEYWORD},
! {"restart", RESTART, UNRESERVED_KEYWORD},
! {"restrict", RESTRICT, UNRESERVED_KEYWORD},
! {"returning", RETURNING, RESERVED_KEYWORD},
! {"returns", RETURNS, UNRESERVED_KEYWORD},
! {"revoke", REVOKE, UNRESERVED_KEYWORD},
! {"right", RIGHT, TYPE_FUNC_NAME_KEYWORD},
! {"role", ROLE, UNRESERVED_KEYWORD},
! {"rollback", ROLLBACK, UNRESERVED_KEYWORD},
! {"row", ROW, COL_NAME_KEYWORD},
! {"rows", ROWS, UNRESERVED_KEYWORD},
! {"rule", RULE, UNRESERVED_KEYWORD},
! {"savepoint", SAVEPOINT, UNRESERVED_KEYWORD},
! {"schema", SCHEMA, UNRESERVED_KEYWORD},
! {"scroll", SCROLL, UNRESERVED_KEYWORD},
! {"search", SEARCH, UNRESERVED_KEYWORD},
! {"second", SECOND_P, UNRESERVED_KEYWORD},
! {"security", SECURITY, UNRESERVED_KEYWORD},
! {"select", SELECT, RESERVED_KEYWORD},
! {"sequence", SEQUENCE, UNRESERVED_KEYWORD},
! {"serializable", SERIALIZABLE, UNRESERVED_KEYWORD},
! {"session", SESSION, UNRESERVED_KEYWORD},
! {"session_user", SESSION_USER, RESERVED_KEYWORD},
! {"set", SET, UNRESERVED_KEYWORD},
! {"setof", SETOF, COL_NAME_KEYWORD},
! {"share", SHARE, UNRESERVED_KEYWORD},
! {"show", SHOW, UNRESERVED_KEYWORD},
! {"similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD},
! {"simple", SIMPLE, UNRESERVED_KEYWORD},
! {"smallint", SMALLINT, COL_NAME_KEYWORD},
! {"some", SOME, RESERVED_KEYWORD},
! {"stable", STABLE, UNRESERVED_KEYWORD},
! {"standalone", STANDALONE_P, UNRESERVED_KEYWORD},
! {"start", START, UNRESERVED_KEYWORD},
! {"statement", STATEMENT, UNRESERVED_KEYWORD},
! {"statistics", STATISTICS, UNRESERVED_KEYWORD},
! {"stdin", STDIN, UNRESERVED_KEYWORD},
! {"stdout", STDOUT, UNRESERVED_KEYWORD},
! {"storage", STORAGE, UNRESERVED_KEYWORD},
! {"strict", STRICT_P, UNRESERVED_KEYWORD},
! {"strip", STRIP_P, UNRESERVED_KEYWORD},
! {"substring", SUBSTRING, COL_NAME_KEYWORD},
! {"superuser", SUPERUSER_P, UNRESERVED_KEYWORD},
! {"symmetric", SYMMETRIC, RESERVED_KEYWORD},
! {"sysid", SYSID, UNRESERVED_KEYWORD},
! {"system", SYSTEM_P, UNRESERVED_KEYWORD},
! {"table", TABLE, RESERVED_KEYWORD},
! {"tablespace", TABLESPACE, UNRESERVED_KEYWORD},
! {"temp", TEMP, UNRESERVED_KEYWORD},
! {"template", TEMPLATE, UNRESERVED_KEYWORD},
! {"temporary", TEMPORARY, UNRESERVED_KEYWORD},
! {"text", TEXT_P, UNRESERVED_KEYWORD},
! {"then", THEN, RESERVED_KEYWORD},
! {"time", TIME, COL_NAME_KEYWORD},
! {"timestamp", TIMESTAMP, COL_NAME_KEYWORD},
! {"to", TO, RESERVED_KEYWORD},
! {"trailing", TRAILING, RESERVED_KEYWORD},
! {"transaction", TRANSACTION, UNRESERVED_KEYWORD},
! {"treat", TREAT, COL_NAME_KEYWORD},
! {"trigger", TRIGGER, UNRESERVED_KEYWORD},
! {"trim", TRIM, COL_NAME_KEYWORD},
! {"true", TRUE_P, RESERVED_KEYWORD},
! {"truncate", TRUNCATE, UNRESERVED_KEYWORD},
! {"trusted", TRUSTED, UNRESERVED_KEYWORD},
! {"type", TYPE_P, UNRESERVED_KEYWORD},
! {"uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD},
! {"unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD},
! {"union", UNION, RESERVED_KEYWORD},
! {"unique", UNIQUE, RESERVED_KEYWORD},
! {"unknown", UNKNOWN, UNRESERVED_KEYWORD},
! {"unlisten", UNLISTEN, UNRESERVED_KEYWORD},
! {"until", UNTIL, UNRESERVED_KEYWORD},
! {"update", UPDATE, UNRESERVED_KEYWORD},
! {"user", USER, RESERVED_KEYWORD},
! {"using", USING, RESERVED_KEYWORD},
! {"vacuum", VACUUM, UNRESERVED_KEYWORD},
! {"valid", VALID, UNRESERVED_KEYWORD},
! {"validator", VALIDATOR, UNRESERVED_KEYWORD},
! {"value", VALUE_P, UNRESERVED_KEYWORD},
! {"values", VALUES, COL_NAME_KEYWORD},
! {"varchar", VARCHAR, COL_NAME_KEYWORD},
! {"variadic", VARIADIC, RESERVED_KEYWORD},
! {"varying", VARYING, UNRESERVED_KEYWORD},
! {"verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD},
! {"version", VERSION_P, UNRESERVED_KEYWORD},
! {"view", VIEW, UNRESERVED_KEYWORD},
! {"volatile", VOLATILE, UNRESERVED_KEYWORD},
! {"when", WHEN, RESERVED_KEYWORD},
! {"where", WHERE, RESERVED_KEYWORD},
! {"whitespace", WHITESPACE_P, UNRESERVED_KEYWORD},

! /*
! * XXX we mark WITH as reserved to force it to be quoted in dumps, even
! * though it is currently unreserved according to gram.y. This is because
! * we expect we'll have to make it reserved to implement SQL WITH clauses.
! * If that patch manages to do without reserving WITH, adjust this entry
! * at that time; in any case this should be back in sync with gram.y after
! * WITH clauses are implemented.
! */
! {"with", WITH, RESERVED_KEYWORD},
! {"without", WITHOUT, UNRESERVED_KEYWORD},
! {"work", WORK, UNRESERVED_KEYWORD},
! {"write", WRITE, UNRESERVED_KEYWORD},
! {"xml", XML_P, UNRESERVED_KEYWORD},
! {"xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD},
! {"xmlconcat", XMLCONCAT, COL_NAME_KEYWORD},
! {"xmlelement", XMLELEMENT, COL_NAME_KEYWORD},
! {"xmlforest", XMLFOREST, COL_NAME_KEYWORD},
! {"xmlparse", XMLPARSE, COL_NAME_KEYWORD},
! {"xmlpi", XMLPI, COL_NAME_KEYWORD},
! {"xmlroot", XMLROOT, COL_NAME_KEYWORD},
! {"xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD},
! {"year", YEAR_P, UNRESERVED_KEYWORD},
! {"yes", YES_P, UNRESERVED_KEYWORD},
! {"zone", ZONE, UNRESERVED_KEYWORD},
! };

! /* End of ScanKeywords, for use elsewhere */
! const ScanKeyword *LastScanKeyword = endof(ScanKeywords);

/*
* ScanKeywordLookup - see if a given word is a keyword
***************
*** 439,450 ****
* 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. */
--- 445,457 ----
* receive a different case-normalization mapping.
*/
const ScanKeyword *
! ScanKeywordLookup(const char *text)
{
int len,
i;
char word[NAMEDATALEN];
! const ScanKeyword *low;
! const ScanKeyword *high;

len = strlen(text);
/* We assume all keywords are shorter than NAMEDATALEN. */
***************
*** 468,476 ****
/*
* 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);
}
--- 475,496 ----
/*
* Now do a binary search using plain strcmp() comparison.
*/
! low = &ScanKeywords[0];
! high = endof(ScanKeywords) - 1;
! 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;
}
On Wed, 2008-07-23 at 23:20 -0400, Stephen Frost wrote:

> * Simon Riggs (simon@2ndquadrant.com) wrote:
> > ...and with command line help also.
>
> The documentation and whatnot looks good to me now. There are a couple
> of other issues I found while looking through and testing the patch
> though-

Thanks for a good review.

> Index: src/bin/pg_dump/pg_dump.c
> ===================================================================
> RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_dump.c,v
> retrieving revision 1.497
> diff -c -r1.497 pg_dump.c
> *** src/bin/pg_dump/pg_dump.c 20 Jul 2008 18:43:30 -0000 1.497
> --- src/bin/pg_dump/pg_dump.c 23 Jul 2008 17:04:24 -0000
> ***************
> *** 225,232 ****
> RestoreOptions *ropt;
>
> static int disable_triggers = 0;
> ! static int outputNoTablespaces = 0;
> static int use_setsessauth = 0;
>
> static struct option long_options[] = {
> {"data-only", no_argument, NULL, 'a'},
> --- 229,238 ----
> RestoreOptions *ropt;
>
> static int disable_triggers = 0;
> ! static int outputNoTablespaces = 0;
> static int use_setsessauth = 0;
> + static int use_schemaBeforeData;
> + static int use_schemaAfterData;
>
> static struct option long_options[] = {
> {"data-only", no_argument, NULL, 'a'},
> ***************
>
> This hunk appears to have a bit of gratuitous whitespace change, not a
> big deal tho.

OK

> ***************
> *** 464,474 ****
> [...]
> + if (dataOnly)
> + dumpObjFlags = REQ_DATA;
> +
> + if (use_schemaBeforeData == 1)
> + dumpObjFlags = REQ_SCHEMA_BEFORE_DATA;
> +
> + if (use_schemaAfterData == 1)
> + dumpObjFlags = REQ_SCHEMA_AFTER_DATA;
> +
> + if (schemaOnly)
> + dumpObjFlags = (REQ_SCHEMA_BEFORE_DATA | REQ_SCHEMA_AFTER_DATA);
> ***************
>
> It wouldn't kill to be consistant between testing for '== 1' and just
> checking for non-zero. Again, not really a big deal, and I wouldn't
> mention these if there weren't other issues.

OK

> ***************
> *** 646,652 ****
> * Dumping blobs is now default unless we saw an inclusion switch or -s
> * ... but even if we did see one of these, -b turns it back on.
> */
> ! if (include_everything && !schemaOnly)
> outputBlobs = true;
>
> /*
> --- 689,695 ----
> * Dumping blobs is now default unless we saw an inclusion switch or -s
> * ... but even if we did see one of these, -b turns it back on.
> */
> ! if (include_everything && WANT_PRE_SCHEMA(dumpObjFlags))
> outputBlobs = true;
>
> /*
> ***************
>
> Shouldn't this change be to "WANT_DATA(dumpObjFlags)"? That's what most
> of the '!schemaOnly' get translated to. Otherwise I think you would be
> getting blobs when you've asked for just schema-before-data, which
> doesn't seem like it'd make much sense.

Yes, fixed

> ***************
> *** 712,718 ****
> dumpStdStrings(g_fout);
>
> /* The database item is always next, unless we don't want it at all */
> ! if (include_everything && !dataOnly)
> dumpDatabase(g_fout);
>
> /* Now the rearrangeable objects. */
> --- 755,761 ----
> dumpStdStrings(g_fout);
>
> /* The database item is always next, unless we don't want it at all */
> ! if (include_everything && WANT_DATA(dumpObjFlags))
> dumpDatabase(g_fout);
>
> /* Now the rearrangeable objects. */
> ***************
>
> Shouldn't this be 'WANT_PRE_SCHEMA(dumpObjFlags)'?

Yes, fixed

> ***************
> *** 3414,3420 ****
> continue;
>
> /* Ignore indexes of tables not to be dumped */
> ! if (!tbinfo->dobj.dump)
> continue;
>
> if (g_verbose)
> --- 3459,3465 ----
> continue;
>
> /* Ignore indexes of tables not to be dumped */
> ! if (!tbinfo->dobj.dump || !WANT_POST_SCHEMA(dumpObjFlags))
> continue;
>
> if (g_verbose)
> ***************
>
> I didn't test this, but it strikes me as an unnecessary addition? If
> anything, wouldn't this check make more sense being done right after
> dropping into getIndexes()? No sense going through the loop just for
> fun.. Technically, it's a behavioral change for --data-only since it
> used to gather index information anyway, but it's a good optimization if
> done in the right place.

Agreed. I've just removed this. Patch not about optimising logic.

> Also around here, there doesn't appear to be any checking in
> dumpEnumType(), which strikes me as odd. Wouldn't that deserve a
>
> if (!WANT_PRE_SCHEMA(dumpObjFlags))
> return;
>
> check? If not even some kind of equivilant ->dobj.dump check..

Agreed. That appears to be a bug in pg_dump, since this would currently
dump enums if --data-only was specified, which in my understanding would
be wrong.

Have included this:

/* Skip if not to be dumped */
if (!tinfo->dobj.dump || !WANT_BEFORE_SCHEMA(dumpObjFlags))
return;

> ***************
> *** 9803,9809 ****
> tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
> }
>
> ! if (!schemaOnly)
> {
> resetPQExpBuffer(query);
> appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
> --- 9848,9854 ----
> tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
> }
>
> ! if (WANT_PRE_SCHEMA(dumpObjFlags))
> {
> resetPQExpBuffer(query);
> appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
> ***************
>
> This is a mistaken logic invert, which results in setval's not being
> dumped at all when pulling out each piece seperately. It should be:
>
> if (WANT_DATA(dumpObjFlags))
>
> so that setval's are correctly included on the --data-only piece. As
> --data-only previously existed, this would be a regression too.

OK, fixed.


> Index: src/bin/pg_dump/pg_restore.c
> ===================================================================
> RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/bin/pg_dump/pg_restore.c,v
> retrieving revision 1.88
> diff -c -r1.88 pg_restore.c
> *** src/bin/pg_dump/pg_restore.c 13 Apr 2008 03:49:22 -0000 1.88
> --- src/bin/pg_dump/pg_restore.c 23 Jul 2008 17:06:59 -0000
> + if (dataOnly)
> + dumpObjFlags = REQ_DATA;
> +
> + if (use_schemaBeforeData == 1)
> + dumpObjFlags = REQ_SCHEMA_BEFORE_DATA;
> +
> + if (use_schemaAfterData == 1)
> + dumpObjFlags = REQ_SCHEMA_AFTER_DATA;
> +
> + if (schemaOnly)
> + dumpObjFlags = (REQ_SCHEMA_BEFORE_DATA | REQ_SCHEMA_AFTER_DATA);
> +
> ***************
>
> Ditto previous comment on this, but in pg_restore.c.

OK

>
> ***************
> *** 405,410 ****
> --- 455,462 ----
> " do not restore data of tables that could not be\n"
> " created\n"));
> printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
> + printf(_(" --schema-before-data dump only the part of schema before table data\n"));
> + printf(_(" --schema-after-data dump only the part of schema after table data\n"));
> printf(_(" --use-set-session-authorization\n"
> " use SESSION AUTHORIZATION commands instead of\n"
> " OWNER TO commands\n"));
> ***************
>
> Forgot to mention this on pg_dump.c, but in both pg_dump and pg_restore,
> and I hate to be the bearer of bad news, but your command-line
> documentation doesn't line up properly in the output. You shouldn't be
> using tabs there but instead should use spaces as the other help text
> does, so everything lines up nicely.

OK

--
Simon Riggs www.2ndQuadrant.com
PostgreSQL Training, Services and Support

No comments: