@@ -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
473526amcheck_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;
0 commit comments