[Gambas-user] create custom user functions in SQLITE3 from Gambas
Angel
angelnunez123 at gmail.com
Fri Apr 7 11:09:39 CEST 2023
El 4/4/23 a las 21:29, Benoit Minisini escribió:
> Le 04/04/2023 à 20:51, Angel a écrit :
>> hello
>>
>> I am trying to create custom user functions in SQLITE3 from Gambas
>> but given my ignorance of C it is impossible.
>>
>> Has anyone tried?The function in C is:
>>
>> int sqlite3_create_function(
>> sqlite3 *db,
>> const char *zFunctionName,
>> int nArg,
>> int eTextRep,
>> void *pApp,
>> void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
>> void (*xStep)(sqlite3_context*,int,sqlite3_value**),
>> void (*xFinal)(sqlite3_context*)
>> );
>>
>> The explanation at: https://www.sqlite.org/c3ref/create_function.html
>>
>> I've done:
>>
>>
>> ' Gambas module file
>>
>> Library "libsqlite3"
>> Private Extern sqlite3_create_function(db As Pointer, name As String,
>> arg As Integer, eTextRep As Integer, pApp As Pointer, xFun As
>> Pointer, xStep As Pointer, xFinal As Pointer)
>> Private BD As Connection
>>
>> Public Sub Main()
>>
>> '#define SQLITE_UTF8 1
>>
>> Dim punt1 As Pointer
>> Dim punt2 As Pointer
>> Dim ia As Integer
>>
>> BD = New Connection
>> With BD
>> .Type = "sqlite3"
>> .Host = Application.Path
>> 'verificating if db exist
>> .Name = ""
>> .Open
>> End With
>>
>> punt1 = VarPtr(BD)
>> Debug sepTelef("666777888")
>> Debug punt1
>>
>> ia = sqlite3_create_function(punt1, "sepTelef", 1, 1, Null,
>> sepTelef, Null, Null)
>>
>> End
>>
>> Function sepTelef(telefono As String) As String
>>
>> Dim scad As String
>>
>> scad = Mid(telefono, 1, 3) & "-" & Mid(telefono, 4, 3) & "-" &
>> Mid(telefono, 7, 3)
>> Return scad
>>
>> End
>>
>>
>> result
>>
>> Segment violation 11
>>
>
> 'VarPtr(BD)' is the memory address where a pointer to a Gambas object
> (BD) is stored. It has nothing to do with the "sqlite3 *" pointer of
> the underlying connection. So It cannot work.
>
> The Handle property of BD returns a pointer that points at a structure
> that represents a SQLite database to Gambas. But it's still not the
> "sqlite3 *" pointer you need.
>
> Fortunately, this pointer is stored at the beginning of that
> structure. (you can know that by reading the source code of the
> 'gb.db.sqlite3' component).
>
> So Try 'Pointer@(BD.Handle)' instead of 'VarPtr(BD)'.
>
> And try a bit to understand how C works otherwise you won't really
> understand how external function management works in Gambas!
>
> Regards,
>
Thanks to Benoit for giving me the track of 'Pointer@(Bd.handle)'
I thought that creating a user function in SQLite3 would be something
similar to declare external function, creating a function in Gambas3 and
SQLite3 would use the value returned by the function.
But it seems that SQLite3 uses calling functions, and is more complicated.
I leave an example in case someone may be interested.
' Gambas module file
' codigo sacado de
https://stackoverflow.com/questions/7867099/how-can-i-create-a-user-defined-function-in-sqlite
' codigo en java
'Static void firstchar(sqlite3_context * context, int argc,
sqlite3_value * * argv)
'{
' If (argc == 1) {
' char * text = sqlite3_value_text(argv[0]);
' If (text & & text[0]) {
' char result[2];
' result[0] = text[0]; result[1] = '\0';
' sqlite3_result_text(context, result, -1, SQLITE_TRANSIENT);
' Return ;
' }
' }
' sqlite3_result_null(context);
'}
Library "libsqlite3" 'declaracion de la libreria
'int sqlite3_create_function(sqlite3 * db, Const char * zFunctionName,
int nArg, int eTextRep, void * pApp, void( * xFunc)(sqlite3_context *,
int, sqlite3_value * * ), void( * xStep)(sqlite3_context *, int,
sqlite3_value * * ), void( * xFinal)(sqlite3_context * ) );
Private Extern sqlite3_create_function(db As Pointer, name As String,
Argc As Integer, numParam As Integer, pApp As Pointer, xFun As Pointer,
xStep As Pointer, xFinal As Pointer)
' void sqlite3_result_text(sqlite3_context*, const char*, int,
void(*)(void*));
Private Extern sqlite3_result_text(sqlite3_context As Pointer, cadena As
String, numParam As Integer, valorsqlite As Pointer)
' void sqlite3_result_null(sqlite3_context*);
Private Extern sqlite3_result_null(sqlite3_context As Pointer)
' const unsigned char *sqlite3_value_text(sqlite3_value*);
Private Extern sqlite3_value_text(sqlite3_value As Pointer) As String
Private BD As Connection
Public Sub Main()
'#define SQLITE_UTF8 1
Dim punt1 As Pointer
Dim ia As Integer
Dim rsFun As Result
Dim tb As Table
Dim rsCli As Result
Dim snombre, stel As String
BD = New Connection
With BD ' creamos Bd en memoria
.Type = "sqlite3"
.Host = Application.Path
.Name = ""
.Open
End With
' creamos una tabla con dos campos en la conexion
bd.Tables.Add("cli")
tb = bd.Tables["cli"]
tb.Fields.Add("nombre", gb.String, 9)
tb.Fields.Add("telf", gb.String, 9)
tb.Update
rsCli = bd.Create("cli")
For i As Integer = 0 To 20 ' llenamos la tabla
Randomize
ia = Rand(100000000, 999999999)
rsCli!nombre = "nombre_" & Str(i)
rsCli!telf = Str(ia)
rsCli.Update
Next
punt1 = Pointer@(BD.Handle) ' obtencion del puntero de la conexion
Debug punt1
' declaracion de user function
sqlite3_create_function(punt1, "sepTelef", 1, 1, Null, sepTelef,
Null, Null)
rsFun = BD.Exec("Select nombre, telf, sepTelef(telf) as funTelf
From cli") ' Result con la llamada a la funcion
rsFun.MoveFirst
For i As Integer = 0 To rsFun.Max
Debug rsFun!nombre, rsFun!telf, rsFun!funTelf
rsFun.MoveNext
Next
End
Sub sepTelef(sqlite3_context As Pointer, Argc As Integer, sqlite_val As
Pointer)
' void sqlite3_result_text(sqlite3_context*, const char*, int,
void(*)(void*));
' const unsigned char *sqlite3_value_text(sqlite3_value*);
'#define SQLITE_STATIC ((sqlite3_destructor_type)0)
'#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
Dim scad, tel As String
Dim punt1 As Pointer
If Argc = 1 Then
punt1 = Pointer@(sqlite_val)
tel = sqlite3_value_text(punt1)
scad = Mid(tel, 1, 3) & "-" & Mid(tel, 4, 3) & "-" & Mid(tel, 7, 3)
sqlite3_result_text(sqlite3_context, scad, -1, -1)
Return
Endif
sqlite3_result_null(sqlite3_context)
End
More information about the User
mailing list