singlestoredb 0.3.3__py3-none-any.whl → 1.0.3__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.

Potentially problematic release.


This version of singlestoredb might be problematic. Click here for more details.

Files changed (121) hide show
  1. singlestoredb/__init__.py +33 -2
  2. singlestoredb/alchemy/__init__.py +90 -0
  3. singlestoredb/auth.py +6 -4
  4. singlestoredb/config.py +116 -16
  5. singlestoredb/connection.py +489 -523
  6. singlestoredb/converters.py +275 -26
  7. singlestoredb/exceptions.py +30 -4
  8. singlestoredb/functions/__init__.py +1 -0
  9. singlestoredb/functions/decorator.py +142 -0
  10. singlestoredb/functions/dtypes.py +1639 -0
  11. singlestoredb/functions/ext/__init__.py +2 -0
  12. singlestoredb/functions/ext/arrow.py +375 -0
  13. singlestoredb/functions/ext/asgi.py +661 -0
  14. singlestoredb/functions/ext/json.py +427 -0
  15. singlestoredb/functions/ext/mmap.py +306 -0
  16. singlestoredb/functions/ext/rowdat_1.py +744 -0
  17. singlestoredb/functions/signature.py +673 -0
  18. singlestoredb/fusion/__init__.py +11 -0
  19. singlestoredb/fusion/graphql.py +213 -0
  20. singlestoredb/fusion/handler.py +621 -0
  21. singlestoredb/fusion/handlers/__init__.py +0 -0
  22. singlestoredb/fusion/handlers/stage.py +257 -0
  23. singlestoredb/fusion/handlers/utils.py +162 -0
  24. singlestoredb/fusion/handlers/workspace.py +412 -0
  25. singlestoredb/fusion/registry.py +164 -0
  26. singlestoredb/fusion/result.py +399 -0
  27. singlestoredb/http/__init__.py +27 -0
  28. singlestoredb/http/connection.py +1192 -0
  29. singlestoredb/management/__init__.py +3 -2
  30. singlestoredb/management/billing_usage.py +148 -0
  31. singlestoredb/management/cluster.py +19 -14
  32. singlestoredb/management/manager.py +100 -40
  33. singlestoredb/management/organization.py +188 -0
  34. singlestoredb/management/region.py +6 -8
  35. singlestoredb/management/utils.py +253 -4
  36. singlestoredb/management/workspace.py +1153 -35
  37. singlestoredb/mysql/__init__.py +177 -0
  38. singlestoredb/mysql/_auth.py +298 -0
  39. singlestoredb/mysql/charset.py +214 -0
  40. singlestoredb/mysql/connection.py +1814 -0
  41. singlestoredb/mysql/constants/CLIENT.py +38 -0
  42. singlestoredb/mysql/constants/COMMAND.py +32 -0
  43. singlestoredb/mysql/constants/CR.py +78 -0
  44. singlestoredb/mysql/constants/ER.py +474 -0
  45. singlestoredb/mysql/constants/FIELD_TYPE.py +32 -0
  46. singlestoredb/mysql/constants/FLAG.py +15 -0
  47. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  48. singlestoredb/mysql/constants/__init__.py +0 -0
  49. singlestoredb/mysql/converters.py +271 -0
  50. singlestoredb/mysql/cursors.py +713 -0
  51. singlestoredb/mysql/err.py +92 -0
  52. singlestoredb/mysql/optionfile.py +20 -0
  53. singlestoredb/mysql/protocol.py +388 -0
  54. singlestoredb/mysql/tests/__init__.py +19 -0
  55. singlestoredb/mysql/tests/base.py +126 -0
  56. singlestoredb/mysql/tests/conftest.py +37 -0
  57. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  58. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  59. singlestoredb/mysql/tests/test_basic.py +452 -0
  60. singlestoredb/mysql/tests/test_connection.py +851 -0
  61. singlestoredb/mysql/tests/test_converters.py +58 -0
  62. singlestoredb/mysql/tests/test_cursor.py +141 -0
  63. singlestoredb/mysql/tests/test_err.py +16 -0
  64. singlestoredb/mysql/tests/test_issues.py +514 -0
  65. singlestoredb/mysql/tests/test_load_local.py +75 -0
  66. singlestoredb/mysql/tests/test_nextset.py +88 -0
  67. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  68. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  69. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  70. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  71. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  72. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  73. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  74. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  75. singlestoredb/mysql/times.py +23 -0
  76. singlestoredb/pytest.py +283 -0
  77. singlestoredb/tests/empty.sql +0 -0
  78. singlestoredb/tests/ext_funcs/__init__.py +385 -0
  79. singlestoredb/tests/test.sql +210 -0
  80. singlestoredb/tests/test2.sql +1 -0
  81. singlestoredb/tests/test_basics.py +482 -117
  82. singlestoredb/tests/test_config.py +13 -15
  83. singlestoredb/tests/test_connection.py +241 -289
  84. singlestoredb/tests/test_dbapi.py +27 -0
  85. singlestoredb/tests/test_exceptions.py +0 -2
  86. singlestoredb/tests/test_ext_func.py +1193 -0
  87. singlestoredb/tests/test_ext_func_data.py +1101 -0
  88. singlestoredb/tests/test_fusion.py +465 -0
  89. singlestoredb/tests/test_http.py +32 -28
  90. singlestoredb/tests/test_management.py +588 -10
  91. singlestoredb/tests/test_plugin.py +33 -0
  92. singlestoredb/tests/test_results.py +11 -14
  93. singlestoredb/tests/test_types.py +0 -2
  94. singlestoredb/tests/test_udf.py +687 -0
  95. singlestoredb/tests/test_xdict.py +0 -2
  96. singlestoredb/tests/utils.py +3 -4
  97. singlestoredb/types.py +4 -5
  98. singlestoredb/utils/config.py +71 -12
  99. singlestoredb/utils/convert_rows.py +0 -2
  100. singlestoredb/utils/debug.py +13 -0
  101. singlestoredb/utils/mogrify.py +151 -0
  102. singlestoredb/utils/results.py +4 -3
  103. singlestoredb/utils/xdict.py +12 -12
  104. singlestoredb-1.0.3.dist-info/METADATA +139 -0
  105. singlestoredb-1.0.3.dist-info/RECORD +112 -0
  106. {singlestoredb-0.3.3.dist-info → singlestoredb-1.0.3.dist-info}/WHEEL +1 -1
  107. singlestoredb-1.0.3.dist-info/entry_points.txt +2 -0
  108. singlestoredb/drivers/__init__.py +0 -46
  109. singlestoredb/drivers/base.py +0 -200
  110. singlestoredb/drivers/cymysql.py +0 -40
  111. singlestoredb/drivers/http.py +0 -49
  112. singlestoredb/drivers/mariadb.py +0 -42
  113. singlestoredb/drivers/mysqlconnector.py +0 -51
  114. singlestoredb/drivers/mysqldb.py +0 -62
  115. singlestoredb/drivers/pymysql.py +0 -39
  116. singlestoredb/drivers/pyodbc.py +0 -67
  117. singlestoredb/http.py +0 -794
  118. singlestoredb-0.3.3.dist-info/METADATA +0 -105
  119. singlestoredb-0.3.3.dist-info/RECORD +0 -46
  120. {singlestoredb-0.3.3.dist-info → singlestoredb-1.0.3.dist-info}/LICENSE +0 -0
  121. {singlestoredb-0.3.3.dist-info → singlestoredb-1.0.3.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,16 @@
1
1
  #!/usr/bin/env python
2
2
  # type: ignore
3
3
  """Basic SingleStoreDB connection testing."""
4
- from __future__ import annotations
5
-
6
4
  import datetime
7
5
  import decimal
8
6
  import os
9
7
  import unittest
10
8
  import uuid
11
- import warnings
12
-
13
- import pandas as pd
14
9
 
15
10
  import singlestoredb as s2
16
11
  from singlestoredb import connection as sc
17
12
  from singlestoredb.tests import utils
13
+ # import pandas as pd
18
14
  # import traceback
19
15
 
20
16
 
@@ -36,9 +32,6 @@ class TestConnection(unittest.TestCase):
36
32
  def setUp(self):
37
33
  self.conn = s2.connect(database=type(self).dbname, local_infile=True)
38
34
  self.cur = self.conn.cursor()
39
- self.driver = self.conn._driver.dbapi.__name__.replace(
40
- 'singlestoredb.', '',
41
- )
42
35
 
43
36
  def tearDown(self):
44
37
  try:
@@ -83,16 +76,16 @@ class TestConnection(unittest.TestCase):
83
76
  assert cbp('enable') is True, cbp('enable')
84
77
  assert cbp('enabled') is True, cbp('enabled')
85
78
 
86
- assert cbp('false') is True, cbp('false')
87
- assert cbp('f') is True, cbp('f')
88
- assert cbp('False') is True, cbp('False')
89
- assert cbp('F') is True, cbp('F')
90
- assert cbp('FALSE') is True, cbp('FALSE')
79
+ assert cbp('false') is False, cbp('false')
80
+ assert cbp('f') is False, cbp('f')
81
+ assert cbp('False') is False, cbp('False')
82
+ assert cbp('F') is False, cbp('F')
83
+ assert cbp('FALSE') is False, cbp('FALSE')
91
84
 
92
- assert cbp('off') is True, cbp('off')
93
- assert cbp('no') is True, cbp('no')
94
- assert cbp('disable') is True, cbp('disable')
95
- assert cbp('disabled') is True, cbp('disabled')
85
+ assert cbp('off') is False, cbp('off')
86
+ assert cbp('no') is False, cbp('no')
87
+ assert cbp('disable') is False, cbp('disable')
88
+ assert cbp('disabled') is False, cbp('disabled')
96
89
 
97
90
  with self.assertRaises(ValueError):
98
91
  cbp('nein')
@@ -121,7 +114,7 @@ class TestConnection(unittest.TestCase):
121
114
  ('e', 'elephants', 0),
122
115
  ]), out
