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