Allow multiple -n (schema) and -t (table) pg_dump options, and add -T
authorBruce Momjian
Tue, 1 Aug 2006 18:05:04 +0000 (18:05 +0000)
committerBruce Momjian
Tue, 1 Aug 2006 18:05:04 +0000 (18:05 +0000)
and -N options to exclude objects.  Also support regular expressions for
option object names.

Greg Sabino Mullane

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 150bf7b0f688007decb25f5e3768ad141c9356fc..baa23d1e5e54a40444134079668e64de243db4b2 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -398,24 +398,107 @@ 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.  Specify both
-        
+        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.
        
 
+       
+       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.
+       
+
+       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 table
+         attempt to dump any other database objects that the selected tables
          may depend upon. Therefore, there is no guarantee
-         that the results of a single-table dump can be successfully
+         that the results of a specific-table dump can be successfully
          restored by themselves into a clean database.
         
        
       
      
 
+     
+      
+      
+      
+       
+        Do not dump any matching tables.
+        More than one option can be used, and POSIX regular expressions are handled just
+        like -t.
+       
+      
+     
+
+     
+      
+      
+      
+       
+        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.
+       
+
+      
+     
+
      
       
       
index fdaee77739b23cf34a540414bbbc58c3c87f4fdd..fc737d59ac251db4d293fae81ab92d7e3c5dfa99 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.91 2006/07/14 14:52:26 momjian Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.92 2006/08/01 18:05:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,9 +72,7 @@ static int    strInArray(const char *pattern, char **arr, int arr_size);
  *   Collect information about all potentially dumpable objects
  */
 TableInfo *
-getSchemaData(int *numTablesPtr,
-             const bool schemaOnly,
-             const bool dataOnly)
+getSchemaData(int *numTablesPtr)
 {
    NamespaceInfo *nsinfo;
    AggInfo    *agginfo;
index ea697739191a70ff71b45896136794fdb8c2d2cd..bf2874f3df8bad8a2d06f85f6e44d5ff01aa1163 100644 (file)
@@ -12,7 +12,7 @@
  * by PostgreSQL
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.442 2006/07/27 19:52:06 tgl Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.443 2006/08/01 18:05:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -91,8 +91,19 @@ static const char *username_subquery;
 /* obsolete as of 7.3: */
 static Oid g_last_builtin_oid; /* value of the last builtin oid */
 
-static char *selectTableName = NULL;   /* name of a single table to dump */
-static char *selectSchemaName = NULL;  /* name of a single schema to dump */
+/* select and exclude tables and schemas */
+typedef struct objnameArg
+{
+   struct objnameArg *next;
+   char *name;         /* name of the relation */
+   bool is_include;    /* include/exclude? */
+} objnameArg;
+
+objnameArg *schemaList = NULL; /* List of schemas to include/exclude */
+objnameArg *tableList = NULL; /* List of tables to include/exclude */
+
+char *matchingSchemas = NULL; /* Final list of schemas to dump by oid */
+char *matchingTables = NULL; /* Final list of tables to dump by oid */
 
 char       g_opaque_type[10];  /* name for the opaque type */
 
@@ -180,6 +191,9 @@ 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 = NULL;
    int         c;
    const char *filename = NULL;
    const char *format = "p";
@@ -195,6 +209,7 @@ 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;
@@ -226,9 +241,11 @@ main(int argc, char **argv)
        {"no-owner", no_argument, NULL, 'O'},
        {"port", required_argument, NULL, 'p'},
        {"schema", required_argument, NULL, 'n'},
+       {"exclude-schema", required_argument, NULL, 'N'},
        {"schema-only", no_argument, NULL, 's'},
        {"superuser", required_argument, NULL, 'S'},
        {"table", required_argument, NULL, 't'},
+       {"exclude-table", required_argument, NULL, 'T'},
        {"password", no_argument, NULL, 'W'},
        {"username", required_argument, NULL, 'U'},
        {"verbose", no_argument, NULL, 'v'},
@@ -281,9 +298,11 @@ main(int argc, char **argv)
        }
    }
 
