Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions | Variables

dumputils.c File Reference

#include "postgres_fe.h"
#include <ctype.h>
#include "dumputils.h"
#include "parser/keywords.h"
Include dependency graph for dumputils.c:

Go to the source code of this file.

Defines

#define supports_grant_options(version)   ((version) >= 70400)
#define CONVERT_PRIV(code, keywd)
#define WHEREAND()

Functions

static bool parseAclItem (const char *item, const char *type, const char *name, const char *subname, int remoteVersion, PQExpBuffer grantee, PQExpBuffer grantor, PQExpBuffer privs, PQExpBuffer privswgo)
static char * copyAclUserName (PQExpBuffer output, char *input)
static void AddAcl (PQExpBuffer aclbuf, const char *keyword, const char *subname)
static PQExpBuffer defaultGetLocalPQExpBuffer (void)
const char * fmtId (const char *rawid)
const char * fmtQualifiedId (int remoteVersion, const char *schema, const char *id)
void appendStringLiteral (PQExpBuffer buf, const char *str, int encoding, bool std_strings)
void appendStringLiteralConn (PQExpBuffer buf, const char *str, PGconn *conn)
void appendStringLiteralDQ (PQExpBuffer buf, const char *str, const char *dqprefix)
void appendByteaLiteral (PQExpBuffer buf, const unsigned char *str, size_t length, bool std_strings)
bool parsePGArray (const char *atext, char ***itemarray, int *nitems)
bool buildACLCommands (const char *name, const char *subname, const char *type, const char *acls, const char *owner, const char *prefix, int remoteVersion, PQExpBuffer sql)
bool buildDefaultACLCommands (const char *type, const char *nspname, const char *acls, const char *owner, int remoteVersion, PQExpBuffer sql)
bool processSQLNamePattern (PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
void buildShSecLabelQuery (PGconn *conn, const char *catalog_name, uint32 objectId, PQExpBuffer sql)
void emitShSecLabels (PGconn *conn, PGresult *res, PQExpBuffer buffer, const char *target, const char *objname)
void simple_string_list_append (SimpleStringList *list, const char *val)
bool simple_string_list_member (SimpleStringList *list, const char *val)

Variables

const ScanKeyword FEScanKeywords []
const int NumFEScanKeywords
int quote_all_identifiers = 0
PQExpBuffer(* getLocalPQExpBuffer )(void) = defaultGetLocalPQExpBuffer

Define Documentation

#define CONVERT_PRIV (   code,
  keywd 
)
Value:
do { \
    if ((pos = strchr(eqpos + 1, code))) \
    { \
        if (*(pos + 1) == '*') \
        { \
            AddAcl(privswgo, keywd, subname); \
            all_without_go = false; \
        } \
        else \
        { \
            AddAcl(privs, keywd, subname); \
            all_with_go = false; \
        } \
    } \
    else \
        all_with_go = all_without_go = false; \
} while (0)

Referenced by parseAclItem().

#define supports_grant_options (   version  )     ((version) >= 70400)

Definition at line 28 of file dumputils.c.

Referenced by buildACLCommands().

#define WHEREAND (  ) 
Value:
(appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
     have_where = true, added_clause = true)

Referenced by processSQLNamePattern().


Function Documentation

static void AddAcl ( PQExpBuffer  aclbuf,
const char *  keyword,
const char *  subname 
) [static]

Definition at line 946 of file dumputils.c.

References appendPQExpBuffer(), appendPQExpBufferChar(), and PQExpBufferData::len.

{
    if (aclbuf->len > 0)
        appendPQExpBufferChar(aclbuf, ',');
    appendPQExpBuffer(aclbuf, "%s", keyword);
    if (subname)
        appendPQExpBuffer(aclbuf, "(%s)", subname);
}

void appendByteaLiteral ( PQExpBuffer  buf,
const unsigned char *  str,
size_t  length,
bool  std_strings 
)

Definition at line 351 of file dumputils.c.

References PQExpBufferData::data, enlargePQExpBuffer(), hextbl, and PQExpBufferData::len.

{
    const unsigned char *source = str;
    char       *target;

    static const char hextbl[] = "0123456789abcdef";

    /*
     * This implementation is hard-wired to produce hex-format output. We do
     * not know the server version the output will be loaded into, so making
     * an intelligent format choice is impossible.  It might be better to
     * always use the old escaped format.
     */
    if (!enlargePQExpBuffer(buf, 2 * length + 5))
        return;

    target = buf->data + buf->len;
    *target++ = '\'';
    if (!std_strings)
        *target++ = '\\';
    *target++ = '\\';
    *target++ = 'x';

    while (length-- > 0)
    {
        unsigned char c = *source++;

        *target++ = hextbl[(c >> 4) & 0xF];
        *target++ = hextbl[c & 0xF];
    }

    /* Write the terminating quote and NUL character. */
    *target++ = '\'';
    *target = '\0';

    buf->len = target - buf->data;
}

void appendStringLiteral ( PQExpBuffer  buf,
const char *  str,
int  encoding,
bool  std_strings 
)

Definition at line 192 of file dumputils.c.

References PQExpBufferData::data, enlargePQExpBuffer(), i, IS_HIGHBIT_SET, PQExpBufferData::len, length(), PQExpBufferData::maxlen, PQmblen(), and SQL_STR_DOUBLE.

Referenced by appendStringLiteralConn().

{
    size_t      length = strlen(str);
    const char *source = str;
    char       *target;

    if (!enlargePQExpBuffer(buf, 2 * length + 2))
        return;

    target = buf->data + buf->len;
    *target++ = '\'';

    while (*source != '\0')
    {
        char        c = *source;
        int         len;
        int         i;

        /* Fast path for plain ASCII */
        if (!IS_HIGHBIT_SET(c))
        {
            /* Apply quoting if needed */
            if (SQL_STR_DOUBLE(c, !std_strings))
                *target++ = c;
            /* Copy the character */
            *target++ = c;
            source++;
            continue;
        }

        /* Slow path for possible multibyte characters */
        len = PQmblen(source, encoding);

        /* Copy the character */
        for (i = 0; i < len; i++)
        {
            if (*source == '\0')
                break;
            *target++ = *source++;
        }

        /*
         * If we hit premature end of string (ie, incomplete multibyte
         * character), try to pad out to the correct length with spaces. We
         * may not be able to pad completely, but we will always be able to
         * insert at least one pad space (since we'd not have quoted a
         * multibyte character).  This should be enough to make a string that
         * the server will error out on.
         */
        if (i < len)
        {
            char       *stop = buf->data + buf->maxlen - 2;

            for (; i < len; i++)
            {
                if (target >= stop)
                    break;
                *target++ = ' ';
            }
            break;
        }
    }

    /* Write the terminating quote and NUL character. */
    *target++ = '\'';
    *target = '\0';

    buf->len = target - buf->data;
}

void appendStringLiteralConn ( PQExpBuffer  buf,
const char *  str,
PGconn conn 
)

Definition at line 270 of file dumputils.c.

References appendPQExpBufferChar(), appendStringLiteral(), PQExpBufferData::data, enlargePQExpBuffer(), ESCAPE_STRING_SYNTAX, PQExpBufferData::len, length(), NULL, PQclientEncoding(), PQescapeStringConn(), and PQserverVersion().

Referenced by dumpCreateDB(), dumpDatabaseConfig(), dumpRoles(), dumpTablespaces(), dumpUserConfig(), emitShSecLabels(), exec_command(), getTables(), lookup_function_oid(), main(), makeAlterConfigCommand(), processSQLNamePattern(), and setup_connection().

{
    size_t      length = strlen(str);

    /*
     * XXX This is a kluge to silence escape_string_warning in our utility
     * programs.  It should go away someday.
     */
    if (strchr(str, '\\') != NULL && PQserverVersion(conn) >= 80100)
    {
        /* ensure we are not adjacent to an identifier */
        if (buf->len > 0 && buf->data[buf->len - 1] != ' ')
            appendPQExpBufferChar(buf, ' ');
        appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
        appendStringLiteral(buf, str, PQclientEncoding(conn), false);
        return;
    }
    /* XXX end kluge */

    if (!enlargePQExpBuffer(buf, 2 * length + 2))
        return;
    appendPQExpBufferChar(buf, '\'');
    buf->len += PQescapeStringConn(conn, buf->data + buf->len,
                                   str, length, NULL);
    appendPQExpBufferChar(buf, '\'');
}

void appendStringLiteralDQ ( PQExpBuffer  buf,
const char *  str,
const char *  dqprefix 
)

Definition at line 308 of file dumputils.c.

References appendPQExpBufferChar(), appendPQExpBufferStr(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), and NULL.

Referenced by dumpFunc().

{
    static const char suffixes[] = "_XXXXXXX";
    int         nextchar = 0;
    PQExpBuffer delimBuf = createPQExpBuffer();

    /* start with $ + dqprefix if not NULL */
    appendPQExpBufferChar(delimBuf, '$');
    if (dqprefix)
        appendPQExpBufferStr(delimBuf, dqprefix);

    /*
     * Make sure we choose a delimiter which (without the trailing $) is not
     * present in the string being quoted. We don't check with the trailing $
     * because a string ending in $foo must not be quoted with $foo$.
     */
    while (strstr(str, delimBuf->data) != NULL)
    {
        appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
        nextchar %= sizeof(suffixes) - 1;
    }

    /* add trailing $ */
    appendPQExpBufferChar(delimBuf, '$');

    /* quote it and we are all done */
    appendPQExpBufferStr(buf, delimBuf->data);
    appendPQExpBufferStr(buf, str);
    appendPQExpBufferStr(buf, delimBuf->data);

    destroyPQExpBuffer(delimBuf);
}

bool buildACLCommands ( const char *  name,
const char *  subname,
const char *  type,
const char *  acls,
const char *  owner,
const char *  prefix,
int  remoteVersion,
PQExpBuffer  sql 
)

Definition at line 498 of file dumputils.c.

