lpsmith / postgresql-simple

Mid-level client library for accessing PostgreSQL from Haskell
Other
206 stars 71 forks source link

Getting back a prepared query without executing? #262

Open SnowySailor opened 6 years ago

SnowySailor commented 6 years ago

Is there currently any support for this? I want to build a large sql file and then have it run all at once instead of running queries live against a database as I'm reading in data because it gives me more control of what's happening and also allows for easier debugging. I see there's a function formatQuery but the documentation specifically says to not use it to prepare queries for execution. So is there any way to submit a query string and some parameters then get back a ByteString with all data in place that I can write to a file? If not, I think it would be a great addition. The Python library psycopg2 has it and it's been pretty good to me (it's called mogrify and it's run exactly like a normal query except it returns your prepared query instead of running it).

Thanks

lpsmith commented 5 years ago

That documentation is a holdover from MySQL. The only real issue with using formatQuery for your use case is that string escape syntax depends on the standard_conforming_strings parameter, which (for Postgresql >8.2 or whatever) is automatically set by postgresql-simple to on upon connection initialization. However, this is getting to be less and less of an issue as time goes on, as standard_conforming_strings is pretty much the standard going forward.

I actually have recently been using postgresql in a similar manner. I have been working on creating a modern version of a subset of the functionality contained in pgcrypto, as a postgresql server-side extension written in C, and have been using postgresql-simple in this fashion to track changes to the output of the C code.

Because I am using git as the primary way (so far) to compare differences in this generated SQL file, precise control over formatting etc. is important to me, so I've actually just resorted to using the lower-level Action interface, and simply using

renderQuery :: Connection -> Action -> IO ()
renderQuery conn action = do
  formatQuery conn "?" (Only action) >>= BS.putStr

This is actually a fairly flexible function; the way I'm using it, every call produces a single (often large) DML query. And, since my C extension currently depends on PostgreSQL 9.6 at a minimum, I don't really have to worry about standard_conforming_strings.