Revise psql pattern-matching switches as per discussion. The rule is now
authorTom Lane
Mon, 9 Oct 2006 23:36:59 +0000 (23:36 +0000)
committerTom Lane
Mon, 9 Oct 2006 23:36:59 +0000 (23:36 +0000)
to process all inclusion switches then all exclusion switches, so that the
behavior is independent of switch ordering.
Use of -T does not cause non-table objects to be suppressed.  And
the patterns are now interpreted the same way psql's \d commands do it,
rather than as pure regex commands; this allows for example -t schema.tab
to do what it should have been doing all along.  Re-enable the --blobs
switch to do something useful, ie, add back blobs into a dump they were
otherwise suppressed from.

doc/src/sgml/ref/pg_dump.sgml
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h

index deafd7c9a989c2cbce3979d94416a298609f5e84..9aa4baf84e74817a3c3e8359b2c4c8a847fda987 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -14,7 +14,7 @@ PostgreSQL documentation
   pg_dump
 
   
-   extract a PostgreSQL database into a script file or other archive file 
+   extract a PostgreSQL database into a script file or other archive file
   
  
 
@@ -126,6 +126,19 @@ PostgreSQL documentation
       
      
 
+     
+      
+      
+      
+       
+        Include large objects in the dump.  This is the default behavior
+        except when 
+        
+        switch is only useful to add large objects to selective dumps.
+       
+      
+     
+
      
       
       
@@ -170,12 +183,14 @@ PostgreSQL documentation
         Dump data as INSERT commands (rather
         than COPY).  This will make restoration very slow;
         it is mainly useful for making dumps that can be loaded into
-        non-PostgreSQL databases.  Note that
+        non-PostgreSQL databases.
+        Also, since this option generates a separate command for each row,
+        an error in reloading a row causes only that row to be lost rather
+        than the entire table contents.
+        Note that
         the restore may fail altogether if you have rearranged column order.
-        The  option is safer, though even slower.
-        Also, while this option generates errors for invalid data, 
-        it allows other INSERTs to continue loading
-        data into the table.
+        The  option is safe against column order changes,
+        though even slower.
        
       
      
@@ -193,9 +208,9 @@ PostgreSQL documentation
         ...).  This will make restoration very slow; it is mainly
         useful for making dumps that can be loaded into
         non-PostgreSQL databases.
-        Also, while this option generates errors for invalid data, 
-        it allows other INSERTs to continue loading
-        data into the table.
+        Also, since this option generates a separate command for each row,
+        an error in reloading a row causes only that row to be lost rather
+        than the entire table contents.
        
       
      
@@ -238,7 +253,7 @@ PostgreSQL documentation
          plain
          
           
-           Output a plain-text SQL script file (default)
+           Output a plain-text SQL script file (the default).
           
          
         
@@ -248,10 +263,10 @@ PostgreSQL documentation
          custom
          
           
-         Output a custom archive suitable for input into 
-         pg_restore. This is the most flexible 
-         format in that it allows reordering of loading data as well 
-         as object definitions. This format is also compressed by default.
+           Output a custom archive suitable for input into
+           pg_restore. This is the most flexible
+           format in that it allows reordering of loading data as well
+           as object definitions. This format is also compressed by default.
           
          
         
@@ -261,11 +276,11 @@ PostgreSQL documentation
          tar
          
           
-         Output a tar archive suitable for input into 
-         pg_restore. Using this archive format 
-         allows reordering and/or exclusion of database objects
-         at the time the database is restored. It is also possible to limit 
-         which data is reloaded at restore time.
+           Output a tar archive suitable for input into
+           pg_restore. Using this archive format
+           allows reordering and/or exclusion of database objects
+           at the time the database is restored. It is also possible to limit
+           which data is reloaded at restore time.
           
          
         
@@ -286,9 +301,11 @@ PostgreSQL documentation
        
 
        
-        pg_dump can handle databases from
+        pg_dump can dump from servers running
         previous releases of PostgreSQL, but very old
-        versions are not supported anymore (currently prior to 7.0).
+        versions are not supported anymore (currently, those prior to 7.0).
+        Dumping from a server newer than pg_dump
+        is likely not to work at all.
         Use this option if you need to override the version check (and
         if pg_dump then fails, don't say
         you weren't warned).
@@ -301,20 +318,61 @@ PostgreSQL documentation
       
       
        
-        Dump the contents of schema
-        only. If this option is not specified, all non-system schemas
-        in the target database will be dumped.
+        Dump only schemas matching 
+        class="parameter">schema; this selects both the
+        schema itself, and all its contained objects.  When this option is
+        not specified, all non-system schemas in the target database will be
+        dumped.  Multiple schemas can be
+        selected by writing multiple 
+        schema parameter is
+        interpreted as a pattern according to the same rules used by
+        psql's \d commands (see 
+        linkend="APP-PSQL-patterns" endterm="APP-PSQL-patterns-title">),
+        so multiple schemas can also be selected by writing wildcard characters
+        in the pattern.  When using wildcards, be careful to quote the pattern
+        if needed to prevent the shell from expanding the wildcards.
        
 
        
         
-         In this mode, pg_dump makes no
-         attempt to dump any other database objects that objects in the
-         selected schema may depend upon. Therefore, there is no
-         guarantee that the results of a single-schema dump can be
-         successfully restored by themselves into a clean database.
+         When 
+         makes no attempt to dump any other database objects that the selected
+         schema(s) may depend upon. Therefore, there is no guarantee
+         that the results of a specific-schema dump can be successfully
+         restored by themselves into a clean database.
+        
+       
+
+       
+        
+         Non-schema objects such as blobs are not dumped when 
+         specified.  You can add blobs back to the dump with the
+         
         
        
+
+      
+     
+
+     
+      
+      
+      
+       
+        Do not dump any schemas matching the 
+        class="parameter">schema pattern.  The pattern is
+        interpreted according to the same rules as for 
+        
+        matching any of several patterns.
+       
+
+       
+        When both 
+        is to dump just the schemas that match at least one 
+        switch but no 
+        without 
+        excluded from what is otherwise a normal dump.
+       
       
      
 