References appendPQExpBuffer(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), fmtId(), free, i, PQExpBufferData::len, parseAclItem(), parsePGArray(), printfPQExpBuffer(), and supports_grant_options.

Referenced by buildDefaultACLCommands(), dumpACL(), dumpCreateDB(), and dumpTablespaces().

{
    char      **aclitems;
    int         naclitems;
    int         i;
    PQExpBuffer grantee,
                grantor,
                privs,
                privswgo;
    PQExpBuffer firstsql,
                secondsql;
    bool        found_owner_privs = false;

    if (strlen(acls) == 0)
        return true;            /* object has default permissions */

    /* treat empty-string owner same as NULL */
    if (owner && *owner == '\0')
        owner = NULL;

    if (!parsePGArray(acls, &aclitems, &naclitems))
    {
        if (aclitems)
            free(aclitems);
        return false;
    }

    grantee = createPQExpBuffer();
    grantor = createPQExpBuffer();
    privs = createPQExpBuffer();
    privswgo = createPQExpBuffer();

    /*
     * At the end, these two will be pasted together to form the result. But
     * the owner privileges need to go before the other ones to keep the
     * dependencies valid.  In recent versions this is normally the case, but
     * in old versions they come after the PUBLIC privileges and that results
     * in problems if we need to run REVOKE on the owner privileges.
     */
    firstsql = createPQExpBuffer();
    secondsql = createPQExpBuffer();

    /*
     * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
     * wire-in knowledge about the default public privileges for different
     * kinds of objects.
     */
    appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
    if (subname)
        appendPQExpBuffer(firstsql, "(%s)", subname);
    appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);

    /*
     * We still need some hacking though to cover the case where new default
     * public privileges are added in new versions: the REVOKE ALL will revoke
     * them, leading to behavior different from what the old version had,
     * which is generally not what's wanted.  So add back default privs if the
     * source database is too old to have had that particular priv.
     */
    if (remoteVersion < 80200 && strcmp(type, "DATABASE") == 0)
    {
        /* database CONNECT priv didn't exist before 8.2 */
        appendPQExpBuffer(firstsql, "%sGRANT CONNECT ON %s %s TO PUBLIC;\n",
                          prefix, type, name);
    }

    /* Scan individual ACL items */
    for (i = 0; i < naclitems; i++)
    {
        if (!parseAclItem(aclitems[i], type, name, subname, remoteVersion,
                          grantee, grantor, privs, privswgo))
        {
            free(aclitems);
            return false;
        }

        if (grantor->len == 0 && owner)
            printfPQExpBuffer(grantor, "%s", owner);

        if (privs->len > 0 || privswgo->len > 0)
        {
            if (owner
                && strcmp(grantee->data, owner) == 0
                && strcmp(grantor->data, owner) == 0)
            {
                found_owner_privs = true;

                /*
                 * For the owner, the default privilege level is ALL WITH
                 * GRANT OPTION (only ALL prior to 7.4).
                 */
                if (supports_grant_options(remoteVersion)
                    ? strcmp(privswgo->data, "ALL") != 0
                    : strcmp(privs->data, "ALL") != 0)
                {
                    appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
                    if (subname)
                        appendPQExpBuffer(firstsql, "(%s)", subname);
                    appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
                                      type, name, fmtId(grantee->data));
                    if (privs->len > 0)
                        appendPQExpBuffer(firstsql,
                                          "%sGRANT %s ON %s %s TO %s;\n",
                                          prefix, privs->data, type, name,
                                          fmtId(grantee->data));
                    if (privswgo->len > 0)
                        appendPQExpBuffer(firstsql,
                            "%sGRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
                                          prefix, privswgo->data, type, name,
                                          fmtId(grantee->data));
                }
            }
            else
            {
                /*
                 * Otherwise can assume we are starting from no privs.
                 */
                if (grantor->len > 0
                    && (!owner || strcmp(owner, grantor->data) != 0))
                    appendPQExpBuffer(secondsql, "SET SESSION AUTHORIZATION %s;\n",
                                      fmtId(grantor->data));

                if (privs->len > 0)
                {
                    appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
                                      prefix, privs->data, type, name);
                    if (grantee->len == 0)
                        appendPQExpBuffer(secondsql, "PUBLIC;\n");
                    else if (strncmp(grantee->data, "group ",
                                     strlen("group ")) == 0)
                        appendPQExpBuffer(secondsql, "GROUP %s;\n",
                                    fmtId(grantee->data + strlen("group ")));
                    else
                        appendPQExpBuffer(secondsql, "%s;\n", fmtId(grantee->data));
                }
                if (privswgo->len > 0)
                {
                    appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
                                      prefix, privswgo->data, type, name);
                    if (grantee->len == 0)
                        appendPQExpBuffer(secondsql, "PUBLIC");
                    else if (strncmp(grantee->data, "group ",
                                     strlen("group ")) == 0)
                        appendPQExpBuffer(secondsql, "GROUP %s",
                                    fmtId(grantee->data + strlen("group ")));
                    else
                        appendPQExpBuffer(secondsql, "%s", fmtId(grantee->data));
                    appendPQExpBuffer(secondsql, " WITH GRANT OPTION;\n");
                }

                if (grantor->len > 0
                    && (!owner || strcmp(owner, grantor->data) != 0))
                    appendPQExpBuffer(secondsql, "RESET SESSION AUTHORIZATION;\n");
            }
        }
    }

    /*
     * If we didn't find any owner privs, the owner must have revoked 'em all
     */
    if (!found_owner_privs && owner)
    {
        appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
        if (subname)
            appendPQExpBuffer(firstsql, "(%s)", subname);
        appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
                          type, name, fmtId(owner));
    }

    destroyPQExpBuffer(grantee);
    destroyPQExpBuffer(grantor);
    destroyPQExpBuffer(privs);
    destroyPQExpBuffer(privswgo);

    appendPQExpBuffer(sql, "%s%s", firstsql->data, secondsql->data);
    destroyPQExpBuffer(firstsql);
    destroyPQExpBuffer(secondsql);

    free(aclitems);

    return true;
}