123
116
 
124
- assert rowcount == 5, rowcount
117
+ assert rowcount in (5, -1), rowcount
125
118
  assert rownumber == 5, rownumber
126
119
  assert lastrowid is None, lastrowid
127
120
  assert len(desc) == 3, desc
@@ -156,7 +149,7 @@ class TestConnection(unittest.TestCase):
156
149
  ('e', 'elephants', 0),
157
150
  ]), out
158
151
 
159
- assert rowcount == 5, rowcount
152
+ assert rowcount in (5, -1), rowcount
160
153
  assert rownumber == 5, rownumber
161
154
  assert lastrowid is None, lastrowid
162
155
  assert len(desc) == 3, desc
@@ -192,7 +185,7 @@ class TestConnection(unittest.TestCase):
192
185
  ('e', 'elephants', 0),
193
186
  ]), out
194
187
 
195
- assert rowcount == 5, rowcount
188
+ assert rowcount in (5, -1), rowcount
196
189
  assert rownumber == 5, rownumber
197
190
  assert lastrowid is None, lastrowid
198
191
  assert len(desc) == 3, desc
@@ -229,7 +222,7 @@ class TestConnection(unittest.TestCase):
229
222
  assert self.cur.rownumber == 5, self.cur.rownumber
230
223
 
231
224
  def test_execute_with_dict_params(self):
232
- self.cur.execute('select * from data where id < :name', dict(name='d'))
225
+ self.cur.execute('select * from data where id < %(name)s', dict(name='d'))
233
226
  out = self.cur.fetchall()
234
227
 
235
228
  desc = self.cur.description
@@ -242,7 +235,7 @@ class TestConnection(unittest.TestCase):
242
235
  ('c', 'cats', 5),
243
236
  ]), out
244
237
 
245
- assert rowcount == 3, rowcount
238
+ assert rowcount in (3, -1), rowcount
246
239
  assert lastrowid is None, lastrowid
247
240
  assert len(desc) == 3, desc
248
241
  assert desc[0].name == 'id', desc[0].name
@@ -253,7 +246,7 @@ class TestConnection(unittest.TestCase):
253
246
  assert desc[2].type_code == 8, desc[2].type_code
254
247
 
255
248
  def test_execute_with_positional_params(self):
256
- self.cur.execute('select * from data where id < :1', ['d'])
249
+ self.cur.execute('select * from data where id < %s', ['d'])
257
250
  out = self.cur.fetchall()
