Skip to content
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

Merged
merged 5 commits into from
May 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 211 additions & 37 deletions driver/catalogue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 */
Copy link
Contributor

@droberts195 droberts195 May 10, 2018

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Nice article.

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) {
Expand All @@ -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 % \\ _
Expand All @@ -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'\'')) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 ' in the received parameter and if none is found, it applies the quoting. If some tokens would be quoted but others not, the driver would pass the argument as is to the plug-in (which would then fail the query due to wrong syntax).
The application could generate illegal SQL in many ways (ex. 'TABLE',,'ALIAS'). But the driver doesn't validate these, since ES/SQL will anyways.

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);
Expand Down
6 changes: 6 additions & 0 deletions driver/catalogue.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
#define __CATALOGUE_H__

#include "error.h"
#include "handles.h"


SQLSMALLINT copy_current_catalog(esodbc_dbc_st *dbc, SQLWCHAR *dest,
SQLSMALLINT room);


SQLRETURN EsSQLTablesW(
SQLHSTMT StatementHandle,
Expand Down
23 changes: 2 additions & 21 deletions driver/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "connect.h"
#include "queries.h"
#include "catalogue.h"
#include "log.h"
#include "info.h"
#include "util.h"
Expand Down Expand Up @@ -2095,26 +2096,6 @@ SQLRETURN EsSQLSetConnectAttrW(
return SQL_SUCCESS;
}

/* writes into 'dest', of size 'room', the current catalog of 'dbc'.
* returns negative on error, or the char count written otherwise */
static SQLSMALLINT get_current_catalog(esodbc_dbc_st *dbc, SQLWCHAR *dest,
SQLSMALLINT room)
{
SQLSMALLINT used;
SQLWCHAR *catalog = MK_WPTR("my_current_catalog"); // FIXME

//
// TODO: use the new SYS CATALOGS query
//

DBGH(dbc, "current catalog: `" LWPD "`.", catalog);
if (! SQL_SUCCEEDED(write_wptr(&dbc->hdr.diag, dest, catalog, room,
&used))) {
return -1;
}
return used;
}

SQLRETURN EsSQLGetConnectAttrW(
SQLHDBC ConnectionHandle,
SQLINTEGER Attribute,
Expand Down Expand Up @@ -2142,7 +2123,7 @@ SQLRETURN EsSQLGetConnectAttrW(
if (! dbc->es_types) {
ERRH(dbc, "no connection active.");
RET_HDIAGS(dbc, SQL_STATE_08003);
} else if ((used = get_current_catalog(dbc, (SQLWCHAR *)ValuePtr,
} else if ((used = copy_current_catalog(dbc, (SQLWCHAR *)ValuePtr,
(SQLSMALLINT)BufferLength)) < 0) {
ERRH(dbc, "failed to get current catalog.");
RET_STATE(dbc->hdr.diag.state);
Expand Down
3 changes: 2 additions & 1 deletion driver/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
#define ESODBC_MAX_CONCURRENT_ACTIVITIES 16
/* maximum identifer length */
/* TODO: review@alpha */
#define ESODBC_MAX_IDENTIFIER_LEN 128
/* match 'keyword' ES type lenght */
#define ESODBC_MAX_IDENTIFIER_LEN 256


/*
Expand Down
Loading