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 Support for prepared statements #44

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

belevy
Copy link
Contributor

@belevy belevy commented Sep 24, 2021

This is definitely a first pass. I am not sure if this is the correct module structure or if the Value type is too "high level"

Some of the mysql_stmt_* functions don't have wrappers implemented yet but figured it was better to get something out there rather than just leaving it hiding on my computer.

@@ -132,11 +169,74 @@ toType v = IntMap.findWithDefault oops (fromIntegral v) typeMap
, ((#const MYSQL_TYPE_VAR_STRING), VarString)
, ((#const MYSQL_TYPE_STRING), String)
, ((#const MYSQL_TYPE_GEOMETRY), Geometry)
#if defined(MYSQL_TYPE_JSON)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems to actually be causing some issues and is why i ended up on this journey in the first place.

I think it is safe to remove since MYSQL_TYPE_JSON has been supported since 2015

withStatement statement $ \mysqlStmt -> do
throwErrnoIf_ (> 0) "mysql_stmt_execute" $ mysql_stmt_execute mysqlStmt

storeResult :: Statement -> IO ()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should this name overlap with the Base.storeResult or should it be storeResultStatement

Comment on lines +22 to 26
connectPort = 33306,
connectUser = "travis",
connectPassword = "esqutest",
connectDatabase = "esqutest",
connectOptions = [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

need to revert this. Was reusing my test db from esqueleto

@@ -28,6 +38,28 @@ main = bracket (connect testConn) close $ \conn -> hspec $ do
describe "Database" $ do
it "seems to be connected" $ do
query conn "select 1 + 1"
result <- useResult conn
result <- storeResult conn
Copy link
Contributor Author

Choose a reason for hiding this comment

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

when using useResult the connection would be left in an unusable state and prepare would fail. By switching to storeResult this issue went away.

| Blob ByteString
deriving (Eq, Show)

withValue :: Value -> (MYSQL_BIND -> IO a) -> IO a
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a better way to implement this or is this kind of boilerplate inevitable?

error err
pure $ Statement mysql stmt

withConn :: Statement -> (Ptr MYSQL -> IO a) -> IO a
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the pointer to the underlying MYSQL is only needed for a mysql_error call which is only relevant for mysql_stmt_close all other functions will call mysql_stmt_error

Should we stop holding on to the ref for the duration of the Statement? Is it possible for the Connection to get dropped if Statement doesn't hold it?

}

Decimal _ ->
error "Unsupported input type: Decimal"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we just treat this like a blob on input instead of throwing a runtime error?

@paul-rouse
Copy link
Owner

One thing which makes me nervous about this package is the lack of detailed tests. This hasn't been too serious up to now, since when I took over as maintainer, I reckoned that the only changes would be minor bug fixes and updated dependencies. However, if we're going to make changes involving several hundred lines of code, I think we would need to add full tests, both for the existing functionality (to make sure it isn't disturbed by the change) and for the new.

Can I ask whether you have looked at mysql-haskell? It supports prepared statements, and doesn't have the thread-safety problems of the C library. It's probably a better way to go in the long run, though I haven't yet had an opportunity to check out persistent-mysql-haskell. I'd be interested in any comments you have.

@belevy
Copy link
Contributor Author

belevy commented Sep 26, 2021

I Am definitely on board with the needing more tests. I was a bad and didn't save all the different things I tested as I was writing the code.

I have not had a look at mysql-haskell but I am wary about re implementing the wire format separate from the rest of the world. What thread-safety issues does the C library have and how are we sure that the haskell reimplementation doesn't have them?

@paul-rouse
Copy link
Owner

On the threading issues, these articles are both a little old, and I haven't checked whether more recent versions of the standard C client library change anything: https://ro-che.info/articles/2015-04-17-safe-concurrent-mysql-haskell and https://www.yesodweb.com/blog/2016/11/use-mysql-safely-in-yesod

I get the point about re-implementations vs. the "standard" library. There do seem to be a number of re-implementations, though (eg the node mysql module just to choose one at random).

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