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

Unexpected behavior of Timestamp fraction precision #173

Closed
bancek opened this issue Dec 17, 2020 · 2 comments
Closed

Unexpected behavior of Timestamp fraction precision #173

bancek opened this issue Dec 17, 2020 · 2 comments

Comments

@bancek
Copy link
Contributor

bancek commented Dec 17, 2020

Amazon QLDB fails to insert a timestamp if fraction precision is 3 and milliseconds are divisible by 10.

Example:

type Entry struct {
	Time ion.Timestamp `ion:"time"`
}

millis := int64(1608218715340)
t := time.Unix(0, millis*1000000)
ts := ion.NewTimestampWithFractionalSeconds(t, ion.TimestampPrecisionNanosecond, ion.TimezoneUTC, 3)

entry := Entry{
	Time: ts,
}

_, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
	return txn.Execute("INSERT INTO Test ?", entry)
})

The error from Amazon QLDB is

BadRequestException: Digests don't match
{
  RespMetadata: {
    StatusCode: 400,
    RequestID: "3GH3JFguR5O3LLcAwTQiiN"
  },
  Code_: "412",
  Message_: "Digests don't match"
}

Is this an expected behavior?

I've fixed this with a helper to calculate the fraction precision but I would expect the ion-go library to do automatically.

func getFractionPrecision(t time.Time) uint8 {
	millis := (t.UnixNano() / 1000000) % 1000
	fractionPrecision := uint8(3)

	if millis == 0 {
		fractionPrecision = 0
	} else {
		for millis > 0 && (millis%10) == 0 {
			millis /= 10
			fractionPrecision--
		}
	}

	return fractionPrecision
}

This is also a problem when using time.Time in a struct and setting it to time.Now().UTC(). It fails with same error Digests don't match.

Full example:

package main

import (
	"context"
	"time"

	"github.com/amzn/ion-go/ion"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/qldbsession"
	"github.com/awslabs/amazon-qldb-driver-go/qldbdriver"
)

func main() {
	awsSession := session.Must(session.NewSession(aws.NewConfig().WithRegion("us-east-1")))
	qldbSession := qldbsession.New(awsSession)

	driver, err := qldbdriver.New(
		"quick-start",
		qldbSession,
		func(options *qldbdriver.DriverOptions) {
			options.LoggerVerbosity = qldbdriver.LogInfo
		})
	if err != nil {
		panic(err)
	}
	defer driver.Shutdown(context.Background())

	_, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
		_, err := txn.Execute("CREATE TABLE Test")
		if err != nil {
			return nil, err
		}
		return nil, nil
	})
	if err != nil {
		panic(err)
	}

	type Entry struct {
		Time ion.Timestamp `ion:"time"`
	}

	millis := int64(1608218715340)
	t := time.Unix(0, millis*1000000)
	ts := ion.NewTimestampWithFractionalSeconds(t, ion.TimestampPrecisionNanosecond, ion.TimezoneUTC, 3)

	entry := Entry{
		Time: ts,
	}

	_, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
		return txn.Execute("INSERT INTO Test ?", entry)
	})
	if err != nil {
		panic(err)
	}
}

Versions:

github.com/amzn/ion-go v1.1.0
github.com/amzn/ion-hash-go v1.1.0
github.com/aws/aws-sdk-go v1.36.8
github.com/awslabs/amazon-qldb-driver-go v1.0.1
@byronlin13
Copy link
Contributor

Hi @bancek ,

We have released a new version of the Go driver that fixes this bug.

@bancek
Copy link
Contributor Author

bancek commented Jun 16, 2021

Thanks 🎉

@bancek bancek closed this as completed Jun 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants