Skip to content

Commit 6470693

Browse files
kulaginmindrups
andauthored
[PGPRO-5612] Support for checkunique parameter of amcheck.bt_index_check() function (PR #456)
Co-authored-by: Elena Indrupskaya <[email protected]>
1 parent a454bd7 commit 6470693

File tree

7 files changed

+291
-44
lines changed

7 files changed

+291
-44
lines changed

Diff for: doc/pgprobackup.xml

+27-8
Original file line numberDiff line numberDiff line change
@@ -4176,7 +4176,7 @@ pg_probackup restore -B <replaceable>backup_dir</replaceable> --instance <replac
41764176
pg_probackup checkdb
41774177
[-B <replaceable>backup_dir</replaceable>] [--instance <replaceable>instance_name</replaceable>] [-D <replaceable>data_dir</replaceable>]
41784178
[--help] [-j <replaceable>num_threads</replaceable>] [--progress]
4179-
[--skip-block-validation] [--amcheck] [--heapallindexed]
4179+
[--skip-block-validation] [--amcheck [--checkunique] [--heapallindexed]]
41804180
[<replaceable>connection_options</replaceable>] [<replaceable>logging_options</replaceable>]
41814181
</programlisting>
41824182
<para>
@@ -4195,17 +4195,24 @@ pg_probackup checkdb
41954195
extension or the <application>amcheck_next</application> extension
41964196
installed in the database to check its indexes. For databases
41974197
without <application>amcheck</application>, index verification will be skipped.
4198+
Additional options <option>--checkunique</option> and <option>--heapallindexed</option>
4199+
are effective depending on the version of <application>amcheck</application> installed.
41984200
</para>
41994201
</listitem>
42004202
</varlistentry>
42014203

42024204
<varlistentry>
4203-
<term><option>--skip-block-validation</option></term>
4205+
<term><option>--checkunique</option></term>
42044206
<listitem>
42054207
<para>
4206-
Skip validation of data files. You can use this flag only
4207-
together with the <option>--amcheck</option> flag, so that only logical
4208-
verification of indexes is performed.
4208+
Verifies unique constraints during logical verification of indexes.
4209+
You can use this flag only together with the <option>--amcheck</option> flag when
4210+
the <application>amcheck</application> extension is
4211+
installed in the database.
4212+
</para>
4213+
<para>
4214+
This verification is only possible if it is supported by the version of the
4215+
<application>amcheck</application> extension you are using.
42094216
</para>
42104217
</listitem>
42114218
</varlistentry>
@@ -4219,12 +4226,24 @@ pg_probackup checkdb
42194226
<option>--amcheck</option> flag.
42204227
</para>
42214228
<para>
4222-
This check is only possible if you are using the
4223-
<application>amcheck</application> extension of version 2.0 or higher, or
4224-
the <application>amcheck_next</application> extension of any version.
4229+
This check is only possible if it is supported by the version of the
4230+
<application>amcheck</application> extension you are using or
4231+
if the <application>amcheck_next</application> extension is used instead.
4232+
</para>
4233+
</listitem>
4234+
</varlistentry>
4235+
<varlistentry>
4236+
4237+
<term><option>--skip-block-validation</option></term>
4238+
<listitem>
4239+
<para>
4240+
Skip validation of data files. You can use this flag only
4241+
together with the <option>--amcheck</option> flag, so that only logical
4242+
verification of indexes is performed.
42254243
</para>
42264244
</listitem>
42274245
</varlistentry>
4246+
42284247
</variablelist>
42294248
</para>
42304249
<para>

Diff for: src/checkdb.c

+93-31
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ typedef struct pg_indexEntry
8383
char *name;
8484
char *namespace;
8585
bool heapallindexed_is_supported;
86+
bool checkunique_is_supported;
8687
/* schema where amcheck extension is located */
8788
char *amcheck_nspname;
8889
/* lock for synchronization of parallel threads */
@@ -351,10 +352,14 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
351352
{
352353
PGresult *res;
353354
char *amcheck_nspname = NULL;
355+
char *amcheck_extname = NULL;
356+
char *amcheck_extversion = NULL;
354357
int i;
355358
bool heapallindexed_is_supported = false;
359+
bool checkunique_is_supported = false;
356360
parray *index_list = NULL;
357361

362+
/* Check amcheck extension version */
358363
res = pgut_execute(db_conn, "SELECT "
359364
"extname, nspname, extversion "
360365
"FROM pg_catalog.pg_namespace n "
@@ -379,24 +384,68 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
379384
return NULL;
380385
}
381386

387+
amcheck_extname = pgut_malloc(strlen(PQgetvalue(res, 0, 0)) + 1);
388+
strcpy(amcheck_extname, PQgetvalue(res, 0, 0));
382389
amcheck_nspname = pgut_malloc(strlen(PQgetvalue(res, 0, 1)) + 1);
383390
strcpy(amcheck_nspname, PQgetvalue(res, 0, 1));
391+
amcheck_extversion = pgut_malloc(strlen(PQgetvalue(res, 0, 2)) + 1);
392+
strcpy(amcheck_extversion, PQgetvalue(res, 0, 2));
393+
PQclear(res);
384394

385395
/* heapallindexed_is_supported is database specific */
386-
if (strcmp(PQgetvalue(res, 0, 2), "1.0") != 0 &&
387-
strcmp(PQgetvalue(res, 0, 2), "1") != 0)
396+
/* TODO this is wrong check, heapallindexed supported also in 1.1.1, 1.2 and 1.2.1... */
397+
if (strcmp(amcheck_extversion, "1.0") != 0 &&
398+
strcmp(amcheck_extversion, "1") != 0)
388399
heapallindexed_is_supported = true;
389400

390401
elog(INFO, "Amchecking database '%s' using extension '%s' "
391402
"version %s from schema '%s'",
392-
dbname, PQgetvalue(res, 0, 0),
393-
PQgetvalue(res, 0, 2), PQgetvalue(res, 0, 1));
403+
dbname, amcheck_extname,
404+
amcheck_extversion, amcheck_nspname);
394405

395406
if (!heapallindexed_is_supported && heapallindexed)
396407
elog(WARNING, "Extension '%s' version %s in schema '%s'"
397408
"do not support 'heapallindexed' option",
398-
PQgetvalue(res, 0, 0), PQgetvalue(res, 0, 2),
399-
PQgetvalue(res, 0, 1));
409+
amcheck_extname, amcheck_extversion,
410+
amcheck_nspname);
411+
412+
#ifndef PGPRO_EE
413+
/*
414+
* Will support when the vanilla patch will commited https://commitfest.postgresql.org/32/2976/
415+
*/
416+
checkunique_is_supported = false;
417+
#else
418+
/*
419+
* Check bt_index_check function signature to determine support of checkunique parameter
420+
* This can't be exactly checked by checking extension version,
421+
* For example, 1.1.1 and 1.2.1 supports this parameter, but 1.2 doesn't (PGPROEE-12.4.1)
422+
*/
423+
res = pgut_execute(db_conn, "SELECT "
424+
" oid "
425+
"FROM pg_catalog.pg_proc "
426+
"WHERE "
427+
" pronamespace = $1::regnamespace "
428+
"AND proname = 'bt_index_check' "
429+
"AND 'checkunique' = ANY(proargnames) "
430+
"AND (pg_catalog.string_to_array(proargtypes::text, ' ')::regtype[])[pg_catalog.array_position(proargnames, 'checkunique')] = 'bool'::regtype",
431+
1, (const char **) &amcheck_nspname);
432+
433+
if (PQresultStatus(res) != PGRES_TUPLES_OK)
434+
{
435+
PQclear(res);
436+
elog(ERROR, "Cannot check 'checkunique' option is supported in bt_index_check function %s: %s",
437+
dbname, PQerrorMessage(db_conn));
438+
}
439+
440+
checkunique_is_supported = PQntuples(res) >= 1;
441+
PQclear(res);
442+
#endif
443+
444+
if (!checkunique_is_supported && checkunique)
445+
elog(WARNING, "Extension '%s' version %s in schema '%s' "
446+
"do not support 'checkunique' parameter",
447+
amcheck_extname, amcheck_extversion,
448+
amcheck_nspname);
400449

401450
/*
402451
* In order to avoid duplicates, select global indexes
@@ -453,6 +502,7 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
453502
strcpy(ind->namespace, namespace); /* enough buffer size guaranteed */
454503

455504
ind->heapallindexed_is_supported = heapallindexed_is_supported;
505+
ind->checkunique_is_supported = checkunique_is_supported;
456506
ind->amcheck_nspname = pgut_malloc(strlen(amcheck_nspname) + 1);
457507
strcpy(ind->amcheck_nspname, amcheck_nspname);
458508
pg_atomic_clear_flag(&ind->lock);
@@ -464,6 +514,9 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
464514
}
465515

466516
PQclear(res);
517+
free(amcheck_extversion);
518+
free(amcheck_nspname);
519+
free(amcheck_extname);
467520

468521
return index_list;
469522
}
@@ -473,46 +526,54 @@ static bool
473526
amcheck_one_index(check_indexes_arg *arguments,
474527
pg_indexEntry *ind)
475528
{
476-
PGresult *res;
477-
char *params[2];
529+
PGresult *res;
530+
char *params[3];
531+
static const char *queries[] = {
532+
"SELECT %s.bt_index_check(index => $1)",
533+
"SELECT %s.bt_index_check(index => $1, heapallindexed => $2)",
534+
"SELECT %s.bt_index_check(index => $1, heapallindexed => $2, checkunique => $3)",
535+
};
536+
int params_count;
478537
char *query = NULL;
479538

480-
params[0] = palloc(64);
539+
if (interrupted)
540+
elog(ERROR, "Interrupted");
481541

542+
#define INDEXRELID 0
543+
#define HEAPALLINDEXED 1
544+
#define CHECKUNIQUE 2
482545
/* first argument is index oid */
483-
sprintf(params[0], "%u", ind->indexrelid);
546+
params[INDEXRELID] = palloc(64);
547+
sprintf(params[INDEXRELID], "%u", ind->indexrelid);
484548
/* second argument is heapallindexed */
485-
params[1] = heapallindexed ? "true" : "false";
549+
params[HEAPALLINDEXED] = heapallindexed ? "true" : "false";
550+
/* third optional argument is checkunique */
551+
params[CHECKUNIQUE] = checkunique ? "true" : "false";
552+
#undef CHECKUNIQUE
553+
#undef HEAPALLINDEXED
486554

487-
if (interrupted)
488-
elog(ERROR, "Interrupted");
489-
490-
if (ind->heapallindexed_is_supported)
491-
{
492-
query = palloc(strlen(ind->amcheck_nspname)+strlen("SELECT .bt_index_check($1, $2)")+1);
493-
sprintf(query, "SELECT %s.bt_index_check($1, $2)", ind->amcheck_nspname);
555+
params_count = ind->checkunique_is_supported ?
556+
3 :
557+
( ind->heapallindexed_is_supported ? 2 : 1 );
494558

495-
res = pgut_execute_parallel(arguments->conn_arg.conn,
496-
arguments->conn_arg.cancel_conn,
497-
query, 2, (const char **)params, true, true, true);
498-
}
499-
else
500-
{
501-
query = palloc(strlen(ind->amcheck_nspname)+strlen("SELECT .bt_index_check($1)")+1);
502-
sprintf(query, "SELECT %s.bt_index_check($1)", ind->amcheck_nspname);
559+
/*
560+
* Prepare query text with schema name
561+
* +1 for \0 and -2 for %s
562+
*/
563+
query = palloc(strlen(ind->amcheck_nspname) + strlen(queries[params_count - 1]) + 1 - 2);
564+
sprintf(query, queries[params_count - 1], ind->amcheck_nspname);
503565

504-
res = pgut_execute_parallel(arguments->conn_arg.conn,
566+
res = pgut_execute_parallel(arguments->conn_arg.conn,
505567
arguments->conn_arg.cancel_conn,
506-
query, 1, (const char **)params, true, true, true);
507-
}
568+
query, params_count, (const char **)params, true, true, true);
508569

509570
if (PQresultStatus(res) != PGRES_TUPLES_OK)
510571
{
511572
elog(WARNING, "Thread [%d]. Amcheck failed in database '%s' for index: '%s.%s': %s",
512573
arguments->thread_num, arguments->conn_opt.pgdatabase,
513574
ind->namespace, ind->name, PQresultErrorMessage(res));
514575

515-
pfree(params[0]);
576+
pfree(params[INDEXRELID]);
516577
pfree(query);
517578
PQclear(res);
518579
return false;
@@ -522,7 +583,8 @@ amcheck_one_index(check_indexes_arg *arguments,
522583
arguments->thread_num,
523584
arguments->conn_opt.pgdatabase, ind->namespace, ind->name);
524585

525-
pfree(params[0]);
586+
pfree(params[INDEXRELID]);
587+
#undef INDEXRELID
526588
pfree(query);
527589
PQclear(res);
528590
return true;

Diff for: src/help.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ help_pg_probackup(void)
190190
printf(_("\n %s checkdb [-B backup-path] [--instance=instance_name]\n"), PROGRAM_NAME);
191191
printf(_(" [-D pgdata-path] [--progress] [-j num-threads]\n"));
192192
printf(_(" [--amcheck] [--skip-block-validation]\n"));
193-
printf(_(" [--heapallindexed]\n"));
193+
printf(_(" [--heapallindexed] [--checkunique]\n"));
194194
printf(_(" [--help]\n"));
195195

196196
printf(_("\n %s show -B backup-path\n"), PROGRAM_NAME);
@@ -601,7 +601,7 @@ help_checkdb(void)
601601
printf(_("\n%s checkdb [-B backup-path] [--instance=instance_name]\n"), PROGRAM_NAME);
602602
printf(_(" [-D pgdata-path] [-j num-threads] [--progress]\n"));
603603
printf(_(" [--amcheck] [--skip-block-validation]\n"));
604-
printf(_(" [--heapallindexed]\n\n"));
604+
printf(_(" [--heapallindexed] [--checkunique]\n\n"));
605605

606606
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
607607
printf(_(" --instance=instance_name name of the instance\n"));
@@ -616,6 +616,8 @@ help_checkdb(void)
616616
printf(_(" using 'amcheck' or 'amcheck_next' extensions\n"));
617617
printf(_(" --heapallindexed also check that heap is indexed\n"));
618618
printf(_(" can be used only with '--amcheck' option\n"));
619+
printf(_(" --checkunique also check unique constraints\n"));
620+
printf(_(" can be used only with '--amcheck' option\n"));
619621

620622
printf(_("\n Logging options:\n"));
621623
printf(_(" --log-level-console=log-level-console\n"));

Diff for: src/pg_probackup.c

+12
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ static parray *exclude_relative_paths_list = NULL;
126126
/* checkdb options */
127127
bool need_amcheck = false;
128128
bool heapallindexed = false;
129+
bool checkunique = false;
129130
bool amcheck_parent = false;
130131

131132
/* delete options */
@@ -240,6 +241,7 @@ static ConfigOption cmd_options[] =
240241
/* checkdb options */
241242
{ 'b', 195, "amcheck", &need_amcheck, SOURCE_CMD_STRICT },
242243
{ 'b', 196, "heapallindexed", &heapallindexed, SOURCE_CMD_STRICT },
244+
{ 'b', 198, "checkunique", &checkunique, SOURCE_CMD_STRICT },
243245
{ 'b', 197, "parent", &amcheck_parent, SOURCE_CMD_STRICT },
244246
/* delete options */
245247
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
@@ -596,6 +598,16 @@ main(int argc, char *argv[])
596598
instance_config.pgdata == NULL)
597599
elog(ERROR, "required parameter not specified: --instance");
598600

601+
/* Check checkdb command options consistency */
602+
if (backup_subcmd == CHECKDB_CMD &&
603+
!need_amcheck)
604+
{
605+
if (heapallindexed)
606+
elog(ERROR, "--heapallindexed can only be used with --amcheck option");
607+
if (checkunique)
608+
elog(ERROR, "--checkunique can only be used with --amcheck option");
609+
}
610+
599611
/* Usually checkdb for file logging requires log_directory
600612
* to be specified explicitly, but if backup_dir and instance name are provided,
601613
* checkdb can use the usual default values or values from config

Diff for: src/pg_probackup.h

+1
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@ extern ShowFormat show_format;
829829

830830
/* checkdb options */
831831
extern bool heapallindexed;
832+
extern bool checkunique;
832833
extern bool skip_block_validation;
833834

834835
/* current settings */

0 commit comments

Comments
 (0)