summaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/pg_dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_dump/pg_dump.c')
-rw-r--r--src/bin/pg_dump/pg_dump.c722
1 files changed, 721 insertions, 1 deletions
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ee7b6bca79..4d4d7f7986 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.469 2007/07/12 23:25:26 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.470 2007/08/21 01:11:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -158,6 +158,10 @@ static void dumpSequence(Archive *fout, TableInfo *tbinfo);
static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
+static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
+static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
+static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
+static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name,
@@ -174,6 +178,7 @@ static char *format_function_arguments(FuncInfo *finfo, int nallargs,
static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
static const char *convertRegProcReference(const char *proc);
static const char *convertOperatorReference(const char *opr);
+static const char *convertTSFunction(Oid funcOid);
static Oid findLastBuiltinOid_V71(const char *);
static Oid findLastBuiltinOid_V70(void);
static void selectSourceSchema(const char *schemaName);
@@ -4678,6 +4683,327 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
/*
+ * getTSParsers:
+ * read all text search parsers in the system catalogs and return them
+ * in the TSParserInfo* structure
+ *
+ * numTSParsers is set to the number of parsers read in
+ */
+TSParserInfo *
+getTSParsers(int *numTSParsers)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSParserInfo *prsinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_prsname;
+ int i_prsnamespace;
+ int i_prsstart;
+ int i_prstoken;
+ int i_prsend;
+ int i_prsheadline;
+ int i_prslextype;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSParsers = 0;
+ return NULL;
+ }
+
+ /*
+ * find all text search objects, including builtin ones; we filter out
+ * system-defined objects at dump-out time.
+ */
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
+ "prsstart::oid, prstoken::oid, "
+ "prsend::oid, prsheadline::oid, prslextype::oid "
+ "FROM pg_ts_parser");
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSParsers = ntups;
+
+ prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_prsname = PQfnumber(res, "prsname");
+ i_prsnamespace = PQfnumber(res, "prsnamespace");
+ i_prsstart = PQfnumber(res, "prsstart");
+ i_prstoken = PQfnumber(res, "prstoken");
+ i_prsend = PQfnumber(res, "prsend");
+ i_prsheadline = PQfnumber(res, "prsheadline");
+ i_prslextype = PQfnumber(res, "prslextype");
+
+ for (i = 0; i < ntups; i++)
+ {
+ prsinfo[i].dobj.objType = DO_TSPARSER;
+ prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&prsinfo[i].dobj);
+ prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
+ prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
+ prsinfo[i].dobj.catId.oid);
+ prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
+ prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
+ prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
+ prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
+ prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(prsinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return prsinfo;
+}
+
+/*
+ * getTSDictionaries:
+ * read all text search dictionaries in the system catalogs and return them
+ * in the TSDictInfo* structure
+ *
+ * numTSDicts is set to the number of dictionaries read in
+ */
+TSDictInfo *
+getTSDictionaries(int *numTSDicts)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSDictInfo *dictinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_dictname;
+ int i_dictnamespace;
+ int i_rolname;
+ int i_dicttemplate;
+ int i_dictinitoption;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSDicts = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
+ "dictnamespace, (%s dictowner) as rolname, "
+ "dicttemplate, dictinitoption "
+ "FROM pg_ts_dict",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSDicts = ntups;
+
+ dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_dictname = PQfnumber(res, "dictname");
+ i_dictnamespace = PQfnumber(res, "dictnamespace");
+ i_rolname = PQfnumber(res, "rolname");
+ i_dictinitoption = PQfnumber(res, "dictinitoption");
+ i_dicttemplate = PQfnumber(res, "dicttemplate");
+
+ for (i = 0; i < ntups; i++)
+ {
+ dictinfo[i].dobj.objType = DO_TSDICT;
+ dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&dictinfo[i].dobj);
+ dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
+ dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
+ dictinfo[i].dobj.catId.oid);
+ dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+ dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
+ if (PQgetisnull(res, i, i_dictinitoption))
+ dictinfo[i].dictinitoption = NULL;
+ else
+ dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(dictinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return dictinfo;
+}
+
+/*
+ * getTSTemplates:
+ * read all text search templates in the system catalogs and return them
+ * in the TSTemplateInfo* structure
+ *
+ * numTSTemplates is set to the number of templates read in
+ */
+TSTemplateInfo *
+getTSTemplates(int *numTSTemplates)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSTemplateInfo *tmplinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_tmplname;
+ int i_tmplnamespace;
+ int i_tmplinit;
+ int i_tmpllexize;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSTemplates = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
+ "tmplnamespace, tmplinit::oid, tmpllexize::oid "
+ "FROM pg_ts_template");
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSTemplates = ntups;
+
+ tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_tmplname = PQfnumber(res, "tmplname");
+ i_tmplnamespace = PQfnumber(res, "tmplnamespace");
+ i_tmplinit = PQfnumber(res, "tmplinit");
+ i_tmpllexize = PQfnumber(res, "tmpllexize");
+
+ for (i = 0; i < ntups; i++)
+ {
+ tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
+ tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&tmplinfo[i].dobj);
+ tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
+ tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
+ tmplinfo[i].dobj.catId.oid);
+ tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
+ tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(tmplinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return tmplinfo;
+}
+
+/*
+ * getTSConfigurations:
+ * read all text search configurations in the system catalogs and return
+ * them in the TSConfigInfo* structure
+ *
+ * numTSConfigs is set to the number of configurations read in
+ */
+TSConfigInfo *
+getTSConfigurations(int *numTSConfigs)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ TSConfigInfo *cfginfo;
+ int i_tableoid;
+ int i_oid;
+ int i_cfgname;
+ int i_cfgnamespace;
+ int i_rolname;
+ int i_cfgparser;
+
+ /* Before 8.3, there is no built-in text search support */
+ if (g_fout->remoteVersion < 80300)
+ {
+ *numTSConfigs = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
+ "cfgnamespace, (%s cfgowner) as rolname, cfgparser "
+ "FROM pg_ts_config",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numTSConfigs = ntups;
+
+ cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_cfgname = PQfnumber(res, "cfgname");
+ i_cfgnamespace = PQfnumber(res, "cfgnamespace");
+ i_rolname = PQfnumber(res, "rolname");
+ i_cfgparser = PQfnumber(res, "cfgparser");
+
+ for (i = 0; i < ntups; i++)
+ {
+ cfginfo[i].dobj.objType = DO_TSCONFIG;
+ cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&cfginfo[i].dobj);
+ cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
+ cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
+ cfginfo[i].dobj.catId.oid);
+ cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+ cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(cfginfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return cfginfo;
+}
+
+
+/*
* dumpComment --
*
* This routine is used to dump any comments associated with the
@@ -5066,6 +5392,18 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_TABLE_TYPE:
/* table rowtypes are never dumped separately */
break;
+ case DO_TSPARSER:
+ dumpTSParser(fout, (TSParserInfo *) dobj);
+ break;
+ case DO_TSDICT:
+ dumpTSDictionary(fout, (TSDictInfo *) dobj);
+ break;
+ case DO_TSTEMPLATE:
+ dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
+ break;
+ case DO_TSCONFIG:
+ dumpTSConfig(fout, (TSConfigInfo *) dobj);
+ break;
case DO_BLOBS:
ArchiveEntry(fout, dobj->catId, dobj->dumpId,
dobj->name, NULL, NULL, "",
@@ -6875,6 +7213,43 @@ convertOperatorReference(const char *opr)
}
/*
+ * Convert a function OID obtained from pg_ts_parser or pg_ts_template
+ *
+ * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
+ * argument lists of these functions are predetermined. Note that the
+ * caller should ensure we are in the proper schema, because the results
+ * are search path dependent!
+ */
+static const char *
+convertTSFunction(Oid funcOid)
+{
+ char *result;
+ char query[128];
+ PGresult *res;
+ int ntups;
+
+ snprintf(query, sizeof(query),
+ "SELECT '%u'::pg_catalog.regproc", funcOid);
+ res = PQexec(g_conn, query);
+ check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "Got %d rows instead of one from \"%s\"\n",
+ ntups, query);
+ exit_nicely();
+ }
+
+ result = strdup(PQgetvalue(res, 0, 0));
+
+ PQclear(res);
+
+ return result;
+}
+
+
+/*
* dumpOpclass
* write out a single operator class definition
*/
@@ -7795,6 +8170,351 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
destroyPQExpBuffer(details);
}
+/*
+ * dumpTSParser
+ * write out a single text search parser
+ */
+static void
+dumpTSParser(Archive *fout, TSParserInfo * prsinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+
+ /* Skip if not to be dumped */
+ if (!prsinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
+ fmtId(prsinfo->dobj.name));
+
+ appendPQExpBuffer(q, " START = %s,\n",
+ convertTSFunction(prsinfo->prsstart));
+ appendPQExpBuffer(q, " GETTOKEN = %s,\n",
+ convertTSFunction(prsinfo->prstoken));
+ appendPQExpBuffer(q, " END = %s,\n",
+ convertTSFunction(prsinfo->prsend));
+ if (prsinfo->prsheadline != InvalidOid)
+ appendPQExpBuffer(q, " HEADLINE = %s,\n",
+ convertTSFunction(prsinfo->prsheadline));
+ appendPQExpBuffer(q, " LEXTYPES = %s );\n",
+ convertTSFunction(prsinfo->prslextype));
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
+ fmtId(prsinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(prsinfo->dobj.name));
+
+ ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
+ prsinfo->dobj.name,
+ prsinfo->dobj.namespace->dobj.name,
+ NULL,
+ "",
+ false, "TEXT SEARCH PARSER", q->data, delq->data, NULL,
+ prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Parser Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
+ fmtId(prsinfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, "",
+ prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpTSDictionary
+ * write out a single text search dictionary
+ */
+static void
+dumpTSDictionary(Archive *fout, TSDictInfo * dictinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer query;
+ PGresult *res;
+ int ntups;
+ char *nspname;
+ char *tmplname;
+
+ /* Skip if not to be dumped */
+ if (!dictinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ query = createPQExpBuffer();
+
+ /* Fetch name and namespace of the dictionary's template */
+ selectSourceSchema("pg_catalog");
+ appendPQExpBuffer(query, "SELECT nspname, tmplname "
+ "FROM pg_ts_template p, pg_namespace n "
+ "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
+ dictinfo->dicttemplate);
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "Got %d rows instead of one from \"%s\"\n",
+ ntups, query->data);
+ exit_nicely();
+ }
+ nspname = PQgetvalue(res, 0, 0);
+ tmplname = PQgetvalue(res, 0, 1);
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
+ fmtId(dictinfo->dobj.name));
+
+ appendPQExpBuffer(q, " TEMPLATE = ");
+ if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
+ appendPQExpBuffer(q, "%s.", fmtId(nspname));
+ appendPQExpBuffer(q, "%s", fmtId(tmplname));
+
+ PQclear(res);
+
+ if (dictinfo->dictinitoption)
+ {
+ appendPQExpBuffer(q, ",\n OPTION = ");
+ appendStringLiteralConn(q, dictinfo->dictinitoption, g_conn);
+ }
+
+ appendPQExpBuffer(q, " );\n");
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
+ fmtId(dictinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(dictinfo->dobj.name));
+
+ ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
+ dictinfo->dobj.name,
+ dictinfo->dobj.namespace->dobj.name,
+ NULL,
+ dictinfo->rolname,
+ false, "TEXT SEARCH DICTIONARY", q->data, delq->data, NULL,
+ dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Dictionary Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
+ fmtId(dictinfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, dictinfo->rolname,
+ dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpTSTemplate
+ * write out a single text search template
+ */
+static void
+dumpTSTemplate(Archive *fout, TSTemplateInfo * tmplinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+
+ /* Skip if not to be dumped */
+ if (!tmplinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
+ fmtId(tmplinfo->dobj.name));
+
+ if (tmplinfo->tmplinit != InvalidOid)
+ appendPQExpBuffer(q, " INIT = %s,\n",
+ convertTSFunction(tmplinfo->tmplinit));
+ appendPQExpBuffer(q, " LEXIZE = %s );\n",
+ convertTSFunction(tmplinfo->tmpllexize));
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
+ fmtId(tmplinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(tmplinfo->dobj.name));
+
+ ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
+ tmplinfo->dobj.name,
+ tmplinfo->dobj.namespace->dobj.name,
+ NULL,
+ "",
+ false, "TEXT SEARCH TEMPLATE", q->data, delq->data, NULL,
+ tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Template Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
+ fmtId(tmplinfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, "",
+ tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpTSConfig
+ * write out a single text search configuration
+ */
+static void
+dumpTSConfig(Archive *fout, TSConfigInfo * cfginfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer query;
+ PGresult *res;
+ char *nspname;
+ char *prsname;
+ int ntups,
+ i;
+ int i_tokenname;
+ int i_dictname;
+
+ /* Skip if not to be dumped */
+ if (!cfginfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ query = createPQExpBuffer();
+
+ /* Fetch name and namespace of the config's parser */
+ selectSourceSchema("pg_catalog");
+ appendPQExpBuffer(query, "SELECT nspname, prsname "
+ "FROM pg_ts_parser p, pg_namespace n "
+ "WHERE p.oid = '%u' AND n.oid = prsnamespace",
+ cfginfo->cfgparser);
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "Got %d rows instead of one from \"%s\"\n",
+ ntups, query->data);
+ exit_nicely();
+ }
+ nspname = PQgetvalue(res, 0, 0);
+ prsname = PQgetvalue(res, 0, 1);
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
+
+ appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
+ fmtId(cfginfo->dobj.name));
+
+ appendPQExpBuffer(q, " PARSER = ");
+ if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
+ appendPQExpBuffer(q, "%s.", fmtId(nspname));
+ appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
+
+ PQclear(res);
+
+ resetPQExpBuffer(query);
+ appendPQExpBuffer(query,
+ "SELECT \n"
+ " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
+ " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
+ " m.mapdict::pg_catalog.regdictionary AS dictname \n"
+ "FROM pg_catalog.pg_ts_config_map AS m \n"
+ "WHERE m.mapcfg = '%u' \n"
+ "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
+ cfginfo->cfgparser, cfginfo->dobj.catId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ ntups = PQntuples(res);
+
+ i_tokenname = PQfnumber(res, "tokenname");
+ i_dictname = PQfnumber(res, "dictname");
+
+ for (i = 0; i < ntups; i++)
+ {
+ char *tokenname = PQgetvalue(res, i, i_tokenname);
+ char *dictname = PQgetvalue(res, i, i_dictname);
+
+ if (i == 0 ||
+ strcmp(tokenname, PQgetvalue(res, i-1, i_tokenname)) != 0)
+ {
+ /* starting a new token type, so start a new command */
+ if (i > 0)
+ appendPQExpBuffer(q, ";\n");
+ appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
+ fmtId(cfginfo->dobj.name));
+ /* tokenname needs quoting, dictname does NOT */
+ appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
+ fmtId(tokenname), dictname);
+ }
+ else
+ appendPQExpBuffer(q, ", %s", dictname);
+ }
+
+ if (ntups > 0)
+ appendPQExpBuffer(q, ";\n");
+
+ PQclear(res);
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
+ fmtId(cfginfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, ".%s;\n",
+ fmtId(cfginfo->dobj.name));
+
+ ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
+ cfginfo->dobj.name,
+ cfginfo->dobj.namespace->dobj.name,
+ NULL,
+ cfginfo->rolname,
+ false, "TEXT SEARCH CONFIGURATION", q->data, delq->data, NULL,
+ cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Configuration Comments */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
+ fmtId(cfginfo->dobj.name));
+ dumpComment(fout, q->data,
+ NULL, cfginfo->rolname,
+ cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(query);
+}
+
/*----------
* Write out grant/revoke information