-   while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:oOp:RsS:t:uU:vWxX:Z:",
+   while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:uU:vWxX:Z:",
                            long_options, &optindex)) != -1)
    {
+       objnameArg *schemaList_tail = NULL, *tableList_tail = NULL;
+
        switch (c)
        {
            case 'a':           /* Dump data only */
@@ -332,8 +351,42 @@ main(int argc, char **argv)
                ignore_version = true;
                break;
 
-           case 'n':           /* Dump data for this schema only */
-               selectSchemaName = strdup(optarg);
+           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(c) ? true : false;
+
+                   /* add new entry to the proper list */
+                   if (tolower(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;
+                   }
+               }
                break;
 
            case 'o':           /* Dump oids */
@@ -361,10 +414,6 @@ main(int argc, char **argv)
                outputSuperuser = strdup(optarg);
                break;
 
-           case 't':           /* Dump data for this table only */
-               selectTableName = strdup(optarg);
-               break;
-
            case 'u':
                force_password = true;
                username = simple_prompt("User name: ", 100, true);
@@ -449,7 +498,7 @@ main(int argc, char **argv)
        exit(1);
    }
 
-   if (selectTableName != NULL || selectSchemaName != NULL)
+   if (matchingTables != NULL || matchingSchemas != NULL)
        outputBlobs = false;
 
    if (dumpInserts == true && oids == true)
@@ -568,11 +617,157 @@ 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)
+   {
+       write_msg(NULL, "Postgres must be at least version 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 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)
+       {
+           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, " ");
+       }
+   }
+
+   /* 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)
+   {
+       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 oid FROM pg_catalog.pg_class WHERE relkind='r' 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)
+       {
+           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, " ");
+       }
+   }
+
+   destroyPQExpBuffer(query);
+
    /*
     * Now scan the database and create DumpableObject structs for all the
     * objects we intend to dump.
     */
-   tblinfo = getSchemaData(&numTables, schemaOnly, dataOnly);
+   tblinfo = getSchemaData(&numTables);
 
    if (!schemaOnly)
        getTableData(tblinfo, numTables, oids);
@@ -628,7 +823,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 && selectTableName == NULL && selectSchemaName == NULL)
+   if (!dataOnly && matchingTables == NULL && matchingSchemas == NULL)
        dumpDatabase(g_fout);
 
    /* Now the rearrangeable objects. */
@@ -687,28 +882,30 @@ help(const char *progname)
    printf(_("  --version                output version information, then exit\n"));
 
    printf(_("\nOptions controlling the output content:\n"));
-   printf(_("  -a, --data-only          dump only the data, not the schema\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, rather than COPY, commands\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(_("  -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(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
+   printf(_("  -a, --data-only             dump only the data, not the schema\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, rather than COPY, commands\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 do NOT dump the named schema\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(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
    printf(_("  -X disable-dollar-quoting, --disable-dollar-quoting\n"
-            "                           disable dollar quoting, use SQL standard quoting\n"));
+            "                              disable dollar quoting, use SQL standard quoting\n"));
    printf(_("  -X disable-triggers, --disable-triggers\n"
-            "                           disable triggers during data-only restore\n"));
+            "                              disable triggers during data-only restore\n"));
    printf(_("  -X use-set-session-authorization, --use-set-session-authorization\n"
-            "                           use SESSION AUTHORIZATION commands instead of\n"
-            "                           OWNER TO commands\n"));
+            "                              use SESSION AUTHORIZATION commands instead of\n"
+            "                              OWNER TO commands\n"));
 
    printf(_("\nConnection options:\n"));
    printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
