Skip to content

Commit 1cc496a

Browse files
committed
Implementation of InListJdbcPrm
1 parent 7e1b9f1 commit 1cc496a

File tree

10 files changed

+461
-67
lines changed

10 files changed

+461
-67
lines changed

jdbc/src/main/java/tech/ydb/jdbc/query/QueryStatement.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import java.util.ArrayList;
55
import java.util.List;
6-
import java.util.function.Supplier;
76

87
import tech.ydb.jdbc.query.params.JdbcPrm;
98

@@ -15,7 +14,7 @@
1514
public class QueryStatement {
1615
private final QueryType queryType;
1716
private final QueryCmd command;
18-
private final List<Supplier<JdbcPrm>> parameters = new ArrayList<>();
17+
private final List<JdbcPrm.Factory> parameters = new ArrayList<>();
1918
private boolean hasReturinng = false;
2019

2120
public QueryStatement(QueryType custom, QueryType baseType, QueryCmd command) {
@@ -31,11 +30,15 @@ public QueryCmd getCmd() {
3130
return command;
3231
}
3332

34-
public List<Supplier<JdbcPrm>> getParams() {
33+
public boolean hasJdbcParameters() {
34+
return !parameters.isEmpty();
35+
}
36+
37+
public List<JdbcPrm.Factory> getJdbcPrmFactories() {
3538
return parameters;
3639
}
3740

38-
public void addParameter(Supplier<JdbcPrm> prm) {
41+
public void addJdbcPrmFactory(JdbcPrm.Factory prm) {
3942
this.parameters.add(prm);
4043
}
4144

jdbc/src/main/java/tech/ydb/jdbc/query/YdbQuery.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ public class YdbQuery {
2727
this.type = type;
2828
this.batcher = batcher;
2929

30-
boolean hasJdbcParamters = false;
30+
boolean hasJdbcParameters = false;
3131
for (QueryStatement st: statements) {
32-
hasJdbcParamters = hasJdbcParamters || !st.getParams().isEmpty();
32+
hasJdbcParameters = hasJdbcParameters || st.hasJdbcParameters();
3333
}
34-
this.isPlainYQL = !hasJdbcParamters;
34+
this.isPlainYQL = !hasJdbcParameters;
3535
}
3636

3737
public QueryType getType() {

jdbc/src/main/java/tech/ydb/jdbc/query/YdbQueryParser.java

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
import java.util.List;
88

99
import tech.ydb.jdbc.YdbConst;
10-
import tech.ydb.jdbc.query.params.SimpleJdbcPrm;
11-
import tech.ydb.jdbc.query.params.UInt64JdbcPrm;
10+
import tech.ydb.jdbc.query.params.JdbcPrm;
1211

1312

1413
/**
@@ -117,7 +116,7 @@ public String parseSQL() throws SQLException {
117116
i++; // make sure the coming ? is not treated as a bind
118117
} else {
119118
String name = nextJdbcPrmName();
120-
statement.addParameter(SimpleJdbcPrm.withName(name));
119+
statement.addJdbcPrmFactory(JdbcPrm.simplePrm(name));
121120
parsed.append(name);
122121
batcher.readParameter();
123122
}
@@ -158,6 +157,15 @@ public String parseSQL() throws SQLException {
158157
fragmentStart = i;
159158
}
160159
}
160+
161+
// Process IN (?, ?, ... )
162+
if (i < chars.length && detectJdbcArgs && isConvertJdbcInToList) {
163+
if (parseInKeyword(chars, keywordStart, keywordLength)) {
164+
parsed.append(chars, fragmentStart, i - fragmentStart);
165+
i = parseInListParameters(chars, i, statement);
166+
fragmentStart = i;
167+
}
168+
}
161169
} else {
162170
boolean skipped = false;
163171
if (isDetectQueryType) {
@@ -297,7 +305,63 @@ private int parseOffsetLimitParameter(char[] query, int offset, QueryStatement s
297305
String name = nextJdbcPrmName();
298306
parsed.append(query, start, offset - start);
299307
parsed.append(name);
300-
st.addParameter(UInt64JdbcPrm.withName(name));
308+
st.addJdbcPrmFactory(JdbcPrm.uint64Prm(name));
309+
return offset + 1;
310+
case '-': // possibly -- style comment
311+
offset = parseLineComment(query, offset);
312+
break;
313+
case '/': // possibly /* */ style comment
314+
offset = parseBlockComment(query, offset);
315+
break;
316+
default:
317+
if (!Character.isWhitespace(query[offset])) {
318+
return start;
319+
}
320+
break;
321+
}
322+
}
323+
324+
return start;
325+
}
326+
327+
private int parseInListParameters(char[] query, int offset, QueryStatement st) {
328+
int start = offset;
329+
int listStartedAt = -1;
330+
int listSize = 0;
331+
boolean waitPrm = false;
332+
while (offset < query.length) {
333+
char ch = query[offset];
334+
switch (ch) {
335+
case '(': // start of list
336+
if (listStartedAt >= 0) {
337+
return start;
338+
}
339+
listStartedAt = offset;
340+
waitPrm = true;
341+
break;
342+
case ',':
343+
if (listStartedAt < 0 || waitPrm) {
344+
return start;
345+
}
346+
waitPrm = true;
347+
break;
348+
case '?' :
349+
if (!waitPrm || (offset + 1 < query.length && query[offset + 1] == '?')) {
350+
return start;
351+
}
352+
listSize++;
353+
waitPrm = false;
354+
break;
355+
case ')':
356+
if (waitPrm || listSize == 0 || listStartedAt < 0) {
357+
return start;
358+
}
359+
360+
String name = nextJdbcPrmName();
361+
parsed.append(query, start, listStartedAt - start);
362+
parsed.append(' '); // add extra space to avoid IN$jpN
363+
parsed.append(name);
364+
st.addJdbcPrmFactory(JdbcPrm.inListOrm(name, listSize));
301365
return offset + 1;
302366
case '-': // possibly -- style comment
303367
offset = parseLineComment(query, offset);
@@ -311,6 +375,7 @@ private int parseOffsetLimitParameter(char[] query, int offset, QueryStatement s
311375
}
312376
break;
313377
}
378+
offset++;
314379
}
315380

316381
return start;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package tech.ydb.jdbc.query.params;
2+
3+
import java.sql.SQLException;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
import tech.ydb.jdbc.YdbConst;
8+
import tech.ydb.jdbc.common.TypeDescription;
9+
import tech.ydb.jdbc.impl.YdbTypes;
10+
import tech.ydb.table.query.Params;
11+
import tech.ydb.table.values.ListType;
12+
import tech.ydb.table.values.Type;
13+
import tech.ydb.table.values.Value;
14+
import tech.ydb.table.values.VoidValue;
15+
16+
/**
17+
*
18+
* @author Aleksandr Gorshenin
19+
*/
20+
public class InListJdbcPrm {
21+
private static final Value<?> NULL = VoidValue.of();
22+
private final String listName;
23+
private final List<Item> items = new ArrayList<>();
24+
private TypeDescription type;
25+
26+
public InListJdbcPrm(String listName, int listSize) {
27+
this.listName = listName;
28+
for (int idx = 0; idx < listSize; idx++) {
29+
items.add(new Item(listName, idx));
30+
}
31+
}
32+
33+
public List<? extends JdbcPrm> toJdbcPrmList() {
34+
return items;
35+
}
36+
37+
private Value<?> buildList() throws SQLException {
38+
if (type == null) {
39+
throw new SQLException(YdbConst.PARAMETER_TYPE_UNKNOWN);
40+
}
41+
42+
boolean hasNull = false;
43+
for (Item item: items) {
44+
if (item.value == null) {
45+
throw new SQLException(YdbConst.MISSING_VALUE_FOR_PARAMETER + item.name);
46+
}
47+
hasNull = hasNull || item.value == NULL;
48+
}
49+
50+
List<Value<?>> values = new ArrayList<>();
51+
if (!hasNull) {
52+
for (Item item: items) {
53+
values.add(item.value);
54+
}
55+
return ListType.of(type.ydbType()).newValue(values);
56+
}
57+
58+
for (Item item: items) {
59+
if (item.value == NULL) {
60+
values.add(type.nullValue());
61+
} else {
62+
values.add(item.value.makeOptional());
63+
}
64+
}
65+
66+
return ListType.of(type.ydbType().makeOptional()).newValue(values);
67+
68+
}
69+
70+
private class Item implements JdbcPrm {
71+
private final String name;
72+
private final int index;
73+
private Value<?> value = null;
74+
75+
Item(String listName, int index) {
76+
this.name = listName + "[" + index + "]";
77+
this.index = index;
78+
}
79+
80+
@Override
81+
public String getName() {
82+
return name;
83+
}
84+
85+
@Override
86+
public TypeDescription getType() {
87+
return type;
88+
}
89+
90+
@Override
91+
public void setValue(Object obj, int sqlType) throws SQLException {
92+
if (type == null) {
93+
Type ydbType = YdbTypes.findType(obj, sqlType);
94+
if (ydbType == null) {
95+
if (obj == null) {
96+
value = NULL;
97+
return;
98+
} else {
99+
throw new SQLException(String.format(YdbConst.PARAMETER_TYPE_UNKNOWN, sqlType, obj));
100+
}
101+
}
102+
103+
type = TypeDescription.of(ydbType);
104+
}
105+
106+
value = type.setters().toValue(obj);
107+
}
108+
109+
@Override
110+
public void copyToParams(Params params) throws SQLException {
111+
if (index == 0) { // first prm
112+
params.put(listName, buildList());
113+
}
114+
}
115+
116+
@Override
117+
public void reset() {
118+
value = null;
119+
if (index == items.size() - 1) { // last prm reset type
120+
type = null;
121+
}
122+
}
123+
}
124+
}

jdbc/src/main/java/tech/ydb/jdbc/query/params/InMemoryQuery.java

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.HashMap;
88
import java.util.List;
99
import java.util.Map;
10-
import java.util.function.Supplier;
1110

1211
import tech.ydb.jdbc.YdbConst;
1312
import tech.ydb.jdbc.common.TypeDescription;
@@ -24,33 +23,22 @@
2423
public class InMemoryQuery implements YdbPreparedQuery {
2524
private final String yql;
2625
private final boolean isAutoDeclare;
27-
private final JdbcPrm[] parameters;
28-
private final Map<String, JdbcPrm> parametersByName;
29-
private final List<Params> batchList;
26+
private final List<JdbcPrm> parameters = new ArrayList<>();
27+
private final Map<String, JdbcPrm> parametersByName = new HashMap<>();
28+
private final List<Params> batchList = new ArrayList<>();
3029

3130
public InMemoryQuery(YdbQuery query, boolean isAutoDeclare) {
3231
this.yql = query.getPreparedYql();
3332
this.isAutoDeclare = isAutoDeclare;
3433

35-
int paramtersCount = 0;
3634
for (QueryStatement st: query.getStatements()) {
37-
paramtersCount += st.getParams().size();
38-
}
39-
this.parameters = new JdbcPrm[paramtersCount];
40-
41-
int idx = 0;
42-
for (QueryStatement st: query.getStatements()) {
43-
for (Supplier<JdbcPrm> prm: st.getParams()) {
44-
parameters[idx++] = prm.get();
35+
for (JdbcPrm.Factory factory: st.getJdbcPrmFactories()) {
36+
for (JdbcPrm prm: factory.create()) {
37+
parameters.add(prm);
38+
parametersByName.put(prm.getName(), prm);
39+
}
4540
}
4641
}
47-
48-
this.parametersByName = new HashMap<>();
49-
for (JdbcPrm prm: this.parameters) {
50-
parametersByName.put(prm.getName(), prm);
51-
}
52-
53-
this.batchList = new ArrayList<>();
5442
}
5543

5644
@Override
@@ -74,7 +62,7 @@ public String getQueryText(Params prms) throws SQLException {
7462

7563
@Override
7664
public int parametersCount() {
77-
return parameters.length;
65+
return parameters.size();
7866
}
7967

8068
@Override
@@ -120,29 +108,29 @@ public Params getCurrentParams() throws SQLException {
120108

121109
@Override
122110
public String getNameByIndex(int index) throws SQLException {
123-
if (index <= 0 || index > parameters.length) {
111+
if (index <= 0 || index > parameters.size()) {
124112
throw new SQLException(YdbConst.PARAMETER_NUMBER_NOT_FOUND + index);
125113
}
126-
return parameters[index - 1].getName();
114+
return parameters.get(index - 1).getName();
127115
}
128116

129117
@Override
130118
public TypeDescription getDescription(int index) throws SQLException {
131-
if (index <= 0 || index > parameters.length) {
119+
if (index <= 0 || index > parameters.size()) {
132120
throw new SQLException(YdbConst.PARAMETER_NUMBER_NOT_FOUND + index);
133121
}
134122

135-
JdbcPrm p = parameters[index - 1];
123+
JdbcPrm p = parameters.get(index - 1);
136124
return p.getType();
137125
}
138126

139127
@Override
140128
public void setParam(int index, Object obj, int sqlType) throws SQLException {
141-
if (index <= 0 || index > parameters.length) {
129+
if (index <= 0 || index > parameters.size()) {
142130
throw new SQLException(YdbConst.PARAMETER_NUMBER_NOT_FOUND + index);
143131
}
144132

145-
parameters[index - 1].setValue(obj, sqlType);
133+
parameters.get(index - 1).setValue(obj, sqlType);
146134
}
147135

148136
@Override

0 commit comments

Comments
 (0)