singlestoredb 1.16.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. singlestoredb/__init__.py +75 -0
  2. singlestoredb/ai/__init__.py +2 -0
  3. singlestoredb/ai/chat.py +139 -0
  4. singlestoredb/ai/embeddings.py +128 -0
  5. singlestoredb/alchemy/__init__.py +90 -0
  6. singlestoredb/apps/__init__.py +3 -0
  7. singlestoredb/apps/_cloud_functions.py +90 -0
  8. singlestoredb/apps/_config.py +72 -0
  9. singlestoredb/apps/_connection_info.py +18 -0
  10. singlestoredb/apps/_dashboards.py +47 -0
  11. singlestoredb/apps/_process.py +32 -0
  12. singlestoredb/apps/_python_udfs.py +100 -0
  13. singlestoredb/apps/_stdout_supress.py +30 -0
  14. singlestoredb/apps/_uvicorn_util.py +36 -0
  15. singlestoredb/auth.py +245 -0
  16. singlestoredb/config.py +484 -0
  17. singlestoredb/connection.py +1487 -0
  18. singlestoredb/converters.py +950 -0
  19. singlestoredb/docstring/__init__.py +33 -0
  20. singlestoredb/docstring/attrdoc.py +126 -0
  21. singlestoredb/docstring/common.py +230 -0
  22. singlestoredb/docstring/epydoc.py +267 -0
  23. singlestoredb/docstring/google.py +412 -0
  24. singlestoredb/docstring/numpydoc.py +562 -0
  25. singlestoredb/docstring/parser.py +100 -0
  26. singlestoredb/docstring/py.typed +1 -0
  27. singlestoredb/docstring/rest.py +256 -0
  28. singlestoredb/docstring/tests/__init__.py +1 -0
  29. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  30. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  31. singlestoredb/docstring/tests/test_google.py +1007 -0
  32. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  33. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  34. singlestoredb/docstring/tests/test_parser.py +248 -0
  35. singlestoredb/docstring/tests/test_rest.py +547 -0
  36. singlestoredb/docstring/tests/test_util.py +70 -0
  37. singlestoredb/docstring/util.py +141 -0
  38. singlestoredb/exceptions.py +120 -0
  39. singlestoredb/functions/__init__.py +16 -0
  40. singlestoredb/functions/decorator.py +201 -0
  41. singlestoredb/functions/dtypes.py +1793 -0
  42. singlestoredb/functions/ext/__init__.py +1 -0
  43. singlestoredb/functions/ext/arrow.py +375 -0
  44. singlestoredb/functions/ext/asgi.py +2133 -0
  45. singlestoredb/functions/ext/json.py +420 -0
  46. singlestoredb/functions/ext/mmap.py +413 -0
  47. singlestoredb/functions/ext/rowdat_1.py +724 -0
  48. singlestoredb/functions/ext/timer.py +89 -0
  49. singlestoredb/functions/ext/utils.py +218 -0
  50. singlestoredb/functions/signature.py +1578 -0
  51. singlestoredb/functions/typing/__init__.py +41 -0
  52. singlestoredb/functions/typing/numpy.py +20 -0
  53. singlestoredb/functions/typing/pandas.py +2 -0
  54. singlestoredb/functions/typing/polars.py +2 -0
  55. singlestoredb/functions/typing/pyarrow.py +2 -0
  56. singlestoredb/functions/utils.py +421 -0
  57. singlestoredb/fusion/__init__.py +11 -0
  58. singlestoredb/fusion/graphql.py +213 -0
  59. singlestoredb/fusion/handler.py +916 -0
  60. singlestoredb/fusion/handlers/__init__.py +0 -0
  61. singlestoredb/fusion/handlers/export.py +525 -0
  62. singlestoredb/fusion/handlers/files.py +690 -0
  63. singlestoredb/fusion/handlers/job.py +660 -0
  64. singlestoredb/fusion/handlers/models.py +250 -0
  65. singlestoredb/fusion/handlers/stage.py +502 -0
  66. singlestoredb/fusion/handlers/utils.py +324 -0
  67. singlestoredb/fusion/handlers/workspace.py +956 -0
  68. singlestoredb/fusion/registry.py +249 -0
  69. singlestoredb/fusion/result.py +399 -0
  70. singlestoredb/http/__init__.py +27 -0
  71. singlestoredb/http/connection.py +1267 -0
  72. singlestoredb/magics/__init__.py +34 -0
  73. singlestoredb/magics/run_personal.py +137 -0
  74. singlestoredb/magics/run_shared.py +134 -0
  75. singlestoredb/management/__init__.py +9 -0
  76. singlestoredb/management/billing_usage.py +148 -0
  77. singlestoredb/management/cluster.py +462 -0
  78. singlestoredb/management/export.py +295 -0
  79. singlestoredb/management/files.py +1102 -0
  80. singlestoredb/management/inference_api.py +105 -0
  81. singlestoredb/management/job.py +887 -0
  82. singlestoredb/management/manager.py +373 -0
  83. singlestoredb/management/organization.py +226 -0
  84. singlestoredb/management/region.py +169 -0
  85. singlestoredb/management/utils.py +423 -0
  86. singlestoredb/management/workspace.py +1927 -0
  87. singlestoredb/mysql/__init__.py +177 -0
  88. singlestoredb/mysql/_auth.py +298 -0
  89. singlestoredb/mysql/charset.py +214 -0
  90. singlestoredb/mysql/connection.py +2032 -0
  91. singlestoredb/mysql/constants/CLIENT.py +38 -0
  92. singlestoredb/mysql/constants/COMMAND.py +32 -0
  93. singlestoredb/mysql/constants/CR.py +78 -0
  94. singlestoredb/mysql/constants/ER.py +474 -0
  95. singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
  96. singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
  97. singlestoredb/mysql/constants/FLAG.py +15 -0
  98. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  99. singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
  100. singlestoredb/mysql/constants/__init__.py +0 -0
  101. singlestoredb/mysql/converters.py +271 -0
  102. singlestoredb/mysql/cursors.py +896 -0
  103. singlestoredb/mysql/err.py +92 -0
  104. singlestoredb/mysql/optionfile.py +20 -0
  105. singlestoredb/mysql/protocol.py +450 -0
  106. singlestoredb/mysql/tests/__init__.py +19 -0
  107. singlestoredb/mysql/tests/base.py +126 -0
  108. singlestoredb/mysql/tests/conftest.py +37 -0
  109. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  110. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  111. singlestoredb/mysql/tests/test_basic.py +452 -0
  112. singlestoredb/mysql/tests/test_connection.py +851 -0
  113. singlestoredb/mysql/tests/test_converters.py +58 -0
  114. singlestoredb/mysql/tests/test_cursor.py +141 -0
  115. singlestoredb/mysql/tests/test_err.py +16 -0
  116. singlestoredb/mysql/tests/test_issues.py +514 -0
  117. singlestoredb/mysql/tests/test_load_local.py +75 -0
  118. singlestoredb/mysql/tests/test_nextset.py +88 -0
  119. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  120. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  121. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  122. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  123. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  124. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  125. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  126. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  127. singlestoredb/mysql/times.py +23 -0
  128. singlestoredb/notebook/__init__.py +16 -0
  129. singlestoredb/notebook/_objects.py +213 -0
  130. singlestoredb/notebook/_portal.py +352 -0
  131. singlestoredb/py.typed +0 -0
  132. singlestoredb/pytest.py +352 -0
  133. singlestoredb/server/__init__.py +0 -0
  134. singlestoredb/server/docker.py +452 -0
  135. singlestoredb/server/free_tier.py +267 -0
  136. singlestoredb/tests/__init__.py +0 -0
  137. singlestoredb/tests/alltypes.sql +307 -0
  138. singlestoredb/tests/alltypes_no_nulls.sql +208 -0
  139. singlestoredb/tests/empty.sql +0 -0
  140. singlestoredb/tests/ext_funcs/__init__.py +702 -0
  141. singlestoredb/tests/local_infile.csv +3 -0
  142. singlestoredb/tests/test.ipynb +18 -0
  143. singlestoredb/tests/test.sql +680 -0
  144. singlestoredb/tests/test2.ipynb +18 -0
  145. singlestoredb/tests/test2.sql +1 -0
  146. singlestoredb/tests/test_basics.py +1332 -0
  147. singlestoredb/tests/test_config.py +318 -0
  148. singlestoredb/tests/test_connection.py +3103 -0
  149. singlestoredb/tests/test_dbapi.py +27 -0
  150. singlestoredb/tests/test_exceptions.py +45 -0
  151. singlestoredb/tests/test_ext_func.py +1472 -0
  152. singlestoredb/tests/test_ext_func_data.py +1101 -0
  153. singlestoredb/tests/test_fusion.py +1527 -0
  154. singlestoredb/tests/test_http.py +288 -0
  155. singlestoredb/tests/test_management.py +1599 -0
  156. singlestoredb/tests/test_plugin.py +33 -0
  157. singlestoredb/tests/test_results.py +171 -0
  158. singlestoredb/tests/test_types.py +132 -0
  159. singlestoredb/tests/test_udf.py +737 -0
  160. singlestoredb/tests/test_udf_returns.py +459 -0
  161. singlestoredb/tests/test_vectorstore.py +51 -0
  162. singlestoredb/tests/test_xdict.py +333 -0
  163. singlestoredb/tests/utils.py +141 -0
  164. singlestoredb/types.py +373 -0
  165. singlestoredb/utils/__init__.py +0 -0
  166. singlestoredb/utils/config.py +950 -0
  167. singlestoredb/utils/convert_rows.py +69 -0
  168. singlestoredb/utils/debug.py +13 -0
  169. singlestoredb/utils/dtypes.py +205 -0
  170. singlestoredb/utils/events.py +65 -0
  171. singlestoredb/utils/mogrify.py +151 -0
  172. singlestoredb/utils/results.py +585 -0
  173. singlestoredb/utils/xdict.py +425 -0
  174. singlestoredb/vectorstore.py +192 -0
  175. singlestoredb/warnings.py +5 -0
  176. singlestoredb-1.16.1.dist-info/METADATA +165 -0
  177. singlestoredb-1.16.1.dist-info/RECORD +183 -0
  178. singlestoredb-1.16.1.dist-info/WHEEL +5 -0
  179. singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
  180. singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
  181. singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
  182. sqlx/__init__.py +4 -0
  183. sqlx/magic.py +113 -0
@@ -0,0 +1,27 @@
1
+ # type: ignore
2
+ from io import StringIO
3
+ from unittest import TestCase
4
+
5
+ from singlestoredb.mysql.optionfile import Parser
6
+
7
+
8
+ __all__ = ['TestParser']
9
+
10
+
11
+ _cfg_file = r"""
12
+ [default]
13
+ string = foo
14
+ quoted = "bar"
15
+ single_quoted = 'foobar'
16
+ skip-slave-start
17
+ """
18
+
19
+
20
+ class TestParser(TestCase):
21
+
22
+ def test_string(self):
23
+ parser = Parser()
24
+ parser.read_file(StringIO(_cfg_file))
25
+ self.assertEqual(parser.get('default', 'string'), 'foo')
26
+ self.assertEqual(parser.get('default', 'quoted'), 'bar')
27
+ self.assertEqual(parser.get('default', 'single_quoted'), 'foobar')
@@ -0,0 +1,6 @@
1
+ from .test_MySQLdb import * # noqa: F403, F401
2
+
3
+ if __name__ == '__main__':
4
+ import unittest
5
+
6
+ unittest.main()
@@ -0,0 +1,9 @@
1
+ # type: ignore
2
+ from .test_MySQLdb_capabilities import test_MySQLdb as test_capabilities # noqa: F401
3
+ from .test_MySQLdb_dbapi20 import test_MySQLdb as test_dbapi2 # noqa: F401
4
+ from .test_MySQLdb_nonstandard import * # noqa: F401, F403
5
+
6
+ if __name__ == '__main__':
7
+ import unittest
8
+
9
+ unittest.main()
@@ -0,0 +1,323 @@
1
+ # type: ignore
2
+ """ Script to test database capabilities and the DB-API interface
3
+ for functionality and memory leaks.
4
+
5
+ Adapted from a script by M-A Lemburg.
6
+
7
+ """
8
+ import unittest
9
+ from time import time
10
+
11
+ import pytest
12
+
13
+
14
+ class DatabaseTest(unittest.TestCase):
15
+
16
+ db_module = None
17
+ connect_args = ()
18
+ connect_kwargs = dict(use_unicode=True, charset='utf8mb4', binary_prefix=True)
19
+ create_table_extra = 'ENGINE=INNODB CHARACTER SET UTF8MB4'
20
+ rows = 10
21
+ debug = False
22
+
23
+ def setUp(self):
24
+ db = self.db_module.connect(*self.connect_args, **self.connect_kwargs)
25
+ self.connection = db
26
+ self.cursor = db.cursor()
27
+ self.BLOBText = ''.join([chr(i) for i in range(256)] * 100)
28
+ self.BLOBUText = ''.join(chr(i) for i in range(16834))
29
+ data = bytearray(range(256)) * 16
30
+ self.BLOBBinary = self.db_module.Binary(data)
31
+
32
+ leak_test = True
33
+
34
+ def tearDown(self):
35
+ if self.leak_test:
36
+ import gc
37
+
38
+ del self.cursor
39
+ orphans = gc.collect()
40
+ self.assertFalse(
41
+ orphans, '%d orphaned objects found after deleting cursor' % orphans,
42
+ )
43
+
44
+ del self.connection
45
+ orphans = gc.collect()
46
+ self.assertFalse(
47
+ orphans, '%d orphaned objects found after deleting connection' % orphans,
48
+ )
49
+
50
+ def table_exists(self, name):
51
+ try:
52
+ self.cursor.execute('select * from %s where 1=0' % name)
53
+ except Exception:
54
+ return False
55
+ else:
56
+ return True
57
+
58
+ def quote_identifier(self, ident):
59
+ return '"%s"' % ident
60
+
61
+ def new_table_name(self):
62
+ i = id(self.cursor)
63
+ while True:
64
+ name = self.quote_identifier('tb%08x' % i)
65
+ if not self.table_exists(name):
66
+ return name
67
+ i = i + 1
68
+
69
+ def create_table(self, columndefs):
70
+ """
71
+ Create a table using a list of column definitions given in columndefs.
72
+
73
+ generator must be a function taking arguments (row_number,
74
+ col_number) returning a suitable data object for insertion
75
+ into the table.
76
+
77
+ """
78
+ self.table = self.new_table_name()
79
+ self.cursor.execute(
80
+ 'CREATE TABLE %s (%s) %s'
81
+ % (self.table, ',\n'.join(columndefs), self.create_table_extra),
82
+ )
83
+
84
+ def check_data_integrity(self, columndefs, generator):
85
+ # insert
86
+ self.create_table(columndefs)
87
+ insert_statement = 'INSERT INTO %s VALUES (%s)' % (
88
+ self.table,
89
+ ','.join('%s' for x in range(len(columndefs))),
90
+ )
91
+ data = [
92
+ [generator(i, j) for j in range(len(columndefs))] for i in range(self.rows)
93
+ ]
94
+ if self.debug:
95
+ print(data)
96
+ self.cursor.executemany(insert_statement, data)
97
+ self.connection.commit()
98
+ # verify
99
+ self.cursor.execute(
100
+ 'select * from %s ORDER BY %s' %
101
+ (self.table, columndefs[0].split()[0]),
102
+ )
103
+ out = self.cursor.fetchall()
104
+ if self.debug:
105
+ print(out)
106
+ self.assertEqual(len(out), self.rows)
107
+ try:
108
+ for i in range(self.rows):
109
+ for j in range(len(columndefs)):
110
+ self.assertEqual(out[i][j], generator(i, j))
111
+ finally:
112
+ if not self.debug:
113
+ self.cursor.execute('drop table %s' % (self.table))
114
+
115
+ def test_transactions(self):
116
+ columndefs = ('col1 INT', 'col2 VARCHAR(255)')
117
+
118
+ def generator(row, col):
119
+ if col == 0:
120
+ return row
121
+ else:
122
+ return ('%i' % (row % 10)) * 255
123
+
124
+ self.create_table(columndefs)
125
+ insert_statement = 'INSERT INTO %s VALUES (%s)' % (
126
+ self.table,
127
+ ','.join('%s' for x in range(len(columndefs))),
128
+ )
129
+ data = [
130
+ [generator(i, j) for j in range(len(columndefs))] for i in range(self.rows)
131
+ ]
132
+ self.cursor.executemany(insert_statement, data)
133
+ # verify
134
+ self.connection.commit()
135
+ self.cursor.execute(
136
+ 'select * from %s ORDER BY %s' %
137
+ (self.table, columndefs[0].split()[0]),
138
+ )
139
+ out = self.cursor.fetchall()
140
+ self.assertEqual(len(out), self.rows)
141
+ for i in range(self.rows):
142
+ for j in range(len(columndefs)):
143
+ self.assertEqual(out[i][j], generator(i, j))
144
+ delete_statement = 'delete from %s where col1=%%s' % self.table
145
+ self.cursor.execute(delete_statement, (0,))
146
+ self.cursor.execute('select col1 from %s where col1=%s' % (self.table, 0))
147
+ out = self.cursor.fetchall()
148
+ self.assertFalse(out, "DELETE didn't work")
149
+ self.connection.rollback()
150
+ self.cursor.execute('select col1 from %s where col1=%s' % (self.table, 0))
151
+ out = self.cursor.fetchall()
152
+ self.assertTrue(len(out) == 1, "ROLLBACK didn't work")
153
+ self.cursor.execute('drop table %s' % (self.table))
154
+
155
+ @pytest.mark.skip(reason='SingleStoreDB does not surface a warning')
156
+ def test_truncation(self):
157
+ columndefs = ('col1 INT', 'col2 VARCHAR(255)')
158
+
159
+ def generator(row, col):
160
+ if col == 0:
161
+ return row
162
+ else:
163
+ return ('%i' % (row % 10)) * ((255 - self.rows // 2) + row)
164
+
165
+ self.create_table(columndefs)
166
+ insert_statement = 'INSERT INTO %s VALUES (%s)' % (
167
+ self.table,
168
+ ','.join('%s' for x in range(len(columndefs))),
169
+ )
170
+
171
+ try:
172
+ self.cursor.execute(insert_statement, (0, '0' * 256))
173
+ except Warning:
174
+ if self.debug:
175
+ print(self.cursor.messages)
176
+ except self.connection.DataError:
177
+ pass
178
+ else:
179
+ self.fail(
180
+ 'Over-long column did not generate warnings/exception with single insert',
181
+ )
182
+
183
+ self.connection.rollback()
184
+
185
+ try:
186
+ for i in range(self.rows):
187
+ data = []
188
+ for j in range(len(columndefs)):
189
+ data.append(generator(i, j))
190
+ self.cursor.execute(insert_statement, tuple(data))
191
+ except Warning:
192
+ if self.debug:
193
+ print(self.cursor.messages)
194
+ except self.connection.DataError:
195
+ pass
196
+ else:
197
+ self.fail(
198
+ 'Over-long columns did not generate warnings/exception '
199
+ 'with execute()',
200
+ )
201
+
202
+ self.connection.rollback()
203
+
204
+ try:
205
+ data = [
206
+ [generator(i, j) for j in range(len(columndefs))]
207
+ for i in range(self.rows)
208
+ ]
209
+ self.cursor.executemany(insert_statement, data)
210
+ except Warning:
211
+ if self.debug:
212
+ print(self.cursor.messages)
213
+ except self.connection.DataError:
214
+ pass
215
+ else:
216
+ self.fail(
217
+ 'Over-long columns did not generate warnings/exception '
218
+ 'with executemany()',
219
+ )
220
+
221
+ self.connection.rollback()
222
+ self.cursor.execute('drop table %s' % (self.table))
223
+
224
+ def test_CHAR(self):
225
+ # Character data
226
+ def generator(row, col):
227
+ return ('%i' % ((row + col) % 10)) * 255
228
+
229
+ self.check_data_integrity(('col1 char(255)', 'col2 char(255)'), generator)
230
+
231
+ def test_INT(self):
232
+ # Number data
233
+ def generator(row, col):
234
+ return row * row
235
+
236
+ self.check_data_integrity(('col1 INT',), generator)
237
+
238
+ def test_DECIMAL(self):
239
+ # DECIMAL
240
+ def generator(row, col):
241
+ from decimal import Decimal
242
+
243
+ return Decimal('%d.%02d' % (row, col))
244
+
245
+ self.check_data_integrity(('col1 DECIMAL(5,2)',), generator)
246
+
247
+ def test_DATE(self):
248
+ ticks = time()
249
+
250
+ def generator(row, col):
251
+ return self.db_module.DateFromTicks(ticks + row * 86400 - col * 1313)
252
+
253
+ self.check_data_integrity(('col1 DATE',), generator)
254
+
255
+ def test_TIME(self):
256
+ ticks = time()
257
+
258
+ def generator(row, col):
259
+ return self.db_module.TimeFromTicks(ticks + row * 86400 - col * 1313)
260
+
261
+ self.check_data_integrity(('col1 TIME',), generator)
262
+
263
+ def test_DATETIME(self):
264
+ ticks = time()
265
+
266
+ def generator(row, col):
267
+ return self.db_module.TimestampFromTicks(ticks + row * 86400 - col * 1313)
268
+
269
+ self.check_data_integrity(('col1 DATETIME',), generator)
270
+
271
+ def test_TIMESTAMP(self):
272
+ ticks = time()
273
+
274
+ def generator(row, col):
275
+ return self.db_module.TimestampFromTicks(ticks + row * 86400 - col * 1313)
276
+
277
+ self.check_data_integrity(('col1 TIMESTAMP',), generator)
278
+
279
+ def test_fractional_TIMESTAMP(self):
280
+ ticks = time()
281
+
282
+ def generator(row, col):
283
+ return self.db_module.TimestampFromTicks(
284
+ ticks + row * 86400 - col * 1313 + row * 0.7 * col / 3.0,
285
+ )
286
+
287
+ self.check_data_integrity(('col1 TIMESTAMP',), generator)
288
+
289
+ def test_LONG(self):
290
+ def generator(row, col):
291
+ if col == 0:
292
+ return row
293
+ else:
294
+ return self.BLOBUText # 'BLOB Text ' * 1024
295
+
296
+ self.check_data_integrity(('col1 INT', 'col2 LONG'), generator)
297
+
298
+ def test_TEXT(self):
299
+ def generator(row, col):
300
+ if col == 0:
301
+ return row
302
+ else:
303
+ return self.BLOBUText[:5192] # 'BLOB Text ' * 1024
304
+
305
+ self.check_data_integrity(('col1 INT', 'col2 TEXT'), generator)
306
+
307
+ def test_LONG_BYTE(self):
308
+ def generator(row, col):
309
+ if col == 0:
310
+ return row
311
+ else:
312
+ return self.BLOBBinary # 'BLOB\000Binary ' * 1024
313
+
314
+ self.check_data_integrity(('col1 INT', 'col2 LONG BYTE'), generator)
315
+
316
+ def test_BLOB(self):
317
+ def generator(row, col):
318
+ if col == 0:
319
+ return row
320
+ else:
321
+ return self.BLOBBinary # 'BLOB\000Binary ' * 1024
322
+
323
+ self.check_data_integrity(('col1 INT', 'col2 BLOB'), generator)