diff options
Diffstat (limited to 'src/bin/pg_dump/pg_dump.c')
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 273 |
1 files changed, 271 insertions, 2 deletions
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index fe08c1b15d2..977b72e3449 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -165,6 +165,7 @@ static void dumpShellType(Archive *fout, DumpOptions *dopt, ShellTypeInfo *stinf static void dumpProcLang(Archive *fout, DumpOptions *dopt, ProcLangInfo *plang); static void dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo); static void dumpCast(Archive *fout, DumpOptions *dopt, CastInfo *cast); +static void dumpTransform(Archive *fout, DumpOptions *dopt, TransformInfo *transform); static void dumpOpr(Archive *fout, DumpOptions *dopt, OprInfo *oprinfo); static void dumpOpclass(Archive *fout, DumpOptions *dopt, OpclassInfo *opcinfo); static void dumpOpfamily(Archive *fout, DumpOptions *dopt, OpfamilyInfo *opfinfo); @@ -6566,6 +6567,110 @@ getCasts(Archive *fout, DumpOptions *dopt, int *numCasts) return castinfo; } +static char * +get_language_name(Archive *fout, Oid langid) +{ + PQExpBuffer query; + PGresult *res; + char *lanname; + + query = createPQExpBuffer(); + appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid); + res = ExecuteSqlQueryForSingleRow(fout, query->data); + lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0))); + destroyPQExpBuffer(query); + PQclear(res); + + return lanname; +} + +/* + * getTransforms + * get basic information about every transform in the system + * + * numTransforms is set to the number of transforms read in + */ +TransformInfo * +getTransforms(Archive *fout, int *numTransforms) +{ + PGresult *res; + int ntups; + int i; + PQExpBuffer query = createPQExpBuffer(); + TransformInfo *transforminfo; + int i_tableoid; + int i_oid; + int i_trftype; + int i_trflang; + int i_trffromsql; + int i_trftosql; + + /* Transforms didn't exist pre-9.5 */ + if (fout->remoteVersion < 90500) + { + *numTransforms = 0; + return NULL; + } + + /* Make sure we are in proper schema */ + selectSourceSchema(fout, "pg_catalog"); + + appendPQExpBuffer(query, "SELECT tableoid, oid, " + "trftype, trflang, trffromsql::oid, trftosql::oid " + "FROM pg_transform " + "ORDER BY 3,4"); + + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + *numTransforms = ntups; + + transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo)); + + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_trftype = PQfnumber(res, "trftype"); + i_trflang = PQfnumber(res, "trflang"); + i_trffromsql = PQfnumber(res, "trffromsql"); + i_trftosql = PQfnumber(res, "trftosql"); + + for (i = 0; i < ntups; i++) + { + PQExpBufferData namebuf; + TypeInfo *typeInfo; + char *lanname; + + transforminfo[i].dobj.objType = DO_TRANSFORM; + transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid)); + transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); + AssignDumpId(&transforminfo[i].dobj); + transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype)); + transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang)); + transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql)); + transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql)); + + /* + * Try to name transform as concatenation of type and language name. + * This is only used for purposes of sorting. If we fail to find + * either, the name will be an empty string. + */ + initPQExpBuffer(&namebuf); + typeInfo = findTypeByOid(transforminfo[i].trftype); + lanname = get_language_name(fout, transforminfo[i].trflang); + if (typeInfo && lanname) + appendPQExpBuffer(&namebuf, "%s %s", + typeInfo->dobj.name, lanname); + transforminfo[i].dobj.name = namebuf.data; + } + + PQclear(res); + + destroyPQExpBuffer(query); + + return transforminfo; +} + /* * getTableAttrs - * for each interesting table, read info about its attributes @@ -8182,6 +8287,9 @@ dumpDumpableObject(Archive *fout, DumpOptions *dopt, DumpableObject *dobj) case DO_CAST: dumpCast(fout, dopt, (CastInfo *) dobj); break; + case DO_TRANSFORM: + dumpTransform(fout, dopt, (TransformInfo *) dobj); + break; case DO_TABLE_DATA: if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE) dumpSequenceData(fout, (TableDataInfo *) dobj); @@ -9989,6 +10097,7 @@ dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo) char *proallargtypes; char *proargmodes; char *proargnames; + char *protrftypes; char *proiswindow; char *provolatile; char *proisstrict; @@ -10021,10 +10130,28 @@ dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo) selectSourceSchema(fout, finfo->dobj.namespace->dobj.name); /* Fetch function-specific details */ - if (fout->remoteVersion >= 90200) + if (fout->remoteVersion >= 90500) { /* - * proleakproof was added at v9.2 + * protrftypes was added in 9.5 + */ + appendPQExpBuffer(query, + "SELECT proretset, prosrc, probin, " + "pg_catalog.pg_get_function_arguments(oid) AS funcargs, " + "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " + "pg_catalog.pg_get_function_result(oid) AS funcresult, " + "array_to_string(protrftypes, ' ') AS protrftypes, " + "proiswindow, provolatile, proisstrict, prosecdef, " + "proleakproof, proconfig, procost, prorows, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", + finfo->dobj.catId.oid); + } + else if (fout->remoteVersion >= 90200) + { + /* + * proleakproof was added in 9.2 */ appendPQExpBuffer(query, "SELECT proretset, prosrc, probin, " @@ -10173,6 +10300,10 @@ dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo) proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames")); funcargs = funciargs = funcresult = NULL; } + if (PQfnumber(res, "protrftypes") != -1) + protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes")); + else + protrftypes = NULL; proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow")); provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile")); proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict")); @@ -10316,6 +10447,22 @@ dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo) appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname)); + if (protrftypes != NULL && strcmp(protrftypes, "") != 0) + { + Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid)); + int i; + + appendPQExpBufferStr(q, " TRANSFORM "); + parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS); + for (i = 0; typeids[i]; i++) + { + if (i != 0) + appendPQExpBufferStr(q, ", "); + appendPQExpBuffer(q, "FOR TYPE %s", + getFormattedTypeName(fout, typeids[i], zeroAsNone)); + } + } + if (proiswindow[0] == 't') appendPQExpBufferStr(q, " WINDOW"); @@ -10540,6 +10687,127 @@ dumpCast(Archive *fout, DumpOptions *dopt, CastInfo *cast) } /* + * Dump a transform + */ +static void +dumpTransform(Archive *fout, DumpOptions *dopt, TransformInfo *transform) +{ + PQExpBuffer defqry; + PQExpBuffer delqry; + PQExpBuffer labelq; + FuncInfo *fromsqlFuncInfo = NULL; + FuncInfo *tosqlFuncInfo = NULL; + char *lanname; + + /* Skip if not to be dumped */ + if (!transform->dobj.dump || dopt->dataOnly) + return; + + /* Cannot dump if we don't have the transform functions' info */ + if (OidIsValid(transform->trffromsql)) + { + fromsqlFuncInfo = findFuncByOid(transform->trffromsql); + if (fromsqlFuncInfo == NULL) + return; + } + if (OidIsValid(transform->trftosql)) + { + tosqlFuncInfo = findFuncByOid(transform->trftosql); + if (tosqlFuncInfo == NULL) + return; + } + + /* Make sure we are in proper schema (needed for getFormattedTypeName) */ + selectSourceSchema(fout, "pg_catalog"); + + defqry = createPQExpBuffer(); + delqry = createPQExpBuffer(); + labelq = createPQExpBuffer(); + + lanname = get_language_name(fout, transform->trflang); + + appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n", + getFormattedTypeName(fout, transform->trftype, zeroAsNone), + lanname); + + appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (", + getFormattedTypeName(fout, transform->trftype, zeroAsNone), + lanname); + + if (!transform->trffromsql && !transform->trftosql) + write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n"); + + if (transform->trffromsql) + { + if (fromsqlFuncInfo) + { + char *fsig = format_function_signature(fout, fromsqlFuncInfo, true); + + /* + * Always qualify the function name, in case it is not in + * pg_catalog schema (format_function_signature won't qualify + * it). + */ + appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s", + fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig); + free(fsig); + } + else + write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n"); + } + + if (transform->trftosql) + { + if (transform->trffromsql) + appendPQExpBuffer(defqry, ", "); + + if (tosqlFuncInfo) + { + char *fsig = format_function_signature(fout, tosqlFuncInfo, true); + + /* + * Always qualify the function name, in case it is not in + * pg_catalog schema (format_function_signature won't qualify + * it). + */ + appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s", + fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig); + free(fsig); + } + else + write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n"); + } + + appendPQExpBuffer(defqry, ");\n"); + + appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s", + getFormattedTypeName(fout, transform->trftype, zeroAsNone), + lanname); + + if (dopt->binary_upgrade) + binary_upgrade_extension_member(defqry, &transform->dobj, labelq->data); + + ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId, + labelq->data, + "pg_catalog", NULL, "", + false, "TRANSFORM", SECTION_PRE_DATA, + defqry->data, delqry->data, NULL, + transform->dobj.dependencies, transform->dobj.nDeps, + NULL, NULL); + + /* Dump Transform Comments */ + dumpComment(fout, dopt, labelq->data, + NULL, "", + transform->dobj.catId, 0, transform->dobj.dumpId); + + free(lanname); + destroyPQExpBuffer(defqry); + destroyPQExpBuffer(delqry); + destroyPQExpBuffer(labelq); +} + + +/* * dumpOpr * write out a single operator definition */ @@ -15658,6 +15926,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, case DO_TSCONFIG: case DO_FDW: case DO_FOREIGN_SERVER: + case DO_TRANSFORM: case DO_BLOB: /* Pre-data objects: must come before the pre-data boundary */ addObjectDependency(preDataBound, dobj->dumpId); |