@@ -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;