bool buildDefaultACLCommands ( const char *  type,
const char *  nspname,
const char *  acls,
const char *  owner,
int  remoteVersion,
PQExpBuffer  sql 
)

Definition at line 697 of file dumputils.c.

References appendPQExpBuffer(), buildACLCommands(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), fmtId(), and NULL.

Referenced by dumpDefaultACL().

{
    bool        result;
    PQExpBuffer prefix;

    prefix = createPQExpBuffer();

    /*
     * We incorporate the target role directly into the command, rather than
     * playing around with SET ROLE or anything like that.  This is so that a
     * permissions error leads to nothing happening, rather than changing
     * default privileges for the wrong user.
     */
    appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
                      fmtId(owner));
    if (nspname)
        appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));

    result = buildACLCommands("", NULL,
                              type, acls, owner,
                              prefix->data, remoteVersion,
                              sql);

    destroyPQExpBuffer(prefix);

    return result;
}

void buildShSecLabelQuery ( PGconn conn,
const char *  catalog_name,
uint32  objectId,
PQExpBuffer  sql 
)

Definition at line 1174 of file dumputils.c.

References appendPQExpBuffer().

Referenced by buildShSecLabels(), and dumpDatabase().

{
    appendPQExpBuffer(sql,
                      "SELECT provider, label FROM pg_catalog.pg_shseclabel "
                      "WHERE classoid = '%s'::pg_catalog.regclass AND "
                      "objoid = %u", catalog_name, objectId);
}

static char * copyAclUserName ( PQExpBuffer  output,
char *  input 
) [static]

Definition at line 907 of file dumputils.c.

References appendPQExpBufferChar(), and resetPQExpBuffer().

Referenced by parseAclItem().

{
    resetPQExpBuffer(output);

    while (*input && *input != '=')
    {
        /*
         * If user name isn't quoted, then just add it to the output buffer
         */
        if (*input != '"')
            appendPQExpBufferChar(output, *input++);
        else
        {
            /* Otherwise, it's a quoted username */
            input++;
            /* Loop until we come across an unescaped quote */
            while (!(*input == '"' && *(input + 1) != '"'))
            {
                if (*input == '\0')
                    return input;       /* really a syntax error... */

                /*
                 * Quoting convention is to escape " as "".  Keep this code in
                 * sync with putid() in backend's acl.c.
                 */
                if (*input == '"' && *(input + 1) == '"')
                    input++;
                appendPQExpBufferChar(output, *input++);
            }
            input++;
        }
    }
    return input;
}

static PQExpBuffer defaultGetLocalPQExpBuffer ( void   )  [static]

Definition at line 52 of file dumputils.c.

References createPQExpBuffer(), and resetPQExpBuffer().

{
    static PQExpBuffer id_return = NULL;

    if (id_return)              /* first time through? */
    {
        /* same buffer, just wipe contents */
        resetPQExpBuffer(id_return);
    }
    else
    {
        /* new buffer */
        id_return = createPQExpBuffer();
    }

    return id_return;
}

void emitShSecLabels ( PGconn conn,
PGresult res,
PQExpBuffer  buffer,
const char *  target,
const char *  objname 
)

Definition at line 1190 of file dumputils.c.

References appendPQExpBuffer(), appendStringLiteralConn(), fmtId(), i, label, PQgetvalue(), and PQntuples().

Referenced by buildShSecLabels(), and dumpDatabase().

{
    int         i;

    for (i = 0; i < PQntuples(res); i++)
    {
        char       *provider = PQgetvalue(res, i, 0);
        char       *label = PQgetvalue(res, i, 1);

        /* must use fmtId result before calling it again */
        appendPQExpBuffer(buffer,
                          "SECURITY LABEL FOR %s ON %s",
                          fmtId(provider), target);
        appendPQExpBuffer(buffer,
                          " %s IS ",
                          fmtId(objname));
        appendStringLiteralConn(buffer, label, conn);
        appendPQExpBuffer(buffer, ";\n");
    }
}

const char* fmtId ( const char *  rawid  ) 

Definition at line 77 of file dumputils.c.

