Page 1 of 1

SetDatabaseBlob with two Databases

Posted: Thu Jul 11, 2024 10:04 pm
by Little_man
How to put back "DatabaseQuery" into a database (BLOB);
(DataBase out "SQL_OUD" and insterted into Database "SQL_TEST")

Code: Select all

OpenDatabase(SQL__TEST, SQL__TEST__Path_File, #Null$, #Null$, #PB_Database_SQLite)

;###############################################################################
OpenDatabase(SQL__OUD, SQL__OUD__Path_File, #Null$, #Null$, #PB_Database_SQLite)
  DatabaseQuery(SQL__OUD, "SELECT * FROM Product_Description")

  While NextDatabaseRow(SQL__OUD)
    SQLRequest__TEST = "INSERT INTO Product_Description "
    SQLRequest__TEST + "("
    SQLRequest__TEST + "Nr, Description, Ingredients, Price, FAT_Rate, "
    SQLRequest__TEST + "Product_Image_Name, Product_Image_Path, Product_Image_Photo, Product_Image_Size"
    SQLRequest__TEST + ") VALUES ("
    SQLRequest__TEST + "'" + GetDatabaseString(SQL__OUD, 1) + "', "                                ;Nr                      - 1   TEXT.
    SQLRequest__TEST + "'" + ReplaceString(GetDatabaseString(SQL__OUD, 2), "'", "|") + "', "       ;Description             - 2   TEXT.
    SQLRequest__TEST + "'" + ReplaceString(GetDatabaseString(SQL__OUD, 3), "'", "|") + "', "       ;Ingredients             - 3   TEXT.
    SQLRequest__TEST + "'" + GetDatabaseString(SQL__OUD, 4) + "', "                                ;Price                   - 4   TEXT.
    SQLRequest__TEST + "'" + GetDatabaseString(SQL__OUD, 5) + "', "                                ;FAT_Rate                - 5   TEXT.
    SQLRequest__TEST + "'" + GetDatabaseString(SQL__OUD, 6) + "', "                                ;Product_Image_Name      - 6   TEXT.
    SQLRequest__TEST + "'" + GetDatabaseString(SQL__OUD, 7) + "', "                                ;Product_Image_Path      - 7   TEXT.
    
    If GetDatabaseString(SQL__OUD, 8) <> #Null$
        *Buffer = AllocateMemory(DatabaseColumnSize(SQL__OUD, 8), #PB_Memory_NoClear)
        If *Buffer
          If GetDatabaseBlob(SQL__OUD, 8, *Buffer, MemorySize(*Buffer))
            Line$ = Base64Encoder(*Buffer, MemorySize(*Buffer))

            ;Base64Decoder(Input$, *OutputBuffer, OutputSize) 

            ;How to put back into a database  ??????
            ;=======================================

            SQLRequest__TEST + "'" + Line$                          + "', "                        ;Product_Image_Photo     - 8   BLOB.
            SQLRequest__TEST + "'" + GetDatabaseString(SQL__OUD, 9) + "') "                        ;Product_Image_Photo     - 9   INTEGER.

          EndIf
          FreeMemory(*Buffer)
        EndIf
      Else
        SQLRequest__TEST + "'" + ""                        + "', "                                 ;Product_Image_Photo     - 8   BLOB.
        SQLRequest__TEST + "'" + "" + "') "                                                        ;Product_Image_Photo     - 9   INTEGER.
    EndIf

    DatabaseUpdate(SQL__TEST, SQLRequest__TEST)
  Wend

  FinishDatabaseQuery(SQL__OUD)
  FinishDatabaseQuery(SQL__TEST)
CloseDatabase(SQL__OUD)
CloseDatabase(SQL__TEST)
;###############################################################################
Kind regards,
Little_man

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 4:31 am
by boddhi
Hello,

1) Why SetDatabaseBlob() in your title if you're using Base64Encoder()?

2) You really shouldn't use the database instruction set the way you do.
Β 
I haven't tested it, but based on your code, this is what it might look like:

Code: Select all

OpenDatabase(SQL__TEST, SQL__TEST__Path_File, "", "", #PB_Database_SQLite)

;###############################################################################
OpenDatabase(SQL__OUD, SQL__OUD__Path_File, "", "", #PB_Database_SQLite)
DatabaseQuery(SQL__OUD, "SELECT * FROM Product_Description")

SQLRequest__TEST = "INSERT INTO Product_Description "
SQLRequest__TEST + "("
SQLRequest__TEST + "Nr, Description, Ingredients, Price, FAT_Rate, " ; 0,1,2,3
SQLRequest__TEST + "Product_Image_Name, Product_Image_Path, Product_Image_Photo, Product_Image_Size" ; 4,5,6,7,8
SQLRequest__TEST + ") VALUES (?,?,?,?,?,?,?,?,?)"

While NextDatabaseRow(SQL__OUD)
  ; Here, prefer GetDatabaseLong() or GetDatabaseQuad() when values are numeric even if SQLite does the conversion automatically. It makes the code more intelligible.
  Nr.s=GetDatabaseString(SQL__OUD, 1)
  Description.s=GetDatabaseString(SQL__OUD, 2)
  Ingredients.s=GetDatabaseString(SQL__OUD, 3)
  Price.s=GetDatabaseString(SQL__OUD, 4)
  FAT_Rate.s=GetDatabaseString(SQL__OUD, 5)
  Product_Image_Name.s=GetDatabaseString(SQL__OUD, 6)
  Product_Image_Path.s=GetDatabaseString(SQL__OUD, 7)
  Product_Image_Size.s=GetDatabaseString(SQL__OUD, 9)
  
  BlobSize=DatabaseColumnSize(SQL__OUD, 8)
  If BlobSize
    *Buffer = AllocateMemory(BlobSize)
    If *Buffer
      GetDatabaseBlob(SQL__OUD, 8, *Buffer,BlobSize)
    EndIf
  EndIf
  
  ; Here, prefer SetDatabaseLong() or SetDatabaseQuad() when values are numeric even if SQLite does the conversion automatically. It makes the code more intelligible.
  SetDatabaseString(SQL__TEST,0,Nr)
  SetDatabaseString(SQL__TEST,1,Description)
  SetDatabaseString(SQL__TEST,2,Ingredients)
  SetDatabaseString(SQL__TEST,3,Price)
  SetDatabaseString(SQL__TEST,4,FAT_Rate)
  SetDatabaseString(SQL__TEST,5,Product_Image_Name)
  SetDatabaseString(SQL__TEST,6,Product_Image_Path)
  
  If BlobSize And *Buffer
    SetDatabaseBlob(SQL__TEST,7,*Buffer,BlobSize)
    SetDatabaseString(SQL__TEST,8,Product_Image_Size)
  Else
    SetDatabaseNull(SQL__TEST,7)
    SetDatabaseNull(SQL__TEST,8)
  EndIf
  DatabaseUpdate(SQL__TEST, SQLRequest__TEST)
  
  If *Buffer
    FreeMemory(*buffer)
  EndIf
Wend
FinishDatabaseQuery(SQL__OUD)
; FinishDatabaseQuery(SQL__TEST) : Absolutely useless, since there's no query on this database!

CloseDatabase(SQL__OUD)
CloseDatabase(SQL__TEST)
;###############################################################################
Β 
PS: To facilitate exchanges between several databases, you can also use the SQLite "ATTACH DATABASE" statement.

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 6:33 am
by Little_man
"boddhi": Your code doesn't work!!..

The information from:
;==================================================================
Re: Blob and variable
Post by infratec Β» Sun Nov 06, 2022 12:08 pm
Since a blob is binary, you need Base64Encoder() to get it into a string variable.
I showed this one post below.
;==================================================================

Code: Select all

...
*Buffer = AllocateMemory(DatabaseColumnSize(DB, i), #PB_Memory_NoClear)
If *Buffer
  If GetDatabaseBlob(DB, i, *Buffer, MemorySize(*Buffer))
    Line$ + Base64Encoder(*Buffer, MemorySize(*Buffer))
  EndIf
  FreeMemory(*Buffer)
EndIf
...


Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 6:44 am
by infratec
Do you need the blob in a string variable?
I don't think so.

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 10:02 am
by boddhi
Little_man wrote: Since a blob is binary, you need Base64Encoder() to get it into a string variable.
😱😱 Damn!!!! I'm going to have to modify all my programs that use blobs!!!! 😭😭😭
Β 
"boddhi": Your code doesn't work!!..
A little bit (too fast?) peremptory! Did you at least test it?

I know that the info provided in the official doc sometimes lacks precisions, but where did you see any obligation to use Base64Encoder() with SetDatabaseBlob() described?

And a little logic, please: Base64Encoder() returns a string. To store a string in a DB, we use SetDatabaseString().
So the question is: What could SetDatabaseBlob() possibly be used for?
And the answer is: To store binary data like, for example, images!

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 10:17 am
by Little_man
boddhi,

Yes, I made a test but it didn't work

Little_man

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 10:29 am
by Fred
Blob stands for Binary Object, so you can put raw binary object directly in the DB. It's indeed not needed to use base64encoder as it will generate larger data and use more CPU / disk space.

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 2:02 pm
by boddhi
Ainsi parla Fred !
Thus Fred spoke!

:D

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 2:23 pm
by Little_man
Got it working after some adjustments.

little_man

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 6:19 pm
by boddhi
Little_man wrote: Got it working after some adjustments.
My code didn't work before probably because your SQL column 'Product_Image_Photo' was defined as String and not as Blob and you had to change its type.
Which I forgot to mention because it was so obvious to me...

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 6:31 pm
by Mindphazer
Little_man wrote: Fri Jul 12, 2024 2:23 pm Got it working after some adjustments.

little_man
The less you can do is to show how you get it working
They were many to try to help you, maybe one day someone will have the same question, and i guess he'd be glad to have the answer :wink:

Re: SetDatabaseBlob with two Databases

Posted: Fri Jul 12, 2024 9:27 pm
by Little_man
Mindphazer
Adjustment:

If Product_Image_Size <> #Null$ (Not always an Image present)
FreeMemory(*Buffer)
EndIf

Little_Man

Re: SetDatabaseBlob with two Databases

Posted: Sat Jul 13, 2024 12:57 am
by boddhi
Little_man wrote: Adjustment:
[...]
:shock: Only this? And where are the provided advices?

Always How to, never Like?

So, for those who might be interested, below is a very simple and succinct example (not all error handling tests have been implemented) of how to copy a blob from one DB to another.
Remember that you can also use the SQLite "ATTACH DATABASE" statement, which makes things much easier in some cases.

Code: Select all

EnableExplicit
; ╔═════════════════════════════════════════════════════════════════════════════════════╗
; β•‘ PLUGINS - STRUCTURES - ENUMERATIONS - CONSTANTS - MACROS - MAPS - GLOBAL VARIABLES  β•‘
; β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
;{ ════  PLUGINS              ════
;- ════  PLUGINS
UseSQLiteDatabase()
UseJPEGImageDecoder()
;}
;{ ════  ENUMERATIONS         ════
;- ════  ENUMERATIONS ════
Enumeration Windows  ;{
  #WIN_MAIN
EndEnumeration ;}
Enumeration Gadgets  ;{ Gadgets fenΓͺtre principale
  #GAD_BT_COPYDATA
  #GAD_ED_REPORT
  #GAD_IMG_IMAGEPB
EndEnumeration ;}
Enumeration Images   ;{
  #IMG_IMAGE
EndEnumeration ;}
Enumeration SqlDB    ;{
  #SQLDB_SOURCE
  #SQLDB_TARGET
EndEnumeration ;}
;}
;{ ════  CONSTANTS            ════
;- ════  CONSTANTS            ════
#SQL_CREATETABLE  ="CREATE TABLE MyTable (Id INTEGER,ImageBlob LONGBLOB)"
#SQL_GETRECORDS   ="SELECT * FROM MyTable"
#SQL_INSERTRECORD ="INSERT INTO MyTable VALUES (?,?)"
;}
;{ ════  GLOBAL VARIABLES     ════
; -════  GLOBAL VARIABLES     ════
Global.s TempDir=GetTemporaryDirectory()
Global.s SourceDBName=TempDir+"Temp_SourceDB.sqlite"
Global.s TargetDBName=TempDir+"Temp_TargetDB.sqlite"
;}
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
; ╔════════════╗
; β•‘ PROCEDURES β•‘
; β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
Procedure.a Fc_DBsDeletion()
  Protected.a Result=#True
  
  ; Source DB
  If FileSize(SourceDBName)>=0
    If Not DeleteFile(SourceDBName,#PB_FileSystem_Force)
      Result=#False
      MessageRequester("","Error while deleting source DB!",#PB_MessageRequester_Error)
    EndIf
  EndIf
  
  ; Target DB
  If FileSize(TargetDBName)>=0
    If Not DeleteFile(TargetDBName,#PB_FileSystem_Force)
      Result=#False
      MessageRequester("","Error while deleting target DB!",#PB_MessageRequester_Error)
    EndIf
  EndIf
  
  ProcedureReturn Result
EndProcedure
Procedure   Pc_DBsClosing()
  If IsDatabase(#SQLDB_SOURCE):CloseDatabase(#SQLDB_SOURCE):EndIf
  If IsDatabase(#SQLDB_TARGET):CloseDatabase(#SQLDB_TARGET):EndIf
EndProcedure
Procedure.a Fc_DBsCreation()
  Protected *ImageBuffer
  Protected.l ImageSize ; .l because we don't need bigger in our example
  
  ; Previous DBs deletion
  If Not Fc_DBsDeletion():ProcedureReturn #False:EndIf
  ;
  ; -----------------------
  ; Source DB file creation
  ; -----------------------
  If Not CreateFile(#SQLDB_SOURCE,SourceDBName)
    MessageRequester("","Error while creating source DB!",#PB_MessageRequester_Error)
    Goto Fc_DBCreation_Error
  EndIf
  CloseFile(#SQLDB_SOURCE)
  ;
  ; Source DB file opening
  If Not OpenDatabase(#SQLDB_SOURCE,SourceDBName,"","",#PB_Database_SQLite)
    MessageRequester("","Error while opening source DB!",#PB_MessageRequester_Error)
    Goto Fc_DBCreation_Error
  EndIf
  ;
  ; Table creation
  If Not DatabaseUpdate(#SQLDB_SOURCE,#SQL_CREATETABLE)
    MessageRequester("","Error while create source table!",#PB_MessageRequester_Error)
    Goto Fc_DBCreation_Error
  EndIf
  ; 
  ; -----------------------
  ; Target DB file creation
  ; -----------------------
  If Not CreateFile(#SQLDB_TARGET,TargetDBName)
    MessageRequester("","Error while creating target DB!",#PB_MessageRequester_Error)
    Goto Fc_DBCreation_Error
  EndIf
  CloseFile(#SQLDB_TARGET)
  ;
  ; Target DB file opening
  If Not OpenDatabase(#SQLDB_TARGET,TargetDBName,"","",#PB_Database_SQLite)
    MessageRequester("","Error while opening target DB!",#PB_MessageRequester_Error)
    Goto Fc_DBCreation_Error
  EndIf
  ;
  ; Table creation
  If Not DatabaseUpdate(#SQLDB_TARGET,#SQL_CREATETABLE)
    MessageRequester("","Error while create target table!",#PB_MessageRequester_Error)
    Goto Fc_DBCreation_Error
  EndIf
  ;
  ; -----------------------
  ; Source table populating
  ; -----------------------
  ; First record
  ImageSize=?ImagePB_End-?ImagePB_Start ; See datasection below
  SetDatabaseLong(#SQLDB_SOURCE,0,1)                          ; Field 1 ID
  *ImageBuffer=AllocateMemory(ImageSize)
  If *ImageBuffer
    CopyMemory(?ImagePB_Start,*ImageBuffer,ImageSize)
    SetDatabaseBlob(#SQLDB_SOURCE,1,*ImageBuffer,ImageSize)   ; Field 2 Blob
  Else
    SetDatabaseNull(#SQLDB_SOURCE,1)
  EndIf
  DatabaseUpdate(#SQLDB_SOURCE,#SQL_INSERTRECORD)
  If *ImageBuffer:FreeMemory(*ImageBuffer):EndIf
  ;
  ; Second record
  SetDatabaseLong(#SQLDB_SOURCE,0,2)                          ; Field 1 ID
  SetDatabaseNull(#SQLDB_SOURCE,1)                            ; Field 2 Blob
  DatabaseUpdate(#SQLDB_SOURCE,#SQL_INSERTRECORD)
  
  ProcedureReturn #True
  
Fc_DBCreation_Error:
  Pc_DBsClosing()
  Fc_DBsDeletion()
  ProcedureReturn #False
EndProcedure
Procedure   Pc_SourceRecordsCopying()
  Protected *ImageBuffer
  Protected.i Id
  Protected.l ImageSize ; .l because we don't need bigger in our example
  Protected.s RecordReport
  
  Select GetGadgetData(#GAD_BT_COPYDATA)
    Case 0
      ; -------------------------------------
      ; Records copying from source to target
      ; -------------------------------------
      ; Record selection
      AddGadgetItem(#GAD_ED_REPORT,-1,"Selection of source table records")
      If DatabaseQuery(#SQLDB_SOURCE,#SQL_GETRECORDS,#PB_Database_StaticCursor)
        DatabaseUpdate(#SQLDB_TARGET,"BEGIN")
        While NextDatabaseRow(#SQLDB_SOURCE)
          ImageSize=DatabaseColumnSize(#SQLDB_SOURCE,1)
          RecordReport="  Record "+GetDatabaseString(#SQLDB_SOURCE,0)+" : ImageSize : "+Str(ImageSize)
          If ImageSize
            *ImageBuffer=AllocateMemory(ImageSize)
            If *ImageBuffer
              If GetDatabaseBlob(#SQLDB_SOURCE,1,*ImageBuffer,ImageSize)
                Id=GetDatabaseLong(#SQLDB_SOURCE,0)
                RecordReport+" & Blob ok"
              Else
                ImageSize=0
                RecordReport+" & Error blob"
              EndIf
            Else
              MessageRequester("","Memory allocation error!",#PB_MessageRequester_Error)
            EndIf
            AddGadgetItem(#GAD_ED_REPORT,-1,RecordReport)
            ; Target table populating only if a blob exists
            If *ImageBuffer And ImageSize
              SetDatabaseLong(#SQLDB_TARGET,0,Id)
              SetDatabaseBlob(#SQLDB_TARGET,1,*ImageBuffer,ImageSize)
              If DatabaseUpdate(#SQLDB_TARGET,#SQL_INSERTRECORD)
                AddGadgetItem(#GAD_ED_REPORT,-1,"    Copy to target DB : Ok")
              EndIf
            EndIf
            If *ImageBuffer:FreeMemory(*ImageBuffer):EndIf
          Else
            AddGadgetItem(#GAD_ED_REPORT,-1,RecordReport+" & No blob")
          EndIf
        Wend
        DatabaseUpdate(#SQLDB_TARGET,"COMMIT")
        FinishDatabaseQuery(#SQLDB_SOURCE)
      EndIf
      SetGadgetData(#GAD_BT_COPYDATA,1)
      SetGadgetText(#GAD_BT_COPYDATA,"Retrieve data from target table")
    Case 1
      ; ----------------------------
      ; Target table data retrieving 
      ; ----------------------------
      AddGadgetItem(#GAD_ED_REPORT,-1,"")
      AddGadgetItem(#GAD_ED_REPORT,-1,"Selection of target table records")
      If DatabaseQuery(#SQLDB_TARGET,#SQL_GETRECORDS,#PB_Database_StaticCursor)
        While NextDatabaseRow(#SQLDB_TARGET)
          ImageSize=DatabaseColumnSize(#SQLDB_TARGET,1)
          RecordReport="  Record "+GetDatabaseString(#SQLDB_TARGET,0)+" : ImageSize : "+Str(ImageSize)
          If ImageSize
            *ImageBuffer=AllocateMemory(ImageSize)
            If *ImageBuffer
              If GetDatabaseBlob(#SQLDB_TARGET,1,*ImageBuffer,ImageSize)
                RecordReport+" & Blob ok"
              Else
                ImageSize=0
                RecordReport+" & Error blob"
              EndIf
            Else
              MessageRequester("","Memory allocation error!",#PB_MessageRequester_Error)
            EndIf
            AddGadgetItem(#GAD_ED_REPORT,-1,RecordReport)
            ;
            ; Image catching to display it in ImageGadget
            If *ImageBuffer And ImageSize
              If CatchImage(#IMG_IMAGE,*ImageBuffer)
                SetGadgetState(#GAD_IMG_IMAGEPB,ImageID(#IMG_IMAGE))
                AddGadgetItem(#GAD_ED_REPORT,-1,"    Image displaying")
              EndIf
            EndIf
            If *ImageBuffer:FreeMemory(*ImageBuffer):EndIf
          Else
            AddGadgetItem(#GAD_ED_REPORT,-1,RecordReport+" & No blob")
          EndIf
        Wend
        FinishDatabaseQuery(#SQLDB_SOURCE)
      EndIf
      DisableGadget(#GAD_BT_COPYDATA,#True)
      Pc_DBsClosing() ; Closing bases here only because they're no longer needed afterwards
                      ; However, as long as the application is not closed, you can consult the target table with a DB manager to see what the blob contains.
  EndSelect  
EndProcedure
Procedure   Pc_DisplayUI()
  Protected.i Event,EventType,GadgetNb
  
  OpenWindow(#WIN_MAIN,0,0,400,310,"Test",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  EditorGadget(#GAD_ED_REPORT,10,10,380,200,#PB_Editor_ReadOnly|#PB_Editor_WordWrap)
  ButtonGadget(#GAD_BT_COPYDATA,10,220,380,22,"Copy data from source DB to target DB")
  ImageGadget(#GAD_IMG_IMAGEPB,116,260,168,35,0)
  Repeat
    Event=WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow:Break
      Case #PB_Event_Gadget
        GadgetNb=EventGadget()
        Select EventType()
          Case #PB_EventType_LeftClick
            Select GadgetNb
              Case #GAD_BT_COPYDATA:Pc_SourceRecordsCopying()
            EndSelect
          EndSelect
    EndSelect
  ForEver
EndProcedure
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
; ╔════════════╗
; β•‘ MAIN CALLS β•‘
; β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
If Fc_DBsCreation()
  Pc_DisplayUI()
  Fc_DBsDeletion()
EndIf
End
;-══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
; ╔═════════════╗
; β•‘ DATASECTION β•‘
; β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•
DataSection
ImagePB_Start:  
  IncludeBinary #PB_Compiler_Home+"\Examples\Sources\Data\PureBasic.bmp"
ImagePB_End:  
EndDataSection
Β 
Note: Don't hesitate to use folding to better understand code structure :wink: