Joe Conway <[email protected]> writes:
> What about just TYPE then?
> SELECT x::TYPE(some_expression) FROM ...
> SELECT CAST (x AS TYPE(some_expression)) FROM ...
Yeah, that would work. Quick-hack proof-of-concept patch attached.
Some usage examples in the regression database:
regression=# select pg_typeof(43::type(q1)) from int8_tbl;
pg_typeof
-----------
bigint
bigint
bigint
bigint
bigint
(5 rows)
regression=# select pg_typeof(43::type(q1/0.0)) from int8_tbl;
pg_typeof
-----------
numeric
numeric
numeric
numeric
numeric
(5 rows)
regression=# select pg_typeof(43::type(f1)) from point_tbl;
ERROR: cannot cast type integer to point
LINE 1: select pg_typeof(43::type(f1)) from point_tbl;
^
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.
regards, tom lane
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 6616639..d5d0f73 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,61 ----
* 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.
! * However, the TYPE(expression) syntax is not accepted when pstate is NULL.
*/
Type
LookupTypeName(ParseState *pstate, const TypeName *typeName,
*************** LookupTypeName(ParseState *pstate, const
*** 143,148 ****
--- 146,188 ----
format_type_be(typoid))));
}
}
+ else if (pstate != NULL &&
+ 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);
+
+ /* XXX should invent a new EXPR_KIND for this, likely */
+ typexpr = transformExpr(pstate, typexpr, EXPR_KIND_SELECT_TARGET);
+
+ /* 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);
+
+ /* If an array reference, return the array type instead */
+ if (typeName->arrayBounds != NIL)
+ typoid = get_array_type(typoid);
+
+ if (!OidIsValid(typoid))
+ {
+ if (typmod_p)
+ *typmod_p = -1;
+ return NULL;
+ }
+
+ if (typmod_p)
+ *typmod_p = exprTypmod(typexpr);
+
+ /* Duplicative, but I'm too lazy to refactor this function right now */
+ tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
+ if (!HeapTupleIsValid(tup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for type %u", typoid);
+
+ return (Type) tup;
+ }
else
{
/* Normal reference to a type name */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers