forked from databricks/databricks-jdbc
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDatabricksParameterMetaData.java
More file actions
213 lines (183 loc) · 6.69 KB
/
Copy pathDatabricksParameterMetaData.java
File metadata and controls
213 lines (183 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package com.databricks.jdbc.api.impl;
import static com.databricks.jdbc.common.DatabricksJdbcConstants.EMPTY_STRING;
import com.databricks.jdbc.common.util.DatabricksTypeUtil;
import com.databricks.jdbc.common.util.WrapperUtil;
import com.databricks.jdbc.log.JdbcLogger;
import com.databricks.jdbc.log.JdbcLoggerFactory;
import com.databricks.jdbc.model.core.ColumnInfoTypeName;
import java.sql.ParameterMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
// TODO (PECO-1738): Implement ParameterMetaData
public class DatabricksParameterMetaData implements ParameterMetaData {
private static final JdbcLogger LOGGER =
JdbcLoggerFactory.getLogger(DatabricksParameterMetaData.class);
private final Map<Integer, ImmutableSqlParameter> parameterBindings;
private final int parameterCount;
public DatabricksParameterMetaData() {
this(null);
}
public DatabricksParameterMetaData(String sql) {
this.parameterBindings = new HashMap<>();
this.parameterCount = countParameters(sql);
}
public void put(int param, ImmutableSqlParameter value) {
this.parameterBindings.put(param, value);
}
public Map<Integer, ImmutableSqlParameter> getParameterBindings() {
return parameterBindings;
}
public void clear() {
this.parameterBindings.clear();
}
@Override
public int getParameterCount() throws SQLException {
validateParameterBindings();
return parameterCount;
}
/**
* Validates that parameter bindings do not exceed the parameter count.
*
* @throws SQLException if there are more parameter bindings than expected parameters
*/
private void validateParameterBindings() throws SQLException {
if (parameterBindings.size() > parameterCount) {
throw new SQLException(
"Number of parameter bindings ("
+ parameterBindings.size()
+ ") exceeds parameter count ("
+ parameterCount
+ ")");
}
}
@Override
public int isNullable(int param) throws SQLException {
// TODO (PECO-1711): Implement isNullable
return ParameterMetaData.parameterNullableUnknown;
}
@Override
public boolean isSigned(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return DatabricksTypeUtil.isSigned(getObject(param).type());
}
@Override
public int getPrecision(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return DatabricksTypeUtil.getPrecision(
DatabricksTypeUtil.getColumnType(getObject(param).type()));
}
@Override
public int getScale(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return DatabricksTypeUtil.getScale(DatabricksTypeUtil.getColumnType(getObject(param).type()));
}
@Override
public int getParameterType(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return DatabricksTypeUtil.getColumnType(getObject(param).type());
}
@Override
public String getParameterTypeName(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return getObject(param).type().name();
}
@Override
public String getParameterClassName(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return DatabricksTypeUtil.getColumnTypeClassName(getObject(param).type());
}
@Override
public int getParameterMode(int param) throws SQLException {
LOGGER.warn("This feature is not fully implemented in the driver yet.");
return ParameterMetaData
.parameterModeIn; // In context of prepared statement, only IN parameters are provided.
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return WrapperUtil.unwrap(iface, this);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return WrapperUtil.isWrapperFor(iface, this);
}
private ImmutableSqlParameter getObject(int param) {
if (!parameterBindings.containsKey(param)) {
LOGGER.info("Parameter not added in the prepared statement yet. Sending default value");
return ImmutableSqlParameter.builder()
.type(ColumnInfoTypeName.STRING)
.cardinal(1)
.value(EMPTY_STRING)
.build();
}
return parameterBindings.get(param);
}
/**
* Counts the number of parameter markers (?) in the SQL statement. This is currently a hacky
* implementation that may need improvement for complex SQL.
*
* @param sql The SQL statement to analyze
* @return The number of parameter markers in the SQL statement
*/
private int countParameters(String sql) {
if (sql == null || sql.isEmpty()) {
return 0;
}
int count = 0;
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
boolean inLineComment = false;
boolean inBlockComment = false;
for (int i = 0; i < sql.length(); i++) {
char c = sql.charAt(i);
char next = (i < sql.length() - 1) ? sql.charAt(i + 1) : '\0';
// Handle comments
if (!inSingleQuote && !inDoubleQuote) {
if (!inBlockComment && !inLineComment && c == '-' && next == '-') {
inLineComment = true;
i++; // Skip next dash
continue;
} else if (!inBlockComment && !inLineComment && c == '/' && next == '*') {
inBlockComment = true;
i++; // Skip next asterisk
continue;
} else if (inLineComment && (c == '\n' || c == '\r')) {
inLineComment = false;
} else if (inBlockComment && c == '*' && next == '/') {
inBlockComment = false;
i++; // Skip next slash
continue;
}
}
// Skip if in comment
if (inLineComment || inBlockComment) {
continue;
}
// Handle quotes with escaped quotes
if (c == '\'') {
if (!inDoubleQuote) {
// Check for escaped single quote
if (inSingleQuote && i < sql.length() - 1 && sql.charAt(i + 1) == '\'') {
i++; // Skip the escaped quote
} else {
inSingleQuote = !inSingleQuote;
}
}
} else if (c == '"') {
if (!inSingleQuote) {
// Check for escaped double quote
if (inDoubleQuote && i < sql.length() - 1 && sql.charAt(i + 1) == '"') {
i++; // Skip the escaped quote
} else {
inDoubleQuote = !inDoubleQuote;
}
}
}
// Count parameter markers only when not inside quotes or comments
if (c == '?' && !inSingleQuote && !inDoubleQuote) {
count++;
}
}
return count;
}
}