Closed ejschoen closed 8 years ago
Commit c62b6cd hasn't been released yet, are you building Korma from master yourself?
It is difficult to say what's wrong based on this information. I would first inspect the data produced by for
, it looks like semunit-id
is nil but of course this is just guessing.
I was building from master. Really just an experiment. I had wanted to add the ability to provide limit and offset arts to union (and union-all and intersect), which was trivial to do.
The data provided in the values call was correct. As I mentioned, all it took was printing the value that came from the for expression to make the insert work right. So I'm thinking it has something to do with being a lazy seq, but it's not clear why. A little more detail: the data that the for is iterating over comes from a prior select query. So, if there is some laziness involved, it might be the effect of generating values for the insert on data that hasn't yet been realized from the prior query. But it's still not clear to me why the code change in the commit would trigger this. (The behavior I'm observing is from our integration test suite, which runs flawlessly on released version 0.4.2.)
I'll try to make a reproducible case.
Thanks, Eric
On Sunday, January 24, 2016, Immo Heikkinen notifications@github.com wrote:
Commit c62b6cd https://github.com/korma/Korma/commit/c62b6cd665c01dfb7579ee937cc4baf5268ba84e hasn't been released yet, are you building Korma from master yourself?
It is difficult to say what's wrong based on this information. I would first inspect the data produced by for, it looks like semunit-id is nil but of course this is just guessing.
— Reply to this email directly or view it on GitHub https://github.com/korma/Korma/issues/341#issuecomment-174265992.
Yeah, I can reproduce with data that comes from select query that has has-many relation. Interesting.
It's as if the lazy seq isn't fully realized when the insert statement gets formed, but if so, this breaks my model of how Clojure lazy seqs work.
I was using an H2 DB for testing. However, if this had been a .NET environment and I had been using LINQ with entity framework, where queries are lazy, too, I would have recognized this as a multiple active result sets problem.
Thanks for looking into it. Eric
On Monday, January 25, 2016, Immo Heikkinen notifications@github.com wrote:
Yeah, I can reproduce with data that comes from select query that has has-many relation. Interesting.
— Reply to this email directly or view it on GitHub https://github.com/korma/Korma/issues/341#issuecomment-174420347.
I added a failing test for this, it can be found in branch https://github.com/korma/Korma/tree/issue_341_insert_bug. It gets even more weird, the test is supposed to insert 1 row but the error message shows that it is trying to insert 16 rows:
ERROR in (insert-based-on-select-with-relation) (DbException.java:345)
expected: (not (nil? (insert email (values data))))
actual: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "user_id"; SQL statement:
INSERT INTO "email" ("email_address", "user_id") VALUES (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL) [23502-187]
I guess that has something to do with lazy sequence chunk size.
The breaking commit is actually 62992975b60b45c6d0e07974fd2cddb4ce826eff (PR #330), not the one that you assumed.
Thanks! Your test failure is amazing weird. I wonder if it’s a JDBC behavior impacting Clojure.
Eric
On Jan 27, 2016, at 1:27 AM, Immo Heikkinen notifications@github.com wrote:
I added a failing test for this, it can be found in branch https://github.com/korma/Korma/tree/issue_341_insert_bug https://github.com/korma/Korma/tree/issue_341_insert_bug. It gets even more weird, the test is supposed to insert 1 row but the error message shows that it is trying to insert 16 rows:
ERROR in (insert-based-on-select-with-relation) (DbException.java:345) expected: (not (nil? (insert email (values data)))) actual: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "user_id"; SQL statement: INSERT INTO "email" ("email_address", "user_id") VALUES (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL), (NULL, NULL) [23502-187] I guess that has something to do with lazy sequence chunk size.
The breaking commit is actually 6299297 https://github.com/korma/Korma/commit/62992975b60b45c6d0e07974fd2cddb4ce826eff (PR #330 https://github.com/korma/Korma/pull/330), not the one that you assumed.
— Reply to this email directly or view it on GitHub https://github.com/korma/Korma/issues/341#issuecomment-175462755.
It is not JDBC issue. Adding this to the test case:
(prn (:values (query-only (insert email (values data)))))
outputs:
{:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil} {:user_id nil, :email_address nil}]
which means the data gets corrupted somewhere in Korma.
Ok, I think I finally understand what's going on. Modifying the test to:
(deftest insert-based-on-select-with-relation
(let [data (for [user-with-email (select user (with email))
[k v] (:email user-with-email)]
{k (str v)})]
;; This makes the test pass
;; (prn data)
(is (not (nil? (insert email (values data)))))
makes it fail with the following error message:
ERROR in (insert-based-on-select-with-relation) (DbException.java:345)
expected: (not (nil? (insert email (values data))))
actual: org.h2.jdbc.JdbcSQLException: Column "alias" not found; SQL statement:
INSERT INTO "email" ("alias", "aliases", "db", "ent", "fields", "from", "group", "joins", "modifiers", "order", "params", "results", "sql-str", "table", "type", "where") VALUES (NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?), (NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL), (NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL), (?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL), (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, NULL, NULL, NULL, NULL) [42122-187]
This reveals that the value of :email
key is the query map for selecting emails for user instead of rows from email table. This is caused by change 6299297 which binds :query
to exec-mode
so that queries can be composed, unfortunately this doesn't play well with lazy sequences. (http://cemerick.com/2009/11/03/be-mindful-of-clojures-binding/ is a very good blog post about it.)
The fix is to revert commit 6299297.
For what it's worth, I think this change is creating an insert issue for me. Sorry that this isn't a particularly concrete bug report with a repro... I'll see if I can gen one up. In the mean time, what I am seeing is that when the values to insert come from a
for
block applied to some other data, the resulting insert statement is corrupt. For example, I am trying to insert into a many-to-many association table. The data to be inserted comes from:where
foo
is bound to:The resulting insert statement is:
I then get a SQL error because I'm trying to insert
NULL
into a non-nullable column. I was curious if something was wrong with the insert values, so I inserted a(pprint foo)
into the code, and the error and corrupt statement vanish. So, something to do with an unrealized lazy seq? (But testingfoo
for realized? returnedtrue
).Thanks, Eric