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

Reply via email to