Skip to content

Commit 13f4883

Browse files
committed
single quote table type arg in SQLTables()
The spec allows for this argument to contain a list of table types to filter by. The list of types can be given as quoted or unquoted tokens. ES/SQL only suppots the quoted synthax, so do the quoting in the driver. Note: no sanity check done by the driver, though (i.e. mixed quoted/unquoted or invalid characters). This isn't done for the other arguments either.
1 parent 3fcf521 commit 13f4883

File tree

4 files changed

+144
-38
lines changed

4 files changed

+144
-38
lines changed

driver/catalogue.c

Lines changed: 122 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,53 @@ SQLSMALLINT copy_current_catalog(esodbc_dbc_st *dbc, SQLWCHAR *dest,
132132
return used;
133133
}
134134

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+
DBG("len=%d.", len);
146+
copying = FALSE;
147+
pos = dest;
148+
for (i = 0; i < len; i ++) {
149+
DBG("src[%d]=%C, dest:`" LWPD "`.", i, src[i], dest);
150+
switch (src[i]) {
151+
/* ignore white space */
152+
case L' ':
153+
case L'\t':
154+
TRACE;
155+
if (copying) {
156+
*pos ++ = L'\''; /* end current token */
157+
copying = FALSE;
158+
}
159+
continue; /* don't copy WS */
160+
161+
case L',':
162+
TRACE;
163+
if (copying) {
164+
*pos ++ = L'\''; /* end current token */
165+
copying = FALSE;
166+
} /* else continue; -- to remove extra `,` */
167+
break;
168+
169+
default:
170+
TRACE;
171+
if (! copying) {
172+
*pos ++ = L'\''; /* start a new token */
173+
}
174+
copying = TRUE;
175+
}
176+
*pos ++ = src[i];
177+
}
178+
/* should not overrun */
179+
assert(i < 2/*see typ_buf below*/ * ESODBC_MAX_IDENTIFIER_LEN);
180+
return pos - dest;
181+
}
135182

136183
SQLRETURN EsSQLTablesW(
137184
SQLHSTMT StatementHandle,
@@ -146,29 +193,47 @@ SQLRETURN EsSQLTablesW(
146193
{
147194
esodbc_stmt_st *stmt = STMH(StatementHandle);
148195
SQLRETURN ret;
149-
SQLWCHAR wbuf[sizeof(SQL_TABLES) + 2 * ESODBC_MAX_IDENTIFIER_LEN];
150-
SQLWCHAR *table, *schema, *catalog;
151-
size_t cnt_tab, cnt_sch, cnt_cat, pos;
196+
/* b/c declaring an array with a const doesn't work with MSVC's compiler */
197+
enum wbuf_len { wbuf_len = sizeof(SQL_TABLES)
198+
+ sizeof(SQL_TABLES_CAT)
199+
+ sizeof(SQL_TABLES_TAB)
200+
+ sizeof(SQL_TABLES_TYP)
201+
+ 3 * ESODBC_MAX_IDENTIFIER_LEN /* it has 4x 0-term space */
202+
};
203+
SQLWCHAR wbuf[wbuf_len];
204+
SQLWCHAR *table, *schema, *catalog, *type;
205+
size_t cnt_tab, cnt_sch, cnt_cat, cnt_typ, pos;
206+
/* 2x: "a,b,c" -> "'a','b','c'" : each "x," => "'x'," */
207+
SQLWCHAR typ_buf[2 * ESODBC_MAX_IDENTIFIER_LEN];
152208

153209
if (stmt->metadata_id == SQL_TRUE)
154210
FIXME; // FIXME
155211

212+
pos = sizeof(SQL_TABLES) - 1;
213+
wmemcpy(wbuf, MK_WPTR(SQL_TABLES), pos);
214+
156215
if (CatalogName) {
157216
catalog = CatalogName;
158217
if (NameLength1 == SQL_NTS) {
159218
cnt_cat = wcslen(catalog);
160219
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_cat) {
161220
ERRH(stmt, "catalog identifier name '" LTPDL "' too long "
162-
"(%d. max=%d).", cnt_cat, catalog, cnt_cat,
221+
"(%zd. max=%d).", (int)cnt_cat, catalog, cnt_cat,
163222
ESODBC_MAX_IDENTIFIER_LEN);
164223
RET_HDIAG(stmt, SQL_STATE_HY090, "catalog name too long", 0);
165224
}
166225
} else {
167226
cnt_cat = NameLength1;
168227
}
169-
} else {
170-
catalog = MK_WPTR(SQL_ALL_CATALOGS);
171-
cnt_cat = sizeof(SQL_ALL_CATALOGS) - /*0-term*/1;
228+
229+
cnt_cat = swprintf(wbuf + pos, wbuf_len - pos, SQL_TABLES_CAT,
230+
(int)cnt_cat, catalog);
231+
if (cnt_cat <= 0) {
232+
ERRH(stmt, "failed to print 'catalog' for tables catalog SQL.");
233+
RET_HDIAGS(stmt, SQL_STATE_HY000);
234+
} else {
235+
pos += cnt_cat;
236+
}
172237
}
173238

174239
if (SchemaName) {
@@ -177,23 +242,20 @@ SQLRETURN EsSQLTablesW(
177242
cnt_sch = wcslen(schema);
178243
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_sch) {
179244
ERRH(stmt, "schema identifier name '" LTPDL "' too long "
180-
"(%d. max=%d).", cnt_sch, schema, cnt_sch,
245+
"(%zd. max=%d).", (int)cnt_sch, schema, cnt_sch,
181246
ESODBC_MAX_IDENTIFIER_LEN);
182247
RET_HDIAG(stmt, SQL_STATE_HY090, "schema name too long", 0);
183248
}
184249
} else {
185250
cnt_sch = NameLength2;
186251
}
187-
} else {
188-
schema = MK_WPTR(SQL_ALL_SCHEMAS);
189-
cnt_sch = sizeof(SQL_ALL_SCHEMAS) - /*0-term*/1;
190-
}
191252

192-
/* TODO: server support needed for sch. name filtering */
193-
if (cnt_sch && wszmemcmp(schema, MK_WPTR(SQL_ALL_SCHEMAS),
194-
(long)cnt_sch)) {
195-
ERRH(stmt, "filtering by schemas is not supported.");
196-
RET_HDIAG(stmt, SQL_STATE_IM001, "schema filtering not supported", 0);
253+
/* TODO: server support needed for sch. name filtering */
254+
if (wszmemcmp(schema, MK_WPTR(SQL_ALL_SCHEMAS), (long)cnt_sch)) {
255+
ERRH(stmt, "filtering by schemas is not supported.");
256+
RET_HDIAG(stmt, SQL_STATE_IM001, "schema filtering not supported",
257+
0);
258+
}
197259
}
198260

199261
// FIXME: string needs escaping of % \\ _
@@ -203,31 +265,58 @@ SQLRETURN EsSQLTablesW(
203265
cnt_tab = wcslen(table);
204266
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_tab) {
205267
ERRH(stmt, "table identifier name '" LTPDL "' too long "
206-
"(%d. max=%d).", cnt_tab, table, cnt_tab,
268+
"(%zd. max=%d).", (int)cnt_tab, table, cnt_tab,
207269
ESODBC_MAX_IDENTIFIER_LEN);
208270
RET_HDIAG(stmt, SQL_STATE_HY090, "table name too long", 0);
209271
}
210272
} else {
211273
cnt_tab = NameLength3;
212274
}
213-
} else {
214-
table = MK_WPTR(ESODBC_ALL_TABLES);
215-
cnt_tab = sizeof(ESODBC_ALL_TABLES) - /*0-term*/1;
216-
}
217-
#if 1 // TODO: GH#4334
218-
if (cnt_tab == 0) {
219-
table = MK_WPTR(ESODBC_ALL_TABLES);
220-
cnt_tab = sizeof(ESODBC_ALL_TABLES) - /*0-term*/1;
275+
276+
cnt_tab = swprintf(wbuf + pos, wbuf_len - pos, SQL_TABLES_TAB,
277+
(int)cnt_tab, table);
278+
if (cnt_tab <= 0) {
279+
ERRH(stmt, "failed to print 'table' for tables catalog SQL.");
280+
RET_HDIAGS(stmt, SQL_STATE_HY000);
281+
} else {
282+
pos += cnt_tab;
283+
}
221284
}
222-
#endif // 1
223285

224-
/* print SQL to send to server */
225-
pos = swprintf(wbuf, sizeof(wbuf)/sizeof(wbuf[0]), SQL_TABLES,
226-
(int)cnt_cat, catalog, (int)cnt_tab, table);
227-
if (pos <= 0) {
228-
ERRH(stmt, "failed to print 'tables' catalog SQL.");
229-
RET_HDIAGS(stmt, SQL_STATE_HY000);
286+
#if 1 // GH#30398
287+
if (TableType) {
288+
type = TableType;
289+
if (NameLength4 == SQL_NTS) {
290+
cnt_typ = wcslen(type);
291+
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_typ) {
292+
ERRH(stmt, "type identifier name '" LTPDL "' too long "
293+
"(%zd. max=%d).", (int)cnt_typ, type, cnt_typ,
294+
ESODBC_MAX_IDENTIFIER_LEN);
295+
RET_HDIAG(stmt, SQL_STATE_HY090, "type name too long", 0);
296+
}
297+
} else {
298+
cnt_typ = NameLength4;
299+
}
300+
301+
/* In this argument, "each value can be enclosed in single quotation
302+
* marks (') or unquoted" => quote if not quoted (see GH#30398). */
303+
if (! wcsnstr(type, cnt_typ, L'\'')) {
304+
cnt_typ = quote_tokens(type, cnt_typ, typ_buf);
305+
type = typ_buf;
306+
}
307+
308+
cnt_typ = swprintf(wbuf + pos, wbuf_len - pos, SQL_TABLES_TYP,
309+
(int)cnt_typ, type);
310+
if (cnt_typ <= 0) {
311+
ERRH(stmt, "failed to print 'type' for tables catalog SQL.");
312+
RET_HDIAGS(stmt, SQL_STATE_HY000);
313+
} else {
314+
pos += cnt_typ;
315+
}
230316
}
317+
#endif // 0
318+
319+
DBGH(stmt, "tables catalog SQL [%d]:`" LWPDL "`.", pos, pos, wbuf);
231320

232321
ret = EsSQLFreeStmt(stmt, ESODBC_SQL_CLOSE);
233322
assert(SQL_SUCCEEDED(ret)); /* can't return error */

driver/defs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
#define ESODBC_MAX_CONCURRENT_ACTIVITIES 16
6060
/* maximum identifer length */
6161
/* TODO: review@alpha */
62-
#define ESODBC_MAX_IDENTIFIER_LEN 128
62+
/* match 'keyword' ES type lenght */
63+
#define ESODBC_MAX_IDENTIFIER_LEN 256
6364

6465

6566
/*

driver/util.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ int wmemncasecmp(const SQLWCHAR *a, const SQLWCHAR *b, size_t len)
103103
if (diff)
104104
break;
105105
}
106-
//DBG("`" LWPDL "` vs `" LWPDL "` => %d (len=%zd, i=%d).",
106+
//DBG("`" LWPDL "` vs `" LWPDL "` => %d (len=%zd, i=%d).",
107107
// len, a, len, b, diff, len, i);
108108
return diff;
109109
}
@@ -124,6 +124,17 @@ int wszmemcmp(const SQLWCHAR *a, const SQLWCHAR *b, long count)
124124
return *a - *b;
125125
}
126126

127+
const SQLWCHAR* wcsnstr(const SQLWCHAR *hay, size_t len, SQLWCHAR needle)
128+
{
129+
size_t i;
130+
for (i = 0; i < len; i ++) {
131+
if (hay[i] == needle) {
132+
return hay + i;
133+
}
134+
}
135+
return NULL;
136+
}
137+
127138
/* retuns the length of a buffer to hold the escaped variant of the unescaped
128139
* given json object */
129140
static inline size_t json_escaped_len(const char *json, size_t len)

driver/util.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,19 @@ int wmemncasecmp(const SQLWCHAR *a, const SQLWCHAR *b, size_t len);
8585
* either of them or until 'count' characters are evaluated. If 'count'
8686
* parameter is negative, it is ignored.
8787
*
88-
* This is useful in comparing SQL strings which the API allows to be passed
88+
* This is useful in comparing SQL strings which the API allows to be passed
8989
* either as 0-terminated or not (SQL_NTS).
9090
* The function does a single pass (no length evaluation of the strings).
9191
* wmemcmp() might read over the boundary of one of the objects, if the
9292
* provided 'count' paramter is not the minimum of the strings' length.
9393
*/
9494
int wszmemcmp(const SQLWCHAR *a, const SQLWCHAR *b, long count);
9595

96+
/*
97+
* wcsstr() variant for non-NTS.
98+
*/
99+
const SQLWCHAR* wcsnstr(const SQLWCHAR *hay, size_t len, SQLWCHAR needle);
100+
96101
typedef struct wstr {
97102
SQLWCHAR *str;
98103
size_t cnt;
@@ -119,7 +124,7 @@ BOOL wstr2bool(wstr_st *val);
119124
BOOL wstr2long(wstr_st *val, long *out);
120125

121126
#ifdef _WIN32
122-
/*
127+
/*
123128
* "[D]oes not null-terminate an output string if the input string length is
124129
* explicitly specified without a terminating null character. To
125130
* null-terminate an output string for this function, the application should
@@ -155,7 +160,7 @@ typedef cstr_st tstr_st;
155160
#endif /* UNICODE */
156161

157162

158-
/*
163+
/*
159164
* JSON-escapes a string.
160165
* If string len is 0, it assumes a NTS.
161166
* If output buffer (jout) is NULL, it returns the buffer size needed for

0 commit comments

Comments
 (0)