]> granicus.if.org Git - postgresql/commitdiff
Fix coredumping bug in pg_dump -z; also eliminate memory leaks
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Dec 1998 22:09:57 +0000 (22:09 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Dec 1998 22:09:57 +0000 (22:09 +0000)
in the ACL code, and spell "GRANT RULE" correctly.
Apply patch from Oliver Elphick to not dump inherited constraints.
Apply patch from Constantin Teodorescu to dump table definitions with a
readable layout.

src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h

index a4bd2a49b828bec40ecc9a328f15bd1782e2be07..5e508e91079faadbc7ed9498510bcaca9b4ec3be 100644 (file)
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.95 1998/11/15 07:09:13 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.96 1998/12/05 22:09:57 tgl Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
@@ -92,9 +92,8 @@ static int    findLastBuiltinOid(void);
 static bool isViewRule(char *relname);
 static void setMaxOid(FILE *fout);
 
-static char *AddAcl(char *s, const char *add);
-static char *GetPrivledges(char *s);
-static ACL *ParseACL(const char *acls, int *count);
+static void AddAcl(char *aclbuf, const char *keyword);
+static char *GetPrivileges(const char *s);
 static void becomeUser(FILE *fout, const char *username);
 
 extern char *optarg;
@@ -1464,7 +1463,51 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
                tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
 
-               /* Get CHECK constraints */
+               /* Exclude inherited CHECKs from CHECK constraints total.
+                * If a constraint matches by name and condition with a constraint
+                * belonging to a parent class, we assume it was inherited.
+                */
+               if (tblinfo[i].ncheck > 0)
+               {
+                       PGresult        *res2;
+                       int                     ntups2;
+
+                       if (g_verbose)
+                               fprintf(stderr, "%s excluding inherited CHECK constraints "
+                                               "for relation: '%s' %s\n",
+                                               g_comment_start,
+                                               tblinfo[i].relname,
+                                               g_comment_end);
+
+                       sprintf(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
+                                       "where rcrelid = '%s'::oid "
+                                       " and rcrelid = i.inhrel"
+                                       " and exists "
+                                       "  (select * from pg_relcheck as c "
+                                       "    where c.rcname = pg_relcheck.rcname "
+                                       "      and c.rcsrc = pg_relcheck.rcsrc "
+                                       "      and c.rcrelid = i.inhparent) ",
+                                       tblinfo[i].oid);
+                       res2 = PQexec(g_conn, query);
+                       if (!res2 ||
+                               PQresultStatus(res2) != PGRES_TUPLES_OK)
+                       {
+                               fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed\n");
+                               exit_nicely(g_conn);
+                       }
+                       ntups2 = PQntuples(res2);
+                       tblinfo[i].ncheck -= ntups2;
+                       if (tblinfo[i].ncheck < 0)
+                       {
+                               fprintf(stderr, "getTables(): found more inherited CHECKs than total for "
+                                               "relation %s\n",
+                                               tblinfo[i].relname);
+                               exit_nicely(g_conn);
+                       }
+                       PQclear(res2);
+               }
+
+               /* Get non-inherited CHECK constraints, if any */
                if (tblinfo[i].ncheck > 0)
                {
                        PGresult   *res2;
@@ -1480,7 +1523,13 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                                                g_comment_end);
 
                        sprintf(query, "SELECT rcname, rcsrc from pg_relcheck "
-                                       "where rcrelid = '%s'::oid ",
+                                       "where rcrelid = '%s'::oid "
+                                       "   and not exists "
+                                       "  (select * from pg_relcheck as c, pg_inherits as i "
+                                       "   where i.inhrel = pg_relcheck.rcrelid "
+                                       "     and c.rcname = pg_relcheck.rcname "
+                                       "     and c.rcsrc = pg_relcheck.rcsrc "
+                                       "     and c.rcrelid = i.inhparent) ",
                                        tblinfo[i].oid);
                        res2 = PQexec(g_conn, query);
                        if (!res2 ||
@@ -1504,10 +1553,10 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                                char       *name = PQgetvalue(res2, i2, i_rcname);
                                char       *expr = PQgetvalue(res2, i2, i_rcsrc);
 
-                               query[0] = 0;
+                               query[0] = '\0';
                                if (name[0] != '$')
-                                       sprintf(query, "CONSTRAINT %s ", name);
-                               sprintf(query, "%sCHECK (%s)", query, expr);
+                                       sprintf(query, "CONSTRAINT %s ", fmtId(name));
+                               sprintf(query + strlen(query), "CHECK (%s)", expr);
                                tblinfo[i].check_expr[i2] = strdup(query);
                        }
                        PQclear(res2);
@@ -2411,119 +2460,46 @@ dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
  *
  * Matthew C. Aycock 12/02/97
  */
-/*
- * This will return a new string: "s,add"
+
+/* Append a keyword to a keyword list, inserting comma if needed.
+ * Caller must make aclbuf big enough for all possible keywords.
  */
-static char *
-AddAcl(char *s, const char *add)
+static void
+AddAcl (char *aclbuf, const char *keyword)
 {
-       char       *t;
-
-       if (s == (char *) NULL)
-               return strdup(add);
-
-       t = (char *) calloc((strlen(s) + strlen(add) + 1), sizeof(char));
-       sprintf(t, "%s,%s", s, add);
-
-       return t;
+       if (*aclbuf)
+               strcat(aclbuf, ",");
+       strcat(aclbuf, keyword);
 }
 
 /*
- * This will take a string of 'arwR' and return a
+ * This will take a string of 'arwR' and return a malloced,
  * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
  */
 static char *
-GetPrivledges(char *s)
+GetPrivileges(const char *s)
 {
-       char       *acls = NULL;
+       char            aclbuf[100];
 
-       /* Grant All     == arwR */
-       /* INSERT                == a   */
-       /* UPDATE/DELETE == w   */
-       /* SELECT                == r   */
-       /* RULE                  == R   */
-
-       if (strstr(s, "arwR"))
-               return strdup("ALL");
+       aclbuf[0] = '\0';
 
        if (strchr(s, 'a'))
-               acls = AddAcl(acls, "INSERT");
+               AddAcl(aclbuf, "INSERT");
 
        if (strchr(s, 'w'))
-               acls = AddAcl(acls, "UPDATE,DELETE");
+               AddAcl(aclbuf, "UPDATE,DELETE");
 
        if (strchr(s, 'r'))
-               acls = AddAcl(acls, "SELECT");
+               AddAcl(aclbuf, "SELECT");
 
        if (strchr(s, 'R'))
-               acls = AddAcl(acls, "RULES");
-
-       return acls;
-}
-
-/* This will parse the acl string of TableInfo
- * into a two deminsional aray:
- *       user | Privledges
- * So to reset the acls I need to grant these priviledges
- * to user
- */
-static ACL *
-ParseACL(const char *acls, int *count)
-{
-       ACL                *ParsedAcl = NULL;
-       int                     i,
-                               len,
-                               NumAcls = 1,    /* There is always public */
-                               AclLen = 0;
-       char       *s = NULL,
-                          *user = NULL,
-                          *priv = NULL,
-                          *tok;
-
-       AclLen = strlen(acls);
-
-       if (AclLen == 0)
-       {
-               *count = 0;
-               return (ACL *) NULL;
-       }
-
-       for (i = 0; i < AclLen; i++)
-               if (acls[i] == ',')
-                       NumAcls++;
-
-       ParsedAcl = (ACL *) calloc(AclLen, sizeof(ACL));
-       if (!ParsedAcl)
-       {
-               fprintf(stderr, "Could not allocate space for ACLS!\n");
-               exit_nicely(g_conn);
-       }
+               AddAcl(aclbuf, "RULE");
 
-       s = strdup(acls);
-
-       /* Setup up public */
-       ParsedAcl[0].user = NULL;       /* indicates PUBLIC */
-       tok = strtok(s, ",");
-       ParsedAcl[0].privledges = GetPrivledges(strchr(tok, '='));
+       /* Special-case when they're all there */
+       if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
+               return strdup("ALL");
 
-       /* Do the rest of the users */
-       i = 1;
-       while ((i < NumAcls) && ((tok = strtok(NULL, ",")) != (char *) NULL))
-       {
-               /* User name is string up to = in tok */
-               len = strchr(tok, '=') - tok - 1;
-               user = (char *) calloc(len + 1, sizeof(char));
-               strncpy(user, tok + 1, len);
-               if (user[len - 1] == '\"')
-                       user[len - 1] = (char) NULL;
-               priv = GetPrivledges(tok + len + 2);
-               ParsedAcl[i].user = user;
-               ParsedAcl[i].privledges = priv;
-               i++;
-       }
-
-       *count = NumAcls;
-       return ParsedAcl;
+       return strdup(aclbuf);
 }
 
 /*
@@ -2535,46 +2511,70 @@ ParseACL(const char *acls, int *count)
 static void
 dumpACL(FILE *fout, TableInfo tbinfo)
 {
-       int                     k,
-                               l;
-       ACL                *ACLlist;
+       const char *acls = tbinfo.relacl;
+       char       *aclbuf,
+                          *tok,
+                          *eqpos,
+                          *priv;
+
+       if (strlen(acls) == 0)
+               return;                                 /* table has default permissions */
+
+       /* Revoke Default permissions for PUBLIC.
+        * Is this actually necessary, or is it just a waste of time?
+        */
+       fprintf(fout,
+                       "REVOKE ALL on %s from PUBLIC;\n",
+                       fmtId(tbinfo.relname));
+
+       /* Make a working copy of acls so we can use strtok */
+       aclbuf = strdup(acls);
 
-       ACLlist = ParseACL(tbinfo.relacl, &l);
-       if (ACLlist == (ACL *) NULL)
+       /* Scan comma-separated ACL items */
+       for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
        {
-               if (l == 0)
-               {
-                       return;
-               }
-               else
+               /* Token may start with '{' and/or '"'.  Actually only the start of
+                * the string should have '{', but we don't verify that.
+                */
+               if (*tok == '{')
+                       tok++;
+               if (*tok == '"')
+                       tok++;
+
+               /* User name is string up to = in tok */
+               eqpos = strchr(tok, '=');
+               if (! eqpos)
                {
                        fprintf(stderr, "Could not parse ACL list for '%s'...Exiting!\n",
                                        tbinfo.relname);
                        exit_nicely(g_conn);
                }
-       }
-
-       /* Revoke Default permissions for PUBLIC */
-       fprintf(fout,
-                       "REVOKE ALL on %s from PUBLIC;\n",
-                       fmtId(tbinfo.relname));
 
-       for (k = 0; k < l; k++)
-       {
-               if (ACLlist[k].privledges != (char *) NULL)
+               /* Parse the privileges (right-hand side).  Skip if there are none. */
+               priv = GetPrivileges(eqpos + 1);
+               if (*priv)
                {
-                       /* If you change this code, bear in mind fmtId() can be
-                        * used only once per printf() call...
-                        */
                        fprintf(fout,
                                        "GRANT %s on %s to ",
-                                       ACLlist[k].privledges, fmtId(tbinfo.relname));
-                       if (ACLlist[k].user == (char *) NULL)
+                                       priv, fmtId(tbinfo.relname));
+                       /* Note: fmtId() can only be called once per printf, so don't
+                        * try to merge printing of username into the above printf.
+                        */
+                       if (eqpos == tok)
+                       {
+                               /* Empty left-hand side means "PUBLIC" */
                                fprintf(fout, "PUBLIC;\n");
+                       }
                        else
-                               fprintf(fout, "%s;\n", fmtId(ACLlist[k].user));
+                       {
+                               *eqpos = '\0';  /* it's ok to clobber aclbuf */
+                               fprintf(fout, "%s;\n", fmtId(tok));
+                       }
                }
+               free(priv);
        }
