On 07/30/2015 09:51 AM, Tom Lane wrote: > Joe Conway <m...@joeconway.com> writes: >> What about just TYPE then? > >> SELECT x::TYPE(some_expression) FROM ... >> SELECT CAST (x AS TYPE(some_expression)) FROM ...
> The main limitation of this patch is that it won't work for call sites > that pass pstate == NULL to LookupTypeName. There are a fair number > of them, some of which wouldn't care because they could never invoke > this notation anyway, but for others we'd need to do some work to cons > up a suitable pstate. Sorry it took so long for me to get back to this, but any reason the attached won't work? Joe -- Crunchy Data - http://crunchydata.com PostgreSQL Support for Secure Enterprises Consulting, Training, & Open Source Development
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 5b0d568..a1aba26 100644 *** a/src/backend/parser/parse_agg.c --- b/src/backend/parser/parse_agg.c *************** check_agglevels_and_constraints(ParseSta *** 485,490 **** --- 485,493 ---- err = _("grouping operations are not allowed in trigger WHEN conditions"); break; + case EXPR_KIND_TYPE: + /* okay */ + break; /* * There is intentionally no default: case here, so that the *************** transformWindowFuncCall(ParseState *psta *** 842,847 **** --- 845,853 ---- case EXPR_KIND_TRIGGER_WHEN: err = _("window functions are not allowed in trigger WHEN conditions"); break; + case EXPR_KIND_TYPE: + /* okay */ + break; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index fa77ef1..9f76ee6 100644 *** a/src/backend/parser/parse_expr.c --- b/src/backend/parser/parse_expr.c *************** transformSubLink(ParseState *pstate, Sub *** 1690,1695 **** --- 1690,1696 ---- case EXPR_KIND_OFFSET: case EXPR_KIND_RETURNING: case EXPR_KIND_VALUES: + case EXPR_KIND_TYPE: /* okay */ break; case EXPR_KIND_CHECK_CONSTRAINT: *************** ParseExprKindName(ParseExprKind exprKind *** 3225,3230 **** --- 3226,3233 ---- return "EXECUTE"; case EXPR_KIND_TRIGGER_WHEN: return "WHEN"; + case EXPR_KIND_TYPE: + return "TYPE"; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 6616639..19a2684 100644 *** a/src/backend/parser/parse_type.c --- b/src/backend/parser/parse_type.c *************** *** 19,25 **** --- 19,27 ---- #include "catalog/pg_type.h" #include "lib/stringinfo.h" #include "nodes/makefuncs.h" + #include "nodes/nodeFuncs.h" #include "parser/parser.h" + #include "parser/parse_expr.h" #include "parser/parse_type.h" #include "utils/array.h" #include "utils/builtins.h" *************** static int32 typenameTypeMod(ParseState *** 52,58 **** * found but is a shell, and there is typmod decoration, an error will be * thrown --- this is intentional. * ! * pstate is only used for error location info, and may be NULL. */ Type LookupTypeName(ParseState *pstate, const TypeName *typeName, --- 54,60 ---- * found but is a shell, and there is typmod decoration, an error will be * thrown --- this is intentional. * ! * In most cases pstate is only used for error location info, and may be NULL. */ Type LookupTypeName(ParseState *pstate, const TypeName *typeName, *************** LookupTypeName(ParseState *pstate, const *** 60,66 **** { Oid typoid; HeapTuple tup; ! int32 typmod; if (typeName->names == NIL) { --- 62,68 ---- { Oid typoid; HeapTuple tup; ! int32 typmod = -2; if (typeName->names == NIL) { *************** LookupTypeName(ParseState *pstate, const *** 143,148 **** --- 145,172 ---- format_type_be(typoid)))); } } + else if (list_length(typeName->typmods) == 1 && + list_length(typeName->names) == 1 && + strcmp(strVal(linitial(typeName->names)), "type") == 0) + { + /* TYPE(expression) notation */ + Node *typexpr = (Node *) linitial(typeName->typmods); + + /* If needed, create a dummy ParseState for transformExpr */ + if (pstate == NULL) + pstate = make_parsestate(NULL); + + typexpr = transformExpr(pstate, typexpr, EXPR_KIND_TYPE); + + /* We needn't bother assigning collations to the expr */ + /* We use the expression's type/typmod and then throw the expr away */ + typoid = exprType(typexpr); + typmod = exprTypmod(typexpr); + + /* If an array reference, return the array type instead */ + if (typeName->arrayBounds != NIL) + typoid = get_array_type(typoid); + } else { /* Normal reference to a type name */ *************** LookupTypeName(ParseState *pstate, const *** 192,198 **** if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for type %u", typoid); ! typmod = typenameTypeMod(pstate, typeName, (Type) tup); if (typmod_p) *typmod_p = typmod; --- 216,223 ---- if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for type %u", typoid); ! if (typmod == -2) ! typmod = typenameTypeMod(pstate, typeName, (Type) tup); if (typmod_p) *typmod_p = typmod; diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index 5249945..7e82af8 100644 *** a/src/include/parser/parse_node.h --- b/src/include/parser/parse_node.h *************** typedef enum ParseExprKind *** 64,70 **** EXPR_KIND_ALTER_COL_TRANSFORM, /* transform expr in ALTER COLUMN TYPE */ EXPR_KIND_EXECUTE_PARAMETER, /* parameter value in EXECUTE */ EXPR_KIND_TRIGGER_WHEN, /* WHEN condition in CREATE TRIGGER */ ! EXPR_KIND_POLICY /* USING or WITH CHECK expr in policy */ } ParseExprKind; --- 64,71 ---- EXPR_KIND_ALTER_COL_TRANSFORM, /* transform expr in ALTER COLUMN TYPE */ EXPR_KIND_EXECUTE_PARAMETER, /* parameter value in EXECUTE */ EXPR_KIND_TRIGGER_WHEN, /* WHEN condition in CREATE TRIGGER */ ! EXPR_KIND_POLICY, /* USING or WITH CHECK expr in policy */ ! EXPR_KIND_TYPE /* expr defining type cast */ } ParseExprKind;
signature.asc
Description: OpenPGP digital signature