Hi,
In the past I've found the error message in cases such as this somewhat
less helpful than it could be:
=# CREATE TABLE qqq (a int);
=# CREATE UNIQUE INDEX IF NOT EXISTS qqq_a_idx ON qqq(a);
=# ALTER TABLE qqq ALTER COLUMN a TYPE json USING NULL;
ERROR: data type json has no default operator class for access method
"btree"
HINT: You must specify an operator class for the index or define a
default operator class for the data type.
The attached patch adds a CONTEXT line to index and constraint rebuilds,
e.g:
CONTEXT: while rebuilding index qqq_a_idx
Any feedback welcome.
.m
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 82,87 ****
--- 82,88 ----
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
+ #include "utils/elog.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
***************
*** 309,314 **** static void ATController(AlterTableStmt *parsetree,
--- 310,316 ----
Relation rel, List *cmds, bool recurse, LOCKMODE
lockmode);
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
bool recurse, bool recursing, LOCKMODE lockmode);
+ static void ATRewriteSubcommandErrorCallback(void *arg);
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
AlterTableCmd *cmd, LOCKMODE lockmode);
***************
*** 3373,3378 **** ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
--- 3375,3399 ----
tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
}
+ static void
+ ATRewriteSubcommandErrorCallback(void *arg)
+ {
+ AlterTableCmd *subcmd = (AlterTableCmd *) arg;
+
+ switch (subcmd->subtype)
+ {
+ case AT_ReAddIndex:
+ errcontext("while rebuilding index %s", subcmd->name);
+ break;
+ case AT_ReAddConstraint:
+ errcontext("while rebuilding constraint %s",
subcmd->name);
+ break;
+ default:
+ /* keep compiler quiet */
+ (void) 0;
+ }
+ }
+
/*
* ATRewriteCatalogs
*
***************
*** 3402,3407 **** ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
--- 3423,3429 ----
List *subcmds = tab->subcmds[pass];
Relation rel;
ListCell *lcmd;
+ ErrorContextCallback errcallback;
if (subcmds == NIL)
continue;
***************
*** 3411,3418 **** ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
*/
rel = relation_open(tab->relid, NoLock);
foreach(lcmd, subcmds)
! ATExecCmd(wqueue, tab, rel, (AlterTableCmd *)
lfirst(lcmd), lockmode);
/*
* After the ALTER TYPE pass, do cleanup work (this is
not done in
--- 3433,3451 ----
*/
rel = relation_open(tab->relid, NoLock);
+ errcallback.callback = ATRewriteSubcommandErrorCallback;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
+
foreach(lcmd, subcmds)
! {
! AlterTableCmd *subcmd = (AlterTableCmd *)
lfirst(lcmd);
!
! errcallback.arg = subcmd;
! ATExecCmd(wqueue, tab, rel, subcmd, lockmode);
! }
!
! error_context_stack = errcallback.previous;
/*
* After the ALTER TYPE pass, do cleanup work (this is
not done in
***************
*** 8682,8687 **** ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
char *cmd,
--- 8715,8721 ----
newcmd = makeNode(AlterTableCmd);
newcmd->subtype = AT_ReAddIndex;
+ newcmd->name = stmt->idxname;
newcmd->def = (Node *) stmt;
tab->subcmds[AT_PASS_OLD_INDEX] =
lappend(tab->subcmds[AT_PASS_OLD_INDEX],
newcmd);
***************
*** 8712,8717 **** ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
char *cmd,
--- 8746,8752 ----
RelationRelationId, 0);
cmd->subtype = AT_ReAddIndex;
+ cmd->name = indstmt->idxname;
tab->subcmds[AT_PASS_OLD_INDEX] =
lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
***************
*** 8734,8739 **** ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
char *cmd,
--- 8769,8775 ----
!rewrite && tab->rewrite == 0)
TryReuseForeignKey(oldId, con);
cmd->subtype = AT_ReAddConstraint;
+ cmd->name = con->conname;
tab->subcmds[AT_PASS_OLD_CONSTR] =
lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
***************
*** 1737,1742 **** alter table anothertab alter column atcol1 type boolean
--- 1737,1743 ----
using case when atcol1 % 2 = 0 then true else false end; -- fails
ERROR: operator does not exist: boolean <= integer
HINT: No operator matches the given name and argument type(s). You might
need to add explicit type casts.
+ CONTEXT: while rebuilding constraint anothertab_chk
alter table anothertab drop constraint anothertab_chk;
alter table anothertab drop constraint anothertab_chk; -- fails
ERROR: constraint "anothertab_chk" of relation "anothertab" does not exist
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers