Skip to content

Commit 49e4567

Browse files
committed
Correct handling of date and time values in mssql provider
1 parent 78d9617 commit 49e4567

7 files changed

+81
-10
lines changed

src/providers/mssql/qgsmssqlfeatureiterator.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,10 @@ bool QgsMssqlFeatureIterator::fetchFeature( QgsFeature& feature )
284284
for ( int i = 0; i < mAttributesToFetch.count(); i++ )
285285
{
286286
QVariant v = mQuery->value( i );
287-
feature.setAttribute( mAttributesToFetch[i], mQuery->value( i ) );
287+
const QgsField &fld = mSource->mFields.at( i );
288+
if ( v.type() != fld.type() )
289+
v = QgsVectorDataProvider::convertValue( fld.type(), v.toString() );
290+
feature.setAttribute( mAttributesToFetch.at( i ), v );
288291
}
289292

290293
feature.setFeatureId( mQuery->record().value( mSource->mFidColName ).toLongLong() );

src/providers/mssql/qgsmssqlprovider.cpp

+31-2
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ QgsMssqlProvider::QgsMssqlProvider( const QString& uri )
160160
<< QgsVectorDataProvider::NativeType( tr( "Decimal number (real)" ), "real", QVariant::Double )
161161
<< QgsVectorDataProvider::NativeType( tr( "Decimal number (double)" ), "float", QVariant::Double )
162162

163+
// date/time types
164+
<< QgsVectorDataProvider::NativeType( tr( "Date" ), "date", QVariant::Date, -1, -1, -1, -1 )
165+
<< QgsVectorDataProvider::NativeType( tr( "Time" ), "time", QVariant::Time, -1, -1, -1, -1 )
166+
<< QgsVectorDataProvider::NativeType( tr( "Date & Time" ), "datetime", QVariant::DateTime, -1, -1, -1, -1 )
167+
163168
// string types
164169
<< QgsVectorDataProvider::NativeType( tr( "Text, fixed length (char)" ), "char", QVariant::String, 1, 255 )
165170
<< QgsVectorDataProvider::NativeType( tr( "Text, limited variable length (varchar)" ), "varchar", QVariant::String, 1, 255 )
@@ -321,11 +326,14 @@ QVariant::Type QgsMssqlProvider::DecodeSqlType( const QString& sqlTypeName )
321326
{
322327
type = QVariant::Date;
323328
}
324-
else if ( sqlTypeName.startsWith( "time", Qt::CaseInsensitive ) ||
325-
sqlTypeName.startsWith( "timestamp", Qt::CaseInsensitive ) )
329+
else if ( sqlTypeName.startsWith( "timestamp", Qt::CaseInsensitive ) )
326330
{
327331
type = QVariant::String;
328332
}
333+
else if ( sqlTypeName.startsWith( "time", Qt::CaseInsensitive ) )
334+
{
335+
type = QVariant::Time;
336+
}
329337
else
330338
{
331339
QgsDebugMsg( QString( "Unknown field type: %1" ).arg( sqlTypeName ) );
@@ -408,6 +416,15 @@ void QgsMssqlProvider::loadFields()
408416
query.value( 7 ).toInt(),
409417
query.value( 8 ).toInt() ) );
410418
}
419+
else if ( sqlType == QVariant::Date || sqlType == QVariant::DateTime || sqlType == QVariant::Time )
420+
{
421+
mAttributeFields.append(
422+
QgsField(
423+
query.value( 3 ).toString(), sqlType,
424+
sqlTypeName,
425+
-1,
426+
-1 ) );
427+
}
411428
else
412429
{
413430
mAttributeFields.append(
@@ -1455,8 +1472,20 @@ bool QgsMssqlProvider::convertField( QgsField &field )
14551472
break;
14561473

14571474
case QVariant::DateTime:
1475+
fieldType = "datetime";
1476+
fieldPrec = -1;
1477+
break;
1478+
14581479
case QVariant::Date:
1480+
fieldType = "date";
1481+
fieldPrec = -1;
1482+
break;
1483+
14591484
case QVariant::Time:
1485+
fieldType = "time";
1486+
fieldPrec = -1;
1487+
break;
1488+
14601489
case QVariant::String:
14611490
fieldType = "nvarchar(max)";
14621491
fieldPrec = -1;

tests/src/python/test_provider_mssql.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from qgis.core import NULL
1919

2020
from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsProviderRegistry
21-
from PyQt4.QtCore import QSettings
21+
from PyQt4.QtCore import QSettings, QDate, QTime, QDateTime, QVariant
2222
from utilities import (unitTestDataPath,
2323
getQgisTestApp,
2424
unittest,
@@ -53,5 +53,27 @@ def enableCompiler(self):
5353
def disableCompiler(self):
5454
QSettings().setValue(u'/qgis/compileExpressions', False)
5555

56+
# HERE GO THE PROVIDER SPECIFIC TESTS
57+
def testDateTimeTypes(self):
58+
vl = QgsVectorLayer('%s table="qgis_test"."date_times" sql=' % (self.dbconn), "testdatetimes", "mssql")
59+
assert(vl.isValid())
60+
61+
fields = vl.dataProvider().fields()
62+
self.assertEqual(fields.at(fields.indexFromName('date_field')).type(), QVariant.Date)
63+
self.assertEqual(fields.at(fields.indexFromName('time_field')).type(), QVariant.Time)
64+
self.assertEqual(fields.at(fields.indexFromName('datetime_field')).type(), QVariant.DateTime)
65+
66+
f = vl.getFeatures(QgsFeatureRequest()).next()
67+
68+
date_idx = vl.fieldNameIndex('date_field')
69+
assert isinstance(f.attributes()[date_idx], QDate)
70+
self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
71+
time_idx = vl.fieldNameIndex('time_field')
72+
assert isinstance(f.attributes()[time_idx], QTime)
73+
self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52))
74+
datetime_idx = vl.fieldNameIndex('datetime_field')
75+
assert isinstance(f.attributes()[datetime_idx], QDateTime)
76+
self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)))
77+
5678
if __name__ == '__main__':
5779
unittest.main()

tests/src/python/test_provider_postgres.py

+3
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,13 @@ def testDateTimeTypes(self):
7272

7373
date_idx = vl.fieldNameIndex('date_field')
7474
assert isinstance(f.attributes()[date_idx], QDate)
75+
self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
7576
time_idx = vl.fieldNameIndex('time_field')
7677
assert isinstance(f.attributes()[time_idx], QTime)
78+
self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52))
7779
datetime_idx = vl.fieldNameIndex('datetime_field')
7880
assert isinstance(f.attributes()[datetime_idx], QDateTime)
81+
self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)))
7982

8083
def testQueryLayers(self):
8184
def test_query(dbconn, query, key):

tests/src/python/test_provider_tabfile.py

+3
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ def testDateTimeFormats(self):
4747

4848
date_idx = vl.fieldNameIndex('date')
4949
assert isinstance(f.attributes()[date_idx], QDate)
50+
self.assertEqual(f.attributes()[date_idx], QDate(2004, 5, 3))
5051
time_idx = vl.fieldNameIndex('time')
5152
assert isinstance(f.attributes()[time_idx], QTime)
53+
self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 00))
5254
datetime_idx = vl.fieldNameIndex('date_time')
5355
assert isinstance(f.attributes()[datetime_idx], QDateTime)
56+
self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2004, 5, 3), QTime(13, 41, 00)))
5457

5558
if __name__ == '__main__':
5659
unittest.main()

tests/src/python/test_qgsvectorfilewriter.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def testDateTimeWriteShapefile(self):
7272

7373
ft = QgsFeature()
7474
ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
75-
ft.setAttributes([1, QDate(2014, 0o3, 0o5), QTime(13, 45, 22), QDateTime(QDate(2014, 0o3, 0o5), QTime(13, 45, 22))])
75+
ft.setAttributes([1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))])
7676
res, features = provider.addFeatures([ft])
7777
assert res
7878
assert len(features) > 0
@@ -103,15 +103,15 @@ def testDateTimeWriteShapefile(self):
103103

104104
date_idx = created_layer.fieldNameIndex('date_f')
105105
assert isinstance(f.attributes()[date_idx], QDate)
106-
self.assertEqual(f.attributes()[date_idx], QDate(2014, 0o3, 0o5))
106+
self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5))
107107
time_idx = created_layer.fieldNameIndex('time_f')
108108
#shapefiles do not support time types
109109
assert isinstance(f.attributes()[time_idx], basestring)
110110
self.assertEqual(f.attributes()[time_idx], '13:45:22')
111111
#shapefiles do not support datetime types
112112
datetime_idx = created_layer.fieldNameIndex('dt_f')
113113
assert isinstance(f.attributes()[datetime_idx], QDate)
114-
self.assertEqual(f.attributes()[datetime_idx], QDate(2014, 0o3, 0o5))
114+
self.assertEqual(f.attributes()[datetime_idx], QDate(2014, 3, 5))
115115

116116
def testDateTimeWriteTabfile(self):
117117
"""Check writing date and time fields to an MapInfo tabfile."""
@@ -128,7 +128,7 @@ def testDateTimeWriteTabfile(self):
128128

129129
ft = QgsFeature()
130130
ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
131-
ft.setAttributes([1, QDate(2014, 0o3, 0o5), QTime(13, 45, 22), QDateTime(QDate(2014, 0o3, 0o5), QTime(13, 45, 22))])
131+
ft.setAttributes([1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))])
132132
res, features = provider.addFeatures([ft])
133133
assert res
134134
assert len(features) > 0
@@ -157,13 +157,13 @@ def testDateTimeWriteTabfile(self):
157157

158158
date_idx = created_layer.fieldNameIndex('date_f')
159159
assert isinstance(f.attributes()[date_idx], QDate)
160-
self.assertEqual(f.attributes()[date_idx], QDate(2014, 0o3, 0o5))
160+
self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5))
161161
time_idx = created_layer.fieldNameIndex('time_f')
162162
assert isinstance(f.attributes()[time_idx], QTime)
163163
self.assertEqual(f.attributes()[time_idx], QTime(13, 45, 22))
164164
datetime_idx = created_layer.fieldNameIndex('dt_f')
165165
assert isinstance(f.attributes()[datetime_idx], QDateTime)
166-
self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 0o3, 0o5), QTime(13, 45, 22)))
166+
self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)))
167167

168168
if __name__ == '__main__':
169169
unittest.main()

tests/testdata/provider/testdata_mssql.sql

+11
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,21 @@ CREATE TABLE qgis_test.[someData] (
88
geom geometry
99
)
1010

11+
CREATE TABLE qgis_test.[date_times] (
12+
id integer PRIMARY KEY,
13+
date_field date,
14+
time_field time,
15+
datetime_field datetime
16+
);
17+
18+
1119
INSERT INTO qgis_test.[someData] (pk, cnt, name, name2, geom) VALUES
1220
(5, -200, NULL, 'NuLl', geometry::STGeomFromText( 'Point(-71.123 78.23)', 4326 )),
1321
(3, 300, 'Pear', 'PEaR', NULL),
1422
(1, 100, 'Orange', 'oranGe', geometry::STGeomFromText( 'Point(-70.332 66.33)', 4326 )),
1523
(2, 200, 'Apple', 'Apple', geometry::STGeomFromText( 'Point(-68.2 70.8)', 4326 )),
1624
(4, 400, 'Honey', 'Honey', geometry::STGeomFromText( 'Point(-65.32 78.3)', 4326 ))
1725
;
26+
27+
INSERT INTO qgis_test.[date_times] (id, date_field, time_field, datetime_field ) VALUES
28+
(1, '2004-03-04', '13:41:52', '2004-03-04 13:41:52' );

0 commit comments

Comments
 (0)