Skip to content

Commit 202c716

Browse files
committed
SQL: Prefer resultSets over exceptions in metadata (#40641)
Changed the JDBC metadata to return empty results sets instead of throwing SQLFeatureNotSupported as it seems a more safer/compatible approach for consumers. Fix #40533 (cherry picked from commit ef2d252)
1 parent 9aefa28 commit 202c716

File tree

7 files changed

+272
-41
lines changed

7 files changed

+272
-41
lines changed

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcConfiguration.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private JdbcConfiguration(URI baseURI, String u, Properties props) throws JdbcSQ
162162
}
163163

164164
@Override
165-
protected Collection<? extends String> extraOptions() {
165+
protected Collection<String> extraOptions() {
166166
return OPTION_NAMES;
167167
}
168168

@@ -192,9 +192,8 @@ public static boolean canAccept(String url) {
192192

193193
public DriverPropertyInfo[] driverPropertyInfo() {
194194
List<DriverPropertyInfo> info = new ArrayList<>();
195-
for (String option : OPTION_NAMES) {
196-
String value = null;
197-
DriverPropertyInfo prop = new DriverPropertyInfo(option, value);
195+
for (String option : optionNames()) {
196+
DriverPropertyInfo prop = new DriverPropertyInfo(option, null);
198197
info.add(prop);
199198
}
200199

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcConnection.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@ class JdbcConnection implements Connection, JdbcWrapper {
4545
* If we remove it, we need to make sure no other types of Exceptions (runtime or otherwise) are thrown
4646
*/
4747
JdbcConnection(JdbcConfiguration connectionInfo) throws SQLException {
48-
cfg = connectionInfo;
49-
client = new JdbcHttpClient(connectionInfo);
48+
this(connectionInfo, true);
49+
}
5050

51+
JdbcConnection(JdbcConfiguration connectionInfo, boolean checkServer) throws SQLException {
52+
cfg = connectionInfo;
53+
client = new JdbcHttpClient(connectionInfo, checkServer);
5154
url = connectionInfo.connectionString();
5255
userName = connectionInfo.authUser();
5356
}

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java

Lines changed: 140 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@
1010

1111
import java.sql.Connection;
1212
import java.sql.DatabaseMetaData;
13+
import java.sql.DriverPropertyInfo;
1314
import java.sql.JDBCType;
1415
import java.sql.PreparedStatement;
1516
import java.sql.ResultSet;
1617
import java.sql.RowIdLifetime;
1718
import java.sql.SQLException;
18-
import java.sql.SQLFeatureNotSupportedException;
1919
import java.util.ArrayList;
2020
import java.util.List;
2121

22+
import static java.sql.JDBCType.BIGINT;
23+
import static java.sql.JDBCType.BOOLEAN;
2224
import static java.sql.JDBCType.INTEGER;
2325
import static java.sql.JDBCType.SMALLINT;
2426
import static org.elasticsearch.xpack.sql.client.StringUtils.EMPTY;
@@ -664,8 +666,7 @@ public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
664666
// https://www.postgresql.org/docs/9.0/static/infoschema-routines.html
665667
@Override
666668
public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException {
667-
return emptySet(con.cfg,
668-
"ROUTINES",
669+
return emptySet(con.cfg, "ROUTINES",
669670
"PROCEDURE_CAT",
670671
"PROCEDURE_SCHEM",
671672
"PROCEDURE_NAME",
@@ -680,8 +681,7 @@ public ResultSet getProcedures(String catalog, String schemaPattern, String proc
680681
@Override
681682
public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern)
682683
throws SQLException {
683-
return emptySet(con.cfg,
684-
"PARAMETERS",
684+
return emptySet(con.cfg, "ROUTINES_COLUMNS",
685685
"PROCEDURE_CAT",
686686
"PROCEDURE_SCHEM",
687687
"PROCEDURE_NAME",
@@ -775,14 +775,14 @@ public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLExce
775775
public ResultSet getCatalogs() throws SQLException {
776776
// TABLE_CAT is the first column
777777
Object[][] data = queryColumn(con, "SYS TABLES CATALOG LIKE '%'", 1);
778-
return memorySet(con.cfg, columnInfo("", "TABLE_CAT"), data);
778+
return memorySet(con.cfg, columnInfo("CATALOGS", "TABLE_CAT"), data);
779779
}
780780

781781
@Override
782782
public ResultSet getTableTypes() throws SQLException {
783783
// TABLE_TYPE (4)
784784
Object[][] data = queryColumn(con, "SYS TABLES TYPE '%'", 4);
785-
return memorySet(con.cfg, columnInfo("", "TABLE_TYPE"), data);
785+
return memorySet(con.cfg, columnInfo("TABLE_TYPES", "TABLE_TYPE"), data);
786786
}
787787

788788
@Override
@@ -798,43 +798,128 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
798798

799799
@Override
800800
public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException {
801-
throw new SQLFeatureNotSupportedException("Privileges not supported");
801+
return emptySet(con.cfg, "",
802+
"TABLE_CAT",
803+
"TABLE_SCHEM",
804+
"TABLE_NAME",
805+
"COLUMN_NAME",
806+
"GRANTOR",
807+
"GRANTEE",
808+
"PRIVILEGE",
809+
"IS_GRANTABLE");
802810
}
803811

804812
@Override
805813
public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
806-
throw new SQLFeatureNotSupportedException("Privileges not supported");
814+
return emptySet(con.cfg, "",
815+
"TABLE_CAT",
816+
"TABLE_SCHEM",
817+
"TABLE_NAME",
818+
"GRANTOR",
819+
"GRANTEE",
820+
"PRIVILEGE",
821+
"IS_GRANTABLE");
807822
}
808823

809824
@Override
810825
public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException {
811-
throw new SQLFeatureNotSupportedException("Row identifiers not supported");
826+
return emptySet(con.cfg, "",
827+
"SCOPE", SMALLINT,
828+
"COLUMN_NAME",
829+
"DATA_TYPE", INTEGER,
830+
"TYPE_NAME",
831+
"COLUMN_SIZE", INTEGER,
832+
"BUFFER_LENGTH", INTEGER,
833+
"DECIMAL_DIGITS", SMALLINT,
834+
"PSEUDO_COLUMN", SMALLINT);
812835
}
813836

814837
@Override
815838
public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException {
816-
throw new SQLFeatureNotSupportedException("Version column not supported yet");
839+
return emptySet(con.cfg, "",
840+
"SCOPE", SMALLINT,
841+
"COLUMN_NAME",
842+
"DATA_TYPE", INTEGER,
843+
"TYPE_NAME",
844+
"COLUMN_SIZE", INTEGER,
845+
"BUFFER_LENGTH", INTEGER,
846+
"DECIMAL_DIGITS", SMALLINT,
847+
"PSEUDO_COLUMN", SMALLINT);
817848
}
818849

819850
@Override
820851
public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
821-
throw new SQLFeatureNotSupportedException("Primary keys not supported");
852+
return emptySet(con.cfg, "",
853+
"TABLE_CAT",
854+
"TABLE_SCHEM",
855+
"TABLE_NAME",
856+
"COLUMN_NAME",
857+
"KEY_SEQ", SMALLINT,
858+
"PK_NAME");
822859
}
823860

824861
@Override
825862
public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
826-
throw new SQLFeatureNotSupportedException("Imported keys not supported");
863+
return emptySet(con.cfg, "",
864+
"PKTABLE_CAT",
865+
"PKTABLE_SCHEM",
866+
"PKTABLE_NAME",
867+
"PKCOLUMN_NAME",
868+
"FKTABLE_CAT",
869+
"FKTABLE_SCHEM",
870+
"FKTABLE_NAME",
871+
"FKCOLUMN_NAME",
872+
"KEY_SEQ", SMALLINT,
873+
"UPDATE_RULE ", SMALLINT,
874+
"DELETE_RULE ", SMALLINT,
875+
"FK_NAME",
876+
"PK_NAME ",
877+
"DEFERRABILITY", SMALLINT,
878+
"IS_NULLABLE"
879+
);
827880
}
828881

829882
@Override
830883
public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
831-
throw new SQLFeatureNotSupportedException("Exported keys not supported");
884+
return emptySet(con.cfg, "",
885+
"PKTABLE_CAT",
886+
"PKTABLE_SCHEM",
887+
"PKTABLE_NAME",
888+
"PKCOLUMN_NAME",
889+
"FKTABLE_CAT",
890+
"FKTABLE_SCHEM",
891+
"FKTABLE_NAME",
892+
"FKCOLUMN_NAME",
893+
"KEY_SEQ", SMALLINT,
894+
"UPDATE_RULE ", SMALLINT,
895+
"DELETE_RULE ", SMALLINT,
896+
"FK_NAME",
897+
"PK_NAME ",
898+
"DEFERRABILITY", SMALLINT,
899+
"IS_NULLABLE"
900+
);
832901
}
833902

834903
@Override
835904
public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog,
836905
String foreignSchema, String foreignTable) throws SQLException {
837-
throw new SQLFeatureNotSupportedException("Cross reference not supported");
906+
return emptySet(con.cfg, "",
907+
"PKTABLE_CAT",
908+
"PKTABLE_SCHEM",
909+
"PKTABLE_NAME",
910+
"PKCOLUMN_NAME",
911+
"FKTABLE_CAT",
912+
"FKTABLE_SCHEM",
913+
"FKTABLE_NAME",
914+
"FKCOLUMN_NAME",
915+
"KEY_SEQ", SMALLINT,
916+
"UPDATE_RULE ", SMALLINT,
917+
"DELETE_RULE ", SMALLINT,
918+
"FK_NAME",
919+
"PK_NAME ",
920+
"DEFERRABILITY", SMALLINT,
921+
"IS_NULLABLE"
922+
);
838923
}
839924

840925
@Override
@@ -844,7 +929,22 @@ public ResultSet getTypeInfo() throws SQLException {
844929

845930
@Override
846931
public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException {
847-
throw new SQLFeatureNotSupportedException("Indicies not supported");
932+
return emptySet(con.cfg, "",
933+
"TABLE_CAT",
934+
"TABLE_SCHEM",
935+
"TABLE_NAME",
936+
"NON_UNIQUE", BOOLEAN,
937+
"INDEX_QUALIFIER",
938+
"INDEX_NAME",
939+
"TYPE", SMALLINT,
940+
"ORDINAL_POSITION", SMALLINT,
941+
"COLUMN_NAME",
942+
"ASC_OR_DESC",
943+
"CARDINALITY", BIGINT,
944+
"PAGES", BIGINT,
945+
"FILTER_CONDITION",
946+
"TYPE_NAME"
947+
);
848948
}
849949

850950
@Override
@@ -909,7 +1009,7 @@ public boolean supportsBatchUpdates() throws SQLException {
9091009

9101010
@Override
9111011
public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException {
912-
return emptySet(con.cfg,
1012+
return emptySet(con.cfg, "",
9131013
"USER_DEFINED_TYPES",
9141014
"TYPE_CAT",
9151015
"TYPE_SCHEM",
@@ -947,7 +1047,7 @@ public boolean supportsGetGeneratedKeys() throws SQLException {
9471047

9481048
@Override
9491049
public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException {
950-
return emptySet(con.cfg,
1050+
return emptySet(con.cfg, "",
9511051
"SUPER_TYPES",
9521052
"TYPE_CAT",
9531053
"TYPE_SCHEM",
@@ -960,7 +1060,7 @@ public ResultSet getSuperTypes(String catalog, String schemaPattern, String type
9601060

9611061
@Override
9621062
public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
963-
return emptySet(con.cfg, "SUPER_TABLES",
1063+
return emptySet(con.cfg, "",
9641064
"TABLE_CAT",
9651065
"TABLE_SCHEM",
9661066
"TABLE_NAME",
@@ -970,7 +1070,7 @@ public ResultSet getSuperTables(String catalog, String schemaPattern, String tab
9701070
@Override
9711071
public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern)
9721072
throws SQLException {
973-
return emptySet(con.cfg,
1073+
return emptySet(con.cfg, "",
9741074
"ATTRIBUTES",
9751075
"TYPE_CAT",
9761076
"TYPE_SCHEM",
@@ -1057,12 +1157,27 @@ public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
10571157

10581158
@Override
10591159
public ResultSet getClientInfoProperties() throws SQLException {
1060-
throw new SQLException("Client info not implemented yet");
1160+
DriverPropertyInfo[] info = con.cfg.driverPropertyInfo();
1161+
Object[][] data = new Object[info.length][];
1162+
1163+
for (int i = 0; i < data.length; i++) {
1164+
data[i] = new Object[4];
1165+
data[i][0] = info[i].name;
1166+
data[i][1] = Integer.valueOf(-1);
1167+
data[i][2] = EMPTY;
1168+
data[i][3] = EMPTY;
1169+
}
1170+
1171+
return memorySet(con.cfg, columnInfo("",
1172+
"NAME",
1173+
"MAX_LEN", INTEGER,
1174+
"DEFAULT_VALUE",
1175+
"DESCRIPTION"), data);
10611176
}
10621177

10631178
@Override
10641179
public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException {
1065-
return emptySet(con.cfg,
1180+
return emptySet(con.cfg, "",
10661181
"FUNCTIONS",
10671182
"FUNCTION_CAT",
10681183
"FUNCTION_SCHEM",
@@ -1075,7 +1190,7 @@ public ResultSet getFunctions(String catalog, String schemaPattern, String funct
10751190
@Override
10761191
public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern)
10771192
throws SQLException {
1078-
return emptySet(con.cfg,
1193+
return emptySet(con.cfg, "",
10791194
"FUNCTION_COLUMNS",
10801195
"FUNCTION_CAT",
10811196
"FUNCTION_SCHEM",
@@ -1098,7 +1213,7 @@ public ResultSet getFunctionColumns(String catalog, String schemaPattern, String
10981213
@Override
10991214
public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
11001215
throws SQLException {
1101-
return emptySet(con.cfg,
1216+
return emptySet(con.cfg, "",
11021217
"PSEUDO_COLUMNS",
11031218
"TABLE_CAT",
11041219
"TABLE_SCHEM",
@@ -1213,7 +1328,7 @@ public Object column(int column) {
12131328

12141329
@Override
12151330
public int batchSize() {
1216-
return data.length;
1331+
return ObjectUtils.isEmpty(data) ? 0 : data.length;
12171332
}
12181333

12191334
@Override

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcHttpClient.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@
3030
class JdbcHttpClient {
3131
private final HttpClient httpClient;
3232
private final JdbcConfiguration conCfg;
33-
private final InfoResponse serverInfo;
33+
private InfoResponse serverInfo;
3434

3535
/**
3636
* The SQLException is the only type of Exception the JDBC API can throw (and that the user expects).
3737
* If we remove it, we need to make sure no other types of Exceptions (runtime or otherwise) are thrown
3838
*/
3939
JdbcHttpClient(JdbcConfiguration conCfg) throws SQLException {
40+
this(conCfg, true);
41+
}
42+
43+
JdbcHttpClient(JdbcConfiguration conCfg, boolean checkServer) throws SQLException {
4044
httpClient = new HttpClient(conCfg);
4145
this.conCfg = conCfg;
42-
this.serverInfo = fetchServerInfo();
43-
checkServerVersion();
46+
if (checkServer) {
47+
this.serverInfo = fetchServerInfo();
48+
checkServerVersion();
49+
}
4450
}
4551

4652
boolean ping(long timeoutInMs) throws SQLException {
@@ -77,6 +83,9 @@ boolean queryClose(String cursor) throws SQLException {
7783
}
7884

7985
InfoResponse serverInfo() throws SQLException {
86+
if (serverInfo == null) {
87+
serverInfo = fetchServerInfo();
88+
}
8089
return serverInfo;
8190
}
8291

x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcResultSet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,7 @@ public void updateNClob(String columnLabel, Reader reader) throws SQLException {
12031203

12041204
@Override
12051205
public String toString() {
1206-
return format(Locale.ROOT, "%s:row %d", getClass().getSimpleName(), rowNumber);
1206+
return format(Locale.ROOT, "%s:row %d:cursor size %d:%s", getClass().getSimpleName(), rowNumber, cursor.batchSize(),
1207+
cursor.columns());
12071208
}
12081209
}

0 commit comments

Comments
 (0)