mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Implement precision support for timestamp and time, both with and without
time zones. SQL99 spec requires a default of zero (round to seconds) which is set in gram.y as typmod is set in the parse tree. We *could* change to a default of either 6 (for internal compatibility with previous versions) or 2 (for external compatibility with previous versions). Evaluate entries in pg_proc wrt the iscachable attribute for timestamp and other date/time types. Try to recognize cases where side effects like the current time zone setting may have an effect on results to decide whether something is cachable or not.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.198 2001/09/07 21:57:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.199 2001/10/03 05:29:12 thomas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -510,11 +510,10 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
* No user-supplied value, so add a targetentry with DEFAULT
|
||||
* expr and correct data for the target column.
|
||||
*/
|
||||
te = makeTargetEntry(
|
||||
makeResdom(attrno,
|
||||
te = makeTargetEntry(makeResdom(attrno,
|
||||
thisatt->atttypid,
|
||||
thisatt->atttypmod,
|
||||
pstrdup(NameStr(thisatt->attname)),
|
||||
pstrdup(NameStr(thisatt->attname)),
|
||||
false),
|
||||
stringToNode(defval[ndef].adbin));
|
||||
qry->targetList = lappend(qry->targetList, te);
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.256 2001/10/02 21:39:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.257 2001/10/03 05:29:12 thomas Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -4075,10 +4075,10 @@ opt_numeric: '(' Iconst ',' Iconst ')'
|
||||
{
|
||||
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
|
||||
elog(ERROR,"NUMERIC precision %d must be beween 1 and %d",
|
||||
$2, NUMERIC_MAX_PRECISION);
|
||||
$2, NUMERIC_MAX_PRECISION);
|
||||
if ($4 < 0 || $4 > $2)
|
||||
elog(ERROR,"NUMERIC scale %d must be between 0 and precision %d",
|
||||
$4,$2);
|
||||
$4,$2);
|
||||
|
||||
$$ = (($2 << 16) | $4) + VARHDRSZ;
|
||||
}
|
||||
@@ -4086,7 +4086,7 @@ opt_numeric: '(' Iconst ',' Iconst ')'
|
||||
{
|
||||
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
|
||||
elog(ERROR,"NUMERIC precision %d must be beween 1 and %d",
|
||||
$2, NUMERIC_MAX_PRECISION);
|
||||
$2, NUMERIC_MAX_PRECISION);
|
||||
|
||||
$$ = ($2 << 16) + VARHDRSZ;
|
||||
}
|
||||
@@ -4163,7 +4163,7 @@ bit: BIT opt_varying
|
||||
* SQL92 character data types
|
||||
* The following implements CHAR() and VARCHAR().
|
||||
*/
|
||||
Character: character '(' Iconst ')'
|
||||
Character: character '(' Iconst ')' opt_charset
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
@@ -4180,34 +4180,37 @@ Character: character '(' Iconst ')'
|
||||
* truncate where necessary)
|
||||
*/
|
||||
$$->typmod = VARHDRSZ + $3;
|
||||
|
||||
if (($5 != NULL) && (strcmp($5, "sql_text") != 0)) {
|
||||
char *type;
|
||||
|
||||
type = palloc(strlen($$->name) + 1 + strlen($5) + 1);
|
||||
strcpy(type, $$->name);
|
||||
strcat(type, "_");
|
||||
strcat(type, $5);
|
||||
$$->name = xlateSqlType(type);
|
||||
};
|
||||
}
|
||||
| character
|
||||
| character opt_charset
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
/* default length, if needed, will be inserted later */
|
||||
$$->typmod = -1;
|
||||
|
||||
if (($2 != NULL) && (strcmp($2, "sql_text") != 0)) {
|
||||
char *type;
|
||||
|
||||
type = palloc(strlen($$->name) + 1 + strlen($2) + 1);
|
||||
strcpy(type, $$->name);
|
||||
strcat(type, "_");
|
||||
strcat(type, $2);
|
||||
$$->name = xlateSqlType(type);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
character: CHARACTER opt_varying opt_charset
|
||||
{
|
||||
char *type, *c;
|
||||
if (($3 == NULL) || (strcmp($3, "sql_text") == 0)) {
|
||||
if ($2) type = xlateSqlType("varchar");
|
||||
else type = xlateSqlType("bpchar");
|
||||
} else {
|
||||
if ($2) {
|
||||
c = palloc(strlen("var") + strlen($3) + 1);
|
||||
strcpy(c, "var");
|
||||
strcat(c, $3);
|
||||
type = xlateSqlType(c);
|
||||
} else {
|
||||
type = xlateSqlType($3);
|
||||
}
|
||||
};
|
||||
$$ = type;
|
||||
}
|
||||
character: CHARACTER opt_varying { $$ = xlateSqlType($2 ? "varchar": "bpchar"); }
|
||||
| CHAR opt_varying { $$ = xlateSqlType($2 ? "varchar": "bpchar"); }
|
||||
| VARCHAR { $$ = xlateSqlType("varchar"); }
|
||||
| NATIONAL CHARACTER opt_varying { $$ = xlateSqlType($3 ? "varchar": "bpchar"); }
|
||||
@@ -4233,6 +4236,22 @@ ConstDatetime: datetime
|
||||
$$->name = xlateSqlType($1);
|
||||
$$->typmod = -1;
|
||||
}
|
||||
| TIMESTAMP '(' Iconst ')' opt_timezone_x
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
if ($5)
|
||||
$$->name = xlateSqlType("timestamptz");
|
||||
else
|
||||
$$->name = xlateSqlType("timestamp");
|
||||
/* XXX the timezone field seems to be unused
|
||||
* - thomas 2001-09-06
|
||||
*/
|
||||
$$->timezone = $5;
|
||||
if (($3 < 0) || ($3 > 13))
|
||||
elog(ERROR,"TIMESTAMP %s precision %d must be beween 0 and %d",
|
||||
($5? " WITH TIME ZONE": ""), 0, 13);
|
||||
$$->typmod = $3;
|
||||
}
|
||||
| TIMESTAMP opt_timezone_x
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
@@ -4244,7 +4263,19 @@ ConstDatetime: datetime
|
||||
* - thomas 2001-09-06
|
||||
*/
|
||||
$$->timezone = $2;
|
||||
$$->typmod = -1;
|
||||
$$->typmod = 0;
|
||||
}
|
||||
| TIME '(' Iconst ')' opt_timezone
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
if ($5)
|
||||
$$->name = xlateSqlType("timetz");
|
||||
else
|
||||
$$->name = xlateSqlType("time");
|
||||
if (($3 < 0) || ($3 > 13))
|
||||
elog(ERROR,"TIME %s precision %d must be beween 0 and %d",
|
||||
($5? " WITH TIME ZONE": ""), 0, 13);
|
||||
$$->typmod = $3;
|
||||
}
|
||||
| TIME opt_timezone
|
||||
{
|
||||
@@ -4253,7 +4284,10 @@ ConstDatetime: datetime
|
||||
$$->name = xlateSqlType("timetz");
|
||||
else
|
||||
$$->name = xlateSqlType("time");
|
||||
$$->typmod = -1;
|
||||
/* SQL99 specified a default precision of zero.
|
||||
* - thomas 2001-09-30
|
||||
*/
|
||||
$$->typmod = 0;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -5586,8 +5620,6 @@ ColId: IDENT { $$ = $1; }
|
||||
| NATIONAL { $$ = "national"; }
|
||||
| NONE { $$ = "none"; }
|
||||
| PATH_P { $$ = "path"; }
|
||||
| TIME { $$ = "time"; }
|
||||
| TIMESTAMP { $$ = "timestamp"; }
|
||||
;
|
||||
|
||||
/* Parser tokens to be used as identifiers.
|
||||
@@ -5839,6 +5871,8 @@ ColLabel: ColId { $$ = $1; }
|
||||
| SUBSTRING { $$ = "substring"; }
|
||||
| TABLE { $$ = "table"; }
|
||||
| THEN { $$ = "then"; }
|
||||
| TIME { $$ = "time"; }
|
||||
| TIMESTAMP { $$ = "timestamp"; }
|
||||
| TO { $$ = "to"; }
|
||||
| TRAILING { $$ = "trailing"; }
|
||||
| TRANSACTION { $$ = "transaction"; }
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.61 2001/09/28 08:09:09 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.62 2001/10/03 05:29:12 thomas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -287,8 +287,7 @@ coerce_type_typmod(ParseState *pstate, Node *node,
|
||||
* We assume that only typmod values greater than 0 indicate a forced
|
||||
* conversion is necessary.
|
||||
*/
|
||||
if (atttypmod <= 0 ||
|
||||
atttypmod == exprTypmod(node))
|
||||
if ((atttypmod <= 0) || (atttypmod == exprTypmod(node)))
|
||||
return node;
|
||||
|
||||
funcname = typeidTypeName(targetTypeId);
|
||||
@@ -376,9 +375,9 @@ select_common_type(List *typeids, const char *context)
|
||||
Oid ntype = (Oid) lfirsti(l);
|
||||
|
||||
/* move on to next one if no new information... */
|
||||
if (ntype && (ntype != UNKNOWNOID) && (ntype != ptype))
|
||||
if ((ntype != InvalidOid) && (ntype != UNKNOWNOID) && (ntype != ptype))
|
||||
{
|
||||
if (!ptype || ptype == UNKNOWNOID)
|
||||
if ((ptype == InvalidOid) || ptype == UNKNOWNOID)
|
||||
{
|
||||
/* so far, only nulls so take anything... */
|
||||
ptype = ntype;
|
||||
@@ -456,6 +455,9 @@ coerce_to_common_type(ParseState *pstate, Node *node,
|
||||
|
||||
/* TypeCategory()
|
||||
* Assign a category to the specified OID.
|
||||
* XXX This should be moved to system catalog lookups
|
||||
* to allow for better type extensibility.
|
||||
* - thomas 2001-09-30
|
||||
*/
|
||||
CATEGORY
|
||||
TypeCategory(Oid inType)
|
||||
@@ -538,16 +540,22 @@ TypeCategory(Oid inType)
|
||||
|
||||
/* IsPreferredType()
|
||||
* Check if this type is a preferred type.
|
||||
* XXX This should be moved to system catalog lookups
|
||||
* to allow for better type extensibility.
|
||||
* - thomas 2001-09-30
|
||||
*/
|
||||
bool
|
||||
IsPreferredType(CATEGORY category, Oid type)
|
||||
{
|
||||
return type == PreferredType(category, type);
|
||||
return (type == PreferredType(category, type));
|
||||
} /* IsPreferredType() */
|
||||
|
||||
|
||||
/* PreferredType()
|
||||
* Return the preferred type OID for the specified category.
|
||||
* XXX This should be moved to system catalog lookups
|
||||
* to allow for better type extensibility.
|
||||
* - thomas 2001-09-30
|
||||
*/
|
||||
static Oid
|
||||
PreferredType(CATEGORY category, Oid type)
|
||||
@@ -603,210 +611,3 @@ PreferredType(CATEGORY category, Oid type)
|
||||
}
|
||||
return result;
|
||||
} /* PreferredType() */
|
||||
|
||||
|
||||
#ifdef NOT_USED
|
||||
Oid
|
||||
PromoteTypeToNext(Oid inType)
|
||||
{
|
||||
Oid result;
|
||||
|
||||
switch (inType)
|
||||
{
|
||||
case (CHAROID):
|
||||
case (BPCHAROID):
|
||||
result = VARCHAROID;
|
||||
break;
|
||||
|
||||
case (VARCHAROID):
|
||||
result = TEXTOID;
|
||||
break;
|
||||
|
||||
case (INT2OID):
|
||||
case (CASHOID):
|
||||
result = INT4OID;
|
||||
break;
|
||||
|
||||
case (INT4OID):
|
||||
case (INT8OID):
|
||||
case (FLOAT4OID):
|
||||
result = FLOAT8OID;
|
||||
break;
|
||||
|
||||
case (NUMERICOID):
|
||||
result = NUMERICOID;
|
||||
break;
|
||||
|
||||
case (DATEOID):
|
||||
result = TIMESTAMPOID;
|
||||
break;
|
||||
|
||||
case (ABSTIMEOID):
|
||||
case (TIMESTAMPOID):
|
||||
result = TIMESTAMPTZOID;
|
||||
break;
|
||||
|
||||
case (TIMEOID):
|
||||
case (RELTIMEOID):
|
||||
result = INTERVALOID;
|
||||
break;
|
||||
|
||||
case (BOOLOID):
|
||||
case (TEXTOID):
|
||||
case (FLOAT8OID):
|
||||
case (TIMESTAMPTZOID):
|
||||
case (INTERVALOID):
|
||||
default:
|
||||
result = inType;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
} /* PromoteTypeToNext() */
|
||||
|
||||
|
||||
Oid
|
||||
DemoteType(Oid inType)
|
||||
{
|
||||
Oid result;
|
||||
|
||||
switch (inType)
|
||||
{
|
||||
case (FLOAT4OID):
|
||||
case (FLOAT8OID):
|
||||
result = INT4OID;
|
||||
break;
|
||||
|
||||
default:
|
||||
result = inType;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
} /* DemoteType() */
|
||||
|
||||
|
||||
Oid
|
||||
PromoteLesserType(Oid inType1, Oid inType2, Oid *newType1, Oid *newType2)
|
||||
{
|
||||
Oid result;
|
||||
|
||||
if (inType1 == inType2)
|
||||
{
|
||||
result = PromoteTypeToNext(inType1);
|
||||
inType1 = result;
|
||||
*arg2 = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
kind1 = ClassifyType(inType1);
|
||||
kind2 = ClassifyType(*arg2);
|
||||
if (kind1 != kind2)
|
||||
{
|
||||
*newType1 = inType1;
|
||||
*newType2 = inType2;
|
||||
result = InvalidOid;
|
||||
}
|
||||
|
||||
isBuiltIn1 = IS_BUILTIN_TYPE(inType1);
|
||||
isBuiltIn2 = IS_BUILTIN_TYPE(*arg2);
|
||||
|
||||
if (isBuiltIn1 && isBuiltIn2)
|
||||
{
|
||||
switch (*arg1)
|
||||
{
|
||||
case (CHAROID):
|
||||
switch (*arg2)
|
||||
{
|
||||
case (BPCHAROID):
|
||||
case (VARCHAROID):
|
||||
case (TEXTOID):
|
||||
|
||||
case (INT2OID):
|
||||
case (INT4OID):
|
||||
case (FLOAT4OID):
|
||||
case (FLOAT8OID):
|
||||
case (CASHOID):
|
||||
|
||||
case (POINTOID):
|
||||
case (LSEGOID):
|
||||
case (LINEOID):
|
||||
case (BOXOID):
|
||||
case (PATHOID):
|
||||
case (CIRCLEOID):
|
||||
case (POLYGONOID):
|
||||
|
||||
case (InvalidOid):
|
||||
case (UNKNOWNOID):
|
||||
case (BOOLOID):
|
||||
default:
|
||||
*arg1 = InvalidOid;
|
||||
*arg2 = InvalidOid;
|
||||
result = InvalidOid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isBuiltIn1 && !isBuiltIn2)
|
||||
{
|
||||
if ((promotedType = PromoteBuiltInType(*arg1)) != *arg1)
|
||||
{
|
||||
*arg1 = promotedType;
|
||||
return promotedType;
|
||||
}
|
||||
else if (CanCoerceType(*arg1, *arg2))
|
||||
{
|
||||
*arg1 = *arg2;
|
||||
return *arg2;
|
||||
}
|
||||
}
|
||||
else if (!isBuiltIn1 && isBuiltIn2)
|
||||
{
|
||||
if ((promotedType = PromoteBuiltInType(*arg2)) != *arg2)
|
||||
{
|
||||
*arg2 = promotedType;
|
||||
return promotedType;
|
||||
}
|
||||
else if (CanCoerceType(*arg2, *arg1))
|
||||
{
|
||||
*arg2 = *arg1;
|
||||
return *arg1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (*arg2 == InvalidOid)
|
||||
return InvalidOid;
|
||||
|
||||
switch (*arg1)
|
||||
{
|
||||
case (CHAROID):
|
||||
switch (*arg2)
|
||||
{
|
||||
case (BPCHAROID):
|
||||
case (VARCHAROID):
|
||||
case (TEXTOID):
|
||||
|
||||
case (INT2OID):
|
||||
case (INT4OID):
|
||||
case (FLOAT4OID):
|
||||
case (FLOAT8OID):
|
||||
case (CASHOID):
|
||||
|
||||
case (POINTOID):
|
||||
case (LSEGOID):
|
||||
case (LINEOID):
|
||||
case (BOXOID):
|
||||
case (PATHOID):
|
||||
case (CIRCLEOID):
|
||||
case (POLYGONOID):
|
||||
|
||||
case (InvalidOid):
|
||||
case (UNKNOWNOID):
|
||||
case (BOOLOID):
|
||||
default:
|
||||
*arg1 = InvalidOid;
|
||||
*arg2 = InvalidOid;
|
||||
result = InvalidOid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user