Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reimplement datediff and dateadd in c to improve performance #2035

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
589 changes: 587 additions & 2 deletions contrib/babelfishpg_common/src/datetime.c

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions contrib/babelfishpg_common/src/datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ extern Timestamp initializeToDefaultDatetime(void);
extern double calculateDaysFromDefaultDatetime(Timestamp timestamp_left);
extern int roundFractionalSeconds(int fractseconds);

extern int days_in_date(int day, int month, int year);
extern char* datetypeName(int num);

extern bool int64_multiply_add(int64 val, int64 multiplier, int64 *sum);
extern bool int32_multiply_add(int32 val, int32 multiplier, int32 *sum);

/* Range-check a datetime */
#define IS_VALID_DATETIME(t) (MIN_DATETIME <= (t) && (t) < END_DATETIME)

Expand Down
105 changes: 105 additions & 0 deletions contrib/babelfishpg_common/src/datetimeoffset.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "utils/datetime.h"
#include "libpq/pqformat.h"
#include "utils/timestamp.h"
#include "parser/scansup.h"

#include "fmgr.h"
#include "miscadmin.h"
Expand Down Expand Up @@ -63,6 +64,9 @@ PG_FUNCTION_INFO_V1(datetimeoffset_datetime2);
PG_FUNCTION_INFO_V1(datetimeoffset_scale);

PG_FUNCTION_INFO_V1(get_datetimeoffset_tzoffset_internal);
PG_FUNCTION_INFO_V1(dateadd_datetimeoffset);

#define DTK_NANO 32


/* datetimeoffset_in()
Expand Down Expand Up @@ -832,3 +836,104 @@ EncodeDatetimeoffsetTimezone(char *str, int tz, int style)

*tmp = '\0';
}

Datum
dateadd_datetimeoffset(PG_FUNCTION_ARGS) {
text *field = PG_GETARG_TEXT_PP(0);
int num = PG_GETARG_INT32(1);
tsql_datetimeoffset *init_startdate = PG_GETARG_DATETIMEOFFSET(2);
bool validDateAdd = true;
char *lowunits;
int type,
val;
tsql_datetimeoffset *result;
Interval *interval;
int timezone = DirectFunctionCall1(get_datetimeoffset_tzoffset_internal, DatetimeoffsetGetDatum(init_startdate)) * 2;
tsql_datetimeoffset *startdate = (tsql_datetimeoffset *) DirectFunctionCall2(datetimeoffset_pl_interval, DatetimeoffsetGetDatum(init_startdate), DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, timezone, 0));


lowunits = downcase_truncate_identifier(VARDATA_ANY(field),
VARSIZE_ANY_EXHDR(field),
false);

type = DecodeUnits(0, lowunits, &val);

if(strncmp(lowunits, "doy", 3) == 0 || strncmp(lowunits, "dayofyear", 9) == 0) {
type = UNITS;
val = DTK_DOY;
}

if(strncmp(lowunits, "nanosecond", 11) == 0) {
type = UNITS;
val = DTK_NANO;
}
if(strncmp(lowunits, "weekday", 7) == 0) {
type = UNITS;
val = DTK_DAY;
}

if(type == UNITS) {
switch(val) {
case DTK_YEAR:
interval = (Interval *) DirectFunctionCall7(make_interval, num, 0, 0, 0, 0, 0, 0);
break;
case DTK_QUARTER:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, num * 3, 0, 0, 0, 0, 0);
break;
case DTK_MONTH:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, num, 0, 0, 0, 0, 0);
break;
case DTK_WEEK:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, num, 0, 0, 0, 0);
break;
case DTK_DAY:
case DTK_DOY:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, num, 0, 0, 0);
break;
case DTK_HOUR:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, num, 0, 0);
break;
case DTK_MINUTE:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, num, 0);
break;
case DTK_SECOND:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum(num));
break;
case DTK_MILLISEC:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.001));
break;
case DTK_MICROSEC:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.000001));
break;
case DTK_NANO:
interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.000000001));
break;
default:
validDateAdd = false;
break;
}
} else {
validDateAdd = false;
}

if(!validDateAdd) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\'%s\' is not a recognized %s option", lowunits, "dateadd")));
}

PG_TRY();
{
result = (tsql_datetimeoffset *) DirectFunctionCall2(datetimeoffset_pl_interval, DatetimeoffsetGetDatum(startdate), PointerGetDatum(interval));

}
PG_CATCH();
{
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("Adding a value to a \'%s\' column caused an overflow.", "datetimeoffset")));
}
PG_END_TRY();

PG_RETURN_DATETIMEOFFSET(result);
}
5 changes: 4 additions & 1 deletion contrib/babelfishpg_tds/error_mapping.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,7 @@ XX000 ERRCODE_INTERNAL_ERROR "The table-valued parameter \"%s\" must be declared
0A000 ERRCODE_FEATURE_NOT_SUPPORTED "Column name or number of supplied values does not match table definition." SQL_ERROR_213 16
42501 ERRCODE_INSUFFICIENT_PRIVILEGE "Only members of the sysadmin role can execute this stored procedure." SQL_ERROR_15003 16
42809 ERRCODE_WRONG_OBJECT_TYPE "The target \"%s\" of the OUTPUT INTO clause cannot be a view or common table expression." SQL_ERROR_330 16

22008 ERRCODE_DATETIME_VALUE_OUT_OF_RANGE "The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart" SQL_ERROR_535 16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have we validated the transactional/control behavior for new error mappings? we need to make sure we are compatible with TSQL for these. There are automated scripts to validate an error's behavior. Please talk to Dipesh for more details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zhibai and I validated the transactional/control behavior for the new error mappings and it is compatible with TSQL

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes , I have asked in purpose and it has test cases regarding the transaction behavior

22023 ERRCODE_INVALID_PARAMETER_VALUE "\'%s\' is not a recognized %s option" SQL_ERROR_155 15
22023 ERRCODE_INVALID_PARAMETER_VALUE "The datepart %s is not supported by date function %s for data type %s." SQL_ERROR_9810 16
22008 ERRCODE_DATETIME_VALUE_OUT_OF_RANGE "Adding a value to a \'%s\' column caused an overflow." SQL_ERROR_517 16
Loading
Loading