258
251
 
259
252
  desc = self.cur.description
@@ -266,7 +259,7 @@ class TestConnection(unittest.TestCase):
266
259
  ('c', 'cats', 5),
267
260
  ]), out
268
261
 
269
- assert rowcount == 3, rowcount
262
+ assert rowcount in (3, -1), rowcount
270
263
  assert lastrowid is None, lastrowid
271
264
  assert len(desc) == 3, desc
272
265
  assert desc[0].name == 'id', desc[0].name
@@ -278,7 +271,7 @@ class TestConnection(unittest.TestCase):
278
271
 
279
272
  def test_execute_with_escaped_positional_substitutions(self):
280
273
  self.cur.execute(
281
- 'select `id`, `time` from alltypes where `time` = :1', [
274
+ 'select `id`, `time` from alltypes where `time` = %s', [
282
275
  '00:07:00',
283
276
  ],
284
277
  )
@@ -291,44 +284,44 @@ class TestConnection(unittest.TestCase):
291
284
  out = self.cur.fetchall()
292
285
  assert out[0] == (0, datetime.timedelta(seconds=420)), out[0]
293
286
 
294
- with self.assertRaises(IndexError):
295
- self.cur.execute(
296
- 'select `id`, `time` from alltypes where `id` = :1 '
297
- 'or `time` = "00:07:00"', [0],
298
- )
287
+ # with self.assertRaises(IndexError):
288
+ # self.cur.execute(
289
+ # 'select `id`, `time` from alltypes where `id` = %1s '
290
+ # 'or `time` = "00:07:00"', [0],
291
+ # )
299
292
 
300
293
  self.cur.execute(
301
- 'select `id`, `time` from alltypes where `id` = :1 '
302
- 'or `time` = "00::07::00"', [0],
294
+ 'select `id`, `time` from alltypes where `id` = %s '
295
+ 'or `time` = "00:07:00"', [0],
303
296
  )
304
297
  out = self.cur.fetchall()
305
298
  assert out[0] == (0, datetime.timedelta(seconds=420)), out[0]
306
299
 
307
300
  def test_execute_with_escaped_substitutions(self):
308
301
  self.cur.execute(
309
- 'select `id`, `time` from alltypes where `time` = :time',
302
+ 'select `id`, `time` from alltypes where `time` = %(time)s',
310
303
  dict(time='00:07:00'),
311
304
  )
312
305
  out = self.cur.fetchall()
313
306
  assert out[0] == (0, datetime.timedelta(seconds=420)), out[0]
314
307
 
315
308
  self.cur.execute(
316
- 'select `id`, `time` from alltypes where `time` = :time',
317
- dict(time='00::07::00'),
309
+ 'select `id`, `time` from alltypes where `time` = %(time)s',
310
+ dict(time='00:07:00'),
318
311
  )
319
312
  out = self.cur.fetchall()
320
- assert len(out) == 0, out
313
+ assert len(out) == 1, out
321
314
 
322
315
  with self.assertRaises(KeyError):
323
316
  self.cur.execute(
324
317
  'select `id`, `time`, `char_100` from alltypes '
325
- 'where `time` = :time or `char_100` like "foo:bar"',
326
- dict(time='00:07:00'),
318
+ 'where `time` = %(time)s or `char_100` like "foo:bar"',
319
+ dict(x='00:07:00'),
327
320
  )
328
321
 
329
322
  self.cur.execute(
330
323
  'select `id`, `time`, `char_100` from alltypes '
331
- 'where `time` = :time or `char_100` like "foo::bar"',
324
+ 'where `time` = %(time)s or `char_100` like "foo::bar"',
332
325
  dict(time='00:07:00'),
333
326
  )
334
327
  out = self.cur.fetchall()
@@ -352,7 +345,7 @@ class TestConnection(unittest.TestCase):
352
345
  def test_executemany(self):
353
346
  # NOTE: Doesn't actually do anything since no rows match
354
347
  self.cur.executemany(
355
- 'delete from data where id > :name',
348
+ 'delete from data where id > %(name)s',
356
349
  [dict(name='z'), dict(name='y')],
357
350
  )
358
351
 
@@ -541,8 +534,6 @@ class TestConnection(unittest.TestCase):
541
534
  with self.assertRaises(s2.ProgrammingError) as cm:
542
535
  self.cur.execute('garbage syntax')
543
536
  exc = cm.exception
544
- if self.driver != 'pyodbc':
545
- assert exc.errno == 1064, exc.errno
546
537
  assert 'You have an error in your SQL syntax' in exc.errmsg, exc.errmsg
547
538
 
548
539
  def test_alltypes(self):
@@ -555,30 +546,8 @@ class TestConnection(unittest.TestCase):
555
546
 
556
547
  bits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
557
548
 
558
- if self.driver == 'pyodbc':
559
- odbc_types = {
560
- # int -> bigint
561
- 3: 8, 1: 8, 2: 8, 9: 8,
562
- # float -> double
563
- 4: 5,
564
- # timestamp -> datetime
565
- 7: 12,
566
- # year -> bigint
567
- 13: 8,
568
- # char/binary -> varchar/varbinary
569
- 249: 15, 250: 15, 251: 15, 252: 15, 253: 15, 254: 15, 255: 15,
570
- # newdecimal -> decimal
571
- 246: 0,
572
- # json -> varchar
573
- 245: 15,
574
- # bit -> varchar
575
- 16: 15,
576
- }
577
- else:
578
- odbc_types = {}
579
-
580
549
  def otype(x):
581
- return odbc_types.get(x, x)
550
+ return x
582
551
 
583
552
  assert row['id'] == 0, row['id']
584
553
  assert typ['id'] == otype(3), typ['id']
@@ -664,11 +633,6 @@ class TestConnection(unittest.TestCase):
664
633
  assert row['time'] == datetime.timedelta(minutes=7), row['time']
665
634
  assert typ['time'] == 11, typ['time']
666
635
 
667
- # pyodbc doesn't support microseconds on times
668
- if not self.driver == 'pyodbc':
669
- assert row['time_6'] == datetime.timedelta(
670
- hours=1, minutes=10, microseconds=2,
671
- ), row['time_6']
672
636
  assert typ['time_6'] == 11, typ['time_6']
673
637
 
674
638
  assert row['datetime'] == datetime.datetime(
@@ -742,14 +706,10 @@ class TestConnection(unittest.TestCase):
742
706
  ), row['tinyblob']
743
707
  assert typ['tinyblob'] == otype(249), typ['tinyblob']
744
708
 
745
- # pyodbc surfaces json as varchar
746
- if self.driver == 'pyodbc':
747
- assert row['json'] == '{"a":10,"b":2.75,"c":"hello world"}', row['json']
748
- else:
749
- assert row['json'] == {
750
- 'a': 10, 'b': 2.75,
751
- 'c': 'hello world',
752
- }, row['json']
709
+ assert row['json'] == {
710
+ 'a': 10, 'b': 2.75,
711
+ 'c': 'hello world',
712
+ }, row['json']
753
713
  assert typ['json'] == otype(245), typ['json']
754
714
 
755
715
  assert row['enum'] == 'one', row['enum']
@@ -758,10 +718,7 @@ class TestConnection(unittest.TestCase):
758
718
  assert row['set'] == 'two', row['set']
759
719
  assert typ['set'] == otype(253), typ['set'] # mysql code: 248
760
720
 
761
- if self.driver == 'pyodbc':
762
- assert row['bit'] == b'\x80\x00\x00\x00\x00\x00\x00\x00', row['bit']
763
- else:
764
- assert row['bit'] == b'\x00\x00\x00\x00\x00\x00\x00\x80', row['bit']
721
+ assert row['bit'] == b'\x00\x00\x00\x00\x00\x00\x00\x80', row['bit']
765
722
  assert typ['bit'] == otype(16), typ['bit']
766
723
 
767
724
  def test_alltypes_nulls(self):
@@ -772,30 +729,8 @@ class TestConnection(unittest.TestCase):
772
729
  row = dict(zip(names, out))
773
730
  typ = dict(zip(names, types))
774
731
 
775
- if self.driver == 'pyodbc':
776
- odbc_types = {
777
- # int -> bigint
778
- 3: 8, 1: 8, 2: 8, 9: 8,
779
- # float -> double
780
- 4: 5,
781
- # timestamp -> datetime
782
- 7: 12,
783
- # year -> bigint
784
- 13: 8,
785
- # char/binary -> varchar/varbinary
786
- 249: 15, 250: 15, 251: 15, 252: 15, 253: 15, 254: 15, 255: 15,
787
- # newdecimal -> decimal
788
- 246: 0,
789
- # json -> varchar
790
- 245: 15,
791
- # bit -> varchar
792
- 16: 15,
793
- }
794
- else:
795
- odbc_types = {}
796
-
797
732
  def otype(x):
798
- return odbc_types.get(x, x)
733
+ return x
799
734
 
800
735
  assert row['id'] == 1, row['id']
801
736
  assert typ['id'] == otype(3), typ['id']
@@ -924,78 +859,6 @@ class TestConnection(unittest.TestCase):
924
859
  assert row['bit'] is None, row['bit']
925
860
  assert typ['bit'] == otype(16), typ['bit']
926
861
 
927
- def test_convert_exception(self):
928
- driver = self.conn._driver
929
- dbapi = driver.dbapi
930
-
931
- if self.driver in ['mysql.connector', 'http', 'https']:
932
- exc_args = tuple()
933
- exc_kwargs = dict(errno=-1, msg='hi there')
934
- else:
935
- exc_args = (-1, 'hi there')
936
- exc_kwargs = {}
937
-
938
- exc = driver.convert_exception(
939
- dbapi.NotSupportedError(*exc_args, **exc_kwargs),
940
- )
941
- assert exc.args[0] == -1
942
- assert exc.args[1] == 'hi there'
943
- assert exc.errno == -1
944
- assert exc.errmsg == 'hi there'
945
- assert exc.msg == 'hi there'
946
-
947
- with self.assertRaises(s2.NotSupportedError):
948
- raise driver.convert_exception(
949
- dbapi.NotSupportedError(*exc_args, **exc_kwargs),
950
- )
951
-
952
- with self.assertRaises(s2.ProgrammingError):
953
- raise driver.convert_exception(
954
- dbapi.ProgrammingError(*exc_args, **exc_kwargs),
955
- )
956
-
957
- with self.assertRaises(s2.InternalError):
958
- raise driver.convert_exception(
959
- dbapi.InternalError(*exc_args, **exc_kwargs),
960
- )
961
-
962
- with self.assertRaises(s2.IntegrityError):
963
- raise driver.convert_exception(
964
- dbapi.IntegrityError(*exc_args, **exc_kwargs),
965
- )
966
-
967
- with self.assertRaises(s2.OperationalError):
968
- raise driver.convert_exception(
969
- dbapi.OperationalError(*exc_args, **exc_kwargs),
970
- )
971
-
972
- with self.assertRaises(s2.DataError):
973
- raise driver.convert_exception(
974
- dbapi.DataError(*exc_args, **exc_kwargs),
975
- )
976
-
977
- with self.assertRaises(s2.DatabaseError):
978
- raise driver.convert_exception(
979
- dbapi.DatabaseError(*exc_args, **exc_kwargs),
980
- )
981
-
982
- with self.assertRaises(s2.InterfaceError):
983
- raise driver.convert_exception(
984
- dbapi.InterfaceError(*exc_args, **exc_kwargs),
985
- )
986
-
987
- with self.assertRaises(s2.Error):
988
- raise driver.convert_exception(
989
- dbapi.Error(*exc_args, **exc_kwargs),
990
- )
991
-
992
- if self.driver == 'mariadb':
993
- with self.assertRaises(s2.Error):
994
- raise driver.convert_exception(dbapi.Warning('hi there'))
995
- else:
996
- with self.assertRaises(s2.Warning):
997
- raise driver.convert_exception(dbapi.Warning('hi there'))
998
-
999
862
  def test_name_check(self):
1000
863
  nc = sc._name_check
1001
864
  assert nc('foo') == 'foo'
@@ -1016,46 +879,31 @@ class TestConnection(unittest.TestCase):
1016
879
  self.cur.execute('echo return_int()')
1017
880
 
1018
881
  out = self.cur.fetchall()
1019
- assert out == [(1234567890,)], out
1020
-
1021
- # These take an extra `nextset` for some reason
1022
- if self.driver in ['pymysql', 'MySQLdb', 'cymysql', 'pyodbc']:
1023
- self.cur.nextset()
882
+ assert list(out) == [(1234567890,)], out
1024
883
 
1025
884
  out = self.cur.nextset()
1026
- assert out is False, out
885
+ assert out is None, out
1027
886
 
1028
887
  def test_echo_with_result_set(self):
1029
888
  self.cur.execute('echo result_set_and_return_int()')
1030
889
 
1031
890
  out = self.cur.fetchall()
1032
- assert out == [(5,)], out
1033
-
1034
- if self.driver == 'mysql.connector' and s2.get_option('pure_python'):
1035
- warnings.warn(
1036
- 'The mysql.connector in pure python mode does not '
1037
- 'support multiple result sets.',
1038
- )
1039
- return
891
+ assert list(out) == [(5,)], out
1040
892
 
1041
893
  out = self.cur.nextset()
1042
894
  assert out is True, out
1043
895
 
1044
896
  out = self.cur.fetchall()
1045
- assert out == [(1, 2, 3)], out
897
+ assert list(out) == [(1, 2, 3)], out
1046
898
 
1047
899
  out = self.cur.nextset()
1048
900
  assert out is True, out
1049
901
 
1050
902
  out = self.cur.fetchall()
1051
- assert out == [(1234567890,)], out
1052
-
1053
- # These take an extra `nextset` for some reason
1054
- if self.driver in ['pymysql', 'MySQLdb', 'cymysql', 'pyodbc']:
1055
- self.cur.nextset()
903
+ assert list(out) == [(1234567890,)], out
1056
904
 
1057
905
  out = self.cur.nextset()
1058
- assert out is False, out
906
+ assert out is None, out
1059
907
 
1060
908
  def test_callproc(self):
1061
909
  self.cur.callproc('get_animal', ['cats'])
@@ -1063,25 +911,21 @@ class TestConnection(unittest.TestCase):
1063
911
  out = self.cur.fetchall()
1064
912
  assert list(out) == [(5,)], out
1065
913
 
1066
- if self.driver == 'mysql.connector' and s2.get_option('pure_python'):
1067
- warnings.warn(
1068
- 'The mysql.connector in pure python mode does not '
1069
- 'support multiple result sets.',
1070
- )
1071
- return
1072
-
1073
914
  out = self.cur.nextset()
1074
915
  assert out is True, out
1075
916
 
1076
917
  out = self.cur.fetchall()
1077
918
  assert list(out) == [(1, 2, 3)], out
1078
919
 
1079
- # These take an extra `nextset` for some reason
1080
- if self.driver in ['pymysql', 'MySQLdb', 'cymysql', 'pyodbc']:
1081
- self.cur.nextset()
920
+ out = self.cur.nextset()
921
+ assert out is True, out
922
+
923
+ # Always get an empty set at the end
924
+ out = self.cur.fetchall()
925
+ assert list(out) == [], out
1082
926
 
1083
927
  out = self.cur.nextset()
1084
- assert out is False, out
928
+ assert out is None, out
1085
929
 
1086
930
  def test_callproc_no_args(self):
1087
931
  self.cur.callproc('no_args')
@@ -1089,38 +933,37 @@ class TestConnection(unittest.TestCase):
1089
933
  out = self.cur.fetchall()
1090
934
  assert list(out) == [(4, 5, 6)], out
1091
935
 
1092
- # These take an extra `nextset` for some reason
1093
- if self.driver in ['pymysql', 'MySQLdb', 'cymysql', 'pyodbc']:
1094
- self.cur.nextset()
936
+ out = self.cur.nextset()
937
+ assert out is True, out
938
+
939
+ # Always get an empty set at the end
940
+ out = self.cur.fetchall()
941
+ assert list(out) == [], out
1095
942
 
1096
943
  out = self.cur.nextset()
1097
- assert out is False, out
944
+ assert out is None, out
1098
945
 
1099
946
  def test_callproc_return_int(self):
1100
947
  self.cur.callproc('result_set_and_return_int')
1101
948
 
1102
949
  out = self.cur.fetchall()
1103
- assert out == [(5,)], out
1104
-
1105
- if self.driver == 'mysql.connector' and s2.get_option('pure_python'):
1106
- warnings.warn(
1107
- 'The mysql.connector in pure python mode does not '
1108
- 'support multiple result sets.',
1109
- )
1110
- return
950
+ assert list(out) == [(5,)], out
1111
951
 
1112
952
  out = self.cur.nextset()
1113
953
  assert out is True, out
1114
954
 
1115
955
  out = self.cur.fetchall()
1116
- assert out == [(1, 2, 3)], out
956
+ assert list(out) == [(1, 2, 3)], out
1117
957
 
1118
- # These take an extra `nextset` for some reason
1119
- if self.driver in ['pymysql', 'MySQLdb', 'cymysql', 'pyodbc']:
1120
- self.cur.nextset()
958
+ out = self.cur.nextset()
959
+ assert out is True, out
960
+
961
+ # Always get an empty set at the end
962
+ out = self.cur.fetchall()
963
+ assert list(out) == [], out
1121
964
 
1122
965
  out = self.cur.nextset()
1123
- assert out is False, out
966
+ assert out is None, out
1124
967
 
1125
968
  def test_callproc_bad_args(self):
1126
969
  self.cur.callproc('get_animal', [10])
@@ -1128,31 +971,28 @@ class TestConnection(unittest.TestCase):
1128
971
  out = self.cur.fetchall()
1129
972
  assert list(out) == [], out
1130
973
 
1131
- if self.driver == 'mysql.connector' and s2.get_option('pure_python'):
1132
- warnings.warn(
1133
- 'The mysql.connector in pure python mode does not '
1134
- 'support multiple result sets.',
1135
- )
1136
- return
1137
-
1138
974
  out = self.cur.nextset()
1139
975
  assert out is True, out
1140
976
 
1141
977
  out = self.cur.fetchall()
1142
978
  assert list(out) == [(1, 2, 3)], out
1143
979
 
1144
- # These take an extra `nextset` for some reason
1145
- if self.driver in ['pymysql', 'MySQLdb', 'cymysql', 'pyodbc']:
1146
- self.cur.nextset()
980
+ out = self.cur.nextset()
981
+ assert out is True, out
982
+
983
+ # Always get an empty set at the end
984
+ out = self.cur.fetchall()
985
+ assert list(out) == [], out
1147
986
 
1148
987
  out = self.cur.nextset()
1149
- assert out is False, out
988
+ assert out is None, out
1150
989
 
1151
990
  def test_callproc_too_many_args(self):
1152
991
  with self.assertRaises((
1153
992
  s2.ProgrammingError,
1154
993
  s2.OperationalError,
1155
994
  s2.InternalError,
995
+ TypeError,
1156
996
  )):
1157
997
  self.cur.callproc('get_animal', ['cats', 'dogs'])
1158
998
 
@@ -1160,6 +1000,7 @@ class TestConnection(unittest.TestCase):
1160
1000
  s2.ProgrammingError,
1161
1001
  s2.OperationalError,
1162
1002
  s2.InternalError,
1003
+ TypeError,
1163
1004
  )):
1164
1005
  self.cur.callproc('get_animal', [])
1165
1006
 
@@ -1167,43 +1008,43 @@ class TestConnection(unittest.TestCase):
1167
1008
  s2.ProgrammingError,
1168
1009
  s2.OperationalError,
1169
1010
  s2.InternalError,
1011
+ TypeError,
1170
1012
  )):
1171
1013
  self.cur.callproc('get_animal')
1172
1014
 
1173
1015
  def test_cursor_close(self):
1174
1016
  self.cur.close()
1175
1017
 
1176
- with self.assertRaises(s2.InterfaceError):
1177
- self.cur.close()
1018
+ self.cur.close()
1178
1019
 
1179
- with self.assertRaises(s2.InterfaceError):
1020
+ with self.assertRaises(s2.ProgrammingError):
1180
1021
  self.cur.callproc('foo')
1181
1022
 
1182
- with self.assertRaises(s2.InterfaceError):
1023
+ with self.assertRaises(s2.ProgrammingError):
1183
1024
  self.cur.execute('select 1')
1184
1025
 
1185
- with self.assertRaises(s2.InterfaceError):
1186
- self.cur.executemany('select 1')
1026
+ # with self.assertRaises(s2.ProgrammingError):
1027
+ # self.cur.executemany('select 1')
1187
1028
 