References appendPQExpBufferChar(), appendPQExpBufferStr(), ScanKeyword::category, PQExpBufferData::data, getLocalPQExpBuffer, NULL, NumFEScanKeywords, quote_all_identifiers, ScanKeywordLookup(), and UNRESERVED_KEYWORD.

Referenced by _disableTriggersIfNecessary(), _doSetFixedOutputState(), _enableTriggersIfNecessary(), _getObjectDescription(), _printTocEntry(), _reconnectToDB(), _selectOutputSchema(), _selectTablespace(), binary_upgrade_extension_member(), buildACLCommands(), buildDefaultACLCommands(), convertRegProcReference(), describeOneTableDetails(), dropDBs(), dropRoles(), dropTablespaces(), dumpAgg(), dumpAttrDef(), dumpBaseType(), dumpCast(), dumpCollation(), dumpCompositeType(), dumpCompositeTypeColComments(), dumpConstraint(), dumpConversion(), dumpCreateDB(), dumpDatabase(), dumpDatabases(), dumpDomain(), dumpEnumType(), dumpEventTrigger(), dumpExtension(), dumpForeignDataWrapper(), dumpForeignServer(), dumpFunc(), dumpGroups(), dumpIndex(), dumpNamespace(), dumpOpclass(), dumpOpfamily(), dumpOpr(), dumpProcLang(), dumpRangeType(), dumpRoleMembership(), dumpRoles(), dumpRule(), dumpSecLabel(), dumpSequence(), dumpSequenceData(), dumpShellType(), dumpTable(), dumpTableComment(), dumpTableConstraintComment(), dumpTableData(), dumpTableData_insert(), dumpTableSchema(), dumpTableSecLabel(), dumpTablespaces(), dumpTrigger(), dumpTSConfig(), dumpTSDictionary(), dumpTSParser(), dumpTSTemplate(), dumpUserMappings(), emitShSecLabels(), exec_command(), fmtCopyColumnList(), fmtQualifiedId(), format_aggregate_signature(), format_function_arguments(), format_function_arguments_old(), format_function_signature(), getFormattedTypeName(), main(), makeAlterConfigCommand(), myFormatType(), refreshMatViewData(), reindex_one_database(), restore_toc_entry(), selectSourceSchema(), and setup_connection().

{
    PQExpBuffer id_return = getLocalPQExpBuffer();

    const char *cp;
    bool        need_quotes = false;

    /*
     * These checks need to match the identifier production in scan.l. Don't
     * use islower() etc.
     */
    if (quote_all_identifiers)
        need_quotes = true;
    /* slightly different rules for first character */
    else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
        need_quotes = true;
    else
    {
        /* otherwise check the entire string */
        for (cp = rawid; *cp; cp++)
        {
            if (!((*cp >= 'a' && *cp <= 'z')
                  || (*cp >= '0' && *cp <= '9')
                  || (*cp == '_')))
            {
                need_quotes = true;
                break;
            }
        }
    }

    if (!need_quotes)
    {
        /*
         * Check for keyword.  We quote keywords except for unreserved ones.
         * (In some cases we could avoid quoting a col_name or type_func_name
         * keyword, but it seems much harder than it's worth to tell that.)
         *
         * Note: ScanKeywordLookup() does case-insensitive comparison, but
         * that's fine, since we already know we have all-lower-case.
         */
        const ScanKeyword *keyword = ScanKeywordLookup(rawid,
                                                       FEScanKeywords,
                                                       NumFEScanKeywords);

        if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
            need_quotes = true;
    }

    if (!need_quotes)
    {
        /* no quoting needed */
        appendPQExpBufferStr(id_return, rawid);
    }
    else
    {
        appendPQExpBufferChar(id_return, '\"');
        for (cp = rawid; *cp; cp++)
        {
            /*
             * Did we find a double-quote in the string? Then make this a
             * double double-quote per SQL99. Before, we put in a
             * backslash/double-quote pair. - thomas 2000-08-05
             */
            if (*cp == '\"')
                appendPQExpBufferChar(id_return, '\"');
            appendPQExpBufferChar(id_return, *cp);
        }
        appendPQExpBufferChar(id_return, '\"');
    }

    return id_return->data;
}

const char* fmtQualifiedId ( int  remoteVersion,
const char *  schema,
const char *  id 
)

Definition at line 161 of file dumputils.c.

References appendPQExpBuffer(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), fmtId(), and getLocalPQExpBuffer.

Referenced by dumpTableData_copy(), dumpTableData_insert(), getTables(), and lockTableNoWait().

{
    PQExpBuffer id_return;
    PQExpBuffer lcl_pqexp = createPQExpBuffer();

    /* Suppress schema name if fetching from pre-7.3 DB */
    if (remoteVersion >= 70300 && schema && *schema)
    {
        appendPQExpBuffer(lcl_pqexp, "%s.", fmtId(schema));
    }
    appendPQExpBuffer(lcl_pqexp, "%s", fmtId(id));

    id_return = getLocalPQExpBuffer();

    appendPQExpBuffer(id_return, "%s", lcl_pqexp->data);
    destroyPQExpBuffer(lcl_pqexp);

    return id_return->data;
}

static bool parseAclItem ( const char *  item,
const char *  type,
const char *  name,
const char *  subname,
int  remoteVersion,
PQExpBuffer  grantee,
PQExpBuffer  grantor,
PQExpBuffer  privs,
PQExpBuffer  privswgo 
) [static]

Definition at line 745 of file dumputils.c.

References appendPQExpBuffer(), buf, CONVERT_PRIV, copyAclUserName(), free, NULL, printfPQExpBuffer(), and resetPQExpBuffer().

Referenced by buildACLCommands().

{
    char       *buf;
    bool        all_with_go = true;
    bool        all_without_go = true;
    char       *eqpos;
    char       *slpos;
    char       *pos;

    buf = strdup(item);
    if (!buf)
        return false;

    /* user or group name is string up to = */
    eqpos = copyAclUserName(grantee, buf);
    if (*eqpos != '=')
    {
        free(buf);
        return false;
    }

    /* grantor may be listed after / */
    slpos = strchr(eqpos + 1, '/');
    if (slpos)
    {
        *slpos++ = '\0';
        slpos = copyAclUserName(grantor, slpos);
        if (*slpos != '\0')
        {
            free(buf);
            return false;
        }
    }
    else
        resetPQExpBuffer(grantor);

    /* privilege codes */
#define CONVERT_PRIV(code, keywd) \
do { \
    if ((pos = strchr(eqpos + 1, code))) \
    { \
        if (*(pos + 1) == '*') \
        { \
            AddAcl(privswgo, keywd, subname); \
            all_without_go = false; \
        } \
        else \
        { \
            AddAcl(privs, keywd, subname); \
            all_with_go = false; \
        } \
    } \
    else \
        all_with_go = all_without_go = false; \
} while (0)

    resetPQExpBuffer(privs);
    resetPQExpBuffer(privswgo);

    if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0 ||
        strcmp(type, "TABLES") == 0 || strcmp(type, "SEQUENCES") == 0)
    {
        CONVERT_PRIV('r', "SELECT");

        if (strcmp(type, "SEQUENCE") == 0 ||
            strcmp(type, "SEQUENCES") == 0)
            /* sequence only */
            CONVERT_PRIV('U', "USAGE");
        else
        {
            /* table only */
            CONVERT_PRIV('a', "INSERT");
            if (remoteVersion >= 70200)
                CONVERT_PRIV('x', "REFERENCES");
            /* rest are not applicable to columns */
            if (subname == NULL)
            {
                if (remoteVersion >= 70200)
                {
                    CONVERT_PRIV('d', "DELETE");
                    CONVERT_PRIV('t', "TRIGGER");
                }
                if (remoteVersion >= 80400)
                    CONVERT_PRIV('D', "TRUNCATE");
            }
        }

        /* UPDATE */
        if (remoteVersion >= 70200 ||
            strcmp(type, "SEQUENCE") == 0 ||
            strcmp(type, "SEQUENCES") == 0)
            CONVERT_PRIV('w', "UPDATE");
        else
            /* 7.0 and 7.1 have a simpler worldview */
            CONVERT_PRIV('w', "UPDATE,DELETE");
    }
    else if (strcmp(type, "FUNCTION") == 0 ||
             strcmp(type, "FUNCTIONS") == 0)
        CONVERT_PRIV('X', "EXECUTE");
    else if (strcmp(type, "LANGUAGE") == 0)
        CONVERT_PRIV('U', "USAGE");
    else if (strcmp(type, "SCHEMA") == 0)
    {
        CONVERT_PRIV('C', "CREATE");
        CONVERT_PRIV('U', "USAGE");
    }
    else if (strcmp(type, "DATABASE") == 0)
    {
        CONVERT_PRIV('C', "CREATE");
        CONVERT_PRIV('c', "CONNECT");
        CONVERT_PRIV('T', "TEMPORARY");
    }
    else if (strcmp(type, "TABLESPACE") == 0)
        CONVERT_PRIV('C', "CREATE");
    else if (strcmp(type, "TYPE") == 0 ||
             strcmp(type, "TYPES") == 0)
        CONVERT_PRIV('U', "USAGE");
    else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
        CONVERT_PRIV('U', "USAGE");
    else if (strcmp(type, "FOREIGN SERVER") == 0)
        CONVERT_PRIV('U', "USAGE");
    else if (strcmp(type, "FOREIGN TABLE") == 0)
        CONVERT_PRIV('r', "SELECT");
    else if (strcmp(type, "LARGE OBJECT") == 0)
    {
        CONVERT_PRIV('r', "SELECT");
        CONVERT_PRIV('w', "UPDATE");
    }
    else
        abort();

#undef CONVERT_PRIV

    if (all_with_go)
    {
        resetPQExpBuffer(privs);
        printfPQExpBuffer(privswgo, "ALL");
        if (subname)
            appendPQExpBuffer(privswgo, "(%s)", subname);
    }
    else if (all_without_go)
    {
        resetPQExpBuffer(privswgo);
        printfPQExpBuffer(privs, "ALL");
        if (subname)
            appendPQExpBuffer(privs, "(%s)", subname);
    }

    free(buf);

    return true;
}

