11
11
import org .elasticsearch .xpack .sql .expression .Attribute ;
12
12
import org .elasticsearch .xpack .sql .expression .predicate .regex .LikePattern ;
13
13
import org .elasticsearch .xpack .sql .plan .logical .command .Command ;
14
+ import org .elasticsearch .xpack .sql .proto .Mode ;
14
15
import org .elasticsearch .xpack .sql .session .Rows ;
15
16
import org .elasticsearch .xpack .sql .session .SchemaRowSet ;
16
17
import org .elasticsearch .xpack .sql .session .SqlSession ;
@@ -58,21 +59,29 @@ protected NodeInfo<SysColumns> info() {
58
59
59
60
@ Override
60
61
public List <Attribute > output () {
62
+ return output (false );
63
+ }
64
+
65
+ private List <Attribute > output (boolean odbcCompatible ) {
66
+ // https://github.com/elastic/elasticsearch/issues/35376
67
+ // ODBC expects some fields as SHORT while JDBC as Integer
68
+ // which causes conversion issues and CCE
69
+ DataType clientBasedType = odbcCompatible ? SHORT : INTEGER ;
61
70
return asList (keyword ("TABLE_CAT" ),
62
71
keyword ("TABLE_SCHEM" ),
63
72
keyword ("TABLE_NAME" ),
64
73
keyword ("COLUMN_NAME" ),
65
- field ("DATA_TYPE" , INTEGER ),
74
+ field ("DATA_TYPE" , clientBasedType ),
66
75
keyword ("TYPE_NAME" ),
67
76
field ("COLUMN_SIZE" , INTEGER ),
68
77
field ("BUFFER_LENGTH" , INTEGER ),
69
- field ("DECIMAL_DIGITS" , INTEGER ),
70
- field ("NUM_PREC_RADIX" , INTEGER ),
71
- field ("NULLABLE" , INTEGER ),
78
+ field ("DECIMAL_DIGITS" , clientBasedType ),
79
+ field ("NUM_PREC_RADIX" , clientBasedType ),
80
+ field ("NULLABLE" , clientBasedType ),
72
81
keyword ("REMARKS" ),
73
82
keyword ("COLUMN_DEF" ),
74
- field ("SQL_DATA_TYPE" , INTEGER ),
75
- field ("SQL_DATETIME_SUB" , INTEGER ),
83
+ field ("SQL_DATA_TYPE" , clientBasedType ),
84
+ field ("SQL_DATETIME_SUB" , clientBasedType ),
76
85
field ("CHAR_OCTET_LENGTH" , INTEGER ),
77
86
field ("ORDINAL_POSITION" , INTEGER ),
78
87
keyword ("IS_NULLABLE" ),
@@ -88,11 +97,13 @@ public List<Attribute> output() {
88
97
89
98
@ Override
90
99
public void execute (SqlSession session , ActionListener <SchemaRowSet > listener ) {
100
+ boolean isOdbcClient = session .settings ().mode () == Mode .ODBC ;
101
+ List <Attribute > output = output (isOdbcClient );
91
102
String cluster = session .indexResolver ().clusterName ();
92
103
93
104
// bail-out early if the catalog is present but differs
94
105
if (Strings .hasText (catalog ) && !cluster .equals (catalog )) {
95
- listener .onResponse (Rows .empty (output () ));
106
+ listener .onResponse (Rows .empty (output ));
96
107
return ;
97
108
}
98
109
@@ -104,15 +115,15 @@ public void execute(SqlSession session, ActionListener<SchemaRowSet> listener) {
104
115
session .indexResolver ().resolveAsSeparateMappings (idx , regex , ActionListener .wrap (esIndices -> {
105
116
List <List <?>> rows = new ArrayList <>();
106
117
for (EsIndex esIndex : esIndices ) {
107
- fillInRows (cluster , esIndex .name (), esIndex .mapping (), null , rows , columnMatcher );
118
+ fillInRows (cluster , esIndex .name (), esIndex .mapping (), null , rows , columnMatcher , isOdbcClient );
108
119
}
109
120
110
- listener .onResponse (Rows .of (output () , rows ));
121
+ listener .onResponse (Rows .of (output , rows ));
111
122
}, listener ::onFailure ));
112
123
}
113
124
114
125
static void fillInRows (String clusterName , String indexName , Map <String , EsField > mapping , String prefix , List <List <?>> rows ,
115
- Pattern columnMatcher ) {
126
+ Pattern columnMatcher , boolean isOdbcClient ) {
116
127
int pos = 0 ;
117
128
for (Map .Entry <String , EsField > entry : mapping .entrySet ()) {
118
129
pos ++; // JDBC is 1-based so we start with 1 here
@@ -128,24 +139,24 @@ static void fillInRows(String clusterName, String indexName, Map<String, EsField
128
139
null ,
129
140
indexName ,
130
141
name ,
131
- type .sqlType .getVendorTypeNumber (),
142
+ odbcCompatible ( type .sqlType .getVendorTypeNumber (), isOdbcClient ),
132
143
type .esType .toUpperCase (Locale .ROOT ),
133
144
type .displaySize ,
134
145
// TODO: is the buffer_length correct?
135
146
type .size ,
136
147
// no DECIMAL support
137
148
null ,
138
- DataTypes .metaSqlRadix (type ),
149
+ odbcCompatible ( DataTypes .metaSqlRadix (type ), isOdbcClient ),
139
150
// everything is nullable
140
- DatabaseMetaData .columnNullable ,
151
+ odbcCompatible ( DatabaseMetaData .columnNullable , isOdbcClient ) ,
141
152
// no remarks
142
153
null ,
143
154
// no column def
144
155
null ,
145
156
// SQL_DATA_TYPE apparently needs to be same as DATA_TYPE except for datetime and interval data types
146
- DataTypes .metaSqlDataType (type ),
157
+ odbcCompatible ( DataTypes .metaSqlDataType (type ), isOdbcClient ),
147
158
// SQL_DATETIME_SUB ?
148
- DataTypes .metaSqlDateTimeSub (type ),
159
+ odbcCompatible ( DataTypes .metaSqlDateTimeSub (type ), isOdbcClient ),
149
160
// char octet length
150
161
type .isString () || type == DataType .BINARY ? type .size : null ,
151
162
// position
@@ -160,11 +171,18 @@ static void fillInRows(String clusterName, String indexName, Map<String, EsField
160
171
));
161
172
}
162
173
if (field .getProperties () != null ) {
163
- fillInRows (clusterName , indexName , field .getProperties (), name , rows , columnMatcher );
174
+ fillInRows (clusterName , indexName , field .getProperties (), name , rows , columnMatcher , isOdbcClient );
164
175
}
165
176
}
166
177
}
167
178
179
+ private static Object odbcCompatible (Integer value , boolean isOdbcClient ) {
180
+ if (isOdbcClient && value != null ) {
181
+ return Short .valueOf (value .shortValue ());
182
+ }
183
+ return value ;
184
+ }
185
+
168
186
@ Override
169
187
public int hashCode () {
170
188
return Objects .hash (catalog , index , pattern , columnPattern );
0 commit comments