1188
- with self.assertRaises(s2.InterfaceError):
1029
+ with self.assertRaises(s2.ProgrammingError):
1189
1030
  self.cur.fetchone()
1190
1031
 
1191
- with self.assertRaises(s2.InterfaceError):
1032
+ with self.assertRaises(s2.ProgrammingError):
1192
1033
  self.cur.fetchall()
1193
1034
 
1194
- with self.assertRaises(s2.InterfaceError):
1035
+ with self.assertRaises(s2.ProgrammingError):
1195
1036
  self.cur.fetchmany()
1196
1037
 
1197
- with self.assertRaises(s2.InterfaceError):
1038
+ with self.assertRaises(s2.ProgrammingError):
1198
1039
  self.cur.nextset()
1199
1040
 
1200
- with self.assertRaises(s2.InterfaceError):
1201
- self.cur.setinputsizes([])
1041
+ # with self.assertRaises(s2.ProgrammingError):
1042
+ # self.cur.setinputsizes([])
1202
1043
 
1203
- with self.assertRaises(s2.InterfaceError):
1204
- self.cur.setoutputsize(10)
1044
+ # with self.assertRaises(s2.ProgrammingError):
1045
+ # self.cur.setoutputsize(10)
1205
1046
 
1206
- with self.assertRaises(s2.InterfaceError):
1047
+ with self.assertRaises(s2.ProgrammingError):
1207
1048
  self.cur.scroll(2)
