@@ -20,6 +20,7 @@ email : hugo dot mercier at oslandia dot com
20
20
#include < stdexcept>
21
21
22
22
#include < QCoreApplication>
23
+ #include < QBuffer>
23
24
24
25
#include < qgsapplication.h>
25
26
#include < qgsvectorlayer.h>
@@ -636,6 +637,178 @@ void module_destroy( void* )
636
637
}
637
638
}
638
639
640
+ // the expression context used for calling qgis functions
641
+ QgsExpressionContext qgisFunctionExpressionContext;
642
+
643
+ void qgisFunctionWrapper ( sqlite3_context* ctxt, int nArgs, sqlite3_value** args )
644
+ {
645
+ // convert from sqlite3 value to QVariant and then call the qgis expression function
646
+ // the 3 basic sqlite3 types (int, float, text) are converted to their QVariant equivalent
647
+ // Expression::Interval is handled specifically
648
+ // geometries are converted between spatialite and QgsGeometry
649
+ // other data types (datetime mainly) are represented as BLOBs thanks to QVariant serializing functions
650
+
651
+ QgsExpression::Function* foo = reinterpret_cast <QgsExpression::Function*>( sqlite3_user_data ( ctxt ) );
652
+
653
+ QVariantList variants;
654
+ for ( int i = 0 ; i < nArgs; i++ )
655
+ {
656
+ int t = sqlite3_value_type ( args[i] );
657
+ switch ( t )
658
+ {
659
+ case SQLITE_INTEGER:
660
+ variants << QVariant ( sqlite3_value_int64 ( args[i] ) );
661
+ break ;
662
+ case SQLITE_FLOAT:
663
+ variants << QVariant ( sqlite3_value_double ( args[i] ) );
664
+ break ;
665
+ case SQLITE_TEXT:
666
+ {
667
+ int n = sqlite3_value_bytes ( args[i] );
668
+ const char * t = reinterpret_cast <const char *>( sqlite3_value_text ( args[i] ) );
669
+ QString str ( QByteArray::fromRawData ( t, n ) ); // don't copy data
670
+ variants << QVariant ( str );
671
+ break ;
672
+ }
673
+ case SQLITE_BLOB:
674
+ {
675
+ int n = sqlite3_value_bytes ( args[i] );
676
+ const char * blob = reinterpret_cast <const char *>( sqlite3_value_blob ( args[i] ) );
677
+ // spatialite blobs start with a 0 byte
678
+ if ( n > 0 && blob[0 ] == 0 )
679
+ {
680
+ QgsGeometry geom = spatialiteBlobToQgsGeometry ( blob, n );
681
+ variants << QVariant::fromValue ( geom );
682
+ }
683
+ else
684
+ {
685
+ // else it is another type
686
+ QByteArray ba = QByteArray::fromRawData ( blob + 1 , n - 1 );
687
+ QBuffer buffer ( &ba );
688
+ buffer.open ( QIODevice::ReadOnly );
689
+ QDataStream ds ( &buffer );
690
+ QVariant v;
691
+ ds >> v;
692
+ buffer.close ();
693
+ variants << v;
694
+ }
695
+ break ;
696
+ }
697
+ default :
698
+ variants << QVariant (); // null
699
+ break ;
700
+ };
701
+ }
702
+
703
+ QgsExpression parentExpr ( " " );
704
+ QVariant ret = foo->func ( variants, &qgisFunctionExpressionContext, &parentExpr );
705
+ if ( parentExpr.hasEvalError () )
706
+ {
707
+ QByteArray ba = parentExpr.evalErrorString ().toUtf8 ();
708
+ sqlite3_result_error ( ctxt, ba.constData (), ba.size () );
709
+ return ;
710
+ }
711
+
712
+ if ( ret.isNull () )
713
+ {
714
+ sqlite3_result_null ( ctxt );
715
+ return ;
716
+ }
717
+
718
+ switch ( ret.type () )
719
+ {
720
+ case QVariant::Bool:
721
+ case QVariant::Int:
722
+ case QVariant::UInt:
723
+ case QVariant::LongLong:
724
+ sqlite3_result_int64 ( ctxt, ret.toLongLong () );
725
+ break ;
726
+ case QVariant::Double:
727
+ sqlite3_result_double ( ctxt, ret.toDouble () );
728
+ break ;
729
+ case QVariant::String:
730
+ {
731
+ QByteArray ba ( ret.toByteArray () );
732
+ sqlite3_result_text ( ctxt, ba.constData (), ba.size (), SQLITE_TRANSIENT );
733
+ break ;
734
+ }
735
+ case QVariant::UserType:
736
+ {
737
+ if ( ret.canConvert <QgsGeometry>() )
738
+ {
739
+ char * blob = nullptr ;
740
+ int size = 0 ;
741
+ qgsGeometryToSpatialiteBlob ( ret.value <QgsGeometry>(), /* srid*/ 0 , blob, size );
742
+ sqlite3_result_blob ( ctxt, blob, size, deleteGeometryBlob );
743
+ }
744
+ else if ( ret.canConvert <QgsExpression::Interval>() )
745
+ {
746
+ sqlite3_result_double ( ctxt, ret.value <QgsExpression::Interval>().seconds () );
747
+ }
748
+ break ;
749
+ }
750
+ default :
751
+ {
752
+ QBuffer buffer;
753
+ buffer.open ( QBuffer::ReadWrite );
754
+ QDataStream ds ( &buffer );
755
+ // something different from 0 (to distinguish from the first byte of a geometry blob)
756
+ char type = 1 ;
757
+ buffer.write ( &type, 1 );
758
+ // then the serialized version of the variant
759
+ ds << ret;
760
+ buffer.close ();
761
+ sqlite3_result_blob ( ctxt, buffer.buffer ().constData (), buffer.buffer ().size (), SQLITE_TRANSIENT );
762
+ }
763
+ };
764
+ }
765
+
766
+ void registerQgisFunctions ( sqlite3* db )
767
+ {
768
+ QStringList excludedFunctions;
769
+ excludedFunctions << " min" << " max" << " coalesce" << " get_feature" << " getFeature" << " attribute" ;
770
+ QStringList reservedFunctions;
771
+ reservedFunctions << " left" << " right" << " union" ;
772
+ // register QGIS expression functions
773
+ foreach ( QgsExpression::Function* foo, QgsExpression::Functions () )
774
+ {
775
+ if ( foo->usesgeometry () || foo->lazyEval () )
776
+ {
777
+ // there is no "current" feature here, so calling functions that access "the" geometry does not make sense
778
+ // also, we can't pass Node values for lazy evaluations
779
+ continue ;
780
+ }
781
+ if ( excludedFunctions.contains ( foo->name () ) )
782
+ continue ;
783
+
784
+ QStringList names;
785
+ names << foo->name ();
786
+ names << foo->aliases ();
787
+
788
+ foreach ( QString name, names ) // for each alias
789
+ {
790
+ if ( reservedFunctions.contains ( name ) ) // reserved keyword
791
+ name = " _" + name;
792
+ if ( name.startsWith ( " $" ) )
793
+ continue ;
794
+
795
+ // register the function and pass the pointer to the Function* as user data
796
+ int r = sqlite3_create_function ( db, name.toUtf8 ().constData (), foo->params (), SQLITE_UTF8, foo, qgisFunctionWrapper, nullptr , nullptr );
797
+ if ( r != SQLITE_OK )
798
+ {
799
+ // is it because a function of the same name already exist (in Spatialite for instance ?)
800
+ // we then try to recreate it with a prefix
801
+ name = " qgis_" + name;
802
+ r = sqlite3_create_function ( db, name.toUtf8 ().constData (), foo->params (), SQLITE_UTF8, foo, qgisFunctionWrapper, nullptr , nullptr );
803
+ }
804
+ }
805
+ }
806
+
807
+ // initialize the expression context
808
+ qgisFunctionExpressionContext << QgsExpressionContextUtils::globalScope ();
809
+ qgisFunctionExpressionContext << QgsExpressionContextUtils::projectScope ();
810
+ }
811
+
639
812
int qgsvlayer_module_init ( sqlite3 *db, char **pzErrMsg, void * unused /* const sqlite3_api_routines *pApi*/ )
640
813
{
641
814
Q_UNUSED ( pzErrMsg );
@@ -682,5 +855,7 @@ int qgsvlayer_module_init( sqlite3 *db, char **pzErrMsg, void * unused /*const s
682
855
683
856
sqlite3_create_module_v2 ( db, " QgsVLayer" , &module , nullptr , module_destroy );
684
857
858
+ registerQgisFunctions ( db );
859
+
685
860
return rc;
686
861
}
0 commit comments