date.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,274 行 · 第 1/4 页

C
2,274
字号
	if (dterr == 0)		dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);	if (dterr != 0)		DateTimeParseError(dterr, str, "time");	tm2time(tm, fsec, &result);	AdjustTimeForTypmod(&result, typmod);	PG_RETURN_TIMEADT(result);}/* tm2time() * Convert a tm structure to a time data type. */static inttm2time(struct tm * tm, fsec_t fsec, TimeADT *result){#ifdef HAVE_INT64_TIMESTAMP	*result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)				* INT64CONST(1000000)) + fsec);#else	*result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);#endif	return 0;}/* time2tm() * Convert time data type to POSIX time structure. * For dates within the system-supported time_t range, convert to the *	local time zone. If out of this range, leave as GMT. - tgl 97/05/27 */static inttime2tm(TimeADT time, struct tm * tm, fsec_t *fsec){#ifdef HAVE_INT64_TIMESTAMP	tm->tm_hour = (time / INT64CONST(3600000000));	time -= (tm->tm_hour * INT64CONST(3600000000));	tm->tm_min = (time / INT64CONST(60000000));	time -= (tm->tm_min * INT64CONST(60000000));	tm->tm_sec = (time / INT64CONST(1000000));	time -= (tm->tm_sec * INT64CONST(1000000));	*fsec = time;#else	double		trem;	trem = time;	TMODULO(trem, tm->tm_hour, 3600e0);	TMODULO(trem, tm->tm_min, 60e0);	TMODULO(trem, tm->tm_sec, 1e0);	*fsec = trem;#endif	return 0;}Datumtime_out(PG_FUNCTION_ARGS){	TimeADT		time = PG_GETARG_TIMEADT(0);	char	   *result;	struct tm	tt,			   *tm = &tt;	fsec_t		fsec;	char		buf[MAXDATELEN + 1];	time2tm(time, tm, &fsec);	EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);	result = pstrdup(buf);	PG_RETURN_CSTRING(result);}/* *		time_recv			- converts external binary format to time * * We make no attempt to provide compatibility between int and float * time representations ... */Datumtime_recv(PG_FUNCTION_ARGS){	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);#ifdef HAVE_INT64_TIMESTAMP	PG_RETURN_TIMEADT((TimeADT) pq_getmsgint64(buf));#else	PG_RETURN_TIMEADT((TimeADT) pq_getmsgfloat8(buf));#endif}/* *		time_send			- converts time to binary format */Datumtime_send(PG_FUNCTION_ARGS){	TimeADT		time = PG_GETARG_TIMEADT(0);	StringInfoData buf;	pq_begintypsend(&buf);#ifdef HAVE_INT64_TIMESTAMP	pq_sendint64(&buf, time);#else	pq_sendfloat8(&buf, time);#endif	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* time_scale() * Adjust time type for specified scale factor. * Used by PostgreSQL type system to stuff columns. */Datumtime_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);}/* AdjustTimeForTypmod() * Force the precision of the time value to a specified value. * Uses *exactly* the same code as in AdjustTimestampForTypemod() * but we make a separate copy because those types do not * have a fundamental tie together but rather a coincidence of * implementation. - thomas */static voidAdjustTimeForTypmod(TimeADT *time, int32 typmod){#ifdef HAVE_INT64_TIMESTAMP	static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {		INT64CONST(1000000),		INT64CONST(100000),		INT64CONST(10000),		INT64CONST(1000),		INT64CONST(100),		INT64CONST(10),		INT64CONST(1)	};	static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {		INT64CONST(500000),		INT64CONST(50000),		INT64CONST(5000),		INT64CONST(500),		INT64CONST(50),		INT64CONST(5),		INT64CONST(0)	};#else	/* note MAX_TIME_PRECISION differs in this case */	static const double TimeScales[MAX_TIME_PRECISION + 1] = {		1.0,		10.0,		100.0,		1000.0,		10000.0,		100000.0,		1000000.0,		10000000.0,		100000000.0,		1000000000.0,		10000000000.0	};#endif	if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION))	{		/*		 * Note: this round-to-nearest code is not completely consistent		 * about rounding values that are exactly halfway between integral		 * values.	On most platforms, rint() will implement		 * round-to-nearest-even, but the integer code always rounds up		 * (away from zero).  Is it worth trying to be consistent?		 */#ifdef HAVE_INT64_TIMESTAMP		if (*time >= INT64CONST(0))		{			*time = (((*time + TimeOffsets[typmod]) / TimeScales[typmod])					 * TimeScales[typmod]);		}		else		{			*time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod])					  * TimeScales[typmod]);		}#else		*time = (rint(((double) *time) * TimeScales[typmod])				 / TimeScales[typmod]);#endif	}}Datumtime_eq(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_BOOL(time1 == time2);}Datumtime_ne(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_BOOL(time1 != time2);}Datumtime_lt(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_BOOL(time1 < time2);}Datumtime_le(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_BOOL(time1 <= time2);}Datumtime_gt(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_BOOL(time1 > time2);}Datumtime_ge(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_BOOL(time1 >= time2);}Datumtime_cmp(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	if (time1 < time2)		PG_RETURN_INT32(-1);	if (time1 > time2)		PG_RETURN_INT32(1);	PG_RETURN_INT32(0);}Datumtime_larger(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);}Datumtime_smaller(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);}/* overlaps_time() --- implements the SQL92 OVERLAPS operator. * * Algorithm is per SQL92 spec.  This is much harder than you'd think * because the spec requires us to deliver a non-null answer in some cases * where some of the inputs are null. */Datumoverlaps_time(PG_FUNCTION_ARGS){	/*	 * The arguments are TimeADT, but we leave them as generic Datums to	 * avoid dereferencing nulls (TimeADT is pass-by-reference!)	 */	Datum		ts1 = PG_GETARG_DATUM(0);	Datum		te1 = PG_GETARG_DATUM(1);	Datum		ts2 = PG_GETARG_DATUM(2);	Datum		te2 = PG_GETARG_DATUM(3);	bool		ts1IsNull = PG_ARGISNULL(0);	bool		te1IsNull = PG_ARGISNULL(1);	bool		ts2IsNull = PG_ARGISNULL(2);	bool		te2IsNull = PG_ARGISNULL(3);#define TIMEADT_GT(t1,t2) \	(DatumGetTimeADT(t1) > DatumGetTimeADT(t2))#define TIMEADT_LT(t1,t2) \	(DatumGetTimeADT(t1) < DatumGetTimeADT(t2))	/*	 * If both endpoints of interval 1 are null, the result is null	 * (unknown). If just one endpoint is null, take ts1 as the non-null	 * one. Otherwise, take ts1 as the lesser endpoint.	 */	if (ts1IsNull)	{		if (te1IsNull)			PG_RETURN_NULL();		/* swap null for non-null */		ts1 = te1;		te1IsNull = true;	}	else if (!te1IsNull)	{		if (TIMEADT_GT(ts1, te1))		{			Datum		tt = ts1;			ts1 = te1;			te1 = tt;		}	}	/* Likewise for interval 2. */	if (ts2IsNull)	{		if (te2IsNull)			PG_RETURN_NULL();		/* swap null for non-null */		ts2 = te2;		te2IsNull = true;	}	else if (!te2IsNull)	{		if (TIMEADT_GT(ts2, te2))		{			Datum		tt = ts2;			ts2 = te2;			te2 = tt;		}	}	/*	 * At this point neither ts1 nor ts2 is null, so we can consider three	 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2	 */	if (TIMEADT_GT(ts1, ts2))	{		/*		 * This case is ts1 < te2 OR te1 < te2, which may look redundant		 * but in the presence of nulls it's not quite completely so.		 */		if (te2IsNull)			PG_RETURN_NULL();		if (TIMEADT_LT(ts1, te2))			PG_RETURN_BOOL(true);		if (te1IsNull)			PG_RETURN_NULL();		/*		 * If te1 is not null then we had ts1 <= te1 above, and we just		 * found ts1 >= te2, hence te1 >= te2.		 */		PG_RETURN_BOOL(false);	}	else if (TIMEADT_LT(ts1, ts2))	{		/* This case is ts2 < te1 OR te2 < te1 */		if (te1IsNull)			PG_RETURN_NULL();		if (TIMEADT_LT(ts2, te1))			PG_RETURN_BOOL(true);		if (te2IsNull)			PG_RETURN_NULL();		/*		 * If te2 is not null then we had ts2 <= te2 above, and we just		 * found ts2 >= te1, hence te2 >= te1.		 */		PG_RETURN_BOOL(false);	}	else	{		/*		 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a		 * rather silly way of saying "true if both are nonnull, else		 * null".		 */		if (te1IsNull || te2IsNull)			PG_RETURN_NULL();		PG_RETURN_BOOL(true);	}#undef TIMEADT_GT#undef TIMEADT_LT}/* timestamp_time() * Convert timestamp to time data type. */Datumtimestamp_time(PG_FUNCTION_ARGS){	Timestamp	timestamp = PG_GETARG_TIMESTAMP(0);	TimeADT		result;	struct tm	tt,			   *tm = &tt;	fsec_t		fsec;	if (TIMESTAMP_NOT_FINITE(timestamp))		PG_RETURN_NULL();	if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)		ereport(ERROR,				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),				 errmsg("timestamp out of range")));#ifdef HAVE_INT64_TIMESTAMP	/*	 * Could also do this with time = (timestamp / 86400000000 *	 * 86400000000) - timestamp;	 */	result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)			   * INT64CONST(1000000)) + fsec);#else	result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);#endif	PG_RETURN_TIMEADT(result);}/* timestamptz_time() * Convert timestamptz to time data type. */Datumtimestamptz_time(PG_FUNCTION_ARGS){	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);	TimeADT		result;	struct tm	tt,			   *tm = &tt;	int			tz;	fsec_t		fsec;	char	   *tzn;	if (TIMESTAMP_NOT_FINITE(timestamp))		PG_RETURN_NULL();	if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)		ereport(ERROR,				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),				 errmsg("timestamp out of range")));#ifdef HAVE_INT64_TIMESTAMP	/*	 * Could also do this with time = (timestamp / 86400000000 *	 * 86400000000) - timestamp;	 */	result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)			   * INT64CONST(1000000)) + fsec);#else	result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);#endif	PG_RETURN_TIMEADT(result);}/* datetime_timestamp() * Convert date and time to timestamp data type. */Datumdatetime_timestamp(PG_FUNCTION_ARGS){	DateADT		date = PG_GETARG_DATEADT(0);	TimeADT		time = PG_GETARG_TIMEADT(1);	Timestamp	result;	result = DatumGetTimestamp(DirectFunctionCall1(date_timestamp,												 DateADTGetDatum(date)));	result += time;	PG_RETURN_TIMESTAMP(result);}/* time_interval() * Convert time to interval data type. */Datumtime_interval(PG_FUNCTION_ARGS){	TimeADT		time = PG_GETARG_TIMEADT(0);	Interval   *result;	result = (Interval *) palloc(sizeof(Interval));	result->time = time;	result->month = 0;	PG_RETURN_INTERVAL_P(result);}/* interval_time() * Convert interval to time data type. * * This is defined as producing the fractional-day portion of the interval. * Therefore, we can just ignore the months field.	It is not real clear * what to do with negative intervals, but we choose to subtract the floor, * so that, say, '-2 hours' becomes '22:00:00'. */Datuminterval_time(PG_FUNCTION_ARGS){	Interval   *span = PG_GETARG_INTERVAL_P(0);	TimeADT		result;#ifdef HAVE_INT64_TIMESTAMP	int64		days;	result = span->time;	if (result >= INT64CONST(86400000000))	{		days = result / INT64CONST(86400000000);		result -= days * INT64CONST(86400000000);	}	else if (result < 0)	{		days = (-result + INT64CONST(86400000000) - 1) / INT64CONST(86400000000);		result += days * INT64CONST(86400000000);	}#else	result = span->time;	if (result >= 86400e0 || result < 0)		result -= floor(result / 86400e0) * 86400e0;#endif	PG_RETURN_TIMEADT(result);}/* time_mi_time() * Subtract two times to produce an interval. */Datumtime_mi_time(PG_FUNCTION_ARGS){	TimeADT		time1 = PG_GETARG_TIMEADT(0);	TimeADT		time2 = PG_GETARG_TIMEADT(1);	Interval   *result;	result = (Interval *) palloc(sizeof(Interval));	result->time = (time1 - time2);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?