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

core: added scanning for results #1246

Merged
merged 1 commit into from
Jan 20, 2025
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
31 changes: 16 additions & 15 deletions core/types/data_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"regexp"
"strconv"
"strings"

"github.com/kwilteam/kwil-db/core/types/decimal"
)

// DataType is a data type.
Expand Down Expand Up @@ -144,7 +142,7 @@ func (c *DataType) PGScalar() (string, error) {
scalar = "UINT256"
case NumericStr:
if !c.HasMetadata() {
return "", errors.New("decimal type requires metadata")
return "", errors.New("numeric type requires metadata")
} else {
scalar = fmt.Sprintf("NUMERIC(%d,%d)", c.Metadata[0], c.Metadata[1])
}
Expand Down Expand Up @@ -174,7 +172,7 @@ func (c *DataType) Clean() error {
if !c.HasMetadata() {
return fmt.Errorf("type %s requires metadata", c.Name)
}
err := decimal.CheckPrecisionAndScale(c.Metadata[0], c.Metadata[1])
err := CheckDecimalPrecisionAndScale(c.Metadata[0], c.Metadata[1])
if err != nil {
return err
}
Expand Down Expand Up @@ -263,14 +261,14 @@ var (
Name: uuidStr,
}
UUIDArrayType = ArrayType(UUIDType)
// DecimalType contains 1,0 metadata.
// NumericType contains 1,0 metadata.
// For type detection, users should prefer compare a datatype
// name with the DecimalStr constant.
DecimalType = &DataType{
// name with the NumericStr constant.
NumericType = &DataType{
Name: NumericStr,
Metadata: [2]uint16{0, 0}, // unspecified precision and scale
}
DecimalArrayType = ArrayType(DecimalType)
NumericArrayType = ArrayType(NumericType)
Uint256Type = &DataType{
Name: uint256Str, // TODO: delete
}
Expand Down Expand Up @@ -307,9 +305,9 @@ const (
nullStr = "null"
)

// NewDecimalType creates a new fixed point decimal type.
func NewDecimalType(precision, scale uint16) (*DataType, error) {
err := decimal.CheckPrecisionAndScale(precision, scale)
// NewNumericType creates a new fixed point numeric type.
func NewNumericType(precision, scale uint16) (*DataType, error) {
err := CheckDecimalPrecisionAndScale(precision, scale)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -351,21 +349,24 @@ func ParseDataType(s string) (*DataType, error) {
var metadata [2]uint16
if rawMetadata != "" {
metadata = [2]uint16{}
// only decimal types can have metadata
// only numeric types can have metadata
if baseName != NumericStr {
return nil, fmt.Errorf("metadata is only allowed for decimal type")
return nil, fmt.Errorf("metadata is only allowed for numeric type")
}

parts := strings.Split(rawMetadata, ",")
// can be either DECIMAL(10,5) or just DECIMAL
if len(parts) != 2 && len(parts) != 0 {
// must be either NUMERIC(10,5)
if len(parts) != 2 {
return nil, fmt.Errorf("invalid metadata format: %s", rawMetadata)
}
for i, part := range parts {
num, err := strconv.Atoi(strings.TrimSpace(part))
if err != nil {
return nil, fmt.Errorf("invalid metadata value: %s", part)
}
if num > int(maxPrecision) {
return nil, fmt.Errorf("precision must be less than %d", maxPrecision)
}
metadata[i] = uint16(num)
}
}
Expand Down
67 changes: 38 additions & 29 deletions core/types/decimal/decimal.go → core/types/decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// It is mostly a wrapper around github.com/cockroachdb/apd/v3, with some
// functionality that makes it easier to use in the context of Kwil. It enforces
// certain semantics of Postgres's decimal, such as precision and scale.
package decimal
package types

import (
"database/sql"
Expand Down Expand Up @@ -44,9 +44,9 @@ type Decimal struct {
precision uint16
}

// NewExplicit creates a new Decimal from a string, with an explicit precision and scale.
// NewDecimalExplicit creates a new Decimal from a string, with an explicit precision and scale.
// The precision must be between 1 and 1000, and the scale must be between 0 and precision.
func NewExplicit(s string, precision, scale uint16) (*Decimal, error) {
func NewDecimalExplicit(s string, precision, scale uint16) (*Decimal, error) {
dec := &Decimal{}

if err := dec.SetPrecisionAndScale(precision, scale); err != nil {
Expand All @@ -60,16 +60,25 @@ func NewExplicit(s string, precision, scale uint16) (*Decimal, error) {
return dec, nil
}

// NewFromString creates a new Decimal from a string. It automatically infers the precision and scale.
func NewFromString(s string) (*Decimal, error) {
// ParseDecimal creates a new Decimal from a string. It automatically infers the precision and scale.
func ParseDecimal(s string) (*Decimal, error) {
inferredPrecision, inferredScale := inferPrecisionAndScale(s)

return NewExplicit(s, inferredPrecision, inferredScale)
return NewDecimalExplicit(s, inferredPrecision, inferredScale)
}

// NewFromBigInt creates a new Decimal from a big.Int and an exponent.
// MustParseDecimal is like ParseDecimal but panics if the string cannot be parsed.
func MustParseDecimal(s string) *Decimal {
dec, err := ParseDecimal(s)
if err != nil {
panic(err)
}
return dec
}

// NewDecimalFromBigInt creates a new Decimal from a big.Int and an exponent.
// The negative of the exponent is the scale of the decimal.
func NewFromBigInt(i *big.Int, exp int32) (*Decimal, error) {
func NewDecimalFromBigInt(i *big.Int, exp int32) (*Decimal, error) {
if exp > 0 {
i2 := big.NewInt(10)
i2.Exp(i2, big.NewInt(int64(exp)), nil)
Expand Down Expand Up @@ -98,15 +107,15 @@ func NewFromBigInt(i *big.Int, exp int32) (*Decimal, error) {
dec.precision = dec.scale
}

if err := CheckPrecisionAndScale(dec.precision, dec.scale); err != nil {
if err := CheckDecimalPrecisionAndScale(dec.precision, dec.scale); err != nil {
return nil, err
}

return dec, nil
}

// NewNaN creates a new NaN Decimal.
func NewNaN() *Decimal {
// NewNaNDecimal creates a new NaN Decimal.
func NewNaNDecimal() *Decimal {
return &Decimal{
dec: apd.Decimal{
Form: apd.NaN,
Expand Down Expand Up @@ -193,7 +202,7 @@ func (d *Decimal) setScale(scale uint16) error {
// SetPrecisionAndScale sets the precision and scale of the decimal.
// The precision must be between 1 and 1000, and the scale must be between 0 and precision.
func (d *Decimal) SetPrecisionAndScale(precision, scale uint16) error {
if err := CheckPrecisionAndScale(precision, scale); err != nil {
if err := CheckDecimalPrecisionAndScale(precision, scale); err != nil {
return err
}

Expand Down Expand Up @@ -340,7 +349,7 @@ func (d *Decimal) Scan(src interface{}) error {
}

// set scale and prec from the string
d2, err := NewFromString(s)
d2, err := ParseDecimal(s)
if err != nil {
return err
}
Expand Down Expand Up @@ -468,44 +477,44 @@ func (d *Decimal) enforceScale() error {
return err
}

// Add adds two decimals together.
// DecimalAdd adds two decimals together.
// It will return a decimal with maximum precision and scale.
func Add(x, y *Decimal) (*Decimal, error) {
func DecimalAdd(x, y *Decimal) (*Decimal, error) {
return mathOp(x, y, context.Add)
}

// Sub subtracts y from x.
// DecimalSub subtracts y from x.
// It will return a decimal with maximum precision and scale.
func Sub(x, y *Decimal) (*Decimal, error) {
func DecimalSub(x, y *Decimal) (*Decimal, error) {
return mathOp(x, y, context.Sub)
}

// Mul multiplies two decimals together.
// DecimalMul multiplies two decimals together.
// It will return a decimal with maximum precision and scale.
func Mul(x, y *Decimal) (*Decimal, error) {
func DecimalMul(x, y *Decimal) (*Decimal, error) {
return mathOp(x, y, context.Mul)
}

// Div divides x by y.
// DecimalDiv divides x by y.
// It will return a decimal with maximum precision and scale.
func Div(x, y *Decimal) (*Decimal, error) {
func DecimalDiv(x, y *Decimal) (*Decimal, error) {
return mathOp(x, y, context.Quo)
}

// Mod returns the remainder of x divided by y.
// DecimalMod returns the remainder of x divided by y.
// It will return a decimal with maximum precision and scale.
func Mod(x, y *Decimal) (*Decimal, error) {
func DecimalMod(x, y *Decimal) (*Decimal, error) {
return mathOp(x, y, context.Rem)
}

// Pow raises x to the power of y.
func Pow(x, y *Decimal) (*Decimal, error) {
// DecimalPow raises x to the power of y.
func DecimalPow(x, y *Decimal) (*Decimal, error) {
return mathOp(x, y, context.Pow)
}

// Cmp compares two decimals.
// DecimalCmp compares two decimals.
// It returns -1 if x < y, 0 if x == y, and 1 if x > y.
func Cmp(x, y *Decimal) (int64, error) {
func DecimalCmp(x, y *Decimal) (int64, error) {
z := apd.New(0, 0)
_, err := context.Cmp(z, &x.dec, &y.dec)
if err != nil {
Expand All @@ -516,8 +525,8 @@ func Cmp(x, y *Decimal) (int64, error) {
// return x.dec.Cmp(&y.dec)
}

// CheckPrecisionAndScale checks if the precision and scale are valid.
func CheckPrecisionAndScale(precision, scale uint16) error {
// CheckDecimalPrecisionAndScale checks if the precision and scale are valid.
func CheckDecimalPrecisionAndScale(precision, scale uint16) error {
if precision < 1 {
return fmt.Errorf("precision must be at least 1: %d", precision)
}
Expand Down
Loading
Loading