1208
1049
 
1209
1050
  with self.assertRaises(s2.InterfaceError):
@@ -1221,15 +1062,9 @@ class TestConnection(unittest.TestCase):
1221
1062
  self.cur.setinputsizes([10, 20, 30])
1222
1063
 
1223
1064
  def test_setoutputsize(self):
1224
- if self.driver in ['MySQLdb', 'pymysql', 'cymysql']:
1225
- self.skipTest('outputsize is not supported')
1226
-
1227
1065
  self.cur.setoutputsize(100)
1228
1066
 
1229
1067
  def test_scroll(self):
1230
- if self.driver in ['mysql.connector', 'pyodbc', 'mariadb', 'cymysql']:
1231
- self.skipTest('scroll is not supported')
1232
-
1233
1068
  self.cur.execute('select * from data order by name')
1234
1069
 
1235
1070
  out = self.cur.fetchone()
@@ -1242,19 +1077,21 @@ class TestConnection(unittest.TestCase):
1242
1077
  assert out[1] == 'elephants', out[1]
1243
1078
  assert self.cur.rownumber == 5, self.cur.rownumber
1244
1079
 
1245
- self.cur.scroll(0, mode='absolute')
1246
-
1247
- assert self.cur.rownumber == 0, self.cur.rownumber
1080
+ try:
1081
+ self.cur.scroll(0, mode='absolute')
1082
+ assert self.cur.rownumber == 0, self.cur.rownumber
1248
1083
 
1249
- out = self.cur.fetchone()
1250
- assert out[1] == 'antelopes', out[1]
1251
- assert self.cur.rownumber == 1, self.cur.rownumber
1084
+ out = self.cur.fetchone()
1085
+ assert out[1] == 'antelopes', out[1]
1086
+ assert self.cur.rownumber == 1, self.cur.rownumber
1087
+ except s2.NotSupportedError:
1088
+ pass
1252
1089
 
1253
1090
  with self.assertRaises((ValueError, s2.ProgrammingError)):
1254
1091
  self.cur.scroll(0, mode='badmode')
1255
1092
 
1256
1093
  def test_autocommit(self):
1257
- if self.driver in ['http', 'https']:
1094
+ if self.conn.driver in ['http', 'https']:
1258
1095
  self.skipTest('Can not set autocommit in HTTP')
1259
1096
 
1260
1097
  orig = self.conn.locals.autocommit
@@ -1272,10 +1109,11 @@ class TestConnection(unittest.TestCase):
1272
1109
  def test_conn_close(self):