@@ -340,7 +398,7 @@ PostgreSQL documentation
         Do not output commands to set
         ownership of objects to match the original database.
         By default, pg_dump issues
-        ALTER OWNER or 
+        ALTER OWNER or
         SET SESSION AUTHORIZATION
         statements to set ownership of created database objects.
         These statements
@@ -397,67 +455,47 @@ PostgreSQL documentation
       
       
        
-        Dump data for table
-        only. It is possible for there to be multiple tables with the same 
-        name in different schemas; if that is the case, all matching tables 
-        will be dumped. Also, if any POSIX regular expression character appears
-        in the table name (([{\.?+, the string will be interpreted
-        as a regular expression.  Note that when in regular expression mode, the
-        string will not be anchored to the start/end unless ^ and
-        $ are used at the beginning/end of the string.
+        Dump only tables (or views or sequences) matching 
+        class="parameter">table.  Multiple tables can be
+        selected by writing multiple 
+        table parameter is
+        interpreted as a pattern according to the same rules used by
+        psql's \d commands (see 
+        linkend="APP-PSQL-patterns" endterm="APP-PSQL-patterns-title">),
+        so multiple tables can also be selected by writing wildcard characters
+        in the pattern.  When using wildcards, be careful to quote the pattern
+        if needed to prevent the shell from expanding the wildcards.
        
 
        
-       The options 
-       can be used together to achieve a high degree of control over what is
-       dumped. Multiple arguments can be used, and are parsed in the order 
-       given to build a list of valid tables and schemas. The schema options are 
-       parsed first to create a list of schemas to dump, and then the table options 
-       are parsed to only find tables in the matching schemas.
+        The 
+        
+        be dumped regardless of those switches, and non-table objects will not
+        be dumped.
        
 
-       For example, to dump a single table named pg_class:
-
-
-$ pg_dump -t pg_class mydb > db.out
-
-       
-
-       To dump all tables starting with employee in the 
-       detroit schema, except for the table named employee_log:
-
-
-$ pg_dump -n detroit -t ^employee -T employee_log mydb > db.out
-
-       
-
-       To dump all schemas starting with east or west and ending in
-       gsm, but not schemas that contain the letters test, except for 
-       one named east_alpha_test_five:
-
-
-$ pg_dump -n "^(east|west).*gsm$" -N test -n east_alpha_test_five mydb > db.out
-
-       
-
-
-       To dump all tables except for those beginning with ts_:
-
-
-$ pg_dump -T "^ts_" mydb > db.out
-
-       
-
-
        
         
-         In this mode, pg_dump makes no
-         attempt to dump any other database objects that the selected tables
-         may depend upon. Therefore, there is no guarantee
+         When 
+         makes no attempt to dump any other database objects that the selected
+         table(s) may depend upon. Therefore, there is no guarantee
          that the results of a specific-table dump can be successfully
          restored by themselves into a clean database.
         
        
+
+       
+        
+         The behavior of the 
+         compatible with pre-8.2 PostgreSQL
+         versions.  Formerly, writing -t tab would dump all
+         tables named tab, but now it just dumps whichever one
+         is visible in your default search path.  To get the old behavior
+         you can write -t '*.tab'.  Also, you must write something
+         like -t sch.tab to select a table in a particular schema,
+         rather than the old locution of -n sch -t tab.
+        
+       
       
      
 
@@ -466,36 +504,20 @@ PostgreSQL documentation
       
       
        
-        Do not dump any matching tables.
-        More than one option can be used, and POSIX regular expressions are handled just
-        like -t.
+        Do not dump any tables matching the 
+        class="parameter">table pattern.  The pattern is
+        interpreted according to the same rules as for 
+        
+        matching any of several patterns.
        
-      
-     
-
-     
-      
-      
-      
-       
-        Dump only the matching schemas.
-        More than one option can be used, and POSIX regular expressions are handled just
-        like -t.
-       
-
-      
-     
 
-     
-      
-      
-      
        
-        Do not dump the matching schemas.
-        More than one option can be used, and POSIX regular expressions are handled just
-        like -t.
+        When both 
+        is to dump just the tables that match at least one 
+        switch but no 
+        without 
+        excluded from what is otherwise a normal dump.
        
-
       
      
 
@@ -506,7 +528,7 @@ PostgreSQL documentation
        
         Specifies verbose mode.  This will cause
         pg_dump to output detailed object
-        comments and start/stop times to the dump file, and progress 
+        comments and start/stop times to the dump file, and progress
         messages to standard error.
        
       
@@ -742,33 +764,80 @@ CREATE DATABASE foo WITH TEMPLATE template0;
   Examples
 
   
-   To dump a database:
+   To dump a database called mydb into a SQL-script file:
+
+$ pg_dump mydb > db.sql
+
+  
+
+  
+   To reload such a script into a (freshly created) database named
+   newdb:
+
 
-$ pg_dump mydb > db.out
+$ psql -d newdb -f db.sql
 
   
 
   
-   To reload this database:
+   To dump a database into a custom-format archive file:
+
+
+$ pg_dump -Fc mydb > db.dump
+
+  
+
+  
+   To reload an archive file into a (freshly created) database named
+   newdb:
+
+
+$ pg_restore -d newdb db.dump
+
+  
+
+  
+   To dump a single table named mytab:
+
+
+$ pg_dump -t mytab mydb > db.sql
+
+  
+
+  
+   To dump all tables whose names start with emp in the
+   detroit schema, except for the table named
+   employee_log:
+
+
+$ pg_dump -t 'detroit.emp*' -T detroit.employee_log mydb > db.sql
+
+  
+
+  
+   To dump all schemas whose names start with east or
+   west and end in gsm, excluding any schemas whose
+   names contain the word test:
+
 
-$ psql -d database -f db.out
+$ pg_dump -n 'east*gsm' -n 'west*gsm' -N '*test*' mydb > db.sql
 
   
 
   
-   To dump a database called mydb to a file in custom format:
-   file:
+   The same, using regular expression notation to consolidate the switches:
 
 
-$ pg_dump -Fc mydb > db.out
+$ pg_dump -n '(east|west)*gsm' -N '*test*' mydb > db.sql
 
   
 
   
-   To reload this dump into an existing database called newdb:
+   To dump all database objects except for tables whose names begin with
+   ts_:
 
 
-$ pg_restore -d newdb db.out
+$ pg_dump -T 'ts_*' mydb > db.sql
 
   
 
index f4b4a1e5bbb0ae6558a863c666b6282900082172..44ccb2eab1f53cb8369f39ac92f4c69b903c2251 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.93 2006/09/27 15:41:23 tgl Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.94 2006/10/09 23:36:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -402,16 +402,14 @@ AssignDumpId(DumpableObject *dobj)
        {
            newAlloc = 256;
            dumpIdMap = (DumpableObject **)
-               malloc(newAlloc * sizeof(DumpableObject *));
+               pg_malloc(newAlloc * sizeof(DumpableObject *));
        }
        else
        {
            newAlloc = allocedDumpIds * 2;
            dumpIdMap = (DumpableObject **)
-               realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
+               pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
        }
-       if (dumpIdMap == NULL)
-           exit_horribly(NULL, NULL, "out of memory\n");
        memset(dumpIdMap + allocedDumpIds, 0,
               (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
        allocedDumpIds = newAlloc;
@@ -541,9 +539,7 @@ getDumpableObjects(DumpableObject ***objs, int *numObjs)
                j;
 
    *objs = (DumpableObject **)
-       malloc(allocedDumpIds * sizeof(DumpableObject *));
-   if (*objs == NULL)
-       exit_horribly(NULL, NULL, "out of memory\n");
+       pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
    j = 0;
    for (i = 1; i < allocedDumpIds; i++)
    {
@@ -567,17 +563,15 @@ addObjectDependency(DumpableObject *dobj, DumpId refId)
        {
            dobj->allocDeps = 16;
            dobj->dependencies = (DumpId *)
-               malloc(dobj->allocDeps * sizeof(DumpId));
+               pg_malloc(dobj->allocDeps * sizeof(DumpId));
        }
        else
        {
            dobj->allocDeps *= 2;
            dobj->dependencies = (DumpId *)
-               realloc(dobj->dependencies,
-                       dobj->allocDeps * sizeof(DumpId));
+               pg_realloc(dobj->dependencies,
+                          dobj->allocDeps * sizeof(DumpId));
        }
-       if (dobj->dependencies == NULL)
-           exit_horribly(NULL, NULL, "out of memory\n");
    }
    dobj->dependencies[dobj->nDeps++] = refId;
 }
@@ -707,7 +701,8 @@ findParentsByOid(TableInfo *self,
 
    if (numParents > 0)
    {
-       self->parents = (TableInfo **) malloc(sizeof(TableInfo *) * numParents);
+       self->parents = (TableInfo **)
+           pg_malloc(sizeof(TableInfo *) * numParents);
        j = 0;
        for (i = 0; i < numInherits; i++)
        {
@@ -806,3 +801,124 @@ strInArray(const char *pattern, char **arr, int arr_size)
    }
    return -1;
 }
+
+
+/*
+ * Support for simple list operations
+ */
+
+void
+simple_oid_list_append(SimpleOidList *list, Oid val)
+{
+   SimpleOidListCell *cell;
+
+   cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
+   cell->next = NULL;
+   cell->val = val;
+
+   if (list->tail)
+       list->tail->next = cell;
+   else
+       list->head = cell;
+   list->tail = cell;
+}
+
+void
+simple_string_list_append(SimpleStringList *list, const char *val)
+{
+   SimpleStringListCell *cell;
+
+   /* this calculation correctly accounts for the null trailing byte */
+   cell = (SimpleStringListCell *)
+       pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
+   cell->next = NULL;
+   strcpy(cell->val, val);
+
+   if (list->tail)
+       list->tail->next = cell;
+   else
+       list->head = cell;
+   list->tail = cell;
+}
+
+bool
+simple_oid_list_member(SimpleOidList *list, Oid val)
+{
+   SimpleOidListCell *cell;
+
+   for (cell = list->head; cell; cell = cell->next)
+   {
+       if (cell->val == val)
+           return true;
+   }
+   return false;
+}
+
+bool
+simple_string_list_member(SimpleStringList *list, const char *val)
+{
+   SimpleStringListCell *cell;
+
+   for (cell = list->head; cell; cell = cell->next)
+   {
+       if (strcmp(cell->val, val) == 0)
+           return true;
+   }
+   return false;
+}
+
+
+/*
+ * Safer versions of some standard C library functions. If an
+ * out-of-memory condition occurs, these functions will bail out
+ * safely; therefore, their return value is guaranteed to be non-NULL.
+ *
+ * XXX need to refactor things so that these can be in a file that can be
+ * shared by pg_dumpall and pg_restore as well as pg_dump.
+ */
+
+char *
+pg_strdup(const char *string)
+{
+   char       *tmp;
+
+   if (!string)
+       exit_horribly(NULL, NULL, "cannot duplicate null pointer\n");
+   tmp = strdup(string);
+   if (!tmp)
+       exit_horribly(NULL, NULL, "out of memory\n");
+   return tmp;
+}
+
+void *
+pg_malloc(size_t size)
+{
+   void       *tmp;
+
+   tmp = malloc(size);
+   if (!tmp)
+       exit_horribly(NULL, NULL, "out of memory\n");
+   return tmp;
+}
+
+void *
+pg_calloc(size_t nmemb, size_t size)
+{
+   void       *tmp;
+
+   tmp = calloc(nmemb, size);
+   if (!tmp)
+       exit_horribly(NULL, NULL, "out of memory\n");
+   return tmp;
+}
+
+void *
+pg_realloc(void *ptr, size_t size)
+{
+   void       *tmp;
+
+   tmp = realloc(ptr, size);
+   if (!tmp)
+       exit_horribly(NULL, NULL, "out of memory\n");
+   return tmp;
+}
index 5cf0b76b50f36cb2c73917898301146864a1adb0..c4df03083e116dd8889d655e422a87b06a6b1dec 100644 (file)
@@ -12,7 +12,7 @@
  * by PostgreSQL
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.452 2006/10/07 20:59:04 petere Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.453 2006/10/09 23:36:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,8 +40,6 @@
 int            optreset;
 #endif
 
-
-
 #include "access/htup.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_proc.h"
@@ -87,20 +85,24 @@ static const char *username_subquery;
 /* obsolete as of 7.3: */
 static Oid g_last_builtin_oid; /* value of the last builtin oid */
 
-/* select and exclude tables and schemas */
-typedef struct objnameArg
-{
-   struct objnameArg *next;
-   char       *name;           /* name of the relation */
-   bool        is_include;     /* include/exclude? */
-} objnameArg;
+/*
+ * Object inclusion/exclusion lists
+ *
+ * The string lists record the patterns given by command-line switches,
+ * which we then convert to lists of OIDs of matching objects.
+ */
+static SimpleStringList schema_include_patterns = { NULL, NULL };
+static SimpleOidList schema_include_oids = { NULL, NULL };
+static SimpleStringList schema_exclude_patterns = { NULL, NULL };
+static SimpleOidList schema_exclude_oids = { NULL, NULL };
 
-objnameArg *schemaList = NULL; /* List of schemas to include/exclude */
-objnameArg *tableList = NULL;  /* List of tables to include/exclude */
+static SimpleStringList table_include_patterns = { NULL, NULL };
+static SimpleOidList table_include_oids = { NULL, NULL };
+static SimpleStringList table_exclude_patterns = { NULL, NULL };
+static SimpleOidList table_exclude_oids = { NULL, NULL };
 
-char      *matchingSchemas = NULL;     /* Final list of schemas to dump by
-                                        * oid */
-char      *matchingTables = NULL;      /* Final list of tables to dump by oid */
+/* default, if no "inclusion" switches appear, is to dump everything */
+static bool include_everything = true;
 
 char       g_opaque_type[10];  /* name for the opaque type */
 
@@ -119,6 +121,10 @@ static int disable_dollar_quoting = 0;
 
 
 static void help(const char *progname);
+static void expand_schema_name_patterns(SimpleStringList *patterns,
+                                       SimpleOidList *oids);
+static void expand_table_name_patterns(SimpleStringList *patterns,
+                                      SimpleOidList *oids);
 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
 static void dumpComment(Archive *fout, const char *target,
@@ -188,11 +194,6 @@ static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
 int
 main(int argc, char **argv)
 {
-   PQExpBuffer query = createPQExpBuffer();
-   PGresult   *res;
-   objnameArg *this_obj_name,
-              *schemaList_tail = NULL,
-              *tableList_tail = NULL;
    int         c;
    const char *filename = NULL;
    const char *format = "p";
@@ -208,14 +209,13 @@ main(int argc, char **argv)
    DumpableObject **dobjs;
    int         numObjs;
    int         i;
-   bool        switch_include_exclude;
    bool        force_password = false;
    int         compressLevel = -1;
    bool        ignore_version = false;
    int         plainText = 0;
    int         outputClean = 0;
    int         outputCreate = 0;
-   bool        outputBlobs = true;
+   bool        outputBlobs = false;
    int         outputNoOwner = 0;
    static int  use_setsessauth = 0;
    static int  disable_triggers = 0;
@@ -306,7 +306,7 @@ main(int argc, char **argv)
                break;
 
            case 'b':           /* Dump blobs */
-               /* this is now default, so just ignore the switch */
+               outputBlobs = true;
                break;
 
            case 'c':           /* clean (i.e., drop) schema prior to create */
@@ -347,42 +347,13 @@ main(int argc, char **argv)
                ignore_version = true;
                break;
 
-           case 'n':           /* Include schemas */
-           case 'N':           /* Exclude schemas */
-           case 't':           /* Include tables */
-           case 'T':           /* Exclude tables */
-
-               if (strlen(optarg) < 1)
-               {
-                   fprintf(stderr, _("%s: invalid -%c option\n"), progname, c);
-                   exit(1);
-               }
-
-               {
-                   /* Create a struct for this name */
-                   objnameArg *new_obj_name = (objnameArg *)
-                   malloc(sizeof(objnameArg));
-
-                   new_obj_name->next = NULL;
-                   new_obj_name->name = strdup(optarg);
-                   new_obj_name->is_include = islower((unsigned char) c) ? true : false;
+           case 'n':           /* include schema(s) */
+               simple_string_list_append(&schema_include_patterns, optarg);
+               include_everything = false;
+               break;
 
-                   /* add new entry to the proper list */
-                   if (tolower((unsigned char) c) == 'n')
-                   {
-                       if (!schemaList_tail)
-                           schemaList_tail = schemaList = new_obj_name;
-                       else
-                           schemaList_tail = schemaList_tail->next = new_obj_name;
-                   }
-                   else
-                   {
-                       if (!tableList_tail)
-                           tableList_tail = tableList = new_obj_name;
-                       else
-                           tableList_tail = tableList_tail->next = new_obj_name;
-                   }
-               }
+           case 'N':           /* exclude schema(s) */
+               simple_string_list_append(&schema_exclude_patterns, optarg);
                break;
 
            case 'o':           /* Dump oids */
@@ -403,13 +374,21 @@ main(int argc, char **argv)
 
            case 's':           /* dump schema only */
                schemaOnly = true;
-               outputBlobs = false;
                break;
 
            case 'S':           /* Username for superuser in plain text output */
                outputSuperuser = strdup(optarg);
                break;
 
+           case 't':           /* include table(s) */
+               simple_string_list_append(&table_include_patterns, optarg);
+               include_everything = false;
+               break;
+
+           case 'T':           /* exclude table(s) */
+               simple_string_list_append(&table_exclude_patterns, optarg);
+               break;
+
            case 'u':
                force_password = true;
                username = simple_prompt("User name: ", 100, true);
@@ -488,9 +467,6 @@ main(int argc, char **argv)
        exit(1);
    }
 
-   if (matchingTables != NULL || matchingSchemas != NULL)
-       outputBlobs = false;
-
    if (dumpInserts == true && oids == true)
    {
        write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together\n");
@@ -607,162 +583,42 @@ main(int argc, char **argv)
            write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
    }
 
-
-   if (schemaList != NULL && g_fout->remoteVersion < 70300)
+   /* Expand schema selection patterns into OID lists */
+   if (schema_include_patterns.head != NULL)
    {
-       write_msg(NULL, "server version must be at least 7.3 to use schema switches\n");
-       exit_nicely();
-   }
-
-   /* Check schema selection flags */
-   resetPQExpBuffer(query);
-   switch_include_exclude = true;
-
-   for (this_obj_name = schemaList; this_obj_name; this_obj_name = this_obj_name->next)
-   {
-       if (switch_include_exclude)
-       {
-           /* Special case for when -N is the first argument */
-           if (this_obj_name == schemaList && !this_obj_name->is_include)
-               appendPQExpBuffer(query,
-                                 "SELECT oid FROM pg_catalog.pg_namespace "
-                                 "WHERE nspname NOT LIKE 'pg_%%' AND "
-                          "      nspname != 'information_schema' EXCEPT\n");
-
-           appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_namespace WHERE");
-       }
-
-       appendPQExpBuffer(query, "%s nspname %c ", switch_include_exclude ? "" : " OR",
-       /* any meta-characters? */
-              strpbrk(this_obj_name->name, "([{\\.?+") == NULL ? '=' : '~');
-       appendStringLiteralAH(query, this_obj_name->name, g_fout);
-
-       if (this_obj_name->next && this_obj_name->next->is_include == this_obj_name->is_include)
-           switch_include_exclude = false;
-       else
-       {
-           switch_include_exclude = true;
-
-           /* Add the joiner if needed */
-           if (this_obj_name->next)
-               appendPQExpBuffer(query, "\n%s\n",
-                      this_obj_name->next->is_include ? "UNION" : "EXCEPT");
-       }
-   }
-
-   /* Construct OID list of matching schemas */
-   if (schemaList)
-   {
-       int         len;
-
-       res = PQexec(g_conn, query->data);
-       check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
-       if (PQntuples(res) == 0)
+       expand_schema_name_patterns(&schema_include_patterns,
+                                   &schema_include_oids);
+       if (schema_include_oids.head == NULL)
        {
            write_msg(NULL, "No matching schemas were found\n");
            exit_nicely();
        }
-
-       for (i = 0, len = strlen(" "); i < PQntuples(res); i++)
-           len += strlen(PQgetvalue(res, i, 0)) + 1;
-
-       /*
-        * Need to use comma separators so it can be used by IN.  zero is a
-        * dummy placeholder.  Format is " oid oid oid ".
-        */
-       matchingSchemas = malloc(len + 1);
-       strcpy(matchingSchemas, " ");
-       for (i = 0; i < PQntuples(res); i++)
-       {
-           strcat(matchingSchemas, PQgetvalue(res, i, 0));
-           strcat(matchingSchemas, " ");
-       }
    }
+   expand_schema_name_patterns(&schema_exclude_patterns,
+                               &schema_exclude_oids);
+   /* non-matching exclusion patterns aren't an error */
 
-   /* Check table selection flags */
-   resetPQExpBuffer(query);
-   switch_include_exclude = true;
-
-   for (this_obj_name = tableList; this_obj_name; this_obj_name = this_obj_name->next)
+   /* Expand table selection patterns into OID lists */
+   if (table_include_patterns.head != NULL)
    {
-       if (switch_include_exclude)
-       {
-           /* Special case for when -T is the first argument */
-           if (this_obj_name == tableList && !this_obj_name->is_include && !strlen(query->data))
-               appendPQExpBuffer(query,
-                                 "SELECT pg_class.oid FROM pg_catalog.pg_class, pg_catalog.pg_namespace "
-                                 "WHERE relkind='r' AND "
-                                 "      relnamespace = pg_namespace.oid AND "
-                                 "      nspname NOT LIKE 'pg_%%' AND "
-                          "      nspname != 'information_schema' EXCEPT\n");
-
-           appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND (");
-       }
-
-       appendPQExpBuffer(query, "%srelname %c ", switch_include_exclude ? "" : " OR ",
-       /* any meta-characters? */
-              strpbrk(this_obj_name->name, "([{\\.?+") == NULL ? '=' : '~');
-       appendStringLiteralAH(query, this_obj_name->name, g_fout);
-
-       if (this_obj_name->next && this_obj_name->next->is_include == this_obj_name->is_include)
-           switch_include_exclude = false;
-       else
-       {
-           switch_include_exclude = true;
-           appendPQExpBuffer(query, ")");
-
-           /* Add the joiner if needed */
-           if (this_obj_name->next)
-               appendPQExpBuffer(query, "\n%s\n", this_obj_name->next->is_include ?
-                                 "UNION" : "EXCEPT");
-       }
-   }
-
-   /* Construct OID list of matching tables */
-   if (tableList)
-   {
-       int         len;
-
-       /* Restrict by schema? */
-       if (matchingSchemas != NULL)
-       {
-           char       *matchingSchemas_commas = strdup(matchingSchemas),
-                      *p;
-
-           /* Construct "IN" SQL string by adding commas, " oid, oid, oid " */
-           for (p = matchingSchemas_commas; *p; p++)
-           {
-               /* No commas for first/last characters */
-               if (*p == ' ' && p != matchingSchemas_commas && *(p + 1))
-                   *p = ',';
-           }
-
-           appendPQExpBuffer(query,
-                             "\nINTERSECT\nSELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND relnamespace IN (%s)\n",
-                             matchingSchemas_commas);
-       }
-
-       res = PQexec(g_conn, query->data);
-       check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
-       if (PQntuples(res) == 0)
+       expand_table_name_patterns(&table_include_patterns,
+                                  &table_include_oids);
+       if (table_include_oids.head == NULL)
        {
            write_msg(NULL, "No matching tables were found\n");
            exit_nicely();
        }
-
-       for (i = 0, len = strlen(" "); i < PQntuples(res); i++)
-           len += strlen(PQgetvalue(res, i, 0)) + 1;
-
-       matchingTables = malloc(len + 1);
-       strcpy(matchingTables, " ");
-       for (i = 0; i < PQntuples(res); i++)
-       {
-           strcat(matchingTables, PQgetvalue(res, i, 0));
-           strcat(matchingTables, " ");
-       }
    }
+   expand_table_name_patterns(&table_exclude_patterns,
+                              &table_exclude_oids);
+   /* non-matching exclusion patterns aren't an error */
 
-   destroyPQExpBuffer(query);
+   /*
+    * 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;
 
    /*
     * Now scan the database and create DumpableObject structs for all the
@@ -824,7 +680,7 @@ main(int argc, char **argv)
    dumpStdStrings(g_fout);
 
    /* The database item is always next, unless we don't want it at all */
-   if (!dataOnly && matchingTables == NULL && matchingSchemas == NULL)
+   if (include_everything && !dataOnly)
        dumpDatabase(g_fout);
 
    /* Now the rearrangeable objects. */
@@ -884,28 +740,28 @@ help(const char *progname)
 
    printf(_("\nOptions controlling the output content:\n"));
    printf(_("  -a, --data-only             dump only the data, not the schema\n"));
+   printf(_("  -b, --blobs                 include large objects in dump\n"));
    printf(_("  -c, --clean                 clean (drop) schema prior to create\n"));
    printf(_("  -C, --create                include commands to create database in dump\n"));
    printf(_("  -d, --inserts               dump data as INSERT commands, rather than COPY\n"));
    printf(_("  -D, --column-inserts        dump data as INSERT commands with column names\n"));
    printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
-   printf(_("  -n, --schema=SCHEMA         dump the named schema only\n"));
-   printf(_("  -N, --exclude-schema=SCHEMA\n"
-        "                              do NOT dump the named schema\n"));
+   printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
+   printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
    printf(_("  -o, --oids                  include OIDs in dump\n"));
    printf(_("  -O, --no-owner              skip restoration of object ownership\n"
             "                              in plain text format\n"));
    printf(_("  -s, --schema-only           dump only the schema, no data\n"));
    printf(_("  -S, --superuser=NAME        specify the superuser user name to use in\n"
             "                              plain text format\n"));
-   printf(_("  -t, --table=TABLE           dump the named table only\n"));
-   printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table\n"));
+   printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
+   printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
    printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
    printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
    printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
    printf(_("  --use-set-session-authorization\n"
             "                              use SESSION AUTHORIZATION commands instead of\n"
-            "                              OWNER TO commands\n"));
+            "                              ALTER OWNER commands to set ownership\n"));
 
    printf(_("\nConnection options:\n"));
    printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
@@ -928,66 +784,159 @@ exit_nicely(void)
 }
 
 /*
- * selectDumpableNamespace: policy-setting subroutine
- *     Mark a namespace as to be dumped or not
+ * Find the OIDs of all schemas matching the given list of patterns,
+ * and append them to the given OID list.
  */
 static void
-selectDumpableNamespace(NamespaceInfo *nsinfo)
+expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
 {
+   PQExpBuffer query;
+   PGresult   *res;
+   SimpleStringListCell *cell;
+   int         i;
+
+   if (patterns->head == NULL)
+       return;                 /* nothing to do */
+
+   if (g_fout->remoteVersion < 70300)
+   {
+       write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
+       exit_nicely();
+   }
+
+   query = createPQExpBuffer();
+
    /*
-    * If specific tables are being dumped, do not dump any complete
-    * namespaces.  If specific namespaces are being dumped, dump just those
-    * namespaces. Otherwise, dump all non-system namespaces.
+    * We use UNION ALL rather than UNION; this might sometimes result in
+    * duplicate entries in the OID list, but we don't care.
     */
-   nsinfo->dobj.dump = false;
 
-   if (matchingTables != NULL)
-        /* false */ ;
-   else if (matchingSchemas != NULL)
+   for (cell = patterns->head; cell; cell = cell->next)
    {
-       char       *search_oid = malloc(20);
+       if (cell != patterns->head)
+           appendPQExpBuffer(query, "UNION ALL\n");
+       appendPQExpBuffer(query,
+                         "SELECT oid FROM pg_catalog.pg_namespace n\n");
+       processSQLNamePattern(g_conn, query, cell->val, false, false,
+                             NULL, "n.nspname", NULL,
+                             NULL);
+   }
 
-       sprintf(search_oid, " %d ", nsinfo->dobj.catId.oid);
-       if (strstr(matchingSchemas, search_oid) != NULL)
-           nsinfo->dobj.dump = true;
+   res = PQexec(g_conn, query->data);
+   check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
-       free(search_oid);
+   for (i = 0; i < PQntuples(res); i++)
+   {
+       simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    }
-   /* The server prevents users from creating pg_ schemas */
-   else if (strncmp(nsinfo->dobj.name, "pg_", 3) != 0 &&
-            strcmp(nsinfo->dobj.name, "information_schema") != 0)
-       nsinfo->dobj.dump = true;
+
+   PQclear(res);
+   destroyPQExpBuffer(query);
 }
 
 /*
- * selectDumpableTable: policy-setting subroutine
- *     Mark a table as to be dumped or not
+ * Find the OIDs of all tables matching the given list of patterns,
+ * and append them to the given OID list.
  */
 static void
-selectDumpableTable(TableInfo *tbinfo)
+expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
 {
+   PQExpBuffer query;
+   PGresult   *res;
+   SimpleStringListCell *cell;
+   int         i;
+
+   if (patterns->head == NULL)
+       return;                 /* nothing to do */
+
+   query = createPQExpBuffer();
+
    /*
-    * Always dump if dumping parent namespace; else, if a particular
-    * tablename has been specified, dump matching table name; else, do not
-    * dump.
+    * We use UNION ALL rather than UNION; this might sometimes result in
+    * duplicate entries in the OID list, but we don't care.
     */
-   tbinfo->dobj.dump = false;
 
-   if (matchingTables == NULL)
+   for (cell = patterns->head; cell; cell = cell->next)
    {
-       if (tbinfo->dobj.namespace->dobj.dump)
-           tbinfo->dobj.dump = true;
+       if (cell != patterns->head)
+           appendPQExpBuffer(query, "UNION ALL\n");
+       appendPQExpBuffer(query,
+                         "SELECT c.oid"
+                         "\nFROM pg_catalog.pg_class c"
+                         "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
+                         "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
+                         RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+       processSQLNamePattern(g_conn, query, cell->val, true, false,
+                             "n.nspname", "c.relname", NULL,
+                             "pg_catalog.pg_table_is_visible(c.oid)");
    }
-   else
-   {
-       char       *search_oid = malloc(20);
 
-       sprintf(search_oid, " %d ", tbinfo->dobj.catId.oid);
-       if (strstr(matchingTables, search_oid) != NULL)
-           tbinfo->dobj.dump = true;
+   res = PQexec(g_conn, query->data);
+   check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
-       free(search_oid);
+   for (i = 0; i < PQntuples(res); i++)
+   {
+       simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    }
+
+   PQclear(res);
+   destroyPQExpBuffer(query);
+}
+
+/*
+ * selectDumpableNamespace: policy-setting subroutine
+ *     Mark a namespace as to be dumped or not
+ */
+static void
+selectDumpableNamespace(NamespaceInfo *nsinfo)
+{
+   /*
+    * If specific tables are being dumped, do not dump any complete
+    * namespaces. If specific namespaces are being dumped, dump just those
+    * namespaces. Otherwise, dump all non-system namespaces.
+    */
+   if (table_include_oids.head != NULL)
+       nsinfo->dobj.dump = false;
+   else if (schema_include_oids.head != NULL)
+       nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
+                                                  nsinfo->dobj.catId.oid);
+   else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
+            strcmp(nsinfo->dobj.name, "information_schema") == 0)
+       nsinfo->dobj.dump = false;
+   else
+       nsinfo->dobj.dump = true;
+   /*
+    * In any case, a namespace can be excluded by an exclusion switch
+    */
+   if (nsinfo->dobj.dump &&
+       simple_oid_list_member(&schema_exclude_oids,
+                              nsinfo->dobj.catId.oid))
+       nsinfo->dobj.dump = false;
+}
+
+/*
+ * selectDumpableTable: policy-setting subroutine
+ *     Mark a table as to be dumped or not
+ */
+static void
+selectDumpableTable(TableInfo *tbinfo)
+{
+   /*
+    * If specific tables are being dumped, dump just those tables;
+    * else, dump according to the parent namespace's dump flag.
+    */
+   if (table_include_oids.head != NULL)
+       tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
+                                                  tbinfo->dobj.catId.oid);
+   else
+       tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
+   /*
+    * In any case, a table can be excluded by an exclusion switch
+    */
+   if (tbinfo->dobj.dump &&
+       simple_oid_list_member(&table_exclude_oids,
+                              tbinfo->dobj.catId.oid))
+       tbinfo->dobj.dump = false;
 }
 
 /*
@@ -5596,7 +5545,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 static bool
 shouldDumpProcLangs(void)
 {
-   if (matchingTables != NULL || matchingSchemas != NULL)
+   if (!include_everything)
        return false;
    /* And they're schema not data */
    if (dataOnly)
index 65f5e84c4164e95969a3d6f6379f16c7d3a5a054..dad62f960653099f8bcf75cb14a0cb4b8e5baae1 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.129 2006/08/21 00:57:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.130 2006/10/09 23:36:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,6 +41,35 @@ typedef struct
 
 typedef int DumpId;
 
+/*
+ * Data structures for simple lists of OIDs and strings.  The support for
+ * these is very primitive compared to the backend's List facilities, but
+ * it's all we need in pg_dump.
+ */
+
+typedef struct SimpleOidListCell
+{
+   struct SimpleOidListCell *next;
+   Oid         val;
+} SimpleOidListCell;
+
+typedef struct SimpleOidList
+{
+   SimpleOidListCell *head;
+   SimpleOidListCell *tail;
+} SimpleOidList;
+
+typedef struct SimpleStringListCell
+{
+   struct SimpleStringListCell *next;
+   char        val[1];         /* VARIABLE LENGTH FIELD */
+} SimpleStringListCell;
+
+typedef struct SimpleStringList
+{
+   SimpleStringListCell *head;
+   SimpleStringListCell *tail;
+} SimpleStringList;
 
 /*
  * The data structures used to store system catalog information.  Every
@@ -364,6 +393,16 @@ extern TypeInfo *findTypeByOid(Oid oid);
 extern FuncInfo *findFuncByOid(Oid oid);
 extern OprInfo *findOprByOid(Oid oid);
 
+extern void simple_oid_list_append(SimpleOidList *list, Oid val);
+extern void simple_string_list_append(SimpleStringList *list, const char *val);
+extern bool simple_oid_list_member(SimpleOidList *list, Oid val);
+extern bool simple_string_list_member(SimpleStringList *list, const char *val);
+
+extern char *pg_strdup(const char *string);
+extern void *pg_malloc(size_t size);
+extern void *pg_calloc(size_t nmemb, size_t size);
+extern void *pg_realloc(void *ptr, size_t size);
+
 extern void check_conn_and_db(void);
 extern void exit_nicely(void);