@@ -738,18 +935,20 @@ static void
 selectDumpableNamespace(NamespaceInfo *nsinfo)
 {
    /*
-    * If a specific table is being dumped, do not dump any complete
-    * namespaces.  If a specific namespace is being dumped, dump just that
-    * namespace. Otherwise, dump all non-system namespaces.
+    * 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 (selectTableName != NULL)
+   if (matchingTables != NULL)
        nsinfo->dobj.dump = false;
-   else if (selectSchemaName != NULL)
+   else if (matchingSchemas != NULL)
    {
-       if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
+       char *searchname = NULL;
+       searchname = malloc(20);
+       sprintf(searchname, " %d ", nsinfo->dobj.catId.oid);
+       if (strstr(matchingSchemas, searchname) != NULL)
            nsinfo->dobj.dump = true;
-       else
-           nsinfo->dobj.dump = false;
+       free(searchname);
    }
    else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
             strcmp(nsinfo->dobj.name, "information_schema") == 0)
@@ -771,16 +970,16 @@ selectDumpableTable(TableInfo *tbinfo)
     * dump.
     */
    tbinfo->dobj.dump = false;
-   if (tbinfo->dobj.namespace->dobj.dump)
+   if (tbinfo->dobj.namespace->dobj.dump || matchingTables == NULL)
        tbinfo->dobj.dump = true;
-   else if (selectTableName != NULL &&
-            strcmp(tbinfo->dobj.name, selectTableName) == 0)
+   else
    {
-       /* If both -s and -t specified, must match both to dump */
-       if (selectSchemaName == NULL)
-           tbinfo->dobj.dump = true;
-       else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
+       char *searchname = NULL;
+       searchname = malloc(20);
+       sprintf(searchname, " %d ", tbinfo->dobj.catId.oid);
+       if (strstr(matchingTables, searchname) != NULL)
            tbinfo->dobj.dump = true;
+       free(searchname);
    }
 }
 
@@ -1722,25 +1921,6 @@ getNamespaces(int *numNamespaces)
                      nsinfo[i].dobj.name);
    }
 
-   /*
-    * If the user attempted to dump a specific namespace, check to ensure
-    * that the specified namespace actually exists.
-    */
-   if (selectSchemaName)
-   {
-       for (i = 0; i < ntups; i++)
-           if (strcmp(nsinfo[i].dobj.name, selectSchemaName) == 0)
-               break;
-
-       /* Didn't find a match */
-       if (i == ntups)
-       {
-           write_msg(NULL, "specified schema \"%s\" does not exist\n",
-                     selectSchemaName);
-           exit_nicely();
-       }
-   }
-
    PQclear(res);
    destroyPQExpBuffer(query);
 
@@ -2905,26 +3085,6 @@ getTables(int *numTables)
                      tblinfo[i].dobj.name);
    }
 
-   /*
-    * If the user is attempting to dump a specific table, check to ensure
-    * that the specified table actually exists.  (This is a bit simplistic
-    * since we don't fully check the combination of -n and -t switches.)
-    */
-   if (selectTableName)
-   {
-       for (i = 0; i < ntups; i++)
-           if (strcmp(tblinfo[i].dobj.name, selectTableName) == 0)
-               break;
-
-       /* Didn't find a match */
-       if (i == ntups)
-       {
-           write_msg(NULL, "specified table \"%s\" does not exist\n",
-                     selectTableName);
-           exit_nicely();
-       }
-   }
-
    PQclear(res);
    destroyPQExpBuffer(query);
    destroyPQExpBuffer(delqry);
@@ -5438,7 +5598,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 static bool
 shouldDumpProcLangs(void)
 {
-   if (selectTableName != NULL || selectSchemaName != NULL)
+   if (matchingTables != NULL || matchingSchemas != NULL)
        return false;
    /* And they're schema not data */
    if (dataOnly)
index 738eff36ac8227f198ac00712c6030653d399d6e..3650ae50de2d19dd4c365c7d8016866c7a93edb8 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.127 2006/07/27 19:52:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.128 2006/08/01 18:05:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -340,9 +340,7 @@ extern char g_opaque_type[10];  /* name for the opaque type */
  * common utility functions
  */
 
-extern TableInfo *getSchemaData(int *numTablesPtr,
-             const bool schemaOnly,
-             const bool dataOnly);
+extern TableInfo *getSchemaData(int *numTablesPtr);
 
 typedef enum _OidOptions
 {