Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Provide an error cursor for "can't subscript" error messages.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 11 Dec 2020 22:54:10 +0000 (17:54 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 11 Dec 2020 23:58:21 +0000 (18:58 -0500)
Commit c7aba7c14 didn't add this, but after more fooling with the
feature I feel that it'd be useful.  To make this possible, refactor
getSubscriptingRoutines() so that the caller is responsible for
throwing any error.  (In clauses.c, I just chose to make the
most conservative assumption rather than throwing an error.  We don't
expect failures there anyway really, so the code space for an error
message would be a poor investment.)

src/backend/executor/execExpr.c
src/backend/optimizer/util/clauses.c
src/backend/parser/parse_node.c
src/backend/utils/cache/lsyscache.c
src/test/regress/expected/arrays.out

index 0134ecc261e1345a1673140a06819466aa84cae6..5c3210a9ccaddf8d0c8d4db9cdba7ced1599c1b4 100644 (file)
@@ -2536,6 +2536,14 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
 
    /* Look up the subscripting support methods */
    sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
+   if (!sbsroutines)
+       ereport(ERROR,
+               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                errmsg("cannot subscript type %s because it does not support subscripting",
+                       format_type_be(sbsref->refcontainertype)),
+                state->parent ?
+                executor_errposition(state->parent->state,
+                                     exprLocation((Node *) sbsref)) : 0));
 
    /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
    sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
index e3a81a7a02a51e897cda7e96c73797eb0b119705..8f5cbf99f43e01c0b9ea26490dc0ad8d58f84d14 100644 (file)
@@ -848,7 +848,7 @@ contain_nonstrict_functions_walker(Node *node, void *context)
            return true;
        /* Otherwise we must look up the subscripting support methods */
        sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
-       if (!sbsroutines->fetch_strict)
+       if (!(sbsroutines && sbsroutines->fetch_strict))
            return true;
        /* else fall through to check args */
    }
@@ -1144,7 +1144,8 @@ contain_leaked_vars_walker(Node *node, void *context)
                /* Consult the subscripting support method info */
                sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype,
                                                      NULL);
-               if (!(sbsref->refassgnexpr != NULL ?
+               if (!sbsroutines ||
+                   !(sbsref->refassgnexpr != NULL ?
                      sbsroutines->store_leakproof :
                      sbsroutines->fetch_leakproof))
                {
index e90f6c9d0106b60873f77b42dd9118bc1572bf30..3e20dfff2e250dc04abbb6163c67d818e3ed5682 100644 (file)
@@ -271,6 +271,12 @@ transformContainerSubscripts(ParseState *pstate,
     * functions and typelem.
     */
    sbsroutines = getSubscriptingRoutines(containerType, &elementType);
+   if (!sbsroutines)
+       ereport(ERROR,
+               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                errmsg("cannot subscript type %s because it does not support subscripting",
+                       format_type_be(containerType)),
+                parser_errposition(pstate, exprLocation(containerBase))));
 
    /*
     * Detect whether any of the indirection items are slice specifiers.
index 7dd4945446223248fdb913388437b928b7b9d82b..204bcd03c0b3b0709a999e4a286492226dc59b86 100644 (file)
@@ -3031,7 +3031,7 @@ get_typsubscript(Oid typid, Oid *typelemp)
  * getSubscriptingRoutines
  *
  *     Given the type OID, fetch the type's subscripting methods struct.
- *     Fail if type is not subscriptable.
+ *     Return NULL if type is not subscriptable.
  *
  * If typelemp isn't NULL, we also store the type's typelem value there.
  * This saves some callers an extra catalog lookup.
@@ -3042,10 +3042,7 @@ getSubscriptingRoutines(Oid typid, Oid *typelemp)
    RegProcedure typsubscript = get_typsubscript(typid, typelemp);
 
    if (!OidIsValid(typsubscript))
-       ereport(ERROR,
-               (errcode(ERRCODE_DATATYPE_MISMATCH),
-                errmsg("cannot subscript type %s because it does not support subscripting",
-                       format_type_be(typid))));
+       return NULL;
 
    return (const struct SubscriptRoutines *)
        DatumGetPointer(OidFunctionCall0(typsubscript));
index 0254fac801178b6b117c880457d0344457a0008b..8bc7721e7d5db9c0ad7785c08116f53351a8558b 100644 (file)
@@ -238,6 +238,8 @@ ERROR:  array subscript in assignment must not be null
 -- Un-subscriptable type
 SELECT (now())[1];
 ERROR:  cannot subscript type timestamp with time zone because it does not support subscripting
+LINE 1: SELECT (now())[1];
+                ^
 -- test slices with empty lower and/or upper index
 CREATE TEMP TABLE arrtest_s (
   a       int2[],