[
https://issues.apache.org/jira/browse/IGNITE-4518?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Anghel Botos updated IGNITE-4518:
---------------------------------
Description:
Scenario:
* Cache entity with 3 key fields mapped to database as columns {{KC1}},
{{KC2}}, {{KC3}}
* The following data is in the database table {{MY_TABLE}} (the values 0 to 4
encoded as binary):
||KC1||KC2||KC3||
|0|0|0|
|0|0|1|
|0|1|0|
|0|1|1|
|1|0|0|
When running {{org.apache.ignite.IgniteCache#loadCache(null)}} (i.e. with no
custom SQL query arguments) the following happens:
* In {{org.apache.ignite.cache.store.jdbc.CacheAbstractJdbcStore#loadCache}},
the query produced by
{{org.apache.ignite.cache.store.jdbc.dialect.JdbcDialect#loadCacheSelectRangeQuery}}
is used to determine the range boundaries for the load. In our case the query
would be:
{{SELECT KC1,KC2,KC3 FROM (SELECT KC1,KC2,KC3, ROWNUM AS rn FROM (SELECT
KC1,KC2,KC3 FROM MY_TABLE ORDER BY KC1,KC2,KC3)) WHERE mod(rn, 2) = 0}} (I used
{{parallelLoadCacheMinThreshold=2}} just as an example so that the problem is
visible for this small data set).
The results of this query are:
||KC1||KC2||KC3||
|0|0|1|
|0|1|1|
(which is correct, due to https://issues.apache.org/jira/browse/IGNITE-4163
being fixed now)
These results will be used by
{{org.apache.ignite.cache.store.jdbc.CacheAbstractJdbcStore#loadCacheRange}} to
generate queries using
{{org.apache.ignite.cache.store.jdbc.dialect.JdbcDialect#loadCacheRangeQuery}}
which will be executed in parallel. Since there were 2 rows in the above
result, this means that the load will occur using 3 ranges/queries:
# No lower bound, upper bound using first row of the selectRangeQuery result
# Lower bound using the first row of the selectRangeQuery result, upper bound
using the second row of the selectRangeQuery result
# Lower bound using the second row of the selectRangeQuery result, no upper
bound
The queries are the following:
# {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 <= ?
OR KC1 = ? AND KC2 <= ? OR KC1 <= ? )}}
# {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ? OR
KC1 = ? AND KC2 > ? OR KC1 > ? ) AND (KC1 = ? AND KC2 = ? AND KC3 <= ? OR KC1
= ? AND KC2 <= ? OR KC1 <= ? )}}
# {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ? OR
KC1 = ? AND KC2 > ? OR KC1 > ? )}}
Replacing the first bound in the first query yields the following query:
{{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = 0 AND KC2 = 0 AND KC3 <= 1 OR
KC1 = 0 AND KC2 <= 0 OR KC1 <= 0 )}}, which executed, yields the following
results:
||KC1||KC2||KC3||
|0|0|0|
|0|0|1|
|0|1|0|
|0|1|1|
which is not correct, as the result set should have contained only 2 rows (due
to {{parallelLoadCacheMinThreshold=2}}). Something similar will happen also to
the second query (the one with both lower and upper bound).
The problem arises due to how the upper bound part of the WHERE clause is being
generated, namely the conditions when NOT ALL of the key columns are
constrained. These conditions should use *<* (strictly less), not *<=* (less or
equal).
The correct queries should be (please note the {{OR KC1 = ? AND KC2 < ? OR KC1
< ?}} part which makes the difference):
# {{SELECT KC1, KC2, KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 <= ?
OR KC1 = ? AND KC2 < ? OR KC1 < ? )}}
# {{SELECT KC1, KC2, KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ?
OR KC1 = ? AND KC2 > ? OR KC1 > ? ) AND (KC1 = ? AND KC2 = ? AND KC3 <= ? OR
KC1 = ? AND KC2 < ? OR KC1 < ? )}}
# {{SELECT KC1, KC2, KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ?
OR KC1 = ? AND KC2 > ? OR KC1 > ? )}}
My fix to generate the correct queries was to use the following code instead of
{{org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect#loadCacheRangeQuery:193-205}}:
{code}
sb.append("(");
for (int cnt = keyCols.size(); cnt > 0; cnt--) {
for (int j = 0; j < cnt; j++) {
if (j == cnt - 1) {
if (cnt == keyCols.size()) {
sb.append(cols[j]).append(" <= ? ");
} else {
sb.append(cols[j]).append(" < ? ");
}
} else {
sb.append(cols[j]).append(" = ? AND ");
}
}
if (cnt != 1) {
sb.append(" OR ");
}
}
sb.append(")");
{code}
was:
Scenario:
* Cache entity with 3 key fields mapped to database as columns {{KC1}},
{{KC2}}, {{KC3}}
* The following data is in the database table {{MY_TABLE}} (the values 0 to 4
encoded as binary):
||KC1||KC2||KC3||
|0|0|0|
|0|0|1|
|0|1|0|
|0|1|1|
|1|0|0|
When running {{org.apache.ignite.IgniteCache#loadCache(null)}} (i.e. with no
custom SQL query arguments) the following happens:
* In {{org.apache.ignite.cache.store.jdbc.CacheAbstractJdbcStore#loadCache}},
the query produced by
{{org.apache.ignite.cache.store.jdbc.dialect.JdbcDialect#loadCacheSelectRangeQuery}}
is used to determine the range boundaries for the load. In our case the query
would be:
{{SELECT KC1,KC2,KC3 FROM (SELECT KC1,KC2,KC3, ROWNUM AS rn FROM (SELECT
KC1,KC2,KC3 FROM MY_TABLE ORDER BY KC1,KC2,KC3)) WHERE mod(rn, 2) = 0}} (I used
{{parallelLoadCacheMinThreshold=2}} just as an example so that the problem is
visible for this small data set).
The results of this query are:
||KC1||KC2||KC3||
|0|0|1|
|0|1|1|
(which is correct, due to https://issues.apache.org/jira/browse/IGNITE-4163
being fixed now)
> Wrong WHERE clause generated by
> org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect#loadCacheRangeQuery
> for upper bounds
> --------------------------------------------------------------------------------------------------------------------------------
>
> Key: IGNITE-4518
> URL: https://issues.apache.org/jira/browse/IGNITE-4518
> Project: Ignite
> Issue Type: Bug
> Components: SQL
> Affects Versions: 1.8
> Reporter: Anghel Botos
>
> Scenario:
> * Cache entity with 3 key fields mapped to database as columns {{KC1}},
> {{KC2}}, {{KC3}}
> * The following data is in the database table {{MY_TABLE}} (the values 0 to 4
> encoded as binary):
> ||KC1||KC2||KC3||
> |0|0|0|
> |0|0|1|
> |0|1|0|
> |0|1|1|
> |1|0|0|
> When running {{org.apache.ignite.IgniteCache#loadCache(null)}} (i.e. with no
> custom SQL query arguments) the following happens:
> * In {{org.apache.ignite.cache.store.jdbc.CacheAbstractJdbcStore#loadCache}},
> the query produced by
> {{org.apache.ignite.cache.store.jdbc.dialect.JdbcDialect#loadCacheSelectRangeQuery}}
> is used to determine the range boundaries for the load. In our case the
> query would be:
> {{SELECT KC1,KC2,KC3 FROM (SELECT KC1,KC2,KC3, ROWNUM AS rn FROM (SELECT
> KC1,KC2,KC3 FROM MY_TABLE ORDER BY KC1,KC2,KC3)) WHERE mod(rn, 2) = 0}} (I
> used {{parallelLoadCacheMinThreshold=2}} just as an example so that the
> problem is visible for this small data set).
> The results of this query are:
> ||KC1||KC2||KC3||
> |0|0|1|
> |0|1|1|
> (which is correct, due to https://issues.apache.org/jira/browse/IGNITE-4163
> being fixed now)
> These results will be used by
> {{org.apache.ignite.cache.store.jdbc.CacheAbstractJdbcStore#loadCacheRange}}
> to generate queries using
> {{org.apache.ignite.cache.store.jdbc.dialect.JdbcDialect#loadCacheRangeQuery}}
> which will be executed in parallel. Since there were 2 rows in the above
> result, this means that the load will occur using 3 ranges/queries:
> # No lower bound, upper bound using first row of the selectRangeQuery result
> # Lower bound using the first row of the selectRangeQuery result, upper bound
> using the second row of the selectRangeQuery result
> # Lower bound using the second row of the selectRangeQuery result, no upper
> bound
> The queries are the following:
> # {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 <= ?
> OR KC1 = ? AND KC2 <= ? OR KC1 <= ? )}}
> # {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ?
> OR KC1 = ? AND KC2 > ? OR KC1 > ? ) AND (KC1 = ? AND KC2 = ? AND KC3 <= ? OR
> KC1 = ? AND KC2 <= ? OR KC1 <= ? )}}
> # {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ?
> OR KC1 = ? AND KC2 > ? OR KC1 > ? )}}
> Replacing the first bound in the first query yields the following query:
> {{SELECT KC1,KC2,KC3 FROM MY_TABLE WHERE (KC1 = 0 AND KC2 = 0 AND KC3 <= 1
> OR KC1 = 0 AND KC2 <= 0 OR KC1 <= 0 )}}, which executed, yields the
> following results:
> ||KC1||KC2||KC3||
> |0|0|0|
> |0|0|1|
> |0|1|0|
> |0|1|1|
> which is not correct, as the result set should have contained only 2 rows
> (due to {{parallelLoadCacheMinThreshold=2}}). Something similar will happen
> also to the second query (the one with both lower and upper bound).
> The problem arises due to how the upper bound part of the WHERE clause is
> being generated, namely the conditions when NOT ALL of the key columns are
> constrained. These conditions should use *<* (strictly less), not *<=* (less
> or equal).
> The correct queries should be (please note the {{OR KC1 = ? AND KC2 < ? OR
> KC1 < ?}} part which makes the difference):
> # {{SELECT KC1, KC2, KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 <=
> ? OR KC1 = ? AND KC2 < ? OR KC1 < ? )}}
> # {{SELECT KC1, KC2, KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ?
> OR KC1 = ? AND KC2 > ? OR KC1 > ? ) AND (KC1 = ? AND KC2 = ? AND KC3 <= ? OR
> KC1 = ? AND KC2 < ? OR KC1 < ? )}}
> # {{SELECT KC1, KC2, KC3 FROM MY_TABLE WHERE (KC1 = ? AND KC2 = ? AND KC3 > ?
> OR KC1 = ? AND KC2 > ? OR KC1 > ? )}}
> My fix to generate the correct queries was to use the following code instead
> of
> {{org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect#loadCacheRangeQuery:193-205}}:
> {code}
> sb.append("(");
> for (int cnt = keyCols.size(); cnt > 0; cnt--) {
> for (int j = 0; j < cnt; j++) {
> if (j == cnt - 1) {
> if (cnt == keyCols.size()) {
> sb.append(cols[j]).append(" <= ? ");
> } else {
> sb.append(cols[j]).append(" < ? ");
> }
> } else {
> sb.append(cols[j]).append(" = ? AND ");
> }
> }
> if (cnt != 1) {
> sb.append(" OR ");
> }
> }
> sb.append(")");
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)