@@ -251,6 +251,9 @@ static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
251251const char * objlabel );
252252static const char * getAttrName (int attrnum ,TableInfo * tblInfo );
253253static const char * fmtCopyColumnList (const TableInfo * ti ,PQExpBuffer buffer );
254+ static bool nonemptyReloptions (const char * reloptions );
255+ static void fmtReloptionsArray (Archive * fout ,PQExpBuffer buffer ,
256+ const char * reloptions ,const char * prefix );
254257static char * get_synchronized_snapshot (Archive * fout );
255258static PGresult * ExecuteSqlQueryForSingleRow (Archive * fout ,char * query );
256259static void setupDumpWorker (Archive * AHX ,DumpOptions * dopt ,RestoreOptions * ropt );
@@ -4585,10 +4588,10 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
45854588"d.refobjid AS owning_tab, "
45864589"d.refobjsubid AS owning_col, "
45874590"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4588- "array_to_string( array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4591+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
45894592"CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
45904593"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4591- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4594+ "tc.reloptions AS toast_reloptions "
45924595"FROM pg_class c "
45934596"LEFT JOIN pg_depend d ON "
45944597"(c.relkind = '%c' AND "
@@ -4627,10 +4630,10 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
46274630"d.refobjid AS owning_tab, "
46284631"d.refobjsubid AS owning_col, "
46294632"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4630- "array_to_string( array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4633+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
46314634"CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
46324635"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4633- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4636+ "tc.reloptions AS toast_reloptions "
46344637"FROM pg_class c "
46354638"LEFT JOIN pg_depend d ON "
46364639"(c.relkind = '%c' AND "
@@ -4669,10 +4672,10 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
46694672"d.refobjid AS owning_tab, "
46704673"d.refobjsubid AS owning_col, "
46714674"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4672- "array_to_string( array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4675+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
46734676"CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
46744677"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4675- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4678+ "tc.reloptions AS toast_reloptions "
46764679"FROM pg_class c "
46774680"LEFT JOIN pg_depend d ON "
46784681"(c.relkind = '%c' AND "
@@ -4711,8 +4714,8 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
47114714"d.refobjid AS owning_tab, "
47124715"d.refobjsubid AS owning_col, "
47134716"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4714- "array_to_string( c.reloptions, ', ') AS reloptions, "
4715- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4717+ " c.reloptions AS reloptions, "
4718+ "tc.reloptions AS toast_reloptions "
47164719"FROM pg_class c "
47174720"LEFT JOIN pg_depend d ON "
47184721"(c.relkind = '%c' AND "
@@ -4751,8 +4754,8 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
47514754"d.refobjid AS owning_tab, "
47524755"d.refobjsubid AS owning_col, "
47534756"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4754- "array_to_string( c.reloptions, ', ') AS reloptions, "
4755- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4757+ " c.reloptions AS reloptions, "
4758+ "tc.reloptions AS toast_reloptions "
47564759"FROM pg_class c "
47574760"LEFT JOIN pg_depend d ON "
47584761"(c.relkind = '%c' AND "
@@ -4790,8 +4793,8 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
47904793"d.refobjid AS owning_tab, "
47914794"d.refobjsubid AS owning_col, "
47924795"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4793- "array_to_string( c.reloptions, ', ') AS reloptions, "
4794- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4796+ " c.reloptions AS reloptions, "
4797+ "tc.reloptions AS toast_reloptions "
47954798"FROM pg_class c "
47964799"LEFT JOIN pg_depend d ON "
47974800"(c.relkind = '%c' AND "
@@ -4829,7 +4832,7 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
48294832"d.refobjid AS owning_tab, "
48304833"d.refobjsubid AS owning_col, "
48314834"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4832- "array_to_string( c.reloptions, ', ') AS reloptions, "
4835+ " c.reloptions AS reloptions, "
48334836"NULL AS toast_reloptions "
48344837"FROM pg_class c "
48354838"LEFT JOIN pg_depend d ON "
@@ -5302,7 +5305,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
53025305i_conoid ,
53035306i_condef ,
53045307i_tablespace ,
5305- i_options ,
5308+ i_indreloptions ,
53065309i_relpages ;
53075310int ntups ;
53085311
@@ -5360,7 +5363,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
53605363"c.oid AS conoid, "
53615364"pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
53625365"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5363- "array_to_string( t.reloptions, ', ') ASoptions "
5366+ " t.reloptions ASindreloptions "
53645367"FROM pg_catalog.pg_index i "
53655368"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
53665369"LEFT JOIN pg_catalog.pg_constraint c "
@@ -5391,7 +5394,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
53915394"c.oid AS conoid, "
53925395"pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
53935396"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5394- "array_to_string( t.reloptions, ', ') ASoptions "
5397+ " t.reloptions ASindreloptions "
53955398"FROM pg_catalog.pg_index i "
53965399"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
53975400"LEFT JOIN pg_catalog.pg_constraint c "
@@ -5418,7 +5421,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
54185421"c.oid AS conoid, "
54195422"null AS condef, "
54205423"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5421- "array_to_string( t.reloptions, ', ') ASoptions "
5424+ " t.reloptions ASindreloptions "
54225425"FROM pg_catalog.pg_index i "
54235426"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
54245427"LEFT JOIN pg_catalog.pg_depend d "
@@ -5448,7 +5451,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
54485451"c.oid AS conoid, "
54495452"null AS condef, "
54505453"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5451- "null ASoptions "
5454+ "null ASindreloptions "
54525455"FROM pg_catalog.pg_index i "
54535456"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
54545457"LEFT JOIN pg_catalog.pg_depend d "
@@ -5477,7 +5480,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
54775480"c.oid AS conoid, "
54785481"null AS condef, "
54795482"NULL AS tablespace, "
5480- "null ASoptions "
5483+ "null ASindreloptions "
54815484"FROM pg_catalog.pg_index i "
54825485"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
54835486"LEFT JOIN pg_catalog.pg_depend d "
@@ -5509,7 +5512,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
55095512"t.oid AS conoid, "
55105513"null AS condef, "
55115514"NULL AS tablespace, "
5512- "null ASoptions "
5515+ "null ASindreloptions "
55135516"FROM pg_index i, pg_class t "
55145517"WHERE t.oid = i.indexrelid "
55155518"AND i.indrelid = '%u'::oid "
@@ -5536,7 +5539,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
55365539"t.oid AS conoid, "
55375540"null AS condef, "
55385541"NULL AS tablespace, "
5539- "null ASoptions "
5542+ "null ASindreloptions "
55405543"FROM pg_index i, pg_class t "
55415544"WHERE t.oid = i.indexrelid "
55425545"AND i.indrelid = '%u'::oid "
@@ -5565,7 +5568,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
55655568i_conoid = PQfnumber (res ,"conoid" );
55665569i_condef = PQfnumber (res ,"condef" );
55675570i_tablespace = PQfnumber (res ,"tablespace" );
5568- i_options = PQfnumber (res ,"options " );
5571+ i_indreloptions = PQfnumber (res ,"indreloptions " );
55695572
55705573indxinfo = (IndxInfo * )pg_malloc (ntups * sizeof (IndxInfo ));
55715574constrinfo = (ConstraintInfo * )pg_malloc (ntups * sizeof (ConstraintInfo ));
@@ -5584,7 +5587,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
55845587indxinfo [j ].indexdef = pg_strdup (PQgetvalue (res ,j ,i_indexdef ));
55855588indxinfo [j ].indnkeys = atoi (PQgetvalue (res ,j ,i_indnkeys ));
55865589indxinfo [j ].tablespace = pg_strdup (PQgetvalue (res ,j ,i_tablespace ));
5587- indxinfo [j ].options = pg_strdup (PQgetvalue (res ,j ,i_options ));
5590+ indxinfo [j ].indreloptions = pg_strdup (PQgetvalue (res ,j ,i_indreloptions ));
55885591
55895592/*
55905593 * In pre-7.4 releases, indkeys may contain more entries than
@@ -13810,8 +13813,12 @@ dumpTableSchema(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
1381013813tbinfo -> dobj .catId .oid , false);
1381113814
1381213815appendPQExpBuffer (q ,"CREATE VIEW %s" ,fmtId (tbinfo -> dobj .name ));
13813- if (tbinfo -> reloptions && strlen (tbinfo -> reloptions )> 0 )
13814- appendPQExpBuffer (q ," WITH (%s)" ,tbinfo -> reloptions );
13816+ if (nonemptyReloptions (tbinfo -> reloptions ))
13817+ {
13818+ appendPQExpBufferStr (q ," WITH (" );
13819+ fmtReloptionsArray (fout ,q ,tbinfo -> reloptions ,"" );
13820+ appendPQExpBufferChar (q ,')' );
13821+ }
1381513822result = createViewAsClause (fout ,tbinfo );
1381613823appendPQExpBuffer (q ," AS\n%s" ,result -> data );
1381713824destroyPQExpBuffer (result );
@@ -14055,21 +14062,22 @@ dumpTableSchema(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
1405514062appendPQExpBuffer (q ,"\nSERVER %s" ,fmtId (srvname ));
1405614063}
1405714064
14058- if ((tbinfo -> reloptions && strlen ( tbinfo -> reloptions ) > 0 )||
14059- (tbinfo -> toast_reloptions && strlen ( tbinfo -> toast_reloptions ) > 0 ))
14065+ if (nonemptyReloptions (tbinfo -> reloptions )||
14066+ nonemptyReloptions (tbinfo -> toast_reloptions ))
1406014067{
1406114068bool addcomma = false;
1406214069
1406314070appendPQExpBufferStr (q ,"\nWITH (" );
14064- if (tbinfo -> reloptions && strlen (tbinfo -> reloptions )> 0 )
14071+ if (nonemptyReloptions (tbinfo -> reloptions ))
1406514072{
1406614073addcomma = true;
14067- appendPQExpBufferStr ( q ,tbinfo -> reloptions );
14074+ fmtReloptionsArray ( fout , q ,tbinfo -> reloptions , "" );
1406814075}
14069- if (tbinfo -> toast_reloptions && strlen (tbinfo -> toast_reloptions )> 0 )
14076+ if (nonemptyReloptions (tbinfo -> toast_reloptions ))
1407014077{
14071- appendPQExpBuffer (q ,"%s%s" ,addcomma ?", " :"" ,
14072- tbinfo -> toast_reloptions );
14078+ if (addcomma )
14079+ appendPQExpBufferStr (q ,", " );
14080+ fmtReloptionsArray (fout ,q ,tbinfo -> toast_reloptions ,"toast." );
1407314081}
1407414082appendPQExpBufferChar (q ,')' );
1407514083}
@@ -14651,8 +14659,12 @@ dumpConstraint(Archive *fout, DumpOptions *dopt, ConstraintInfo *coninfo)
1465114659
1465214660appendPQExpBufferChar (q ,')' );
1465314661
14654- if (indxinfo -> options && strlen (indxinfo -> options )> 0 )
14655- appendPQExpBuffer (q ," WITH (%s)" ,indxinfo -> options );
14662+ if (nonemptyReloptions (indxinfo -> indreloptions ))
14663+ {
14664+ appendPQExpBufferStr (q ," WITH (" );
14665+ fmtReloptionsArray (fout ,q ,indxinfo -> indreloptions ,"" );
14666+ appendPQExpBufferChar (q ,')' );
14667+ }
1465614668
1465714669if (coninfo -> condeferrable )
1465814670{
@@ -15512,11 +15524,12 @@ dumpRule(Archive *fout, DumpOptions *dopt, RuleInfo *rinfo)
1551215524/*
1551315525 * Apply view's reloptions when its ON SELECT rule is separate.
1551415526 */
15515- if (rinfo -> reloptions && strlen (rinfo -> reloptions )> 0 )
15527+ if (nonemptyReloptions (rinfo -> reloptions ))
1551615528{
15517- appendPQExpBuffer (cmd ,"ALTER VIEW %s SET (%s);\n" ,
15518- fmtId (tbinfo -> dobj .name ),
15519- rinfo -> reloptions );
15529+ appendPQExpBuffer (cmd ,"ALTER VIEW %s SET (" ,
15530+ fmtId (tbinfo -> dobj .name ));
15531+ fmtReloptionsArray (fout ,cmd ,rinfo -> reloptions ,"" );
15532+ appendPQExpBufferStr (cmd ,");\n" );
1552015533}
1552115534
1552215535/*
@@ -16389,6 +16402,83 @@ fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
1638916402return buffer -> data ;
1639016403}
1639116404
16405+ /*
16406+ * Check if a reloptions array is nonempty.
16407+ */
16408+ static bool
16409+ nonemptyReloptions (const char * reloptions )
16410+ {
16411+ /* Don't want to print it if it's just "{}" */
16412+ return (reloptions != NULL && strlen (reloptions )> 2 );
16413+ }
16414+
16415+ /*
16416+ * Format a reloptions array and append it to the given buffer.
16417+ *
16418+ * "prefix" is prepended to the option names; typically it's "" or "toast.".
16419+ *
16420+ * Note: this logic should generally match the backend's flatten_reloptions()
16421+ * (in adt/ruleutils.c).
16422+ */
16423+ static void
16424+ fmtReloptionsArray (Archive * fout ,PQExpBuffer buffer ,const char * reloptions ,
16425+ const char * prefix )
16426+ {
16427+ char * * options ;
16428+ int noptions ;
16429+ int i ;
16430+
16431+ if (!parsePGArray (reloptions ,& options ,& noptions ))
16432+ {
16433+ write_msg (NULL ,"WARNING: could not parse reloptions array\n" );
16434+ if (options )
16435+ free (options );
16436+ return ;
16437+ }
16438+
16439+ for (i = 0 ;i < noptions ;i ++ )
16440+ {
16441+ char * option = options [i ];
16442+ char * name ;
16443+ char * separator ;
16444+ char * value ;
16445+
16446+ /*
16447+ * Each array element should have the form name=value. If the "=" is
16448+ * missing for some reason, treat it like an empty value.
16449+ */
16450+ name = option ;
16451+ separator = strchr (option ,'=' );
16452+ if (separator )
16453+ {
16454+ * separator = '\0' ;
16455+ value = separator + 1 ;
16456+ }
16457+ else
16458+ value = "" ;
16459+
16460+ if (i > 0 )
16461+ appendPQExpBufferStr (buffer ,", " );
16462+ appendPQExpBuffer (buffer ,"%s%s=" ,prefix ,fmtId (name ));
16463+
16464+ /*
16465+ * In general we need to quote the value; but to avoid unnecessary
16466+ * clutter, do not quote if it is an identifier that would not need
16467+ * quoting. (We could also allow numbers, but that is a bit trickier
16468+ * than it looks --- for example, are leading zeroes significant? We
16469+ * don't want to assume very much here about what custom reloptions
16470+ * might mean.)
16471+ */
16472+ if (strcmp (fmtId (value ),value )== 0 )
16473+ appendPQExpBufferStr (buffer ,value );
16474+ else
16475+ appendStringLiteralAH (buffer ,value ,fout );
16476+ }
16477+
16478+ if (options )
16479+ free (options );
16480+ }
16481+
1639216482/*
1639316483 * Execute an SQL query and verify that we got exactly one row back.
1639416484 */