29
29
QgsField ,
30
30
QgsAbstractDatabaseProviderConnection ,
31
31
QgsProviderConnectionException ,
32
+ QgsFeature ,
33
+ QgsGeometry ,
32
34
)
33
35
from qgis .PyQt import QtCore
34
36
from qgis .PyQt .QtTest import QSignalSpy
@@ -88,59 +90,94 @@ def _test_operations(self, md, conn):
88
90
# Schema operations
89
91
if (capabilities & QgsAbstractDatabaseProviderConnection .CreateSchema and
90
92
capabilities & QgsAbstractDatabaseProviderConnection .Schemas and
91
- capabilities & QgsAbstractDatabaseProviderConnection .RenameSchema and
92
93
capabilities & QgsAbstractDatabaseProviderConnection .DropSchema ):
93
- if capabilities & QgsAbstractDatabaseProviderConnection .DropSchema and 'myNewSchema' in conn .schemas ():
94
+
95
+ # Start clean
96
+ if 'myNewSchema' in conn .schemas ():
94
97
conn .dropSchema ('myNewSchema' , True )
98
+
95
99
# Create
96
100
conn .createSchema ('myNewSchema' )
97
101
schemas = conn .schemas ()
98
102
self .assertTrue ('myNewSchema' in schemas )
103
+
99
104
# Create again
100
105
with self .assertRaises (QgsProviderConnectionException ) as ex :
101
106
conn .createSchema ('myNewSchema' )
102
- # Rename
103
- conn .renameSchema ('myNewSchema' , 'myVeryNewSchema' )
107
+
108
+ # Test rename
109
+ if capabilities & QgsAbstractDatabaseProviderConnection .RenameSchema :
110
+ # Rename
111
+ conn .renameSchema ('myNewSchema' , 'myVeryNewSchema' )
112
+ schemas = conn .schemas ()
113
+ self .assertTrue ('myVeryNewSchema' in schemas )
114
+ self .assertFalse ('myNewSchema' in schemas )
115
+ conn .renameSchema ('myVeryNewSchema' , 'myNewSchema' )
116
+ schemas = conn .schemas ()
117
+ self .assertFalse ('myVeryNewSchema' in schemas )
118
+ self .assertTrue ('myNewSchema' in schemas )
119
+
120
+ # Drop
121
+ conn .dropSchema ('myNewSchema' )
104
122
schemas = conn .schemas ()
105
- self .assertTrue ('myVeryNewSchema' in schemas )
106
123
self .assertFalse ('myNewSchema' in schemas )
107
- # Drop
108
- conn .dropSchema ('myVeryNewSchema' )
124
+
125
+ #UTF8 schema
126
+ conn .createSchema ('myUtf8\U0001f604 NewSchema' )
127
+ schemas = conn .schemas ()
128
+ conn .dropSchema ('myUtf8\U0001f604 NewSchema' )
109
129
schemas = conn .schemas ()
110
- self .assertFalse ('myVeryNewSchema ' in schemas )
130
+ self .assertFalse ('myUtf8 \U0001f604 NewSchema ' in schemas )
111
131
112
132
# Table operations
113
133
if (capabilities & QgsAbstractDatabaseProviderConnection .CreateVectorTable and
114
134
capabilities & QgsAbstractDatabaseProviderConnection .Tables and
115
- capabilities & QgsAbstractDatabaseProviderConnection .RenameVectorTable and
116
135
capabilities & QgsAbstractDatabaseProviderConnection .DropVectorTable ):
117
136
118
- if capabilities & QgsAbstractDatabaseProviderConnection .DropSchema and 'myNewSchema' in conn .schemas ():
119
- conn .dropSchema ('myNewSchema' , True )
120
137
if capabilities & QgsAbstractDatabaseProviderConnection .CreateSchema :
121
138
schema = 'myNewSchema'
122
139
conn .createSchema ('myNewSchema' )
123
140
else :
124
141
schema = 'public'
125
142
143
+ # Start clean
126
144
if 'myNewTable' in self ._table_names (conn .tables (schema )):
127
145
conn .dropVectorTable (schema , 'myNewTable' )
146
+
128
147
fields = QgsFields ()
129
- fields .append (QgsField ("string " , QVariant .String ))
130
- fields .append (QgsField ("long " , QVariant .LongLong ))
131
- fields .append (QgsField ("double " , QVariant .Double ))
132
- fields .append (QgsField ("integer " , QVariant .Int ))
133
- fields .append (QgsField ("date " , QVariant .Date ))
134
- fields .append (QgsField ("datetime " , QVariant .DateTime ))
135
- fields .append (QgsField ("time " , QVariant .Time ))
148
+ fields .append (QgsField ("string_t " , QVariant .String ))
149
+ fields .append (QgsField ("long_t " , QVariant .LongLong ))
150
+ fields .append (QgsField ("double_t " , QVariant .Double ))
151
+ fields .append (QgsField ("integer_t " , QVariant .Int ))
152
+ fields .append (QgsField ("date_t " , QVariant .Date ))
153
+ fields .append (QgsField ("datetime_t " , QVariant .DateTime ))
154
+ fields .append (QgsField ("time_t " , QVariant .Time ))
136
155
options = {}
137
156
crs = QgsCoordinateReferenceSystem .fromEpsgId (3857 )
138
157
typ = QgsWkbTypes .LineString
158
+
139
159
# Create
140
160
conn .createVectorTable (schema , 'myNewTable' , fields , typ , crs , True , options )
141
161
table_names = self ._table_names (conn .tables (schema ))
142
162
self .assertTrue ('myNewTable' in table_names )
143
163
164
+ # Create UTF8 table
165
+ conn .createVectorTable (schema , 'myUtf8\U0001f604 Table' , fields , typ , crs , True , options )
166
+ table_names = self ._table_names (conn .tables (schema ))
167
+ self .assertTrue ('myNewTable' in table_names )
168
+ self .assertTrue ('myUtf8\U0001f604 Table' in table_names )
169
+ conn .dropVectorTable (schema , 'myUtf8\U0001f604 Table' )
170
+ table_names = self ._table_names (conn .tables (schema ))
171
+ self .assertFalse ('myUtf8\U0001f604 Table' in table_names )
172
+ self .assertTrue ('myNewTable' in table_names )
173
+
174
+ # insert something, because otherwise MSSQL cannot guess
175
+ if self .providerKey == 'mssql' :
176
+ f = QgsFeature (fields )
177
+ f .setGeometry (QgsGeometry .fromWkt ('LineString (-72.345 71.987, -80 80)' ))
178
+ vl = QgsVectorLayer (conn .tableUri ('myNewSchema' , 'myNewTable' ), 'vl' , 'mssql' )
179
+ vl .dataProvider ().addFeatures ([f ])
180
+
144
181
# Check table information
145
182
table_properties = conn .tables (schema )
146
183
table_property = self ._table_by_name (table_properties , 'myNewTable' )
@@ -164,8 +201,7 @@ def _test_operations(self, md, conn):
164
201
self .assertEqual (table_property .geometryColumn (), '' )
165
202
self .assertEqual (table_property .defaultName (), 'myNewAspatialTable' )
166
203
cols = table_property .geometryColumnTypes ()
167
- self .assertEqual (cols [0 ].wkbType , QgsWkbTypes .NoGeometry )
168
- self .assertFalse (cols [0 ].crs .isValid ())
204
+ self .assertEqual (cols , [])
169
205
self .assertFalse (table_property .flags () & QgsAbstractDatabaseProviderConnection .Raster )
170
206
self .assertFalse (table_property .flags () & QgsAbstractDatabaseProviderConnection .Vector )
171
207
self .assertTrue (table_property .flags () & QgsAbstractDatabaseProviderConnection .Aspatial )
@@ -177,23 +213,30 @@ def _test_operations(self, md, conn):
177
213
table = "\" %s\" .\" myNewAspatialTable\" " % schema
178
214
else :
179
215
table = 'myNewAspatialTable'
180
- sql = "INSERT INTO %s (string, long, double, integer, date, datetime, time) VALUES ('QGIS Rocks - \U0001f604 ', 666, 1.234, 1234, '2019-07-08', '2019-07-08T12:00:12', '12:00:13.00')" % table
216
+
217
+ # MSSQL literal syntax for UTF8 requires 'N' prefix
218
+ sql = "INSERT INTO %s (string_t, long_t, double_t, integer_t, date_t, datetime_t, time_t) VALUES (%s'QGIS Rocks - \U0001f604 ', 666, 1.234, 1234, '2019-07-08', '2019-07-08T12:00:12', '12:00:13.00')" % (table , 'N' if self .providerKey == 'mssql' else '' )
181
219
res = conn .executeSql (sql )
182
220
self .assertEqual (res , [])
183
- sql = "SELECT string, long, double, integer, date, datetime FROM %s" % table
221
+ sql = "SELECT string_t, long_t, double_t, integer_t, date_t, datetime_t FROM %s" % table
184
222
res = conn .executeSql (sql )
185
223
# GPKG has no type for time and spatialite has no support for dates and time ...
186
224
if self .providerKey == 'spatialite' :
187
225
self .assertEqual (res , [['QGIS Rocks - \U0001f604 ' , 666 , 1.234 , 1234 , '2019-07-08' , '2019-07-08T12:00:12' ]])
188
226
else :
189
227
self .assertEqual (res , [['QGIS Rocks - \U0001f604 ' , 666 , 1.234 , 1234 , QtCore .QDate (2019 , 7 , 8 ), QtCore .QDateTime (2019 , 7 , 8 , 12 , 0 , 12 )]])
190
- sql = "SELECT time FROM %s" % table
228
+ sql = "SELECT time_t FROM %s" % table
191
229
res = conn .executeSql (sql )
192
- self .assertIn (res , ([[QtCore .QTime (12 , 0 , 13 )]], [['12:00:13.00' ]]))
193
- sql = "DELETE FROM %s WHERE string = 'QGIS Rocks - \U0001f604 '" % table
230
+
231
+ # This does not work in MSSQL and returns a QByteArray, we have no way to know that it is a time
232
+ # value and there is no way we can convert it.
233
+ if self .providerKey != 'mssql' :
234
+ self .assertIn (res , ([[QtCore .QTime (12 , 0 , 13 )]], [['12:00:13.00' ]]))
235
+
236
+ sql = "DELETE FROM %s WHERE string_t = %s'QGIS Rocks - \U0001f604 '" % (table , 'N' if self .providerKey == 'mssql' else '' )
194
237
res = conn .executeSql (sql )
195
238
self .assertEqual (res , [])
196
- sql = "SELECT string, integer FROM %s" % table
239
+ sql = "SELECT string_t, integer_t FROM %s" % table
197
240
res = conn .executeSql (sql )
198
241
self .assertEqual (res , [])
199
242
@@ -203,7 +246,7 @@ def _test_operations(self, md, conn):
203
246
self .assertFalse ('myNewAspatialTable' in table_names )
204
247
205
248
# Query for rasters (in qgis_test schema or no schema for GPKG, spatialite has no support)
206
- if self .providerKey != 'spatialite' :
249
+ if self .providerKey not in ( 'spatialite' , 'mssql' ) :
207
250
table_properties = conn .tables ('qgis_test' , QgsAbstractDatabaseProviderConnection .Raster )
208
251
# At least one raster should be there (except for spatialite)
209
252
self .assertTrue (len (table_properties ) >= 1 )
@@ -212,22 +255,29 @@ def _test_operations(self, md, conn):
212
255
self .assertFalse (table_property .flags () & QgsAbstractDatabaseProviderConnection .Vector )
213
256
self .assertFalse (table_property .flags () & QgsAbstractDatabaseProviderConnection .Aspatial )
214
257
215
- # Rename
216
- conn .renameVectorTable (schema , 'myNewTable' , 'myVeryNewTable' )
217
- tables = self ._table_names (conn .tables (schema ))
218
- self .assertFalse ('myNewTable' in tables )
219
- self .assertTrue ('myVeryNewTable' in tables )
258
+ if capabilities & QgsAbstractDatabaseProviderConnection .RenameVectorTable :
259
+ # Rename
260
+ conn .renameVectorTable (schema , 'myNewTable' , 'myVeryNewTable' )
261
+ tables = self ._table_names (conn .tables (schema ))
262
+ self .assertFalse ('myNewTable' in tables )
263
+ self .assertTrue ('myVeryNewTable' in tables )
264
+ # Rename it back
265
+ conn .renameVectorTable (schema , 'myVeryNewTable' , 'myNewTable' )
266
+ tables = self ._table_names (conn .tables (schema ))
267
+ self .assertTrue ('myNewTable' in tables )
268
+ self .assertFalse ('myVeryNewTable' in tables )
269
+
220
270
# Vacuum
221
271
if capabilities & QgsAbstractDatabaseProviderConnection .Vacuum :
222
- conn .vacuum ('myNewSchema' , 'myVeryNewTable ' )
272
+ conn .vacuum ('myNewSchema' , 'myNewTable ' )
223
273
224
274
if capabilities & QgsAbstractDatabaseProviderConnection .DropSchema :
225
275
# Drop schema (should fail)
226
276
with self .assertRaises (QgsProviderConnectionException ) as ex :
227
277
conn .dropSchema ('myNewSchema' )
228
278
229
279
# Check some column types operations
230
- table = self ._table_by_name (conn .tables (schema ), 'myVeryNewTable ' )
280
+ table = self ._table_by_name (conn .tables (schema ), 'myNewTable ' )
231
281
self .assertEqual (len (table .geometryColumnTypes ()), 1 )
232
282
ct = table .geometryColumnTypes ()[0 ]
233
283
self .assertEqual (ct .crs , QgsCoordinateReferenceSystem .fromEpsgId (3857 ))
@@ -249,10 +299,10 @@ def _test_operations(self, md, conn):
249
299
self .assertEqual (ct .wkbType , QgsWkbTypes .LineString )
250
300
251
301
# Drop table
252
- conn .dropVectorTable (schema , 'myVeryNewTable ' )
302
+ conn .dropVectorTable (schema , 'myNewTable ' )
253
303
conn .dropVectorTable (schema , 'myNewAspatialTable' )
254
304
table_names = self ._table_names (conn .tables (schema ))
255
- self .assertFalse ('myVeryNewTable ' in table_names )
305
+ self .assertFalse ('myNewTable ' in table_names )
256
306
257
307
if capabilities & QgsAbstractDatabaseProviderConnection .DropSchema :
258
308
# Drop schema
0 commit comments