1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +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:
Thomas G. Lockhart
2001-10-03 05:29:27 +00:00
parent a51de40fb6
commit 3e1beda2cd
22 changed files with 946 additions and 942 deletions

View File

@@ -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);

View File

@@ -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"; }

View File

@@ -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

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.58 2001/09/28 08:09:10 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.59 2001/10/03 05:29:24 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,9 @@
#include "utils/timestamp.h"
static void
AdjustTimeForTypmod(TimeADT *time, int32 typmod);
/*****************************************************************************
* Date ADT
*****************************************************************************/
@@ -425,7 +428,11 @@ Datum
time_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
TimeADT time;
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
TimeADT result;
double fsec;
struct tm tt,
*tm = &tt;
@@ -439,9 +446,11 @@ time_in(PG_FUNCTION_ARGS)
|| (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, NULL) != 0))
elog(ERROR, "Bad time external representation '%s'", str);
time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
PG_RETURN_TIMEADT(time);
AdjustTimeForTypmod(&result, typmod);
PG_RETURN_TIMEADT(result);
}
Datum
@@ -452,13 +461,14 @@ time_out(PG_FUNCTION_ARGS)
struct tm tt,
*tm = &tt;
double fsec;
double trem;
char buf[MAXDATELEN + 1];
tm->tm_hour = (time / (60 * 60));
tm->tm_min = (((int) (time / 60)) % 60);
tm->tm_sec = (((int) time) % 60);
fsec = 0;
trem = time;
TMODULO(trem, tm->tm_hour, 3600e0);
TMODULO(trem, tm->tm_min, 60e0);
TMODULO(trem, tm->tm_sec, 1e0);
fsec = trem;
EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
@@ -466,6 +476,43 @@ time_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
/* time_scale()
* Adjust time type for specified scale factor.
* Used by PostgreSQL type system to stuff columns.
*/
Datum
time_scale(PG_FUNCTION_ARGS)
{
TimeADT time = PG_GETARG_TIMEADT(0);
int32 typmod = PG_GETARG_INT32(1);
TimeADT result;
result = time;
AdjustTimeForTypmod(&result, typmod);
PG_RETURN_TIMEADT(result);
}
static void
AdjustTimeForTypmod(TimeADT *time, int32 typmod)
{
if ((typmod >= 0) && (typmod <= 13))
{
static double TimeScale = 1;
static int32 TimeTypmod = 0;
if (typmod != TimeTypmod)
TimeScale = pow(10, typmod);
*time = (rint(((double) *time)*TimeScale)/TimeScale);
if (*time >= 86400)
*time -= 86400;
}
return;
}
Datum
time_eq(PG_FUNCTION_ARGS)
@@ -882,12 +929,15 @@ text_time(PG_FUNCTION_ARGS)
* Time With Time Zone ADT
*****************************************************************************/
Datum
timetz_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
TimeTzADT *time;
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
TimeTzADT *result;
double fsec;
struct tm tt,
*tm = &tt;
@@ -902,12 +952,14 @@ timetz_in(PG_FUNCTION_ARGS)
|| (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
elog(ERROR, "Bad time external representation '%s'", str);
time = (TimeTzADT *) palloc(sizeof(TimeTzADT));
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
time->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
time->zone = tz;
result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
result->zone = tz;
PG_RETURN_TIMETZADT_P(time);
AdjustTimeForTypmod(&(result->time), typmod);
PG_RETURN_TIMETZADT_P(result);
}
Datum
@@ -919,13 +971,15 @@ timetz_out(PG_FUNCTION_ARGS)
*tm = &tt;
double fsec;
int tz;
double trem;
char buf[MAXDATELEN + 1];
tm->tm_hour = (time->time / (60 * 60));
tm->tm_min = (((int) (time->time / 60)) % 60);
tm->tm_sec = (((int) time->time) % 60);
trem = time->time;
TMODULO(trem, tm->tm_hour, 3600e0);
TMODULO(trem, tm->tm_min, 60e0);
TMODULO(trem, tm->tm_sec, 1e0);
fsec = trem;
fsec = 0;
tz = time->zone;
EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
@@ -934,6 +988,27 @@ timetz_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
/* timetz_scale()
* Adjust time type for specified scale factor.
* Used by PostgreSQL type system to stuff columns.
*/
Datum
timetz_scale(PG_FUNCTION_ARGS)
{
TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
int32 typmod = PG_GETARG_INT32(1);
TimeTzADT *result;
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
result->time = time->time;
result->zone = time->zone;
AdjustTimeForTypmod(&(result->time), typmod);
PG_RETURN_TIMETZADT_P(result);
}
static int
timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.67 2001/09/28 08:09:10 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.68 2001/10/03 05:29:24 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,8 +26,6 @@
#include "utils/datetime.h"
#define ROUND_ALL 1
static int DecodeNumber(int flen, char *field,
int fmask, int *tmask,
struct tm * tm, double *fsec, int *is2digits);
@@ -2173,8 +2171,27 @@ EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
sec = (tm->tm_sec + fsec);
sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
sprintf((str + 6), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);
sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
/* If we have fractional seconds, then include a decimal point
* We will do up to 6 fractional digits, and we have rounded any inputs
* to eliminate anything to the right of 6 digits anyway.
* If there are no fractional seconds, then do not bother printing
* a decimal point at all. - thomas 2001-09-29
*/
if (fsec != 0) {
sprintf((str + strlen(str)), ":%013.10f", sec);
/* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0)
&& (*(str + strlen(str) - 3) != '.'))
{
*(str + strlen(str) - 2) = '\0';
}
}
else
{
sprintf((str + strlen(str)), ":%02.0f", sec);
}
if (tzp != NULL)
{
@@ -2221,9 +2238,28 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
case USE_ISO_DATES:
if (tm->tm_year > 0)
{
sprintf(str, "%04d-%02d-%02d %02d:%02d:",
sprintf(str, "%04d-%02d-%02d %02d:%02d",
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
sprintf((str + strlen(str)), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);
/* If we have fractional seconds, then include a decimal point
* We will do up to 6 fractional digits, and we have rounded any inputs
* to eliminate anything to the right of 6 digits anyway.
* If there are no fractional seconds, then do not bother printing
* a decimal point at all. - thomas 2001-09-29
*/
if (fsec != 0) {
sprintf((str + strlen(str)), ":%013.10f", sec);
/* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0)
&& (*(str + strlen(str) - 3) != '.'))
{
*(str + strlen(str) - 2) = '\0';
}
}
else
{
sprintf((str + strlen(str)), ":%02.0f", sec);
}
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
{
@@ -2261,8 +2297,28 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
if (tm->tm_year > 0)
{
sprintf((str + 5), "/%04d %02d:%02d:%05.2f",
tm->tm_year, tm->tm_hour, tm->tm_min, sec);
sprintf((str + 5), "/%04d %02d:%02d",
tm->tm_year, tm->tm_hour, tm->tm_min);
/* If we have fractional seconds, then include a decimal point
* We will do up to 6 fractional digits, and we have rounded any inputs
* to eliminate anything to the right of 6 digits anyway.
* If there are no fractional seconds, then do not bother printing
* a decimal point at all. - thomas 2001-09-29
*/
if (fsec != 0) {
sprintf((str + strlen(str)), ":%013.10f", sec);
/* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0)
&& (*(str + strlen(str) - 3) != '.'))
{
*(str + strlen(str) - 2) = '\0';
}
}
else
{
sprintf((str + strlen(str)), ":%02.0f", sec);
}
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
@@ -2277,8 +2333,28 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
if (tm->tm_year > 0)
{
sprintf((str + 5), ".%04d %02d:%02d:%05.2f",
tm->tm_year, tm->tm_hour, tm->tm_min, sec);
sprintf((str + 5), ".%04d %02d:%02d",
tm->tm_year, tm->tm_hour, tm->tm_min);
/* If we have fractional seconds, then include a decimal point
* We will do up to 6 fractional digits, and we have rounded any inputs
* to eliminate anything to the right of 6 digits anyway.
* If there are no fractional seconds, then do not bother printing
* a decimal point at all. - thomas 2001-09-29
*/
if (fsec != 0) {
sprintf((str + strlen(str)), ":%013.10f", sec);
/* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0)
&& (*(str + strlen(str) - 3) != '.'))
{
*(str + strlen(str) - 2) = '\0';
}
}
else
{
sprintf((str + strlen(str)), ":%02.0f", sec);
}
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
@@ -2305,18 +2381,30 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
if (tm->tm_year > 0)
{
sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
if (fsec != 0)
{
sprintf((str + 16), ":%05.2f %04d", sec, tm->tm_year);
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
/* If we have fractional seconds, then include a decimal point
* We will do up to 6 fractional digits, and we have rounded any inputs
* to eliminate anything to the right of 6 digits anyway.
* If there are no fractional seconds, then do not bother printing
* a decimal point at all. - thomas 2001-09-29
*/
if (fsec != 0) {
sprintf((str + strlen(str)), ":%013.10f", sec);
/* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0)
&& (*(str + strlen(str) - 3) != '.'))
{
*(str + strlen(str) - 2) = '\0';
}
}
else
{
sprintf((str + 16), ":%02.0f %04d", sec, tm->tm_year);
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
sprintf((str + strlen(str)), ":%02.0f", sec);
}
sprintf((str + strlen(str)), " %04d", tm->tm_year);
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
}
else
{

View File

@@ -5,7 +5,7 @@
*
* 1998 Jan Wieck
*
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.43 2001/08/14 22:21:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.44 2001/10/03 05:29:24 thomas Exp $
*
* ----------
*/
@@ -193,10 +193,8 @@ Datum
numeric_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
NumericVar value;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.51 2001/09/28 08:09:11 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.52 2001/10/03 05:29:24 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,6 +32,8 @@
static double time2t(const int hour, const int min, const double sec);
static int EncodeSpecialTimestamp(Timestamp dt, char *str);
static Timestamp dt2local(Timestamp dt, int timezone);
static void
AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
/*****************************************************************************
@@ -45,6 +47,10 @@ Datum
timestamp_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
Timestamp result;
double fsec;
struct tm tt,
@@ -89,6 +95,8 @@ timestamp_in(PG_FUNCTION_ARGS)
TIMESTAMP_NOEND(result);
}
AdjustTimestampForTypmod(&result, typmod);
PG_RETURN_TIMESTAMP(result);
}
@@ -98,7 +106,7 @@ timestamp_in(PG_FUNCTION_ARGS)
Datum
timestamp_out(PG_FUNCTION_ARGS)
{
Timestamp dt = PG_GETARG_TIMESTAMP(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
char *result;
struct tm tt,
*tm = &tt;
@@ -106,9 +114,9 @@ timestamp_out(PG_FUNCTION_ARGS)
char *tzn = NULL;
char buf[MAXDATELEN + 1];
if (TIMESTAMP_NOT_FINITE(dt))
EncodeSpecialTimestamp(dt, buf);
else if (timestamp2tm(dt, NULL, tm, &fsec, NULL) == 0)
if (TIMESTAMP_NOT_FINITE(timestamp))
EncodeSpecialTimestamp(timestamp, buf);
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf);
else
elog(ERROR, "Unable to format timestamp; internal coding error");
@@ -117,6 +125,42 @@ timestamp_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
/* timestamp_scale()
* Adjust time type for specified scale factor.
* Used by PostgreSQL type system to stuff columns.
*/
Datum
timestamp_scale(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
int32 typmod = PG_GETARG_INT32(1);
Timestamp result;
result = timestamp;
if (! TIMESTAMP_NOT_FINITE(result))
AdjustTimestampForTypmod(&result, typmod);
PG_RETURN_TIMESTAMP(result);
}
static void
AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
{
if ((typmod >= 0) && (typmod <= 13))
{
static double TimestampScale = 1;
static int32 TimestampTypmod = 0;
if (typmod != TimestampTypmod)
TimestampScale = pow(10, typmod);
*time = (rint(((double) *time)*TimestampScale)/TimestampScale);
}
return;
}
/* timestamptz_in()
* Convert a string to internal form.
@@ -125,6 +169,10 @@ Datum
timestamptz_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
TimestampTz result;
double fsec;
struct tm tt,
@@ -169,6 +217,8 @@ timestamptz_in(PG_FUNCTION_ARGS)
TIMESTAMP_NOEND(result);
}
AdjustTimestampForTypmod(&result, typmod);
PG_RETURN_TIMESTAMPTZ(result);
}
@@ -198,6 +248,25 @@ timestamptz_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
/* timestamptz_scale()
* Adjust time type for specified scale factor.
* Used by PostgreSQL type system to stuff columns.
*/
Datum
timestamptz_scale(PG_FUNCTION_ARGS)
{
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
int32 typmod = PG_GETARG_INT32(1);
TimestampTz result;
result = timestamp;
if (! TIMESTAMP_NOT_FINITE(result))
AdjustTimestampForTypmod(&result, typmod);
PG_RETURN_TIMESTAMPTZ(result);
}
/* interval_in()
* Convert a string to internal form.
@@ -2119,16 +2188,13 @@ timestamp_part(PG_FUNCTION_ARGS)
text *units = PG_GETARG_TEXT_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
float8 result;
int tz;
int type,
val;
int i;
char *up,
*lp,
lowunits[MAXDATELEN + 1];
double dummy;
double fsec;
char *tzn;
struct tm tt,
*tm = &tt;
@@ -2152,24 +2218,10 @@ timestamp_part(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(result);
}
if ((type == UNITS) && (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0))
if ((type == UNITS) && (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0))
{
switch (val)
{
case DTK_TZ:
result = tz;
break;
case DTK_TZ_MINUTE:
result = tz / 60;
TMODULO(result, dummy, 60e0);
break;
case DTK_TZ_HOUR:
dummy = tz;
TMODULO(dummy, result, 3600e0);
break;
case DTK_MICROSEC:
result = (fsec * 1000000);
break;
@@ -2222,11 +2274,13 @@ timestamp_part(PG_FUNCTION_ARGS)
result = (tm->tm_year / 1000);
break;
case DTK_TZ:
case DTK_TZ_MINUTE:
case DTK_TZ_HOUR:
default:
elog(ERROR, "Timestamp units '%s' not supported", lowunits);
result = 0;
}
}
else if (type == RESERV)
{
@@ -2237,14 +2291,14 @@ timestamp_part(PG_FUNCTION_ARGS)
break;
case DTK_DOW:
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
elog(ERROR, "Unable to encode timestamp");
result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
break;
case DTK_DOY:
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
elog(ERROR, "Unable to encode timestamp");
result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.82 2001/09/11 05:18:59 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.83 2001/10/03 05:29:24 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,7 +33,7 @@
* at CREATE TABLE time.
*
* It's hard to implement these types because we cannot figure out
* the length of the type from the type itself. I change (hopefully all) the
* the length of the type from the type itself. I changed (hopefully all) the
* fmgr calls that invoke input functions of a data type to supply the
* length also. (eg. in INSERTs, we have the tupleDescriptor which contains
* the length of the attributes and hence the exact length of the char() or