On 07/30/2015 09:51 AM, Tom Lane wrote: > Joe Conway <[email protected]> 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
