Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
singlestore-labs
GitHub Repository: singlestore-labs/singlestoredb-python
Path: blob/main/singlestoredb/mysql/tests/test_issues.py
469 views
1
# type: ignore
2
import datetime
3
import time
4
import warnings
5
6
import pytest
7
8
import singlestoredb.mysql as sv
9
from singlestoredb.mysql.tests import base
10
11
__all__ = ['TestOldIssues', 'TestNewIssues', 'TestGitHubIssues']
12
13
14
class TestOldIssues(base.PyMySQLTestCase):
15
16
def test_issue_3(self):
17
"""Undefined methods datetime_or_None, date_or_None."""
18
conn = self.connect()
19
c = conn.cursor()
20
with warnings.catch_warnings():
21
warnings.filterwarnings('ignore')
22
c.execute('drop table if exists issue3')
23
c.execute('create table issue3 (d date, t time, dt datetime, ts timestamp)')
24
try:
25
c.execute(
26
'insert into issue3 (d, t, dt, ts) values (%s,%s,%s,%s)',
27
(None, None, None, None),
28
)
29
c.execute('select d from issue3')
30
self.assertEqual(None, c.fetchone()[0])
31
c.execute('select t from issue3')
32
self.assertEqual(None, c.fetchone()[0])
33
c.execute('select dt from issue3')
34
self.assertEqual(None, c.fetchone()[0])
35
c.execute('select ts from issue3')
36
self.assertIn(
37
type(c.fetchone()[0]),
38
(type(None), datetime.datetime),
39
'expected Python type None or datetime from SQL timestamp',
40
)
41
finally:
42
c.execute('drop table issue3')
43
44
def test_issue_4(self):
45
"""Can't retrieve TIMESTAMP fields."""
46
conn = self.connect()
47
c = conn.cursor()
48
with warnings.catch_warnings():
49
warnings.filterwarnings('ignore')
50
c.execute('drop table if exists issue4')
51
c.execute('create table issue4 (ts timestamp)')
52
try:
53
c.execute('insert into issue4 (ts) values (now())')
54
c.execute('select ts from issue4')
55
self.assertTrue(isinstance(c.fetchone()[0], datetime.datetime))
56
finally:
57
c.execute('drop table issue4')
58
59
def test_issue_5(self):
60
"""Query on information_schema.tables fails."""
61
con = self.connect()
62
cur = con.cursor()
63
cur.execute('select * from information_schema.tables')
64
65
@pytest.mark.skip(reason='database is not created')
66
def test_issue_6(self):
67
"""TypeError: ord() expected a character, but string of length 0 found."""
68
# ToDo: this test requires access to db 'mysql'.
69
kwargs = self.databases[0].copy()
70
kwargs['database'] = 'mysql'
71
conn = sv.connect(**kwargs)
72
c = conn.cursor()
73
c.execute('select * from user')
74
conn.close()
75
76
def test_issue_8(self):
77
"""Primary Key and Index error when selecting data."""
78
conn = self.connect()
79
c = conn.cursor()
80
with warnings.catch_warnings():
81
warnings.filterwarnings('ignore')
82
c.execute('drop table if exists test')
83
c.execute(
84
"""CREATE TABLE `test` (`station` int NOT NULL DEFAULT '0', `dh`
85
datetime NOT NULL DEFAULT '2015-01-01 00:00:00', `echeance` int NOT NULL
86
DEFAULT '0', `me` double DEFAULT NULL, `mo` double DEFAULT NULL, PRIMARY
87
KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""",
88
)
89
try:
90
self.assertIn(c.execute('SELECT * FROM test'), [0, -1])
91
c.execute('ALTER TABLE `test` ADD INDEX `idx_station` (`station`)')
92
self.assertIn(c.execute('SELECT * FROM test'), [0, -1])
93
finally:
94
c.execute('drop table test')
95
96
def test_issue_13(self):
97
"""Can't handle large result fields."""
98
conn = self.connect()
99
cur = conn.cursor()
100
with warnings.catch_warnings():
101
warnings.filterwarnings('ignore')
102
cur.execute('drop table if exists issue13')
103
try:
104
cur.execute('create table issue13 (t text)')
105
# ticket says 18k
106
size = 18 * 1024
107
cur.execute('insert into issue13 (t) values (%s)', ('x' * size,))
108
cur.execute('select t from issue13')
109
# use assertTrue so that obscenely huge error messages don't print
110
r = cur.fetchone()[0]
111
self.assertTrue('x' * size == r)
112
finally:
113
cur.execute('drop table issue13')
114
115
def test_issue_15(self):
116
"""Query should be expanded before perform character encoding."""
117
conn = self.connect()
118
c = conn.cursor()
119
with warnings.catch_warnings():
120
warnings.filterwarnings('ignore')
121
c.execute('drop table if exists issue15')
122
c.execute('create table issue15 (t varchar(32))')
123
try:
124
c.execute('insert into issue15 (t) values (%s)', ('\xe4\xf6\xfc',))
125
c.execute('select t from issue15')
126
self.assertEqual('\xe4\xf6\xfc', c.fetchone()[0])
127
finally:
128
c.execute('drop table issue15')
129
130
def test_issue_16(self):
131
"""Patch for string and tuple escaping."""
132
conn = self.connect()
133
c = conn.cursor()
134
with warnings.catch_warnings():
135
warnings.filterwarnings('ignore')
136
c.execute('drop table if exists issue16')
137
c.execute(
138
'create table issue16 (name varchar(32) primary key, email varchar(32))',
139
)
140
try:
141
c.execute(
142
"insert into issue16 (name, email) values ('pete', 'floydophone')",
143
)
144
c.execute('select email from issue16 where name=%s', ('pete',))
145
self.assertEqual('floydophone', c.fetchone()[0])
146
finally:
147
c.execute('drop table issue16')
148
149
@pytest.mark.skip(
150
'test_issue_17() requires a custom, legacy MySQL configuration '
151
'and will not be run.',
152
)
153
def test_issue_17(self):
154
"""Could not connect mysql use password."""
155
conn = self.connect()
156
host = self.databases[0]['host']
157
db = self.databases[0]['database']
158
c = conn.cursor()
159
160
# grant access to a table to a user with a password
161
try:
162
with warnings.catch_warnings():
163
warnings.filterwarnings('ignore')
164
c.execute('drop table if exists issue17')
165
c.execute('create table issue17 (x varchar(32) primary key)')
166
c.execute("insert into issue17 (x) values ('hello, world!')")
167
c.execute(
168
(
169
"grant all privileges on %s.issue17 to 'issue17user'@'%%' "
170
"identified by '1234'"
171
) % db,
172
)
173
conn.commit()
174
175
conn2 = sv.connect(host=host, user='issue17user', passwd='1234', db=db)
176
c2 = conn2.cursor()
177
c2.execute('select x from issue17')
178
self.assertEqual('hello, world!', c2.fetchone()[0])
179
finally:
180
c.execute('drop table issue17')
181
182
183
class TestNewIssues(base.PyMySQLTestCase):
184
185
def test_issue_34(self):
186
try:
187
sv.connect(host='localhost', port=1237, user='root')
188
self.fail()
189
except sv.OperationalError as e:
190
self.assertEqual(2003, e.args[0])
191
except Exception:
192
self.fail()
193
194
def test_issue_33(self):
195
conn = sv.connect(charset='utf8', **self.databases[0])
196
self.safe_create_table(
197
conn, 'hei\xdfe', 'create table hei\xdfe (name varchar(32))',
198
)
199
c = conn.cursor()
200
c.execute("insert into hei\xdfe (name) values ('Pi\xdfata')")
201
c.execute('select name from hei\xdfe')
202
self.assertEqual('Pi\xdfata', c.fetchone()[0])
203
204
@pytest.mark.skip('This test requires manual intervention')
205
def test_issue_35(self):
206
conn = self.connect()
207
c = conn.cursor()
208
print('sudo killall -9 mysqld within the next 10 seconds')
209
try:
210
c.execute('select sleep(10)')
211
self.fail()
212
except sv.OperationalError as e:
213
self.assertEqual(2013, e.args[0])
214
215
def test_issue_36(self):
216
# connection 0 is super user, connection 1 isn't
217
conn = self.connections[1]
218
c = conn.cursor()
219
c.execute('show processlist')
220
kill_id = None
221
for row in c.fetchall():
222
id = row[0]
223
info = row[7]
224
if info == 'show processlist':
225
kill_id = id
226
break
227
self.assertEqual(kill_id, conn.thread_id())
228
# now nuke the connection
229
self.connections[0].kill(kill_id)
230
# make sure this connection has broken
231
try:
232
c.execute('show tables')
233
self.fail()
234
except Exception:
235
pass
236
c.close()
237
conn.close()
238
239
# check the process list from the other connection
240
try:
241
# Wait since Travis-CI sometimes fail this test.
242
time.sleep(0.1)
243
244
c = self.connections[0].cursor()
245
c.execute('show processlist')
246
ids = [row[0] for row in c.fetchall()]
247
self.assertFalse(kill_id in ids)
248
finally:
249
del self.connections[1]
250
251
@pytest.mark.skip(reason='@foo is not set in SingleStoreDB')
252
def test_issue_37(self):
253
conn = self.connect()
254
c = conn.cursor()
255
self.assertEqual(1, c.execute('SELECT @foo'))
256
self.assertEqual((None,), c.fetchone())
257
self.assertEqual(0, c.execute("SET @foo = 'bar'"))
258
c.execute("set @foo = 'bar'")
259
260
def test_issue_38(self):
261
conn = self.connect()
262
c = conn.cursor()
263
datum = 'a' * 1024 * 1023 # reduced size for most default mysql installs
264
265
try:
266
with warnings.catch_warnings():
267
warnings.filterwarnings('ignore')
268
c.execute('drop table if exists issue38')
269
c.execute('create table issue38 (id integer, data mediumblob)')
270
c.execute('insert into issue38 values (1, %s)', (datum,))
271
finally:
272
c.execute('drop table issue38')
273
274
def disabled_test_issue_54(self):
275
conn = self.connect()
276
c = conn.cursor()
277
with warnings.catch_warnings():
278
warnings.filterwarnings('ignore')
279
c.execute('drop table if exists issue54')
280
big_sql = 'select * from issue54 where '
281
big_sql += ' and '.join('%d=%d' % (i, i) for i in range(0, 100000))
282
283
try:
284
c.execute('create table issue54 (id integer primary key)')
285
c.execute('insert into issue54 (id) values (7)')
286
c.execute(big_sql)
287
self.assertEqual(7, c.fetchone()[0])
288
finally:
289
c.execute('drop table issue54')
290
291
292
class TestGitHubIssues(base.PyMySQLTestCase):
293
294
def test_issue_66(self):
295
"""'Connection' object has no attribute 'insert_id'."""
296
conn = self.connect()
297
c = conn.cursor()
298
self.assertEqual(0, conn.insert_id())
299
try:
300
with warnings.catch_warnings():
301
warnings.filterwarnings('ignore')
302
c.execute('drop table if exists issue66')
303
c.execute(
304
'create table issue66 (id integer primary key auto_increment, x integer)',
305
)
306
c.execute('insert into issue66 (x) values (1)')
307
c.execute('insert into issue66 (x) values (1)')
308
self.assertEqual(2, conn.insert_id())
309
finally:
310
c.execute('drop table issue66')
311
312
def test_issue_79(self):
313
"""Duplicate field overwrites the previous one in the result of DictCursor."""
314
conn = self.connect(cursorclass=sv.cursors.DictCursor)
315
c = conn.cursor()
316
317
with warnings.catch_warnings():
318
warnings.filterwarnings('ignore')
319
c.execute('drop table if exists a')
320
c.execute('drop table if exists b')
321
c.execute("""CREATE TABLE a (id int, value int)""")
322
c.execute("""CREATE TABLE b (id int, value int)""")
323
324
a = (1, 11)
325
b = (1, 22)
326
try:
327
c.execute('insert into a values (%s, %s)', a)
328
c.execute('insert into b values (%s, %s)', b)
329
330
c.execute('SELECT * FROM a inner join b on a.id = b.id')
331
r = c.fetchall()[0]
332
self.assertEqual(r['id'], 1)
333
self.assertEqual(r['value'], 11)
334
self.assertEqual(r['b.value'], 22)
335
finally:
336
c.execute('drop table a')
337
c.execute('drop table b')
338
339
def test_issue_95(self):
340
"""Leftover trailing OK packet for "CALL my_sp" queries."""
341
conn = self.connect()
342
cur = conn.cursor()
343
with warnings.catch_warnings():
344
warnings.filterwarnings('ignore')
345
cur.execute('DROP PROCEDURE IF EXISTS `foo`')
346
cur.execute(
347
"""CREATE PROCEDURE `foo` () AS
348
BEGIN
349
ECHO SELECT 1;
350
END""",
351
)
352
try:
353
cur.execute("""CALL foo()""")
354
cur.execute("""SELECT 1""")
355
self.assertEqual(cur.fetchone()[0], 1)
356
finally:
357
with warnings.catch_warnings():
358
warnings.filterwarnings('ignore')
359
cur.execute('DROP PROCEDURE IF EXISTS `foo`')
360
361
def test_issue_114(self):
362
"""Autocommit is not set after reconnecting with ping()."""
363
conn = sv.connect(charset='utf8', **self.databases[0])
364
conn.autocommit(False)
365
c = conn.cursor()
366
367
if type(c).__name__.startswith('SS'):
368
self.skipTest('Test hangs with unbuffered cursor')
369
370
c.execute("""select @@autocommit;""")
371
self.assertFalse(c.fetchone()[0])
372
conn.close()
373
conn.ping()
374
c.execute("""select @@autocommit;""")
375
self.assertFalse(c.fetchone()[0])
376
conn.close()
377
378
# Ensure autocommit() is still working
379
conn = sv.connect(charset='utf8', **self.databases[0])
380
c = conn.cursor()
381
c.execute("""select @@autocommit;""")
382
self.assertFalse(c.fetchone()[0])
383
conn.close()
384
conn.ping()
385
conn.autocommit(True)
386
c.execute("""select @@autocommit;""")
387
self.assertTrue(c.fetchone()[0])
388
conn.close()
389
390
def test_issue_175(self):
391
"""The number of fields returned by server is read in wrong way."""
392
conn = self.connect()
393
cur = conn.cursor()
394
for length in (200, 300):
395
columns = ', '.join('c{0} integer'.format(i) for i in range(length))
396
sql = 'create table test_field_count ({0})'.format(columns)
397
try:
398
cur.execute(sql)
399
cur.execute('select * from test_field_count')
400
assert len(cur.description) == length
401
finally:
402
with warnings.catch_warnings():
403
warnings.filterwarnings('ignore')
404
cur.execute('drop table if exists test_field_count')
405
406
def test_issue_321(self):
407
"""Test iterable as query argument."""
408
conn = sv.connect(charset='utf8', **self.databases[0])
409
self.safe_create_table(
410
conn,
411
'issue321',
412
'create table issue321 (value_1 varchar(1), value_2 varchar(1))',
413
)
414
415
sql_insert = 'insert into issue321 (value_1, value_2) values (%s, %s)'
416
sql_dict_insert = (
417
'insert into issue321 (value_1, value_2) '
418
'values (%(value_1)s, %(value_2)s)'
419
)
420
sql_select = 'select * from issue321 ' + \
421
'where value_1 in %s and value_2=%s order by value_1'
422
data = [
423
[('a',), '\u0430'],
424
[['b'], '\u0430'],
425
{'value_1': [['c']], 'value_2': '\u0430'},
426
]
427
cur = conn.cursor()
428
self.assertEqual(cur.execute(sql_insert, data[0]), 1)
429
self.assertEqual(cur.execute(sql_insert, data[1]), 1)
430
self.assertEqual(cur.execute(sql_dict_insert, data[2]), 1)
431
self.assertIn(cur.execute(sql_select, [('a', 'b', 'c'), '\u0430']), [3, -1])
432
self.assertEqual(cur.fetchone(), ('a', '\u0430'))
433
self.assertEqual(cur.fetchone(), ('b', '\u0430'))
434
self.assertEqual(cur.fetchone(), ('c', '\u0430'))
435
436
def test_issue_364(self):
437
"""Test mixed unicode/binary arguments in executemany."""
438
conn = sv.connect(charset='utf8mb4', **self.databases[0])
439
self.safe_create_table(
440
conn,
441
'issue364',
442
'create table issue364 (value_1 binary(3), value_2 varchar(3)) '
443
'engine=InnoDB default charset=utf8mb4',
444
)
445
446
sql = 'insert into issue364 (value_1, value_2) values (_binary %s, %s)'
447
usql = 'insert into issue364 (value_1, value_2) values (_binary %s, %s)'
448
values = [sv.Binary(b'\x00\xff\x00'), '\xe4\xf6\xfc']
449
450
# test single insert and select
451
cur = conn.cursor()
452
cur.execute(sql, args=values)
453
cur.execute('select * from issue364')
454
self.assertEqual(cur.fetchone(), tuple(values))
455
456
# test single insert unicode query
457
cur.execute(usql, args=values)
458
459
# test multi insert and select
460
cur.executemany(sql, args=(values, values, values))
461
cur.execute('select * from issue364')
462
for row in cur.fetchall():
463
self.assertEqual(row, tuple(values))
464
465
# test multi insert with unicode query
466
cur.executemany(usql, args=(values, values, values))
467
468
@pytest.mark.skip(reason='syntax not supported by SingleStoreDB')
469
def test_issue_363(self):
470
"""Test binary / geometry types."""
471
conn = sv.connect(charset='utf8', **self.databases[0])
472
self.safe_create_table(
473
conn,
474
'issue363',
475
'CREATE TABLE issue363 ( '
476
'id INTEGER PRIMARY KEY, geom LINESTRING NOT NULL /*!80003 SRID 0 */, '
477
'SPATIAL KEY geom (geom)) '
478
'ENGINE=MyISAM',
479
)
480
481
cur = conn.cursor()
482
query = (
483
'INSERT INTO issue363 (id, geom) VALUES'
484
"(1998, ST_GeomFromText('LINESTRING(1.1 1.1,2.2 2.2)'))"
485
)
486
cur.execute(query)
487
488
# select WKT
489
query = 'SELECT ST_AsText(geom) FROM issue363'
490
cur.execute(query)
491
row = cur.fetchone()
492
self.assertEqual(row, ('LINESTRING(1.1 1.1,2.2 2.2)',))
493
494
# select WKB
495
query = 'SELECT ST_AsBinary(geom) FROM issue363'
496
cur.execute(query)
497
row = cur.fetchone()
498
self.assertEqual(
499
row,
500
(
501
b'\x01\x02\x00\x00\x00\x02\x00\x00\x00'
502
b'\x9a\x99\x99\x99\x99\x99\xf1?'
503
b'\x9a\x99\x99\x99\x99\x99\xf1?'
504
b'\x9a\x99\x99\x99\x99\x99\x01@'
505
b'\x9a\x99\x99\x99\x99\x99\x01@',
506
),
507
)
508
509
# select internal binary
510
cur.execute('SELECT geom FROM issue363')
511
row = cur.fetchone()
512
# don't assert the exact internal binary value, as it could
513
# vary across implementations
514
self.assertTrue(isinstance(row[0], bytes))
515
516