1717#include "info.h"
1818#include "queries.h"
1919
20- // TODO: add type (and schema, when supported)
21- #define SQL_TABLES "SYS TABLES" \
22- " CATALOG LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \
20+
21+ #define SYS_CATALOGS \
22+ "SYS CATALOGS"
23+
24+ /* SYS TABLES syntax tokens; these need to stay broken down, since this
25+ * query makes a difference between a predicate being '%' or left out */
26+ // TODO: schema, when supported
27+ #define SQL_TABLES \
28+ "SYS TABLES"
29+ #define SQL_TABLES_CAT \
30+ " CATALOG LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM
31+ #define SQL_TABLES_TAB \
2332 " LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM
33+ #define SQL_TABLES_TYP \
34+ " TYPE " WPFWP_LDESC
2435
2536// TODO add schema, when supported
2637#define SQL_COLUMNS (...) "SYS COLUMNS" __VA_ARGS__ \
2738 " TABLE LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \
2839 " LIKE " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM
29- #define SQL_COL_CAT \
40+ #define SQL_COL_CAT \
3041 " CATALOG " ESODBC_STRING_DELIM WPFWP_LDESC ESODBC_STRING_DELIM \
3142
3243
44+ /* writes into 'dest', of size 'room', the current catalog of 'dbc'.
45+ * returns negative on error, or the char count written otherwise */
46+ SQLSMALLINT copy_current_catalog (esodbc_dbc_st * dbc , SQLWCHAR * dest ,
47+ SQLSMALLINT room )
48+ {
49+ esodbc_stmt_st * stmt = NULL ;
50+ SQLSMALLINT used = -1 ; /*failure*/
51+ SQLLEN row_cnt ;
52+ SQLLEN ind_len = SQL_NULL_DATA ;
53+ SQLWCHAR buff [ESODBC_MAX_IDENTIFIER_LEN ];
54+ SQLWCHAR * catalog ;
55+
56+ if (! SQL_SUCCEEDED (EsSQLAllocHandle (SQL_HANDLE_STMT , dbc , & stmt ))) {
57+ ERRH (dbc , "failed to alloc a statement handle." );
58+ return -1 ;
59+ }
60+ assert (stmt );
61+
62+ if (! SQL_SUCCEEDED (attach_sql (stmt , MK_WPTR (SYS_CATALOGS ),
63+ sizeof (SYS_CATALOGS ) - 1 ))) {
64+ ERRH (dbc , "failed to attach query to statement." );
65+ goto end ;
66+ }
67+ if (! SQL_SUCCEEDED (post_statement (stmt ))) {
68+ ERRH (dbc , "failed to post query." );
69+ goto end ;
70+ }
71+
72+ /* check that we have received proper number of rows (non-0, less than
73+ * max allowed here) */
74+ if (! SQL_SUCCEEDED (EsSQLRowCount (stmt , & row_cnt ))) {
75+ ERRH (dbc , "failed to get result rows count." );
76+ goto end ;
77+ } else if (row_cnt <= 0 ) {
78+ WARNH (stmt , "Elasticsearch returned no current catalog." );
79+ catalog = MK_WPTR ("" ); /* empty string, it's not quite an error */
80+ } else {
81+ DBGH (stmt , "Elasticsearch catalogs rows count: %ld." , row_cnt );
82+ if (1 < row_cnt ) {
83+ WARNH (dbc , "Elasticsearch connected to %d clusters, returning "
84+ "the first's name as current catalog." , row_cnt );
85+ }
86+
87+ if (! SQL_SUCCEEDED (EsSQLBindCol (stmt , /*col#*/ 1 , SQL_C_WCHAR , buff ,
88+ sizeof (buff ), & ind_len ))) {
89+ ERRH (dbc , "failed to bind first column." );
90+ goto end ;
91+ }
92+ if (! SQL_SUCCEEDED (EsSQLFetch (stmt ))) {
93+ ERRH (stmt , "failed to fetch results." );
94+ goto end ;
95+ }
96+ if (ind_len <= 0 ) {
97+ WARNH (dbc , "NULL catalog received." ); /*tho maybe != NULL_DATA */
98+ catalog = MK_WPTR ("" );
99+ } else {
100+ catalog = buff ;
101+ DBGH (dbc , "current catalog (first value returned): `" LWPD "`." ,
102+ catalog );
103+ }
104+ }
105+
106+ if (! SQL_SUCCEEDED (write_wptr (& dbc -> hdr .diag , dest , catalog , room ,
107+ & used ))) {
108+ ERRH (dbc , "failed to copy catalog: `" LWPD "`." , catalog );
109+ used = -1 ; /* write_wptr() can change pointer, and still fail */
110+ }
111+
112+ end :
113+ /* safe even if no binding occured */
114+ if (! SQL_SUCCEEDED (EsSQLFreeStmt (stmt , SQL_UNBIND ))) {
115+ ERRH (stmt , "failed to unbind statement" );
116+ used = -1 ;
117+ }
118+ if (! SQL_SUCCEEDED (EsSQLFreeHandle (SQL_HANDLE_STMT , stmt ))) {
119+ ERRH (dbc , "failed to free statement handle!" );
120+ }
121+ return used ;
122+ }
123+
124+ /*
125+ * Quote the tokens in a string: "a, b,,c" -> "'a','b',,'c'".
126+ * No string sanity done (garbage in, garbage out).
127+ */
128+ size_t quote_tokens (SQLWCHAR * src , size_t len , SQLWCHAR * dest )
129+ {
130+ size_t i ;
131+ BOOL copying ;
132+ SQLWCHAR * pos ;
133+
134+ copying = FALSE;
135+ pos = dest ;
136+ for (i = 0 ; i < len ; i ++ ) {
137+ switch (src [i ]) {
138+ /* ignore white space */
139+ case L' ' :
140+ case L'\t' :
141+ if (copying ) {
142+ * pos ++ = L'\'' ; /* end current token */
143+ copying = FALSE;
144+ }
145+ continue ; /* don't copy WS */
146+
147+ case L',' :
148+ if (copying ) {
149+ * pos ++ = L'\'' ; /* end current token */
150+ copying = FALSE;
151+ } /* else continue; -- to remove extra `,` */
152+ break ;
153+
154+ default :
155+ if (! copying ) {
156+ * pos ++ = L'\'' ; /* start a new token */
157+ }
158+ copying = TRUE;
159+ }
160+ * pos ++ = src [i ];
161+ }
162+ /* should not overrun */
163+ assert (i < 2 /*see typ_buf below*/ * ESODBC_MAX_IDENTIFIER_LEN );
164+ return pos - dest ;
165+ }
166+
33167SQLRETURN EsSQLTablesW (
34168 SQLHSTMT StatementHandle ,
35169 _In_reads_opt_ (NameLength1 ) SQLWCHAR * CatalogName ,
@@ -43,29 +177,47 @@ SQLRETURN EsSQLTablesW(
43177{
44178 esodbc_stmt_st * stmt = STMH (StatementHandle );
45179 SQLRETURN ret ;
46- SQLWCHAR wbuf [sizeof (SQL_TABLES ) + 2 * ESODBC_MAX_IDENTIFIER_LEN ];
47- SQLWCHAR * table , * schema , * catalog ;
48- size_t cnt_tab , cnt_sch , cnt_cat , pos ;
180+ /* b/c declaring an array with a const doesn't work with MSVC's compiler */
181+ enum wbuf_len { wbuf_len = sizeof (SQL_TABLES )
182+ + sizeof (SQL_TABLES_CAT )
183+ + sizeof (SQL_TABLES_TAB )
184+ + sizeof (SQL_TABLES_TYP )
185+ + 3 * ESODBC_MAX_IDENTIFIER_LEN /* it has 4x 0-term space */
186+ };
187+ SQLWCHAR wbuf [wbuf_len ];
188+ SQLWCHAR * table , * schema , * catalog , * type ;
189+ size_t cnt_tab , cnt_sch , cnt_cat , cnt_typ , pos ;
190+ /* 2x: "a,b,c" -> "'a','b','c'" : each "x," => "'x'," */
191+ SQLWCHAR typ_buf [2 * ESODBC_MAX_IDENTIFIER_LEN ];
49192
50193 if (stmt -> metadata_id == SQL_TRUE )
51194 FIXME ; // FIXME
52195
196+ pos = sizeof (SQL_TABLES ) - 1 ;
197+ wmemcpy (wbuf , MK_WPTR (SQL_TABLES ), pos );
198+
53199 if (CatalogName ) {
54200 catalog = CatalogName ;
55201 if (NameLength1 == SQL_NTS ) {
56202 cnt_cat = wcslen (catalog );
57203 if (ESODBC_MAX_IDENTIFIER_LEN < cnt_cat ) {
58204 ERRH (stmt , "catalog identifier name '" LTPDL "' too long "
59- "(%d . max=%d)." , cnt_cat , catalog , cnt_cat ,
205+ "(%zd . max=%d)." , ( int ) cnt_cat , catalog , cnt_cat ,
60206 ESODBC_MAX_IDENTIFIER_LEN );
61207 RET_HDIAG (stmt , SQL_STATE_HY090 , "catalog name too long" , 0 );
62208 }
63209 } else {
64210 cnt_cat = NameLength1 ;
65211 }
66- } else {
67- catalog = MK_WPTR (SQL_ALL_CATALOGS );
68- cnt_cat = sizeof (SQL_ALL_CATALOGS ) - /*0-term*/ 1 ;
212+
213+ cnt_cat = swprintf (wbuf + pos , wbuf_len - pos , SQL_TABLES_CAT ,
214+ (int )cnt_cat , catalog );
215+ if (cnt_cat <= 0 ) {
216+ ERRH (stmt , "failed to print 'catalog' for tables catalog SQL." );
217+ RET_HDIAGS (stmt , SQL_STATE_HY000 );
218+ } else {
219+ pos += cnt_cat ;
220+ }
69221 }
70222
71223 if (SchemaName ) {
@@ -74,23 +226,20 @@ SQLRETURN EsSQLTablesW(
74226 cnt_sch = wcslen (schema );
75227 if (ESODBC_MAX_IDENTIFIER_LEN < cnt_sch ) {
76228 ERRH (stmt , "schema identifier name '" LTPDL "' too long "
77- "(%d . max=%d)." , cnt_sch , schema , cnt_sch ,
229+ "(%zd . max=%d)." , ( int ) cnt_sch , schema , cnt_sch ,
78230 ESODBC_MAX_IDENTIFIER_LEN );
79231 RET_HDIAG (stmt , SQL_STATE_HY090 , "schema name too long" , 0 );
80232 }
81233 } else {
82234 cnt_sch = NameLength2 ;
83235 }
84- } else {
85- schema = MK_WPTR (SQL_ALL_SCHEMAS );
86- cnt_sch = sizeof (SQL_ALL_SCHEMAS ) - /*0-term*/ 1 ;
87- }
88236
89- /* TODO: server support needed for sch. name filtering */
90- if (cnt_sch && wszmemcmp (schema , MK_WPTR (SQL_ALL_SCHEMAS ),
91- (long )cnt_sch )) {
92- ERRH (stmt , "filtering by schemas is not supported." );
93- RET_HDIAG (stmt , SQL_STATE_IM001 , "schema filtering not supported" , 0 );
237+ /* TODO: server support needed for sch. name filtering */
238+ if (wszmemcmp (schema , MK_WPTR (SQL_ALL_SCHEMAS ), (long )cnt_sch )) {
239+ ERRH (stmt , "filtering by schemas is not supported." );
240+ RET_HDIAG (stmt , SQL_STATE_IM001 , "schema filtering not supported" ,
241+ 0 );
242+ }
94243 }
95244
96245 // FIXME: string needs escaping of % \\ _
@@ -100,32 +249,57 @@ SQLRETURN EsSQLTablesW(
100249 cnt_tab = wcslen (table );
101250 if (ESODBC_MAX_IDENTIFIER_LEN < cnt_tab ) {
102251 ERRH (stmt , "table identifier name '" LTPDL "' too long "
103- "(%d . max=%d)." , cnt_tab , table , cnt_tab ,
252+ "(%zd . max=%d)." , ( int ) cnt_tab , table , cnt_tab ,
104253 ESODBC_MAX_IDENTIFIER_LEN );
105254 RET_HDIAG (stmt , SQL_STATE_HY090 , "table name too long" , 0 );
106255 }
107256 } else {
108257 cnt_tab = NameLength3 ;
109258 }
110- } else {
111- table = MK_WPTR (ESODBC_ALL_TABLES );
112- cnt_tab = sizeof (ESODBC_ALL_TABLES ) - /*0-term*/ 1 ;
113- }
114- #if 1 // TODO: GH#4334
115- if (cnt_tab == 0 ) {
116- table = MK_WPTR (ESODBC_ALL_TABLES );
117- cnt_tab = sizeof (ESODBC_ALL_TABLES ) - /*0-term*/ 1 ;
259+
260+ cnt_tab = swprintf (wbuf + pos , wbuf_len - pos , SQL_TABLES_TAB ,
261+ (int )cnt_tab , table );
262+ if (cnt_tab <= 0 ) {
263+ ERRH (stmt , "failed to print 'table' for tables catalog SQL." );
264+ RET_HDIAGS (stmt , SQL_STATE_HY000 );
265+ } else {
266+ pos += cnt_tab ;
267+ }
118268 }
119- #endif // 1
120269
121- /* print SQL to send to server */
122- pos = swprintf (wbuf , sizeof (wbuf )/sizeof (wbuf [0 ]), SQL_TABLES ,
123- (int )cnt_cat , catalog , (int )cnt_tab , table );
124- if (pos <= 0 ) {
125- ERRH (stmt , "failed to print 'tables' catalog SQL." );
126- RET_HDIAGS (stmt , SQL_STATE_HY000 );
270+ if (TableType ) {
271+ type = TableType ;
272+ if (NameLength4 == SQL_NTS ) {
273+ cnt_typ = wcslen (type );
274+ if (ESODBC_MAX_IDENTIFIER_LEN < cnt_typ ) {
275+ ERRH (stmt , "type identifier name '" LTPDL "' too long "
276+ "(%zd. max=%d)." , (int )cnt_typ , type , cnt_typ ,
277+ ESODBC_MAX_IDENTIFIER_LEN );
278+ RET_HDIAG (stmt , SQL_STATE_HY090 , "type name too long" , 0 );
279+ }
280+ } else {
281+ cnt_typ = NameLength4 ;
282+ }
283+
284+ /* In this argument, "each value can be enclosed in single quotation
285+ * marks (') or unquoted" => quote if not quoted (see GH#30398). */
286+ if (! wcsnstr (type , cnt_typ , L'\'' )) {
287+ cnt_typ = quote_tokens (type , cnt_typ , typ_buf );
288+ type = typ_buf ;
289+ }
290+
291+ cnt_typ = swprintf (wbuf + pos , wbuf_len - pos , SQL_TABLES_TYP ,
292+ (int )cnt_typ , type );
293+ if (cnt_typ <= 0 ) {
294+ ERRH (stmt , "failed to print 'type' for tables catalog SQL." );
295+ RET_HDIAGS (stmt , SQL_STATE_HY000 );
296+ } else {
297+ pos += cnt_typ ;
298+ }
127299 }
128300
301+ DBGH (stmt , "tables catalog SQL [%d]:`" LWPDL "`." , pos , pos , wbuf );
302+
129303 ret = EsSQLFreeStmt (stmt , ESODBC_SQL_CLOSE );
130304 assert (SQL_SUCCEEDED (ret )); /* can't return error */
131305 ret = attach_sql (stmt , wbuf , pos );
0 commit comments