Skip to content

Commit

Permalink
[FEATURE] Binary (blob) field support for memory layers
Browse files Browse the repository at this point in the history
Allows storage of binary blob fields in memory layers
  • Loading branch information
nyalldawson committed Nov 12, 2018
1 parent d96ce7a commit 429320d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
13 changes: 12 additions & 1 deletion src/core/providers/memory/qgsmemoryprovider.cpp
Expand Up @@ -93,13 +93,17 @@ QgsMemoryProvider::QgsMemoryProvider( const QString &uri, const ProviderOptions

// string types
<< QgsVectorDataProvider::NativeType( tr( "Text, unlimited length (text)" ), QStringLiteral( "text" ), QVariant::String, -1, -1, -1, -1 )

// blob
<< QgsVectorDataProvider::NativeType( tr( "Binary object (BLOB)" ), QStringLiteral( "binary" ), QVariant::ByteArray )

);

if ( url.hasQueryItem( QStringLiteral( "field" ) ) )
{
QList<QgsField> attributes;
QRegExp reFieldDef( "\\:"
"(int|integer|long|int8|real|double|string|date|time|datetime)" // type
"(int|integer|long|int8|real|double|string|date|time|datetime|binary)" // type
"(?:\\((\\-?\\d+)" // length
"(?:\\,(\\d+))?" // precision
"\\))?(\\[\\])?" // array
Expand Down Expand Up @@ -156,6 +160,12 @@ QgsMemoryProvider::QgsMemoryProvider( const QString &uri, const ProviderOptions
typeName = QStringLiteral( "datetime" );
length = -1;
}
else if ( typeName == QLatin1String( "binary" ) )
{
type = QVariant::ByteArray;
typeName = QStringLiteral( "binary" );
length = -1;
}

if ( !reFieldDef.cap( 2 ).isEmpty() )
{
Expand Down Expand Up @@ -443,6 +453,7 @@ bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
case QVariant::LongLong:
case QVariant::StringList:
case QVariant::List:
case QVariant::ByteArray:
break;
default:
QgsDebugMsg( "Field type not supported: " + it->typeName() );
Expand Down
3 changes: 3 additions & 0 deletions src/core/providers/memory/qgsmemoryproviderutils.cpp
Expand Up @@ -44,6 +44,9 @@ QString memoryLayerFieldType( QVariant::Type type )
case QVariant::DateTime:
return QStringLiteral( "datetime" );

case QVariant::ByteArray:
return QStringLiteral( "binary" );

default:
break;
}
Expand Down
43 changes: 42 additions & 1 deletion tests/src/python/test_provider_memory.py
Expand Up @@ -42,7 +42,7 @@
)

from providertestbase import ProviderTestCase
from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtCore import QVariant, QByteArray

start_app()
TEST_DATA_DIR = unitTestDataPath()
Expand Down Expand Up @@ -410,6 +410,7 @@ def testCreateMemoryLayer(self):
fields.append(QgsField("time", QVariant.Time))
fields.append(QgsField("#complex_name", QVariant.String))
fields.append(QgsField("complex/name", QVariant.String))
fields.append(QgsField("binaryfield", QVariant.ByteArray))
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
Expand Down Expand Up @@ -509,6 +510,46 @@ def testMinMaxCache(self):
self.assertEqual(vl.dataProvider().minimumValue(0), -100)
self.assertEqual(vl.dataProvider().maximumValue(0), 400)

def testBinary(self):
vl = QgsVectorLayer(
'Point?crs=epsg:4326&field=f1:integer&field=f2:binary',
'test', 'memory')
self.assertTrue(vl.isValid())

dp = vl.dataProvider()
fields = dp.fields()
self.assertEqual([f.name() for f in fields], ['f1', 'f2'])
self.assertEqual([f.type() for f in fields], [QVariant.Int, QVariant.ByteArray])
self.assertEqual([f.typeName() for f in fields], ['integer', 'binary'])

f = QgsFeature(dp.fields())
bin_1 = b'xxx'
bin_val1 = QByteArray(bin_1)
f.setAttributes([1, bin_val1])
self.assertTrue(dp.addFeature(f))

f2 = [f for f in dp.getFeatures()][0]
self.assertEqual(f2.attributes(), [1, bin_val1])

# add binary field
self.assertTrue(dp.addAttributes([QgsField('binfield2', QVariant.ByteArray, 'Binary')]))

fields = dp.fields()
bin2_field = fields[fields.lookupField('binfield2')]
self.assertEqual(bin2_field.type(), QVariant.ByteArray)
self.assertEqual(bin2_field.typeName(), 'Binary')

f = QgsFeature(fields)
bin_2 = b'yyy'
bin_val2 = QByteArray(bin_2)
f.setAttributes([2, NULL, bin_val2])
self.assertTrue(dp.addFeature(f))

f1 = [f for f in dp.getFeatures()][0]
self.assertEqual(f1.attributes(), [1, bin_val1, NULL])
f2 = [f for f in dp.getFeatures()][1]
self.assertEqual(f2.attributes(), [2, NULL, bin_val2])


class TestPyQgsMemoryProviderIndexed(unittest.TestCase, ProviderTestCase):

Expand Down

0 comments on commit 429320d

Please sign in to comment.