Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
singlestore-labs
GitHub Repository: singlestore-labs/singlestoredb-python
Path: blob/main/singlestoredb/tests/test_ext_func.py
801 views
1
#!/usr/bin/env python
2
# type: ignore
3
"""Test SingleStoreDB external functions."""
4
import os
5
import socket
6
import subprocess
7
import time
8
import unittest
9
10
import requests
11
12
import singlestoredb as s2
13
import singlestoredb.mysql.constants.FIELD_TYPE as ft
14
from . import ext_funcs
15
from . import utils
16
from singlestoredb.functions.ext.asgi import create_app
17
18
19
try:
20
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
21
s.connect(('8.8.8.8', 80))
22
HTTP_HOST = s.getsockname()[0]
23
except Exception:
24
HTTP_HOST = '127.0.0.1'
25
finally:
26
s.close()
27
28
29
def get_open_port() -> int:
30
"""Find an open port number."""
31
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
32
s.bind(('', 0))
33
s.listen(1)
34
port = s.getsockname()[1]
35
s.close()
36
return port
37
38
39
def start_http_server(database, data_format='rowdat_1'):
40
"""Start an external function server."""
41
port = get_open_port()
42
print(f'Start UDF HTTP server on http://{HTTP_HOST}:{port}')
43
proc = subprocess.Popen(
44
['uvicorn', 'singlestoredb.functions.ext.asgi:create_app'],
45
env=dict(
46
PATH=os.environ['PATH'],
47
PYTHONPATH=os.environ.get('PYTHONPATH', ''),
48
UVICORN_HOST=str(HTTP_HOST),
49
UVICORN_PORT=str(port),
50
UVICORN_FACTORY='1',
51
SINGLESTOREDB_EXT_FUNCTIONS='singlestoredb.tests.ext_funcs',
52
SINGLESTOREDB_PURE_PYTHON=os.environ.get('SINGLESTOREDB_PURE_PYTHON', '0'),
53
),
54
)
55
56
# Wait for server to be available
57
retries = 10
58
while retries > 0:
59
try:
60
out = requests.get(f'http://{HTTP_HOST}:{port}/show/create_function')
61
if out.status_code == 200:
62
break
63
except Exception:
64
pass
65
time.sleep(3)
66
retries -= 1
67
68
app = create_app(
69
ext_funcs,
70
url=f'http://{HTTP_HOST}:{port}/invoke',
71
data_format=data_format,
72
)
73
app.register_functions(
74
database=database,
75
)
76
77
with s2.connect(database=database) as conn:
78
with conn.cursor() as cur:
79
cur.execute('set global enable_external_functions=on')
80
cur.execute('show functions')
81
for item in list(cur):
82
cur.execute(f'show create function `{item[0]}`')
83
for func in list(cur):
84
print(*func)
85
86
return proc, HTTP_HOST, port
87
88
89
def stop_http_server(proc, database):
90
"""Stop the external function server."""
91
proc.terminate()
92
app = create_app(ext_funcs)
93
app.drop_functions(database=database)
94
95
96
class TestExtFunc(unittest.TestCase):
97
98
dbname: str = ''
99
dbexisted: bool = False
100
http_server = None
101
http_host = '127.0.0.1'
102
http_port = 0
103
104
@classmethod
105
def setUpClass(cls):
106
sql_file = os.path.join(os.path.dirname(__file__), 'test.sql')
107
cls.dbname, cls.dbexisted = utils.load_sql(sql_file)
108
cls.http_server, cls.http_host, cls.http_port = \
109
start_http_server(cls.dbname, 'rowdat_1')
110
111
@classmethod
112
def tearDownClass(cls):
113
stop_http_server(cls.http_server, cls.dbname)
114
cls.http_server = None
115
cls.http_host = '127.0.0.1'
116
cls.http_port = 0
117
if not cls.dbexisted:
118
utils.drop_database(cls.dbname)
119
120
def setUp(self):
121
self.conn = s2.connect(database=type(self).dbname)
122
self.cur = self.conn.cursor()
123
124
def tearDown(self):
125
try:
126
if self.cur is not None:
127
self.cur.close()
128
except Exception:
129
# traceback.print_exc()
130
pass
131
132
try:
133
if self.conn is not None:
134
self.conn.close()
135
except Exception:
136
# traceback.print_exc()
137
pass
138
139
def test_show_create_function(self):
140
out = requests.get(
141
f'http://{type(self).http_host}:{type(self).http_port}'
142
'/show/create_function',
143
)
144
print(out.text)
145
146
def test_double_mult(self):
147
self.cur.execute('select double_mult(value, 100) as res from data order by id')
148
149
assert [tuple(x) for x in self.cur] == \
150
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
151
152
desc = self.cur.description
153
assert len(desc) == 1
154
assert desc[0].name == 'res'
155
assert desc[0].type_code == ft.DOUBLE
156
assert desc[0].null_ok is False
157
158
# NULL is not valid
159
with self.assertRaises(self.conn.OperationalError):
160
self.cur.execute(
161
'select double_mult(value, NULL) as res '
162
'from data order by id',
163
)
164
165
def test_timeout_double_mult(self):
166
with self.assertRaises(self.conn.OperationalError) as exc:
167
self.cur.execute(
168
'select timeout_double_mult(value, 100) as res '
169
'from longer_data order by id',
170
)
171
assert 'timeout' in str(exc.exception).lower()
172
173
def test_async_double_mult(self):
174
self.cur.execute(
175
'select async_double_mult(value, 100) as res from data order by id',
176
)
177
178
assert [tuple(x) for x in self.cur] == \
179
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
180
181
desc = self.cur.description
182
assert len(desc) == 1
183
assert desc[0].name == 'res'
184
assert desc[0].type_code == ft.DOUBLE
185
assert desc[0].null_ok is False
186
187
# NULL is not valid
188
with self.assertRaises(self.conn.OperationalError):
189
self.cur.execute(
190
'select async_double_mult(value, NULL) as res '
191
'from data order by id',
192
)
193
194
def test_async_timeout_double_mult(self):
195
with self.assertRaises(self.conn.OperationalError) as exc:
196
self.cur.execute(
197
'select async_timeout_double_mult(value, 100) as res '
198
'from longer_data order by id',
199
)
200
assert 'timeout' in str(exc.exception).lower()
201
202
def test_pandas_double_mult(self):
203
self.cur.execute(
204
'select pandas_double_mult(value, 100) as res '
205
'from data order by id',
206
)
207
208
assert [tuple(x) for x in self.cur] == \
209
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
210
211
desc = self.cur.description
212
assert len(desc) == 1
213
assert desc[0].name == 'res'
214
assert desc[0].type_code == ft.DOUBLE
215
assert desc[0].null_ok is False
216
217
# NULL is not valid
218
with self.assertRaises(self.conn.OperationalError):
219
self.cur.execute(
220
'select pandas_double_mult(value, NULL) as res '
221
'from data order by id',
222
)
223
224
def test_numpy_double_mult(self):
225
self.cur.execute(
226
'select numpy_double_mult(value, 100) as res '
227
'from data order by id',
228
)
229
230
assert [tuple(x) for x in self.cur] == \
231
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
232
233
desc = self.cur.description
234
assert len(desc) == 1
235
assert desc[0].name == 'res'
236
assert desc[0].type_code == ft.DOUBLE
237
assert desc[0].null_ok is False
238
239
# NULL is not valid
240
with self.assertRaises(self.conn.OperationalError):
241
self.cur.execute(
242
'select numpy_double_mult(value, NULL) as res '
243
'from data order by id',
244
)
245
246
def test_async_numpy_double_mult(self):
247
self.cur.execute(
248
'select async_numpy_double_mult(value, 100) as res '
249
'from data order by id',
250
)
251
252
assert [tuple(x) for x in self.cur] == \
253
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
254
255
desc = self.cur.description
256
assert len(desc) == 1
257
assert desc[0].name == 'res'
258
assert desc[0].type_code == ft.DOUBLE
259
assert desc[0].null_ok is False
260
261
# NULL is not valid
262
with self.assertRaises(self.conn.OperationalError):
263
self.cur.execute(
264
'select async_numpy_double_mult(value, NULL) as res '
265
'from data order by id',
266
)
267
268
def test_arrow_double_mult(self):
269
self.cur.execute(
270
'select arrow_double_mult(value, 100) as res '
271
'from data order by id',
272
)
273
274
assert [tuple(x) for x in self.cur] == \
275
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
276
277
desc = self.cur.description
278
assert len(desc) == 1
279
assert desc[0].name == 'res'
280
assert desc[0].type_code == ft.DOUBLE
281
assert desc[0].null_ok is False
282
283
# NULL is not valid
284
with self.assertRaises(self.conn.OperationalError):
285
self.cur.execute(
286
'select arrow_double_mult(value, NULL) as res '
287
'from data order by id',
288
)
289
290
def test_polars_double_mult(self):
291
self.cur.execute(
292
'select polars_double_mult(value, 100) as res '
293
'from data order by id',
294
)
295
296
assert [tuple(x) for x in self.cur] == \
297
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
298
299
desc = self.cur.description
300
assert len(desc) == 1
301
assert desc[0].name == 'res'
302
assert desc[0].type_code == ft.DOUBLE
303
assert desc[0].null_ok is False
304
305
# NULL is not valid
306
with self.assertRaises(self.conn.OperationalError):
307
self.cur.execute(
308
'select polars_double_mult(value, NULL) as res '
309
'from data order by id',
310
)
311
312
def test_nullable_double_mult(self):
313
self.cur.execute(
314
'select nullable_double_mult(value, 100) as res from '
315
'data_with_nulls order by id',
316
)
317
318
assert [tuple(x) for x in self.cur] == \
319
[(200.0,), (200.0,), (500.0,), (None,), (0.0,)]
320
321
desc = self.cur.description
322
assert len(desc) == 1
323
assert desc[0].name == 'res'
324
assert desc[0].type_code == ft.DOUBLE
325
assert desc[0].null_ok is True
326
327
self.cur.execute(
328
'select nullable_double_mult(value, NULL) as res '
329
'from data_with_nulls order by id',
330
)
331
332
assert [tuple(x) for x in self.cur] == \
333
[(None,), (None,), (None,), (None,), (None,)]
334
335
def test_float_mult(self):
336
self.cur.execute(
337
'select float_mult(value, 100) as res '
338
'from data order by id',
339
)
340
341
assert [tuple(x) for x in self.cur] == \
342
[(200.0,), (200.0,), (500.0,), (400.0,), (0.0,)]
343
344
desc = self.cur.description
345
assert len(desc) == 1
346
assert desc[0].name == 'res'
347
assert desc[0].type_code == ft.FLOAT
348
assert desc[0].null_ok is False
349
350
# NULL is not valid
351
with self.assertRaises(self.conn.OperationalError):
352
self.cur.execute(
353
'select float_mult(value, NULL) as res '
354
'from data order by id',
355
)
356
357
def test_nullable_float_mult(self):
358
self.cur.execute(
359
'select nullable_float_mult(value, 100) as res '
360
'from data_with_nulls order by id',
361
)
362
363
assert [tuple(x) for x in self.cur] == \
364
[(200.0,), (200.0,), (500.0,), (None,), (0.0,)]
365
366
desc = self.cur.description
367
assert len(desc) == 1
368
assert desc[0].name == 'res'
369
assert desc[0].type_code == ft.FLOAT
370
assert desc[0].null_ok is True
371
372
self.cur.execute(
373
'select nullable_float_mult(value, NULL) as res '
374
'from data_with_nulls order by id',
375
)
376
377
assert [tuple(x) for x in self.cur] == \
378
[(None,), (None,), (None,), (None,), (None,)]
379
380
def test_int_mult(self):
381
self.cur.execute(
382
'select int_mult(value, 100) as res '
383
'from data order by id',
384
)
385
386
assert [tuple(x) for x in self.cur] == \
387
[(200,), (200,), (500,), (400,), (0,)]
388
389
desc = self.cur.description
390
assert len(desc) == 1
391
assert desc[0].name == 'res'
392
assert desc[0].type_code == ft.LONGLONG
393
assert desc[0].null_ok is False
394
395
# NULL is not valid
396
with self.assertRaises(self.conn.OperationalError):
397
self.cur.execute(
398
'select int_mult(value, NULL) as res '
399
'from data order by id',
400
)
401
402
def test_tinyint_mult(self):
403
self.cur.execute(
404
'select tinyint_mult(value, 100) as res '
405
'from data order by id',
406
)
407
408
assert [tuple(x) for x in self.cur] == \
409
[(127,), (127,), (127,), (127,), (0,)]
410
411
desc = self.cur.description
412
assert len(desc) == 1
413
assert desc[0].name == 'res'
414
assert desc[0].type_code == ft.TINY
415
assert desc[0].null_ok is False
416
417
# NULL is not valid
418
with self.assertRaises(self.conn.OperationalError):
419
self.cur.execute(
420
'select tinyint_mult(value, NULL) as res '
421
'from data order by id',
422
)
423
424
def test_pandas_tinyint_mult(self):
425
self.cur.execute(
426
'select pandas_tinyint_mult(value, 100) as res '
427
'from data order by id',
428
)
429
430
assert [tuple(x) for x in self.cur] == \
431
[(127,), (127,), (127,), (127,), (0,)]
432
433
desc = self.cur.description
434
assert len(desc) == 1
435
assert desc[0].name == 'res'
436
assert desc[0].type_code == ft.TINY
437
assert desc[0].null_ok is False
438
439
# NULL is not valid
440
with self.assertRaises(self.conn.OperationalError):
441
self.cur.execute(
442
'select pandas_tinyint_mult(value, NULL) as res '
443
'from data order by id',
444
)
445
446
def test_polars_tinyint_mult(self):
447
self.cur.execute(
448
'select polars_tinyint_mult(value, 100) as res '
449
'from data order by id',
450
)
451
452
assert [tuple(x) for x in self.cur] == \
453
[(127,), (127,), (127,), (127,), (0,)]
454
455
desc = self.cur.description
456
assert len(desc) == 1
457
assert desc[0].name == 'res'
458
assert desc[0].type_code == ft.TINY
459
assert desc[0].null_ok is False
460
461
# NULL is not valid
462
with self.assertRaises(self.conn.OperationalError):
463
self.cur.execute(
464
'select polars_tinyint_mult(value, NULL) as res '
465
'from data order by id',
466
)
467
468
def test_numpy_tinyint_mult(self):
469
self.cur.execute(
470
'select numpy_tinyint_mult(value, 100) as res '
471
'from data order by id',
472
)
473
474
assert [tuple(x) for x in self.cur] == \
475
[(127,), (127,), (127,), (127,), (0,)]
476
477
desc = self.cur.description
478
assert len(desc) == 1
479
assert desc[0].name == 'res'
480
assert desc[0].type_code == ft.TINY
481
assert desc[0].null_ok is False
482
483
# NULL is not valid
484
with self.assertRaises(self.conn.OperationalError):
485
self.cur.execute(
486
'select numpy_tinyint_mult(value, NULL) as res '
487
'from data order by id',
488
)
489
490
def test_arrow_tinyint_mult(self):
491
self.cur.execute(
492
'select arrow_tinyint_mult(value, 100) as res from '
493
'data order by id',
494
)
495
496
assert [tuple(x) for x in self.cur] == \
497
[(127,), (127,), (127,), (127,), (0,)]
498
499
desc = self.cur.description
500
assert len(desc) == 1
501
assert desc[0].name == 'res'
502
assert desc[0].type_code == ft.TINY
503
assert desc[0].null_ok is False
504
505
# NULL is not valid
506
with self.assertRaises(self.conn.OperationalError):
507
self.cur.execute(
508
'select arrow_tinyint_mult(value, NULL) as res '
509
'from data order by id',
510
)
511
512
def test_nullable_tinyint_mult(self):
513
self.cur.execute(
514
'select nullable_tinyint_mult(value, 100) as res from '
515
'data_with_nulls order by id',
516
)
517
518
assert [tuple(x) for x in self.cur] == \
519
[(127,), (127,), (127,), (None,), (0,)]
520
521
desc = self.cur.description
522
assert len(desc) == 1
523
assert desc[0].name == 'res'
524
assert desc[0].type_code == ft.TINY
525
assert desc[0].null_ok is True
526
527
def test_pandas_nullable_tinyint_mult(self):
528
self.cur.execute(
529
'select pandas_nullable_tinyint_mult(value, 100) as res '
530
'from data_with_nulls order by id',
531
)
532
533
assert [tuple(x) for x in self.cur] == \
534
[(127,), (127,), (127,), (0,), (0,)]
535
536
desc = self.cur.description
537
assert len(desc) == 1
538
assert desc[0].name == 'res'
539
assert desc[0].type_code == ft.TINY
540
assert desc[0].null_ok is True
541
542
def test_pandas_nullable_tinyint_mult_with_masks(self):
543
self.cur.execute(
544
'select pandas_nullable_tinyint_mult_with_masks(value, 100) '
545
'as res from data_with_nulls order by id',
546
)
547
548
assert [tuple(x) for x in self.cur] == \
549
[(127,), (127,), (127,), (None,), (0,)]
550
551
desc = self.cur.description
552
assert len(desc) == 1
553
assert desc[0].name == 'res'
554
assert desc[0].type_code == ft.TINY
555
assert desc[0].null_ok is True
556
557
def test_polars_nullable_tinyint_mult(self):
558
self.cur.execute(
559
'select polars_nullable_tinyint_mult(value, 100) as res '
560
'from data_with_nulls order by id',
561
)
562
563
assert [tuple(x) for x in self.cur] == \
564
[(127,), (127,), (127,), (0,), (0,)]
565
566
desc = self.cur.description
567
assert len(desc) == 1
568
assert desc[0].name == 'res'
569
assert desc[0].type_code == ft.TINY
570
assert desc[0].null_ok is True
571
572
def test_polars_nullable_tinyint_mult_with_masks(self):
573
self.cur.execute(
574
'select polars_nullable_tinyint_mult_with_masks(value, 100) '
575
'as res from data_with_nulls order by id',
576
)
577
578
assert [tuple(x) for x in self.cur] == \
579
[(127,), (127,), (127,), (None,), (0,)]
580
581
desc = self.cur.description
582
assert len(desc) == 1
583
assert desc[0].name == 'res'
584
assert desc[0].type_code == ft.TINY
585
assert desc[0].null_ok is True
586
587
def test_numpy_nullable_tinyint_mult(self):
588
self.cur.execute(
589
'select numpy_nullable_tinyint_mult(value, 100) as res '
590
'from data_with_nulls order by id',
591
)
592
593
assert [tuple(x) for x in self.cur] == \
594
[(127,), (127,), (127,), (0,), (0,)]
595
596
desc = self.cur.description
597
assert len(desc) == 1
598
assert desc[0].name == 'res'
599
assert desc[0].type_code == ft.TINY
600
assert desc[0].null_ok is True
601
602
def test_numpy_nullable_tinyint_mult_with_masks(self):
603
self.cur.execute(
604
'select numpy_nullable_tinyint_mult_with_masks(value, 100) '
605
'as res from data_with_nulls order by id',
606
)
607
608
assert [tuple(x) for x in self.cur] == \
609
[(127,), (127,), (127,), (None,), (0,)]
610
611
desc = self.cur.description
612
assert len(desc) == 1
613
assert desc[0].name == 'res'
614
assert desc[0].type_code == ft.TINY
615
assert desc[0].null_ok is True
616
617
def test_arrow_nullable_tinyint_mult(self):
618
self.cur.execute(
619
'select arrow_nullable_tinyint_mult(value, 100) as res '
620
'from data_with_nulls order by id',
621
)
622
623
assert [tuple(x) for x in self.cur] == \
624
[(127,), (127,), (127,), (None,), (0,)]
625
626
desc = self.cur.description
627
assert len(desc) == 1
628
assert desc[0].name == 'res'
629
assert desc[0].type_code == ft.TINY
630
assert desc[0].null_ok is True
631
632
def test_arrow_nullable_tinyint_mult_with_masks(self):
633
self.cur.execute(
634
'select arrow_nullable_tinyint_mult_with_masks(value, 100) '
635
'as res from data_with_nulls order by id',
636
)
637
638
assert [tuple(x) for x in self.cur] == \
639
[(127,), (127,), (127,), (None,), (0,)]
640
641
desc = self.cur.description
642
assert len(desc) == 1
643
assert desc[0].name == 'res'
644
assert desc[0].type_code == ft.TINY
645
assert desc[0].null_ok is True
646
647
def test_smallint_mult(self):
648
self.cur.execute(
649
'select smallint_mult(value, 100) as res '
650
'from data order by id',
651
)
652
653
assert [tuple(x) for x in self.cur] == \
654
[(200,), (200,), (500,), (400,), (0,)]
655
656
desc = self.cur.description
657
assert len(desc) == 1
658
assert desc[0].name == 'res'
659
assert desc[0].type_code == ft.SHORT
660
assert desc[0].null_ok is False
661
662
# NULL is not valid
663
with self.assertRaises(self.conn.OperationalError):
664
self.cur.execute(
665
'select smallint_mult(value, NULL) as res '
666
'from data order by id',
667
)
668
669
def test_pandas_smallint_mult(self):
670
self.cur.execute(
671
'select pandas_smallint_mult(value, 100) as res '
672
'from data order by id',
673
)
674
675
assert [tuple(x) for x in self.cur] == \
676
[(200,), (200,), (500,), (400,), (0,)]
677
678
desc = self.cur.description
679
assert len(desc) == 1
680
assert desc[0].name == 'res'
681
assert desc[0].type_code == ft.SHORT
682
assert desc[0].null_ok is False
683
684
# NULL is not valid
685
with self.assertRaises(self.conn.OperationalError):
686
self.cur.execute(
687
'select pandas_smallint_mult(value, NULL) as res '
688
'from data order by id',
689
)
690
691
def test_polars_smallint_mult(self):
692
self.cur.execute(
693
'select polars_smallint_mult(value, 100) as res '
694
'from data order by id',
695
)
696
697
assert [tuple(x) for x in self.cur] == \
698
[(200,), (200,), (500,), (400,), (0,)]
699
700
desc = self.cur.description
701
assert len(desc) == 1
702
assert desc[0].name == 'res'
703
assert desc[0].type_code == ft.SHORT
704
assert desc[0].null_ok is False
705
706
# NULL is not valid
707
with self.assertRaises(self.conn.OperationalError):
708
self.cur.execute(
709
'select polars_smallint_mult(value, NULL) as res '
710
'from data order by id',
711
)
712
713
def test_numpy_smallint_mult(self):
714
self.cur.execute(
715
'select numpy_smallint_mult(value, 100) as res '
716
'from data order by id',
717
)
718
719
assert [tuple(x) for x in self.cur] == \
720
[(200,), (200,), (500,), (400,), (0,)]
721
722
desc = self.cur.description
723
assert len(desc) == 1
724
assert desc[0].name == 'res'
725
assert desc[0].type_code == ft.SHORT
726
assert desc[0].null_ok is False
727
728
# NULL is not valid
729
with self.assertRaises(self.conn.OperationalError):
730
self.cur.execute(
731
'select numpy_smallint_mult(value, NULL) as res '
732
'from data order by id',
733
)
734
735
def test_arrow_smallint_mult(self):
736
self.cur.execute(
737
'select arrow_smallint_mult(value, 100) as res '
738
'from data order by id',
739
)
740
741
assert [tuple(x) for x in self.cur] == \
742
[(200,), (200,), (500,), (400,), (0,)]
743
744
desc = self.cur.description
745
assert len(desc) == 1
746
assert desc[0].name == 'res'
747
assert desc[0].type_code == ft.SHORT
748
assert desc[0].null_ok is False
749
750
# NULL is not valid
751
with self.assertRaises(self.conn.OperationalError):
752
self.cur.execute(
753
'select arrow_smallint_mult(value, NULL) as res '
754
'from data order by id',
755
)
756
757
def test_nullable_smallint_mult(self):
758
self.cur.execute(
759
'select nullable_smallint_mult(value, 100) as res '
760
'from data_with_nulls order by id',
761
)
762
763
assert [tuple(x) for x in self.cur] == \
764
[(200,), (200,), (500,), (None,), (0,)]
765
766
desc = self.cur.description
767
assert len(desc) == 1
768
assert desc[0].name == 'res'
769
assert desc[0].type_code == ft.SHORT
770
assert desc[0].null_ok is True
771
772
def test_mediumint_mult(self):
773
self.cur.execute(
774
'select mediumint_mult(value, 100) as res '
775
'from data order by id',
776
)
777
778
assert [tuple(x) for x in self.cur] == \
779
[(200,), (200,), (500,), (400,), (0,)]
780
781
desc = self.cur.description
782
assert len(desc) == 1
783
assert desc[0].name == 'res'
784
assert desc[0].type_code == ft.INT24
785
assert desc[0].null_ok is False
786
787
# NULL is not valid
788
with self.assertRaises(self.conn.OperationalError):
789
self.cur.execute(
790
'select mediumint_mult(value, NULL) as res '
791
'from data order by id',
792
)
793
794
def test_pandas_mediumint_mult(self):
795
self.cur.execute(
796
'select pandas_mediumint_mult(value, 100) as res '
797
'from data order by id',
798
)
799
800
assert [tuple(x) for x in self.cur] == \
801
[(200,), (200,), (500,), (400,), (0,)]
802
803
desc = self.cur.description
804
assert len(desc) == 1
805
assert desc[0].name == 'res'
806
assert desc[0].type_code == ft.INT24
807
assert desc[0].null_ok is False
808
809
# NULL is not valid
810
with self.assertRaises(self.conn.OperationalError):
811
self.cur.execute(
812
'select pandas_mediumint_mult(value, NULL) as res '
813
'from data order by id',
814
)
815
816
def test_polars_mediumint_mult(self):
817
self.cur.execute(
818
'select polars_mediumint_mult(value, 100) as res '
819
'from data order by id',
820
)
821
822
assert [tuple(x) for x in self.cur] == \
823
[(200,), (200,), (500,), (400,), (0,)]
824
825
desc = self.cur.description
826
assert len(desc) == 1
827
assert desc[0].name == 'res'
828
assert desc[0].type_code == ft.INT24
829
assert desc[0].null_ok is False
830
831
# NULL is not valid
832
with self.assertRaises(self.conn.OperationalError):
833
self.cur.execute(
834
'select polars_mediumint_mult(value, NULL) as res '
835
'from data order by id',
836
)
837
838
def test_numpy_mediumint_mult(self):
839
self.cur.execute(
840
'select numpy_mediumint_mult(value, 100) as res '
841
'from data order by id',
842
)
843
844
assert [tuple(x) for x in self.cur] == \
845
[(200,), (200,), (500,), (400,), (0,)]
846
847
desc = self.cur.description
848
assert len(desc) == 1
849
assert desc[0].name == 'res'
850
assert desc[0].type_code == ft.INT24
851
assert desc[0].null_ok is False
852
853
# NULL is not valid
854
with self.assertRaises(self.conn.OperationalError):
855
self.cur.execute(
856
'select numpy_mediumint_mult(value, NULL) as res '
857
'from data order by id',
858
)
859
860
def test_arrow_mediumint_mult(self):
861
self.cur.execute(
862
'select arrow_mediumint_mult(value, 100) as res '
863
'from data order by id',
864
)
865
866
assert [tuple(x) for x in self.cur] == \
867
[(200,), (200,), (500,), (400,), (0,)]
868
869
desc = self.cur.description
870
assert len(desc) == 1
871
assert desc[0].name == 'res'
872
assert desc[0].type_code == ft.INT24
873
assert desc[0].null_ok is False
874
875
# NULL is not valid
876
with self.assertRaises(self.conn.OperationalError):
877
self.cur.execute(
878
'select arrow_mediumint_mult(value, NULL) as res '
879
'from data order by id',
880
)
881
882
def test_nullable_mediumint_mult(self):
883
self.cur.execute(
884
'select nullable_mediumint_mult(value, 100) as res '
885
'from data_with_nulls order by id',
886
)
887
888
assert [tuple(x) for x in self.cur] == \
889
[(200,), (200,), (500,), (None,), (0,)]
890
891
desc = self.cur.description
892
assert len(desc) == 1
893
assert desc[0].name == 'res'
894
assert desc[0].type_code == ft.INT24
895
assert desc[0].null_ok is True
896
897
def test_bigint_mult(self):
898
self.cur.execute(
899
'select bigint_mult(value, 100) as res '
900
'from data order by id',
901
)
902
903
assert [tuple(x) for x in self.cur] == \
904
[(200,), (200,), (500,), (400,), (0,)]
905
906
desc = self.cur.description
907
assert len(desc) == 1
908
assert desc[0].name == 'res'
909
assert desc[0].type_code == ft.LONGLONG
910
assert desc[0].null_ok is False
911
912
# NULL is not valid
913
with self.assertRaises(self.conn.OperationalError):
914
self.cur.execute(
915
'select bigint_mult(value, NULL) as res '
916
'from data order by id',
917
)
918
919
def test_pandas_bigint_mult(self):
920
self.cur.execute(
921
'select pandas_bigint_mult(value, 100) as res '
922
'from data order by id',
923
)
924
925
assert [tuple(x) for x in self.cur] == \
926
[(200,), (200,), (500,), (400,), (0,)]
927
928
desc = self.cur.description
929
assert len(desc) == 1
930
assert desc[0].name == 'res'
931
assert desc[0].type_code == ft.LONGLONG
932
assert desc[0].null_ok is False
933
934
# NULL is not valid
935
with self.assertRaises(self.conn.OperationalError):
936
self.cur.execute(
937
'select pandas_bigint_mult(value, NULL) as res '
938
'from data order by id',
939
)
940
941
def test_polars_bigint_mult(self):
942
self.cur.execute(
943
'select polars_bigint_mult(value, 100) as res '
944
'from data order by id',
945
)
946
947
assert [tuple(x) for x in self.cur] == \
948
[(200,), (200,), (500,), (400,), (0,)]
949
950
desc = self.cur.description
951
assert len(desc) == 1
952
assert desc[0].name == 'res'
953
assert desc[0].type_code == ft.LONGLONG
954
assert desc[0].null_ok is False
955
956
# NULL is not valid
957
with self.assertRaises(self.conn.OperationalError):
958
self.cur.execute(
959
'select polars_bigint_mult(value, NULL) as res '
960
'from data order by id',
961
)
962
963
def test_numpy_bigint_mult(self):
964
self.cur.execute(
965
'select numpy_bigint_mult(value, 100) as res '
966
'from data order by id',
967
)
968
969
assert [tuple(x) for x in self.cur] == \
970
[(200,), (200,), (500,), (400,), (0,)]
971
972
desc = self.cur.description
973
assert len(desc) == 1
974
assert desc[0].name == 'res'
975
assert desc[0].type_code == ft.LONGLONG
976
assert desc[0].null_ok is False
977
978
# NULL is not valid
979
with self.assertRaises(self.conn.OperationalError):
980
self.cur.execute(
981
'select numpy_bigint_mult(value, NULL) as res '
982
'from data order by id',
983
)
984
985
def test_numpy_nullable_bigint_mult(self):
986
self.cur.execute(
987
'select numpy_nullable_bigint_mult(value, 100) as res '
988
'from data_with_nulls order by id',
989
)
990
991
# assert [tuple(x) for x in self.cur] == \
992
# [(200,), (200,), (500,), (None,), (0,)]
993
assert [tuple(x) for x in self.cur] == \
994
[(200,), (200,), (500,), (0,), (0,)]
995
996
desc = self.cur.description
997
assert len(desc) == 1
998
assert desc[0].name == 'res'
999
assert desc[0].type_code == ft.LONGLONG
1000
assert desc[0].null_ok is True
1001
1002
def test_arrow_bigint_mult(self):
1003
self.cur.execute(
1004
'select arrow_bigint_mult(value, 100) as res '
1005
'from data order by id',
1006
)
1007
1008
assert [tuple(x) for x in self.cur] == \
1009
[(200,), (200,), (500,), (400,), (0,)]
1010
1011
desc = self.cur.description
1012
assert len(desc) == 1
1013
assert desc[0].name == 'res'
1014
assert desc[0].type_code == ft.LONGLONG
1015
assert desc[0].null_ok is False
1016
1017
# NULL is not valid
1018
with self.assertRaises(self.conn.OperationalError):
1019
self.cur.execute(
1020
'select arrow_bigint_mult(value, NULL) as res '
1021
'from data order by id',
1022
)
1023
1024
def test_nullable_bigint_mult(self):
1025
self.cur.execute(
1026
'select nullable_bigint_mult(value, 100) as res '
1027
'from data_with_nulls order by id',
1028
)
1029
1030
assert [tuple(x) for x in self.cur] == \
1031
[(200,), (200,), (500,), (None,), (0,)]
1032
1033
desc = self.cur.description
1034
assert len(desc) == 1
1035
assert desc[0].name == 'res'
1036
assert desc[0].type_code == ft.LONGLONG
1037
assert desc[0].null_ok is True
1038
1039
def test_nullable_int_mult(self):
1040
self.cur.execute(
1041
'select nullable_int_mult(value, 100) as res '
1042
'from data_with_nulls order by id',
1043
)
1044
1045
assert [tuple(x) for x in self.cur] == \
1046
[(200,), (200,), (500,), (None,), (0,)]
1047
1048
desc = self.cur.description
1049
assert len(desc) == 1
1050
assert desc[0].name == 'res'
1051
assert desc[0].type_code == ft.LONGLONG
1052
assert desc[0].null_ok is True
1053
1054
# ========== BOOL TESTS ==========
1055
1056
def test_bool_and(self):
1057
"""Test scalar (non-vector) bool AND."""
1058
self.cur.execute('select bool_and(TRUE, TRUE) as res')
1059
assert [tuple(x) for x in self.cur] == [(1,)]
1060
1061
self.cur.execute('select bool_and(TRUE, FALSE) as res')
1062
assert [tuple(x) for x in self.cur] == [(0,)]
1063
1064
self.cur.execute('select bool_and(FALSE, TRUE) as res')
1065
assert [tuple(x) for x in self.cur] == [(0,)]
1066
1067
self.cur.execute('select bool_and(FALSE, FALSE) as res')
1068
assert [tuple(x) for x in self.cur] == [(0,)]
1069
1070
desc = self.cur.description
1071
assert len(desc) == 1
1072
assert desc[0].name == 'res'
1073
assert desc[0].type_code == ft.TINY # BOOL is stored as TINYINT
1074
assert desc[0].null_ok is False
1075
1076
def test_bool_or(self):
1077
"""Test scalar (non-vector) bool OR."""
1078
self.cur.execute('select bool_or(TRUE, TRUE) as res')
1079
assert [tuple(x) for x in self.cur] == [(1,)]
1080
1081
self.cur.execute('select bool_or(TRUE, FALSE) as res')
1082
assert [tuple(x) for x in self.cur] == [(1,)]
1083
1084
self.cur.execute('select bool_or(FALSE, TRUE) as res')
1085
assert [tuple(x) for x in self.cur] == [(1,)]
1086
1087
self.cur.execute('select bool_or(FALSE, FALSE) as res')
1088
assert [tuple(x) for x in self.cur] == [(0,)]
1089
1090
desc = self.cur.description
1091
assert len(desc) == 1
1092
assert desc[0].name == 'res'
1093
assert desc[0].type_code == ft.TINY
1094
assert desc[0].null_ok is False
1095
1096
def test_bool_not(self):
1097
"""Test scalar (non-vector) bool NOT."""
1098
self.cur.execute('select bool_not(TRUE) as res')
1099
assert [tuple(x) for x in self.cur] == [(0,)]
1100
1101
self.cur.execute('select bool_not(FALSE) as res')
1102
assert [tuple(x) for x in self.cur] == [(1,)]
1103
1104
desc = self.cur.description
1105
assert len(desc) == 1
1106
assert desc[0].name == 'res'
1107
assert desc[0].type_code == ft.TINY
1108
assert desc[0].null_ok is False
1109
1110
def test_bool_xor(self):
1111
"""Test scalar (non-vector) bool XOR."""
1112
self.cur.execute('select bool_xor(TRUE, TRUE) as res')
1113
assert [tuple(x) for x in self.cur] == [(0,)]
1114
1115
self.cur.execute('select bool_xor(TRUE, FALSE) as res')
1116
assert [tuple(x) for x in self.cur] == [(1,)]
1117
1118
self.cur.execute('select bool_xor(FALSE, TRUE) as res')
1119
assert [tuple(x) for x in self.cur] == [(1,)]
1120
1121
self.cur.execute('select bool_xor(FALSE, FALSE) as res')
1122
assert [tuple(x) for x in self.cur] == [(0,)]
1123
1124
desc = self.cur.description
1125
assert len(desc) == 1
1126
assert desc[0].name == 'res'
1127
assert desc[0].type_code == ft.TINY
1128
assert desc[0].null_ok is False
1129
1130
def test_numpy_bool_and(self):
1131
"""Test vector bool AND using numpy arrays."""
1132
self.cur.execute(
1133
'select numpy_bool_and(bool_a, bool_b) as res '
1134
'from bool_data order by id',
1135
)
1136
1137
assert [tuple(x) for x in self.cur] == \
1138
[(0,), (0,), (0,), (1,)]
1139
1140
desc = self.cur.description
1141
assert len(desc) == 1
1142
assert desc[0].name == 'res'
1143
assert desc[0].type_code == ft.TINY
1144
assert desc[0].null_ok is False
1145
1146
# NULL is not valid
1147
with self.assertRaises(self.conn.OperationalError):
1148
self.cur.execute(
1149
'select numpy_bool_and(bool_a, NULL) as res '
1150
'from bool_data order by id',
1151
)
1152
1153
def test_pandas_bool_and(self):
1154
"""Test vector bool AND using pandas Series."""
1155
self.cur.execute(
1156
'select pandas_bool_and(bool_a, bool_b) as res '
1157
'from bool_data order by id',
1158
)
1159
1160
assert [tuple(x) for x in self.cur] == \
1161
[(0,), (0,), (0,), (1,)]
1162
1163
desc = self.cur.description
1164
assert len(desc) == 1
1165
assert desc[0].name == 'res'
1166
assert desc[0].type_code == ft.TINY
1167
assert desc[0].null_ok is False
1168
1169
# NULL is not valid
1170
with self.assertRaises(self.conn.OperationalError):
1171
self.cur.execute(
1172
'select pandas_bool_and(bool_a, NULL) as res '
1173
'from bool_data order by id',
1174
)
1175
1176
def test_polars_bool_and(self):
1177
"""Test vector bool AND using polars Series."""
1178
self.cur.execute(
1179
'select polars_bool_and(bool_a, bool_b) as res '
1180
'from bool_data order by id',
1181
)
1182
1183
assert [tuple(x) for x in self.cur] == \
1184
[(0,), (0,), (0,), (1,)]
1185
1186
desc = self.cur.description
1187
assert len(desc) == 1
1188
assert desc[0].name == 'res'
1189
assert desc[0].type_code == ft.TINY
1190
assert desc[0].null_ok is False
1191
1192
# NULL is not valid
1193
with self.assertRaises(self.conn.OperationalError):
1194
self.cur.execute(
1195
'select polars_bool_and(bool_a, NULL) as res '
1196
'from bool_data order by id',
1197
)
1198
1199
def test_arrow_bool_and(self):
1200
"""Test vector bool AND using pyarrow arrays."""
1201
self.cur.execute(
1202
'select arrow_bool_and(bool_a, bool_b) as res '
1203
'from bool_data order by id',
1204
)
1205
1206
assert [tuple(x) for x in self.cur] == \
1207
[(0,), (0,), (0,), (1,)]
1208
1209
desc = self.cur.description
1210
assert len(desc) == 1
1211
assert desc[0].name == 'res'
1212
assert desc[0].type_code == ft.TINY
1213
assert desc[0].null_ok is False
1214
1215
# NULL is not valid
1216
with self.assertRaises(self.conn.OperationalError):
1217
self.cur.execute(
1218
'select arrow_bool_and(bool_a, NULL) as res '
1219
'from bool_data order by id',
1220
)
1221
1222
def test_nullable_bool_and(self):
1223
"""Test nullable scalar bool AND."""
1224
self.cur.execute(
1225
'select nullable_bool_and(bool_a, bool_b) as res '
1226
'from bool_data_with_nulls order by id',
1227
)
1228
1229
assert [tuple(x) for x in self.cur] == \
1230
[(0,), (None,), (None,), (None,), (1,)]
1231
1232
desc = self.cur.description
1233
assert len(desc) == 1
1234
assert desc[0].name == 'res'
1235
assert desc[0].type_code == ft.TINY
1236
assert desc[0].null_ok is True
1237
1238
self.cur.execute(
1239
'select nullable_bool_and(bool_a, NULL) as res '
1240
'from bool_data_with_nulls order by id',
1241
)
1242
1243
assert [tuple(x) for x in self.cur] == \
1244
[(None,), (None,), (None,), (None,), (None,)]
1245
1246
def test_numpy_nullable_bool_and(self):
1247
"""Test nullable vector bool AND using numpy."""
1248
self.cur.execute(
1249
'select numpy_nullable_bool_and(bool_a, bool_b) as res '
1250
'from bool_data_with_nulls order by id',
1251
)
1252
1253
# Note: Without masks, NULL values may behave like 0 in numpy
1254
assert [tuple(x) for x in self.cur] == \
1255
[(0,), (0,), (0,), (0,), (1,)]
1256
1257
desc = self.cur.description
1258
assert len(desc) == 1
1259
assert desc[0].name == 'res'
1260
assert desc[0].type_code == ft.TINY
1261
assert desc[0].null_ok is True
1262
1263
def test_pandas_nullable_bool_and(self):
1264
"""Test nullable vector bool AND using pandas."""
1265
self.cur.execute(
1266
'select pandas_nullable_bool_and(bool_a, bool_b) as res '
1267
'from bool_data_with_nulls order by id',
1268
)
1269
1270
# Note: Without masks, NULL values may behave like 0 in pandas
1271
assert [tuple(x) for x in self.cur] == \
1272
[(0,), (0,), (0,), (0,), (1,)]
1273
1274
desc = self.cur.description
1275
assert len(desc) == 1
1276
assert desc[0].name == 'res'
1277
assert desc[0].type_code == ft.TINY
1278
assert desc[0].null_ok is True
1279
1280
def test_polars_nullable_bool_and(self):
1281
"""Test nullable vector bool AND using polars."""
1282
self.cur.execute(
1283
'select polars_nullable_bool_and(bool_a, bool_b) as res '
1284
'from bool_data_with_nulls order by id',
1285
)
1286
1287
# Note: Without masks, NULL values may behave like 0 in polars
1288
assert [tuple(x) for x in self.cur] == \
1289
[(0,), (0,), (0,), (0,), (1,)]
1290
1291
desc = self.cur.description
1292
assert len(desc) == 1
1293
assert desc[0].name == 'res'
1294
assert desc[0].type_code == ft.TINY
1295
assert desc[0].null_ok is True
1296
1297
def test_arrow_nullable_bool_and(self):
1298
"""Test nullable vector bool AND using pyarrow."""
1299
self.cur.execute(
1300
'select arrow_nullable_bool_and(bool_a, bool_b) as res '
1301
'from bool_data_with_nulls order by id',
1302
)
1303
1304
assert [tuple(x) for x in self.cur] == \
1305
[(0,), (None,), (None,), (None,), (1,)]
1306
1307
desc = self.cur.description
1308
assert len(desc) == 1
1309
assert desc[0].name == 'res'
1310
assert desc[0].type_code == ft.TINY
1311
assert desc[0].null_ok is True
1312
1313
def test_numpy_nullable_bool_and_with_masks(self):
1314
"""Test nullable vector bool AND with masks using numpy."""
1315
self.cur.execute(
1316
'select numpy_nullable_bool_and_with_masks(bool_a, bool_b) as res '
1317
'from bool_data_with_nulls order by id',
1318
)
1319
1320
assert [tuple(x) for x in self.cur] == \
1321
[(0,), (None,), (None,), (None,), (1,)]
1322
1323
desc = self.cur.description
1324
assert len(desc) == 1
1325
assert desc[0].name == 'res'
1326
assert desc[0].type_code == ft.TINY
1327
assert desc[0].null_ok is True
1328
1329
def test_pandas_nullable_bool_and_with_masks(self):
1330
"""Test nullable vector bool AND with masks using pandas."""
1331
self.cur.execute(
1332
'select pandas_nullable_bool_and_with_masks(bool_a, bool_b) as res '
1333
'from bool_data_with_nulls order by id',
1334
)
1335
1336
assert [tuple(x) for x in self.cur] == \
1337
[(0,), (None,), (None,), (None,), (1,)]
1338
1339
desc = self.cur.description
1340
assert len(desc) == 1
1341
assert desc[0].name == 'res'
1342
assert desc[0].type_code == ft.TINY
1343
assert desc[0].null_ok is True
1344
1345
def test_polars_nullable_bool_and_with_masks(self):
1346
"""Test nullable vector bool AND with masks using polars."""
1347
self.cur.execute(
1348
'select polars_nullable_bool_and_with_masks(bool_a, bool_b) as res '
1349
'from bool_data_with_nulls order by id',
1350
)
1351
1352
assert [tuple(x) for x in self.cur] == \
1353
[(0,), (None,), (None,), (None,), (1,)]
1354
1355
desc = self.cur.description
1356
assert len(desc) == 1
1357
assert desc[0].name == 'res'
1358
assert desc[0].type_code == ft.TINY
1359
assert desc[0].null_ok is True
1360
1361
def test_arrow_nullable_bool_and_with_masks(self):
1362
"""Test nullable vector bool AND with masks using pyarrow."""
1363
self.cur.execute(
1364
'select arrow_nullable_bool_and_with_masks(bool_a, bool_b) as res '
1365
'from bool_data_with_nulls order by id',
1366
)
1367
1368
assert [tuple(x) for x in self.cur] == \
1369
[(0,), (None,), (None,), (None,), (1,)]
1370
1371
desc = self.cur.description
1372
assert len(desc) == 1
1373
assert desc[0].name == 'res'
1374
assert desc[0].type_code == ft.TINY
1375
assert desc[0].null_ok is True
1376
1377
# ========== END BOOL TESTS ==========
1378
1379
def test_string_mult(self):
1380
self.cur.execute(
1381
'select string_mult(name, value) as res '
1382
'from data order by id',
1383
)
1384
1385
assert [tuple(x) for x in self.cur] == [
1386
('antelopesantelopes',),
1387
('bearsbears',),
1388
('catscatscatscatscats',),
1389
('dogsdogsdogsdogs',),
1390
('',),
1391
]
1392
1393
desc = self.cur.description
1394
assert len(desc) == 1
1395
assert desc[0].name == 'res'
1396
assert desc[0].type_code == ft.BLOB
1397
assert desc[0].null_ok is False
1398
1399
# NULL is not valid
1400
with self.assertRaises(self.conn.OperationalError):
1401
self.cur.execute(
1402
'select string_mult(NULL, value) as res '
1403
'from data order by id',
1404
)
1405
1406
def test_pandas_string_mult(self):
1407
self.cur.execute(
1408
'select pandas_string_mult(name, value) as res '
1409
'from data order by id',
1410
)
1411
1412
assert [tuple(x) for x in self.cur] == [
1413
('antelopesantelopes',),
1414
('bearsbears',),
1415
('catscatscatscatscats',),
1416
('dogsdogsdogsdogs',),
1417
('',),
1418
]
1419
1420
desc = self.cur.description
1421
assert len(desc) == 1
1422
assert desc[0].name == 'res'
1423
assert desc[0].type_code == ft.BLOB
1424
assert desc[0].null_ok is False
1425
1426
# NULL is not valid
1427
with self.assertRaises(self.conn.OperationalError):
1428
self.cur.execute(
1429
'select pandas_string_mult(NULL, value) as res '
1430
'from data order by id',
1431
)
1432
1433
def test_numpy_string_mult(self):
1434
self.cur.execute(
1435
'select numpy_string_mult(name, value) as res '
1436
'from data order by id',
1437
)
1438
1439
assert [tuple(x) for x in self.cur] == [
1440
('antelopesantelopes',),
1441
('bearsbears',),
1442
('catscatscatscatscats',),
1443
('dogsdogsdogsdogs',),
1444
('',),
1445
]
1446
1447
desc = self.cur.description
1448
assert len(desc) == 1
1449
assert desc[0].name == 'res'
1450
assert desc[0].type_code == ft.BLOB
1451
assert desc[0].null_ok is False
1452
1453
# NULL is not valid
1454
with self.assertRaises(self.conn.OperationalError):
1455
self.cur.execute(
1456
'select numpy_string_mult(NULL, value) as res '
1457
'from data order by id',
1458
)
1459
1460
def _test_polars_string_mult(self):
1461
self.cur.execute(
1462
'select polars_string_mult(name, value) as res '
1463
'from data order by id',
1464
)
1465
1466
assert [tuple(x) for x in self.cur] == [
1467
('antelopesantelopes',),
1468
('bearsbears',),
1469
('catscatscatscatscats',),
1470
('dogsdogsdogsdogs',),
1471
('',),
1472
]
1473
1474
desc = self.cur.description
1475
assert len(desc) == 1
1476
assert desc[0].name == 'res'
1477
assert desc[0].type_code == ft.BLOB
1478
assert desc[0].null_ok is False
1479
1480
# NULL is not valid
1481
with self.assertRaises(self.conn.OperationalError):
1482
self.cur.execute(
1483
'select polars_string_mult(NULL, value) as res '
1484
'from data order by id',
1485
)
1486
1487
def _test_arrow_string_mult(self):
1488
self.cur.execute(
1489
'select arrow_string_mult(name, value) as res '
1490
'from data order by id',
1491
)
1492
1493
assert [tuple(x) for x in self.cur] == [
1494
('antelopesantelopes',),
1495
('bearsbears',),
1496
('catscatscatscatscats',),
1497
('dogsdogsdogsdogs',),
1498
('',),
1499
]
1500
1501
desc = self.cur.description
1502
assert len(desc) == 1
1503
assert desc[0].name == 'res'
1504
assert desc[0].type_code == ft.BLOB
1505
assert desc[0].null_ok is False
1506
1507
# NULL is not valid
1508
with self.assertRaises(self.conn.OperationalError):
1509
self.cur.execute(
1510
'select arrow_string_mult(NULL, value) as res '
1511
'from data order by id',
1512
)
1513
1514
def test_nullable_string_mult(self):
1515
self.cur.execute(
1516
'select nullable_string_mult(name, value) as res '
1517
'from data_with_nulls order by id',
1518
)
1519
1520
assert [tuple(x) for x in self.cur] == [
1521
('antelopesantelopes',),
1522
(None,),
1523
(None,),
1524
(None,),
1525
('',),
1526
]
1527
1528
desc = self.cur.description
1529
assert len(desc) == 1
1530
assert desc[0].name == 'res'
1531
assert desc[0].type_code == ft.BLOB
1532
assert desc[0].null_ok is True
1533
1534
def _test_varchar_mult(self):
1535
self.cur.execute(
1536
'select varchar_mult(name, value) as res '
1537
'from data order by id',
1538
)
1539
1540
assert [tuple(x) for x in self.cur] == [
1541
('antelopesantelopes',),
1542
('bearsbears',),
1543
('catscatscatscatscats',),
1544
('dogsdogsdogsdogs',),
1545
('',),
1546
]
1547
1548
desc = self.cur.description
1549
assert len(desc) == 1
1550
assert desc[0].name == 'res'
1551
assert desc[0].type_code == ft.BLOB
1552
assert desc[0].null_ok is False
1553
1554
# NULL is not valid
1555
with self.assertRaises(self.conn.OperationalError):
1556
self.cur.execute(
1557
'select varchar_mult(NULL, value) as res '
1558
'from data order by id',
1559
)
1560
1561
def _test_nullable_varchar_mult(self):
1562
self.cur.execute(
1563
'select nullable_varchar_mult(name, value) as res '
1564
'from data_with_nulls order by id',
1565
)
1566
1567
assert [tuple(x) for x in self.cur] == [
1568
('antelopesantelopes',),
1569
(None,),
1570
(None,),
1571
(None,),
1572
('',),
1573
]
1574
1575
desc = self.cur.description
1576
assert len(desc) == 1
1577
assert desc[0].name == 'res'
1578
assert desc[0].type_code == ft.BLOB
1579
assert desc[0].null_ok is True
1580
1581
def test_numpy_fixed_strings(self):
1582
self.cur.execute('select * from numpy_fixed_strings()')
1583
1584
assert [tuple(x) for x in self.cur] == [
1585
('hello',),
1586
('hi there 😜',),
1587
('😜 bye',),
1588
]
1589
1590
desc = self.cur.description
1591
assert len(desc) == 1
1592
assert desc[0].name == 'res'
1593
assert desc[0].type_code == ft.BLOB
1594
assert desc[0].null_ok is False
1595
1596
def test_numpy_fixed_binary(self):
1597
self.cur.execute('select * from numpy_fixed_binary()')
1598
1599
assert [tuple(x) for x in self.cur] == [
1600
('hello'.encode('utf8'),),
1601
('hi there 😜'.encode('utf8'),),
1602
('😜 bye'.encode('utf8'),),
1603
]
1604
1605
desc = self.cur.description
1606
assert len(desc) == 1
1607
assert desc[0].name == 'res'
1608
assert desc[0].type_code == ft.BLOB
1609
assert desc[0].null_ok is False
1610
1611
def test_no_args_no_return_value(self):
1612
self.cur.execute('select no_args_no_return_value() as res')
1613
1614
assert [tuple(x) for x in self.cur] == [(None,)]
1615
1616
desc = self.cur.description
1617
assert len(desc) == 1
1618
assert desc[0].name == 'res'
1619
assert desc[0].type_code == ft.TINY
1620
assert desc[0].null_ok is True
1621
1622
def test_table_function(self):
1623
self.cur.execute('select * from table_function(5)')
1624
1625
assert [x[0] for x in self.cur] == [10, 10, 10, 10, 10]
1626
1627
desc = self.cur.description
1628
assert len(desc) == 1
1629
assert desc[0].name == 'a'
1630
assert desc[0].type_code == ft.LONGLONG
1631
assert desc[0].null_ok is False
1632
1633
def test_async_table_function(self):
1634
self.cur.execute('select * from async_table_function(5)')
1635
1636
assert [x[0] for x in self.cur] == [10, 10, 10, 10, 10]
1637
1638
desc = self.cur.description
1639
assert len(desc) == 1
1640
assert desc[0].name == 'a'
1641
assert desc[0].type_code == ft.LONGLONG
1642
assert desc[0].null_ok is False
1643
1644
def test_table_function_tuple(self):
1645
self.cur.execute('select * from table_function_tuple(3)')
1646
1647
out = list(self.cur)
1648
1649
assert out == [
1650
(10, 10.0, 'ten'),
1651
(10, 10.0, 'ten'),
1652
(10, 10.0, 'ten'),
1653
]
1654
1655
desc = self.cur.description
1656
assert len(desc) == 3
1657
assert desc[0].name == 'c_int'
1658
assert desc[1].name == 'c_float'
1659
assert desc[2].name == 'c_str'
1660
1661
def test_table_function_struct(self):
1662
self.cur.execute('select * from table_function_struct(3)')
1663
1664
out = list(self.cur)
1665
1666
assert out == [
1667
(10, 10.0, 'ten'),
1668
(10, 10.0, 'ten'),
1669
(10, 10.0, 'ten'),
1670
]
1671
1672
desc = self.cur.description
1673
assert len(desc) == 3
1674
assert desc[0].name == 'c_int'
1675
assert desc[1].name == 'c_float'
1676
assert desc[2].name == 'c_str'
1677
1678
def test_vec_function(self):
1679
self.cur.execute('select vec_function(5, 10) as res')
1680
1681
assert [tuple(x) for x in self.cur] == [(50.0,)]
1682
1683
def test_vec_function_ints(self):
1684
self.cur.execute('select vec_function_ints(5, 10) as res')
1685
1686
assert [tuple(x) for x in self.cur] == [(50,)]
1687
1688
def test_vec_function_df(self):
1689
self.cur.execute('select * from vec_function_df(5, 10)')
1690
1691
out = list(self.cur)
1692
1693
assert out == [
1694
(1, 1.1),
1695
(2, 2.2),
1696
(3, 3.3),
1697
]
1698
1699
desc = self.cur.description
1700
assert len(desc) == 2
1701
assert desc[0].name == 'res'
1702
assert desc[0].type_code == ft.SHORT
1703
assert desc[0].null_ok is False
1704
assert desc[1].name == 'res2'
1705
assert desc[1].type_code == ft.DOUBLE
1706
assert desc[1].null_ok is False
1707
1708
def test_async_vec_function_df(self):
1709
self.cur.execute('select * from async_vec_function_df(5, 10)')
1710
1711
out = list(self.cur)
1712
1713
assert out == [
1714
(1, 1.1),
1715
(2, 2.2),
1716
(3, 3.3),
1717
]
1718
1719
desc = self.cur.description
1720
assert len(desc) == 2
1721
assert desc[0].name == 'res'
1722
assert desc[0].type_code == ft.SHORT
1723
assert desc[0].null_ok is False
1724
assert desc[1].name == 'res2'
1725
assert desc[1].type_code == ft.DOUBLE
1726
assert desc[1].null_ok is False
1727
1728
def test_vec_function_ints_masked(self):
1729
self.cur.execute('select * from vec_function_ints_masked(5, 10)')
1730
1731
assert [tuple(x) for x in self.cur] == [(50,)]
1732
1733
desc = self.cur.description
1734
assert len(desc) == 1
1735
assert desc[0].name == 'res'
1736
assert desc[0].type_code == ft.SHORT
1737
assert desc[0].null_ok is True
1738
1739
self.cur.execute('select * from vec_function_ints_masked(NULL, 10)')
1740
1741
assert [tuple(x) for x in self.cur] == [(None,)]
1742
1743
desc = self.cur.description
1744
assert len(desc) == 1
1745
assert desc[0].name == 'res'
1746
assert desc[0].type_code == ft.SHORT
1747
assert desc[0].null_ok is True
1748
1749
self.cur.execute('select * from vec_function_ints_masked(5, NULL)')
1750
1751
assert [tuple(x) for x in self.cur] == [(None,)]
1752
1753
desc = self.cur.description
1754
assert len(desc) == 1
1755
assert desc[0].name == 'res'
1756
assert desc[0].type_code == ft.SHORT
1757
assert desc[0].null_ok is True
1758
1759
def test_vec_function_ints_masked2(self):
1760
self.cur.execute('select * from vec_function_ints_masked2(5, 10)')
1761
1762
assert [tuple(x) for x in self.cur] == [(50, 50)]
1763
1764
desc = self.cur.description
1765
assert len(desc) == 2
1766
assert desc[0].name == 'res'
1767
assert desc[0].type_code == ft.SHORT
1768
assert desc[0].null_ok is True
1769
assert desc[1].name == 'res2'
1770
assert desc[1].type_code == ft.SHORT
1771
assert desc[1].null_ok is True
1772
1773
self.cur.execute('select * from vec_function_ints_masked2(NULL, 10)')
1774
1775
assert [tuple(x) for x in self.cur] == [(None, None)]
1776
1777
desc = self.cur.description
1778
assert len(desc) == 2
1779
assert desc[0].name == 'res'
1780
assert desc[0].type_code == ft.SHORT
1781
assert desc[0].null_ok is True
1782
assert desc[1].name == 'res2'
1783
assert desc[1].type_code == ft.SHORT
1784
assert desc[1].null_ok is True
1785
1786
self.cur.execute('select * from vec_function_ints_masked2(5, NULL)')
1787
1788
assert [tuple(x) for x in self.cur] == [(None, None)]
1789
1790
desc = self.cur.description
1791
assert len(desc) == 2
1792
assert desc[0].name == 'res'
1793
assert desc[0].type_code == ft.SHORT
1794
assert desc[0].null_ok is True
1795
assert desc[1].name == 'res2'
1796
assert desc[1].type_code == ft.SHORT
1797
assert desc[1].null_ok is True
1798
1799