@@ -83,6 +83,7 @@ typedef struct pg_indexEntry
8383char * name ;
8484char * namespace ;
8585bool heapallindexed_is_supported ;
86+ bool checkunique_is_supported ;
8687/* schema where amcheck extension is located */
8788char * 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{
352353PGresult * res ;
353354char * amcheck_nspname = NULL ;
355+ char * amcheck_extname = NULL ;
356+ char * amcheck_extversion = NULL ;
354357int i ;
355358bool heapallindexed_is_supported = false;
359+ bool checkunique_is_supported = false;
356360parray * index_list = NULL ;
357361
362+ /* Check amcheck extension version */
358363res = 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,
379384return NULL ;
380385}
381386
387+ amcheck_extname = pgut_malloc (strlen (PQgetvalue (res ,0 ,0 ))+ 1 );
388+ strcpy (amcheck_extname ,PQgetvalue (res ,0 ,0 ));
382389amcheck_nspname = pgut_malloc (strlen (PQgetvalue (res ,0 ,1 ))+ 1 );
383390strcpy (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 )
388399heapallindexed_is_supported = true;
389400
390401elog (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
395406if (!heapallindexed_is_supported && heapallindexed )
396407elog (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,
453502strcpy (ind -> namespace ,namespace );/* enough buffer size guaranteed */
454503
455504ind -> heapallindexed_is_supported = heapallindexed_is_supported ;
505+ ind -> checkunique_is_supported = checkunique_is_supported ;
456506ind -> amcheck_nspname = pgut_malloc (strlen (amcheck_nspname )+ 1 );
457507strcpy (ind -> amcheck_nspname ,amcheck_nspname );
458508pg_atomic_clear_flag (& ind -> lock );
@@ -464,6 +514,9 @@ get_index_list(const char *dbname, bool first_db_with_amcheck,
464514}
465515
466516PQclear (res );
517+ free (amcheck_extversion );
518+ free (amcheck_nspname );
519+ free (amcheck_extname );
467520
468521return index_list ;
469522}
@@ -473,46 +526,54 @@ static bool
473526amcheck_one_index (check_indexes_arg * arguments ,
474527pg_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 ;
478537char * 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 ,
505567arguments -> 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
509570if (PQresultStatus (res )!= PGRES_TUPLES_OK )
510571{
511572elog (WARNING ,"Thread [%d]. Amcheck failed in database '%s' for index: '%s.%s': %s" ,
512573arguments -> thread_num ,arguments -> conn_opt .pgdatabase ,
513574ind -> namespace ,ind -> name ,PQresultErrorMessage (res ));
514575
515- pfree (params [0 ]);
576+ pfree (params [INDEXRELID ]);
516577pfree (query );
517578PQclear (res );
518579return false;
@@ -522,7 +583,8 @@ amcheck_one_index(check_indexes_arg *arguments,
522583arguments -> thread_num ,
523584arguments -> conn_opt .pgdatabase ,ind -> namespace ,ind -> name );
524585
525- pfree (params [0 ]);
586+ pfree (params [INDEXRELID ]);
587+ #undef INDEXRELID
526588pfree (query );
527589PQclear (res );
528590return true;