Skip to content

Use string rather than []byte for types.JSON #301

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

Closed
wants to merge 1 commit into from

Conversation

dterei
Copy link

@dterei dterei commented Jun 7, 2018

This fixes an issue with MySQL that doesn't accept []byte (mapped to binary in MySQL) as a valid type for JSON columns due to the lack of character encoding information.

Ideally, the Golang SQL driver should have an explicit JSON type so that this can be pushed down to the drivers to handle. However, sadly the driver interface doesn't support this and we must collapse to either []byte or string. I believe string should work across all databases for JSON.

This fixes an issue with MySQL that doesn't accept []byte (mapped to
binary in MySQL) as a valid type for JSON columns due to the lack of
character encoding information.
@dterei
Copy link
Author

dterei commented Jun 7, 2018

Oh, to replicate this bug, need the following three conditions:

  1. MySQL
  2. Column with JSON type
  3. Use interpolateParams=true in go-sql-drivers/mysql config

Then, just run the SQLBoiler tests for generated code and Inserts will fail with:

unable to upsert for t: Error 3144: Cannot create a JSON value from a string with CHARACTER SET 'binary'

Some relevant MySQL bugs on the binary string for JSON column issue.

@aarondl
Copy link
Member

aarondl commented Jun 11, 2018

I saw this as soon as you opened it, apologies for not having replied sooner. The problem is I didn't know what to do with it. It's another one of these "mysql ruins everything" bugs (which are surprisingly frequent). The proper type for JSON in Go is []byte. In the end this sounds like a mysql driver bug to me.

Allow me to elaborate: You have turned on interpolateParams=true presumably for performance which already makes me cautious in accepting the PR because it's not the normal configuration for the mysql driver. However, this means that instead of using prepared statements and asking the database to do all the heavy lifting in terms of types and parameter replacement, the mysql driver library itself is doing it.

Now mysql happens to have an annoying bug which they should probably actually fix since as reported there's many people who can't import their exported schemas (which is kind of funny). And we have a driver whose job it is to interface with that broken database but when we use the driver in a way that is seemingly normal for the language we're using it breaks. Literally it'd be beneficial for all users of that database if it were fixed in their driver, instead of just in sqlboiler.

Lastly, you might ask why I would resist such a seemingly innocuous change to begin with. The main reason is: I don't like making concessions for a single database engine where I don't have to because at the end of the day maybe the JSON column in postgres or mssql must be a []byte (sounded like we haven't tested, we really need our CI back, ugh). Or worse, maybe a database engine we're planning to add sqlite or cockroachdb requires it and one day we'll have to consider reverting (as it's most likely Go drivers for any database will want []byte not string given the interface of the json package).

So in order to get this change through there's two conditions:

  1. We need to talk to the go-mysql-driver people and ask them if they can't fix this.
  2. We need to test with the above databases to ensure that it's not going to break anyone.

In the case where it breaks the other database engines, we'll have no choice but to use a new JSON type for this. v3 has the ability to replace types and it's nearing release. Until then hopefully you can keep hanging on with your fork.

Sorry for making this tough. I bet never in a million years did you imagine this kind of response when you changed just a few characters haha. I feel bad about it :(

@dterei
Copy link
Author

dterei commented Jun 11, 2018 via email

@aarondl
Copy link
Member

aarondl commented Jun 11, 2018

I'm fairly sure they have reasonable control over conversions these days in the sql/driver package. NamedValueChecker is one way, and the ValueConverter is another. (Though NamedValueChecker isn't really a solution in our case).

I haven't played around with the driver interfaces in a long while but I do know that these are new and were designed to tackle this exact problem.

If I were you I'd definitely raise an issue on the go-mysql-driver lib and see if nothing can be done. They probably understand their options a little bit better than I do. Not sure unless we ask :D

Thanks for being so understanding. I'm going to close this PR for now (like the issue list to stay relatively clean), but if you remember to please update here if there's any movement on the issue in general :)

@dterei
Copy link
Author

dterei commented Jun 17, 2018

@aarondl Just to close, the go-sql-driver/mysql folks think using string is best. I think we'll just avoid interpolateParams for the short-term. How far out do you think V3 is?

@aarondl
Copy link
Member

aarondl commented Jun 17, 2018

Around the corner. I plan on making very few changes to the current v3.0.0-rc2 tag. I'm just working on videos to go along with the release before announcing.

@aarondl
Copy link
Member

aarondl commented Jun 17, 2018

That's to say don't wait. You can use it now. I'll be very responsive to any issues during this time.

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