aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_coerce.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-10-05 19:11:39 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-10-05 19:11:39 +0000
commit05e3d0ee8666b74f11ffad16f46e372459d6e53e (patch)
treeb273892bfda60f6bad315e84aaa2e9826e226931 /src/backend/parser/parse_coerce.c
parent5292637f52c6db8a22f99177f228273cb69fc510 (diff)
downloadpostgresql-05e3d0ee8666b74f11ffad16f46e372459d6e53e.tar.gz
postgresql-05e3d0ee8666b74f11ffad16f46e372459d6e53e.zip
Reimplementation of UNION/INTERSECT/EXCEPT. INTERSECT/EXCEPT now meet the
SQL92 semantics, including support for ALL option. All three can be used in subqueries and views. DISTINCT and ORDER BY work now in views, too. This rewrite fixes many problems with cross-datatype UNIONs and INSERT/SELECT where the SELECT yields different datatypes than the INSERT needs. I did that by making UNION subqueries and SELECT in INSERT be treated like subselects-in-FROM, thereby allowing an extra level of targetlist where the datatype conversions can be inserted safely. INITDB NEEDED!
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r--src/backend/parser/parse_coerce.c96
1 files changed, 95 insertions, 1 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index bd098fb6c68..ef13d67cf1c 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.46 2000/07/30 22:13:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.47 2000/10/05 19:11:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -314,6 +314,100 @@ coerce_type_typmod(ParseState *pstate, Node *node,
}
+/* select_common_type()
+ * Determine the common supertype of a list of input expression types.
+ * This is used for determining the output type of CASE and UNION
+ * constructs.
+ *
+ * typeids is a nonempty integer list of type OIDs. Note that earlier items
+ * in the list will be preferred if there is doubt.
+ * 'context' is a phrase to use in the error message if we fail to select
+ * a usable type.
+ *
+ * XXX this code is WRONG, since (for example) given the input (int4,int8)
+ * it will select int4, whereas according to SQL92 clause 9.3 the correct
+ * answer is clearly int8. To fix this we need a notion of a promotion
+ * hierarchy within type categories --- something more complete than
+ * just a single preferred type.
+ */
+Oid
+select_common_type(List *typeids, const char *context)
+{
+ Oid ptype;
+ CATEGORY pcategory;
+ List *l;
+
+ Assert(typeids != NIL);
+ ptype = (Oid) lfirsti(typeids);
+ pcategory = TypeCategory(ptype);
+ foreach(l, lnext(typeids))
+ {
+ Oid ntype = (Oid) lfirsti(l);
+
+ /* move on to next one if no new information... */
+ if (ntype && (ntype != UNKNOWNOID) && (ntype != ptype))
+ {
+ if (!ptype || ptype == UNKNOWNOID)
+ {
+ /* so far, only nulls so take anything... */
+ ptype = ntype;
+ pcategory = TypeCategory(ptype);
+ }
+ else if (TypeCategory(ntype) != pcategory)
+ {
+ /*
+ * both types in different categories? then
+ * not much hope...
+ */
+ elog(ERROR, "%s types \"%s\" and \"%s\" not matched",
+ context, typeidTypeName(ptype), typeidTypeName(ntype));
+ }
+ else if (IsPreferredType(pcategory, ntype)
+ && can_coerce_type(1, &ptype, &ntype))
+ {
+ /*
+ * new one is preferred and can convert? then
+ * take it...
+ */
+ ptype = ntype;
+ pcategory = TypeCategory(ptype);
+ }
+ }
+ }
+ return ptype;
+}
+
+/* coerce_to_common_type()
+ * Coerce an expression to the given type.
+ *
+ * This is used following select_common_type() to coerce the individual
+ * expressions to the desired type. 'context' is a phrase to use in the
+ * error message if we fail to coerce.
+ *
+ * NOTE: pstate may be NULL.
+ */
+Node *
+coerce_to_common_type(ParseState *pstate, Node *node,
+ Oid targetTypeId,
+ const char *context)
+{
+ Oid inputTypeId = exprType(node);
+
+ if (inputTypeId == targetTypeId)
+ return node; /* no work */
+ if (can_coerce_type(1, &inputTypeId, &targetTypeId))
+ {
+ node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1);
+ }
+ else
+ {
+ elog(ERROR, "%s unable to convert to type \"%s\"",
+ context, typeidTypeName(targetTypeId));
+ }
+ return node;
+}
+
+
/* TypeCategory()
* Assign a category to the specified OID.
*/