+
+       free(aclbuf);
 }
 
 
@@ -2592,9 +2592,7 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
        int                     i,
                                j,
                                k;
-       char            q[MAXQUERYLEN],
-                               id1[MAXQUERYLEN],
-                               id2[MAXQUERYLEN];
+       char            q[MAXQUERYLEN];
        char      **parentRels;         /* list of names of parent relations */
        int                     numParents;
        int                     actual_atts;    /* number of attrs in this CREATE statment */
@@ -2632,67 +2630,53 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
 
                        becomeUser(fout, tblinfo[i].usename);
 
-                       sprintf(q, "CREATE TABLE %s (", fmtId(tblinfo[i].relname));
+                       sprintf(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname));
                        actual_atts = 0;
                        for (j = 0; j < tblinfo[i].numatts; j++)
                        {
                                if (tblinfo[i].inhAttrs[j] == 0)
                                {
+                                       if (actual_atts > 0)
+                                               strcat(q, ",\n\t");
+                                       sprintf(q + strlen(q), "%s ",
+                                                       fmtId(tblinfo[i].attnames[j]));
 
                                        /* Show lengths on bpchar and varchar */
                                        if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
                                        {
-                                               sprintf(q, "%s%s%s char",
-                                                               q,
-                                                               (actual_atts > 0) ? ", " : "",
-                                                               fmtId(tblinfo[i].attnames[j]));
-
-                                               sprintf(q, "%s(%d)",
-                                                               q,
+                                               sprintf(q + strlen(q), "char(%d)",
                                                                tblinfo[i].atttypmod[j] - VARHDRSZ);
-                                               actual_atts++;
                                        }
                                        else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
                                        {
-                                               sprintf(q, "%s%s%s %s",
-                                                               q,
-                                                               (actual_atts > 0) ? ", " : "",
-                                                               fmtId(tblinfo[i].attnames[j]),
+                                               sprintf(q + strlen(q), "%s",
                                                                tblinfo[i].typnames[j]);
-                                               if(tblinfo[i].atttypmod[j] != -1) {
-                                                       sprintf(q, "%s(%d)",
-                                                               q,
-                                                               tblinfo[i].atttypmod[j] - VARHDRSZ);
-                                               }
-                                               else {
-                                                       sprintf(q, "%s", q);
+                                               if (tblinfo[i].atttypmod[j] != -1)
+                                               {
+                                                       sprintf(q + strlen(q), "(%d)",
+                                                                       tblinfo[i].atttypmod[j] - VARHDRSZ);
                                                }
-                                               actual_atts++;
                                        }
                                        else
                                        {
-                                               strcpy(id1, fmtId(tblinfo[i].attnames[j]));
-                                               strcpy(id2, fmtId(tblinfo[i].typnames[j]));
-                                               sprintf(q, "%s%s%s %s",
-                                                               q,
-                                                               (actual_atts > 0) ? ", " : "",
-                                                               id1,
-                                                               id2);
-                                               actual_atts++;
+                                               sprintf(q + strlen(q), "%s",
+                                                               fmtId(tblinfo[i].typnames[j]));
                                        }
                                        if (tblinfo[i].adef_expr[j] != NULL)
-                                               sprintf(q, "%s DEFAULT %s", q, tblinfo[i].adef_expr[j]);
+                                               sprintf(q + strlen(q), " DEFAULT %s",
+                                                               tblinfo[i].adef_expr[j]);
                                        if (tblinfo[i].notnull[j])
-                                               sprintf(q, "%s NOT NULL", q);
+                                               strcat(q, " NOT NULL");
+                                       actual_atts++;
                                }
                        }
 
                        /* put the CONSTRAINTS inside the table def */
                        for (k = 0; k < tblinfo[i].ncheck; k++)
                        {
-                               sprintf(q, "%s%s %s",
-                                               q,
-                                               (actual_atts + k > 0) ? ", " : "",
+                               if (actual_atts + k > 0)
+                                       strcat(q, ",\n\t");
+                               sprintf(q + strlen(q), "%s",
                                                tblinfo[i].check_expr[k]);
                        }
 
@@ -2700,11 +2684,10 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
 
                        if (numParents > 0)
                        {
-                               sprintf(q, "%s inherits ( ", q);
+                               strcat(q, "\ninherits (");
                                for (k = 0; k < numParents; k++)
                                {
-                                       sprintf(q, "%s%s%s",
-                                                       q,
+                                       sprintf(q + strlen(q), "%s%s",
                                                        (k > 0) ? ", " : "",
                                                        fmtId(parentRels[k]));
                                }
index 67e2bfc9d0c0b9b4e01230081718d06940a3b7ab..2a6fb95eae7fb005b6611ad70490dd3934dbbc5c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.35 1998/10/06 22:14:21 momjian Exp $
+ * $Id: pg_dump.h,v 1.36 1998/12/05 22:09:56 tgl Exp $
  *
  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
  *
@@ -151,18 +151,6 @@ typedef struct _oprInfo
        char       *usename;
 } OprInfo;
 
-/*
- * This is some support functions to fix the acl problem of pg_dump
- *
- * Matthew C. Aycock 12/02/97
- */
-typedef struct _AclType
-{
-       char       *user;
-       char       *privledges;
-} ACL;
-
-
 /* global decls */
 extern bool g_force_quotes;            /* double-quotes for identifiers flag */
 extern bool g_verbose;                 /* verbose flag */