28
28
#include "info.h"
29
29
#include "queries.h"
30
30
31
- // TODO: add type (and schema, when supported)
32
- #define SQL_TABLES "SYS TABLES" \
33
- " CATALOG LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \
31
+
32
+ #define SYS_CATALOGS \
33
+ "SYS CATALOGS"
34
+
35
+ /* SYS TABLES syntax tokens; these need to stay broken down, since this
36
+ * query makes a difference between a predicate being '%' or left out */
37
+ // TODO: schema, when supported
38
+ #define SQL_TABLES \
39
+ "SYS TABLES"
40
+ #define SQL_TABLES_CAT \
41
+ " CATALOG LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM
42
+ #define SQL_TABLES_TAB \
34
43
" LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM
44
+ #define SQL_TABLES_TYP \
45
+ " TYPE " WPFWP_LDESC
35
46
36
47
// TODO add schema, when supported
37
48
#define SQL_COLUMNS (...) "SYS COLUMNS" __VA_ARGS__ \
38
49
" TABLE LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \
39
50
" LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM
40
- #define SQL_COL_CAT \
51
+ #define SQL_COL_CAT \
41
52
" CATALOG " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \
42
53
43
54
55
+ /* writes into 'dest', of size 'room', the current catalog of 'dbc'.
56
+ * returns negative on error, or the char count written otherwise */
57
+ SQLSMALLINT copy_current_catalog (esodbc_dbc_st * dbc , SQLWCHAR * dest ,
58
+ SQLSMALLINT room )
59
+ {
60
+ esodbc_stmt_st * stmt = NULL ;
61
+ SQLSMALLINT used = -1 ; /*failure*/
62
+ SQLLEN row_cnt ;
63
+ SQLLEN ind_len = SQL_NULL_DATA ;
64
+ SQLWCHAR buff [ESODBC_MAX_IDENTIFIER_LEN ];
65
+ SQLWCHAR * catalog ;
66
+
67
+ if (! SQL_SUCCEEDED (EsSQLAllocHandle (SQL_HANDLE_STMT , dbc , & stmt ))) {
68
+ ERRH (dbc , "failed to alloc a statement handle." );
69
+ return -1 ;
70
+ }
71
+ assert (stmt );
72
+
73
+ if (! SQL_SUCCEEDED (attach_sql (stmt , MK_WPTR (SYS_CATALOGS ),
74
+ sizeof (SYS_CATALOGS ) - 1 ))) {
75
+ ERRH (dbc , "failed to attach query to statement." );
76
+ goto end ;
77
+ }
78
+ if (! SQL_SUCCEEDED (post_statement (stmt ))) {
79
+ ERRH (dbc , "failed to post query." );
80
+ goto end ;
81
+ }
82
+
83
+ /* check that we have received proper number of rows (non-0, less than
84
+ * max allowed here) */
85
+ if (! SQL_SUCCEEDED (EsSQLRowCount (stmt , & row_cnt ))) {
86
+ ERRH (dbc , "failed to get result rows count." );
87
+ goto end ;
88
+ } else if (row_cnt <= 0 ) {
89
+ WARNH (stmt , "Elasticsearch returned no current catalog." );
90
+ catalog = MK_WPTR ("" ); /* empty string, it's not quite an error */
91
+ } else {
92
+ DBGH (stmt , "Elasticsearch catalogs rows count: %ld." , row_cnt );
93
+ if (1 < row_cnt ) {
94
+ WARNH (dbc , "Elasticsearch connected to %d clusters, returning "
95
+ "the first's name as current catalog." , row_cnt );
96
+ }
97
+
98
+ if (! SQL_SUCCEEDED (EsSQLBindCol (stmt , /*col#*/ 1 , SQL_C_WCHAR , buff ,
99
+ sizeof (buff ), & ind_len ))) {
100
+ ERRH (dbc , "failed to bind first column." );
101
+ goto end ;
102
+ }
103
+ if (! SQL_SUCCEEDED (EsSQLFetch (stmt ))) {
104
+ ERRH (stmt , "failed to fetch results." );
105
+ goto end ;
106
+ }
107
+ if (ind_len <= 0 ) {
108
+ WARNH (dbc , "NULL catalog received." ); /*tho maybe != NULL_DATA */
109
+ catalog = MK_WPTR ("" );
110
+ } else {
111
+ catalog = buff ;
112
+ DBGH (dbc , "current catalog (first value returned): `" LWPD "`." ,
113
+ catalog );
114
+ }
115
+ }
116
+
117
+ if (! SQL_SUCCEEDED (write_wptr (& dbc -> hdr .diag , dest , catalog , room ,
118
+ & used ))) {
119
+ ERRH (dbc , "failed to copy catalog: `" LWPD "`." , catalog );
120
+ used = -1 ; /* write_wptr() can change pointer, and still fail */
121
+ }
122
+
123
+ end :
124
+ /* safe even if no binding occured */
125
+ if (! SQL_SUCCEEDED (EsSQLFreeStmt (stmt , SQL_UNBIND ))) {
126
+ ERRH (stmt , "failed to unbind statement" );
127
+ used = -1 ;
128
+ }
129
+ if (! SQL_SUCCEEDED (EsSQLFreeHandle (SQL_HANDLE_STMT , stmt ))) {
130
+ ERRH (dbc , "failed to free statement handle!" );
131
+ }
132
+ return used ;
133
+ }
134
+
135
+ /*
136
+ * Quote the tokens in a string: "a, b,,c" -> "'a','b',,'c'".
137
+ * No string sanity done (garbage in, garbage out).
138
+ */
139
+ size_t quote_tokens (SQLWCHAR * src , size_t len , SQLWCHAR * dest )
140
+ {
141
+ size_t i ;
142
+ BOOL copying ;
143
+ SQLWCHAR * pos ;
144
+
145
+ copying = FALSE;
146
+ pos = dest ;
147
+ for (i = 0 ; i < len ; i ++ ) {
148
+ switch (src [i ]) {
149
+ /* ignore white space */
150
+ case L' ' :
151
+ case L'\t' :
152
+ if (copying ) {
153
+ * pos ++ = L'\'' ; /* end current token */
154
+ copying = FALSE;
155
+ }
156
+ continue ; /* don't copy WS */
157
+
158
+ case L',' :
159
+ if (copying ) {
160
+ * pos ++ = L'\'' ; /* end current token */
161
+ copying = FALSE;
162
+ } /* else continue; -- to remove extra `,` */
163
+ break ;
164
+
165
+ default :
166
+ if (! copying ) {
167
+ * pos ++ = L'\'' ; /* start a new token */
168
+ }
169
+ copying = TRUE;
170
+ }
171
+ * pos ++ = src [i ];
172
+ }
173
+ /* should not overrun */
174
+ assert (i < 2 /*see typ_buf below*/ * ESODBC_MAX_IDENTIFIER_LEN );
175
+ return pos - dest ;
176
+ }
177
+
44
178
SQLRETURN EsSQLTablesW (
45
179
SQLHSTMT StatementHandle ,
46
180
_In_reads_opt_ (NameLength1 ) SQLWCHAR * CatalogName ,
@@ -54,29 +188,47 @@ SQLRETURN EsSQLTablesW(
54
188
{
55
189
esodbc_stmt_st * stmt = STMH (StatementHandle );
56
190
SQLRETURN ret ;
57
- SQLWCHAR wbuf [sizeof (SQL_TABLES ) + 2 * ESODBC_MAX_IDENTIFIER_LEN ];
58
- SQLWCHAR * table , * schema , * catalog ;
59
- size_t cnt_tab , cnt_sch , cnt_cat , pos ;
191
+ /* b/c declaring an array with a const doesn't work with MSVC's compiler */
192
+ enum wbuf_len { wbuf_len = sizeof (SQL_TABLES )
193
+ + sizeof (SQL_TABLES_CAT )
194
+ + sizeof (SQL_TABLES_TAB )
195
+ + sizeof (SQL_TABLES_TYP )
196
+ + 3 * ESODBC_MAX_IDENTIFIER_LEN /* it has 4x 0-term space */
197
+ };
198
+ SQLWCHAR wbuf [wbuf_len ];
199
+ SQLWCHAR * table , * schema , * catalog , * type ;
200
+ size_t cnt_tab , cnt_sch , cnt_cat , cnt_typ , pos ;
201
+ /* 2x: "a,b,c" -> "'a','b','c'" : each "x," => "'x'," */
202
+ SQLWCHAR typ_buf [2 * ESODBC_MAX_IDENTIFIER_LEN ];
60
203
61
204
if (stmt -> metadata_id == SQL_TRUE )
62
205
FIXME ; // FIXME
63
206
207
+ pos = sizeof (SQL_TABLES ) - 1 ;
208
+ wmemcpy (wbuf , MK_WPTR (SQL_TABLES ), pos );
209
+
64
210
if (CatalogName ) {
65
211
catalog = CatalogName ;
66
212
if (NameLength1 == SQL_NTS ) {
67
213
cnt_cat = wcslen (catalog );
68
214
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_cat ) {
69
215
ERRH (stmt , "catalog identifier name '" LTPDL "' too long "
70
- "(%d . max=%d)." , cnt_cat , catalog , cnt_cat ,
216
+ "(%zd . max=%d)." , ( int ) cnt_cat , catalog , cnt_cat ,
71
217
ESODBC_MAX_IDENTIFIER_LEN );
72
218
RET_HDIAG (stmt , SQL_STATE_HY090 , "catalog name too long" , 0 );
73
219
}
74
220
} else {
75
221
cnt_cat = NameLength1 ;
76
222
}
77
- } else {
78
- catalog = MK_WPTR (SQL_ALL_CATALOGS );
79
- cnt_cat = sizeof (SQL_ALL_CATALOGS ) - /*0-term*/ 1 ;
223
+
224
+ cnt_cat = swprintf (wbuf + pos , wbuf_len - pos , SQL_TABLES_CAT ,
225
+ (int )cnt_cat , catalog );
226
+ if (cnt_cat <= 0 ) {
227
+ ERRH (stmt , "failed to print 'catalog' for tables catalog SQL." );
228
+ RET_HDIAGS (stmt , SQL_STATE_HY000 );
229
+ } else {
230
+ pos += cnt_cat ;
231
+ }
80
232
}
81
233
82
234
if (SchemaName ) {
@@ -85,23 +237,20 @@ SQLRETURN EsSQLTablesW(
85
237
cnt_sch = wcslen (schema );
86
238
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_sch ) {
87
239
ERRH (stmt , "schema identifier name '" LTPDL "' too long "
88
- "(%d . max=%d)." , cnt_sch , schema , cnt_sch ,
240
+ "(%zd . max=%d)." , ( int ) cnt_sch , schema , cnt_sch ,
89
241
ESODBC_MAX_IDENTIFIER_LEN );
90
242
RET_HDIAG (stmt , SQL_STATE_HY090 , "schema name too long" , 0 );
91
243
}
92
244
} else {
93
245
cnt_sch = NameLength2 ;
94
246
}
95
- } else {
96
- schema = MK_WPTR (SQL_ALL_SCHEMAS );
97
- cnt_sch = sizeof (SQL_ALL_SCHEMAS ) - /*0-term*/ 1 ;
98
- }
99
247
100
- /* TODO: server support needed for sch. name filtering */
101
- if (cnt_sch && wszmemcmp (schema , MK_WPTR (SQL_ALL_SCHEMAS ),
102
- (long )cnt_sch )) {
103
- ERRH (stmt , "filtering by schemas is not supported." );
104
- RET_HDIAG (stmt , SQL_STATE_IM001 , "schema filtering not supported" , 0 );
248
+ /* TODO: server support needed for sch. name filtering */
249
+ if (wszmemcmp (schema , MK_WPTR (SQL_ALL_SCHEMAS ), (long )cnt_sch )) {
250
+ ERRH (stmt , "filtering by schemas is not supported." );
251
+ RET_HDIAG (stmt , SQL_STATE_IM001 , "schema filtering not supported" ,
252
+ 0 );
253
+ }
105
254
}
106
255
107
256
// FIXME: string needs escaping of % \\ _
@@ -111,32 +260,57 @@ SQLRETURN EsSQLTablesW(
111
260
cnt_tab = wcslen (table );
112
261
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_tab ) {
113
262
ERRH (stmt , "table identifier name '" LTPDL "' too long "
114
- "(%d . max=%d)." , cnt_tab , table , cnt_tab ,
263
+ "(%zd . max=%d)." , ( int ) cnt_tab , table , cnt_tab ,
115
264
ESODBC_MAX_IDENTIFIER_LEN );
116
265
RET_HDIAG (stmt , SQL_STATE_HY090 , "table name too long" , 0 );
117
266
}
118
267
} else {
119
268
cnt_tab = NameLength3 ;
120
269
}
121
- } else {
122
- table = MK_WPTR (ESODBC_ALL_TABLES );
123
- cnt_tab = sizeof (ESODBC_ALL_TABLES ) - /*0-term*/ 1 ;
124
- }
125
- #if 1 // TODO: GH#4334
126
- if (cnt_tab == 0 ) {
127
- table = MK_WPTR (ESODBC_ALL_TABLES );
128
- cnt_tab = sizeof (ESODBC_ALL_TABLES ) - /*0-term*/ 1 ;
270
+
271
+ cnt_tab = swprintf (wbuf + pos , wbuf_len - pos , SQL_TABLES_TAB ,
272
+ (int )cnt_tab , table );
273
+ if (cnt_tab <= 0 ) {
274
+ ERRH (stmt , "failed to print 'table' for tables catalog SQL." );
275
+ RET_HDIAGS (stmt , SQL_STATE_HY000 );
276
+ } else {
277
+ pos += cnt_tab ;
278
+ }
129
279
}
130
- #endif // 1
131
280
132
- /* print SQL to send to server */
133
- pos = swprintf (wbuf , sizeof (wbuf )/sizeof (wbuf [0 ]), SQL_TABLES ,
134
- (int )cnt_cat , catalog , (int )cnt_tab , table );
135
- if (pos <= 0 ) {
136
- ERRH (stmt , "failed to print 'tables' catalog SQL." );
137
- RET_HDIAGS (stmt , SQL_STATE_HY000 );
281
+ if (TableType ) {
282
+ type = TableType ;
283
+ if (NameLength4 == SQL_NTS ) {
284
+ cnt_typ = wcslen (type );
285
+ if (ESODBC_MAX_IDENTIFIER_LEN < cnt_typ ) {
286
+ ERRH (stmt , "type identifier name '" LTPDL "' too long "
287
+ "(%zd. max=%d)." , (int )cnt_typ , type , cnt_typ ,
288
+ ESODBC_MAX_IDENTIFIER_LEN );
289
+ RET_HDIAG (stmt , SQL_STATE_HY090 , "type name too long" , 0 );
290
+ }
291
+ } else {
292
+ cnt_typ = NameLength4 ;
293
+ }
294
+
295
+ /* In this argument, "each value can be enclosed in single quotation
296
+ * marks (') or unquoted" => quote if not quoted (see GH#30398). */
297
+ if (! wcsnstr (type , cnt_typ , L'\'' )) {
298
+ cnt_typ = quote_tokens (type , cnt_typ , typ_buf );
299
+ type = typ_buf ;
300
+ }
301
+
302
+ cnt_typ = swprintf (wbuf + pos , wbuf_len - pos , SQL_TABLES_TYP ,
303
+ (int )cnt_typ , type );
304
+ if (cnt_typ <= 0 ) {
305
+ ERRH (stmt , "failed to print 'type' for tables catalog SQL." );
306
+ RET_HDIAGS (stmt , SQL_STATE_HY000 );
307
+ } else {
308
+ pos += cnt_typ ;
309
+ }
138
310
}
139
311
312
+ DBGH (stmt , "tables catalog SQL [%d]:`" LWPDL "`." , pos , pos , wbuf );
313
+
140
314
ret = EsSQLFreeStmt (stmt , ESODBC_SQL_CLOSE );
141
315
assert (SQL_SUCCEEDED (ret )); /* can't return error */
142
316
ret = attach_sql (stmt , wbuf , pos );
0 commit comments