@@ -256,6 +256,9 @@ static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
256
256
const char * objlabel );
257
257
static const char * getAttrName (int attrnum , TableInfo * tblInfo );
258
258
static const char * fmtCopyColumnList (const TableInfo * ti , PQExpBuffer buffer );
259
+ static bool nonemptyReloptions (const char * reloptions );
260
+ static void fmtReloptionsArray (Archive * fout , PQExpBuffer buffer ,
261
+ const char * reloptions , const char * prefix );
259
262
static char * get_synchronized_snapshot (Archive * fout );
260
263
static PGresult * ExecuteSqlQueryForSingleRow (Archive * fout , char * query );
261
264
static void setupDumpWorker (Archive * AHX , DumpOptions * dopt , RestoreOptions * ropt );
@@ -4604,10 +4607,10 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4604
4607
"d.refobjid AS owning_tab, "
4605
4608
"d.refobjsubid AS owning_col, "
4606
4609
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4607
- "array_to_string( array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4610
+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
4608
4611
"CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4609
4612
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4610
- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4613
+ "tc.reloptions AS toast_reloptions "
4611
4614
"FROM pg_class c "
4612
4615
"LEFT JOIN pg_depend d ON "
4613
4616
"(c.relkind = '%c' AND "
@@ -4646,10 +4649,10 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4646
4649
"d.refobjid AS owning_tab, "
4647
4650
"d.refobjsubid AS owning_col, "
4648
4651
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4649
- "array_to_string( array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4652
+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
4650
4653
"CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4651
4654
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4652
- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4655
+ "tc.reloptions AS toast_reloptions "
4653
4656
"FROM pg_class c "
4654
4657
"LEFT JOIN pg_depend d ON "
4655
4658
"(c.relkind = '%c' AND "
@@ -4688,10 +4691,10 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4688
4691
"d.refobjid AS owning_tab, "
4689
4692
"d.refobjsubid AS owning_col, "
4690
4693
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4691
- "array_to_string( array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4694
+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
4692
4695
"CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4693
4696
"WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4694
- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4697
+ "tc.reloptions AS toast_reloptions "
4695
4698
"FROM pg_class c "
4696
4699
"LEFT JOIN pg_depend d ON "
4697
4700
"(c.relkind = '%c' AND "
@@ -4730,8 +4733,8 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4730
4733
"d.refobjid AS owning_tab, "
4731
4734
"d.refobjsubid AS owning_col, "
4732
4735
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4733
- "array_to_string( c.reloptions, ', ') AS reloptions, "
4734
- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4736
+ " c.reloptions AS reloptions, "
4737
+ "tc.reloptions AS toast_reloptions "
4735
4738
"FROM pg_class c "
4736
4739
"LEFT JOIN pg_depend d ON "
4737
4740
"(c.relkind = '%c' AND "
@@ -4770,8 +4773,8 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4770
4773
"d.refobjid AS owning_tab, "
4771
4774
"d.refobjsubid AS owning_col, "
4772
4775
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4773
- "array_to_string( c.reloptions, ', ') AS reloptions, "
4774
- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4776
+ " c.reloptions AS reloptions, "
4777
+ "tc.reloptions AS toast_reloptions "
4775
4778
"FROM pg_class c "
4776
4779
"LEFT JOIN pg_depend d ON "
4777
4780
"(c.relkind = '%c' AND "
@@ -4809,8 +4812,8 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4809
4812
"d.refobjid AS owning_tab, "
4810
4813
"d.refobjsubid AS owning_col, "
4811
4814
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4812
- "array_to_string( c.reloptions, ', ') AS reloptions, "
4813
- "array_to_string(array(SELECT 'toast.' || x FROM unnest( tc.reloptions) x), ', ') AS toast_reloptions "
4815
+ " c.reloptions AS reloptions, "
4816
+ "tc.reloptions AS toast_reloptions "
4814
4817
"FROM pg_class c "
4815
4818
"LEFT JOIN pg_depend d ON "
4816
4819
"(c.relkind = '%c' AND "
@@ -4848,7 +4851,7 @@ getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4848
4851
"d.refobjid AS owning_tab, "
4849
4852
"d.refobjsubid AS owning_col, "
4850
4853
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4851
- "array_to_string( c.reloptions, ', ') AS reloptions, "
4854
+ " c.reloptions AS reloptions, "
4852
4855
"NULL AS toast_reloptions "
4853
4856
"FROM pg_class c "
4854
4857
"LEFT JOIN pg_depend d ON "
@@ -5321,7 +5324,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5321
5324
i_conoid ,
5322
5325
i_condef ,
5323
5326
i_tablespace ,
5324
- i_options ,
5327
+ i_indreloptions ,
5325
5328
i_relpages ;
5326
5329
int ntups ;
5327
5330
@@ -5379,7 +5382,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5379
5382
"c.oid AS conoid, "
5380
5383
"pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5381
5384
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5382
- "array_to_string( t.reloptions, ', ') AS options "
5385
+ " t.reloptions AS indreloptions "
5383
5386
"FROM pg_catalog.pg_index i "
5384
5387
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5385
5388
"LEFT JOIN pg_catalog.pg_constraint c "
@@ -5410,7 +5413,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5410
5413
"c.oid AS conoid, "
5411
5414
"pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5412
5415
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5413
- "array_to_string( t.reloptions, ', ') AS options "
5416
+ " t.reloptions AS indreloptions "
5414
5417
"FROM pg_catalog.pg_index i "
5415
5418
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5416
5419
"LEFT JOIN pg_catalog.pg_constraint c "
@@ -5437,7 +5440,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5437
5440
"c.oid AS conoid, "
5438
5441
"null AS condef, "
5439
5442
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5440
- "array_to_string( t.reloptions, ', ') AS options "
5443
+ " t.reloptions AS indreloptions "
5441
5444
"FROM pg_catalog.pg_index i "
5442
5445
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5443
5446
"LEFT JOIN pg_catalog.pg_depend d "
@@ -5467,7 +5470,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5467
5470
"c.oid AS conoid, "
5468
5471
"null AS condef, "
5469
5472
"(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5470
- "null AS options "
5473
+ "null AS indreloptions "
5471
5474
"FROM pg_catalog.pg_index i "
5472
5475
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5473
5476
"LEFT JOIN pg_catalog.pg_depend d "
@@ -5496,7 +5499,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5496
5499
"c.oid AS conoid, "
5497
5500
"null AS condef, "
5498
5501
"NULL AS tablespace, "
5499
- "null AS options "
5502
+ "null AS indreloptions "
5500
5503
"FROM pg_catalog.pg_index i "
5501
5504
"JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5502
5505
"LEFT JOIN pg_catalog.pg_depend d "
@@ -5528,7 +5531,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5528
5531
"t.oid AS conoid, "
5529
5532
"null AS condef, "
5530
5533
"NULL AS tablespace, "
5531
- "null AS options "
5534
+ "null AS indreloptions "
5532
5535
"FROM pg_index i, pg_class t "
5533
5536
"WHERE t.oid = i.indexrelid "
5534
5537
"AND i.indrelid = '%u'::oid "
@@ -5555,7 +5558,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5555
5558
"t.oid AS conoid, "
5556
5559
"null AS condef, "
5557
5560
"NULL AS tablespace, "
5558
- "null AS options "
5561
+ "null AS indreloptions "
5559
5562
"FROM pg_index i, pg_class t "
5560
5563
"WHERE t.oid = i.indexrelid "
5561
5564
"AND i.indrelid = '%u'::oid "
@@ -5584,7 +5587,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5584
5587
i_conoid = PQfnumber (res , "conoid" );
5585
5588
i_condef = PQfnumber (res , "condef" );
5586
5589
i_tablespace = PQfnumber (res , "tablespace" );
5587
- i_options = PQfnumber (res , "options " );
5590
+ i_indreloptions = PQfnumber (res , "indreloptions " );
5588
5591
5589
5592
indxinfo = (IndxInfo * ) pg_malloc (ntups * sizeof (IndxInfo ));
5590
5593
constrinfo = (ConstraintInfo * ) pg_malloc (ntups * sizeof (ConstraintInfo ));
@@ -5603,7 +5606,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5603
5606
indxinfo [j ].indexdef = pg_strdup (PQgetvalue (res , j , i_indexdef ));
5604
5607
indxinfo [j ].indnkeys = atoi (PQgetvalue (res , j , i_indnkeys ));
5605
5608
indxinfo [j ].tablespace = pg_strdup (PQgetvalue (res , j , i_tablespace ));
5606
- indxinfo [j ].options = pg_strdup (PQgetvalue (res , j , i_options ));
5609
+ indxinfo [j ].indreloptions = pg_strdup (PQgetvalue (res , j , i_indreloptions ));
5607
5610
5608
5611
/*
5609
5612
* In pre-7.4 releases, indkeys may contain more entries than
@@ -10255,7 +10258,8 @@ dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo)
10255
10258
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
10256
10259
"array_to_string(protrftypes, ' ') AS protrftypes, "
10257
10260
"proiswindow, provolatile, proisstrict, prosecdef, "
10258
- "proleakproof, proconfig, procost, prorows, proparallel, "
10261
+ "proleakproof, proconfig, procost, prorows, "
10262
+ "proparallel, "
10259
10263
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10260
10264
"FROM pg_catalog.pg_proc "
10261
10265
"WHERE oid = '%u'::pg_catalog.oid" ,
@@ -13869,8 +13873,12 @@ dumpTableSchema(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
13869
13873
tbinfo -> dobj .catId .oid , false);
13870
13874
13871
13875
appendPQExpBuffer (q , "CREATE VIEW %s" , fmtId (tbinfo -> dobj .name ));
13872
- if (tbinfo -> reloptions && strlen (tbinfo -> reloptions ) > 0 )
13873
- appendPQExpBuffer (q , " WITH (%s)" , tbinfo -> reloptions );
13876
+ if (nonemptyReloptions (tbinfo -> reloptions ))
13877
+ {
13878
+ appendPQExpBufferStr (q , " WITH (" );
13879
+ fmtReloptionsArray (fout , q , tbinfo -> reloptions , "" );
13880
+ appendPQExpBufferChar (q , ')' );
13881
+ }
13874
13882
result = createViewAsClause (fout , tbinfo );
13875
13883
appendPQExpBuffer (q , " AS\n%s" , result -> data );
13876
13884
destroyPQExpBuffer (result );
@@ -14114,21 +14122,22 @@ dumpTableSchema(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
14114
14122
appendPQExpBuffer (q , "\nSERVER %s" , fmtId (srvname ));
14115
14123
}
14116
14124
14117
- if ((tbinfo -> reloptions && strlen ( tbinfo -> reloptions ) > 0 ) ||
14118
- (tbinfo -> toast_reloptions && strlen ( tbinfo -> toast_reloptions ) > 0 ))
14125
+ if (nonemptyReloptions (tbinfo -> reloptions ) ||
14126
+ nonemptyReloptions (tbinfo -> toast_reloptions ))
14119
14127
{
14120
14128
bool addcomma = false;
14121
14129
14122
14130
appendPQExpBufferStr (q , "\nWITH (" );
14123
- if (tbinfo -> reloptions && strlen (tbinfo -> reloptions ) > 0 )
14131
+ if (nonemptyReloptions (tbinfo -> reloptions ))
14124
14132
{
14125
14133
addcomma = true;
14126
- appendPQExpBufferStr ( q , tbinfo -> reloptions );
14134
+ fmtReloptionsArray ( fout , q , tbinfo -> reloptions , "" );
14127
14135
}
14128
- if (tbinfo -> toast_reloptions && strlen (tbinfo -> toast_reloptions ) > 0 )
14136
+ if (nonemptyReloptions (tbinfo -> toast_reloptions ))
14129
14137
{
14130
- appendPQExpBuffer (q , "%s%s" , addcomma ? ", " : "" ,
14131
- tbinfo -> toast_reloptions );
14138
+ if (addcomma )
14139
+ appendPQExpBufferStr (q , ", " );
14140
+ fmtReloptionsArray (fout , q , tbinfo -> toast_reloptions , "toast." );
14132
14141
}
14133
14142
appendPQExpBufferChar (q , ')' );
14134
14143
}
@@ -14710,8 +14719,12 @@ dumpConstraint(Archive *fout, DumpOptions *dopt, ConstraintInfo *coninfo)
14710
14719
14711
14720
appendPQExpBufferChar (q , ')' );
14712
14721
14713
- if (indxinfo -> options && strlen (indxinfo -> options ) > 0 )
14714
- appendPQExpBuffer (q , " WITH (%s)" , indxinfo -> options );
14722
+ if (nonemptyReloptions (indxinfo -> indreloptions ))
14723
+ {
14724
+ appendPQExpBufferStr (q , " WITH (" );
14725
+ fmtReloptionsArray (fout , q , indxinfo -> indreloptions , "" );
14726
+ appendPQExpBufferChar (q , ')' );
14727
+ }
14715
14728
14716
14729
if (coninfo -> condeferrable )
14717
14730
{
@@ -15571,11 +15584,12 @@ dumpRule(Archive *fout, DumpOptions *dopt, RuleInfo *rinfo)
15571
15584
/*
15572
15585
* Apply view's reloptions when its ON SELECT rule is separate.
15573
15586
*/
15574
- if (rinfo -> reloptions && strlen (rinfo -> reloptions ) > 0 )
15587
+ if (nonemptyReloptions (rinfo -> reloptions ))
15575
15588
{
15576
- appendPQExpBuffer (cmd , "ALTER VIEW %s SET (%s);\n" ,
15577
- fmtId (tbinfo -> dobj .name ),
15578
- rinfo -> reloptions );
15589
+ appendPQExpBuffer (cmd , "ALTER VIEW %s SET (" ,
15590
+ fmtId (tbinfo -> dobj .name ));
15591
+ fmtReloptionsArray (fout , cmd , rinfo -> reloptions , "" );
15592
+ appendPQExpBufferStr (cmd , ");\n" );
15579
15593
}
15580
15594
15581
15595
/*
@@ -16448,6 +16462,83 @@ fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
16448
16462
return buffer -> data ;
16449
16463
}
16450
16464
16465
+ /*
16466
+ * Check if a reloptions array is nonempty.
16467
+ */
16468
+ static bool
16469
+ nonemptyReloptions (const char * reloptions )
16470
+ {
16471
+ /* Don't want to print it if it's just "{}" */
16472
+ return (reloptions != NULL && strlen (reloptions ) > 2 );
16473
+ }
16474
+
16475
+ /*
16476
+ * Format a reloptions array and append it to the given buffer.
16477
+ *
16478
+ * "prefix" is prepended to the option names; typically it's "" or "toast.".
16479
+ *
16480
+ * Note: this logic should generally match the backend's flatten_reloptions()
16481
+ * (in adt/ruleutils.c).
16482
+ */
16483
+ static void
16484
+ fmtReloptionsArray (Archive * fout , PQExpBuffer buffer , const char * reloptions ,
16485
+ const char * prefix )
16486
+ {
16487
+ char * * options ;
16488
+ int noptions ;
16489
+ int i ;
16490
+
16491
+ if (!parsePGArray (reloptions , & options , & noptions ))
16492
+ {
16493
+ write_msg (NULL , "WARNING: could not parse reloptions array\n" );
16494
+ if (options )
16495
+ free (options );
16496
+ return ;
16497
+ }
16498
+
16499
+ for (i = 0 ; i < noptions ; i ++ )
16500
+ {
16501
+ char * option = options [i ];
16502
+ char * name ;
16503
+ char * separator ;
16504
+ char * value ;
16505
+
16506
+ /*
16507
+ * Each array element should have the form name=value. If the "=" is
16508
+ * missing for some reason, treat it like an empty value.
16509
+ */
16510
+ name = option ;
16511
+ separator = strchr (option , '=' );
16512
+ if (separator )
16513
+ {
16514
+ * separator = '\0' ;
16515
+ value = separator + 1 ;
16516
+ }
16517
+ else
16518
+ value = "" ;
16519
+
16520
+ if (i > 0 )
16521
+ appendPQExpBufferStr (buffer , ", " );
16522
+ appendPQExpBuffer (buffer , "%s%s=" , prefix , fmtId (name ));
16523
+
16524
+ /*
16525
+ * In general we need to quote the value; but to avoid unnecessary
16526
+ * clutter, do not quote if it is an identifier that would not need
16527
+ * quoting. (We could also allow numbers, but that is a bit trickier
16528
+ * than it looks --- for example, are leading zeroes significant? We
16529
+ * don't want to assume very much here about what custom reloptions
16530
+ * might mean.)
16531
+ */
16532
+ if (strcmp (fmtId (value ), value ) == 0 )
16533
+ appendPQExpBufferStr (buffer , value );
16534
+ else
16535
+ appendStringLiteralAH (buffer , value , fout );
16536
+ }
16537
+
16538
+ if (options )
16539
+ free (options );
16540
+ }
16541
+
16451
16542
/*
16452
16543
* Execute an SQL query and verify that we got exactly one row back.
16453
16544
*/
0 commit comments