expression must be of Boolean type.
-
-
Some comparison-related functions are also available, as shown in
linkend="functions-comparison-func-table"/>.
S097 Array element assignment NO
S098 ARRAY_AGG YES
S111 ONLY in query expressions YES
-S151 Type predicate NO
+S151 Type predicate NO see pg_typeof()
S161 Subtype treatment NO
S162 Subtype treatment for references NO
S201 SQL-invoked routines on arrays YES
appendStringInfoString(str, " NULLIF ");
WRITE_NODE_FIELD(name);
break;
- case AEXPR_OF:
- appendStringInfoString(str, " OF ");
- WRITE_NODE_FIELD(name);
- break;
case AEXPR_IN:
appendStringInfoString(str, " IN ");
WRITE_NODE_FIELD(name);
{
$$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2);
}
- | a_expr IS OF '(' type_list ')' %prec IS
- {
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
- }
- | a_expr IS NOT OF '(' type_list ')' %prec IS
- {
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
- }
| a_expr BETWEEN opt_asymmetric b_expr AND a_expr %prec BETWEEN
{
$$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN,
{
$$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2);
}
- | b_expr IS OF '(' type_list ')' %prec IS
- {
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
- }
- | b_expr IS NOT OF '(' type_list ')' %prec IS
- {
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
- }
| b_expr IS DOCUMENT_P %prec IS
{
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
static Node *transformAExprOpAll(ParseState *pstate, A_Expr *a);
static Node *transformAExprDistinct(ParseState *pstate, A_Expr *a);
static Node *transformAExprNullIf(ParseState *pstate, A_Expr *a);
-static Node *transformAExprOf(ParseState *pstate, A_Expr *a);
static Node *transformAExprIn(ParseState *pstate, A_Expr *a);
static Node *transformAExprBetween(ParseState *pstate, A_Expr *a);
static Node *transformBoolExpr(ParseState *pstate, BoolExpr *a);
case AEXPR_NULLIF:
result = transformAExprNullIf(pstate, a);
break;
- case AEXPR_OF:
- result = transformAExprOf(pstate, a);
- break;
case AEXPR_IN:
result = transformAExprIn(pstate, a);
break;
return (Node *) result;
}
-/*
- * Checking an expression for match to a list of type names. Will result
- * in a boolean constant node.
- */
-static Node *
-transformAExprOf(ParseState *pstate, A_Expr *a)
-{
- Node *lexpr = a->lexpr;
- Const *result;
- ListCell *telem;
- Oid ltype,
- rtype;
- bool matched = false;
-
- if (operator_precedence_warning)
- emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_IS, "IS",
- lexpr, NULL,
- a->location);
-
- lexpr = transformExprRecurse(pstate, lexpr);
-
- ltype = exprType(lexpr);
- foreach(telem, (List *) a->rexpr)
- {
- rtype = typenameTypeId(pstate, lfirst(telem));
- matched = (rtype == ltype);
- if (matched)
- break;
- }
-
- /*
- * We have two forms: equals or not equals. Flip the sense of the result
- * for not equals.
- */
- if (strcmp(strVal(linitial(a->name)), "<>") == 0)
- matched = (!matched);
-
- result = (Const *) makeBoolConst(matched, false);
-
- /* Make the result have the original input's parse location */
- result->location = exprLocation((Node *) a);
-
- return (Node *) result;
-}
-
static Node *
transformAExprIn(ParseState *pstate, A_Expr *a)
{
*nodename = "IS";
group = PREC_GROUP_INFIX_IS;
}
- else if (aexpr->kind == AEXPR_OF)
- {
- *nodename = "IS";
- group = PREC_GROUP_POSTFIX_IS;
- }
else if (aexpr->kind == AEXPR_IN)
{
*nodename = "IN";
AEXPR_DISTINCT, /* IS DISTINCT FROM - name must be "=" */
AEXPR_NOT_DISTINCT, /* IS NOT DISTINCT FROM - name must be "=" */
AEXPR_NULLIF, /* NULLIF - name must be "=" */
- AEXPR_OF, /* IS [NOT] OF - name must be "=" or "<>" */
AEXPR_IN, /* [NOT] IN - name must be "=" or "<>" */
AEXPR_LIKE, /* [NOT] LIKE - name must be "~~" or "!~~" */
AEXPR_ILIKE, /* [NOT] ILIKE - name must be "~~*" or "!~~*" */
{1,2,3}
(1 row)
-SELECT ARRAY[1,2,3]::text[]::int[]::float8[] is of (float8[]) as "TRUE";
- TRUE
-------
- t
+SELECT pg_typeof(ARRAY[1,2,3]::text[]::int[]::float8[]) AS "double precision[]";
+ double precision[]
+--------------------
+ double precision[]
(1 row)
SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] AS "{{a,bc},{def,hijk}}";
{{a,bc},{def,hijk}}
(1 row)
-SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] is of (varchar[]) as "TRUE";
- TRUE
-------
- t
+SELECT pg_typeof(ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[]) AS "character varying[]";
+ character varying[]
+---------------------
+ character varying[]
(1 row)
SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}";
(3 rows)
-- check that union/case/coalesce type resolution handles domains properly
-select coalesce(4::domainint4, 7) is of (int4) as t;
- t
----
- t
-(1 row)
-
-select coalesce(4::domainint4, 7) is of (domainint4) as f;
- f
----
- f
+select pg_typeof(coalesce(4::domainint4, 7));
+ pg_typeof
+-----------
+ integer
(1 row)
-select coalesce(4::domainint4, 7::domainint4) is of (domainint4) as t;
- t
----
- t
+select pg_typeof(coalesce(4::domainint4, 7::domainint4));
+ pg_typeof
+------------
+ domainint4
(1 row)
drop table basictest;
-- Test behavior with an unknown-type literal in the WITH
WITH q AS (SELECT 'foo' AS x)
-SELECT x, x IS OF (text) AS is_text FROM q;
- x | is_text
------+---------
- foo | t
+SELECT x, pg_typeof(x) FROM q;
+ x | pg_typeof
+-----+-----------
+ foo | text
(1 row)
WITH RECURSIVE t(n) AS (
UNION ALL
SELECT n || ' bar' FROM t WHERE length(n) < 20
)
-SELECT n, n IS OF (text) AS is_text FROM t;
- n | is_text
--------------------------+---------
- foo | t
- foo bar | t
- foo bar bar | t
- foo bar bar bar | t
- foo bar bar bar bar | t
- foo bar bar bar bar bar | t
+SELECT n, pg_typeof(n) FROM t;
+ n | pg_typeof
+-------------------------+-----------
+ foo | text
+ foo bar | text
+ foo bar bar | text
+ foo bar bar bar | text
+ foo bar bar bar bar | text
+ foo bar bar bar bar bar | text
(6 rows)
-- In a perfect world, this would work and resolve the literal as int ...
UNION ALL
SELECT n+1 FROM t WHERE n < 10
)
-SELECT n, n IS OF (int) AS is_int FROM t;
+SELECT n, pg_typeof(n) FROM t;
ERROR: operator does not exist: text + integer
LINE 4: SELECT n+1 FROM t WHERE n < 10
^
-- array casts
SELECT ARRAY[1,2,3]::text[]::int[]::float8[] AS "{1,2,3}";
-SELECT ARRAY[1,2,3]::text[]::int[]::float8[] is of (float8[]) as "TRUE";
+SELECT pg_typeof(ARRAY[1,2,3]::text[]::int[]::float8[]) AS "double precision[]";
SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] AS "{{a,bc},{def,hijk}}";
-SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] is of (varchar[]) as "TRUE";
+SELECT pg_typeof(ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[]) AS "character varying[]";
SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}";
SELECT NULL::text[]::int[] AS "NULL";
from basictest;
-- check that union/case/coalesce type resolution handles domains properly
-select coalesce(4::domainint4, 7) is of (int4) as t;
-select coalesce(4::domainint4, 7) is of (domainint4) as f;
-select coalesce(4::domainint4, 7::domainint4) is of (domainint4) as t;
+select pg_typeof(coalesce(4::domainint4, 7));
+select pg_typeof(coalesce(4::domainint4, 7::domainint4));
drop table basictest;
drop domain domainvarchar restrict;
-- Test behavior with an unknown-type literal in the WITH
WITH q AS (SELECT 'foo' AS x)
-SELECT x, x IS OF (text) AS is_text FROM q;
+SELECT x, pg_typeof(x) FROM q;
WITH RECURSIVE t(n) AS (
SELECT 'foo'
UNION ALL
SELECT n || ' bar' FROM t WHERE length(n) < 20
)
-SELECT n, n IS OF (text) AS is_text FROM t;
+SELECT n, pg_typeof(n) FROM t;
-- In a perfect world, this would work and resolve the literal as int ...
-- but for now, we have to be content with resolving to text too soon.
UNION ALL
SELECT n+1 FROM t WHERE n < 10
)
-SELECT n, n IS OF (int) AS is_int FROM t;
+SELECT n, pg_typeof(n) FROM t;
--
-- Some examples with a tree