sqlite3 question

New to FreeBASIC? Post your questions here.
Post Reply
PeterHu
Posts: 159
Joined: Jul 24, 2022 4:57

sqlite3 question

Post by PeterHu »

I moved the topic here from another thread to seek help as I think there is some fundamental concept with pointers/array interacts with system api call/c/3rd party libraries which I don't understand.

Below code snippet is my execise translation C code from http://zetcode.com/db/sqlitec/

When it runs,It prints "ALL DONE".

But it doesn't work properly,that is,the blob data does not insert into the db. Confirm test1.db and sample.jpg are fine in the folder.I tested the original C code with PellesC and it runs as expected.

Help would be appreciated.

Code: Select all

#include "sqlite3.bi"
#include "crt.bi"

function main_function() as integer
	
	dim fp as file ptr
	fp=fopen("sample.jpg","rb")
	
	if(fp=null) then
		fprintf(stderr,!"Cann't open image file\n")
		return 1
	end if
	
	
	
	fseek(fp,0,SEEK_END)
	
	if(ferror(fp)<>0) then
		fprintf(stderr,!"fseek() failed\n")
		dim as integer r =fclose(fp)
		if(r<>0) then
			fprintf(stderr,!"Cannot close file handler\n")
		end if
	end if

	return 1
	
	dim flen as integer=ftell(fp)
	if(flen=-1) then
		perror(!"error occurred\n")
		dim as integer r=fclose(fp)
		
		if(r<>0) then 
			fprintf(stderr,!"Cannot close file handler\n")
		end if
		return 1
	end if
	
	fseek(fp,0,SEEK_SET)
	if(ferror(fp)) then
		fprintf(stderr,!"fseek() failed\n")
		dim as integer r=fclose(fp)
		if(r<>0) then
			fprintf(stderr,!"Cannot close file handler\n")
		end if
		return 1
	end if
	
	'dim datas(flen+1) as byte
	dim as ulong datas(flen+1)
	
	dim as integer res=fread(@datas(0),1,flen,fp)
	if(ferror(fp)) then
		fprintf(stderr,!"fread() failed\n")
		dim as integer r=fclose(fp)
		
		if(r<>0) then 
			fprintf(stderr,!"Cann't close file handler\n")
		end if
		return 1
	end if
	dim as integer r=fclose(fp)
	if(r<>0) then 
		fprintf(stderr,"Cann't close file handler\n")
	end if
	
	
	dim db as sqlite3 ptr
	dim err_msg as zstring ptr=null
	
	dim as integer rc=sqlite3_open("test1.db",@db)
	if(rc<>SQLITE_OK) then
		fprintf(stderr,!"Cannot open database :%s\n",sqlite3_errmsg(db))
		sqlite3_close(db)
		
		return 1
	end if
	
	dim as sqlite3_stmt ptr pStmt
	dim as string sql="Insert into images(data) values(?)"
	rc=sqlite3_prepare(db,strptr(sql),-1,@pStmt,null)
	
	if(rc<>SQLITE_OK) then
		fprintf(stderr,!"Cannot prepare statement:%s\n",sqlite3_errmsg(db))
		return 1
	end if
	
	if(sqlite3_bind_blob(pStmt,1,@datas(0),res,SQLITE_STATIC)<>SQLITE_OK) then
		fprintf(stderr,!"Cannot insert blob data to db:%s\n",sqlite3_errmsg(db))
		return 1
	end if
	
	
	rc=sqlite3_step(pStmt)
	if(rc<>SQLITE_DONE) then
		printf(!"Execution failed:%s",sqlite3_errmsg(db))
	end if
	
	sqlite3_finalize(pStmt)
	sqlite3_close(db)
	
	printf(!"Everything is DONE!\n")  ''''-------->This line doesn't get printed in the console
	
	sleep
	return 0
	
end function

main_function

? "ALL DONE!" ''''--------------------->This line gets printed in the console
sleep


TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: sqlite3 question

Post by TJF »

Due to line 26

Code: Select all

	return 1
the return value of your main_function is always 1. (Why don't you evaluate the return value?) The function closes the opened file only in case of an error.

Regards
PeterHu
Posts: 159
Joined: Jul 24, 2022 4:57

Re: sqlite3 question

Post by PeterHu »

TJF wrote: Dec 06, 2023 5:20 Due to line 26

Code: Select all

	return 1
the return value of your main_function is always 1. (Why don't you evaluate the return value?) The function closes the opened file only in case of an error.

Regards
Thank you so much for the help! Apologies to the mistake. 【Edit on Dec 7,15:24】Forgot to mark the issue has been fixed.

During the past several days I was doubting whether 1 or both of below 2 statements was wrong due to my misunderstanding of the fundamentals:

Code: Select all

'dim flen as integer=ftell(fp)
' 1---int array[flen+1] in c++ is not allowed,so maybe below line is wrong ?But I can't reply to myself
dim ulong datas(flen+1)
'2---Does not allocate memory for datas() before using it,maybe this is wrong?
'     So I tried below but the the program ran without change. 
'      dim as zstring ptr flen=allocate(sizeof(stirng)*N)
'       dim fp as file ptr
'       fp=fopen(filename,"rb")
'       if(fp<>null) then
'             fscanf(fp,"%s",flen)
'             fclose(fp)
'       endif

dim as integer res=fread(@datas(0),1,flen,fp)
Last edited by PeterHu on Dec 07, 2023 7:28, edited 1 time in total.
shadow008
Posts: 86
Joined: Nov 26, 2013 2:43

Re: sqlite3 question

Post by shadow008 »

As TJF has already pointed out, you're returning from the function for seemingly no reason right in the middle. Perhaps a relic of debugging? You ought to remove it.

Anyway:
' 1---int array[flen+1] in c++ is not allowed,so maybe below line is wrong ?But I can't reply to myself
dim ulong datas(flen+1)
That line is legal, it allocates that array of flen + 1 ulongs on the stack though. However, I think you meant to use ubyte and not ulong. A ulong (on your probably 64 bit machine & 64 bit compiler) is 4 bytes in size. You're allocating 3 times more memory than you need. On the stack nonetheless.
'2---Does not allocate memory for datas() before using it,maybe this is wrong?
No it's being allocated, just on the stack not the heap. Since you appear to be trying to load the contents of an entire file into that space in memory, you should realize there's a relatively small limit to how big an array you can allocate with dim. I don't know what it is off the top of my head, but I'd wager it's around 1 or 2MB, and configurable via compiler options.

For that reason, what you had stated afterward is a preferable way of doing what you're doing.
' So I tried below but the the program ran without change.
' dim as zstring ptr flen=allocate(sizeof(stirng)*N)
' dim fp as file ptr
' fp=fopen(filename,"rb")
' if(fp<>null) then
' fscanf(fp,"%s",flen)
' fclose(fp)
' endif
Just don't forget to deallocate.

Now... about your error checking...
You have to realize that any time you return from the function without closing your files/deallocating, your leaking resources. There's a few ways to do this, but a quick an easy way is to use a tactical goto and label (no, goto's are not heresy when used correctly). Starting AFTER you've opened your file, your error checks should look more like this:

Code: Select all

	if(sqlite3_bind_blob(pStmt,1,@datas(0),res,SQLITE_STATIC)<>SQLITE_OK) then
		fprintf(stderr,!"Cannot insert blob data to db:%s\n",sqlite3_errmsg(db))
		some_variable_for_error = true OR 1 OR something...
		goto cleanup
	end if
And the end of your function would instead look like this:

Code: Select all

cleanup:
	printf(!"Everything is DONE!\n")  ''''-------->This line doesn't get printed in the console
	
	sqlite3_finalize(pStmt)
	sqlite3_close(db)
	deallocate(some_array_of_sorts)
	... clean up all resources here etc ...
	
	sleep
	return some_variable_for_error
	
end function
PeterHu
Posts: 159
Joined: Jul 24, 2022 4:57

Re: sqlite3 question

Post by PeterHu »

shadow008 wrote: Dec 07, 2023 6:11 As TJF has already pointed out, you're returning from the function for seemingly no reason right in the middle. Perhaps a relic of debugging? You ought to remove it.

Anyway:
' 1---int array[flen+1] in c++ is not allowed,so maybe below line is wrong ?But I can't reply to myself
dim ulong datas(flen+1)
That line is legal, it allocates that array of flen + 1 ulongs on the stack though. However, I think you meant to use ubyte and not ulong. A ulong (on your probably 64 bit machine & 64 bit compiler) is 4 bytes in size. You're allocating 3 times more memory than you need. On the stack nonetheless.
'2---Does not allocate memory for datas() before using it,maybe this is wrong?
No it's being allocated, just on the stack not the heap. Since you appear to be trying to load the contents of an entire file into that space in memory, you should realize there's a relatively small limit to how big an array you can allocate with dim. I don't know what it is off the top of my head, but I'd wager it's around 1 or 2MB, and configurable via compiler options.

For that reason, what you had stated afterward is a preferable way of doing what you're doing.
' So I tried below but the the program ran without change.
' dim as zstring ptr flen=allocate(sizeof(stirng)*N)
' dim fp as file ptr
' fp=fopen(filename,"rb")
' if(fp<>null) then
' fscanf(fp,"%s",flen)
' fclose(fp)
' endif
Just don't forget to deallocate.

Now... about your error checking...
You have to realize that any time you return from the function without closing your files/deallocating, your leaking resources. There's a few ways to do this, but a quick an easy way is to use a tactical goto and label (no, goto's are not heresy when used correctly). Starting AFTER you've opened your file, your error checks should look more like this:

Code: Select all

	if(sqlite3_bind_blob(pStmt,1,@datas(0),res,SQLITE_STATIC)<>SQLITE_OK) then
		fprintf(stderr,!"Cannot insert blob data to db:%s\n",sqlite3_errmsg(db))
		some_variable_for_error = true OR 1 OR something...
		goto cleanup
	end if
And the end of your function would instead look like this:

Code: Select all

cleanup:
	printf(!"Everything is DONE!\n")  ''''-------->This line doesn't get printed in the console
	
	sqlite3_finalize(pStmt)
	sqlite3_close(db)
	deallocate(some_array_of_sorts)
	... clean up all resources here etc ...
	
	sleep
	return some_variable_for_error
	
end function
Thank you so much for the patience and what you have pointed out to me.Those are what I am expecting to learning deeper.
When I replied TJF I just carelessly forgot to confirm the issue has been fixed.The issue was due to the wrongly placed "return 1" in line 26 of the original source file,that should be in the if .. end if when fseek() failed.

During the past years of self-studying of programming,I was once loving features like oops,generics,templates,lamdas,design patterns etc. and those fancy libraries written upon these features ,but at last I found that almost 90% of the time when a question/problem came out which I can't understand or just can't tell what was wrong,that was all about fundamentals.So now I would like to spend more time not on those fancy features,but the basics,for example,reading my favorite online free book A beginner's Guide to Programminghttps://github.com/Axle-Ozz-i-sofT/A-BE ... ROGRAMMING.【When reading c++ books,someone said that don't spend too much time on how it was designed/created under the hood,just use it to get your job done.Was I the only person who doubts the stand of the point?

Thank you all for taking time to help me on these very basics.

Best regards
shadow008
Posts: 86
Joined: Nov 26, 2013 2:43

Re: sqlite3 question

Post by shadow008 »

【When reading c++ books,someone said that don't spend too much time on how it was designed/created under the hood,just use it to get your job done.Was I the only person who doubts the stand of the point?】
Do you know the in's and out's of your processor or do you just use it to run your machine code?
Do you know how your internal combustion engine was designed or do you just drive your car?
That's overall not bad advice.

When you're learning a library you generally start out with a use case you think the library is capable of handling, do some research to figure out what the minimal effort you need to get results, and then when the use case is satisfied, either move on or delve deeper. Sometimes when you delve deeper, you'll realize you need to know something specific about the design/implementation. You'll know when that time comes when it comes, don't sweat it.
PeterHu
Posts: 159
Joined: Jul 24, 2022 4:57

Re: sqlite3 question

Post by PeterHu »

shadow008 wrote: Dec 07, 2023 18:58
【When reading c++ books,someone said that don't spend too much time on how it was designed/created under the hood,just use it to get your job done.Was I the only person who doubts the stand of the point?】
Do you know the in's and out's of your processor or do you just use it to run your machine code?
Do you know how your internal combustion engine was designed or do you just drive your car?
That's overall not bad advice.

When you're learning a library you generally start out with a use case you think the library is capable of handling, do some research to figure out what the minimal effort you need to get results, and then when the use case is satisfied, either move on or delve deeper. Sometimes when you delve deeper, you'll realize you need to know something specific about the design/implementation. You'll know when that time comes when it comes, don't sweat it.
Thank you...
Post Reply