1273
1110
  self.conn.close()
1274
1111
 
1275
- self.conn.close()
1112
+ with self.assertRaises(s2.Error):
1113
+ self.conn.close()
1276
1114
 
1277
1115
  with self.assertRaises(s2.InterfaceError):
1278
- self.conn.autocommit()
1116
+ self.conn.autocommit(False)
1279
1117
 
1280
1118
  with self.assertRaises(s2.InterfaceError):
1281
1119
  self.conn.commit()
@@ -1283,11 +1121,11 @@ class TestConnection(unittest.TestCase):
1283
1121
  with self.assertRaises(s2.InterfaceError):
1284
1122
  self.conn.rollback()
1285
1123
 
1286
- with self.assertRaises(s2.InterfaceError):
1287
- self.conn.cursor()
1124
+ # with self.assertRaises(s2.InterfaceError):
1125
+ # self.conn.cursor()
1288
1126
 
1289
- with self.assertRaises(s2.InterfaceError):
1290
- self.conn.messages
1127
+ # with self.assertRaises(s2.InterfaceError):
1128
+ # self.conn.messages
1291
1129
 
1292
1130
  with self.assertRaises(s2.InterfaceError):
1293
1131
  self.conn.globals.autocommit = True
@@ -1308,7 +1146,7 @@ class TestConnection(unittest.TestCase):
1308
1146
  self.conn.disable_data_api()
1309
1147
 
1310
1148
  def test_rollback(self):
1311
- if self.driver in ['http', 'https']:
1149
+ if self.conn.driver in ['http', 'https']:
1312
1150
  self.skipTest('Can not set autocommit in HTTP')
1313
1151
 
1314
1152
  self.conn.autocommit(False)
@@ -1330,7 +1168,7 @@ class TestConnection(unittest.TestCase):
1330
1168
  assert len(out) == 5, len(out)
1331
1169
 
1332
1170
  def test_commit(self):
1333
- if self.driver in ['http', 'https']:
1171
+ if self.conn.driver in ['http', 'https']:
1334
1172
  self.skipTest('Can not set autocommit in HTTP')
1335
1173
 
1336
1174
  self.conn.autocommit(False)
@@ -1379,7 +1217,7 @@ class TestConnection(unittest.TestCase):
1379
1217
  assert val == orig, val
1380
1218
 
1381
1219
  def test_session_var(self):
1382
- if self.driver in ['http', 'https']:
1220
+ if self.conn.driver in ['http', 'https']:
1383
1221
  self.skipTest('Can not change session variable in HTTP')
1384
1222
 
1385
1223
  orig = self.conn.locals.enable_multipartition_queries
@@ -1397,7 +1235,7 @@ class TestConnection(unittest.TestCase):
1397
1235
  assert val == orig, val
1398
1236
 
1399
1237
  def test_local_infile(self):
1400
- if self.driver in ['http', 'https']:
1238
+ if self.conn.driver in ['http', 'https']:
1401
1239
  self.skipTest('Can not load local files in HTTP')
1402
1240
 
1403
1241
  path = os.path.join(os.path.dirname(__file__), 'local_infile.csv')
@@ -1413,16 +1251,16 @@ class TestConnection(unittest.TestCase):
1413
1251
 
1414
1252
  try:
1415
1253
  self.cur.execute(
1416
- f'load data local infile :1 into table {tblname} '
1254
+ f'load data local infile %s into table {tblname} '
1417
1255
  'fields terminated by "," lines terminated by "\n";', [path],
1418
1256
  )
1419
1257
 
1420
- self.cur.execute(f'select * from {tblname};')
1258
+ self.cur.execute(f'select * from {tblname} order by first_name')
1421
1259
  out = list(self.cur)
1422
1260
  assert out == [
1423
1261
  ('John', 'Doe', 34),
1424
- ('Sandy', 'Smith', 24),
1425
1262
  ('Patty', 'Jones', 57),
1263
+ ('Sandy', 'Smith', 24),
1426
1264
  ], out
1427
1265
 
1428
1266
  finally:
@@ -1444,7 +1282,7 @@ class TestConnection(unittest.TestCase):
1444
1282
  254: upper,
1445
1283
  }
1446
1284
 
1447
- with s2.connect(database=type(self).dbname, converters=convs) as conn:
1285
+ with s2.connect(database=type(self).dbname, conv=convs) as conn:
1448
1286
  with conn.cursor() as cur:
1449
1287
  cur.execute('select * from alltypes where id = 0')
1450
1288
  names = [x[0] for x in cur.description]
@@ -1474,7 +1312,7 @@ class TestConnection(unittest.TestCase):
1474
1312
  assert row['tinytext'] == 'This is a tinytext column.', \
1475
1313
  row['tinytext']
1476
1314
 
1477
- def test_results_format(self):
1315
+ def test_results_type(self):
1478
1316
  columns = [
1479
1317
  'id', 'tinyint', 'unsigned_tinyint', 'bool', 'boolean',
1480
1318
  'smallint', 'unsigned_smallint', 'mediumint', 'unsigned_mediumint',
@@ -1488,33 +1326,147 @@ class TestConnection(unittest.TestCase):
1488
1326
  'set', 'bit',
1489
1327
  ]
1490
1328
 
1491
- with s2.connect(database=type(self).dbname, results_format='tuple') as conn:
1329
+ with s2.connect(database=type(self).dbname, results_type='tuples') as conn:
1492
1330
  with conn.cursor() as cur:
1493
1331
  cur.execute('select * from alltypes')
1494
1332
  out = cur.fetchall()
1495
1333
  assert type(out[0]) is tuple, type(out[0])
1496
1334
  assert len(out[0]) == len(columns), len(out[0])
1497
1335
 
1498
- with s2.connect(database=type(self).dbname, results_format='namedtuple') as conn:
1336
+ with s2.connect(database=type(self).dbname, results_type='namedtuples') as conn:
1499
1337
  with conn.cursor() as cur:
1500
1338
  cur.execute('select * from alltypes')
1501
1339
  out = cur.fetchall()
1502
1340
  assert type(out[0]).__name__ == 'Row', type(out)
