Fix pg_dump to not emit invalid SQL for an empty operator class.
authorTom Lane <[email protected]>
Fri, 26 May 2017 16:51:06 +0000 (12:51 -0400)
committerTom Lane <[email protected]>
Fri, 26 May 2017 16:51:06 +0000 (12:51 -0400)
If an operator class has no operators or functions, and doesn't need
a STORAGE clause, we emitted "CREATE OPERATOR CLASS ... AS ;" which
is syntactically invalid.  Fix by forcing a STORAGE clause to be
emitted anyway in this case.

(At some point we might consider changing the grammar to allow CREATE
OPERATOR CLASS without an opclass_item_list.  But probably we'd want to
omit the AS in that case, so that wouldn't fix this pg_dump issue anyway.)

It's been like this all along, so back-patch to all supported branches.

Daniel Gustafsson, tweaked by me to avoid a dangling-pointer bug

Discussion: https://postgr.es/m/D9E5FC64-7A37-4F3D-B946-7E4FB468F88A@yesql.se

src/bin/pg_dump/pg_dump.c

index 0de7399195631f86109e72c48aa4d1118db96a7e..a0a5ba76d4b8a809b55c5e7ceeca7ff4a4907368 100644 (file)
@@ -10237,7 +10237,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
    i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
    i_amname = PQfnumber(res, "amname");
 
-   opcintype = PQgetvalue(res, 0, i_opcintype);
+   /* opcintype may still be needed after we PQclear res */
+   opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
    opckeytype = PQgetvalue(res, 0, i_opckeytype);
    opcdefault = PQgetvalue(res, 0, i_opcdefault);
    /* opcfamily will still be needed after we PQclear res */
@@ -10471,6 +10472,15 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 
    PQclear(res);
 
+   /*
+    * If needComma is still false it means we haven't added anything after
+    * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
+    * clause with the same datatype.  This isn't sanctioned by the
+    * documentation, but actually DefineOpClass will treat it as a no-op.
+    */
+   if (!needComma)
+       appendPQExpBuffer(q, "STORAGE %s", opcintype);
+
    appendPQExpBuffer(q, ";\n");
 
    appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
@@ -10496,6 +10506,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
                opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
                opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
 
+   free(opcintype);
+   free(opcfamily);
    free(amname);
    destroyPQExpBuffer(query);
    destroyPQExpBuffer(q);