16
16
17
17
UID = "elastic"
18
18
CONNECT_STRING = 'Driver={Elasticsearch Driver};UID=%s;PWD=%s;Secure=0;' % (UID , Elasticsearch .AUTH_PASSWORD )
19
- CATALOG = "elasticsearch" # nightly built
20
- #CATALOG = "distribution_run" # source built
19
+ CATALOG = "distribution_run" # source built, "elasticsearch": nightly builds
21
20
22
21
class Testing (unittest .TestCase ):
23
22
24
23
_data = None
25
24
_dsn = None
26
25
_pyodbc = None
26
+ _catalog = None
27
27
28
- def __init__ (self , test_data , dsn = None ):
28
+ def __init__ (self , test_data , catalog = CATALOG , dsn = None ):
29
29
super ().__init__ ()
30
30
self ._data = test_data
31
- self ._dsn = dsn if dsn else CONNECT_STRING
31
+ self ._catalog = catalog
32
+ if dsn :
33
+ if "Driver=" not in dsn :
34
+ self ._dsn = CONNECT_STRING + dsn
35
+ else :
36
+ self ._dsn = dsn
37
+ else :
38
+ self ._dsn = CONNECT_STRING
32
39
print ("Using DSN: '%s'." % self ._dsn )
33
40
34
41
# only import pyODBC if running tests (vs. for instance only loading test data in ES)
@@ -120,8 +127,8 @@ def _catalog_tables(self, no_table_type_as=""):
120
127
res = curs .tables ("" , "%" , "" , no_table_type_as ).fetchall ()
121
128
self .assertEqual (len (res ), 1 )
122
129
for i in range (0 ,10 ):
123
- self .assertEqual (res [0 ][i ], None if i else CATALOG )
124
- #self.assertEqual(res, [tuple([CATALOG ] + [None for i in range(9)])]) # XXX?
130
+ self .assertEqual (res [0 ][i ], None if i else self . _catalog )
131
+ #self.assertEqual(res, [tuple([self._catalog ] + [None for i in range(9)])]) # XXX?
125
132
126
133
# enumerate table types
127
134
res = curs .tables ("" , "" , "" , "%" ).fetchall ()
@@ -146,11 +153,12 @@ def _catalog_columns(self, use_catalog=False, use_surrogate=True):
146
153
cnxn .autocommit = True
147
154
curs = cnxn .cursor ()
148
155
if not use_surrogate :
149
- res = curs .columns (table = TestData .BATTERS_INDEX , catalog = CATALOG if use_catalog else None ).fetchall ()
156
+ res = curs .columns (table = TestData .BATTERS_INDEX , \
157
+ catalog = self ._catalog if use_catalog else None ).fetchall ()
150
158
else :
151
159
if use_catalog :
152
160
stmt = "SYS COLUMNS CATALOG '%s' TABLE LIKE '%s' ESCAPE '\\ ' LIKE '%%' ESCAPE '\\ '" % \
153
- (CATALOG , TestData .BATTERS_INDEX )
161
+ (self . _catalog , TestData .BATTERS_INDEX )
154
162
else :
155
163
stmt = "SYS COLUMNS TABLE LIKE '%s' ESCAPE '\\ ' LIKE '%%' ESCAPE '\\ '" % TestData .BATTERS_INDEX
156
164
res = curs .execute (stmt )
@@ -207,6 +215,8 @@ def _type_to_instance(self, data_type, data_val):
207
215
instance = float (data_val )
208
216
elif data_type == "float" :
209
217
instance = float (data_val .strip ("fF" ))
218
+ # reduce precision, py's float is a double
219
+ instance = ctypes .c_float (instance ).value
210
220
elif data_type in ["datetime" , "date" , "time" ]:
211
221
fmt = "%H:%M:%S"
212
222
fmt = "%Y-%m-%dT" + fmt
@@ -257,32 +267,65 @@ def _proto_tests(self):
257
267
for t in tests :
258
268
(query , col_name , data_type , data_val , cli_val , disp_size ) = t
259
269
# print("T: %s, %s, %s, %s, %s, %s" % (query, col_name, data_type, data_val, cli_val, disp_size))
260
- with cnxn .execute (query ) as curs :
261
- self .assertEqual (curs .rowcount , 1 )
262
- res = curs .fetchone ()[0 ]
263
-
264
- if data_val != cli_val : # INTERVAL tests
265
- assert (query .lower ().startswith ("select interval" ))
266
- # extract the literal value (`INTERVAL -'1 1' -> `-1 1``)
267
- expect = re .match ("[^-]*(-?\s*'[^']*').*" , query ).groups ()[0 ]
268
- expect = expect .replace ("'" , "" )
269
- # filter out tests with fractional seconds:
270
- # https://github.com/elastic/elasticsearch/issues/41635
271
- if re .search ("\d*\.\d+" , expect ):
272
- continue
273
- else : # non-INTERVAL tests
274
- assert (data_type .lower () == data_type )
275
- # Change the value read in the tests to type and format of the result expected to be
276
- # returned by driver.
277
- expect = self ._type_to_instance (data_type , data_val )
278
-
279
- self .assertEqual (res , expect )
270
+
271
+ if data_val != cli_val : # INTERVAL tests
272
+ assert (query .lower ().startswith ("select interval" ))
273
+ # extract the literal value (`INTERVAL -'1 1' -> `-1 1``)
274
+ expect = re .match ("[^-]*(-?\s*'[^']*').*" , query ).groups ()[0 ]
275
+ expect = expect .replace ("'" , "" )
276
+ # filter out tests with fractional seconds:
277
+ # https://github.com/elastic/elasticsearch/issues/41635
278
+ if re .search ("\d*\.\d+" , expect ):
279
+ continue
280
+ # intervals not supported as params; PyODBC has no interval type support
281
+ # https://github.com/elastic/elasticsearch/issues/45915
282
+ params = []
283
+ else : # non-INTERVAL tests
284
+ assert (data_type .lower () == data_type )
285
+ # Change the value read in the tests to type and format of the result expected to be
286
+ # returned by driver.
287
+ expect = self ._type_to_instance (data_type , data_val )
288
+
289
+ if data_type .lower () == "null" :
290
+ query += " WHERE ? IS NULL"
291
+ params = [expect ]
292
+ else :
293
+ if data_type .lower () == "time" :
294
+ if col_name .find ("+" ) <= 0 :
295
+ # ODBC's TIME_STRUCT lacks fractional component -> strip it away
296
+ col_name = re .sub (r"(\d{2})\.\d+" , "\\ 1" , col_name )
297
+ query += " WHERE %s = ?" % col_name
298
+ params = [expect ]
299
+ else : # it's a time with offset
300
+ # TIE_STRUCT lacks offset component -> perform the simple SELECT
301
+ params = []
302
+ else :
303
+ query += " WHERE %s = ?" % col_name
304
+ params = [expect ]
305
+ # print("Query: %s" % query)
306
+
307
+ last_ex = None
308
+ with cnxn .execute (query , * params ) as curs :
309
+ try :
310
+ self .assertEqual (curs .rowcount , 1 )
311
+ res = curs .fetchone ()[0 ]
312
+ if data_type == "float" :
313
+ # PyODBC will fetch a REAL/float as a double => reduce precision
314
+ res = ctypes .c_float (res ).value
315
+ self .assertEqual (res , expect )
316
+ except Exception as e :
317
+ print (e )
318
+ last_ex = e
319
+
320
+ if last_ex :
321
+ raise last_ex
322
+
280
323
finally :
281
324
cnxn .clear_output_converters ()
282
325
283
326
def perform (self ):
284
327
self ._check_info (self ._pyodbc .SQL_USER_NAME , UID )
285
- self ._check_info (self ._pyodbc .SQL_DATABASE_NAME , CATALOG )
328
+ self ._check_info (self ._pyodbc .SQL_DATABASE_NAME , self . _catalog )
286
329
287
330
# simulate catalog querying as apps do in ES/GH#40775 do
288
331
self ._catalog_tables (no_table_type_as = "" )
0 commit comments