618 lines
24 KiB
Go
618 lines
24 KiB
Go
// Copyright 2024 Dolthub, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package binary
|
|
|
|
import (
|
|
"math"
|
|
"time"
|
|
|
|
"github.com/cockroachdb/apd/v3"
|
|
"github.com/cockroachdb/errors"
|
|
"github.com/dolthub/go-mysql-server/sql"
|
|
|
|
"github.com/dolthub/doltgresql/postgres/parser/duration"
|
|
"github.com/dolthub/doltgresql/postgres/parser/timeofday"
|
|
"github.com/dolthub/doltgresql/postgres/parser/timetz"
|
|
"github.com/dolthub/doltgresql/server/functions"
|
|
"github.com/dolthub/doltgresql/server/functions/framework"
|
|
pgtypes "github.com/dolthub/doltgresql/server/types"
|
|
)
|
|
|
|
// These functions can be gathered using the following query from a Postgres 15 instance:
|
|
// SELECT * FROM pg_operator o WHERE o.oprname = '+' ORDER BY o.oprcode::varchar;
|
|
|
|
// initBinaryPlus registers the functions to the catalog.
|
|
func initBinaryPlus() {
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, date_pl_interval)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, date_pli)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, datetime_pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, datetimetz_pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, float4pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, float48pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, float8pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, float84pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int2pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int24pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int28pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int4pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int42pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int48pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int8pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int82pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, int84pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, integer_pl_date)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, interval_pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, interval_pl_time)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, interval_pl_date)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, interval_pl_timetz)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, interval_pl_timestamp)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, interval_pl_timestamptz)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, numeric_add)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, time_pl_interval)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, timedate_pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, timetz_pl_interval)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, timetzdate_pl)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, timestamp_pl_interval)
|
|
framework.RegisterBinaryFunction(framework.Operator_BinaryPlus, timestamptz_pl_interval)
|
|
}
|
|
|
|
// float4pl_callable is the callable logic for the float4pl function.
|
|
func float4pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return val1.(float32) + val2.(float32), nil
|
|
}
|
|
|
|
// float4pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var float4pl = framework.Function2{
|
|
Name: "float4pl",
|
|
Return: pgtypes.Float32,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Float32, pgtypes.Float32},
|
|
Strict: true,
|
|
Callable: float4pl_callable,
|
|
}
|
|
|
|
// float48pl_callable is the callable logic for the float48pl function.
|
|
func float48pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return float64(val1.(float32)) + val2.(float64), nil
|
|
}
|
|
|
|
// float48pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var float48pl = framework.Function2{
|
|
Name: "float48pl",
|
|
Return: pgtypes.Float64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Float32, pgtypes.Float64},
|
|
Strict: true,
|
|
Callable: float48pl_callable,
|
|
}
|
|
|
|
// float8pl_callable is the callable logic for the float8pl function.
|
|
func float8pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return val1.(float64) + val2.(float64), nil
|
|
}
|
|
|
|
// float8pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var float8pl = framework.Function2{
|
|
Name: "float8pl",
|
|
Return: pgtypes.Float64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Float64, pgtypes.Float64},
|
|
Strict: true,
|
|
Callable: float8pl_callable,
|
|
}
|
|
|
|
// float84pl_callable is the callable logic for the float84pl function.
|
|
func float84pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return val1.(float64) + float64(val2.(float32)), nil
|
|
}
|
|
|
|
// float84pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var float84pl = framework.Function2{
|
|
Name: "float84pl",
|
|
Return: pgtypes.Float64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Float64, pgtypes.Float32},
|
|
Strict: true,
|
|
Callable: float84pl_callable,
|
|
}
|
|
|
|
// int2pl_callable is the callable logic for the int2pl function.
|
|
func int2pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
result := int64(val1.(int16)) + int64(val2.(int16))
|
|
if result > math.MaxInt16 || result < math.MinInt16 {
|
|
return nil, errors.Errorf("smallint out of range")
|
|
}
|
|
return int16(result), nil
|
|
}
|
|
|
|
// int2pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int2pl = framework.Function2{
|
|
Name: "int2pl",
|
|
Return: pgtypes.Int16,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int16, pgtypes.Int16},
|
|
Strict: true,
|
|
Callable: int2pl_callable,
|
|
}
|
|
|
|
// int24pl_callable is the callable logic for the int24pl function.
|
|
func int24pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
result := int64(val1.(int16)) + int64(val2.(int32))
|
|
if result > math.MaxInt16 || result < math.MinInt16 {
|
|
return nil, errors.Errorf("integer out of range")
|
|
}
|
|
return int32(result), nil
|
|
}
|
|
|
|
// int24pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int24pl = framework.Function2{
|
|
Name: "int24pl",
|
|
Return: pgtypes.Int32,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int16, pgtypes.Int32},
|
|
Strict: true,
|
|
Callable: int24pl_callable,
|
|
}
|
|
|
|
// int28pl_callable is the callable logic for the int28pl function.
|
|
func int28pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return plusOverflow(int64(val1.(int16)), val2.(int64))
|
|
}
|
|
|
|
// int28pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int28pl = framework.Function2{
|
|
Name: "int28pl",
|
|
Return: pgtypes.Int64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int16, pgtypes.Int64},
|
|
Strict: true,
|
|
Callable: int28pl_callable,
|
|
}
|
|
|
|
// int4pl_callable is the callable logic for the int4pl function.
|
|
func int4pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
result := int64(val1.(int32)) + int64(val2.(int32))
|
|
if result > math.MaxInt32 || result < math.MinInt32 {
|
|
return nil, errors.Errorf("integer out of range")
|
|
}
|
|
return int32(result), nil
|
|
}
|
|
|
|
// int4pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int4pl = framework.Function2{
|
|
Name: "int4pl",
|
|
Return: pgtypes.Int32,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int32, pgtypes.Int32},
|
|
Strict: true,
|
|
Callable: int4pl_callable,
|
|
}
|
|
|
|
// int42pl_callable is the callable logic for the int42pl function.
|
|
func int42pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
result := int64(val1.(int32)) + int64(val2.(int16))
|
|
if result > math.MaxInt32 || result < math.MinInt32 {
|
|
return nil, errors.Errorf("integer out of range")
|
|
}
|
|
return int32(result), nil
|
|
}
|
|
|
|
// int42pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int42pl = framework.Function2{
|
|
Name: "int42pl",
|
|
Return: pgtypes.Int32,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int32, pgtypes.Int16},
|
|
Strict: true,
|
|
Callable: int42pl_callable,
|
|
}
|
|
|
|
// int48pl_callable is the callable logic for the int48pl function.
|
|
func int48pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return plusOverflow(int64(val1.(int32)), val2.(int64))
|
|
}
|
|
|
|
// int48pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int48pl = framework.Function2{
|
|
Name: "int48pl",
|
|
Return: pgtypes.Int64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int32, pgtypes.Int64},
|
|
Strict: true,
|
|
Callable: int48pl_callable,
|
|
}
|
|
|
|
// int8pl_callable is the callable logic for the int8pl function.
|
|
func int8pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return plusOverflow(val1.(int64), val2.(int64))
|
|
}
|
|
|
|
// int8pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int8pl = framework.Function2{
|
|
Name: "int8pl",
|
|
Return: pgtypes.Int64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int64, pgtypes.Int64},
|
|
Strict: true,
|
|
Callable: int8pl_callable,
|
|
}
|
|
|
|
// int82pl_callable is the callable logic for the int82pl function.
|
|
func int82pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return plusOverflow(val1.(int64), int64(val2.(int16)))
|
|
}
|
|
|
|
// int82pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int82pl = framework.Function2{
|
|
Name: "int82pl",
|
|
Return: pgtypes.Int64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int64, pgtypes.Int16},
|
|
Strict: true,
|
|
Callable: int82pl_callable,
|
|
}
|
|
|
|
// int84pl_callable is the callable logic for the int84pl function.
|
|
func int84pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return plusOverflow(val1.(int64), int64(val2.(int32)))
|
|
}
|
|
|
|
// int84pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var int84pl = framework.Function2{
|
|
Name: "int84pl",
|
|
Return: pgtypes.Int64,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int64, pgtypes.Int32},
|
|
Strict: true,
|
|
Callable: int84pl_callable,
|
|
}
|
|
|
|
// integer_pl_date represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var integer_pl_date = framework.Function2{
|
|
Name: "integer_pl_date",
|
|
Return: pgtypes.Date,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Int32, pgtypes.Date},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
days := val1.(int32)
|
|
date := val2.(time.Time)
|
|
|
|
// Add the specified number of days to the date (reverse of date_pli)
|
|
result := date.AddDate(0, 0, int(days))
|
|
|
|
return result, nil
|
|
},
|
|
}
|
|
|
|
// interval_pl_callable is the callable logic for the interval_pl function.
|
|
func interval_pl_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
dur1 := val1.(duration.Duration)
|
|
dur2 := val2.(duration.Duration)
|
|
return dur1.Add(dur2), nil
|
|
}
|
|
|
|
// interval_pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var interval_pl = framework.Function2{
|
|
Name: "interval_pl",
|
|
Return: pgtypes.Interval,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Interval, pgtypes.Interval},
|
|
Strict: true,
|
|
Callable: interval_pl_callable,
|
|
}
|
|
|
|
// interval_pl_time_callable is the callable logic for the interval_pl_time function.
|
|
func interval_pl_time_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
interval := val1.(duration.Duration)
|
|
timeVal := val2.(timeofday.TimeOfDay)
|
|
return timeVal.Add(interval), nil
|
|
}
|
|
|
|
// interval_pl_time represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var interval_pl_time = framework.Function2{
|
|
Name: "interval_pl_time",
|
|
Return: pgtypes.Time,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Interval, pgtypes.Time},
|
|
Strict: true,
|
|
Callable: interval_pl_time_callable,
|
|
}
|
|
|
|
// interval_pl_date_callable is the callable logic for the interval_pl_date function.
|
|
func interval_pl_date_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return intervalPlusNonInterval(val1.(duration.Duration), val2.(time.Time))
|
|
}
|
|
|
|
// interval_pl_date represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var interval_pl_date = framework.Function2{
|
|
Name: "interval_pl_date",
|
|
Return: pgtypes.Timestamp,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Interval, pgtypes.Date},
|
|
Strict: true,
|
|
Callable: interval_pl_date_callable,
|
|
}
|
|
|
|
// interval_pl_timetz_callable is the callable logic for the interval_pl_timetz function.
|
|
func interval_pl_timetz_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
interval := val1.(duration.Duration)
|
|
timeVal := val2.(timetz.TimeTZ)
|
|
timeVal.TimeOfDay = timeVal.TimeOfDay.Add(interval)
|
|
return timeVal, nil
|
|
}
|
|
|
|
// interval_pl_timetz represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var interval_pl_timetz = framework.Function2{
|
|
Name: "interval_pl_timetz",
|
|
Return: pgtypes.TimeTZ,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Interval, pgtypes.TimeTZ},
|
|
Strict: true,
|
|
Callable: interval_pl_timetz_callable,
|
|
}
|
|
|
|
// interval_pl_timestamp_callable is the callable logic for the interval_pl_timestamp function.
|
|
func interval_pl_timestamp_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return intervalPlusNonInterval(val1.(duration.Duration), val2.(time.Time))
|
|
}
|
|
|
|
// interval_pl_timestamp represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var interval_pl_timestamp = framework.Function2{
|
|
Name: "interval_pl_timestamp",
|
|
Return: pgtypes.Timestamp,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Interval, pgtypes.Timestamp},
|
|
Strict: true,
|
|
Callable: interval_pl_timestamp_callable,
|
|
}
|
|
|
|
// interval_pl_timestamptz_callable is the callable logic for the interval_pl_timestamptz function.
|
|
func interval_pl_timestamptz_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
return intervalPlusNonInterval(val1.(duration.Duration), val2.(time.Time))
|
|
}
|
|
|
|
// interval_pl_timestamptz represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var interval_pl_timestamptz = framework.Function2{
|
|
Name: "interval_pl_timestamptz",
|
|
Return: pgtypes.TimestampTZ,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Interval, pgtypes.TimestampTZ},
|
|
Strict: true,
|
|
Callable: interval_pl_timestamptz_callable,
|
|
}
|
|
|
|
// numeric_add_callable is the callable logic for the numeric_add function.
|
|
func numeric_add_callable(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
num1 := val1.(*apd.Decimal)
|
|
num2 := val2.(*apd.Decimal)
|
|
if num1.Form == apd.NaN || num2.Form == apd.NaN ||
|
|
(num1.Form == apd.Infinite && num2.Form == apd.Infinite && num2.Negative) ||
|
|
(num2.Form == apd.Infinite && num1.Form == apd.Infinite && num1.Negative) {
|
|
return pgtypes.NumericNaN, nil
|
|
}
|
|
if num1.Form == apd.Infinite || num2.Form == apd.Infinite {
|
|
if num1.Negative || num2.Negative {
|
|
return pgtypes.NumericNegInf, nil
|
|
}
|
|
return pgtypes.NumericInf, nil
|
|
}
|
|
|
|
res := new(apd.Decimal)
|
|
p := uint32(math.Max(float64(num1.NumDigits()), float64(num2.NumDigits())+
|
|
math.Max(math.Abs(float64(num1.Exponent)), math.Abs(float64(num2.Exponent)))))
|
|
_, err := sql.DecimalCtx.WithPrecision(p).Add(res, num1, num2)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
// numeric_add represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var numeric_add = framework.Function2{
|
|
Name: "numeric_add",
|
|
Return: pgtypes.Numeric,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Numeric, pgtypes.Numeric},
|
|
Strict: true,
|
|
Callable: numeric_add_callable,
|
|
}
|
|
|
|
// plusOverflow is a convenience function that checks for overflow for int64 addition.
|
|
func plusOverflow(val1 int64, val2 int64) (any, error) {
|
|
if val2 > 0 {
|
|
if val1 > math.MaxInt64-val2 {
|
|
return nil, errors.Errorf("bigint out of range")
|
|
}
|
|
} else {
|
|
if val1 < math.MinInt64-val2 {
|
|
return nil, errors.Errorf("bigint out of range")
|
|
}
|
|
}
|
|
return val1 + val2, nil
|
|
}
|
|
|
|
// date_pl_interval represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var date_pl_interval = framework.Function2{
|
|
Name: "date_pl_interval",
|
|
Return: pgtypes.Timestamp,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Date, pgtypes.Interval},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
date := val1.(time.Time)
|
|
interval := val2.(duration.Duration)
|
|
|
|
// Add the interval to the date using the existing helper function
|
|
return intervalPlusNonInterval(interval, date)
|
|
},
|
|
}
|
|
|
|
// date_pli represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var date_pli = framework.Function2{
|
|
Name: "date_pli",
|
|
Return: pgtypes.Date,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Date, pgtypes.Int32},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
date := val1.(time.Time)
|
|
days := val2.(int32)
|
|
|
|
// Add the specified number of days to the date
|
|
result := date.AddDate(0, 0, int(days))
|
|
|
|
return result, nil
|
|
},
|
|
}
|
|
|
|
// datetime_pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var datetime_pl = framework.Function2{
|
|
Name: "datetime_pl",
|
|
Return: pgtypes.Timestamp,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Date, pgtypes.Time},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
date := val1.(time.Time)
|
|
timeVal := val2.(timeofday.TimeOfDay).ToTime()
|
|
|
|
// Combine date from first parameter with time from second parameter
|
|
// Extract hour, minute, second, nanosecond from time
|
|
hour, min, sec := timeVal.Clock()
|
|
nsec := timeVal.Nanosecond()
|
|
|
|
// Create new timestamp with date components from date and time components from time
|
|
result := time.Date(date.Year(), date.Month(), date.Day(), hour, min, sec, nsec, date.Location())
|
|
|
|
return result, nil
|
|
},
|
|
}
|
|
|
|
// datetimetz_pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var datetimetz_pl = framework.Function2{
|
|
Name: "datetimetz_pl",
|
|
Return: pgtypes.TimestampTZ,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Date, pgtypes.TimeTZ},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
date := val1.(time.Time)
|
|
timetzVal := val2.(timetz.TimeTZ).ToTime()
|
|
|
|
// Combine date from first parameter with time+timezone from second parameter
|
|
// Extract hour, minute, second, nanosecond, and timezone from timetz
|
|
hour, min, sec := timetzVal.Clock()
|
|
nsec := timetzVal.Nanosecond()
|
|
location := timetzVal.Location()
|
|
|
|
// Create new timestamptz with date components from date and time+timezone components from timetz
|
|
result := time.Date(date.Year(), date.Month(), date.Day(), hour, min, sec, nsec, location)
|
|
|
|
return result, nil
|
|
},
|
|
}
|
|
|
|
// timedate_pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var timedate_pl = framework.Function2{
|
|
Name: "timedate_pl",
|
|
Return: pgtypes.Timestamp,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Time, pgtypes.Date},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
timeVal := val1.(timeofday.TimeOfDay).ToTime()
|
|
date := val2.(time.Time)
|
|
|
|
// Combine time from first parameter with date from second parameter
|
|
// Extract hour, minute, second, nanosecond from time
|
|
hour, min, sec := timeVal.Clock()
|
|
nsec := timeVal.Nanosecond()
|
|
|
|
// Create new timestamp with time components from time and date components from date
|
|
result := time.Date(date.Year(), date.Month(), date.Day(), hour, min, sec, nsec, date.Location())
|
|
|
|
return result, nil
|
|
},
|
|
}
|
|
|
|
// timetzdate_pl represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var timetzdate_pl = framework.Function2{
|
|
Name: "timetzdate_pl",
|
|
Return: pgtypes.TimestampTZ,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.TimeTZ, pgtypes.Date},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
timetzVal := val1.(timetz.TimeTZ).ToTime()
|
|
date := val2.(time.Time)
|
|
|
|
// Combine timetz from first parameter with date from second parameter
|
|
// Extract hour, minute, second, nanosecond, and timezone from timetz
|
|
hour, min, sec := timetzVal.Clock()
|
|
nsec := timetzVal.Nanosecond()
|
|
location := timetzVal.Location()
|
|
|
|
// Create new timestamptz with time+timezone components from timetz and date components from date
|
|
result := time.Date(date.Year(), date.Month(), date.Day(), hour, min, sec, nsec, location)
|
|
|
|
return result, nil
|
|
},
|
|
}
|
|
|
|
// timestamp_pl_interval represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var timestamp_pl_interval = framework.Function2{
|
|
Name: "timestamp_pl_interval",
|
|
Return: pgtypes.Timestamp,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Timestamp, pgtypes.Interval},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
timestamp := val1.(time.Time)
|
|
interval := val2.(duration.Duration)
|
|
|
|
// Add the interval to the timestamp using the existing helper function
|
|
return intervalPlusNonInterval(interval, timestamp)
|
|
},
|
|
}
|
|
|
|
// timestamptz_pl_interval represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var timestamptz_pl_interval = framework.Function2{
|
|
Name: "timestamptz_pl_interval",
|
|
Return: pgtypes.TimestampTZ,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.TimestampTZ, pgtypes.Interval},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
timestamptz := val1.(time.Time)
|
|
interval := val2.(duration.Duration)
|
|
|
|
// Add the interval to the timestamptz using the existing helper function
|
|
return intervalPlusNonInterval(interval, timestamptz)
|
|
},
|
|
}
|
|
|
|
// time_pl_interval represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var time_pl_interval = framework.Function2{
|
|
Name: "time_pl_interval",
|
|
Return: pgtypes.Time,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.Time, pgtypes.Interval},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
timeVal := val1.(timeofday.TimeOfDay)
|
|
interval := val2.(duration.Duration)
|
|
return timeVal.Add(interval), nil
|
|
},
|
|
}
|
|
|
|
// timetz_pl_interval represents the PostgreSQL function of the same name, taking the same parameters.
|
|
var timetz_pl_interval = framework.Function2{
|
|
Name: "timetz_pl_interval",
|
|
Return: pgtypes.TimeTZ,
|
|
Parameters: [2]*pgtypes.DoltgresType{pgtypes.TimeTZ, pgtypes.Interval},
|
|
Strict: true,
|
|
Callable: func(ctx *sql.Context, _ [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
|
|
timetzVal := val1.(timetz.TimeTZ)
|
|
interval := val2.(duration.Duration)
|
|
timetzVal.TimeOfDay = timetzVal.TimeOfDay.Add(interval)
|
|
return timetzVal, nil
|
|
},
|
|
}
|
|
|
|
// intervalPlusNonInterval adds given interval duration to the given time.Time value.
|
|
// During converting interval duration to time.Duration type, it can overflow.
|
|
func intervalPlusNonInterval(d duration.Duration, t time.Time) (time.Time, error) {
|
|
seconds, ok := d.AsInt64()
|
|
if !ok {
|
|
return time.Time{}, errors.Errorf("interval overflow")
|
|
}
|
|
nanos := float64(seconds) * functions.NanosPerSec
|
|
if nanos > float64(math.MaxInt64) || nanos < float64(math.MinInt64) {
|
|
return time.Time{}, errors.Errorf("interval overflow")
|
|
}
|
|
return t.Add(time.Duration(nanos)), nil
|
|
}
|