honeysql

liebs 2023-10-17T15:33:54.528389Z

so I have this vector of HoneySQL syntax

[[:constraint :FKPostedBy] [:foreign-key :PostedBy] [:references :User :Person]]
that outputs this SQL:
CONSTRAINT FKPostedBy FOREIGN KEY(PostedBy) REFERENCES User(Person)
which seems to accord with SQL Server documentation on the subject of foreign keys...but the DB itself says incorrect syntax near 'User'. I have other constraints formatted precisely the same it accepts, however. Any ideas about what I'm missing?

liebs 2023-10-17T15:38:31.365499Z

Could it be there's a conflict between the table I'm referencing and one of the internal tables used by SQL Server for database users? I suppose if that's so I could disambiguate by providing the schema...

seancorfield 2023-10-17T16:09:57.677849Z

I think you need :quoted true

liebs 2023-10-17T16:19:08.860409Z

oh nice! That was it. I was trying :raw which did get me past the syntax error as well.

seancorfield 2023-10-17T17:38:22.231429Z

:raw should pretty much always be a last resort at this point...

liebs 2023-10-17T17:38:40.551189Z

duly noted! 🫡

liebs 2023-10-17T22:41:10.224189Z

Question: when dealing with PreparedStatements is it better to just go for handwriting a string of SQL? I just ran into a problem the solution to which is clear in hindsight but I spent some time overlooking, namely that HoneySQL, given something like

(sql/format {:insert-into :a-table
             :columns [:a-column :another]
             :values [[1 :foo] [2 :bar]]})
it produces multiple sets of (?, ?) in the resulting string. But as far as I can tell, PreparedStatement only ever wants one of those, is that correct?

seancorfield 2023-10-17T22:43:24.550859Z

The short answer is: no, not correct. Can you back up and explain more of the context and whether you've actually run into a problem?

seancorfield 2023-10-17T22:44:30.165989Z

PreparedStatement has nothing to do with HoneySQL, so it seems you're asking about some next.jdbc issue here really?

liebs 2023-10-17T22:45:50.574579Z

yeah, the root of the problem for me originated in JDBC but I think I was using the HoneySQL DDL in a manner that was producing a SQL string that JDBC didn't like

seancorfield 2023-10-17T22:46:10.861099Z

DDL != SQL -- you mean DSL?

liebs 2023-10-17T22:46:23.730929Z

yes

seancorfield 2023-10-17T22:46:48.631189Z

OK, so you have some vector with SQL + params and how are you processing that?

seancorfield 2023-10-17T22:46:51.927919Z

(show code)

seancorfield 2023-10-17T22:48:16.180089Z

Which database? Which driver? Versions of both? What exactly is the error you get? Is this for next.jdbc or c.j.j?

liebs 2023-10-17T22:52:52.043709Z

I had a vector of seqs of data like

[(1,2,3),(4,5,6)...]
that I was passing into the :values key like so
{:insert-into :a-table
             :columns [:a-column :another :a-third]
             :values [(1,2,3),(4,5,6)]}
and it was producing
["INSERT INTO a-table (a-column, another, a third) values (?, ?, ?), (?,?,?)"]
which SQL Server (unfortunately a literally archaic version, 2012) doesn't like. But it gives me this error
the conversion from UNKNOWN to UNKNOWN is unsupported

liebs 2023-10-17T22:53:47.593479Z

What I ended up doing is only using the :insert-into and :columns keys and adding the rest by hand

liebs 2023-10-17T22:53:51.379869Z

which works

seancorfield 2023-10-17T22:53:59.743509Z

> and it was producing Presumably with 1 2 3 4 5 6 in that vector as well?

seancorfield 2023-10-17T22:54:28.233679Z

You're still not describing any of the JDBC side of this -- HoneySQL does not execute SQL.

liebs 2023-10-17T22:56:30.238589Z

this is the non-working code

(let [[sql & param-groups]  (sql/format insert-pop-data :quoted true)]
    (try (jdbc/execute-batch! ds sql [(partition 26 param-groups)] {:batch-size 100
                                                                    :return-keys true})
         (catch SQLServerException e
           (Throwable->map e))))
and this is what works
(with-open [conn (jdbc/get-connection ds)
              stmt (jdbc/prepare conn insert-pop-data)]
    (jdbc/execute-batch! stmt test-data {:batch-size 100
                                         :return-keys true}))

seancorfield 2023-10-17T22:57:39.324999Z

OK, execute-batch! is kind of weird -- it doesn't take a standard [SQL+params]` vector

seancorfield 2023-10-17T22:58:16.205229Z

If you use regular execute!, the generated HoneySQL stuff works, but that won't necessarily get you the fast batch insertion.

liebs 2023-10-17T22:59:16.114509Z

yeah I moved to execute-batch! from execute! because I was hitting the TDS parameter limit

seancorfield 2023-10-17T23:00:54.909529Z

What you can do in have a HoneySQL DSL with just one row of (dummy) data -- dummy, since you'll throw it away -- and generate [SQL+params] which will have the dummy params and then use the SQL portion with a partition of your original data. But you can't just pass all that data into HoneySQL if your target is execute-batch!

seancorfield 2023-10-17T23:02:30.677149Z

The issue is that the SQL needed for execute-batch! is as-if you are inserting only one row, but then you pass multiple rows to execute-batch! itself and it does the "magic" behind the scenes.

seancorfield 2023-10-17T23:03:35.706979Z

execute! uses PreparedStatement and .execute() under the hood so this is not a limitation of PreparedStatement. execute-batch! uses .executeBatch() under the hood so it's different at the JDBC level.

👀 1
liebs 2023-10-17T23:03:45.987519Z

somewhat awful but the hack I did was

(-> (sql/format {:insert-into :table
                 :columns [:a, :b, :c]}
   first
   (str " VALUES (?,?,?)")
   vector)
which does work but is surely not great

seancorfield 2023-10-17T23:04:19.372429Z

That is certainly up there on the list of things which are "not great", yes 😄

seancorfield 2023-10-17T23:05:06.586339Z

:values [(first data)] where data is all your rows.

seancorfield 2023-10-17T23:05:57.521969Z

Just watch out for nil and true / false getting generated inline...

seancorfield 2023-10-17T23:06:05.547749Z

OK, gotta run.

liebs 2023-10-17T23:06:15.036979Z

I spent a long time banging my head against the wall over this, largely due to that stunningly opaque error cited above, so thank you for your help and insight!

seancorfield 2023-10-17T23:22:09.872679Z

Yeah, SQL Server (or its driver) is being spectacularly unhelpful there...

seancorfield 2023-10-17T23:26:33.327819Z

Unfortunately, this is just one of those JDBC oddities for which there is no really good solution re: HoneySQL since it is a generic formatter. As you can see, if you start with a vector of vectors (rows) of data, it's that vector you need to pass to execute-batch! and the parameters in the SQL+params vector produced by HoneySQL really don't matter (after all, why would you pass vector of vectors to HoneySQL only to have it unroll them into that SQL+params data again?).

seancorfield 2023-10-17T23:26:49.307199Z

Anyways, off to the gym now for real.