bool parsePGArray ( const char *  atext,
char ***  itemarray,
int *  nitems 
)

Definition at line 402 of file dumputils.c.

References malloc, and NULL.

Referenced by buildACLCommands(), dumpFunc(), and getExtensionMembership().

{
    int         inputlen;
    char      **items;
    char       *strings;
    int         curitem;

    /*
     * We expect input in the form of "{item,item,item}" where any item is
     * either raw data, or surrounded by double quotes (in which case embedded
     * characters including backslashes and quotes are backslashed).
     *
     * We build the result as an array of pointers followed by the actual
     * string data, all in one malloc block for convenience of deallocation.
     * The worst-case storage need is not more than one pointer and one
     * character for each input character (consider "{,,,,,,,,,,}").
     */
    *itemarray = NULL;
    *nitems = 0;
    inputlen = strlen(atext);
    if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}')
        return false;           /* bad input */
    items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char)));
    if (items == NULL)
        return false;           /* out of memory */
    *itemarray = items;
    strings = (char *) (items + inputlen);

    atext++;                    /* advance over initial '{' */
    curitem = 0;
    while (*atext != '}')
    {
        if (*atext == '\0')
            return false;       /* premature end of string */
        items[curitem] = strings;
        while (*atext != '}' && *atext != ',')
        {
            if (*atext == '\0')
                return false;   /* premature end of string */
            if (*atext != '"')
                *strings++ = *atext++;  /* copy unquoted data */
            else
            {
                /* process quoted substring */
                atext++;
                while (*atext != '"')
                {
                    if (*atext == '\0')
                        return false;   /* premature end of string */
                    if (*atext == '\\')
                    {
                        atext++;
                        if (*atext == '\0')
                            return false;       /* premature end of string */
                    }
                    *strings++ = *atext++;      /* copy quoted data */
                }
                atext++;
            }
        }
        *strings++ = '\0';
        if (*atext == ',')
            atext++;
        curitem++;
    }
    if (atext[1] != '\0')
        return false;           /* bogus syntax (embedded '}') */
    *nitems = curitem;
    return true;
}

bool processSQLNamePattern ( PGconn conn,
PQExpBuffer  buf,
const char *  pattern,
bool  have_where,
bool  force_escape,
const char *  schemavar,
const char *  namevar,
const char *  altnamevar,
const char *  visibilityrule 
)

Definition at line 982 of file dumputils.c.

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendStringLiteralConn(), PQExpBufferData::data, encoding, i, initPQExpBuffer(), PQExpBufferData::len, NULL, pg_tolower(), PQclientEncoding(), PQmblen(), resetPQExpBuffer(), termPQExpBuffer(), and WHEREAND.

Referenced by describeAggregates(), describeFunctions(), describeOperators(), describeRoles(), describeTableDetails(), describeTablespaces(), describeTypes(), expand_schema_name_patterns(), expand_table_name_patterns(), listAllDbs(), listCasts(), listCollations(), listConversions(), listDbRoleSettings(), listDefaultACLs(), listDomains(), listEventTriggers(), listExtensionContents(), listExtensions(), listForeignDataWrappers(), listForeignServers(), listForeignTables(), listLanguages(), listSchemas(), listTables(), listTSConfigs(), listTSConfigsVerbose(), listTSDictionaries(), listTSParsers(), listTSParsersVerbose(), listTSTemplates(), listUserMappings(), objectDescription(), and permissionsList().

