Commit 9f0ae0c8 authored by Tom Lane's avatar Tom Lane

First pass at schema-fying pg_dump/pg_restore. Much to do still,

but the basic capability seems to work.
parent 1011fb65
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.44 2002/04/21 19:02:39 thomas Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.45 2002/05/10 22:36:26 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -407,10 +407,11 @@ PostgreSQL documentation ...@@ -407,10 +407,11 @@ PostgreSQL documentation
<term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term> <term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term>
<listitem> <listitem>
<para> <para>
The scripts or archives created by <command>pg_dump</command> Specify the superuser user name to use when disabling triggers.
need to have superuser access in certain cases, such as when This is only relevant if <option>--disable-triggers</> is used.
disabling triggers or setting ownership of schema elements. (Usually, it's better to specify
This option specifies the user name to use for those cases. <option>--use-set-session-authorization</>, and then start the
resulting script as superuser.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -481,6 +482,36 @@ PostgreSQL documentation ...@@ -481,6 +482,36 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-X disable-triggers</></term>
<term><option>--disable-triggers</></term>
<listitem>
<para>
This option is only relevant when creating a data-only dump.
It instructs <command>pg_dump</command> to include commands
to temporarily disable triggers on the target tables while
the data is reloaded. Use this if you have referential
integrity checks or other triggers on the tables that you
do not want to invoke during data reload.
</para>
<para>
Presently, the commands emitted for <option>--disable-triggers</>
must be done as superuser. So, you should also specify
a superuser name with <option>-S</>, or preferably specify
<option>--use-set-session-authorization</> and then be careful to
start the resulting script as a superuser. If you give neither
option, the entire script must be run as superuser.
</para>
<para>
This option is only meaningful for the plain-text format. For
the other formats, you may specify the option when you
call <command>pg_restore</command>.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-Z <replaceable class="parameter">0..9</replaceable></option></term> <term><option>-Z <replaceable class="parameter">0..9</replaceable></option></term>
<term><option>--compress=<replaceable class="parameter">0..9</replaceable></option></term> <term><option>--compress=<replaceable class="parameter">0..9</replaceable></option></term>
......
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.24 2002/04/21 19:02:39 thomas Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.25 2002/05/10 22:36:26 tgl Exp $ -->
<refentry id="APP-PGRESTORE"> <refentry id="APP-PGRESTORE">
<docinfo> <docinfo>
...@@ -336,8 +336,8 @@ ...@@ -336,8 +336,8 @@
<term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term> <term><option>--superuser=<replaceable class="parameter">username</replaceable></option></term>
<listitem> <listitem>
<para> <para>
Specify the superuser user name to use when disabling triggers and/or setting ownership of schema elements. Specify the superuser user name to use when disabling triggers.
By default, <COMMAND>pg_restore</COMMAND> will use the current user name if it is a superuser. This is only relevant if <option>--disable-triggers</> is used.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -402,6 +402,29 @@ ...@@ -402,6 +402,29 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-X disable-triggers</></term>
<term><option>--disable-triggers</></term>
<listitem>
<para>
This option is only relevant when performing a data-only restore.
It instructs <command>pg_restore</command> to execute commands
to temporarily disable triggers on the target tables while
the data is reloaded. Use this if you have referential
integrity checks or other triggers on the tables that you
do not want to invoke during data reload.
</para>
<para>
Presently, the commands emitted for <option>--disable-triggers</>
must be done as superuser. So, you should also specify
a superuser name with <option>-S</>, or preferably specify
<option>--use-set-session-authorization</> and run
<command>pg_restore</command> as a superuser.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
......
...@@ -3,30 +3,15 @@ ...@@ -3,30 +3,15 @@
* common.c * common.c
* common routines between pg_dump and pg4_dump * common routines between pg_dump and pg4_dump
* *
* Since pg4_dump is long-dead code, there is no longer any useful distinction
* between this file and pg_dump.c.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.63 2002/04/24 02:44:19 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.64 2002/05/10 22:36:26 tgl Exp $
*
* Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
*
* - Fixed dumpTable output to output lengths for char and varchar types!
* - Added single. quote to twin single quote expansion for 'insert' string
* mode.
*
* Modifications 14-Sep-2000 - pjw@rhyme.com.au
* - Added enum for findTypeByOid to specify how to handle OID and which
* string to return - formatted type, or base type. If the base type
* is returned then fmtId is called on the string.
*
* Modifications 4-Apr-2001 - pjw@rhyme.com.au
* - Changed flagInhAttrs to check all parent tables for overridden settings
* and set flags accordingly.
*
* BEWARE: Since fmtId uses a static buffer, using 'useBaseTypeName' on more
* than one call in a line will cause problems.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -44,255 +29,48 @@ ...@@ -44,255 +29,48 @@
#include "strdup.h" #include "strdup.h"
#endif #endif
static char **findParentsByOid(TableInfo *tbinfo, int numTables, static void findParentsByOid(TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits, InhInfo *inhinfo, int numInherits,
const char *oid, const char *oid,
int *numParents, int *numParentsPtr, int **parentIndexes);
int (**parentIndexes)[]); static void flagInhTables(TableInfo *tbinfo, int numTables,
static int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid); InhInfo *inhinfo, int numInherits);
static void flagInhAttrs(TableInfo *tbinfo, int numTables, static void flagInhAttrs(TableInfo *tbinfo, int numTables,
InhInfo *inhinfo, int numInherits); InhInfo *inhinfo, int numInherits);
static int strInArray(const char *pattern, char **arr, int arr_size); static int strInArray(const char *pattern, char **arr, int arr_size);
/*
* findTypeByOid
* given an oid of a type, return its typename
*
* Can return various special cases for oid 0.
*
* NOTE: should hash this, but just do linear search for now
*/
char *
findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts)
{
int i;
if (strcmp(oid, "0") == 0)
{
if ((opts & zeroAsOpaque) != 0)
return g_opaque_type;
else if ((opts & zeroAsAny) != 0)
return "'any'";
else if ((opts & zeroAsStar) != 0)
return "*";
else if ((opts & zeroAsNone) != 0)
return "NONE";
}
for (i = 0; i < numTypes; i++)
{
if (strcmp(tinfo[i].oid, oid) == 0)
{
if ((opts & useBaseTypeName) != 0)
return (char *) fmtId(tinfo[i].typname, false);
else
return tinfo[i].typedefn;
}
}
/* no suitable type name was found */
return (NULL);
}
/*
* findOprByOid
* given the oid of an operator, return the name of the operator
*
*
* NOTE: should hash this, but just do linear search for now
*
*/
char *
findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
{
int i;
for (i = 0; i < numOprs; i++)
{
if (strcmp(oprinfo[i].oid, oid) == 0)
return oprinfo[i].oprname;
}
/* should never get here */
write_msg(NULL, "failed sanity check, operator with oid %s not found\n", oid);
/* no suitable operator name was found */
return (NULL);
}
/*
* findParentsByOid
* given the oid of a class, return the names of its parent classes
* and assign the number of parents, and parent indexes to the last arguments.
*
*
* returns NULL if none
*/
static char **
findParentsByOid(TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits, const char *oid,
int *numParentsPtr, int (**parentIndexes)[])
{
int i,
j;
int parentInd,
selfInd;
char **result;
int numParents;
numParents = 0;
for (i = 0; i < numInherits; i++)
{
if (strcmp(inhinfo[i].inhrelid, oid) == 0)
numParents++;
}
*numParentsPtr = numParents;
if (numParents > 0)
{
result = (char **) malloc(sizeof(char *) * numParents);
(*parentIndexes) = malloc(sizeof(int) * numParents);
j = 0;
for (i = 0; i < numInherits; i++)
{
if (strcmp(inhinfo[i].inhrelid, oid) == 0)
{
parentInd = findTableByOid(tblinfo, numTables,
inhinfo[i].inhparent);
if (parentInd < 0)
{
selfInd = findTableByOid(tblinfo, numTables, oid);
if (selfInd >= 0)
write_msg(NULL, "failed sanity check, parent oid %s of table %s (oid %s) not found\n",
inhinfo[i].inhparent,
tblinfo[selfInd].relname,
oid);
else
write_msg(NULL, "failed sanity check, parent oid %s of table (oid %s) not found\n",
inhinfo[i].inhparent,
oid);
exit_nicely();
}
(**parentIndexes)[j] = parentInd;
result[j++] = tblinfo[parentInd].relname;
}
}
return result;
}
else
{
(*parentIndexes) = NULL;
return NULL;
}
}
/*
* parseNumericArray
* parse a string of numbers delimited by spaces into a character array
*/
void
parseNumericArray(const char *str, char **array, int arraysize)
{
int j,
argNum;
char temp[100];
char s;
argNum = 0;
j = 0;
for (;;)
{
s = *str++;
if (s == ' ' || s == '\0')
{
if (j > 0)
{
if (argNum >= arraysize)
{
write_msg(NULL, "parseNumericArray: too many numbers\n");
exit_nicely();
}
temp[j] = '\0';
array[argNum++] = strdup(temp);
j = 0;
}
if (s == '\0')
break;
}
else
{
if (!(isdigit((unsigned char) s) || s == '-') ||
j >= sizeof(temp) - 1)
{
write_msg(NULL, "parseNumericArray: bogus number\n");
exit_nicely();
}
temp[j++] = s;
}
}
while (argNum < arraysize)
array[argNum++] = strdup("0");
}
/*
* strInArray:
* takes in a string and a string array and the number of elements in the
* string array.
* returns the index if the string is somewhere in the array, -1 otherwise
*
*/
static int
strInArray(const char *pattern, char **arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; i++)
{
if (strcmp(pattern, arr[i]) == 0)
return i;
}
return -1;
}
/* /*
* dumpSchema: * dumpSchema:
* we have a valid connection, we are now going to dump the schema * we have a valid connection, we are now going to dump the schema
* into the file * into the file
*
*/ */
TableInfo * TableInfo *
dumpSchema(Archive *fout, dumpSchema(Archive *fout,
int *numTablesPtr, int *numTablesPtr,
const char *tablename,
const bool aclsSkip, const bool aclsSkip,
const bool oids,
const bool schemaOnly, const bool schemaOnly,
const bool dataOnly) const bool dataOnly)
{ {
int numNamespaces;
int numTypes; int numTypes;
int numFuncs; int numFuncs;
int numTables; int numTables;
int numInherits; int numInherits;
int numAggregates; int numAggregates;
int numOperators; int numOperators;
int numIndexes; NamespaceInfo *nsinfo;
TypeInfo *tinfo = NULL; TypeInfo *tinfo;
FuncInfo *finfo = NULL; FuncInfo *finfo;
AggInfo *agginfo = NULL; AggInfo *agginfo;
TableInfo *tblinfo = NULL; TableInfo *tblinfo;
InhInfo *inhinfo = NULL; InhInfo *inhinfo;
OprInfo *oprinfo = NULL; OprInfo *oprinfo;
IndInfo *indinfo = NULL;
if (g_verbose)
write_msg(NULL, "reading namespaces\n");
nsinfo = getNamespaces(&numNamespaces);
if (g_verbose) if (g_verbose)
write_msg(NULL, "reading user-defined types\n"); write_msg(NULL, "reading user-defined types\n");
...@@ -312,32 +90,40 @@ dumpSchema(Archive *fout, ...@@ -312,32 +90,40 @@ dumpSchema(Archive *fout,
if (g_verbose) if (g_verbose)
write_msg(NULL, "reading user-defined tables\n"); write_msg(NULL, "reading user-defined tables\n");
tblinfo = getTables(&numTables, finfo, numFuncs, tablename); tblinfo = getTables(&numTables);
if (g_verbose)
write_msg(NULL, "reading index information\n");
indinfo = getIndexes(&numIndexes);
if (g_verbose) if (g_verbose)
write_msg(NULL, "reading table inheritance information\n"); write_msg(NULL, "reading table inheritance information\n");
inhinfo = getInherits(&numInherits); inhinfo = getInherits(&numInherits);
/* Link tables to parents, mark parents of target tables interesting */
if (g_verbose) if (g_verbose)
write_msg(NULL, "finding the column names and types for each table\n"); write_msg(NULL, "finding inheritance relationships\n");
flagInhTables(tblinfo, numTables, inhinfo, numInherits);
if (g_verbose)
write_msg(NULL, "reading column info for interesting tables\n");
getTableAttrs(tblinfo, numTables); getTableAttrs(tblinfo, numTables);
if (g_verbose) if (g_verbose)
write_msg(NULL, "flagging inherited columns in subtables\n"); write_msg(NULL, "flagging inherited columns in subtables\n");
flagInhAttrs(tblinfo, numTables, inhinfo, numInherits); flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
if (!tablename && !dataOnly) if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out database comment\n"); write_msg(NULL, "dumping out database comment\n");
dumpDBComment(fout); dumpDBComment(fout);
} }
if (!tablename && fout) if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined namespaces\n");
dumpNamespaces(fout, nsinfo, numNamespaces);
}
if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out user-defined types\n"); write_msg(NULL, "dumping out user-defined types\n");
...@@ -346,63 +132,102 @@ dumpSchema(Archive *fout, ...@@ -346,63 +132,102 @@ dumpSchema(Archive *fout,
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out tables\n"); write_msg(NULL, "dumping out tables\n");
dumpTables(fout, tblinfo, numTables,
dumpTables(fout, tblinfo, numTables, tablename,
aclsSkip, schemaOnly, dataOnly); aclsSkip, schemaOnly, dataOnly);
if (fout && !dataOnly) if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out indexes\n"); write_msg(NULL, "dumping out indexes\n");
dumpIndexes(fout, indinfo, numIndexes, tblinfo, numTables, tablename); dumpIndexes(fout, tblinfo, numTables);
} }
if (!tablename && !dataOnly) if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out user-defined procedural languages\n"); write_msg(NULL, "dumping out user-defined procedural languages\n");
dumpProcLangs(fout, finfo, numFuncs, tinfo, numTypes); dumpProcLangs(fout, finfo, numFuncs);
} }
if (!tablename && !dataOnly) if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out user-defined functions\n"); write_msg(NULL, "dumping out user-defined functions\n");
dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes); dumpFuncs(fout, finfo, numFuncs);
} }
if (!tablename && !dataOnly) if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out user-defined aggregate functions\n"); write_msg(NULL, "dumping out user-defined aggregate functions\n");
dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes); dumpAggs(fout, agginfo, numAggregates);
} }
if (!tablename && !dataOnly) if (!dataOnly)
{ {
if (g_verbose) if (g_verbose)
write_msg(NULL, "dumping out user-defined operators\n"); write_msg(NULL, "dumping out user-defined operators\n");
dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes); dumpOprs(fout, oprinfo, numOperators);
} }
*numTablesPtr = numTables; *numTablesPtr = numTables;
clearAggInfo(agginfo, numAggregates);
clearOprInfo(oprinfo, numOperators);
clearTypeInfo(tinfo, numTypes);
clearFuncInfo(finfo, numFuncs);
clearInhInfo(inhinfo, numInherits);
clearIndInfo(indinfo, numIndexes);
return tblinfo; return tblinfo;
} }
/* flagInhAttrs - /* flagInhTables -
* for each table in tblinfo, flag its inherited attributes * Fill in parentIndexes fields of every target table, and mark
* so when we dump the table out, we don't dump out the inherited attributes * parents of target tables as interesting
* *
* initializes the parentRels field of each table * Note that only direct ancestors of targets are marked interesting.
* This is sufficient; we don't much care whether they inherited their
* attributes or not.
* *
* modifies tblinfo * modifies tblinfo
*/
static void
flagInhTables(TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits)
{
int i,
j;
int numParents;
int *parentIndexes;
for (i = 0; i < numTables; i++)
{
/* Sequences and views never have parents */
if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
tblinfo[i].relkind == RELKIND_VIEW)
continue;
/* Don't bother computing anything for non-target tables, either */
if (!tblinfo[i].dump)
continue;
/* Find all the immediate parent tables */
findParentsByOid(tblinfo, numTables,
inhinfo, numInherits,
tblinfo[i].oid,
&tblinfo[i].numParents,
&tblinfo[i].parentIndexes);
numParents = tblinfo[i].numParents;
parentIndexes = tblinfo[i].parentIndexes;
/* Mark the parents as interesting for getTableAttrs */
for (j = 0; j < numParents; j++)
{
int parentInd = parentIndexes[j];
tblinfo[parentInd].interesting = true;
}
}
}
/* flagInhAttrs -
* for each dumpable table in tblinfo, flag its inherited attributes
* so when we dump the table out, we don't dump out the inherited attributes
* *
* modifies tblinfo
*/ */
static void static void
flagInhAttrs(TableInfo *tblinfo, int numTables, flagInhAttrs(TableInfo *tblinfo, int numTables,
...@@ -413,7 +238,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -413,7 +238,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
k; k;
int parentInd; int parentInd;
int inhAttrInd; int inhAttrInd;
int (*parentIndexes)[]; int numParents;
int *parentIndexes;
bool foundAttr; /* Attr was found in a parent */ bool foundAttr; /* Attr was found in a parent */
bool foundNotNull; /* Attr was NOT NULL in a parent */ bool foundNotNull; /* Attr was NOT NULL in a parent */
bool defaultsMatch; /* All non-empty defaults match */ bool defaultsMatch; /* All non-empty defaults match */
...@@ -421,23 +247,22 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -421,23 +247,22 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
char *attrDef; char *attrDef;
char *inhDef; char *inhDef;
/* for (i = 0; i < numTables; i++)
* we go backwards because the tables in tblinfo are in OID order,
* meaning the subtables are after the parent tables we flag inherited
* attributes from child tables first
*/
for (i = numTables - 1; i >= 0; i--)
{ {
/* Sequences can never have parents, and attr info is undefined */ /* Sequences and views never have parents */
if (tblinfo[i].relkind == RELKIND_SEQUENCE) if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
tblinfo[i].relkind == RELKIND_VIEW)
continue; continue;
/* Get all the parents and their indexes. */ /* Don't bother computing anything for non-target tables, either */
tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables, if (!tblinfo[i].dump)
inhinfo, numInherits, continue;
tblinfo[i].oid,
&tblinfo[i].numParents, numParents = tblinfo[i].numParents;
&parentIndexes); parentIndexes = tblinfo[i].parentIndexes;
if (numParents == 0)
continue; /* nothing to see here, move along */
/* /*
* For each attr, check the parent info: if no parent has an attr * For each attr, check the parent info: if no parent has an attr
...@@ -459,18 +284,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -459,18 +284,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
attrDef = tblinfo[i].adef_expr[j]; attrDef = tblinfo[i].adef_expr[j];
for (k = 0; k < tblinfo[i].numParents; k++) for (k = 0; k < numParents; k++)
{
parentInd = (*parentIndexes)[k];
if (parentInd < 0)
{ {
/* shouldn't happen unless findParentsByOid is broken */ parentInd = parentIndexes[k];
write_msg(NULL, "failed sanity check, table \"%s\" not found by flagInhAttrs\n",
tblinfo[i].parentRels[k]);
exit_nicely();
};
inhAttrInd = strInArray(tblinfo[i].attnames[j], inhAttrInd = strInArray(tblinfo[i].attnames[j],
tblinfo[parentInd].attnames, tblinfo[parentInd].attnames,
tblinfo[parentInd].numatts); tblinfo[parentInd].numatts);
...@@ -479,7 +295,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -479,7 +295,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
{ {
foundAttr = true; foundAttr = true;
foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd]; foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
if (attrDef != NULL) /* It we have a default, if (attrDef != NULL) /* If we have a default,
* check parent */ * check parent */
{ {
inhDef = tblinfo[parentInd].adef_expr[inhAttrInd]; inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
...@@ -488,10 +304,10 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -488,10 +304,10 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
{ {
defaultsFound = true; defaultsFound = true;
defaultsMatch &= (strcmp(attrDef, inhDef) == 0); defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
}; }
}; }
}; }
}; }
/* /*
* Based on the scan of the parents, decide if we can rely on * Based on the scan of the parents, decide if we can rely on
...@@ -500,9 +316,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -500,9 +316,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
if (foundAttr) /* Attr was inherited */ if (foundAttr) /* Attr was inherited */
{ {
/* Set inherited flag by default */ /* Set inherited flag by default */
tblinfo[i].inhAttrs[j] = 1; tblinfo[i].inhAttrs[j] = true;
tblinfo[i].inhAttrDef[j] = 1; tblinfo[i].inhAttrDef[j] = true;
tblinfo[i].inhNotNull[j] = 1; tblinfo[i].inhNotNull[j] = true;
/* /*
* Clear it if attr had a default, but parents did not, or * Clear it if attr had a default, but parents did not, or
...@@ -510,8 +326,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -510,8 +326,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
*/ */
if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch)) if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
{ {
tblinfo[i].inhAttrs[j] = 0; tblinfo[i].inhAttrs[j] = false;
tblinfo[i].inhAttrDef[j] = 0; tblinfo[i].inhAttrDef[j] = false;
} }
/* /*
...@@ -520,8 +336,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -520,8 +336,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
*/ */
if (tblinfo[i].notnull[j] && !foundNotNull) if (tblinfo[i].notnull[j] && !foundNotNull)
{ {
tblinfo[i].inhAttrs[j] = 0; tblinfo[i].inhAttrs[j] = false;
tblinfo[i].inhNotNull[j] = 0; tblinfo[i].inhNotNull[j] = false;
} }
} }
} }
...@@ -530,64 +346,199 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -530,64 +346,199 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
/* /*
* findTableByName * findTableByOid
* finds the index (in tblinfo) of the table with the given relname * finds the index (in tblinfo) of the table with the given oid
* returns -1 if not found * returns -1 if not found
* *
* NOTE: should hash this, but just do linear search for now * NOTE: should hash this, but just do linear search for now
*/ */
int int
findTableByName(TableInfo *tblinfo, int numTables, const char *relname) findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
{ {
int i; int i;
for (i = 0; i < numTables; i++) for (i = 0; i < numTables; i++)
{ {
if (strcmp(tblinfo[i].relname, relname) == 0) if (strcmp(tblinfo[i].oid, oid) == 0)
return i; return i;
} }
return -1; return -1;
} }
/* /*
* findTableByOid * findFuncByOid
* finds the index (in tblinfo) of the table with the given oid * finds the index (in finfo) of the function with the given OID
* returns -1 if not found * returns -1 if not found
* *
* NOTE: should hash this, but just do linear search for now * NOTE: should hash this, but just do linear search for now
*/ */
int
static int findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
{ {
int i; int i;
for (i = 0; i < numTables; i++) for (i = 0; i < numFuncs; i++)
{ {
if (strcmp(tblinfo[i].oid, oid) == 0) if (strcmp(finfo[i].oid, oid) == 0)
return i; return i;
} }
return -1; return -1;
} }
/* /*
* findFuncByName * findOprByOid
* finds the index (in finfo) of the function with the given name * given the oid of an operator, return the name of the operator
* returns -1 if not found
* *
* NOTE: should hash this, but just do linear search for now * NOTE: should hash this, but just do linear search for now
*/ */
char *
findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
{
int i;
int for (i = 0; i < numOprs; i++)
findFuncByName(FuncInfo *finfo, int numFuncs, const char *name) {
if (strcmp(oprinfo[i].oid, oid) == 0)
return oprinfo[i].oprname;
}
/* should never get here */
write_msg(NULL, "failed sanity check, operator with oid %s not found\n", oid);
/* no suitable operator name was found */
return (NULL);
}
/*
* findParentsByOid
* given the oid of a class, find its parent classes in tblinfo[]
*
* Returns the number of parents and their array indexes into the
* last two arguments.
*/
static void
findParentsByOid(TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits,
const char *oid,
int *numParentsPtr, int **parentIndexes)
{
int i,
j;
int parentInd,
selfInd;
int numParents;
numParents = 0;
for (i = 0; i < numInherits; i++)
{
if (strcmp(inhinfo[i].inhrelid, oid) == 0)
numParents++;
}
*numParentsPtr = numParents;
if (numParents > 0)
{
*parentIndexes = (int *) malloc(sizeof(int) * numParents);
j = 0;
for (i = 0; i < numInherits; i++)
{
if (strcmp(inhinfo[i].inhrelid, oid) == 0)
{
parentInd = findTableByOid(tblinfo, numTables,
inhinfo[i].inhparent);
if (parentInd < 0)
{
selfInd = findTableByOid(tblinfo, numTables, oid);
if (selfInd >= 0)
write_msg(NULL, "failed sanity check, parent oid %s of table %s (oid %s) not found\n",
inhinfo[i].inhparent,
tblinfo[selfInd].relname,
oid);
else
write_msg(NULL, "failed sanity check, parent oid %s of table (oid %s) not found\n",
inhinfo[i].inhparent,
oid);
exit_nicely();
}
(*parentIndexes)[j++] = parentInd;
}
}
}
else
*parentIndexes = NULL;
}
/*
* parseNumericArray
* parse a string of numbers delimited by spaces into a character array
*/
void
parseNumericArray(const char *str, char **array, int arraysize)
{
int j,
argNum;
char temp[100];
char s;
argNum = 0;
j = 0;
for (;;)
{
s = *str++;
if (s == ' ' || s == '\0')
{
if (j > 0)
{
if (argNum >= arraysize)
{
write_msg(NULL, "parseNumericArray: too many numbers\n");
exit_nicely();
}
temp[j] = '\0';
array[argNum++] = strdup(temp);
j = 0;
}
if (s == '\0')
break;
}
else
{
if (!(isdigit((unsigned char) s) || s == '-') ||
j >= sizeof(temp) - 1)
{
write_msg(NULL, "parseNumericArray: bogus number\n");
exit_nicely();
}
temp[j++] = s;
}
}
while (argNum < arraysize)
array[argNum++] = strdup("0");
}
/*
* strInArray:
* takes in a string and a string array and the number of elements in the
* string array.
* returns the index if the string is somewhere in the array, -1 otherwise
*/
static int
strInArray(const char *pattern, char **arr, int arr_size)
{ {
int i; int i;
for (i = 0; i < numFuncs; i++) for (i = 0; i < arr_size; i++)
{ {
if (strcmp(finfo[i].proname, name) == 0) if (strcmp(pattern, arr[i]) == 0)
return i; return i;
} }
return -1; return -1;
......
...@@ -15,27 +15,7 @@ ...@@ -15,27 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.18 2002/02/11 00:18:20 tgl Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.19 2002/05/10 22:36:26 tgl Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
*
* Initial version.
*
*
* Modifications - 28-Jul-2000 - pjw@rhyme.com.au (1.45)
*
* Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
* Added code to dump 'Create Schema' statement (pg_dump)
* Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
* Cleaned up code for reconnecting to database.
* Force a reconnect as superuser before enabling/disabling triggers.
*
* Modifications - 31-Jul-2000 - pjw@rhyme.com.au (1.46, 1.47)
* Added & Removed --throttle (pg_dump)
* Fixed minor bug in language dumping code: expbuffres were not being reset.
* Fixed version number initialization in _allocAH (pg_backup_archiver.c)
* Added second connection when restoring BLOBs to allow temp. table to survive
* (db reconnection causes temp tables to be lost).
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -87,6 +67,7 @@ typedef struct _restoreOptions ...@@ -87,6 +67,7 @@ typedef struct _restoreOptions
* cirsumstances */ * cirsumstances */
int use_setsessauth;/* use SET SESSSION AUTHORIZATION instead int use_setsessauth;/* use SET SESSSION AUTHORIZATION instead
* of \connect */ * of \connect */
int disable_triggers;/* disable triggers during data-only restore */
char *superuser; /* Username to use as superuser */ char *superuser; /* Username to use as superuser */
int dataOnly; int dataOnly;
int dropSchema; int dropSchema;
...@@ -152,9 +133,11 @@ PGconn *ConnectDatabase(Archive *AH, ...@@ -152,9 +133,11 @@ PGconn *ConnectDatabase(Archive *AH,
/* Called to add a TOC entry */ /* Called to add a TOC entry */
extern void ArchiveEntry(Archive *AH, const char *oid, const char *name, extern void ArchiveEntry(Archive *AHX, const char *oid, const char *name,
const char *desc, const char *((*deps)[]), const char *defn, const char *namespace, const char *owner,
const char *dropStmt, const char *copyStmt, const char *owner, const char *desc, const char *((*deps)[]),
const char *defn, const char *dropStmt,
const char *copyStmt,
DataDumperPtr dumpFn, void *dumpArg); DataDumperPtr dumpFn, void *dumpArg);
/* Called to write *data* to the archive */ /* Called to write *data* to the archive */
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.45 2002/05/06 17:34:45 tgl Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.46 2002/05/10 22:36:26 tgl Exp $
* *
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* *
...@@ -95,8 +95,10 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt, ...@@ -95,8 +95,10 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
const int compression, ArchiveMode mode); const int compression, ArchiveMode mode);
static int _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData); static int _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData);
static void _doSetSessionAuth(ArchiveHandle *AH, const char *autharg);
static void _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te); static void _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te);
static void _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user); static void _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user);
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt); static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt);
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
...@@ -208,23 +210,13 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) ...@@ -208,23 +210,13 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
AHX->minRemoteVersion = 070100; AHX->minRemoteVersion = 070100;
AHX->maxRemoteVersion = 999999; AHX->maxRemoteVersion = 999999;
ConnectDatabase(AHX, ropt->dbname, ropt->pghost, ropt->pgport, ropt->username, ConnectDatabase(AHX, ropt->dbname,
ropt->pghost, ropt->pgport, ropt->username,
ropt->requirePassword, ropt->ignoreVersion); ropt->requirePassword, ropt->ignoreVersion);
/*
* If no superuser was specified then see if the current user will
* do...
*/
if (!ropt->superuser)
{
if (UserIsSuperuser(AH, ConnectedUser(AH)))
ropt->superuser = strdup(ConnectedUser(AH));
}
} }
/* /*
* Work out if we have an implied data-only retore. This can happen if * 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 * 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 * exclude all of the schema data. All we do is look for schema
* entries - if none are found then we set the dataOnly flag. * entries - if none are found then we set the dataOnly flag.
...@@ -253,12 +245,6 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) ...@@ -253,12 +245,6 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
} }
} }
if (!ropt->superuser)
write_msg(modulename, "WARNING:\n"
" Data restoration may fail because existing triggers cannot be disabled\n"
" (no superuser user name specified). This is only a problem when\n"
" restoring into a database with already existing triggers.\n");
/* /*
* Setup the output file if necessary. * Setup the output file if necessary.
*/ */
...@@ -280,8 +266,9 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) ...@@ -280,8 +266,9 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
{ {
/* We want the schema */ /* We want the schema */
ahlog(AH, 1, "dropping %s %s\n", te->desc, te->name); ahlog(AH, 1, "dropping %s %s\n", te->desc, te->name);
/* Reconnect if necessary */ /* Select owner and schema as necessary */
_reconnectAsOwner(AH, NULL, te); _reconnectAsOwner(AH, NULL, te);
_selectOutputSchema(AH, te->namespace);
/* Drop it */ /* Drop it */
ahprintf(AH, "%s", te->dropStmt); ahprintf(AH, "%s", te->dropStmt);
} }
...@@ -376,6 +363,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) ...@@ -376,6 +363,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
* have reconnected) * have reconnected)
*/ */
_reconnectAsOwner(AH, NULL, te); _reconnectAsOwner(AH, NULL, te);
_selectOutputSchema(AH, te->namespace);
ahlog(AH, 1, "restoring data for table %s\n", te->name); ahlog(AH, 1, "restoring data for table %s\n", te->name);
...@@ -433,7 +421,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) ...@@ -433,7 +421,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
if ((reqs & REQ_DATA) != 0) /* We loaded the data */ if ((reqs & REQ_DATA) != 0) /* We loaded the data */
{ {
ahlog(AH, 1, "fixing up large object cross-reference for %s\n", te->name); ahlog(AH, 1, "fixing up large object cross-reference for %s\n", te->name);
FixupBlobRefs(AH, te->name); FixupBlobRefs(AH, te);
} }
} }
else else
...@@ -501,30 +489,31 @@ _canRestoreBlobs(ArchiveHandle *AH) ...@@ -501,30 +489,31 @@ _canRestoreBlobs(ArchiveHandle *AH)
static void static void
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt) _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{ {
char *oldUser = NULL; char *oldUser;
char *oldSchema;
/* Can't do much if we're connected & don't have a superuser */ /* This hack is only needed in a data-only restore */
/* Also, don't bother with triggers unless a data-only retore. */ if (!ropt->dataOnly || !ropt->disable_triggers)
if (!ropt->dataOnly || (_restoringToDB(AH) && !ropt->superuser))
return; return;
oldUser = strdup(AH->currUser);
oldSchema = strdup(AH->currSchema);
/* /*
* Reconnect as superuser if possible, since they are the only ones * Become superuser if possible, since they are the only ones
* who can update pg_class... * who can update pg_class. If -S was not given, but we are allowed
* to use SET SESSION AUTHORIZATION, assume the initial user identity
* is a superuser. Otherwise we just have to bull ahead anyway.
*/ */
if (ropt->superuser) if (ropt->superuser)
{ {
if (!_restoringToDB(AH) || !ConnectedUserIsSuperuser(AH))
{
/*
* If we're not allowing changes for ownership, then remember
* the user so we can change it back here. Otherwise, let
* _reconnectAsOwner do what it has to do.
*/
if (ropt->noOwner)
oldUser = strdup(ConnectedUser(AH));
_reconnectAsUser(AH, NULL, ropt->superuser); _reconnectAsUser(AH, NULL, ropt->superuser);
/* be careful to preserve schema setting */
_selectOutputSchema(AH, oldSchema);
} }
else if (AH->ropt->use_setsessauth)
{
_doSetSessionAuth(AH, "DEFAULT");
} }
ahlog(AH, 1, "disabling triggers\n"); ahlog(AH, 1, "disabling triggers\n");
...@@ -538,52 +527,59 @@ _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *rop ...@@ -538,52 +527,59 @@ _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *rop
/* /*
* Just update the AFFECTED table, if known. * Just update the AFFECTED table, if known.
*/ */
if (te && te->name && strlen(te->name) > 0) if (te && te->name && strlen(te->name) > 0)
ahprintf(AH, "UPDATE \"pg_class\" SET \"reltriggers\" = 0 WHERE \"relname\" = '%s';\n\n", ahprintf(AH, "UPDATE pg_class SET reltriggers = 0 "
te->name); "WHERE oid = '%s'::regclass;\n\n",
fmtId(te->name, false));
else else
ahprintf(AH, "UPDATE \"pg_class\" SET \"reltriggers\" = 0 WHERE \"relname\" !~ '^pg_';\n\n"); ahprintf(AH, "UPDATE pg_class SET reltriggers = 0 FROM pg_namespace "
"WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
/* /*
* Restore the user connection from the start of this procedure if * Restore original user and schema state.
* _reconnectAsOwner is disabled.
*/ */
if (ropt->noOwner && oldUser) if (ropt->superuser)
{ {
_reconnectAsUser(AH, NULL, oldUser); _reconnectAsUser(AH, NULL, oldUser);
free(oldUser); /* be careful to preserve schema setting */
_selectOutputSchema(AH, oldSchema);
}
else if (AH->ropt->use_setsessauth)
{
_doSetSessionAuth(AH, fmtId(oldUser, false));
} }
free(oldUser);
free(oldSchema);
} }
static void static void
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt) _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
{ {
char *oldUser = NULL; char *oldUser;
char *oldSchema;
/* Can't do much if we're connected & don't have a superuser */ /* This hack is only needed in a data-only restore */
/* Also, don't bother with triggers unless a data-only retore. */ if (!ropt->dataOnly || !ropt->disable_triggers)
if (!ropt->dataOnly || (_restoringToDB(AH) && !ropt->superuser))
return; return;
oldUser = strdup(AH->currUser);
oldSchema = strdup(AH->currSchema);
/* /*
* Reconnect as superuser if possible, since they are the only ones * Become superuser if possible, since they are the only ones
* who can update pg_class... * who can update pg_class. If -S was not given, but we are allowed
* to use SET SESSION AUTHORIZATION, assume the initial user identity
* is a superuser. Otherwise we just have to bull ahead anyway.
*/ */
if (ropt->superuser) if (ropt->superuser)
{ {
if (!_restoringToDB(AH) || !ConnectedUserIsSuperuser(AH))
{
/*
* If we're not allowing changes for ownership, then remember
* the user so we can change it back here. Otherwise, let
* _reconnectAsOwner do what it has to do
*/
if (ropt->noOwner)
oldUser = strdup(ConnectedUser(AH));
_reconnectAsUser(AH, NULL, ropt->superuser); _reconnectAsUser(AH, NULL, ropt->superuser);
/* be careful to preserve schema setting */
_selectOutputSchema(AH, oldSchema);
} }
else if (AH->ropt->use_setsessauth)
{
_doSetSessionAuth(AH, "DEFAULT");
} }
ahlog(AH, 1, "enabling triggers\n"); ahlog(AH, 1, "enabling triggers\n");
...@@ -593,29 +589,36 @@ _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt ...@@ -593,29 +589,36 @@ _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt
* 'SET' command when one is available. * 'SET' command when one is available.
*/ */
ahprintf(AH, "-- Enable triggers\n"); ahprintf(AH, "-- Enable triggers\n");
/*
* Just update the AFFECTED table, if known.
*/
if (te && te->name && strlen(te->name) > 0) if (te && te->name && strlen(te->name) > 0)
{
ahprintf(AH, "UPDATE pg_class SET reltriggers = " ahprintf(AH, "UPDATE pg_class SET reltriggers = "
"(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) " "(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) "
"WHERE relname = '%s';\n\n", "WHERE oid = '%s'::regclass;\n\n",
te->name); fmtId(te->name, false));
}
else else
{ ahprintf(AH, "UPDATE pg_class SET reltriggers = "
ahprintf(AH, "UPDATE \"pg_class\" SET \"reltriggers\" = "
"(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) " "(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) "
"WHERE \"relname\" !~ '^pg_';\n\n"); "FROM pg_namespace "
} "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
/* /*
* Restore the user connection from the start of this procedure if * Restore original user and schema state.
* _reconnectAsOwner is disabled.
*/ */
if (ropt->noOwner && oldUser) if (ropt->superuser)
{ {
_reconnectAsUser(AH, NULL, oldUser); _reconnectAsUser(AH, NULL, oldUser);
free(oldUser); /* be careful to preserve schema setting */
_selectOutputSchema(AH, oldSchema);
}
else if (AH->ropt->use_setsessauth)
{
_doSetSessionAuth(AH, fmtId(oldUser, false));
} }
free(oldUser);
free(oldSchema);
} }
/* /*
...@@ -642,8 +645,10 @@ WriteData(Archive *AHX, const void *data, int dLen) ...@@ -642,8 +645,10 @@ WriteData(Archive *AHX, const void *data, int dLen)
/* Public */ /* Public */
void void
ArchiveEntry(Archive *AHX, const char *oid, const char *name, ArchiveEntry(Archive *AHX, const char *oid, const char *name,
const char *desc, const char *((*deps)[]), const char *defn, const char *namespace, const char *owner,
const char *dropStmt, const char *copyStmt, const char *owner, const char *desc, const char *((*deps)[]),
const char *defn, const char *dropStmt,
const char *copyStmt,
DataDumperPtr dumpFn, void *dumpArg) DataDumperPtr dumpFn, void *dumpArg)
{ {
ArchiveHandle *AH = (ArchiveHandle *) AHX; ArchiveHandle *AH = (ArchiveHandle *) AHX;
...@@ -664,20 +669,20 @@ ArchiveEntry(Archive *AHX, const char *oid, const char *name, ...@@ -664,20 +669,20 @@ ArchiveEntry(Archive *AHX, const char *oid, const char *name,
newToc->id = AH->lastID; newToc->id = AH->lastID;
newToc->name = strdup(name); newToc->name = strdup(name);
newToc->namespace = namespace ? strdup(namespace) : NULL;
newToc->owner = strdup(owner);
newToc->desc = strdup(desc); newToc->desc = strdup(desc);
newToc->defn = strdup(defn);
newToc->dropStmt = strdup(dropStmt);
newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
newToc->oid = strdup(oid); newToc->oid = strdup(oid);
newToc->depOid = deps; newToc->depOid = deps; /* NB: not copied */
_fixupOidInfo(newToc); _fixupOidInfo(newToc);
newToc->defn = strdup(defn);
newToc->dropStmt = strdup(dropStmt);
newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
newToc->owner = strdup(owner);
newToc->printed = 0; newToc->printed = 0;
newToc->formatData = NULL; newToc->formatData = NULL;
newToc->dataDumper = dumpFn, newToc->dataDumper = dumpFn;
newToc->dataDumperArg = dumpArg; newToc->dataDumperArg = dumpArg;
newToc->hadDumper = dumpFn ? 1 : 0; newToc->hadDumper = dumpFn ? 1 : 0;
...@@ -1667,6 +1672,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt, ...@@ -1667,6 +1672,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
AH->currUser = strdup(""); /* So it's valid, but we can free() it AH->currUser = strdup(""); /* So it's valid, but we can free() it
* later if necessary */ * later if necessary */
AH->currSchema = strdup(""); /* ditto */
AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry)); AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
if (!AH->toc) if (!AH->toc)
...@@ -1789,6 +1795,7 @@ WriteToc(ArchiveHandle *AH) ...@@ -1789,6 +1795,7 @@ WriteToc(ArchiveHandle *AH)
WriteStr(AH, te->defn); WriteStr(AH, te->defn);
WriteStr(AH, te->dropStmt); WriteStr(AH, te->dropStmt);
WriteStr(AH, te->copyStmt); WriteStr(AH, te->copyStmt);
WriteStr(AH, te->namespace);
WriteStr(AH, te->owner); WriteStr(AH, te->owner);
/* Dump list of dependencies */ /* Dump list of dependencies */
...@@ -1840,6 +1847,9 @@ ReadToc(ArchiveHandle *AH) ...@@ -1840,6 +1847,9 @@ ReadToc(ArchiveHandle *AH)
if (AH->version >= K_VERS_1_3) if (AH->version >= K_VERS_1_3)
te->copyStmt = ReadStr(AH); te->copyStmt = ReadStr(AH);
if (AH->version >= K_VERS_1_6)
te->namespace = ReadStr(AH);
te->owner = ReadStr(AH); te->owner = ReadStr(AH);
/* Read TOC entry dependencies */ /* Read TOC entry dependencies */
...@@ -1975,6 +1985,33 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt) ...@@ -1975,6 +1985,33 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
return res; return res;
} }
/*
* Issue a SET SESSION AUTHORIZATION command. Caller is responsible
* for updating state if appropriate. Note that caller must also quote
* the argument if it's a username (it might be DEFAULT, too).
*/
static void
_doSetSessionAuth(ArchiveHandle *AH, const char *autharg)
{
if (RestoringToDB(AH))
{
PQExpBuffer qry = createPQExpBuffer();
PGresult *res;
appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION %s;", autharg);
res = PQexec(AH->connection, qry->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
die_horribly(AH, modulename, "could not set session user to %s: %s",
autharg, PQerrorMessage(AH->connection));
PQclear(res);
destroyPQExpBuffer(qry);
}
else
ahprintf(AH, "SET SESSION AUTHORIZATION %s;\n\n", autharg);
}
/* /*
* Issue the commands to connect to the database as the specified user * Issue the commands to connect to the database as the specified user
...@@ -1999,25 +2036,7 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user) ...@@ -1999,25 +2036,7 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
*/ */
if (!dbname && AH->ropt->use_setsessauth) if (!dbname && AH->ropt->use_setsessauth)
{ {
if (RestoringToDB(AH)) _doSetSessionAuth(AH, fmtId(user, false));
{
PQExpBuffer qry = createPQExpBuffer();
PGresult *res;
appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION %s;",
fmtId(user, false));
res = PQexec(AH->connection, qry->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
die_horribly(AH, modulename, "could not set session user to %s: %s",
user, PQerrorMessage(AH->connection));
PQclear(res);
destroyPQExpBuffer(qry);
}
else
ahprintf(AH, "SET SESSION AUTHORIZATION %s;\n\n",
fmtId(user, false));
} }
else if (AH->ropt && AH->ropt->noReconnect) else if (AH->ropt && AH->ropt->noReconnect)
{ {
...@@ -2038,6 +2057,11 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user) ...@@ -2038,6 +2057,11 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
ahprintf(AH, qry->data); ahprintf(AH, qry->data);
destroyPQExpBuffer(qry); destroyPQExpBuffer(qry);
/* don't assume we still know the output schema */
if (AH->currSchema)
free(AH->currSchema);
AH->currSchema = strdup("");
} }
/* /*
...@@ -2066,6 +2090,43 @@ _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te) ...@@ -2066,6 +2090,43 @@ _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te)
} }
/*
* Issue the commands to select the specified schema as the current schema
* in the target database.
*/
static void
_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
{
if (!schemaName || *schemaName == '\0' ||
strcmp(AH->currSchema, schemaName) == 0)
return; /* no need to do anything */
if (RestoringToDB(AH))
{
PQExpBuffer qry = createPQExpBuffer();
PGresult *res;
appendPQExpBuffer(qry, "SET search_path = %s;",
fmtId(schemaName, false));
res = PQexec(AH->connection, qry->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
die_horribly(AH, modulename, "could not set search_path to %s: %s",
schemaName, PQerrorMessage(AH->connection));
PQclear(res);
destroyPQExpBuffer(qry);
}
else
ahprintf(AH, "SET search_path = %s;\n\n",
fmtId(schemaName, false));
if (AH->currSchema)
free(AH->currSchema);
AH->currSchema = strdup(schemaName);
}
/* /*
* fmtId * fmtId
* *
...@@ -2139,16 +2200,19 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat ...@@ -2139,16 +2200,19 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
{ {
char *pfx; char *pfx;
/* Reconnect if necessary */ /* Select owner and schema as necessary */
_reconnectAsOwner(AH, NULL, te); _reconnectAsOwner(AH, NULL, te);
_selectOutputSchema(AH, te->namespace);
if (isData) if (isData)
pfx = "Data for "; pfx = "Data for ";
else else
pfx = ""; pfx = "";
ahprintf(AH, "--\n-- %sTOC Entry ID %d (OID %s)\n--\n-- Name: %s Type: %s Owner: %s\n", ahprintf(AH, "--\n-- %sTOC Entry ID %d (OID %s)\n--\n-- Name: %s Type: %s Schema: %s Owner: %s\n",
pfx, te->id, te->oid, te->name, te->desc, te->owner); pfx, te->id, te->oid, te->name, te->desc,
te->namespace ? te->namespace : "-",
te->owner);
if (AH->PrintExtraTocPtr !=NULL) if (AH->PrintExtraTocPtr !=NULL)
(*AH->PrintExtraTocPtr) (AH, te); (*AH->PrintExtraTocPtr) (AH, te);
ahprintf(AH, "--\n\n"); ahprintf(AH, "--\n\n");
......
...@@ -17,17 +17,7 @@ ...@@ -17,17 +17,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.42 2002/04/24 02:21:04 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.43 2002/05/10 22:36:26 tgl Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* - Initial version.
*
* Modifications - 15-Sep-2000 - pjw@rhyme.com.au
* - Added braceDepth to sqlparseInfo to handle braces in rule definitions.
*
* Modifications - 31-Mar-2001 - pjw@rhyme.com.au (1.50)
* - Make dependencies work on ArchiveEntry calls so that UDTs will
* dump in correct order.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -68,8 +58,8 @@ typedef z_stream *z_streamp; ...@@ -68,8 +58,8 @@ typedef z_stream *z_streamp;
#include "libpq-fe.h" #include "libpq-fe.h"
#define K_VERS_MAJOR 1 #define K_VERS_MAJOR 1
#define K_VERS_MINOR 5 #define K_VERS_MINOR 6
#define K_VERS_REV 7 #define K_VERS_REV 0
/* Data block types */ /* Data block types */
#define BLK_DATA 1 #define BLK_DATA 1
...@@ -82,7 +72,8 @@ typedef z_stream *z_streamp; ...@@ -82,7 +72,8 @@ typedef z_stream *z_streamp;
#define K_VERS_1_3 (( (1 * 256 + 3) * 256 + 0) * 256 + 0) /* BLOBs */ #define K_VERS_1_3 (( (1 * 256 + 3) * 256 + 0) * 256 + 0) /* BLOBs */
#define K_VERS_1_4 (( (1 * 256 + 4) * 256 + 0) * 256 + 0) /* Date & name in header */ #define K_VERS_1_4 (( (1 * 256 + 4) * 256 + 0) * 256 + 0) /* Date & name in header */
#define K_VERS_1_5 (( (1 * 256 + 5) * 256 + 0) * 256 + 0) /* Handle dependencies */ #define K_VERS_1_5 (( (1 * 256 + 5) * 256 + 0) * 256 + 0) /* Handle dependencies */
#define K_VERS_MAX (( (1 * 256 + 5) * 256 + 255) * 256 + 0) #define K_VERS_1_6 (( (1 * 256 + 6) * 256 + 0) * 256 + 0) /* Schema field in TOCs */
#define K_VERS_MAX (( (1 * 256 + 6) * 256 + 255) * 256 + 0)
/* No of BLOBs to restore in 1 TX */ /* No of BLOBs to restore in 1 TX */
#define BLOB_BATCH_SIZE 100 #define BLOB_BATCH_SIZE 100
...@@ -235,6 +226,7 @@ typedef struct _archiveHandle ...@@ -235,6 +226,7 @@ typedef struct _archiveHandle
int tocCount; /* Number of TOC entries */ int tocCount; /* Number of TOC entries */
struct _tocEntry *currToc; /* Used when dumping data */ struct _tocEntry *currToc; /* Used when dumping data */
char *currUser; /* Restore: current username in script */ char *currUser; /* Restore: current username in script */
char *currSchema; /* Restore: current schema in script */
int compression; /* Compression requested on open */ int compression; /* Compression requested on open */
ArchiveMode mode; /* File mode - r or w */ ArchiveMode mode; /* File mode - r or w */
void *formatData; /* Header data specific to file format */ void *formatData; /* Header data specific to file format */
...@@ -254,11 +246,12 @@ typedef struct _tocEntry ...@@ -254,11 +246,12 @@ typedef struct _tocEntry
int hadDumper; /* Archiver was passed a dumper routine int hadDumper; /* Archiver was passed a dumper routine
* (used in restore) */ * (used in restore) */
char *name; char *name;
char *namespace; /* null or empty string if not in a schema */
char *owner;
char *desc; char *desc;
char *defn; char *defn;
char *dropStmt; char *dropStmt;
char *copyStmt; char *copyStmt;
char *owner;
char *oid; /* Oid of source of entry */ char *oid; /* Oid of source of entry */
Oid oidVal; /* Value of above */ Oid oidVal; /* Value of above */
const char *((*depOid)[]); const char *((*depOid)[]);
...@@ -314,9 +307,6 @@ extern OutputContext SetOutput(ArchiveHandle *AH, char *filename, int compressio ...@@ -314,9 +307,6 @@ extern OutputContext SetOutput(ArchiveHandle *AH, char *filename, int compressio
extern void ResetOutput(ArchiveHandle *AH, OutputContext savedContext); extern void ResetOutput(ArchiveHandle *AH, OutputContext savedContext);
extern int RestoringToDB(ArchiveHandle *AH); extern int RestoringToDB(ArchiveHandle *AH);
extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser); extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
extern int UserIsSuperuser(ArchiveHandle *AH, char *user);
extern char *ConnectedUser(ArchiveHandle *AH);
extern int ConnectedUserIsSuperuser(ArchiveHandle *AH);
int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH); int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
int ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3))); int ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3)));
......
...@@ -5,25 +5,7 @@ ...@@ -5,25 +5,7 @@
* Implements the basic DB functions used by the archiver. * Implements the basic DB functions used by the archiver.
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.31 2002/01/18 19:17:05 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.32 2002/05/10 22:36:26 tgl Exp $
*
* NOTES
*
* Modifications - 04-Jan-2001 - pjw@rhyme.com.au
*
* - Check results of PQ routines more carefully.
*
* Modifications - 19-Mar-2001 - pjw@rhyme.com.au
*
* - Avoid forcing table name to lower case in FixupBlobXrefs!
*
*
* Modifications - 18-Jan-2002 - pjw@rhyme.com.au
*
* - Split ExecuteSqlCommandBuf into 3 routines for (slightly) improved
* clarity. Modify loop to cater for COPY commands buried in the SQL
* command buffer (prev version assumed COPY command was executed
* in prior call). This was to fix the buf in the 'set max oid' code.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -219,57 +201,6 @@ _check_database_version(ArchiveHandle *AH, bool ignoreVersion) ...@@ -219,57 +201,6 @@ _check_database_version(ArchiveHandle *AH, bool ignoreVersion)
} }
} }
/*
* Check if a given user is a superuser.
*/
int
UserIsSuperuser(ArchiveHandle *AH, char *user)
{
PQExpBuffer qry = createPQExpBuffer();
PGresult *res;
int i_usesuper;
int ntups;
int isSuper;
/* Get the superuser setting */
appendPQExpBuffer(qry, "select usesuper from pg_user where usename = '%s'", user);
res = PQexec(AH->connection, qry->data);
if (!res)
die_horribly(AH, modulename, "null result checking superuser status of %s\n", user);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
die_horribly(AH, modulename, "could not check superuser status of %s: %s",
user, PQerrorMessage(AH->connection));
ntups = PQntuples(res);
if (ntups == 0)
isSuper = 0;
else
{
i_usesuper = PQfnumber(res, "usesuper");
isSuper = (strcmp(PQgetvalue(res, 0, i_usesuper), "t") == 0);
}
PQclear(res);
destroyPQExpBuffer(qry);
return isSuper;
}
int
ConnectedUserIsSuperuser(ArchiveHandle *AH)
{
return UserIsSuperuser(AH, PQuser(AH->connection));
}
char *
ConnectedUser(ArchiveHandle *AH)
{
return PQuser(AH->connection);
}
/* /*
* Reconnect to the server. If dbname is not NULL, use that database, * Reconnect to the server. If dbname is not NULL, use that database,
* else the one associated with the archive handle. If username is * else the one associated with the archive handle. If username is
...@@ -310,6 +241,11 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username) ...@@ -310,6 +241,11 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
AH->username = strdup(newusername); AH->username = strdup(newusername);
/* XXX Why don't we update AH->dbname? */ /* XXX Why don't we update AH->dbname? */
/* don't assume we still know the output schema */
if (AH->currSchema)
free(AH->currSchema);
AH->currSchema = strdup("");
return 1; return 1;
} }
...@@ -481,13 +417,6 @@ ConnectDatabase(Archive *AHX, ...@@ -481,13 +417,6 @@ ConnectDatabase(Archive *AHX,
PQsetNoticeProcessor(AH->connection, notice_processor, NULL); PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
/*
* AH->currUser = PQuser(AH->connection);
*
* Removed because it prevented an initial \connect when dumping to SQL
* in pg_dump.
*/
return AH->connection; return AH->connection;
} }
...@@ -775,8 +704,9 @@ ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen) ...@@ -775,8 +704,9 @@ ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen)
} }
void void
FixupBlobRefs(ArchiveHandle *AH, char *tablename) FixupBlobRefs(ArchiveHandle *AH, TocEntry *te)
{ {
PQExpBuffer tblName;
PQExpBuffer tblQry; PQExpBuffer tblQry;
PGresult *res, PGresult *res,
*uRes; *uRes;
...@@ -784,44 +714,55 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename) ...@@ -784,44 +714,55 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename)
n; n;
char *attr; char *attr;
if (strcmp(tablename, BLOB_XREF_TABLE) == 0) if (strcmp(te->name, BLOB_XREF_TABLE) == 0)
return; return;
tblName = createPQExpBuffer();
tblQry = createPQExpBuffer(); tblQry = createPQExpBuffer();
appendPQExpBuffer(tblQry, "SELECT a.attname FROM pg_class c, pg_attribute a, pg_type t " if (te->namespace && strlen(te->namespace) > 0)
" WHERE a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid " appendPQExpBuffer(tblName, "%s.",
" AND t.typname in ('oid', 'lo') AND c.relname = '%s';", tablename); fmtId(te->namespace, false));
appendPQExpBuffer(tblName, "%s",
fmtId(te->name, false));
appendPQExpBuffer(tblQry,
"SELECT a.attname FROM "
"pg_catalog.pg_attribute a, pg_catalog.pg_type t "
"WHERE a.attnum > 0 AND a.attrelid = '%s'::regclass "
"AND a.atttypid = t.oid AND t.typname in ('oid', 'lo')",
tblName->data);
res = PQexec(AH->blobConnection, tblQry->data); res = PQexec(AH->blobConnection, tblQry->data);
if (!res) if (!res)
die_horribly(AH, modulename, "could not find oid columns of table \"%s\": %s", die_horribly(AH, modulename, "could not find oid columns of table \"%s\": %s",
tablename, PQerrorMessage(AH->connection)); te->name, PQerrorMessage(AH->connection));
if ((n = PQntuples(res)) == 0) if ((n = PQntuples(res)) == 0)
{ {
/* nothing to do */ /* nothing to do */
ahlog(AH, 1, "no OID type columns in table %s\n", tablename); ahlog(AH, 1, "no OID type columns in table %s\n", te->name);
} }
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
attr = PQgetvalue(res, i, 0); attr = PQgetvalue(res, i, 0);
ahlog(AH, 1, "fixing large object cross-references for %s.%s\n", tablename, attr); ahlog(AH, 1, "fixing large object cross-references for %s.%s\n",
te->name, attr);
resetPQExpBuffer(tblQry); resetPQExpBuffer(tblQry);
/* /* Can't use fmtId twice in one call... */
* We should use coalesce here (rather than 'exists'), but it appendPQExpBuffer(tblQry,
* seems to be broken in 7.0.2 (weird optimizer strategy) "UPDATE %s SET %s = %s.newOid",
*/ tblName->data, fmtId(attr, false),
appendPQExpBuffer(tblQry, "UPDATE \"%s\" SET \"%s\" = ", tablename, attr); BLOB_XREF_TABLE);
appendPQExpBuffer(tblQry, " (SELECT x.newOid FROM \"%s\" x WHERE x.oldOid = \"%s\".\"%s\")", appendPQExpBuffer(tblQry,
BLOB_XREF_TABLE, tablename, attr); " FROM %s WHERE %s.oldOid = %s.%s",
appendPQExpBuffer(tblQry, " where exists" BLOB_XREF_TABLE,
"(select * from %s x where x.oldOid = \"%s\".\"%s\");", BLOB_XREF_TABLE,
BLOB_XREF_TABLE, tablename, attr); tblName->data, fmtId(attr, false));
ahlog(AH, 10, "SQL: %s\n", tblQry->data); ahlog(AH, 10, "SQL: %s\n", tblQry->data);
...@@ -829,17 +770,18 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename) ...@@ -829,17 +770,18 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename)
if (!uRes) if (!uRes)
die_horribly(AH, modulename, die_horribly(AH, modulename,
"could not update column \"%s\" of table \"%s\": %s", "could not update column \"%s\" of table \"%s\": %s",
attr, tablename, PQerrorMessage(AH->blobConnection)); attr, te->name, PQerrorMessage(AH->blobConnection));
if (PQresultStatus(uRes) != PGRES_COMMAND_OK) if (PQresultStatus(uRes) != PGRES_COMMAND_OK)
die_horribly(AH, modulename, die_horribly(AH, modulename,
"error while updating column \"%s\" of table \"%s\": %s", "error while updating column \"%s\" of table \"%s\": %s",
attr, tablename, PQerrorMessage(AH->blobConnection)); attr, te->name, PQerrorMessage(AH->blobConnection));
PQclear(uRes); PQclear(uRes);
} }
PQclear(res); PQclear(res);
destroyPQExpBuffer(tblName);
destroyPQExpBuffer(tblQry); destroyPQExpBuffer(tblQry);
} }
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
* Definitions for pg_backup_db.c * Definitions for pg_backup_db.c
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.h,v 1.5 2001/06/27 21:21:37 petere Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.h,v 1.6 2002/05/10 22:36:26 tgl Exp $
*/ */
#define BLOB_XREF_TABLE "dump_blob_xref" /* MUST be lower case */ #define BLOB_XREF_TABLE "pg_dump_blob_xref" /* MUST be lower case */
extern void FixupBlobRefs(ArchiveHandle *AH, char *tablename); extern void FixupBlobRefs(ArchiveHandle *AH, TocEntry *te);
extern int ExecuteSqlCommand(ArchiveHandle *AH, PQExpBuffer qry, char *desc, bool use_blob); extern int ExecuteSqlCommand(ArchiveHandle *AH, PQExpBuffer qry, char *desc, bool use_blob);
extern int ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qry, int bufLen); extern int ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qry, int bufLen);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* pg_backup_null.c * pg_backup_null.c
* *
* Implementation of an archive that is never saved; it is used by * Implementation of an archive that is never saved; it is used by
* pg_dump to output output a plain text SQL script instead of save * pg_dump to output a plain text SQL script instead of save
* a real archive. * a real archive.
* *
* See the headers to pg_restore for more details. * See the headers to pg_restore for more details.
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.8 2002/04/24 02:21:04 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.9 2002/05/10 22:36:26 tgl Exp $
* *
* Modifications - 09-Jul-2000 - pjw@rhyme.com.au * Modifications - 09-Jul-2000 - pjw@rhyme.com.au
* *
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.21 2002/04/24 02:21:04 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.22 2002/05/10 22:36:26 tgl Exp $
* *
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* *
...@@ -835,7 +835,7 @@ _CloseArchive(ArchiveHandle *AH) ...@@ -835,7 +835,7 @@ _CloseArchive(ArchiveHandle *AH)
ropt = NewRestoreOptions(); ropt = NewRestoreOptions();
ropt->dropSchema = 1; ropt->dropSchema = 1;
ropt->compression = 0; ropt->compression = 0;
ropt->superuser = PQuser(AH->connection); ropt->superuser = NULL;
ropt->suppressDumpWarnings = true; ropt->suppressDumpWarnings = true;
savVerbose = AH->public.verbose; savVerbose = AH->public.verbose;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* pg_dump.h * pg_dump.h
* header file for the pg_dump utility * Common header file for the pg_dump utility
* *
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_dump.h,v 1.84 2002/04/24 22:39:49 petere Exp $ * $Id: pg_dump.h,v 1.85 2002/05/10 22:36:27 tgl Exp $
*
* Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
*
* - Fixed dumpTable output to output lengths for char and varchar types!
* - Added single. quote to twin single quote expansion for 'insert' string
* mode.
*
* Modifications - 6/1/97 - igor@sba.miami.edu
* - Added extern's for the functions that clear allocated memory
* in pg_dump.c
*
* Modifications - 14-Sep-2000 - pjw@rhyme.com.au
* - Added typedefn fields to typeinfo and relinfo
* - Added enum for findTypeByOid to allow special handling of
* '0' OID.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,171 +17,133 @@ ...@@ -32,171 +17,133 @@
#include "pg_backup.h" #include "pg_backup.h"
#include "pqexpbuffer.h" #include "pqexpbuffer.h"
/* The data structures used to store system catalog information */ /*
* The data structures used to store system catalog information
*
* NOTE: the structures described here live for the entire pg_dump run;
* and in most cases we make a struct for every object we can find in the
* catalogs, not only those we are actually going to dump. Hence, it's
* best to store a minimal amount of per-object info in these structs,
* and retrieve additional per-object info when and if we dump a specific
* object. In particular, try to avoid retrieving expensive-to-compute
* information until it's known to be needed.
*/
typedef struct _namespaceInfo
{
char *oid;
char *nspname;
char *usename; /* name of owner, or empty string */
char *nspacl;
bool dump; /* true if need to dump definition */
} NamespaceInfo;
typedef struct _typeInfo typedef struct _typeInfo
{ {
char *oid; char *oid;
char *typowner; char *typname; /* name as seen in catalog */
char *typname; /* Note: format_type might produce something different than typname */
char *typlen; NamespaceInfo *typnamespace; /* link to containing namespace */
char *typprtlen; char *usename; /* name of owner, or empty string */
char *typinput; char *typelem; /* OID */
char *typoutput; char *typrelid; /* OID */
char *typreceive; char typtype; /* 'b', 'c', etc */
char *typsend; bool isArray; /* true if user-defined array type */
char *typelem; bool isDefined; /* true if typisdefined */
char *typdelim;
char *typdefault;
char *typrelid;
char *typalign;
char *typstorage;
char *usename;
char *typedefn;
char *typtype;
int passedbyvalue;
int isArray;
int isDefined;
} TypeInfo; } TypeInfo;
typedef struct _funcInfo typedef struct _funcInfo
{ {
char *oid; char *oid;
char *proname; char *proname;
char *proowner; NamespaceInfo *pronamespace; /* link to containing namespace */
char *usename; /* name of owner, or empty string */
Oid lang; Oid lang;
int nargs; int nargs;
char **argtypes; char **argtypes; /* OIDs */
char *prorettype; char *prorettype; /* OID */
int retset; /* 1 if the function returns a set, else 0 */ bool dumped; /* true if already dumped */
char *prosrc;
char *probin;
char *usename;
char provolatile; /* Attr */
bool isimplicit; /* Attr */
bool isstrict; /* Attr */
int dumped; /* 1 if already dumped */
} FuncInfo; } FuncInfo;
typedef struct _trigInfo typedef struct _aggInfo
{ {
char *oid; char *oid;
char *tgname; char *aggname;
char *tgsrc; NamespaceInfo *aggnamespace; /* link to containing namespace */
char *tgdel; char *usename;
char *tgcomment; } AggInfo;
} TrigInfo;
typedef struct _oprInfo
{
char *oid;
char *oprname;
NamespaceInfo *oprnamespace; /* link to containing namespace */
char *usename;
char *oprcode; /* as OID, not regproc name */
} OprInfo;
typedef struct _tableInfo typedef struct _tableInfo
{ {
/*
* These fields are collected for every table in the database.
*/
char *oid; char *oid;
char *relname; char *relname;
NamespaceInfo *relnamespace; /* link to containing namespace */
char *usename; /* name of owner, or empty string */
char *relacl; char *relacl;
char *viewdef;
char *viewoid; /* OID of view - should be >= oid of table
* important because views may be
* constructed manually from rules, and
* rule may ref things created after the
* base table was created. */
char relkind; char relkind;
bool hasindex; /* does it have any indexes? */ bool hasindex; /* does it have any indexes? */
bool hasrules; /* does it have any rules? */
bool hasoids; /* does it have OIDs? */ bool hasoids; /* does it have OIDs? */
int ncheck; /* # of CHECK expressions */
int ntrig; /* # of triggers */
bool interesting; /* true if need to collect more data */
bool dump; /* true if we want to dump it */
/*
* These fields are computed only if we decide the table is interesting
* (it's either a table to dump, or a direct parent of a dumpable table).
*/
int numatts; /* number of attributes */ int numatts; /* number of attributes */
int *inhAttrs; /* an array of flags, one for each
* attribute if the value is 1, then this
* attribute is an inherited attribute */
int *inhAttrDef; /* Flags indicating if attrdef is
* inherited */
int *inhNotNull; /* Flags indicating if NOT NULL in
* inherited */
char **attnames; /* the attribute names */ char **attnames; /* the attribute names */
char **atttypedefns; /* formatted column type definitions */ char **atttypnames; /* attribute type names */
char **typnames; /* fill out attributes */ int *atttypmod; /* type-specific type modifiers */
bool *notnull; /* Not null constraints of an attribute */ /*
* Note: we need to store per-attribute notnull and default stuff for
* all interesting tables so that we can tell which constraints were
* inherited.
*/
bool *notnull; /* Not null constraints on attributes */
char **adef_expr; /* DEFAULT expressions */ char **adef_expr; /* DEFAULT expressions */
int numParents; /* number of (immediate) parent bool *inhAttrs; /* true if each attribute is inherited */
* supertables */ bool *inhAttrDef; /* true if attr's default is inherited */
char **parentRels; /* names of parent relations, NULL if bool *inhNotNull; /* true if NOT NULL is inherited */
* numParents == 0 */
char **out_attnames; /* the attribute names, in the order they /*
* would be in, when the table is created * Stuff computed only for dumpable tables.
* in the target query language. this is */
* needed because the SQL tables will not int numParents; /* number of (immediate) parent tables */
* have the same order of attributes as int *parentIndexes; /* TableInfo indexes of immediate parents */
* the POSTQUEL tables */
int *atttypmod; /* type-specific type modifier */ char *viewoid; /* OID of view - should be >= oid of table
char *usename; * important because views may be
int ncheck; /* # of CHECK expressions */ * constructed manually from rules, and
char **check_expr; /* [CONSTRAINT name] CHECK expressions */ * rule may ref things created after the
int ntrig; /* # of triggers */ * base table was created. */
TrigInfo *triggers; /* Triggers on the table */
char *pkIndexOid; /* Primary Key index OID */
char *primary_key_name; /* PRIMARY KEY name, if any */
} TableInfo; } TableInfo;
typedef struct _inhInfo typedef struct _inhInfo
{ {
char *inhrelid; char *inhrelid; /* OID of a child table */
char *inhparent; char *inhparent; /* OID of its parent */
} InhInfo; } InhInfo;
typedef struct _indInfo
{
char *indexreloid; /* oid of the index itself */
char *indreloid; /* oid of the table the index is on */
char *indexrelname; /* name of the index itself */
char *indrelname; /* name of the indexed table */
char *indexdef; /* index definitional command */
char *indisprimary; /* is this a PK index? */
int indnkeys; /* number of keys in index */
char **indkey; /* attribute numbers of the key
* attributes */
} IndInfo;
typedef struct _aggInfo
{
char *oid;
char *aggname;
char *aggtransfn;
char *aggfinalfn;
char *aggtranstype;
char *aggbasetype;
char *agginitval;
char *usename;
int convertok; /* Flag to indicate of version convertsion
* is OK */
} AggInfo;
typedef struct _oprInfo
{
char *oid;
char *oprname;
char *oprkind; /*----------
* b = binary,
* l = left unary
* r = right unary
*----------
*/
char *oprcode; /* operator function name */
char *oprleft; /* left operand type */
char *oprright; /* right operand type */
char *oprcom; /* oid of the commutator operator */
char *oprnegate; /* oid of the negator operator */
char *oprrest; /* name of the function to calculate
* operator restriction selectivity */
char *oprjoin; /* name of the function to calculate
* operator join selectivity */
char *oprcanhash; /* can we use hash join strategy ? */
char *oprlsortop; /* oid's of the left and right sort
* operators */
char *oprrsortop;
char *usename;
} OprInfo;
/* global decls */ /* global decls */
extern bool force_quotes; /* double-quotes for identifiers flag */ extern bool force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose flag */ extern bool g_verbose; /* verbose flag */
extern Oid g_last_builtin_oid; /* value of the last builtin oid */
extern Archive *g_fout; /* the script file */ extern Archive *g_fout; /* the script file */
/* placeholders for comment starting and ending delimiters */ /* placeholders for comment starting and ending delimiters */
...@@ -212,73 +159,55 @@ extern char g_opaque_type[10]; /* name for the opaque type */ ...@@ -212,73 +159,55 @@ extern char g_opaque_type[10]; /* name for the opaque type */
*/ */
/* /*
* common utility functions * common utility functions
*/ */
extern TableInfo *dumpSchema(Archive *fout, extern TableInfo *dumpSchema(Archive *fout,
int *numTablesPtr, int *numTablesPtr,
const char *tablename, const bool aclsSkip,
const bool acls,
const bool oids,
const bool schemaOnly, const bool schemaOnly,
const bool dataOnly); const bool dataOnly);
extern void dumpSchemaIdx(Archive *fout,
const char *tablename,
TableInfo *tblinfo,
int numTables);
typedef enum _OidOptions typedef enum _OidOptions
{ {
zeroAsOpaque = 1, zeroAsOpaque = 1,
zeroAsAny = 2, zeroAsAny = 2,
zeroAsStar = 4, zeroAsStar = 4,
zeroAsNone = 8, zeroAsNone = 8
useBaseTypeName = 1024
} OidOptions; } OidOptions;
extern char *findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts); extern int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
extern char *findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid); extern char *findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid);
extern int findFuncByName(FuncInfo *finfo, int numFuncs, const char *name); extern int findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid);
extern int findTableByName(TableInfo *tbinfo, int numTables, const char *relname);
extern void check_conn_and_db(void); extern void check_conn_and_db(void);
extern void exit_nicely(void);
extern void parseNumericArray(const char *str, char **array, int arraysize); extern void parseNumericArray(const char *str, char **array, int arraysize);
/* /*
* version specific routines * version specific routines
*/ */
extern NamespaceInfo *getNamespaces(int *numNamespaces);
extern TypeInfo *getTypes(int *numTypes); extern TypeInfo *getTypes(int *numTypes);
extern FuncInfo *getFuncs(int *numFuncs); extern FuncInfo *getFuncs(int *numFuncs);
extern AggInfo *getAggregates(int *numAggregates); extern AggInfo *getAggregates(int *numAggregates);
extern void clearAggInfo(AggInfo *, int);
extern void clearFuncInfo(FuncInfo *, int);
extern void clearInhInfo(InhInfo *, int);
extern void clearIndInfo(IndInfo *, int);
extern void clearOprInfo(OprInfo *, int);
extern void clearTypeInfo(TypeInfo *, int);
extern OprInfo *getOperators(int *numOperators); extern OprInfo *getOperators(int *numOperators);
extern TableInfo *getTables(int *numTables, FuncInfo *finfo, int numFuncs, extern TableInfo *getTables(int *numTables);
const char* tablename);
extern InhInfo *getInherits(int *numInherits); extern InhInfo *getInherits(int *numInherits);
extern void getTableAttrs(TableInfo *tbinfo, int numTables); extern void getTableAttrs(TableInfo *tbinfo, int numTables);
extern IndInfo *getIndexes(int *numIndexes);
extern void dumpDBComment(Archive *outfile); extern void dumpDBComment(Archive *outfile);
extern void dumpNamespaces(Archive *fout,
NamespaceInfo *nsinfo, int numNamespaces);
extern void dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs, extern void dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes); TypeInfo *tinfo, int numTypes);
extern void dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs, extern void dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs);
TypeInfo *tinfo, int numTypes); extern void dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs);
extern void dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs, extern void dumpAggs(Archive *fout, AggInfo *agginfo, int numAggregates);
TypeInfo *tinfo, int numTypes); extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
extern void dumpAggs(Archive *fout, AggInfo *agginfo, int numAggregates, extern void dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
TypeInfo *tinfo, int numTypes); const bool aclsSkip,
extern void dumpOprs(Archive *fout, OprInfo *agginfo, int numOperators,
TypeInfo *tinfo, int numTypes);
extern void dumpTables(Archive *fout, TableInfo *tbinfo, int numTables,
const char *tablename, const bool acls,
const bool schemaOnly, const bool dataOnly); const bool schemaOnly, const bool dataOnly);
extern void dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes, extern void dumpIndexes(Archive *fout, TableInfo *tbinfo, int numTables);
TableInfo *tbinfo, int numTables, const char *tablename);
extern void exit_nicely(void);
#endif /* PG_DUMP_H */ #endif /* PG_DUMP_H */
...@@ -34,22 +34,7 @@ ...@@ -34,22 +34,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.33 2002/01/18 19:17:05 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.34 2002/05/10 22:36:27 tgl Exp $
*
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
*
* Initial version. Command processing taken from original pg_dump.
*
* Modifications - 28-Jul-2000 - pjw@rhyme.com.au (1.45)
*
* Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
* Added code to dump 'Create Schema' statement (pg_dump)
* Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
* Cleaned up code for reconnecting to database.
* Force a reconnect as superuser before enabling/disabling triggers.
*
* Modifications - 6-Mar-2001 - pjw@rhyme.com.au
* Change -U option to -L to allow -U to specify username in future.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -94,6 +79,7 @@ main(int argc, char **argv) ...@@ -94,6 +79,7 @@ main(int argc, char **argv)
extern int optind; extern int optind;
extern char *optarg; extern char *optarg;
static int use_setsessauth = 0; static int use_setsessauth = 0;
static int disable_triggers = 0;
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
struct option cmdopts[] = { struct option cmdopts[] = {
...@@ -130,6 +116,8 @@ main(int argc, char **argv) ...@@ -130,6 +116,8 @@ main(int argc, char **argv)
* letter, but are available as '-X long-name' * letter, but are available as '-X long-name'
*/ */
{"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"disable-triggers", no_argument, &disable_triggers, 1},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
#endif /* HAVE_GETOPT_LONG */ #endif /* HAVE_GETOPT_LONG */
...@@ -281,6 +269,8 @@ main(int argc, char **argv) ...@@ -281,6 +269,8 @@ main(int argc, char **argv)
case 'X': case 'X':
if (strcmp(optarg, "use-set-session-authorization") == 0) if (strcmp(optarg, "use-set-session-authorization") == 0)
use_setsessauth = 1; use_setsessauth = 1;
else if (strcmp(optarg, "disable-triggers") == 0)
disable_triggers = 1;
else else
{ {
fprintf(stderr, fprintf(stderr,
...@@ -309,6 +299,7 @@ main(int argc, char **argv) ...@@ -309,6 +299,7 @@ main(int argc, char **argv)
fileSpec = NULL; fileSpec = NULL;
opts->use_setsessauth = use_setsessauth; opts->use_setsessauth = use_setsessauth;
opts->disable_triggers = disable_triggers;
if (opts->formatName) if (opts->formatName)
{ {
...@@ -416,6 +407,8 @@ usage(const char *progname) ...@@ -416,6 +407,8 @@ usage(const char *progname)
" -X use-set-session-authorization, --use-set-session-authorization\n" " -X use-set-session-authorization, --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead\n" " use SET SESSION AUTHORIZATION commands instead\n"
" of reconnecting, if possible\n" " of reconnecting, if possible\n"
" -X disable-triggers, --disable-triggers\n"
" disable triggers during data-only restore\n"
)); ));
#else /* not HAVE_GETOPT_LONG */ #else /* not HAVE_GETOPT_LONG */
...@@ -452,6 +445,7 @@ usage(const char *progname) ...@@ -452,6 +445,7 @@ usage(const char *progname)
" -X use-set-session-authorization\n" " -X use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead\n" " use SET SESSION AUTHORIZATION commands instead\n"
" of reconnecting, if possible\n" " of reconnecting, if possible\n"
" -X disable-triggers disable triggers during data-only restore\n"
)); ));
#endif #endif
puts(gettext("If no input file name is supplied, then standard input is used.\n")); puts(gettext("If no input file name is supplied, then standard input is used.\n"));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment