Commit 84107b41 authored by Tom Lane's avatar Tom Lane

Fix coredumping bug in pg_dump -z; also eliminate memory leaks

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.
parent 6a7fdf25
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* *
* *
* IDENTIFICATION * 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 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
* *
...@@ -92,9 +92,8 @@ static int findLastBuiltinOid(void); ...@@ -92,9 +92,8 @@ static int findLastBuiltinOid(void);
static bool isViewRule(char *relname); static bool isViewRule(char *relname);
static void setMaxOid(FILE *fout); static void setMaxOid(FILE *fout);
static char *AddAcl(char *s, const char *add); static void AddAcl(char *aclbuf, const char *keyword);
static char *GetPrivledges(char *s); static char *GetPrivileges(const char *s);
static ACL *ParseACL(const char *acls, int *count);
static void becomeUser(FILE *fout, const char *username); static void becomeUser(FILE *fout, const char *username);
extern char *optarg; extern char *optarg;
...@@ -1464,7 +1463,51 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1464,7 +1463,51 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks)); tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers)); 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) if (tblinfo[i].ncheck > 0)
{ {
PGresult *res2; PGresult *res2;
...@@ -1480,7 +1523,13 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1480,7 +1523,13 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
g_comment_end); g_comment_end);
sprintf(query, "SELECT rcname, rcsrc from pg_relcheck " 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); tblinfo[i].oid);
res2 = PQexec(g_conn, query); res2 = PQexec(g_conn, query);
if (!res2 || if (!res2 ||
...@@ -1504,10 +1553,10 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs) ...@@ -1504,10 +1553,10 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
char *name = PQgetvalue(res2, i2, i_rcname); char *name = PQgetvalue(res2, i2, i_rcname);
char *expr = PQgetvalue(res2, i2, i_rcsrc); char *expr = PQgetvalue(res2, i2, i_rcsrc);
query[0] = 0; query[0] = '\0';
if (name[0] != '$') if (name[0] != '$')
sprintf(query, "CONSTRAINT %s ", name); sprintf(query, "CONSTRAINT %s ", fmtId(name));
sprintf(query, "%sCHECK (%s)", query, expr); sprintf(query + strlen(query), "CHECK (%s)", expr);
tblinfo[i].check_expr[i2] = strdup(query); tblinfo[i].check_expr[i2] = strdup(query);
} }
PQclear(res2); PQclear(res2);
...@@ -2411,119 +2460,46 @@ dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs, ...@@ -2411,119 +2460,46 @@ dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
* *
* Matthew C. Aycock 12/02/97 * 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 * static void
AddAcl(char *s, const char *add) AddAcl (char *aclbuf, const char *keyword)
{ {
char *t; if (*aclbuf)
strcat(aclbuf, ",");
if (s == (char *) NULL) strcat(aclbuf, keyword);
return strdup(add);
t = (char *) calloc((strlen(s) + strlen(add) + 1), sizeof(char));
sprintf(t, "%s,%s", s, add);
return t;
} }
/* /*
* 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 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
*/ */
static char * static char *
GetPrivledges(char *s) GetPrivileges(const char *s)
{ {
char *acls = NULL; char aclbuf[100];
/* Grant All == arwR */ aclbuf[0] = '\0';
/* INSERT == a */
/* UPDATE/DELETE == w */
/* SELECT == r */
/* RULE == R */
if (strstr(s, "arwR"))
return strdup("ALL");
if (strchr(s, 'a')) if (strchr(s, 'a'))
acls = AddAcl(acls, "INSERT"); AddAcl(aclbuf, "INSERT");
if (strchr(s, 'w')) if (strchr(s, 'w'))
acls = AddAcl(acls, "UPDATE,DELETE"); AddAcl(aclbuf, "UPDATE,DELETE");
if (strchr(s, 'r')) if (strchr(s, 'r'))
acls = AddAcl(acls, "SELECT"); AddAcl(aclbuf, "SELECT");
if (strchr(s, 'R')) if (strchr(s, 'R'))
acls = AddAcl(acls, "RULES"); AddAcl(aclbuf, "RULE");
return acls;
}
/* This will parse the acl string of TableInfo /* Special-case when they're all there */
* into a two deminsional aray: if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
* user | Privledges return strdup("ALL");
* 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);
}
s = strdup(acls);
/* Setup up public */
ParsedAcl[0].user = NULL; /* indicates PUBLIC */
tok = strtok(s, ",");
ParsedAcl[0].privledges = GetPrivledges(strchr(tok, '='));
/* Do the rest of the users */ return strdup(aclbuf);
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;
} }
/* /*
...@@ -2535,46 +2511,70 @@ ParseACL(const char *acls, int *count) ...@@ -2535,46 +2511,70 @@ ParseACL(const char *acls, int *count)
static void static void
dumpACL(FILE *fout, TableInfo tbinfo) dumpACL(FILE *fout, TableInfo tbinfo)
{ {
int k, const char *acls = tbinfo.relacl;
l; char *aclbuf,
ACL *ACLlist; *tok,
*eqpos,
*priv;
ACLlist = ParseACL(tbinfo.relacl, &l); if (strlen(acls) == 0)
if (ACLlist == (ACL *) NULL) return; /* table has default permissions */
{
if (l == 0) /* 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);
/* Scan comma-separated ACL items */
for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
{ {
return; /* Token may start with '{' and/or '"'. Actually only the start of
} * the string should have '{', but we don't verify that.
else */
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", fprintf(stderr, "Could not parse ACL list for '%s'...Exiting!\n",
tbinfo.relname); tbinfo.relname);
exit_nicely(g_conn); exit_nicely(g_conn);
} }
}
/* Revoke Default permissions for PUBLIC */ /* Parse the privileges (right-hand side). Skip if there are none. */
fprintf(fout, priv = GetPrivileges(eqpos + 1);
"REVOKE ALL on %s from PUBLIC;\n", if (*priv)
fmtId(tbinfo.relname));
for (k = 0; k < l; k++)
{
if (ACLlist[k].privledges != (char *) NULL)
{ {
/* If you change this code, bear in mind fmtId() can be
* used only once per printf() call...
*/
fprintf(fout, fprintf(fout,
"GRANT %s on %s to ", "GRANT %s on %s to ",
ACLlist[k].privledges, fmtId(tbinfo.relname)); priv, fmtId(tbinfo.relname));
if (ACLlist[k].user == (char *) NULL) /* 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"); fprintf(fout, "PUBLIC;\n");
}
else 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, ...@@ -2592,9 +2592,7 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
int i, int i,
j, j,
k; k;
char q[MAXQUERYLEN], char q[MAXQUERYLEN];
id1[MAXQUERYLEN],
id2[MAXQUERYLEN];
char **parentRels; /* list of names of parent relations */ char **parentRels; /* list of names of parent relations */
int numParents; int numParents;
int actual_atts; /* number of attrs in this CREATE statment */ int actual_atts; /* number of attrs in this CREATE statment */
...@@ -2632,67 +2630,53 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables, ...@@ -2632,67 +2630,53 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
becomeUser(fout, tblinfo[i].usename); 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; actual_atts = 0;
for (j = 0; j < tblinfo[i].numatts; j++) for (j = 0; j < tblinfo[i].numatts; j++)
{ {
if (tblinfo[i].inhAttrs[j] == 0) 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 */ /* Show lengths on bpchar and varchar */
if (!strcmp(tblinfo[i].typnames[j], "bpchar")) if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
{ {
sprintf(q, "%s%s%s char", sprintf(q + strlen(q), "char(%d)",
q,
(actual_atts > 0) ? ", " : "",
fmtId(tblinfo[i].attnames[j]));
sprintf(q, "%s(%d)",
q,
tblinfo[i].atttypmod[j] - VARHDRSZ); tblinfo[i].atttypmod[j] - VARHDRSZ);
actual_atts++;
} }
else if (!strcmp(tblinfo[i].typnames[j], "varchar")) else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
{ {
sprintf(q, "%s%s%s %s", sprintf(q + strlen(q), "%s",
q,
(actual_atts > 0) ? ", " : "",
fmtId(tblinfo[i].attnames[j]),
tblinfo[i].typnames[j]); tblinfo[i].typnames[j]);
if(tblinfo[i].atttypmod[j] != -1) { if (tblinfo[i].atttypmod[j] != -1)
sprintf(q, "%s(%d)", {
q, sprintf(q + strlen(q), "(%d)",
tblinfo[i].atttypmod[j] - VARHDRSZ); tblinfo[i].atttypmod[j] - VARHDRSZ);
} }
else {
sprintf(q, "%s", q);
}
actual_atts++;
} }
else else
{ {
strcpy(id1, fmtId(tblinfo[i].attnames[j])); sprintf(q + strlen(q), "%s",
strcpy(id2, fmtId(tblinfo[i].typnames[j])); fmtId(tblinfo[i].typnames[j]));
sprintf(q, "%s%s%s %s",
q,
(actual_atts > 0) ? ", " : "",
id1,
id2);
actual_atts++;
} }
if (tblinfo[i].adef_expr[j] != NULL) 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]) if (tblinfo[i].notnull[j])
sprintf(q, "%s NOT NULL", q); strcat(q, " NOT NULL");
actual_atts++;
} }
} }
/* put the CONSTRAINTS inside the table def */ /* put the CONSTRAINTS inside the table def */
for (k = 0; k < tblinfo[i].ncheck; k++) for (k = 0; k < tblinfo[i].ncheck; k++)
{ {
sprintf(q, "%s%s %s", if (actual_atts + k > 0)
q, strcat(q, ",\n\t");
(actual_atts + k > 0) ? ", " : "", sprintf(q + strlen(q), "%s",
tblinfo[i].check_expr[k]); tblinfo[i].check_expr[k]);
} }
...@@ -2700,11 +2684,10 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables, ...@@ -2700,11 +2684,10 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
if (numParents > 0) if (numParents > 0)
{ {
sprintf(q, "%s inherits ( ", q); strcat(q, "\ninherits (");
for (k = 0; k < numParents; k++) for (k = 0; k < numParents; k++)
{ {
sprintf(q, "%s%s%s", sprintf(q + strlen(q), "%s%s",
q,
(k > 0) ? ", " : "", (k > 0) ? ", " : "",
fmtId(parentRels[k])); fmtId(parentRels[k]));
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
* *
...@@ -151,18 +151,6 @@ typedef struct _oprInfo ...@@ -151,18 +151,6 @@ typedef struct _oprInfo
char *usename; char *usename;
} OprInfo; } 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 */ /* global decls */
extern bool g_force_quotes; /* double-quotes for identifiers flag */ extern bool g_force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose flag */ extern bool g_verbose; /* verbose flag */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment