-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Catalog function fixes #6
Changes from all commits
43cead1
3fcf521
13f4883
f1c0fb5
48714fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,19 +28,153 @@ | |
#include "info.h" | ||
#include "queries.h" | ||
|
||
// TODO: add type (and schema, when supported) | ||
#define SQL_TABLES "SYS TABLES" \ | ||
" CATALOG LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \ | ||
|
||
#define SYS_CATALOGS \ | ||
"SYS CATALOGS" | ||
|
||
/* SYS TABLES syntax tokens; these need to stay broken down, since this | ||
* query makes a difference between a predicate being '%' or left out */ | ||
// TODO: schema, when supported | ||
#define SQL_TABLES \ | ||
"SYS TABLES" | ||
#define SQL_TABLES_CAT \ | ||
" CATALOG LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM | ||
#define SQL_TABLES_TAB \ | ||
" LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM | ||
#define SQL_TABLES_TYP \ | ||
" TYPE " WPFWP_LDESC | ||
|
||
// TODO add schema, when supported | ||
#define SQL_COLUMNS(...) "SYS COLUMNS" __VA_ARGS__ \ | ||
" TABLE LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \ | ||
" LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM | ||
#define SQL_COL_CAT \ | ||
#define SQL_COL_CAT \ | ||
" CATALOG " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \ | ||
|
||
|
||
/* writes into 'dest', of size 'room', the current catalog of 'dbc'. | ||
* returns negative on error, or the char count written otherwise */ | ||
SQLSMALLINT copy_current_catalog(esodbc_dbc_st *dbc, SQLWCHAR *dest, | ||
SQLSMALLINT room) | ||
{ | ||
esodbc_stmt_st *stmt = NULL; | ||
SQLSMALLINT used = -1; /*failure*/ | ||
SQLLEN row_cnt; | ||
SQLLEN ind_len = SQL_NULL_DATA; | ||
SQLWCHAR buff[ESODBC_MAX_IDENTIFIER_LEN]; | ||
SQLWCHAR *catalog; | ||
|
||
if (! SQL_SUCCEEDED(EsSQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))) { | ||
ERRH(dbc, "failed to alloc a statement handle."); | ||
return -1; | ||
} | ||
assert(stmt); | ||
|
||
if (! SQL_SUCCEEDED(attach_sql(stmt, MK_WPTR(SYS_CATALOGS), | ||
sizeof(SYS_CATALOGS) - 1))) { | ||
ERRH(dbc, "failed to attach query to statement."); | ||
goto end; | ||
} | ||
if (! SQL_SUCCEEDED(post_statement(stmt))) { | ||
ERRH(dbc, "failed to post query."); | ||
goto end; | ||
} | ||
|
||
/* check that we have received proper number of rows (non-0, less than | ||
* max allowed here) */ | ||
if (! SQL_SUCCEEDED(EsSQLRowCount(stmt, &row_cnt))) { | ||
ERRH(dbc, "failed to get result rows count."); | ||
goto end; | ||
} else if (row_cnt <= 0) { | ||
WARNH(stmt, "Elasticsearch returned no current catalog."); | ||
catalog = MK_WPTR(""); /* empty string, it's not quite an error */ | ||
} else { | ||
DBGH(stmt, "Elasticsearch catalogs rows count: %ld.", row_cnt); | ||
if (1 < row_cnt) { | ||
WARNH(dbc, "Elasticsearch connected to %d clusters, returning " | ||
"the first's name as current catalog.", row_cnt); | ||
} | ||
|
||
if (! SQL_SUCCEEDED(EsSQLBindCol(stmt, /*col#*/1, SQL_C_WCHAR, buff, | ||
sizeof(buff), &ind_len))) { | ||
ERRH(dbc, "failed to bind first column."); | ||
goto end; | ||
} | ||
if (! SQL_SUCCEEDED(EsSQLFetch(stmt))) { | ||
ERRH(stmt, "failed to fetch results."); | ||
goto end; | ||
} | ||
if (ind_len <= 0) { | ||
WARNH(dbc, "NULL catalog received."); /*tho maybe != NULL_DATA */ | ||
catalog = MK_WPTR(""); | ||
} else { | ||
catalog = buff; | ||
DBGH(dbc, "current catalog (first value returned): `" LWPD "`.", | ||
catalog); | ||
} | ||
} | ||
|
||
if (! SQL_SUCCEEDED(write_wptr(&dbc->hdr.diag, dest, catalog, room, | ||
&used))) { | ||
ERRH(dbc, "failed to copy catalog: `" LWPD "`.", catalog); | ||
used = -1; /* write_wptr() can change pointer, and still fail */ | ||
} | ||
|
||
end: | ||
/* safe even if no binding occured */ | ||
if (! SQL_SUCCEEDED(EsSQLFreeStmt(stmt, SQL_UNBIND))) { | ||
ERRH(stmt, "failed to unbind statement"); | ||
used = -1; | ||
} | ||
if (! SQL_SUCCEEDED(EsSQLFreeHandle(SQL_HANDLE_STMT, stmt))) { | ||
ERRH(dbc, "failed to free statement handle!"); | ||
} | ||
return used; | ||
} | ||
|
||
/* | ||
* Quote the tokens in a string: "a, b,,c" -> "'a','b',,'c'". | ||
* No string sanity done (garbage in, garbage out). | ||
*/ | ||
size_t quote_tokens(SQLWCHAR *src, size_t len, SQLWCHAR *dest) | ||
{ | ||
size_t i; | ||
BOOL copying; | ||
SQLWCHAR *pos; | ||
|
||
copying = FALSE; | ||
pos = dest; | ||
for (i = 0; i < len; i ++) { | ||
switch (src[i]) { | ||
/* ignore white space */ | ||
case L' ': | ||
case L'\t': | ||
if (copying) { | ||
*pos ++ = L'\''; /* end current token */ | ||
copying = FALSE; | ||
} | ||
continue; /* don't copy WS */ | ||
|
||
case L',': | ||
if (copying) { | ||
*pos ++ = L'\''; /* end current token */ | ||
copying = FALSE; | ||
} /* else continue; -- to remove extra `,` */ | ||
break; | ||
|
||
default: | ||
if (! copying) { | ||
*pos ++ = L'\''; /* start a new token */ | ||
} | ||
copying = TRUE; | ||
} | ||
*pos ++ = src[i]; | ||
} | ||
/* should not overrun */ | ||
assert(i < 2/*see typ_buf below*/ * ESODBC_MAX_IDENTIFIER_LEN); | ||
return pos - dest; | ||
} | ||
|
||
SQLRETURN EsSQLTablesW( | ||
SQLHSTMT StatementHandle, | ||
_In_reads_opt_(NameLength1) SQLWCHAR *CatalogName, | ||
|
@@ -54,29 +188,47 @@ SQLRETURN EsSQLTablesW( | |
{ | ||
esodbc_stmt_st *stmt = STMH(StatementHandle); | ||
SQLRETURN ret; | ||
SQLWCHAR wbuf[sizeof(SQL_TABLES) + 2 * ESODBC_MAX_IDENTIFIER_LEN]; | ||
SQLWCHAR *table, *schema, *catalog; | ||
size_t cnt_tab, cnt_sch, cnt_cat, pos; | ||
/* b/c declaring an array with a const doesn't work with MSVC's compiler */ | ||
enum wbuf_len { wbuf_len = sizeof(SQL_TABLES) | ||
+ sizeof(SQL_TABLES_CAT) | ||
+ sizeof(SQL_TABLES_TAB) | ||
+ sizeof(SQL_TABLES_TYP) | ||
+ 3 * ESODBC_MAX_IDENTIFIER_LEN /* it has 4x 0-term space */ | ||
}; | ||
SQLWCHAR wbuf[wbuf_len]; | ||
SQLWCHAR *table, *schema, *catalog, *type; | ||
size_t cnt_tab, cnt_sch, cnt_cat, cnt_typ, pos; | ||
/* 2x: "a,b,c" -> "'a','b','c'" : each "x," => "'x'," */ | ||
SQLWCHAR typ_buf[2 * ESODBC_MAX_IDENTIFIER_LEN]; | ||
|
||
if (stmt->metadata_id == SQL_TRUE) | ||
FIXME; // FIXME | ||
|
||
pos = sizeof(SQL_TABLES) - 1; | ||
wmemcpy(wbuf, MK_WPTR(SQL_TABLES), pos); | ||
|
||
if (CatalogName) { | ||
catalog = CatalogName; | ||
if (NameLength1 == SQL_NTS) { | ||
cnt_cat = wcslen(catalog); | ||
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_cat) { | ||
ERRH(stmt, "catalog identifier name '" LTPDL "' too long " | ||
"(%d. max=%d).", cnt_cat, catalog, cnt_cat, | ||
"(%zd. max=%d).", (int)cnt_cat, catalog, cnt_cat, | ||
ESODBC_MAX_IDENTIFIER_LEN); | ||
RET_HDIAG(stmt, SQL_STATE_HY090, "catalog name too long", 0); | ||
} | ||
} else { | ||
cnt_cat = NameLength1; | ||
} | ||
} else { | ||
catalog = MK_WPTR(SQL_ALL_CATALOGS); | ||
cnt_cat = sizeof(SQL_ALL_CATALOGS) - /*0-term*/1; | ||
|
||
cnt_cat = swprintf(wbuf + pos, wbuf_len - pos, SQL_TABLES_CAT, | ||
(int)cnt_cat, catalog); | ||
if (cnt_cat <= 0) { | ||
ERRH(stmt, "failed to print 'catalog' for tables catalog SQL."); | ||
RET_HDIAGS(stmt, SQL_STATE_HY000); | ||
} else { | ||
pos += cnt_cat; | ||
} | ||
} | ||
|
||
if (SchemaName) { | ||
|
@@ -85,23 +237,20 @@ SQLRETURN EsSQLTablesW( | |
cnt_sch = wcslen(schema); | ||
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_sch) { | ||
ERRH(stmt, "schema identifier name '" LTPDL "' too long " | ||
"(%d. max=%d).", cnt_sch, schema, cnt_sch, | ||
"(%zd. max=%d).", (int)cnt_sch, schema, cnt_sch, | ||
ESODBC_MAX_IDENTIFIER_LEN); | ||
RET_HDIAG(stmt, SQL_STATE_HY090, "schema name too long", 0); | ||
} | ||
} else { | ||
cnt_sch = NameLength2; | ||
} | ||
} else { | ||
schema = MK_WPTR(SQL_ALL_SCHEMAS); | ||
cnt_sch = sizeof(SQL_ALL_SCHEMAS) - /*0-term*/1; | ||
} | ||
|
||
/* TODO: server support needed for sch. name filtering */ | ||
if (cnt_sch && wszmemcmp(schema, MK_WPTR(SQL_ALL_SCHEMAS), | ||
(long)cnt_sch)) { | ||
ERRH(stmt, "filtering by schemas is not supported."); | ||
RET_HDIAG(stmt, SQL_STATE_IM001, "schema filtering not supported", 0); | ||
/* TODO: server support needed for sch. name filtering */ | ||
if (wszmemcmp(schema, MK_WPTR(SQL_ALL_SCHEMAS), (long)cnt_sch)) { | ||
ERRH(stmt, "filtering by schemas is not supported."); | ||
RET_HDIAG(stmt, SQL_STATE_IM001, "schema filtering not supported", | ||
0); | ||
} | ||
} | ||
|
||
// FIXME: string needs escaping of % \\ _ | ||
|
@@ -111,32 +260,57 @@ SQLRETURN EsSQLTablesW( | |
cnt_tab = wcslen(table); | ||
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_tab) { | ||
ERRH(stmt, "table identifier name '" LTPDL "' too long " | ||
"(%d. max=%d).", cnt_tab, table, cnt_tab, | ||
"(%zd. max=%d).", (int)cnt_tab, table, cnt_tab, | ||
ESODBC_MAX_IDENTIFIER_LEN); | ||
RET_HDIAG(stmt, SQL_STATE_HY090, "table name too long", 0); | ||
} | ||
} else { | ||
cnt_tab = NameLength3; | ||
} | ||
} else { | ||
table = MK_WPTR(ESODBC_ALL_TABLES); | ||
cnt_tab = sizeof(ESODBC_ALL_TABLES) - /*0-term*/1; | ||
} | ||
#if 1 // TODO: GH#4334 | ||
if (cnt_tab == 0) { | ||
table = MK_WPTR(ESODBC_ALL_TABLES); | ||
cnt_tab = sizeof(ESODBC_ALL_TABLES) - /*0-term*/1; | ||
|
||
cnt_tab = swprintf(wbuf + pos, wbuf_len - pos, SQL_TABLES_TAB, | ||
(int)cnt_tab, table); | ||
if (cnt_tab <= 0) { | ||
ERRH(stmt, "failed to print 'table' for tables catalog SQL."); | ||
RET_HDIAGS(stmt, SQL_STATE_HY000); | ||
} else { | ||
pos += cnt_tab; | ||
} | ||
} | ||
#endif // 1 | ||
|
||
/* print SQL to send to server */ | ||
pos = swprintf(wbuf, sizeof(wbuf)/sizeof(wbuf[0]), SQL_TABLES, | ||
(int)cnt_cat, catalog, (int)cnt_tab, table); | ||
if (pos <= 0) { | ||
ERRH(stmt, "failed to print 'tables' catalog SQL."); | ||
RET_HDIAGS(stmt, SQL_STATE_HY000); | ||
if (TableType) { | ||
type = TableType; | ||
if (NameLength4 == SQL_NTS) { | ||
cnt_typ = wcslen(type); | ||
if (ESODBC_MAX_IDENTIFIER_LEN < cnt_typ) { | ||
ERRH(stmt, "type identifier name '" LTPDL "' too long " | ||
"(%zd. max=%d).", (int)cnt_typ, type, cnt_typ, | ||
ESODBC_MAX_IDENTIFIER_LEN); | ||
RET_HDIAG(stmt, SQL_STATE_HY090, "type name too long", 0); | ||
} | ||
} else { | ||
cnt_typ = NameLength4; | ||
} | ||
|
||
/* In this argument, "each value can be enclosed in single quotation | ||
* marks (') or unquoted" => quote if not quoted (see GH#30398). */ | ||
if (! wcsnstr(type, cnt_typ, L'\'')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible that some of the tokens could be quoted already but not others? If that is possible then this won't work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is, but that would be an illegal syntax. The driver does a simple scan for |
||
cnt_typ = quote_tokens(type, cnt_typ, typ_buf); | ||
type = typ_buf; | ||
} | ||
|
||
cnt_typ = swprintf(wbuf + pos, wbuf_len - pos, SQL_TABLES_TYP, | ||
(int)cnt_typ, type); | ||
if (cnt_typ <= 0) { | ||
ERRH(stmt, "failed to print 'type' for tables catalog SQL."); | ||
RET_HDIAGS(stmt, SQL_STATE_HY000); | ||
} else { | ||
pos += cnt_typ; | ||
} | ||
} | ||
|
||
DBGH(stmt, "tables catalog SQL [%d]:`" LWPDL "`.", pos, pos, wbuf); | ||
|
||
ret = EsSQLFreeStmt(stmt, ESODBC_SQL_CLOSE); | ||
assert(SQL_SUCCEEDED(ret)); /* can't return error */ | ||
ret = attach_sql(stmt, wbuf, pos); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, with Visual Studio you're stuck with C90 aka C89. The background is here in case you didn't know why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Nice article.