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

add UniqueIdentifier type #203

Merged
merged 3 commits into from
Jan 6, 2017

Conversation

bhcleek
Copy link
Contributor

@bhcleek bhcleek commented Jan 5, 2017

SQL Server's UniqueIdentifier type uses native endianness for some of
its fields within the UUID. Add a new type, UniqueIdentifier, that
correctly handles scanning based on the type of data being scanned.

Scanning a []byte swaps the bytes of the fields that SQL Server stores
using native endianness.

Scanning a string decodes the hex-encoded values without swapping any
bytes.

Implement fmt.Stringer so that the returned value of String is congruent
with the behavior of CAST(myuniqueidentifer AS varchar(36)).

SQL Server's UniqueIdentifier type uses native endianness for some of
its fields within the UUID. Add a new type, UniqueIdentifier, that
correctly handles scanning based on the type of data being scanned.

Scanning a []byte swaps the bytes of the fields that SQL Server stores
using native endianness.

Scanning a string decodes the hex-encoded values without swapping any
bytes.

Implement fmt.Stringer so that the returned value of String is congruent
with the behavior of CAST(myuniqueidentifer AS varchar(36)).

var nilUUID = make([]byte, 16) // RFC 4122 section 4.1.7 says a nil UUID is all zeros.

type UniqueIdentifier []byte
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this a slice rather than an array. I would expect:
type UUID [16]byte


switch vt := v.(type) {
case []byte:
if len(vt) != 16 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This check would go away then.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, you're correct about that this should remain.

}
}

*u = make(UniqueIdentifier, 16)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Then UUID wouldn't need an alloc.

if len(b) != 16 {
b = nilUUID
}
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
Copy link
Collaborator

Choose a reason for hiding this comment

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

In sql server, select newid(); returns letters in capitals.
Maybe fmt.Sprintf("%X-%X-%X-%X-%X", ...)

}

func (u UniqueIdentifier) Equal(u2 UniqueIdentifier) bool {
return bytes.Equal(u, u2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If an array, it would be return u == u2.

Change the underlying type of UniqueIdentifier to ([]byte -> [16]byte).

Changing the type to an array also allowed UniqueIdentifier.Equal to be
removed since array types are comparable.

Modify UniqueIdentifier.String to return a string that uses capitalized
hex encoding for closer parity with SQL Server's conversion of its
UniqueIdentifer type to character types.
@bhcleek
Copy link
Contributor Author

bhcleek commented Jan 5, 2017

Thanks for the feedback, @kardianos. The only suggestion that I wasn't comfortable taking was about eliminating the check for the length of the []byte in Scan; I don't see how changing the underlying type of UniqueIdentifier allows Scan to ignore the length of the []byte slice it's given.

PTAL

}

}
func TestUniqueIdentifierImplementsScanner(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove this test and add a line above the implementation:

var _ sql.Scanner = &UniqueIdentifier{}
var _  fmt.Stringer = UniqueIdentifier{}
var _ driver.Valuer = UniqueIdentifier{}


switch vt := v.(type) {
case []byte:
if len(vt) != 16 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, you're correct about that this should remain.

"fmt"
)

type UniqueIdentifier [16]byte
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we call this UUID? Or is there a reason not to? I'm not sure I care too much, but I can never seem to type UniqueIdentifier right if I'm not paying attention...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems more appropriate to me to keep the name congruent with the SQL Server data type that it represents.

Favor compile-time type checking over type assertion to verify interface
implementations of UniqueIdentifier.
@bhcleek
Copy link
Contributor Author

bhcleek commented Jan 5, 2017

PTAL

@kardianos kardianos merged commit 7a8f906 into denisenkom:master Jan 6, 2017
@bhcleek bhcleek deleted the add-unique-identifier-support branch January 6, 2017 18:04
gabrielcorado pushed a commit to gravitational/go-mssqldb that referenced this pull request Oct 4, 2024
* Vulnerabilty depency x/net

* Att Dependencies
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

Successfully merging this pull request may close these issues.

2 participants