1503
- assert list(out[0]._fields) == columns, out[0]._fields
1341
+ for i, name in enumerate(columns):
1342
+ assert hasattr(out[0], name)
1343
+ assert out[0][i] == getattr(out[0], name)
1504
1344
 
1505
- with s2.connect(database=type(self).dbname, results_format='dict') as conn:
1345
+ with s2.connect(database=type(self).dbname, results_type='dicts') as conn:
1506
1346
  with conn.cursor() as cur:
1507
1347
  cur.execute('select * from alltypes')
1508
1348
  out = cur.fetchall()
1509
1349
  assert type(out[0]) is dict, type(out)
1510
1350
  assert list(out[0].keys()) == columns, out[0].keys()
1511
1351
 
1512
- with s2.connect(database=type(self).dbname, results_format='dataframe') as conn:
1352
+ def test_results_format(self):
1353
+ with self.assertWarns(DeprecationWarning):
1354
+ with s2.connect(database=type(self).dbname, results_format='dicts') as conn:
1355
+ with conn.cursor() as cur:
1356
+ cur.execute('select * from alltypes')
1357
+ out = cur.fetchall()
1358
+ assert type(out[0]) is dict, type(out)
1359
+
1360
+ def test_multi_statements(self):
1361
+ if self.conn.driver not in ['http', 'https']:
1362
+ with s2.connect(database=type(self).dbname, multi_statements=True) as conn:
1363
+ with conn.cursor() as cur:
1364
+ cur.execute('SELECT 1; SELECT 2;')
1365
+ self.assertEqual([(1,)], list(cur))
1366
+
1367
+ r = cur.nextset()
1368
+ self.assertTrue(r)
1369
+
1370
+ self.assertEqual([(2,)], list(cur))
1371
+ self.assertIsNone(cur.nextset())
1372
+
1373
+ def test_connect_timeout(self):
1374
+ with s2.connect(database=type(self).dbname, connect_timeout=8) as conn:
1513
1375
  with conn.cursor() as cur:
1514
- cur.execute('select * from alltypes')
1515
- out = cur.fetchall()
1516
- assert type(out) is pd.DataFrame, type(out)
1517
- assert list(out.columns) == columns, out.columns
1376
+ cur.execute('SELECT 1')
1377
+ self.assertEqual([(1,)], list(cur))
1378
+
1379
+ def test_show_accessors(self):
1380
+ out = self.conn.show.columns('data')
1381
+ assert out.columns == [
1382
+ 'Name', 'Type', 'Null',
1383
+ 'Key', 'Default', 'Extra',
1384
+ ], out.columns
1385
+ assert out.Name == ['id', 'name', 'value'], out.Name
1386
+ assert out.Type == ['varchar(255)', 'varchar(255)', 'bigint(20)'], out.Type
1387
+ assert str(out).count('varchar(255)') == 2, out
1388
+
1389
+ html = out._repr_html_()
1390
+ assert html.count('varchar(255)') == 2
1391
+ assert html.count('bigint(20)') == 1
1392
+ assert '<table' in html
1393
+
1394
+ out = self.conn.show.tables()
1395
+ assert out.columns == ['Name'], out.columns
1396
+ assert 'data' in out.Name, out.Name
1397
+ assert 'alltypes' in out.Name, out.Name
1398
+
1399
+ out = self.conn.show.warnings()
1400
+
1401
+ out = self.conn.show.errors()
1402
+
1403
+ out = self.conn.show.databases()
1404
+ assert out.columns == ['Name'], out.columns
1405
+ assert 'information_schema' in out.Name
1406
+
1407
+ out = self.conn.show.database_status()
1408
+ assert out.columns == ['Name', 'Value'], out.columns
1409
+ assert 'database' in out.Name
1410
+
1411
+ out = self.conn.show.global_status()
1412
+ assert out.columns == ['Name', 'Value'], out.columns
1413
+
1414
+ out = self.conn.show.indexes('data')
1415
+ assert 'Name' in out.columns, out.columns
1416
+ assert 'KeyName' in out.columns, out.columns
1417
+ assert out.Name == ['data'], out.Name
1418
+
1419
+ out = self.conn.show.functions()
1420
+
1421
+ out = self.conn.show.partitions()
1422
+ assert 'Name' in out.columns, out.columns
1423
+ assert 'Role' in out.columns, out.columns
1424
+
1425
+ out = self.conn.show.pipelines()
1426
+
1427
+ # out = self.conn.show.plan(1)
1428
+
1429
+ # out = self.conn.show.plancache()
1430
+
1431
+ out = self.conn.show.processlist()
1432
+ assert 'Name' in out.columns, out.columns
1433
+ assert 'Command' in out.columns, out.columns
1434
+
1435
+ # out = self.conn.show.reproduction()
1436
+
1437
+ out = self.conn.show.schemas()
1438
+ assert out.columns == ['Name'], out.columns
1439
+ assert 'information_schema' in out.Name
1440
+
1441
+ out = self.conn.show.session_status()
1442
+ assert out.columns == ['Name', 'Value']
1443
+
1444
+ out = self.conn.show.status()
1445
+ assert out.columns == ['Name', 'Value']
1446
+
1447
+ out = self.conn.show.table_status()
1448
+ assert 'Name' in out.columns, out.columns
1449
+ assert 'alltypes' in out.Name, out.Name
1450
+ assert 'data' in out.Name, out.Name
1451
+
1452
+ out = self.conn.show.procedures()
1453
+
1454
+ out = self.conn.show.aggregates()
1455
+
1456
+ # out = self.conn.show.create_aggregate('aname')
1457
+
1458
+ # out = self.conn.show.create_function('fname')
1459
+
1460
+ # out = self.conn.show.create_pipeline('pname')
1461
+
1462
+ out = self.conn.show.create_table('data')
1463
+ assert 'Name' in out.columns, out.columns
1464
+ assert 'CreateTable' in out.columns, out.columns
1465
+ assert '`id` varchar(255)' in out.CreateTable[0], out.CreateTable[0]
1466
+ assert '`name` varchar(255)' in out.CreateTable[0], out.CreateTable[0]
1467
+ assert '`value` bigint(20)' in out.CreateTable[0], out.CreateTable[0]
1468
+
1469
+ # out = self.conn.show.create_view('vname')
1518
1470
 
1519
1471
 
1520
1472
  if __name__ == '__main__':