diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 4023837408fd060d8de806d49dc6af46ed60c760..da9459f71e3f1fa46ed42b038e03d3f534f7cbd9 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -2,18 +2,20 @@ * * Utility routines for SQL dumping * Basically this is stuff that is useful in both pg_dump and pg_dumpall. + * Lately it's also being used by psql and bin/scripts/ ... * * * 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/dumputils.c,v 1.32 2006/10/04 00:30:05 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.33 2006/10/09 23:30:33 tgl Exp $ * *------------------------------------------------------------------------- */ - #include "postgres_fe.h" +#include <ctype.h> + #include "dumputils.h" #include "parser/keywords.h" @@ -570,6 +572,8 @@ parseAclItem(const char *item, const char *type, const char *name, char *pos; buf = strdup(item); + if (!buf) + return false; /* user or group name is string up to = */ eqpos = copyAclUserName(grantee, buf); @@ -726,3 +730,200 @@ AddAcl(PQExpBuffer aclbuf, const char *keyword) appendPQExpBufferChar(aclbuf, ','); appendPQExpBuffer(aclbuf, "%s", keyword); } + + +/* + * processSQLNamePattern + * + * Scan a wildcard-pattern string and generate appropriate WHERE clauses + * to limit the set of objects returned. The WHERE clauses are appended + * to the already-partially-constructed query in buf. + * + * conn: connection query will be sent to (consulted for escaping rules). + * buf: output parameter. + * pattern: user-specified pattern option, or NULL if none ("*" is implied). + * have_where: true if caller already emitted "WHERE" (clauses will be ANDed + * onto the existing WHERE clause). + * force_escape: always quote regexp special characters, even outside + * double quotes (else they are quoted only between double quotes). + * schemavar: name of query variable to match against a schema-name pattern. + * Can be NULL if no schema. + * namevar: name of query variable to match against an object-name pattern. + * altnamevar: NULL, or name of an alternate variable to match against name. + * visibilityrule: clause to use if we want to restrict to visible objects + * (for example, "pg_catalog.pg_table_is_visible(p.oid)"). Can be NULL. + * + * Formatting note: the text already present in buf should end with a newline. + * The appended text, if any, will end with one too. + */ +void +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) +{ + PQExpBufferData schemabuf; + PQExpBufferData namebuf; + int encoding = PQclientEncoding(conn); + bool inquotes; + const char *cp; + int i; + +#define WHEREAND() \ + (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), have_where = true) + + if (pattern == NULL) + { + /* Default: select all visible objects */ + if (visibilityrule) + { + WHEREAND(); + appendPQExpBuffer(buf, "%s\n", visibilityrule); + } + return; + } + + 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 + { + /* + * 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); + +#undef WHEREAND +} diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index b177bb4bc82e65e61ccec4efd179ec8b9ab085e6..94beade21379aec03d1091fb3641475d9a06ec49 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -2,12 +2,13 @@ * * Utility routines for SQL dumping * Basically this is stuff that is useful in both pg_dump and pg_dumpall. + * Lately it's also being used by psql and bin/scripts/ ... * * * 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/dumputils.h,v 1.18 2006/10/04 00:30:05 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.19 2006/10/09 23:30:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,5 +32,10 @@ extern bool buildACLCommands(const char *name, const char *type, const char *acls, const char *owner, int remoteVersion, PQExpBuffer sql); +extern void 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); #endif /* DUMPUTILS_H */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index d83a6aa45eec8585f7bc1153efafb5446496f9ae..bab0e24f957912a73dc653329502b5eaab599c71 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.146 2006/10/07 22:21:38 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.147 2006/10/09 23:30:33 tgl Exp $ */ #include "postgres_fe.h" #include "describe.h" @@ -31,11 +31,6 @@ static bool describeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose); -static void processNamePattern(PQExpBuffer buf, const char *pattern, - bool have_where, bool force_escape, - const char *schemavar, const char *namevar, - const char *altnamevar, const char *visibilityrule); - static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers, int *count, PQExpBufferData buf, bool newline); @@ -84,9 +79,9 @@ describeAggregates(const char *pattern, bool verbose) _("Schema"), _("Name"), _("Argument data types"), _("Description")); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "p.proname", NULL, - "pg_catalog.pg_function_is_visible(p.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "p.proname", NULL, + "pg_catalog.pg_function_is_visible(p.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;"); @@ -138,9 +133,9 @@ describeTablespaces(const char *pattern, bool verbose) appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_tablespace\n"); - processNamePattern(&buf, pattern, false, false, - NULL, "spcname", NULL, - NULL); + processSQLNamePattern(pset.db, &buf, pattern, false, false, + NULL, "spcname", NULL, + NULL); appendPQExpBuffer(&buf, "ORDER BY 1;"); @@ -236,9 +231,9 @@ describeFunctions(const char *pattern, bool verbose) " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n" " AND NOT p.proisagg\n"); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "p.proname", NULL, - "pg_catalog.pg_function_is_visible(p.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "p.proname", NULL, + "pg_catalog.pg_function_is_visible(p.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;"); @@ -302,10 +297,10 @@ describeTypes(const char *pattern, bool verbose) appendPQExpBuffer(&buf, "AND t.typname !~ '^_'\n"); /* Match name pattern against either internal or external name */ - processNamePattern(&buf, pattern, true, false, - "n.nspname", "t.typname", - "pg_catalog.format_type(t.oid, NULL)", - "pg_catalog.pg_type_is_visible(t.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "t.typname", + "pg_catalog.format_type(t.oid, NULL)", + "pg_catalog.pg_type_is_visible(t.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); @@ -350,9 +345,9 @@ describeOperators(const char *pattern) _("Left arg type"), _("Right arg type"), _("Result type"), _("Description")); - processNamePattern(&buf, pattern, false, true, - "n.nspname", "o.oprname", NULL, - "pg_catalog.pg_operator_is_visible(o.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, false, true, + "n.nspname", "o.oprname", NULL, + "pg_catalog.pg_operator_is_visible(o.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;"); @@ -455,8 +450,8 @@ permissionsList(const char *pattern) * point of view. You can see 'em by explicit request though, eg with \z * pg_catalog.* */ - processNamePattern(&buf, pattern, true, false, - "n.nspname", "c.relname", NULL, + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "c.relname", NULL, "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); @@ -513,9 +508,9 @@ objectDescription(const char *pattern) " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n" " WHERE p.proisagg\n", _("aggregate")); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "p.proname", NULL, - "pg_catalog.pg_function_is_visible(p.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "p.proname", NULL, + "pg_catalog.pg_function_is_visible(p.oid)"); /* Function descriptions (except in/outs for datatypes) */ appendPQExpBuffer(&buf, @@ -532,9 +527,9 @@ objectDescription(const char *pattern) " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n" " AND NOT p.proisagg\n", _("function")); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "p.proname", NULL, - "pg_catalog.pg_function_is_visible(p.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "p.proname", NULL, + "pg_catalog.pg_function_is_visible(p.oid)"); /* Operator descriptions (only if operator has its own comment) */ appendPQExpBuffer(&buf, @@ -546,9 +541,9 @@ objectDescription(const char *pattern) " FROM pg_catalog.pg_operator o\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n", _("operator")); - processNamePattern(&buf, pattern, false, false, - "n.nspname", "o.oprname", NULL, - "pg_catalog.pg_operator_is_visible(o.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, false, false, + "n.nspname", "o.oprname", NULL, + "pg_catalog.pg_operator_is_visible(o.oid)"); /* Type description */ appendPQExpBuffer(&buf, @@ -560,9 +555,10 @@ objectDescription(const char *pattern) " FROM pg_catalog.pg_type t\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n", _("data type")); - processNamePattern(&buf, pattern, false, false, - "n.nspname", "pg_catalog.format_type(t.oid, NULL)", NULL, - "pg_catalog.pg_type_is_visible(t.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, false, false, + "n.nspname", "pg_catalog.format_type(t.oid, NULL)", + NULL, + "pg_catalog.pg_type_is_visible(t.oid)"); /* Relation (tables, views, indexes, sequences) descriptions */ appendPQExpBuffer(&buf, @@ -577,9 +573,9 @@ objectDescription(const char *pattern) " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n", _("table"), _("view"), _("index"), _("sequence")); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)"); /* Rule description (ignore rules for views) */ appendPQExpBuffer(&buf, @@ -594,9 +590,9 @@ objectDescription(const char *pattern) " WHERE r.rulename != '_RETURN'\n", _("rule")); /* XXX not sure what to do about visibility rule here? */ - processNamePattern(&buf, pattern, true, false, - "n.nspname", "r.rulename", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "r.rulename", NULL, + "pg_catalog.pg_table_is_visible(c.oid)"); /* Trigger description */ appendPQExpBuffer(&buf, @@ -610,9 +606,9 @@ objectDescription(const char *pattern) " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n", _("trigger")); /* XXX not sure what to do about visibility rule here? */ - processNamePattern(&buf, pattern, false, false, - "n.nspname", "t.tgname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, false, false, + "n.nspname", "t.tgname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, ") AS tt\n" @@ -660,9 +656,9 @@ describeTableDetails(const char *pattern, bool verbose) "FROM pg_catalog.pg_class c\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"); - processNamePattern(&buf, pattern, false, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, false, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, "ORDER BY 2, 3;"); @@ -1464,8 +1460,8 @@ describeRoles(const char *pattern, bool verbose) appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_roles r\n"); - processNamePattern(&buf, pattern, false, false, - NULL, "r.rolname", NULL, NULL); + processSQLNamePattern(pset.db, &buf, pattern, false, false, + NULL, "r.rolname", NULL, NULL); appendPQExpBuffer(&buf, "ORDER BY 1;"); @@ -1571,9 +1567,9 @@ listTables(const char *tabtypes, const char *pattern, bool verbose) else appendPQExpBuffer(&buf, " AND n.nspname NOT IN ('pg_catalog', 'pg_toast')\n"); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "c.relname", NULL, - "pg_catalog.pg_table_is_visible(c.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "c.relname", NULL, + "pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1,2;"); @@ -1636,9 +1632,9 @@ listDomains(const char *pattern) _("Modifier"), _("Check")); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "t.typname", NULL, - "pg_catalog.pg_type_is_visible(t.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "t.typname", NULL, + "pg_catalog.pg_type_is_visible(t.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); @@ -1687,9 +1683,9 @@ listConversions(const char *pattern) _("no"), _("Default?")); - processNamePattern(&buf, pattern, true, false, - "n.nspname", "c.conname", NULL, - "pg_catalog.pg_conversion_is_visible(c.oid)"); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + "n.nspname", "c.conname", NULL, + "pg_catalog.pg_conversion_is_visible(c.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); @@ -1787,9 +1783,9 @@ listSchemas(const char *pattern, bool verbose) "WHERE (n.nspname !~ '^pg_temp_' OR\n" " n.nspname = (pg_catalog.current_schemas(true))[1])\n"); /* temp schema is first */ - processNamePattern(&buf, pattern, true, false, - NULL, "n.nspname", NULL, - NULL); + processSQLNamePattern(pset.db, &buf, pattern, true, false, + NULL, "n.nspname", NULL, + NULL); appendPQExpBuffer(&buf, "ORDER BY 1;"); @@ -1806,201 +1802,3 @@ listSchemas(const char *pattern, bool verbose) PQclear(res); return true; } - - -/* - * processNamePattern - * - * Scan a wildcard-pattern option and generate appropriate WHERE clauses - * to limit the set of objects returned. The WHERE clauses are appended - * to buf. - * - * pattern: user-specified pattern option to a \d command, or NULL if none. - * have_where: true if caller already emitted WHERE. - * force_escape: always quote regexp special characters, even outside quotes. - * schemavar: name of WHERE variable to match against a schema-name pattern. - * Can be NULL if no schema. - * namevar: name of WHERE variable to match against an object-name pattern. - * altnamevar: NULL, or name of an alternate variable to match against name. - * visibilityrule: clause to use if we want to restrict to visible objects - * (for example, "pg_catalog.pg_table_is_visible(p.oid)"). Can be NULL. - */ -static void -processNamePattern(PQExpBuffer buf, const char *pattern, - bool have_where, bool force_escape, - const char *schemavar, const char *namevar, - const char *altnamevar, const char *visibilityrule) -{ - PQExpBufferData schemabuf; - PQExpBufferData namebuf; - bool inquotes; - const char *cp; - int i; - -#define WHEREAND() \ - (appendPQExpBuffer(buf, have_where ? " AND " : "WHERE "), have_where = true) - - if (pattern == NULL) - { - /* Default: select all visible objects */ - if (visibilityrule) - { - WHEREAND(); - appendPQExpBuffer(buf, "%s\n", visibilityrule); - } - return; - } - - initPQExpBuffer(&schemabuf); - initPQExpBuffer(&namebuf); - - /* - * Parse the pattern, converting quotes and lower-casing unquoted letters; - * we assume this was NOT done by scan_option. Also, adjust shell-style - * wildcard characters into regexp notation. - * - * Note: the result of this pass is the actual regexp pattern we want to - * execute. Quoting/escaping it into a SQL literal will be done below. - */ - appendPQExpBufferChar(&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 == '*') - { - appendPQExpBuffer(&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); - appendPQExpBufferChar(&namebuf, '^'); - cp++; - } - else - { - /* - * Ordinary data character, transfer to pattern - * - * Inside double quotes, or at all times if parsing an operator - * name, 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, pset.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 > 1) - { - /* We have a name pattern, so constrain the namevar(s) */ - - appendPQExpBufferChar(&namebuf, '$'); - /* Optimize away ".*$", and possibly the whole pattern */ - if (namebuf.len >= 4 && - strcmp(namebuf.data + (namebuf.len - 3), ".*$") == 0) - { - namebuf.len -= 3; - namebuf.data[namebuf.len] = '\0'; - } - - if (namebuf.len > 1) - { - WHEREAND(); - if (altnamevar) - { - appendPQExpBuffer(buf, "(%s ~ ", namevar); - appendStringLiteralConn(buf, namebuf.data, pset.db); - appendPQExpBuffer(buf, "\n OR %s ~ ", altnamevar); - appendStringLiteralConn(buf, namebuf.data, pset.db); - appendPQExpBuffer(buf, ")\n"); - } - else - { - appendPQExpBuffer(buf, "%s ~ ", namevar); - appendStringLiteralConn(buf, namebuf.data, pset.db); - appendPQExpBufferChar(buf, '\n'); - } - } - } - - if (schemabuf.len > 1) - { - /* We have a schema pattern, so constrain the schemavar */ - - appendPQExpBufferChar(&schemabuf, '$'); - /* Optimize away ".*$", and possibly the whole pattern */ - if (schemabuf.len >= 4 && - strcmp(schemabuf.data + (schemabuf.len - 3), ".*$") == 0) - { - schemabuf.len -= 3; - schemabuf.data[schemabuf.len] = '\0'; - } - - if (schemabuf.len > 1 && schemavar) - { - WHEREAND(); - appendPQExpBuffer(buf, "%s ~ ", schemavar); - appendStringLiteralConn(buf, schemabuf.data, pset.db); - 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); - -#undef WHEREAND -}