@@ -83,6 +83,7 @@ typedef struct pg_indexEntry
83
83
char *name;
84
84
char *namespace;
85
85
bool heapallindexed_is_supported;
86
+ bool checkunique_is_supported;
86
87
/* schema where amcheck extension is located */
87
88
char *amcheck_nspname;
88
89
/* lock for synchronization of parallel threads */
@@ -351,10 +352,14 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
351
352
{
352
353
PGresult *res;
353
354
char *amcheck_nspname = NULL;
355
+ char *amcheck_extname = NULL;
356
+ char *amcheck_extversion = NULL;
354
357
int i;
355
358
bool heapallindexed_is_supported = false;
359
+ bool checkunique_is_supported = false;
356
360
parray *index_list = NULL;
357
361
362
+ /* Check amcheck extension version */
358
363
res = pgut_execute(db_conn, "SELECT "
359
364
"extname, nspname, extversion "
360
365
"FROM pg_catalog.pg_namespace n "
@@ -379,24 +384,68 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
379
384
return NULL;
380
385
}
381
386
387
+ amcheck_extname = pgut_malloc(strlen(PQgetvalue(res, 0, 0)) + 1);
388
+ strcpy(amcheck_extname, PQgetvalue(res, 0, 0));
382
389
amcheck_nspname = pgut_malloc(strlen(PQgetvalue(res, 0, 1)) + 1);
383
390
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);
384
394
385
395
/* 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)
388
399
heapallindexed_is_supported = true;
389
400
390
401
elog(INFO, "Amchecking database '%s' using extension '%s' "
391
402
"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 );
394
405
395
406
if (!heapallindexed_is_supported && heapallindexed)
396
407
elog(WARNING, "Extension '%s' version %s in schema '%s'"
397
408
"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);
400
449
401
450
/*
402
451
* In order to avoid duplicates, select global indexes
@@ -453,6 +502,7 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
453
502
strcpy(ind->namespace, namespace); /* enough buffer size guaranteed */
454
503
455
504
ind->heapallindexed_is_supported = heapallindexed_is_supported;
505
+ ind->checkunique_is_supported = checkunique_is_supported;
456
506
ind->amcheck_nspname = pgut_malloc(strlen(amcheck_nspname) + 1);
457
507
strcpy(ind->amcheck_nspname, amcheck_nspname);
458
508
pg_atomic_clear_flag(&ind->lock);
@@ -464,6 +514,9 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
464
514
}
465
515
466
516
PQclear(res);
517
+ free(amcheck_extversion);
518
+ free(amcheck_nspname);
519
+ free(amcheck_extname);
467
520
468
521
return index_list;
469
522
}
@@ -473,46 +526,54 @@ static bool
473
526
amcheck_one_index(check_indexes_arg *arguments,
474
527
pg_indexEntry *ind)
475
528
{
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;
478
537
char *query = NULL;
479
538
480
- params[0] = palloc(64);
539
+ if (interrupted)
540
+ elog(ERROR, "Interrupted");
481
541
542
+ #define INDEXRELID 0
543
+ #define HEAPALLINDEXED 1
544
+ #define CHECKUNIQUE 2
482
545
/* first argument is index oid */
483
- sprintf(params[0], "%u", ind->indexrelid);
546
+ params[INDEXRELID] = palloc(64);
547
+ sprintf(params[INDEXRELID], "%u", ind->indexrelid);
484
548
/* 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
486
554
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 );
494
558
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);
503
565
504
- res = pgut_execute_parallel(arguments->conn_arg.conn,
566
+ res = pgut_execute_parallel(arguments->conn_arg.conn,
505
567
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);
508
569
509
570
if (PQresultStatus(res) != PGRES_TUPLES_OK)
510
571
{
511
572
elog(WARNING, "Thread [%d]. Amcheck failed in database '%s' for index: '%s.%s': %s",
512
573
arguments->thread_num, arguments->conn_opt.pgdatabase,
513
574
ind->namespace, ind->name, PQresultErrorMessage(res));
514
575
515
- pfree(params[0 ]);
576
+ pfree(params[INDEXRELID ]);
516
577
pfree(query);
517
578
PQclear(res);
518
579
return false;
@@ -522,7 +583,8 @@ amcheck_one_index(check_indexes_arg *arguments,
522
583
arguments->thread_num,
523
584
arguments->conn_opt.pgdatabase, ind->namespace, ind->name);
524
585
525
- pfree(params[0]);
586
+ pfree(params[INDEXRELID]);
587
+ #undef INDEXRELID
526
588
pfree(query);
527
589
PQclear(res);
528
590
return true;
0 commit comments