-
-
Notifications
You must be signed in to change notification settings - Fork 17
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
Feature request: add multiple statements to a database #15
Comments
Looking at However, looking at Sect 53.2.2.1 of the Postgres manual, I see that it deals with this in a different way, by allowing queries to contain multiple statements. And the MySQL analogue appears to require only a single statement, with no way of breaking apart an unparsed tail. So I do appreciate that the issue here is probably one of finding a model that works with all of the various back-ends. A crude pre-parse of an SQL multi-statement string is not particularly pretty, but would seem to deal with all of the cases. |
As you said, the problem is in making it work on multiple systems. To add to the complexity you've already mentioned: the PostrgreSQL binding doesn't use the Simple query protocol; it only uses the Extended protocol, which doesn't support multiple statements. But the Extended protocol has a nice binary format for values, whereas the Simple protocol uses a textual format that would require a different (and complicated) set of parsers. So supporting both would be impractically complicated. Parsing the SQL (for 3+ dialects) in Racket would be a large amount of work to get right, and I don't want to add something only-mostly-kind-of-right. For the testing use case, since you have control over the SQL, you can pick a simple approximation to parsing (eg, just split on semicolons, if you never have semicolons within string constants, for example) that works locally. For loading bulk data, this library probably isn't a good fit, and you should probably use the database system's specialized command. (For example, PostgreSQL has COPY IN which is better for bulk data loading than many INSERTs, but this library doesn't support COPY IN.) It would be possible to add a public method only for sqlite3 connections that prepares the first statement from a string and returns the tail (or maybe returns a stream of statements, to avoid repeated allocation). |
Righto – it seems clear that there's no way of getting the underlying SQL system to do the multi-statement parsing in a portable way. I take your point about bulk data – I think the unit-test use-case is the more realistic one (though that could include a few INSERT statements). Thinking instead about a pre-parse, I believe this wouldn't have to be complicated, and need only be the ‘simple approximation to parsing’ that you mention. Hence, I've knocked together, and attached, a |
(...and of course I forgot a test case: extract-sql.rkt) |
thanks @nxg , I am using your module with some helper functions to run a directory of SQL migration files on a Here's some of my helper functions (require db sfri/26 "extract-sql.rkt")
(define (query-exec* conn . stmts)
(for ([stmt stmts])
(query-exec conn stmt)))
(define (query-exec-file conn path)
(apply query-exec* conn
(call-with-input-file path sql0-port->statements)))
(define (query-exec-all-files conn dir-path)
(define filepaths
(sort (map (cut build-path dir-path <>)
(directory-list dir-path))
path<?))
(for ([filepath filepaths])
(query-exec-file conn filepath))) |
Is there an easy way to load multiple statements from a .sql file into a database? I'm curious about bulk loading from Racket without parsing all the SQL. Just stuff it down the pipe? I think PostgresSQL supports multiple statements stuffed directly over the wire, if I understand the docs correctly. |
@winny- maybe try writing a shell one liner to execute your sql, then call that from Racket using |
Definitely could do the trick. For now here's my approach: (define/contract (sql->statements sql)
(-> string? (listof string?))
(regexp-split #px"\\s*;\\s*" sql)) I spotted this in the postgres docs. Not sure if this means it's technically possible to eschew parsing SQL while supporting multiple statements:
https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.6.7.4 |
The
query-exec
function will execute only a single SQL statement. There seems no way that I can see of adding multiple statements at once. Specifically, I would hope that something like the example below would work.The use-cases for this would be reloading a dump of data statements, or for loading DDL statements in the context of creating a fresh DB for unit tests.
Having
query-exec
accept multiple statements would be nice. An alternative API is theprepare
function in Chicken, which has the signaturewhich consumes one SQL statement from the given string, and returns the prepared statement and the rest of the string (I think it would be nicer if the second argument was a port). If the underlying API(s) is firmly constrained to accept only a single statement at a time, then a very simple SQL parser, which need only do just enough to break out the statements within a port, would be a suitable alternative.
The fact that the error below is
multiple statements given
indicates that the library can detect the presence of multiple statements. It would be attractive if it could do more with this than throw an error.The only workaround I can see is to use some other means (
sed
works) to break up a.sql
file into a list of strings. But that's not pretty.The text was updated successfully, but these errors were encountered: