Page 1 of 1
SQLite [Working Code]
Posted: Sat May 22, 2004 12:50 pm
by Num3
This code works fine if i just run it under the compiler "PBCompiler sql_linux.pb", but if i try to run the executable it says "Unable to make Query" (program detects it cannot make a query)
I assume the table has to be in some system folder where it can be reached, but i don't know which...
It's kind of stupid the sqlite.so has to be in the lib folder and Linux does not search in the program executable directory itself
Help, anyone :roll:
Code: Select all
#SQLITE_OK =0 ; Successful Result
Procedure.l SQLite_Get_Table(DB_Handle.l, SQLString.s, * Rows, * Cols)
Shared Result.l
Shared LResultsPtr.l
Shared LRows.l
Shared LCols.l
Result = CallFunction(0, "sqlite_get_table", DB_Handle, SQLString, @LResultsPtr, @LRows, @LCols, 0)
If Result = #SQLITE_OK
; return number of rows/columns
PokeL(*Rows, LRows)
PokeL(*Cols, LCols)
; redimension results array (clears data)
Dim DBData.s(LRows, LCols - 1)
; copy data into array
Address.l = LResultsPtr
AddrInc.l = LCols * 4
For Row.l = 0 To LRows
For Col.l = 0 To LCols - 1
DBData(Row, Col) = PeekS(PeekL(Address + Col * 4))
Next
Address + AddrInc
Next
; free table memory
CallFunction(0, "sqlite_free_table", LResultsPtr)
EndIf
ProcedureReturn Result
EndProcedure
errormsg.s=""
If OpenLibrary(0,"sqlite.so")
db=CallFunction(0,"sqlite_open","test.db",0,errormsg)
If db
SQL.s = "SELECT id, url, site, category FROM bookmarks WHERE category LIKE 'delp%'"
Result = SQLite_Get_Table(db, SQL, @Rows, @Cols)
If Result = #SQLITE_OK
; get the results
; display number of rows/columns
a$=""
a$+ "Rows = " + Str(Rows)+Chr(10)
a$+ "Columns = " + Str(Cols)+Chr(10)+Chr(10)
; display column headers
For Col.l = 0 To Cols - 1
a$+ DBData(0, Col)+Chr(10)
Next
; display returned rows
For Row.l = 1 To Rows
a$+ "--------------" +Chr(10)
For Col = 0 To Cols - 1
a$+ DBData(Row, Col)+Chr(10)
Next
Next
CallFunction(0,"sqlite_close",db)
MessageRequester("Result",a$)
a$=""
Else
MessageRequester("Error","Unable to make query"+Chr(10)+errormsg)
EndIf
Else
MessageRequester("Error","Unable to open database"+Chr(10)+errormsg)
EndIf
Else
MessageRequester("Error","Unable to open library")
EndIf
Posted: Sat May 22, 2004 1:03 pm
by El_Choni
I think this should work in Linux too, and could help you find the problem:
Code: Select all
Result = CallFunction(0, "sqlite_get_table", DB_Handle, SQLString, @LResultsPtr, @LRows, @LCols, @zErrMsg)
If Result=#SQLITE_OK
; code
ElseIf zErrMsg
Debug PeekS(zErrMsg)
EndIf
Posted: Sat May 22, 2004 2:50 pm
by Num3
Found it!
Thanks El_Choni!!!
Ok seems Linux is dumb...
This is how it goes...
sqlite.so goes into lib folder
test.db goes into the root folder
and the code works just fine
Is there any way to force Linux to read a specific directory for those files...
(without being hardcoded)
*G* i really need GetCurrentDirectory() ...
Posted: Sat May 22, 2004 3:42 pm
by freak
Num3 wrote:*G* i really need GetCurrentDirectory() ...
You can read the current directory from the PWD environment variable like this:
Code: Select all
Procedure.s GetEnv(Variable$)
Protected *Environ.LONG
!extrn _environ
!mov eax, [_environ]
!mov [esp+4], eax
Variable$ + "="
While *Environ\l <> 0
If CompareMemoryString(@Variable$, *Environ\l, 0, Len(Variable$)) = 0
ProcedureReturn PeekS(*Environ\l + Len(Variable$))
EndIf
*Environ + 4
Wend
ProcedureReturn ""
EndProcedure
OpenConsole()
PrintN("Current Directory: "+GetEnv("PWD"))
CloseConsole()
End
hum, i better put that in Tips&Tricks too
Timo
Another solution
Posted: Sun Feb 26, 2006 4:27 am
by StanDan
I'm absolutely brand new to the site and to PureBasic (I just bought it today.) However, I found this discussion very useful and since I have a different solution that seems to work I thought I'd post it. The code that uses environ only gets the present working directory. If an application is being called from the shell then the PWD environment variable may not reflect the directory that the executable is in.
This was my problem. Linux places your actual executable name on the stack when your program starts running but I could find no way to insert assembly that early in program execution. So here's my (hack) solution (it may even be hilariously wrong, but it seems to work.) I'm guessing you could call getcwd_() or get_current_dir_name_() but I developed this using the demo version and couldn't get it to work. And that wouldn't return the right value anyway.
Code: Select all
; Get the program's process ID
Procedure.w GetPid()
!mov eax, 20
!int 0x80
ProcedureReturn
EndProcedure
; Read the symlink in mypath and return the file pointed to.
Procedure.s ReadLink(mypath.s)
mybuf.s = ""
mybufsize.l = 512
mybytesread.l = 0
mybuf = Space(mybufsize);
!mov eax, 85
!mov ebx, [esp]
!mov ecx, [esp+4]
!mov edx, [esp+8]
!int 0x80
!mov [esp+12], eax
mybuf = RTrim(mybuf)
If mybytesread > 0
ProcedureReturn mybuf
Else
ProcedureReturn ""
EndIf
EndProcedure
; Get my program filename and path.
Procedure.s GetExe()
pid.w = GetPid()
procpath.s = "/proc/"+Str(pid)+"/exe"
exe.s = ReadLink(procpath)
ProcedureReturn exe
EndProcedure
So a session with this and GetEnv both trying to load a function from a library in the program's path looks like this.
Code: Select all
jonathan@kosmic:~/dev/learning$ make
gcc -Wall -pedantic -fPIC -c mystuff.c
gcc -shared -Wl,-soname,libmystuff.so.1 -o libmystuff.so mystuff.o -lc
pbcompiler -e testso.exe -q testso.pb
jonathan@kosmic:~/dev/learning$ ls
Makefile libmystuff.so mystuff.c mystuff.o testso.exe testso.pb
jonathan@kosmic:~/dev/learning$ ./testso.exe
GetEnv() method is: /home/jonathan/dev/learning/libmystuff.so
GetExe() method is: /home/jonathan/dev/learning/libmystuff.so
libmystuff.so:someFunc() called with 'Hello World!'!
Function returned: 7357
jonathan@kosmic:~/dev/learning$ cd ..
jonathan@kosmic:~/dev$ learning/testso.exe
GetEnv() method is: /home/jonathan/dev/libmystuff.so
GetExe() method is: /home/jonathan/dev/learning/libmystuff.so
Sorry can't load the library!
jonathan@kosmic:~/dev$ cd ..
jonathan@kosmic:~$ /home/jonathan/dev/learning/testso.exe
GetEnv() method is: /home/jonathan/libmystuff.so
GetExe() method is: /home/jonathan/dev/learning/libmystuff.so
Sorry can't load the library!
The c file looks like:
Code: Select all
#include <stdio.h>
int someFunc(char *str);
int someFunc(char *str) {
fprintf(stderr, "libmystuff.so:someFunc() called with '%s'!\n", str);
return 7357;
}
And the PB code looks like:
Code: Select all
myso_pwd.s = GetEnv("PWD") + "/libmystuff.so"
myso_link.s = GetPathPart(GetExe()) + "libmystuff.so"
OpenConsole()
PrintN("GetEnv() method is: "+myso_pwd)
PrintN("GetExe() method is: "+myso_link)
hello$ = "Hello World!"
If OpenLibrary(0, myso_pwd)
*someFunc = IsFunction(0, "someFunc")
If *someFunc
res.l = CallFunctionFast(*someFunc, hello$)
PrintN("Function returned: "+Str(res))
EndIf
CloseLibrary(0)
Else
PrintN("Sorry can't load the library!")
EndIf
So you can see that this method will always return the actual directory your EXE is in, not just the directory it was called from. I hope this is helpful to someone, I spent quite some time figuring it out.
I gather from this discussion:
viewtopic.php?t=19639
That PB4 will have a built in keyword to do this. Way to go! Whoohoo!
Posted: Sun Feb 26, 2006 9:55 pm
by Straker
ts-soft's cross-platform GetCurrentDir() can be found here (last post):
viewtopic.php?t=17817
Posted: Mon Feb 27, 2006 4:43 am
by Straker
Straker wrote:ts-soft's cross-platform GetCurrentDir() can be found here (last post):
viewtopic.php?t=17817
[EDIT]
Whoa - I didn't really how old this thread really was because of the recent post.
Anyway, welcome to PureBasic StanDan!
Thanks Straker!
Posted: Tue Feb 28, 2006 12:17 am
by StanDan
This was exactly what I needed. I did search the forums like crazy but never found this little gem.
I was just doing a search trying to figure out how to typecast a pointer to a string (which doesn't seem possible.) When I noced you'd replied, and his answer accomplishes EXACTLY what I was having a problem with (notably, getting the return value from POSIX getcwd_(0,0) (or GNU_SOURCE__'s get_current_dir_name_()) which returns a pointer which is actually a string.)
I've been declaring two variables when I need to do this (a string and a pointer). Then using inline assembly to copy the pointer value into the string pointer on the stack (and possibly creating a memory leak, I have no idea how PureBasic handles memory.) There must be a better way! Gosh I hate being a newbie. Learning a new language is both exciting and humbling at the same time.
I know you can do this:
Code: Select all
a.s = "some string here"
PrintN(Hex(@a))
But for some reason you can't do this (syntax error):
Code: Select all
a.s = "some string here"
b.l = @a
c.s = "some other string"
@c = b
Memory management is probably the answer why. PureBasic would not deallocate the string "some other string\0" pointed to by @c before it's assigned the address of the string pointed to by @a.
But I don't know JACK so that could be utterly insane and offbase. I also tried using pointer notation *b = @a and that doesn't work either.
Anyway, thanks again for the help. I can now put this thorny problem down and go back to actually doing something productive.

Posted: Tue Feb 28, 2006 2:44 am
by Straker
I am not sure, but I think you are making this harder than it is.
To get the string from a returned pointer, use:
doh!
Posted: Tue Feb 28, 2006 7:26 pm
by StanDan
I saw Peek and Poke in the docs, never put 2 and 2 together. Gosh, I love PureBasic. I knew there was something I was missing -- given the language, it had to be easier. Thanks again man.
Posted: Tue Feb 28, 2006 8:01 pm
by Straker
No problem. I use PeekS() mostly when using the CallFunction() functions, because they return longs, even if the DLL function they are calling returns strings. So if you have issues with calling DLL functions, remember PeekS()!
Good luck.