I spent some time trying to improve the amvalidate functions that were
committed in a rather crude state in 65c5fcd353a859da. Attached is a
very-much-WIP patch showing where I'm headed:
* Check operator and function signatures (argument and result types)
not only their strategy numbers.
* Apply more thorough checks for missing operators and support functions.
* Don't throw ERROR if avoidable, because doing it like that means you can
only identify one problem per run. Instead, print messages at INFO level
and make the amvalidate function return false if there are any complaints.
(A credible alternative would be to print the messages as WARNINGs, but
I think INFO is actually the right choice here, since the point of calling
amvalidate is to see those messages.)
* Make the messages more user-friendly by printing object names not just
OIDs.
I went through the amvalidate modules in the order they're shown in the
attached patch, and only the last (brinvalidate) is really fully
developed. I need to go back and bring the others up to snuff, including
getting down to just one copy of the support routines that I wrote.
(I'm thinking of dumping those into a new file access/index/amvalidate.c.)
Also, I think the identify_opfamily_groups() function I wrote for BRIN
will allow improvement of the other modules' cross-checks for missing
operators/functions, but I've not tried yet.
Also, after this is done some of the queries in opr_sanity.sql will be
redundant and removable, but I didn't do that here.
I'm posting this now just in case anyone has some comments, or quibbles
about the overall intent. In particular, if anyone has an idea for a more
thorough missing-objects check on BRIN opfamilies, I would like to hear
it. The fact that there are two kinds of opfamilies with rather different
internal consistency requirements is a real pain there, and the check
rules I have here are definitely the result of some trial and error.
Comments?
regards, tom lane
diff --git a/src/backend/access/nbtree/nbtvalidate.c b/src/backend/access/nbtree/nbtvalidate.c
index b814b54..2c03688 100644
*** a/src/backend/access/nbtree/nbtvalidate.c
--- b/src/backend/access/nbtree/nbtvalidate.c
***
*** 18,28
--- 18,37
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_opclass.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/syscache.h"
+ static bool check_func_signature(Oid funcid, Oid restype,
+ int nargs, Oid arg1type, Oid arg2type);
+ static bool check_opr_signature(Oid opno, Oid restype,
+ Oid lefttype, Oid righttype);
+
+
/*
* Validator for a btree opclass.
*
*** btvalidate(Oid opclassoid)
*** 77,90
HeapTuple proctup = >members[i]->tuple;
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
! /* Check that only allowed procedure numbers exist */
! if (procform->amprocnum != BTORDER_PROC &&
! procform->amprocnum != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree opfamily %u contains invalid support number %d for procedure %u",
! opfamilyoid,
! procform->amprocnum, procform->amproc)));
/* Remember functions that are specifically for the named opclass */
if (procform->amproclefttype == opcintype &&
--- 86,121
HeapTuple proctup = >members[i]->tuple;
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
! /* Check procedure numbers and function signatures */
! switch (procform->amprocnum)
! {
! case BTORDER_PROC:
! /* comparison func must match the opclass entry */
! if (!check_func_signature(procform->amproc, INT4OID, 2,
! procform->amproclefttype,
! procform->amprocrighttype))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree opfamily %u contains support procedure %u with wrong signature",
! opfamilyoid, procform->amproc)));
! break;
! case BTSORTSUPPORT_PROC:
! /* sortsupport always takes internal and returns void */
! if (!check_func_signature(procform->amproc, VOIDOID, 1,
! INTERNALOID, InvalidOid))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree opfamily %u contains support procedure %u with wrong signature",
! opfamilyoid, procform->amproc)));
! break;
! default:
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree opfamily %u contains invalid support number %d for procedure %u",
! opfamilyoid,
! procform->amprocnum, procform->amproc)));
! break;
! }
/* Remember functions that are specifically for the named opclass */
if (procform->amproclefttype == opcintype &&