{
    PQExpBufferData schemabuf;
    PQExpBufferData namebuf;
    int         encoding = PQclientEncoding(conn);
    bool        inquotes;
    const char *cp;
    int         i;
    bool        added_clause = false;

#define WHEREAND() \
    (appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
     have_where = true, added_clause = true)

    if (pattern == NULL)
    {
        /* Default: select all visible objects */
        if (visibilityrule)
        {
            WHEREAND();
            appendPQExpBuffer(buf, "%s\n", visibilityrule);
        }
        return added_clause;
    }

    initPQExpBuffer(&schemabuf);
    initPQExpBuffer(&namebuf);

    /*
     * Parse the pattern, converting quotes and lower-casing unquoted letters.
     * Also, adjust shell-style wildcard characters into regexp notation.
     *
     * We surround the pattern with "^(...)$" to force it to match the whole
     * string, as per SQL practice.  We have to have parens in case the string
     * contains "|", else the "^" and "$" will be bound into the first and
     * last alternatives which is not what we want.
     *
     * Note: the result of this pass is the actual regexp pattern(s) we want
     * to execute.  Quoting/escaping into SQL literal format will be done
     * below using appendStringLiteralConn().
     */
    appendPQExpBufferStr(&namebuf, "^(");

    inquotes = false;
    cp = pattern;

    while (*cp)
    {
        char        ch = *cp;

        if (ch == '"')
        {
            if (inquotes && cp[1] == '"')
            {
                /* emit one quote, stay in inquotes mode */
                appendPQExpBufferChar(&namebuf, '"');
                cp++;
            }
            else
                inquotes = !inquotes;
            cp++;
        }
        else if (!inquotes && isupper((unsigned char) ch))
        {
            appendPQExpBufferChar(&namebuf,
                                  pg_tolower((unsigned char) ch));
            cp++;
        }
        else if (!inquotes && ch == '*')
        {
            appendPQExpBufferStr(&namebuf, ".*");
            cp++;
        }
        else if (!inquotes && ch == '?')
        {
            appendPQExpBufferChar(&namebuf, '.');
            cp++;
        }
        else if (!inquotes && ch == '.')
        {
            /* Found schema/name separator, move current pattern to schema */
            resetPQExpBuffer(&schemabuf);
            appendPQExpBufferStr(&schemabuf, namebuf.data);
            resetPQExpBuffer(&namebuf);
            appendPQExpBufferStr(&namebuf, "^(");
            cp++;
        }
        else if (ch == '$')
        {
            /*
             * Dollar is always quoted, whether inside quotes or not. The
             * reason is that it's allowed in SQL identifiers, so there's a
             * significant use-case for treating it literally, while because
             * we anchor the pattern automatically there is no use-case for
             * having it possess its regexp meaning.
             */
            appendPQExpBufferStr(&namebuf, "\\$");
            cp++;
        }
        else
        {
            /*
             * Ordinary data character, transfer to pattern
             *
             * Inside double quotes, or at all times if force_escape is true,
             * quote regexp special characters with a backslash to avoid
             * regexp errors.  Outside quotes, however, let them pass through
             * as-is; this lets knowledgeable users build regexp expressions
             * that are more powerful than shell-style patterns.
             */
            if ((inquotes || force_escape) &&
                strchr("|*+?()[]{}.^$\\", ch))
                appendPQExpBufferChar(&namebuf, '\\');
            i = PQmblen(cp, encoding);
            while (i-- && *cp)
            {
                appendPQExpBufferChar(&namebuf, *cp);
                cp++;
            }
        }
    }

    /*
     * Now decide what we need to emit.  Note there will be a leading "^(" in
     * the patterns in any case.
     */
    if (namebuf.len > 2)
    {
        /* We have a name pattern, so constrain the namevar(s) */

        appendPQExpBufferStr(&namebuf, ")$");
        /* Optimize away a "*" pattern */
        if (strcmp(namebuf.data, "^(.*)$") != 0)
        {
            WHEREAND();
            if (altnamevar)
            {
                appendPQExpBuffer(buf, "(%s ~ ", namevar);
                appendStringLiteralConn(buf, namebuf.data, conn);
                appendPQExpBuffer(buf, "\n        OR %s ~ ", altnamevar);
                appendStringLiteralConn(buf, namebuf.data, conn);
                appendPQExpBufferStr(buf, ")\n");
            }
            else
            {
                appendPQExpBuffer(buf, "%s ~ ", namevar);
                appendStringLiteralConn(buf, namebuf.data, conn);
                appendPQExpBufferChar(buf, '\n');
            }
        }
    }

    if (schemabuf.len > 2)
    {
        /* We have a schema pattern, so constrain the schemavar */

        appendPQExpBufferStr(&schemabuf, ")$");
        /* Optimize away a "*" pattern */
        if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
        {
            WHEREAND();
            appendPQExpBuffer(buf, "%s ~ ", schemavar);
            appendStringLiteralConn(buf, schemabuf.data, conn);
            appendPQExpBufferChar(buf, '\n');
        }
    }
    else
    {
        /* No schema pattern given, so select only visible objects */
        if (visibilityrule)
        {
            WHEREAND();
            appendPQExpBuffer(buf, "%s\n", visibilityrule);
        }
    }

    termPQExpBuffer(&schemabuf);
    termPQExpBuffer(&namebuf);

    return added_clause;
#undef WHEREAND
}

void simple_string_list_append ( SimpleStringList list,
const char *  val 
)

Definition at line 1214 of file dumputils.c.

References SimpleStringList::head, SimpleStringListCell::next, pg_malloc(), SimpleStringList::tail, and SimpleStringListCell::val.

Referenced by main().

{
    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_string_list_member ( SimpleStringList list,
const char *  val 
)

Definition at line 1233 of file dumputils.c.

References SimpleStringList::head, SimpleStringListCell::next, and SimpleStringListCell::val.

Referenced by _tocEntryRequired().

{
    SimpleStringListCell *cell;

    for (cell = list->head; cell; cell = cell->next)
    {
        if (strcmp(cell->val, val) == 0)
            return true;
    }
    return false;
}


Variable Documentation

Definition at line 26 of file keywords.c.

PQExpBuffer(* getLocalPQExpBuffer)(void) = defaultGetLocalPQExpBuffer

Definition at line 41 of file dumputils.c.

Referenced by fmtId(), fmtQualifiedId(), and ParallelBackupStart().

const int NumFEScanKeywords

Definition at line 30 of file keywords.c.

Referenced by fmtId().

Definition at line 40 of file dumputils.c.