Portable Sqlite Query module

Share your advanced PureBasic knowledge/code with the community.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Portable Sqlite Query module

Post by Fangbeast »

This is based around the portable MySQL query module I made last year and came about as a result of someone asking me to update LarsG and my tutorial (Which I haven't done yet!) but I needed the module myself, so here it is.

As usual, use it if you like it, don't bother me if you don't. Not as well commented as I would like but it's free. And I get very tired these days. Play with it, update it, fix it, whatever you like. Read the top of the code for dependancies and change library path in datasection.

Code: Select all

;==============================================================================================================================
; Please note that all the SQLite direct database code I found in the PureBasic forum, done by El_Chonie, not by me.
;
; *NOTE* There is no syntax checking on database statements, I simply don't have that sort of time on my hands, nor the
; experience needed. This should be enough for most people.
;
; If you like it, say thanks to El_Choni and (me too maybe???). If you don't like it, I don't want to know. Fang.
;
; DEPENDANCIES
;
; Purevision gadgets library.   I will fix this in a future version.
; SQLite v3.x DLL               I'm using the UPX'ed version. Check this code.
; PBOSL LoadDLLFromMemory.      Very useful stuff
; 
;==============================================================================================================================
; Any procedural declarations for out-of-order procedure processing
;==============================================================================================================================

Declare.s AddDateSuffix(Date.s)                          ; Add the abbreviated date suffix
Declare   GetDayOfWeek(Gadget.l)                         ; Get the day of the week in name form
Declare   AddToDisplay(Gadget.l, Text.s, IconItem.l)     ; Add icons to addrecord and editrecord forms
Declare   CountRecords()                                 ; Return the number of records in a database
Declare   Display()                                      ; Shorten the amount of typing we have to do in a ListIconGadget
Declare   FlushEvents()                                  ; Prevent forms from greying out
Declare   LastLine(Gadget.l)                             ; Always go to the last line of a list object
Declare   SetDate(Windowid.l)                            ; Set the current date in the title bar
Declare   SetStat(Field.l, Message.s)                    ; Shortcut to setting text on the status bar
Declare   GetAllChildHandles(Winhandle)                  ; Get the status bar handle
Declare.s RepQuote(Instring.s)                           ; Properly replace single quotes with double for SQL passing
Declare.s KillQuote(Instring.s)                          ; Kill double quotes in strings for display purposes

;==============================================================================================================================
; El_Choni's sqlite 3 code
;==============================================================================================================================

Declare.l SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l)  ; Return data from an SQLite table to a linked list

;============================================================================================================================
; Visual designer created 
;============================================================================================================================

Global BubbleTipStyle.l

;============================================================================================================================
; Visual designer created 
;============================================================================================================================

BubbleTipStyle = 0

;============================================================================================================================
; Visual designer created 
;============================================================================================================================

Enumeration 1
  #Window_mysqlitetest
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #Gadget_mysqlitetest_fmain
  #Gadget_mysqlitetest_datalist
  #Gadget_mysqlitetest_fquery
  #Gadget_mysqlitetest_lquery
  #Gadget_mysqlitetest_query
  #Gadget_mysqlitetest_cbquery
  #Gadget_mysqlitetest_fcontrol
  #Gadget_mysqlitetest_bgetdatabase
  #Gadget_mysqlitetest_ltables
  #Gadget_mysqlitetest_tables
  #Gadget_mysqlitetest_lcolumns
  #Gadget_mysqlitetest_columns
  #Gadget_mysqlitetest_bload
  #Gadget_mysqlitetest_bsave
  #Gadget_mysqlitetest_fother
  #Gadget_mysqlitetest_helpbutton
  #Gadget_mysqlitetest_exitbutton
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #StatusBar_mysqlitetest
  #StatusBar_mysqlitetest_messages = 0
EndEnumeration

#StatusBarIndex = #PB_Compiler_EnumerationValue

;============================================================================================================================
; Visual designer created 
;============================================================================================================================

Procedure.l Window_mysqlitetest()
  If OpenWindow(#Window_mysqlitetest,48,74,800,575,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible,"SQLite - ")
    Brush.LOGBRUSH\lbColor=16625764
    SetClassLong_(WindowID(#Window_mysqlitetest),#GCL_HBRBACKGROUND,CreateBrushIndirect_(Brush))
    If CreateGadgetList(WindowID(#Window_mysqlitetest))
      Frame3DGadget(#Gadget_mysqlitetest_fmain,0,0,640,510,"")
      ListIconGadget(#Gadget_mysqlitetest_datalist,5,10,630,495,"itemslist",1000,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
        SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist),#LVM_SETBKCOLOR,0,16625764)
        SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist),#LVM_SETTEXTBKCOLOR,0,16625764)
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_datalist,"All items returned from a properly formatted SQL query will end up in this list and be cleared in  the next call",BubbleTipStyle)
      Frame3DGadget(#Gadget_mysqlitetest_fquery,0,510,640,45,"")
      TextGadget(#Gadget_mysqlitetest_lquery,10,530,60,15,"Query  ",#PB_Text_Right)
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_lquery,0,16625764)
      StringGadget(#Gadget_mysqlitetest_query,70,525,470,20,"")
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_query,0,16625764)
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_query,"Type in a properly formatted SQL query in here and press ENTER/RETURN to execute it",BubbleTipStyle)
      CheckBoxGadget(#Gadget_mysqlitetest_cbquery,550,530,80,15,"Clear list")
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_cbquery,0,16625764)
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_cbquery,"Select this button to clear the list before the next SQL query",BubbleTipStyle)
      Frame3DGadget(#Gadget_mysqlitetest_fcontrol,645,0,155,510,"")
      ButtonGadget(#Gadget_mysqlitetest_bgetdatabase,655,15,135,20,"Open Database")
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_bgetdatabase,"press this button to dump the results of the query to a disk file",BubbleTipStyle)
      TextGadget(#Gadget_mysqlitetest_ltables,655,45,135,15,"Table names in database",#PB_Text_Center)
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_ltables,0,16625764)
      ListViewGadget(#Gadget_mysqlitetest_tables,655,60,135,280)
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_tables,0,16625764)
      TextGadget(#Gadget_mysqlitetest_lcolumns,655,345,135,15,"Columns names in table",#PB_Text_Center)
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_lcolumns,0,16625764)
      ListViewGadget(#Gadget_mysqlitetest_columns,655,360,135,95)
        PVDynamic_AddColorGadget(#Gadget_mysqlitetest_columns,0,16625764)
      ButtonGadget(#Gadget_mysqlitetest_bload,655,460,135,20,"Load saved sql dump")
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_bload,"press this button to dump the results of the query to a disk file",BubbleTipStyle)
      ButtonGadget(#Gadget_mysqlitetest_bsave,655,480,135,20,"Save sql dump to disk")
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_bsave,"press this button to dump the results of the query to a disk file",BubbleTipStyle)
      Frame3DGadget(#Gadget_mysqlitetest_fother,645,510,155,45,"")
      ButtonGadget(#Gadget_mysqlitetest_helpbutton,655,525,60,20,"Help")
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_helpbutton,"press this button to show any help file linked to this program",BubbleTipStyle)
      ButtonGadget(#Gadget_mysqlitetest_exitbutton,730,525,60,20,"Exit")
        PVGadgets_BubbleTip(#Window_mysqlitetest,#Gadget_mysqlitetest_exitbutton,"press this button to exit this program immediately",BubbleTipStyle)
      PVDynamic_AddStatusBar(#Window_mysqlitetest,#StatusBar_mysqlitetest,CreateStatusBar(#StatusBar_mysqlitetest,WindowID(#Window_mysqlitetest)),1)
        AddStatusBarField(800)
      PVDynamic_AddLockWindow(#Window_mysqlitetest,#StatusBar_mysqlitetest,1,3)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_fmain,3)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_datalist,3)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_fquery,6)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_lquery,4)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_query,6)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_cbquery,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_fcontrol,9)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_bgetdatabase,8)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_ltables,8)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_tables,9)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_lcolumns,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_columns,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_bload,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_bsave,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_fother,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_helpbutton,12)
      PVDynamic_AddGadget(#Window_mysqlitetest,#Gadget_mysqlitetest_exitbutton,12)
      HideWindow(#Window_mysqlitetest,0)
      ProcedureReturn WindowID()
    EndIf
  EndIf
EndProcedure

;==============================================================================================================================
; SQLite 3 related found by El_Choni
;==============================================================================================================================

#SQLITE3_OK                   =   0     ; Successful Result
#SQLITE3_ERROR                =   1     ; SQL error Or missing database
#SQLITE3_INTERNAL             =   2     ; An internal logic error in SQLite
#SQLITE3_PERM                 =   3     ; Access permission denied
#SQLITE3_ABORT                =   4     ; Callback routine requested An abort
#SQLITE3_BUSY                 =   5     ; The database file is locked
#SQLITE3_LOCKED               =   6     ; A table in The database is locked
#SQLITE3_NOMEM                =   7     ; A malloc() failed
#SQLITE3_READONLY             =   8     ; Attempt To write A readonly database
#SQLITE3_INTERRUPT            =   9     ; Operation terminated by SQLite_Interrupt()
#SQLITE3_IOERR                =  10     ; Some kind of disk I/O error occurred
#SQLITE3_CORRUPT              =  11     ; The database disk image is malformed
#SQLITE3_NOTFOUND             =  12     ; (internal Only) table Or record not found
#SQLITE3_FULL                 =  13     ; Insertion failed because database is full
#SQLITE3_CANTOPEN             =  14     ; Unable To open The database file
#SQLITE3_PROTOCOL             =  15     ; database lock protocol error
#SQLITE3_EMPTY                =  16     ; (internal Only) database table is empty
#SQLITE3_SCHEMA               =  17     ; The database schema changed
#SQLITE3_TOOBIG               =  18     ; Too much Data For one Row of A table
#SQLITE3_CONStraint           =  19     ; abort due To contraint violation
#SQLITE3_MISMATCH             =  20     ; Data type mismatch
#SQLITE3_MISUSE               =  21     ; Library used incorrectly
#SQLITE3_NOLFS                =  22     ; Uses OS features not supported on host
#SQLITE3_AUTH                 =  23     ; Authorization denied
#SQLITE3_ROW                  = 100     ; sqlite_step() has another Row ready
#SQLITE3_DONE                 = 101     ; sqlite_step() has finished executing

;============================================================================================================================
; API date gadget date selection selection
;============================================================================================================================

#DTM_FIRST                    = $1000
#DTM_SETFORMAT                = $1005
#DTS_SHOWNONE                 = $2
#MCM_GETCURSEL                = $1001
#MCM_SETCURSEL                = $1002
#GDT_NONE                     = $1
#DTM_SETSYSTEMTIME            = #DTM_FIRST + 2
#DTM_GETSYSTEMTIME            = #DTN_FIRST + 1

;============================================================================================================================
; My personal constants
;============================================================================================================================

#Version                      = "v0.00"                                       ; Program version
#CopyRight                    = "<°)))o><²³  SQLite data test(c) " + #Version ; Copyright string

#Eol                          = Chr(10) + Chr(13)                             ; End of line marker

;==============================================================================================================================
; My personal constants
;==============================================================================================================================

Enumeration #GadgetIndex
  #Gadget_mysqlitetest_return
EndEnumeration

;==============================================================================================================================
; Common controls structure size
;==============================================================================================================================

dt.INITCOMMONCONTROLSEX\dwSize  = SizeOf(INITCOMMONCONTROLSEX) 
dt\dwICC                        = $100 

InitCommonControlsEx_(@dt) 

;==============================================================================================================================
; Constants for statusbar handling
;==============================================================================================================================

#SB_SETBKCOLOR          = $2001 ; Statusbar colour constant

Colour                  = RGB($E9, $DA, $87)

;============================================================================================================================
; Object colouring in the callback (used later when visual designer library isn't used)
;============================================================================================================================

;Colour  = RGB($FF,$FF,$AA)

Yellow  = CreateSolidBrush_($70DCFC)
Green   = CreateSolidBrush_($7BDF84)
Blue    = CreateSolidBrush_($E5B91A)

;============================================================================================================================
; Custom date routine structure
;==============================================================================================================================

Structure DateStructure ; Custom date routine
  Year.w
  Month.w
  DayOfWeek.w
  Day.w
  Hour.w
  Minute.w
  Second.w
  Milliseconds.w
EndStructure

;==============================================================================================================================
; Window data structure
;==============================================================================================================================

Structure windowdata   ; Window structure data
  winhandle.l           ; Main window handle
  statushandle.l        ; Status bar handle
  newstatwidth.l        ; New status bar width
  oldstatwidth.l        ; Old status bar width
EndStructure

;==============================================================================================================================
; Program data structure
;==============================================================================================================================

Structure programdata  ; Program data structure
  curdir.s              ; Current program startup directory
  progname.s            ; Program name for base filename saves
  libfile.s             ; SQLite dll file, in current directory
  dbhandle.l            ; Handle to the currently open database
  dbname.s              ; Name of the database to open
  dbopen.l              ; Is the database open or not
  query.s               ; Current sql query string
  progquit.l            ; User quit the program, so set the quit value to allow program to end repeat loop
  numitems.l            ; Always the true number of items in the database
  curline.l             ; Always the current line in the list object
  record.s              ; Program record pointer to true database record number
  daynum.l              ; Numerical day of the week mapped to word format
  inifile.s             ; Name and path of the options file
  weekday.s             ; Day of the week in name form
  column.s              ; Name of the highlighted column
  table.s               ; Name of the highlighted table
  colnum.l              ; Number of columns in the returned query
EndStructure

;==============================================================================================================================
; New list to hold returned sqlite data
;==============================================================================================================================

NewList SqlData.s()

;==============================================================================================================================
; All global variables
;==============================================================================================================================

Global program.programdata, form.windowdata

Global sqlite3_open.l,sqlite3_exec.l, sqlite3_close.l, sqlite3_errmsg.l, sqlite3_get_table.l, sqlite3_free_table.l
Global sqlite3_changes, sqlite3_last_insert_rowid, sqlite3_free

;==============================================================================================================================
; Get current direectory and store it for later
;==============================================================================================================================

program\curdir = Space(512)                                          ; Give the variable enough space

If GetCurrentDirectory_(Len(program\curdir), @program\curdir) <> 0   ; Get the current directory
  If Right(program\curdir, 1) <> "\"                                 ; Each O/S does it differently so check for backspace
    program\curdir + "\"
  EndIf
EndIf

;==============================================================================================================================
; Create local picture and icon directory variables
;==============================================================================================================================

program\progname     = "Sqlite Data Test"                       ; Constant program name
program\libfile      = program\curdir + "sqlite3upx.dll"        ; SQLite 3 dll file
program\inifile      = program\curdir + "Sqlite Data Test.ini"  ; The name and path of the program options file 

;==============================================================================================================================
; Setup day and month literal names
;==============================================================================================================================

Dim NameOfDay.s(7)                                        ; Fill an array with the names of the days (Terry Hough I think)

  NameOfDay(0)      = "Sunday"
  NameOfDay(1)      = "Monday"
  NameOfDay(2)      = "Tuesday"
  NameOfDay(3)      = "Wednesday"  
  NameOfDay(4)      = "Thursday"
  NameOfDay(5)      = "Friday"
  NameOfDay(6)      = "Saturday"

Dim DaysPerMonth(12)                                      ; Fill an array on how many days per month there are

  For X = 0 To 11     
    DaysPerMonth(X) = 31 
  Next

  DaysPerMonth(1)   = 28
  DaysPerMonth(3)   = 30
  DaysPerMonth(5)   = 30
  DaysPerMonth(8)   = 30

  DaysPerMonth(10)  = 30

Dim NameOfMonth.s(12)                                    ; fill an array with the names of the months

  NameOfMonth(0)    = "January"
  NameOfMonth(1)    = "February"
  NameOfMonth(2)    = "March" 
  NameOfMonth(3)    = "April"
  NameOfMonth(4)    = "May"
  NameOfMonth(5)    = "June" 
  NameOfMonth(6)    = "July"
  NameOfMonth(7)    = "August"
  NameOfMonth(8)    = "September"
  NameOfMonth(9)    = "October"
  NameOfMonth(10)   = "November"
  NameOfMonth(11)   = "December"

Dim Years.s(7)                                           ; fill an array with the years

  Years(0)          = "2002"
  Years(1)          = "2003"
  Years(2)          = "2004"
  Years(3)          = "2005"
  Years(4)          = "2006" 
  Years(5)          = "2007"
  Years(6)          = "2008"

;==============================================================================================================================
; Any included data in the final exe
;==============================================================================================================================

DataSection
  sqlite3_dll : IncludeBinary "Libraries\sqlite3upx.dll"
EndDataSection

;============================================================================================================================
; Adds a suffix To the End of a <= 31 numeral 'date'
;============================================================================================================================

Procedure.s AddDateSuffix(Date.s)
  If Date = "1" Or Date = "21" Or Date = "31"
    Date = Date + "st"
  ElseIf Date = "2" Or Date = "22"
    Date = Date + "nd"
  ElseIf Date = "3" Or Date = "23"
    Date = Date + "rd"
  Else
    Date = Date + "th"
  EndIf
  ProcedureReturn Date
EndProcedure

;============================================================================================================================
; Get the current date and the day of the week in word form
;============================================================================================================================

Procedure GetDayOfWeek(Gadget.l)
  program\daynum = DayOfWeek(ParseDate("%dd/%mm/%yyyy", GetGadgetText(Gadget.l)))
  Select program\daynum
    Case 0 : program\weekday = "Sunday"
    Case 1 : program\weekday = "Monday" 
    Case 2 : program\weekday = "Tuesday" 
    Case 3 : program\weekday = "Wednesday"
    Case 4 : program\weekday = "Thursday"
    Case 5 : program\weekday = "Friday"
    Case 6 : program\weekday = "Saturday"
  EndSelect
EndProcedure

;============================================================================================================================
; Add an item to the end of any ListIconGadget display
;============================================================================================================================

Procedure AddToDisplay(Gadget.l, Text.s, IconItem.l)
  AddGadgetItem(Gadget.l, -1, Text.s, UseImage(iconItem))
EndProcedure

;============================================================================================================================
; Count the number of records in an SQLite database
;============================================================================================================================

Procedure CountRecords()
  If SQL3GetTable("Select Count(record) AS totalrecs FROM addresses", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      LastElement(SqlData.s())
      ProcedureReturn Val(StringField(SqlData.s(), 1, "|"))
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: Could not get the number of records in the database")
    ProcedureReturn 0
  EndIf  
EndProcedure

;============================================================================================================================
; Clear the windows event buffer to avoid greying out of forms
;============================================================================================================================

Procedure FlushEvents()
  While WindowEvent()
  Wend
EndProcedure

;============================================================================================================================
; Set the last line of a ListIconGadget
;============================================================================================================================

Procedure LastLine(Gadget.l)
  SendMessage_(GadgetID(Gadget.l), #LVM_ENSUREVISIBLE, CountGadgetItems(Gadget.l) -1,0) ; Make sure the current line is visible
EndProcedure

;============================================================================================================================
; Sort out the date and display it
;============================================================================================================================

Procedure SetDate(Windowid.l)
  newDate.dateStructure
  GetSystemTime_(@newDate)
  WeekDay.b = newDate\DayOfWeek
  Day.b     = newDate\Day
  Month.b   = newDate\Month
  Year.w    = newDate\Year
  CurrentDate.s = NameOfDay(WeekDay) + ", " + AddDateSuffix(Str(Day)) + ", " + NameOfMonth(Month - 1) + ", " + Str(Year)
  SetWindowTitle(Windowid.l, #CopyRight + "   --   Today is " + CurrentDate.s)
EndProcedure

;============================================================================================================================
; Custom statusbar routine
;============================================================================================================================

Procedure SetStat(Field.l, Message.s)
  StatusBarText(#StatusBar_mysqlitetest, Field.l, Message.s, 0)
EndProcedure

;============================================================================================================================
; Get data back from an SQLite database table and stuff it into a concatenated linked list
;============================================================================================================================

Procedure.l SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l)
  ClearList(SqlData.s())
  If CallCFunctionFast(sqlite3_get_table, lDataBaseHandle, sSQLQuery, @LResultsPtr, @LRows, @LCols, @ReturnValue) = #SQLITE3_OK
    PokeL(*Rows, LRows)                                     ; return number of rows/columns
    PokeL(*Cols, LCols)
    If LRows > -1 And LCols > 0
      Address.l  = LResultsPtr                              ; copy data into array
      For Row.l  = 1 To LRows
        For Col.l  = 0 To LCols - 1
          tempdata.s + PeekS(PeekL(Address + (((Row * LCols) + Col) * 4))) + "|"
        Next
       AddElement(SqlData.s())
       SqlData.s() = tempdata
       tempdata.s = ""
      Next
    EndIf
    CallCFunctionFast(sqlite3_free_table, LResultsPtr)      ; free table memory
    ProcedureReturn #True
  Else
    CallCFunctionFast(sqlite3_errmsg, @ReturnValue)
    Debug PeekS(ReturnValue)
    ProcedureReturn #False
  EndIf
EndProcedure  

;============================================================================================================================
; Find the handle to a specific child on a window. In this case, the status bar.
;============================================================================================================================

Procedure GetAllChildHandles(Winhandle)
  Childhandle = GetWindow_(Winhandle, #GW_CHILD)
  Repeat
    Namespace.s = Space(999)
    GetClassName_(Childhandle, Namespace.s, 999)
    If Namespace.s = "msctls_statusbar32"
      Form\Statushandle = Childhandle
    EndIf
    Childhandle = GetWindow_(Childhandle, #GW_HWNDNEXT)
  Until Childhandle = 0
EndProcedure

;============================================================================================================================
; Simplify the creation of API calendar gadgets
;============================================================================================================================

Procedure DateInputGadget(x, y, width_, height_) 
  hCal = CreateWindowEx_(0, "SysDateTimePick32", "DateTime", #WS_CHILD | #WS_VISIBLE |#WS_BORDER | #DTS_SHOWNONE, x, y, width_, height_, WindowID(), 0, GetModuleHandle_(0), 0) 
  SetWindowLong_(hCal, #GWL_STYLE, GetWindowLong_(hCal, #GWL_STYLE) | #WS_TABSTOP) 
  ProcedureReturn hCal
EndProcedure 

;============================================================================================================================
; Uncle Berikco's routine to properly replace single quotes with double for SQL passing
;============================================================================================================================

Procedure.s RepQuote(Instring.s)
  For i = 1 To Len(Instring.s)
    If Mid(Instring.s, i, 1) = "'"
      tmp.s = tmp.s + "''"
    Else
      tmp.s = tmp.s + Mid(Instring.s, i, 1)
    EndIf
  Next i
  ProcedureReturn tmp.s
EndProcedure

;============================================================================================================================
; Kill double quotes in strings for display purposes
;============================================================================================================================

Procedure.s KillQuote(Instring.s)
  ProcedureReturn ReplaceString(Instring.s, "''", "'", 1, 1)
EndProcedure

;============================================================================================================================
; Initialise the SQLite dll, create the datebase and the table if they don't exist
;============================================================================================================================

sqlite3_lib                 = LoadLibraryM(?sqlite3_dll)  ; Load the library from memory, don't write to disk

If sqlite3_lib
  sqlite3_open              = GetProcAddressM(sqlite3_lib, "sqlite3_open")
  sqlite3_exec              = GetProcAddressM(sqlite3_lib, "sqlite3_exec")
  sqlite3_close             = GetProcAddressM(sqlite3_lib, "sqlite3_close")
  sqlite3_errmsg            = GetProcAddressM(sqlite3_lib, "sqlite3_errmsg")
  sqlite3_get_table         = GetProcAddressM(sqlite3_lib, "sqlite3_get_table")
  sqlite3_free_table        = GetProcAddressM(sqlite3_lib, "sqlite3_free_table")
  sqlite3_changes           = GetProcAddressM(sqlite3_lib, "sqlite3_sqlite3_changes")
  sqlite3_last_insert_rowid = GetProcAddressM(sqlite3_lib, "sqlite3_last_insert_rowid")
  sqlite3_free              = GetProcAddressM(sqlite3_lib, "sqlite3_free")
Else
  MessageRequester("SQLite3 Error", "Could not initialise the sqlite3upx.dll library file, can't find it or load it")
  End
EndIf 

;============================================================================================================================
; Visual designer created 
;============================================================================================================================

Procedure WindowCallback(WindowID, Message, wParam, lParam)
  ReturnValue = #PB_ProcessPureBasicEvents
  If Message = #WM_GETMINMAXINFO
    ReturnValue = PVDynamic_LockWindow(WindowID, lParam)
  EndIf
  If Message = #WM_SIZE
    ReturnValue = PVDynamic_Resize(WindowID)
  EndIf
  If Message = #WM_CTLCOLORSTATIC Or Message = #WM_CTLCOLOREDIT Or Message = #WM_CTLCOLORLISTBOX
    ReturnValue = PVDynamic_ColorGadget(lParam, wParam)
  EndIf
  ProcedureReturn ReturnValue
EndProcedure

;============================================================================================================================
; Main event handler for the window
;============================================================================================================================

If Window_mysqlitetest()

  ;----------------------------------------------------------------------------------------------------------
  ; Add a return keyboard shortcut to enter queries
  ;----------------------------------------------------------------------------------------------------------
  AddKeyboardShortcut(#Window_mysqlitetest, #PB_Shortcut_Return, #Gadget_mysqlitetest_return)
  
  ;----------------------------------------------------------------------------------------------------------
  ; Standard windows callback made by visual designer for resizing, colouring etc
  ;----------------------------------------------------------------------------------------------------------
  SetWindowCallback(@WindowCallback())

  ;----------------------------------------------------------------------------------------------------------
  ; Get windows handle for tray hiding and other functions
  ;----------------------------------------------------------------------------------------------------------
  form\winhandle = WindowID(#Window_mysqlitetest)

  ;----------------------------------------------------------------------------------------------------------
  ; Find status bar handle and save it to Form\Statushandle
  ;----------------------------------------------------------------------------------------------------------
  GetAllChildHandles(form\winhandle)
  
  ;----------------------------------------------------------------------------------------------------------
  ; Change the status bar colour to whatever we want now that we have found the handle to it
  ;----------------------------------------------------------------------------------------------------------
  SendMessage_(form\statushandle, #SB_SETBKCOLOR, 0, Colour)
  
  ;----------------------------------------------------------------------------------------------------------
  ;Set the program day and date in the title bar
  ;----------------------------------------------------------------------------------------------------------
  SetDate(#Window_mysqlitetest)                                  ; Set current date on form title

  ;----------------------------------------------------------------------------------------------------------
  ; Let the user know that the database is open via the status bar
  ;----------------------------------------------------------------------------------------------------------
  SetStat(#StatusBar_mysqlitetest_messages, "Information: The sqlite3upx.dll library file was loaded, The SQLite 3.x environment is ready to go")
  
  ;----------------------------------------------------------------------------------------------------------
  ; Set initial quit value to 0 so that program doesn't accidentally close
  ;----------------------------------------------------------------------------------------------------------
  program\progquit = 0

  Repeat
    EventID  = WaitWindowEvent()
    MenuID   = EventMenuID()
    GadgetID = EventGadgetID()
    WindowID = EventWindowID()

    Select EventID
      Case #PB_Event_CloseWindow
        If WindowID = #Window_mysqlitetest
          program\progquit = 1
        EndIf

      Case #PB_Event_Menu
        Select MenuID
          Case #Gadget_mysqlitetest_return        : Gosub CheckEnterKey     ; See if ENTER was pressed in query box
        EndSelect
        
      Case #PB_Event_Gadget
        Select GadgetID
          Case #Gadget_mysqlitetest_bgetdatabase  : Gosub OpenADatabase     ; Open a database to process
          Case #Gadget_mysqlitetest_tables        : Gosub GetColumnName     ; Get the columns of the highlighted table
          Case #Gadget_mysqlitetest_bload         : Gosub LoadListFromDisk  ; Load the last sql dump from disk
          Case #Gadget_mysqlitetest_bsave         : Gosub SaveListToDisk    ; Save the sql dump to disk
          Case #Gadget_mysqlitetest_helpbutton    : Gosub HelpWanted        ; Show a help screen to the user
          Case #Gadget_mysqlitetest_exitbutton    : program\progquit = 1     ; Set the quit flag
        EndSelect
    EndSelect
  Until program\progquit
  CloseWindow(#Window_mysqlitetest)
EndIf
End

;============================================================================================================================
OpenADatabase:                    ; Open a database to process
;============================================================================================================================

  program\dbname = OpenFileRequester("Database to open", "", "Database file (*.*)|*.*", 0)
  
  If CallCFunctionFast(sqlite3_open, program\dbname, @program\dbhandle) = #SQLITE3_OK
    program\dbopen = 1
    SetStat(#StatusBar_mysqlitetest_messages, "Information: The database " + program\dbname + " was opened successfully, program ready")
    Gosub GetTableNames
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The database " + program\dbname + " could not be opened")
  EndIf
  
Return

;============================================================================================================================
GetTableNames:                    ; Get a list of the table names in the current database
;============================================================================================================================

  program\query = "Select name FROM sqlite_master WHERE type='table' ORDER BY name"

  If SQL3GetTable(program\query, @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      ForEach SqlData.s()
        AddGadgetItem(#Gadget_mysqlitetest_tables, -1, RemoveString(SqlData.s(), "|", 0))
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no tables")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The table information could not be retrieved")  
  EndIf
  
Return

;============================================================================================================================
GetColumnName:
;============================================================================================================================

  program\table = GetGadgetItemText(#Gadget_mysqlitetest_tables, GetGadgetState(#Gadget_mysqlitetest_tables), 0)
  
  program\query = "PRAGMA table_info(" + program\table + ")"
  
  If SQL3GetTable(program\query, @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      ClearGadgetItemList(#Gadget_mysqlitetest_columns)
      ForEach SqlData.s()
        AddGadgetItem(#Gadget_mysqlitetest_columns, -1, StringField(SqlData.s(), 2, "|"))
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no columns")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The column information could not be retrieved")  
  EndIf
  
Return

;============================================================================================================================
CheckEnterKey:                    ; See if ENTER was pressed in query box
;============================================================================================================================

  FocusID = GetFocus_()                                          ; Get the id of the window/object that has focus

  Select FocusID                                                 ; Use the id in a gadget selection
    Case GadgetID(#Gadget_mysqlitetest_query)                    ; Gadget is the barcode box
      program\query = GetGadgetText(#Gadget_mysqlitetest_query)  ; Get the text from the query box
      Gosub RunDatabaseQuery                                     ; Reusable data return routine
  EndSelect                                                     ; End the selection

Return

;============================================================================================================================
LoadListFromDisk:                 ; Load the last sql dump from disk
;============================================================================================================================

Return

;============================================================================================================================
SaveListToDisk:                   ; Save the sql dump to disk
;============================================================================================================================

  If CreateFile(0, SaveFileRequester("Save returned query", "QueryDump.txt", "Text (*.txt)|*.txt|All files (*.*)|*.*", 0)) <> 0
    For ListItems = 0 To CountGadgetItems(#Gadget_mysqlitetest_datalist) - 1
      For TotalColumns = 0 To program\colnum - 1
        OutString.s + GetGadgetItemText(#Gadget_mysqlitetest_datalist, ListItems, TotalColumns) + ";"
      Next TotalColumns
      WriteStringN(OutString.s)
      OutString.s = ""
    Next ListItems
    CloseFile(0)
  Else
    SetWindowTitle(#Window_mysqltest, #MainTitle + "Cannot save the list to disk, something went wrong")
  EndIf

Return

;============================================================================================================================
RunDatabaseQuery:
;============================================================================================================================

  program\query = GetGadgetText(#Gadget_mysqlitetest_query)

  If program\colnum <> 0                                                  ; Remove columns from previous query
    For colremove = 1 To program\colnum - 1
      RemoveGadgetColumn(#Gadget_mysqlitetest_datalist, 1)
    Next colremove
    program\colnum = 0
  EndIf
  
  If SQL3GetTable(program\query, @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      ClearGadgetItemList(#Gadget_mysqlitetest_datalist)
      SelectElement(SqlData.s(), 0)
      program\colnum = CountString(SqlData.s(), "|")
      For coladd = 1 To program\colnum - 1                                       ;  Add number of columns = to no of fields
        AddGadgetColumn(#Gadget_mysqlitetest_datalist, 1, "Data", 100)
      Next coladd
      ForEach SqlData.s()
        FlushEvents()
        AddGadgetItem(#Gadget_mysqlitetest_datalist, -1, ReplaceString(SqlData.s(), "|", Chr(10), 1, 1))
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no data")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The database information could not be retrieved")  
  EndIf

  For WidthSet = 0 To program\colnum - 1  ; Auto set the field widths to biggest field
    SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist), #LVM_SETCOLUMNWIDTH, WidthSet, #LVSCW_AUTOSIZE)
  Next WidthSet

Return

;============================================================================================================================
HelpWanted:                       ; Show a help screen to the user
;============================================================================================================================


Return
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

OK Fangbeast, this should get me started, at least it will get you off the hook for tutorial for a while :lol:

Many thanks.

I'll probably be back with a few (00's) questions.

cheers

P.S. some folks may have problems finding sqlite3upx.dll - at least it took me a while. Not your problem but it did seem hard to find for me :?
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Post by chris319 »

some folks may have problems finding sqlite3upx.dll
Could you post a link to it?
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

OKay, new perversion..

Post by Fangbeast »

This one has been resized and all dependancies to the visual designer removed. So, all colours and resizing ability are gone but it's still good. Also the code has been reworked to make it more compact, a little more error resistant, more information etc. Redundant checkbox and load button removed. Icon references added for status bar and tray hiding, substitute your own.

Code: Select all

;============================================================================================================================
; Please note that all the SQLite direct database code I found in the PureBasic forum, done by El_Chonie, not by me.
;
; *NOTE* There is no syntax checking on database statements, I simply don't have that sort of time on my hands, nor the
; experience needed. This should be enough for most people.
;
; If you like it, say thanks to El_Choni and (me too maybe???). If you don't like it, I don't want to know. Fang.
;
; DEPENDANCIES:
;
; SQLite v3.x DLL               I'm using the UPX'ed version. Check this code.
; PBOSL LoadDLLFromMemory.      Very useful stuff
; 
;==============================================================================================================================
; Any declarations
;==============================================================================================================================

Declare.s AddDateSuffix(Date.s)                          ; Add the abbreviated date suffix
Declare   GetDayOfWeek(Gadget.l)                         ; Get the day of the week in name form
Declare   AddToDisplay(Gadget.l, Text.s, IconItem.l)     ; Add icons to addrecord and editrecord forms
Declare   CountRecords()                                 ; Return the number of records in a database
Declare   Display()                                      ; Shorten the amount of typing we have to do in a ListIconGadget
Declare   FlushEvents()                                  ; Prevent forms from greying out
Declare   LastLine(Gadget.l)                             ; Always go to the last line of a list object
Declare   SetDate(Windowid.l)                            ; Set the current date in the title bar
Declare   SetStat(Field.l, Message.s)                    ; Shortcut to setting text on the status bar
Declare   GetAllChildHandles(Winhandle)                  ; Get the status bar handle
Declare.s RepQuote(Instring.s)                           ; Properly replace single quotes with double for SQL passing
Declare.s KillQuote(Instring.s)                          ; Kill double quotes in strings for display purposes
Declare.s Sremove(InString.s, Direction.s, Length.l)     ; Remove strings from left or right side of input string

;==============================================================================================================================
; El_Choni's sqlite 3 code
;==============================================================================================================================

Declare.l SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l)  ; Return data from an SQLite table to a linked list

Enumeration 1
  #Window_mysqlitetest
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #Gadget_mysqlitetest_fmain
  #Gadget_mysqlitetest_datalist
  #Gadget_mysqlitetest_fquery
  #Gadget_mysqlitetest_lquery
  #Gadget_mysqlitetest_query
  #Gadget_mysqlitetest_fcontrol
  #Gadget_mysqlitetest_bgetdatabase
  #Gadget_mysqlitetest_ltables
  #Gadget_mysqlitetest_tables
  #Gadget_mysqlitetest_lcolumns
  #Gadget_mysqlitetest_columns
  #Gadget_mysqlitetest_bsave
  #Gadget_mysqlitetest_fother
  #Gadget_mysqlitetest_helpbutton
  #Gadget_mysqlitetest_exitbutton
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #StatusBar_mysqlitetest
  #StatusBar_mysqlitetest_messages  = 0
  #StatusBar_mysqlitetest_records   = 1
EndEnumeration

#StatusBarIndex = #PB_Compiler_EnumerationValue

Procedure.l Window_mysqlitetest()
  If OpenWindow(#Window_mysqlitetest,6,64,900,600,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible,"SQLite - ")
    If CreateGadgetList(WindowID(#Window_mysqlitetest))
      Frame3DGadget(#Gadget_mysqlitetest_fmain,0,0,710,535,"")
      ListIconGadget(#Gadget_mysqlitetest_datalist,5,10,700,520,"itemslist",2048,#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
      Frame3DGadget(#Gadget_mysqlitetest_fquery,0,535,710,40,"")
      TextGadget(#Gadget_mysqlitetest_lquery,10,555,45,15,"Query  ",#PB_Text_Right)
      StringGadget(#Gadget_mysqlitetest_query,55,550,650,20,"")
      Frame3DGadget(#Gadget_mysqlitetest_fcontrol,715,0,180,535,"")
      ButtonGadget(#Gadget_mysqlitetest_bgetdatabase,725,15,165,20,"Open Database")
      TextGadget(#Gadget_mysqlitetest_ltables,725,45,165,15,"Table names in database",#PB_Text_Center)
      ListViewGadget(#Gadget_mysqlitetest_tables,720,60,170,300)
      TextGadget(#Gadget_mysqlitetest_lcolumns,720,365,165,15,"Columns names in table",#PB_Text_Center)
      ListViewGadget(#Gadget_mysqlitetest_columns,720,380,170,125)
      ButtonGadget(#Gadget_mysqlitetest_bsave,720,510,170,20,"Save sql dump to disk")
        GadgetToolTip(#Gadget_mysqlitetest_bsave,"press this button to dump the results of the query to a disk file")
      Frame3DGadget(#Gadget_mysqlitetest_fother,715,535,180,40,"")
      ButtonGadget(#Gadget_mysqlitetest_helpbutton,720,550,85,20,"Help")
      ButtonGadget(#Gadget_mysqlitetest_exitbutton,805,550,85,20,"Exit")
      CreateStatusBar(#StatusBar_mysqlitetest,WindowID(#Window_mysqlitetest))
        AddStatusBarField(712)
        AddStatusBarField(200)
      HideWindow(#Window_mysqlitetest,0)
      ProcedureReturn WindowID()
    EndIf
  EndIf
EndProcedure

;==============================================================================================================================
; SQLite 3 related found by El_Choni
;==============================================================================================================================

#SQLITE3_OK                   =   0     ; Successful Result
#SQLITE3_ERROR                =   1     ; SQL error Or missing database
#SQLITE3_INTERNAL             =   2     ; An internal logic error in SQLite
#SQLITE3_PERM                 =   3     ; Access permission denied
#SQLITE3_ABORT                =   4     ; Callback routine requested An abort
#SQLITE3_BUSY                 =   5     ; The database file is locked
#SQLITE3_LOCKED               =   6     ; A table in The database is locked
#SQLITE3_NOMEM                =   7     ; A malloc() failed
#SQLITE3_READONLY             =   8     ; Attempt To write A readonly database
#SQLITE3_INTERRUPT            =   9     ; Operation terminated by SQLite_Interrupt()
#SQLITE3_IOERR                =  10     ; Some kind of disk I/O error occurred
#SQLITE3_CORRUPT              =  11     ; The database disk image is malformed
#SQLITE3_NOTFOUND             =  12     ; (internal Only) table Or record not found
#SQLITE3_FULL                 =  13     ; Insertion failed because database is full
#SQLITE3_CANTOPEN             =  14     ; Unable To open The database file
#SQLITE3_PROTOCOL             =  15     ; database lock protocol error
#SQLITE3_EMPTY                =  16     ; (internal Only) database table is empty
#SQLITE3_SCHEMA               =  17     ; The database schema changed
#SQLITE3_TOOBIG               =  18     ; Too much Data For one Row of A table
#SQLITE3_CONStraint           =  19     ; abort due To contraint violation
#SQLITE3_MISMATCH             =  20     ; Data type mismatch
#SQLITE3_MISUSE               =  21     ; Library used incorrectly
#SQLITE3_NOLFS                =  22     ; Uses OS features not supported on host
#SQLITE3_AUTH                 =  23     ; Authorization denied
#SQLITE3_ROW                  = 100     ; sqlite_step() has another Row ready
#SQLITE3_DONE                 = 101     ; sqlite_step() has finished executing

;============================================================================================================================
; API date gadget date selection selection
;============================================================================================================================

#DTM_FIRST                    = $1000
#DTM_SETFORMAT                = $1005
#DTS_SHOWNONE                 = $2
#MCM_GETCURSEL                = $1001
#MCM_SETCURSEL                = $1002
#GDT_NONE                     = $1
#DTM_SETSYSTEMTIME            = #DTM_FIRST + 2
#DTM_GETSYSTEMTIME            = #DTN_FIRST + 1

;============================================================================================================================
; My personal constants
;============================================================================================================================

#Version                      = "v0.00"                                       ; Program version
#CopyRight                    = "<°)))o><²³  SQLite data test(c) " + #Version ; Copyright string

#Eol                          = Chr(10) + Chr(13)                             ; End of line marker

;==============================================================================================================================
; My personal constants
;==============================================================================================================================

Enumeration #GadgetIndex
  #Gadget_mysqlitetest_return
  #Gadget_mysqlitetest_exit
EndEnumeration

Enumeration 1
  #Image_mysqlitetest_program
  #Image_mysqlitetest_messages
  #Image_mysqlitetest_records
EndEnumeration

#ImageIndex = #PB_Compiler_EnumerationValue

;==============================================================================================================================
; Common controls structure size
;==============================================================================================================================

dt.INITCOMMONCONTROLSEX\dwSize  = SizeOf(INITCOMMONCONTROLSEX) 
dt\dwICC                        = $100 

InitCommonControlsEx_(@dt) 

;==============================================================================================================================
; Constants for statusbar handling
;==============================================================================================================================

#SB_SETBKCOLOR          = $2001 ; Statusbar colour constant

Colour                  = RGB($E9, $DA, $87)

;============================================================================================================================
; Object colouring in the callback
;============================================================================================================================

;Colour  = RGB($FF,$FF,$AA)

Yellow  = CreateSolidBrush_($70DCFC)
Green   = CreateSolidBrush_($7BDF84)
Blue    = CreateSolidBrush_($E5B91A)

;============================================================================================================================
; Custom date routine structure
;==============================================================================================================================

Structure DateStructure ; Custom date routine
  Year.w
  Month.w
  DayOfWeek.w
  Day.w
  Hour.w
  Minute.w
  Second.w
  Milliseconds.w
EndStructure

;==============================================================================================================================
; Window data structure
;==============================================================================================================================

Structure windowdata   ; Window structure data
  winhandle.l           ; Main window handle
  statushandle.l        ; Status bar handle
  newstatwidth.l        ; New status bar width
  oldstatwidth.l        ; Old status bar width
EndStructure

;==============================================================================================================================
; Program data structure
;==============================================================================================================================

Structure programdata  ; Program data structure
  curdir.s              ; Current program startup directory
  progname.s            ; Program name for base filename saves
  libfile.s             ; SQLite dll file, in current directory
  dbhandle.l            ; Handle to the currently open database
  dbname.s              ; Name of the database to open
  dbopen.l              ; Is the database open or not
  query.s               ; Current sql query string
  progquit.l            ; User quit the program, so set the quit value to allow program to end repeat loop
  numitems.l            ; Always the true number of items in the database
  curline.l             ; Always the current line in the list object
  record.s              ; Program record pointer to true database record number
  daynum.l              ; Numerical day of the week mapped to word format
  inifile.s             ; Name and path of the options file
  weekday.s             ; Day of the week in name form
  column.s              ; Name of the highlighted column
  table.s               ; Name of the highlighted table
  colnum.l              ; Number of columns in the returned query
EndStructure

;==============================================================================================================================
; New list to hold returned sqlite data
;==============================================================================================================================

NewList SqlData.s()

;==============================================================================================================================
; All global variables
;==============================================================================================================================

Global program.programdata, form.windowdata

Global sqlite3_open.l,sqlite3_exec.l, sqlite3_close.l, sqlite3_errmsg.l, sqlite3_get_table.l, sqlite3_free_table.l
Global sqlite3_changes, sqlite3_last_insert_rowid, sqlite3_free

;==============================================================================================================================
; Get current direectory and store it for later
;==============================================================================================================================

program\curdir = Space(512)                                          ; Give the variable enough space

If GetCurrentDirectory_(Len(program\curdir), @program\curdir) <> 0   ; Get the current directory
  If Right(program\curdir, 1) <> "\"                                 ; Each O/S does it differently so check for backspace
    program\curdir + "\"
  EndIf
EndIf

;==============================================================================================================================
; Create local picture and icon directory variables
;==============================================================================================================================

program\progname     = "Sqlite Data Test"                       ; Constant program name
program\libfile      = program\curdir + "sqlite3upx.dll"        ; SQLite 3 dll file
program\inifile      = program\curdir + "Sqlite Data Test.ini"  ; The name and path of the program options file 

;==============================================================================================================================
; Setup day and month literal names
;==============================================================================================================================

Dim NameOfDay.s(7)                                        ; Fill an array with the names of the days (Terry Hough I think)

  NameOfDay(0)      = "Sunday"
  NameOfDay(1)      = "Monday"
  NameOfDay(2)      = "Tuesday"
  NameOfDay(3)      = "Wednesday"  
  NameOfDay(4)      = "Thursday"
  NameOfDay(5)      = "Friday"
  NameOfDay(6)      = "Saturday"

Dim DaysPerMonth(12)                                      ; Fill an array on how many days per month there are

  For X = 0 To 11     
    DaysPerMonth(X) = 31 
  Next

  DaysPerMonth(1)   = 28
  DaysPerMonth(3)   = 30
  DaysPerMonth(5)   = 30
  DaysPerMonth(8)   = 30

  DaysPerMonth(10)  = 30

Dim NameOfMonth.s(12)                                    ; fill an array with the names of the months

  NameOfMonth(0)    = "January"
  NameOfMonth(1)    = "February"
  NameOfMonth(2)    = "March" 
  NameOfMonth(3)    = "April"
  NameOfMonth(4)    = "May"
  NameOfMonth(5)    = "June" 
  NameOfMonth(6)    = "July"
  NameOfMonth(7)    = "August"
  NameOfMonth(8)    = "September"
  NameOfMonth(9)    = "October"
  NameOfMonth(10)   = "November"
  NameOfMonth(11)   = "December"

Dim Years.s(7)                                           ; fill an array with the years

  Years(0)          = "2002"
  Years(1)          = "2003"
  Years(2)          = "2004"
  Years(3)          = "2005"
  Years(4)          = "2006" 
  Years(5)          = "2007"
  Years(6)          = "2008"

;============================================================================================================================
; 
;============================================================================================================================

CatchImage(#Image_mysqlitetest_program,   ?_PTK_mysqlitetest_program)
CatchImage(#Image_mysqlitetest_messages,  ?_PTK_mysqlitetest_messages)
CatchImage(#Image_mysqlitetest_records,   ?_PTK_mysqlitetest_records)

;==============================================================================================================================
; Any included data in the final exe
;==============================================================================================================================

DataSection

  sqlite3_dll : IncludeBinary "Libraries\sqlite3upx.dll"

  _PTK_mysqlitetest_program   : IncludeBinary "Images\program16x16.ico"
  _PTK_mysqlitetest_messages  : IncludeBinary "Images\messages16x16.ico"
  _PTK_mysqlitetest_records   : IncludeBinary "Images\records16x16.ico"

EndDataSection

;============================================================================================================================
; Adds a suffix To the End of a <= 31 numeral 'date'
;============================================================================================================================

Procedure.s AddDateSuffix(Date.s)
  If Date = "1" Or Date = "21" Or Date = "31"
    Date = Date + "st"
  ElseIf Date = "2" Or Date = "22"
    Date = Date + "nd"
  ElseIf Date = "3" Or Date = "23"
    Date = Date + "rd"
  Else
    Date = Date + "th"
  EndIf
  ProcedureReturn Date
EndProcedure

;============================================================================================================================
; Get the current date and the day of the week in word form
;============================================================================================================================

Procedure GetDayOfWeek(Gadget.l)
  program\daynum = DayOfWeek(ParseDate("%dd/%mm/%yyyy", GetGadgetText(Gadget.l)))
  Select program\daynum
    Case 0 : program\weekday = "Sunday"
    Case 1 : program\weekday = "Monday" 
    Case 2 : program\weekday = "Tuesday" 
    Case 3 : program\weekday = "Wednesday"
    Case 4 : program\weekday = "Thursday"
    Case 5 : program\weekday = "Friday"
    Case 6 : program\weekday = "Saturday"
  EndSelect
EndProcedure

;============================================================================================================================
; Add an item to the end of any ListIconGadget display
;============================================================================================================================

Procedure AddToDisplay(Gadget.l, Text.s, IconItem.l)
  AddGadgetItem(Gadget.l, -1, Text.s, UseImage(iconItem))
EndProcedure

;============================================================================================================================
; Count the number of records in an SQLite database
;============================================================================================================================

Procedure CountRecords()
  If SQL3GetTable("Select Count(record) AS totalrecs FROM addresses", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      LastElement(SqlData.s())
      ProcedureReturn Val(StringField(SqlData.s(), 1, "|"))
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: Could not get the number of records in the database")
    ProcedureReturn 0
  EndIf  
EndProcedure

;============================================================================================================================
; Clear the windows event buffer to avoid greying out of forms
;============================================================================================================================

Procedure FlushEvents()
  While WindowEvent()
  Wend
EndProcedure

;============================================================================================================================
; Set the last line of a ListIconGadget
;============================================================================================================================

Procedure LastLine(Gadget.l)
  SendMessage_(GadgetID(Gadget.l), #LVM_ENSUREVISIBLE, CountGadgetItems(Gadget.l) -1,0) ; Make sure the current line is visible
EndProcedure

;============================================================================================================================
; Sort out the date and display it
;============================================================================================================================

Procedure SetDate(Windowid.l)
  newDate.dateStructure
  GetSystemTime_(@newDate)
  WeekDay.b = newDate\DayOfWeek
  Day.b     = newDate\Day
  Month.b   = newDate\Month
  Year.w    = newDate\Year
  CurrentDate.s = NameOfDay(WeekDay) + ", " + AddDateSuffix(Str(Day)) + ", " + NameOfMonth(Month - 1) + ", " + Str(Year)
  SetWindowTitle(Windowid.l, #CopyRight + "   --   Today is " + CurrentDate.s)
EndProcedure

;============================================================================================================================
; Custom statusbar routine
;============================================================================================================================

Procedure SetStat(Field.l, Message.s)
  StatusBarText(#StatusBar_mysqlitetest, Field.l, Message.s, 0)
EndProcedure

;============================================================================================================================
; Get data back from an SQLite database table and stuff it into a concatenated linked list
;============================================================================================================================

Procedure.l SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l)
  ClearList(SqlData.s())
  If CallCFunctionFast(sqlite3_get_table, lDataBaseHandle, sSQLQuery, @LResultsPtr, @LRows, @LCols, @ReturnValue) = #SQLITE3_OK
    PokeL(*Rows, LRows)                                     ; return number of rows/columns
    PokeL(*Cols, LCols)
    If LRows > -1 And LCols > 0
      Address.l  = LResultsPtr                              ; copy data into array
      For Row.l  = 1 To LRows
        For Col.l  = 0 To LCols - 1
          tempdata.s + PeekS(PeekL(Address + (((Row * LCols) + Col) * 4))) + "|"
        Next
       AddElement(SqlData.s())
       SqlData.s() = tempdata
       tempdata.s = ""
      Next
    EndIf
    CallCFunctionFast(sqlite3_free_table, LResultsPtr)      ; free table memory
    ProcedureReturn #True
  Else
    CallCFunctionFast(sqlite3_errmsg, @ReturnValue)
    Debug PeekS(ReturnValue)
    ProcedureReturn #False
  EndIf
EndProcedure  

;============================================================================================================================
; Find the handle to a specific child on a window. In this case, the status bar.
;============================================================================================================================

Procedure GetAllChildHandles(Winhandle)
  Childhandle = GetWindow_(Winhandle, #GW_CHILD)
  Repeat
    Namespace.s = Space(999)
    GetClassName_(Childhandle, Namespace.s, 999)
    If Namespace.s = "msctls_statusbar32"
      Form\Statushandle = Childhandle
    EndIf
    Childhandle = GetWindow_(Childhandle, #GW_HWNDNEXT)
  Until Childhandle = 0
EndProcedure

;============================================================================================================================
; Simplify the creation of API calendar gadgets
;============================================================================================================================

Procedure DateInputGadget(x, y, width_, height_) 
  hCal = CreateWindowEx_(0, "SysDateTimePick32", "DateTime", #WS_CHILD | #WS_VISIBLE |#WS_BORDER | #DTS_SHOWNONE, x, y, width_, height_, WindowID(), 0, GetModuleHandle_(0), 0) 
  SetWindowLong_(hCal, #GWL_STYLE, GetWindowLong_(hCal, #GWL_STYLE) | #WS_TABSTOP) 
  ProcedureReturn hCal
EndProcedure 

;============================================================================================================================
; Uncle Berikco's routine to properly replace single quotes with double for SQL passing
;============================================================================================================================

Procedure.s RepQuote(Instring.s)
  For i = 1 To Len(Instring.s)
    If Mid(Instring.s, i, 1) = "'"
      tmp.s = tmp.s + "''"
    Else
      tmp.s = tmp.s + Mid(Instring.s, i, 1)
    EndIf
  Next i
  ProcedureReturn tmp.s
EndProcedure

;============================================================================================================================
; Kill double quotes in strings for display purposes
;============================================================================================================================

Procedure.s KillQuote(Instring.s)
  ProcedureReturn ReplaceString(Instring.s, "''", "'", 1, 1)
EndProcedure

;============================================================================================================================
; Remove strings from left or right side of input string
;============================================================================================================================

Procedure.s Sremove(InString.s, Direction.s, Length.l)
  StringLen.l = Len(InString.s)
  Select Direction.s
    Case "L"  : ProcedureReturn = Right(InString.s, StringLen - length)
    Case "R"  : ProcedureReturn = Left(InString.s, StringLen - length)
  EndSelect
EndProcedure

;============================================================================================================================
; Initialise the SQLite dll, create the database and the table if they don't exist
;============================================================================================================================

sqlite3_lib                 = LoadLibraryM(?sqlite3_dll)  ; Load the library from memory, don't write to disk

If sqlite3_lib
  sqlite3_open              = GetProcAddressM(sqlite3_lib, "sqlite3_open")
  sqlite3_exec              = GetProcAddressM(sqlite3_lib, "sqlite3_exec")
  sqlite3_close             = GetProcAddressM(sqlite3_lib, "sqlite3_close")
  sqlite3_errmsg            = GetProcAddressM(sqlite3_lib, "sqlite3_errmsg")
  sqlite3_get_table         = GetProcAddressM(sqlite3_lib, "sqlite3_get_table")
  sqlite3_free_table        = GetProcAddressM(sqlite3_lib, "sqlite3_free_table")
  sqlite3_changes           = GetProcAddressM(sqlite3_lib, "sqlite3_sqlite3_changes")
  sqlite3_last_insert_rowid = GetProcAddressM(sqlite3_lib, "sqlite3_last_insert_rowid")
  sqlite3_free              = GetProcAddressM(sqlite3_lib, "sqlite3_free")
Else
  MessageRequester("SQLite3 Error", "Could not initialise the sqlite3upx.dll library file, can't find it or load it")
  End
EndIf 

;============================================================================================================================
; 
;============================================================================================================================

If Window_mysqlitetest()

  ;----------------------------------------------------------------------------------------------------------
  ; Add a return keyboard shortcut to enter queries
  ;----------------------------------------------------------------------------------------------------------
  AddKeyboardShortcut(#Window_mysqlitetest, #PB_Shortcut_Return, #Gadget_mysqlitetest_return)
  AddKeyboardShortcut(#Window_mysqlitetest, #PB_Shortcut_Alt | #PB_Shortcut_X, #Gadget_mysqlitetest_exit)

  ;----------------------------------------------------------------------------------------------------------
  ; Add the message and record statusbar icons
  ;----------------------------------------------------------------------------------------------------------
  StatusBarIcon(#StatusBar_mysqlitetest, #StatusBar_mysqlitetest_messages, UseImage(#Image_mysqlitetest_messages))
  StatusBarIcon(#StatusBar_mysqlitetest, #StatusBar_mysqlitetest_records,  UseImage(#Image_mysqlitetest_records))
  
  ;----------------------------------------------------------------------------------------------------------
  ; Get windows handle for tray hiding and other functions
  ;----------------------------------------------------------------------------------------------------------
  form\winhandle = WindowID(#Window_mysqlitetest)

  ;----------------------------------------------------------------------------------------------------------
  ; Find status bar handle and save it to Form\Statushandle
  ;----------------------------------------------------------------------------------------------------------
  GetAllChildHandles(form\winhandle)
  
  ;----------------------------------------------------------------------------------------------------------
  ; Change the status bar colour to whatever we want now that we have found the handle to it
  ;----------------------------------------------------------------------------------------------------------
  SendMessage_(form\statushandle, #SB_SETBKCOLOR, 0, Colour)
  
  ;----------------------------------------------------------------------------------------------------------
  ;Set the program day and date in the title bar
  ;----------------------------------------------------------------------------------------------------------
  SetDate(#Window_mysqlitetest)                                  ; Set current date on form title

  ;----------------------------------------------------------------------------------------------------------
  ; Let the user know that the database is open via the status bar
  ;----------------------------------------------------------------------------------------------------------
  SetStat(#StatusBar_mysqlitetest_messages, "Information: The sqlite3upx.dll library file was loaded, The SQLite 3.x environment is ready to go")
  SetStat(#StatusBar_mysqlitetest_records,  "Record(s)")
  
  ;----------------------------------------------------------------------------------------------------------
  ; Set initial quit value to 0 so that program doesn't accidentally close
  ;----------------------------------------------------------------------------------------------------------
  program\progquit = 0

  Repeat
    EventID  = WaitWindowEvent()
    MenuID   = EventMenuID()
    GadgetID = EventGadgetID()
    WindowID = EventWindowID()

    If IsIconic_(Form\winhandle) <> 0                              ; The window has been minimized
      HideWindow(#Window_mysqlitetest, 1)
      AddSysTrayIcon(1, form\winhandle, UseImage(#Image_mysqlitetest_program))
      SysTrayIconToolTip(1, "SQLite 3.xx Data retrieval in here!!!")
    EndIf

    Select EventID
      Case #PB_Event_CloseWindow
        If WindowID = #Window_mysqlitetest
          program\progquit = 1
        EndIf

      Case #PB_Event_Menu
        Select MenuID
          Case #Gadget_mysqlitetest_return        : Gosub CheckEnterKey     ; See if ENTER was pressed in query box
          Case #Gadget_mysqlitetest_exit          : program\progquit = 1     ; Set the quit flag
        EndSelect
        
      Case #PB_Event_Gadget
        Select GadgetID
          Case #Gadget_mysqlitetest_bgetdatabase  : Gosub OpenADatabase     ; Open a database to process
          Case #Gadget_mysqlitetest_tables        : Gosub GetColumnName     ; Get the columns of the highlighted table
          Case #Gadget_mysqlitetest_bsave         : Gosub SaveListToDisk    ; Save the sql dump to disk
          Case #Gadget_mysqlitetest_helpbutton
          Case #Gadget_mysqlitetest_exitbutton    : program\progquit = 1     ; Set the quit flag
        EndSelect

       Case #PB_Event_SysTray                                                ; System tray events
         If EventType() = #PB_EventType_LeftClick
           RemoveSysTrayIcon(1)
           HideWindow(#Window_mysqlitetest, 0)
           SetForegroundWindow_(Form\winhandle)                               ; Un-hiding the window brings it to the front
         EndIf

    EndSelect
  Until program\progquit
  CloseWindow(#Window_mysqlitetest)
EndIf
End

;============================================================================================================================
OpenADatabase:                    ; Open a database to process
;============================================================================================================================

  program\dbname = OpenFileRequester("Database to open", "", "Database file (*.*)|*.*", 0)
  
  If CallCFunctionFast(sqlite3_open, program\dbname, @program\dbhandle) = #SQLITE3_OK
    program\dbopen = 1
    SetStat(#StatusBar_mysqlitetest_messages, "Info: The database " + program\dbname + " was opened successfully, program ready")
    Gosub GetTableNames
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The database " + program\dbname + " could not be opened")
  EndIf
  
Return

;============================================================================================================================
GetTableNames:                    ; Get a list of the table names in the current database
;============================================================================================================================

  If SQL3GetTable("Select name FROM sqlite_master WHERE type='table' ORDER BY name", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      ForEach SqlData.s()
        AddGadgetItem(#Gadget_mysqlitetest_tables, -1, RemoveString(SqlData.s(), "|", 0))     ; Get the returned table names
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no tables")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The table information could not be retrieved")  
  EndIf
  
Return

;============================================================================================================================
GetColumnName:
;============================================================================================================================

  program\table = GetGadgetItemText(#Gadget_mysqlitetest_tables, GetGadgetState(#Gadget_mysqlitetest_tables), 0)
  
  If SQL3GetTable("PRAGMA table_info(" + program\table + ")", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      ClearGadgetItemList(#Gadget_mysqlitetest_columns)
      ForEach SqlData.s()
        AddGadgetItem(#Gadget_mysqlitetest_columns, -1, StringField(SqlData.s(), 2, "|"))
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no columns")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The column information could not be retrieved")  
  EndIf
  
Return

;============================================================================================================================
CheckEnterKey:                    ; See if ENTER was pressed in query box
;============================================================================================================================

  FocusID = GetFocus_()                                          ; Get the id of the window/object that has focus

  Select FocusID                                                 ; Use the id in a gadget selection
    Case GadgetID(#Gadget_mysqlitetest_query)                    ; Gadget is the barcode box
      program\query = GetGadgetText(#Gadget_mysqlitetest_query)  ; Get the text from the query box
      Gosub RunDatabaseQuery                                     ; Reusable data return routine
  EndSelect                                                     ; End the selection

Return

;============================================================================================================================
SaveListToDisk:                   ; Save the sql dump to disk
;============================================================================================================================

  If CreateFile(0, SaveFileRequester("Save returned query", "QueryDump.txt", "Text (*.txt)|*.txt|All files (*.*)|*.*", 0)) <> 0
    For ListItems = 0 To CountGadgetItems(#Gadget_mysqlitetest_datalist) - 1  ; Go through items in the list
      For TotalColumns = 0 To program\colnum - 1                ; Go through every column in the list
        OutString.s + Chr(34) + GetGadgetItemText(#Gadget_mysqlitetest_datalist, ListItems, TotalColumns) + Chr(34) + ","
      Next TotalColumns
      SetStat(#StatusBar_mysqlitetest_records, "Saving Line " + Str(ListItems))
      WriteStringN(Sremove(OutString, "R", 1))                  ; Remove trailing comma
      OutString.s = ""
    Next ListItems
    CloseFile(0)
    SetStat(#StatusBar_mysqlitetest_messages, "Info: " + Str(CountGadgetItems(#Gadget_mysqlitetest_datalist)) + " Lines saved To disk")
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: Cannot save the list to disk, something went wrong")
  EndIf

Return

;============================================================================================================================
RunDatabaseQuery:
;============================================================================================================================

  program\query = GetGadgetText(#Gadget_mysqlitetest_query)               ; Get the query text

  If SQL3GetTable(program\query, @myRows, @myCols, program\dbhandle)      ; Run the query
  
    If CountList(SqlData.s()) <> 0

      ClearGadgetItemList(#Gadget_mysqlitetest_datalist)                  ; Clear previous items from the list
      
      If program\colnum <> 0                                              ; Remove columns from previous query if query okay
        For colremove = 1 To program\colnum - 1
          RemoveGadgetColumn(#Gadget_mysqlitetest_datalist, 1)
        Next colremove
        program\colnum = 0
      EndIf

      SelectElement(SqlData.s(), 0)                                       ; Analyse first element of returned query
      program\colnum = CountString(SqlData.s(), "|")                      ; And find the number of returned columns
      
      For coladd = 1 To program\colnum - 1                               ; Add number of columns equal to number of fields
        AddGadgetColumn(#Gadget_mysqlitetest_datalist, 1, "Data", 100)
      Next coladd
      
      ForEach SqlData.s()                                                ; Process each new item and add them to display
        FlushEvents()                                                     ; Flush window events to stop form greying out
        AddGadgetItem(#Gadget_mysqlitetest_datalist, -1, ReplaceString(SqlData.s(), "|", Chr(10), 1, 1))
      Next

      SetStat(#StatusBar_mysqlitetest_messages, "Info: Please wait while I auto resize the display to fit the data width")

      For WidthSet = 0 To program\colnum - 1                             ; Auto set the field widths to biggest field
        SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist), #LVM_SETCOLUMNWIDTH, WidthSet, #LVSCW_AUTOSIZE)
      Next WidthSet
      
      SetStat(#StatusBar_mysqlitetest_messages, "Info: The query matched " + Str(myRows) + " lines of data and " + Str(myCols) + " columns in each line")
    
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no data")
    EndIf
    
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The database information could not be retrieved")  
  EndIf

Return

Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Cheeky bugger:)

Post by Fangbeast »

rsts wrote:OK Fangbeast, this should get me started, at least it will get you off the hook for tutorial for a while :lol:

Many thanks.

I'll probably be back with a few (00's) questions.

cheers

P.S. some folks may have problems finding sqlite3upx.dll - at least it took me a while. Not your problem but it did seem hard to find for me :?
1. You are going to get a dead ferret in the mail. Seriously, I had to learn a few new things to be able to write this. And my hardware keeps shutting down randomly so it's amazing I got this far.

2. Now that this query module works, I can finally add to the tutorial but I also have to find where LarsG is hiding, I need his help too.

3. The dll in question is just the standard SQLITE3.DLL available from SQLITE.ORG but packed with UPX to take less space in the final EXE.

4. Ask away. Now that El_Choni's routines have me up and going properly, I am SQLIteing all my data. 4 programs here have had a total rewrite and are working well.

The real heart of everything in this simple code is the SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l) routine. You may notice that I'm a great fan of returning everything to linked lists for processing and separating the data components after I grab them? It may not be the fastest or best way but it works great here.

You might even say that I'm double handling the data and that would be true but I find it easier dealing with it this way.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post by Fangbeast »

chris319 wrote:
some folks may have problems finding sqlite3upx.dll
Could you post a link to it?
As I said to rsts below "3. The dll in question is just the standard SQLITE3.DLL available from SQLITE.ORG but packed with UPX to take less space in the final EXE. "

UPX.EXE is a free EXE packer available on the internet. I didn't compress the DLL myself but I forget where I got it from myself. Fortunately, the UPX compressor is easy to find, very tiny and a couple of microseconds is all it takes to compress the dll yourself.

Good luck.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Additions to the tutorial

Post by Fangbeast »

The turorial LarsG and I did last year is now out of date but I don't know how to start adding to it for SqLite. I've made a stab at adding SqLite to it, including the query module but..

1. I need standalone code examples.
2. Monolithic programs.
3. Extra tutorial material.
4. Working programs WITH 3'rd party library references (FREE ones)

Anyone want to contribute to it?
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

probably not far enough along to make much of a contribution :(

your second version references some images in the data section that are not to be found - I'm still working on understanding the frst version :)

thanks for your contributions to us novices.

cheers
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post by Fangbeast »

I'd use the second version because

a. it doesn't have any dependancy upon the visual designer library I use.
b. better cleaned up code.
c. redundant buttons and gadgets removed.


Also, the idea with the images is that you replace them with your own.

Format of the icons is 16 (wide) x 16 (high) x 256 (colours)


P.S. Do you want me to email you the gui form (As I noticed you use PV as well) ?
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Newer perversion of SqLite Query module

Post by Fangbeast »

1. No dependancy on any visual designer.
2. Colours! (Even in status bar)
3. Remember the last 20 queries
4. Select old queries from combo box
5. Minimise to tray
6. Colourful, custom bubble tips
7. Add actual returned collumn header names
8. Save collumn header names in data dump.
9. Write SQL error to error log file.
10. Hopefully more intelligent error messages in status.

(One of these days I'll have to figure out how to put and get working, some splitters in there. I always have trouble with them.)

NOTE* Don't be lazy, use your own damn images/icons etc. Don't expect me to do everything!!

Code: Select all

;===========================================================================================================================
; Please note that all the SQLite direct database code I found in the PureBasic forum, done by El_Chonie, not by me.
;
; *NOTE* There is no syntax checking on database statements, I simply don't have that sort of time on my hands, nor the
; experience needed. This should be enough for most people.
;
; If you like it, say thanks to El_Choni and (me too maybe???). If you don't like it, I don't want to know. Fang.
;
; DEPENDANCIES:
;
; SQLite v3.x DLL               I'm using the UPX'ed version. Check this code.
; PBOSL LoadDLLFromMemory.      Very useful stuff
; 
;==============================================================================================================================
; Any declarations
;==============================================================================================================================

Declare.s AddDateSuffix(Date.s)                                     ; Add the abbreviated date suffix
Declare   GetDayOfWeek(Gadget.l)                                    ; Get the day of the week in name form
Declare   WriteError(Module.s)                                      ; Write the errors to an error log file
Declare   CountRecords()                                            ; Return the number of records in a database
Declare   FlushEvents()                                             ; Prevent forms from greying out
Declare   LastLine(Gadget.l)                                        ; Always go to the last line of a list object
Declare   SetDate(Windowid.l)                                       ; Set the current date in the title bar
Declare   SetStat(Field.l, Message.s)                               ; Shortcut to setting text on the status bar
Declare   GetAllChildHandles(Winhandle)                             ; Get the status bar handle
Declare.s RepQuote(Instring.s)                                      ; Properly replace single quotes with double for SQL passing
Declare.s KillQuote(Instring.s)                                     ; Kill double quotes in strings for display purposes
Declare.s Sremove(InString.s, Direction.s, Length.l)                ; Remove strings from left or right side of input string
Declare   SetListIconColumnText(Gadget, index, HeaderText.s)        ; Set the heading of a ListIconGadget (Danilo)
Declare.s GetListIconColumnText(Gadget, index)                      ; Get the heading of a ListIconGadget (Danilo)
Declare   MyBalloonTips(btWindow.l, btGadget.l, btText.s)           ; Personal balloon tooltip window
Declare.s GetIniVal(IniSection.s, IniKey.s)                         ; API Procedure To replace Mr Skunk's INI file reading routine
Declare.l SetIniVal(IniSection.s, IniKey.s, IniValue.s)             ; API procedure to replace Mr Skunk's INI file writing routine

;===========================================================================================================================
; El_Choni's sqlite 3 code
;===========================================================================================================================

Declare.l SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l)  ; Return data from an SQLite table to a linked list

;===========================================================================================================================
; Window and object constants
;===========================================================================================================================

Enumeration 1
  #Window_mysqlitetest
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #Gadget_mysqlitetest_fmain
  #Gadget_mysqlitetest_datalist
  #Gadget_mysqlitetest_fquery
  #Gadget_mysqlitetest_lquery
  #Gadget_mysqlitetest_query
  #Gadget_mysqlitetest_fcontrol
  #Gadget_mysqlitetest_bgetdatabase
  #Gadget_mysqlitetest_ltables
  #Gadget_mysqlitetest_tables
  #Gadget_mysqlitetest_lcolumns
  #Gadget_mysqlitetest_columns
  #Gadget_mysqlitetest_bsave
  #Gadget_mysqlitetest_fother
  #Gadget_mysqlitetest_helpbutton
  #Gadget_mysqlitetest_exitbutton
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #StatusBar_mysqlitetest
  #StatusBar_mysqlitetest_messages = 0
  #StatusBar_mysqlitetest_records  = 1
EndEnumeration

#StatusBarIndex = #PB_Compiler_EnumerationValue

;===========================================================================================================================
; Window code
;===========================================================================================================================

Procedure.l Window_mysqlitetest()
  If OpenWindow(#Window_mysqlitetest,18,72,905,600,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible,"SQLite - ")
    Brush.LOGBRUSH\lbColor=16770015
    SetClassLong_(WindowID(#Window_mysqlitetest),#GCL_HBRBACKGROUND,CreateBrushIndirect_(Brush))
    If CreateGadgetList(WindowID(#Window_mysqlitetest))
      Frame3DGadget(#Gadget_mysqlitetest_fmain,5,0,710,535,"")
      ListIconGadget(#Gadget_mysqlitetest_datalist,10,10,700,520,"itemslist",2048,#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
      Frame3DGadget(#Gadget_mysqlitetest_fquery,5,535,710,40,"")
      TextGadget(#Gadget_mysqlitetest_lquery,15,555,45,15,"Query  ",#PB_Text_Right)
      ComboBoxGadget(#Gadget_mysqlitetest_query,60,550,650,200,#PB_ComboBox_Editable)
      Frame3DGadget(#Gadget_mysqlitetest_fcontrol,720,0,180,535,"")
      ButtonGadget(#Gadget_mysqlitetest_bgetdatabase,725,15,170,20,"Open Database")
      TextGadget(#Gadget_mysqlitetest_ltables,725,40,170,15,"Table names in database",#PB_Text_Center)
      ListViewGadget(#Gadget_mysqlitetest_tables,725,55,170,300)
      TextGadget(#Gadget_mysqlitetest_lcolumns,725,365,170,15,"Columns names in table",#PB_Text_Center)
      ListViewGadget(#Gadget_mysqlitetest_columns,725,380,170,125)
      ButtonGadget(#Gadget_mysqlitetest_bsave,725,510,170,20,"Save sql dump to disk")
      Frame3DGadget(#Gadget_mysqlitetest_fother,720,535,180,40,"")
      ButtonGadget(#Gadget_mysqlitetest_helpbutton,725,550,85,20,"Help")
      ButtonGadget(#Gadget_mysqlitetest_exitbutton,810,550,85,20,"Exit")
      CreateStatusBar(#StatusBar_mysqlitetest,WindowID(#Window_mysqlitetest))
        AddStatusBarField(712)
        AddStatusBarField(200)
      HideWindow(#Window_mysqlitetest,0)
      ProcedureReturn WindowID()
    EndIf
  EndIf
EndProcedure

;==============================================================================================================================
; SQLite 3 related constants found by El_Choni
;==============================================================================================================================

#SQLITE3_OK                   =   0     ; Successful Result
#SQLITE3_ERROR                =   1     ; SQL error Or missing database
#SQLITE3_INTERNAL             =   2     ; An internal logic error in SQLite
#SQLITE3_PERM                 =   3     ; Access permission denied
#SQLITE3_ABORT                =   4     ; Callback routine requested An abort
#SQLITE3_BUSY                 =   5     ; The database file is locked
#SQLITE3_LOCKED               =   6     ; A table in The database is locked
#SQLITE3_NOMEM                =   7     ; A malloc() failed
#SQLITE3_READONLY             =   8     ; Attempt To write A readonly database
#SQLITE3_INTERRUPT            =   9     ; Operation terminated by SQLite_Interrupt()
#SQLITE3_IOERR                =  10     ; Some kind of disk I/O error occurred
#SQLITE3_CORRUPT              =  11     ; The database disk image is malformed
#SQLITE3_NOTFOUND             =  12     ; (internal Only) table Or record not found
#SQLITE3_FULL                 =  13     ; Insertion failed because database is full
#SQLITE3_CANTOPEN             =  14     ; Unable To open The database file
#SQLITE3_PROTOCOL             =  15     ; database lock protocol error
#SQLITE3_EMPTY                =  16     ; (internal Only) database table is empty
#SQLITE3_SCHEMA               =  17     ; The database schema changed
#SQLITE3_TOOBIG               =  18     ; Too much Data For one Row of A table
#SQLITE3_CONStraint           =  19     ; abort due To contraint violation
#SQLITE3_MISMATCH             =  20     ; Data type mismatch
#SQLITE3_MISUSE               =  21     ; Library used incorrectly
#SQLITE3_NOLFS                =  22     ; Uses OS features not supported on host
#SQLITE3_AUTH                 =  23     ; Authorization denied
#SQLITE3_ROW                  = 100     ; sqlite_step() has another Row ready
#SQLITE3_DONE                 = 101     ; sqlite_step() has finished executing

;============================================================================================================================
; API date gadget date selection selection
;============================================================================================================================

#DTM_FIRST                    = $1000
#DTM_SETFORMAT                = $1005
#DTS_SHOWNONE                 = $2
#MCM_GETCURSEL                = $1001
#MCM_SETCURSEL                = $1002
#GDT_NONE                     = $1
#DTM_SETSYSTEMTIME            = #DTM_FIRST + 2
#DTM_GETSYSTEMTIME            = #DTN_FIRST + 1

;============================================================================================================================
; My personal constants
;============================================================================================================================

#Version                      = "v0.00"                                       ; Program version
#CopyRight                    = "<°)))o><²³  SQLite data test(c) " + #Version ; Copyright string

#Eol                          = Chr(10) + Chr(13)                             ; End of line marker

;==============================================================================================================================
; My personal constants
;==============================================================================================================================

Enumeration ;#GadgetIndex
  #Shortcut_mysqlitetest_return
  #Shortcut_mysqlitetest_exit
EndEnumeration

Enumeration ;#ImageIndex
  #Image_mysqlitetest_program
  #Image_mysqlitetest_messages
  #Image_mysqlitetest_records
EndEnumeration

;==============================================================================================================================
; Common controls structure size
;==============================================================================================================================

dt.INITCOMMONCONTROLSEX\dwSize  = SizeOf(INITCOMMONCONTROLSEX) 
dt\dwICC                        = $100 

InitCommonControlsEx_(@dt) 

;==============================================================================================================================
; Constants for statusbar handling
;==============================================================================================================================

#SB_SETBKCOLOR          = $2001 ; Statusbar colour constant

Colour                  = RGB($E9, $DA, $87)

;===========================================================================================================================
; Object colouring in the callback
;===========================================================================================================================

Yellow  = CreateSolidBrush_(16770015)
Green   = CreateSolidBrush_($7BDF84)
Blue    = CreateSolidBrush_($E5B91A)
; 
;============================================================================================================================
; Custom date routine structure
;==============================================================================================================================

Structure DateStructure ; Custom date routine
  Year.w
  Month.w
  DayOfWeek.w
  Day.w
  Hour.w
  Minute.w
  Second.w
  Milliseconds.w
EndStructure

;==============================================================================================================================
; Window data structure
;==============================================================================================================================

Structure windowdata   ; Window structure data
  winhandle.l           ; Main window handle
  statushandle.l        ; Status bar handle
  newstatwidth.l        ; New status bar width
  oldstatwidth.l        ; Old status bar width
EndStructure

;===========================================================================================================================
; ListIconGadget header data structures
;===========================================================================================================================

Structure LVCOLUMN
  mask.l
  fmt.l
  cx.l
  pszText.s
  cchTextMax.l
  iSubItem.l
  iImage.l
  iOrder.l
EndStructure 

;==============================================================================================================================
; Program data structure
;==============================================================================================================================

Structure programdata  ; Program data structure
  curdir.s              ; Current program startup directory
  progname.s            ; Program name for base filename saves
  libfile.s             ; SQLite dll file, in current directory
  dbhandle.l            ; Handle to the currently open database
  dbname.s              ; Name of the database to open
  dbopen.l              ; Is the database open or not
  query.s               ; Current sql query string
  progquit.l            ; User quit the program, so set the quit value to allow program to end repeat loop
  numitems.l            ; Always the true number of items in the database
  curline.l             ; Always the current line in the list object
  record.s              ; Program record pointer to true database record number
  daynum.l              ; Numerical day of the week mapped to word format
  inifile.s             ; Name and path of the options file
  weekday.s             ; Day of the week in name form
  column.s              ; Name of the highlighted column
  table.s               ; Name of the highlighted table
  lastdbdir.s           ; Full path to the last used source database directory
  errorlog.s            ; Name of the error log file
  errorhandle.l         ; Handle of the eror log file
EndStructure

;==============================================================================================================================
; Save the last 10 queries to disk
;==============================================================================================================================

NewList SqlQuery.s()

;==============================================================================================================================
; New list to hold returned sqlite data
;==============================================================================================================================

NewList SqlData.s()

;==============================================================================================================================
; All global variables
;==============================================================================================================================

Global program.programdata, form.windowdata

Global sqlite3_open.l,sqlite3_exec.l, sqlite3_close.l, sqlite3_errmsg.l, sqlite3_get_table.l, sqlite3_free_table.l
Global sqlite3_changes, sqlite3_last_insert_rowid, sqlite3_free, sqlite3_column_name, sqlite3_prepare, sqlite3_finalize

Global Yellow, Green, Blue

;==============================================================================================================================
; Get current direectory and store it for later
;==============================================================================================================================

program\curdir = Space(512)                                          ; Give the variable enough space

If GetCurrentDirectory_(Len(program\curdir), @program\curdir) <> 0   ; Get the current directory
  If Right(program\curdir, 1) <> "\"                                 ; Each O/S does it differently so check for backspace
    program\curdir + "\"
  EndIf
EndIf

;==============================================================================================================================
; Create local picture and icon directory variables
;==============================================================================================================================

program\progname     = "Sqlite Data Test"                       ; Constant program name
program\libfile      = program\curdir + "sqlite3upx.dll"        ; SQLite 3 dll file
program\inifile      = program\curdir + "Sqlite Data Test.ini"  ; The name and path of the program options file 
program\errorlog     = program\curdir + "Sqlite Data Test.log"  ; Name of the error log file

;==============================================================================================================================
; Setup day and month literal names
;==============================================================================================================================

Dim NameOfDay.s(7)                                        ; Fill an array with the names of the days (Terry Hough I think)

  NameOfDay(0)      = "Sunday"
  NameOfDay(1)      = "Monday"
  NameOfDay(2)      = "Tuesday"
  NameOfDay(3)      = "Wednesday"  
  NameOfDay(4)      = "Thursday"
  NameOfDay(5)      = "Friday"
  NameOfDay(6)      = "Saturday"

Dim DaysPerMonth(12)                                      ; Fill an array on how many days per month there are

  For X = 0 To 11     
    DaysPerMonth(X) = 31 
  Next

  DaysPerMonth(1)   = 28
  DaysPerMonth(3)   = 30
  DaysPerMonth(5)   = 30
  DaysPerMonth(8)   = 30

  DaysPerMonth(10)  = 30

Dim NameOfMonth.s(12)                                    ; fill an array with the names of the months

  NameOfMonth(0)    = "January"
  NameOfMonth(1)    = "February"
  NameOfMonth(2)    = "March" 
  NameOfMonth(3)    = "April"
  NameOfMonth(4)    = "May"
  NameOfMonth(5)    = "June" 
  NameOfMonth(6)    = "July"
  NameOfMonth(7)    = "August"
  NameOfMonth(8)    = "September"
  NameOfMonth(9)    = "October"
  NameOfMonth(10)   = "November"
  NameOfMonth(11)   = "December"

Dim Years.s(7)                                           ; fill an array with the years

  Years(0)          = "2002"
  Years(1)          = "2003"
  Years(2)          = "2004"
  Years(3)          = "2005"
  Years(4)          = "2006" 
  Years(5)          = "2007"
  Years(6)          = "2008"

;============================================================================================================================
; Include any images in the final exe and load them from memory
;============================================================================================================================

CatchImage(#Image_mysqlitetest_program,   ?_PTK_mysqlitetest_program)
CatchImage(#Image_mysqlitetest_messages,  ?_PTK_mysqlitetest_messages)
CatchImage(#Image_mysqlitetest_records,   ?_PTK_mysqlitetest_records)

;==============================================================================================================================
; Any included data in the final exe
;==============================================================================================================================

DataSection

  sqlite3_dll : IncludeBinary "Libraries\sqlite3upx.dll"

  _PTK_mysqlitetest_program   : IncludeBinary "Images\program.ico"
  _PTK_mysqlitetest_messages  : IncludeBinary "Images\messages.ico"
  _PTK_mysqlitetest_records   : IncludeBinary "Images\records.ico"

EndDataSection

;============================================================================================================================
; Adds a suffix To the End of a <= 31 numeral 'date' (Could be Terry Hough)
;============================================================================================================================

Procedure.s AddDateSuffix(Date.s)
  If Date = "1" Or Date = "21" Or Date = "31"
    Date = Date + "st"
  ElseIf Date = "2" Or Date = "22"
    Date = Date + "nd"
  ElseIf Date = "3" Or Date = "23"
    Date = Date + "rd"
  Else
    Date = Date + "th"
  EndIf
  ProcedureReturn Date
EndProcedure

;============================================================================================================================
; Get the current date and the day of the week in word form
;============================================================================================================================

Procedure GetDayOfWeek(Gadget.l)
  program\daynum = DayOfWeek(ParseDate("%dd/%mm/%yyyy", GetGadgetText(Gadget.l)))
  Select program\daynum
    Case 0 : program\weekday = "Sunday"
    Case 1 : program\weekday = "Monday" 
    Case 2 : program\weekday = "Tuesday" 
    Case 3 : program\weekday = "Wednesday"
    Case 4 : program\weekday = "Thursday"
    Case 5 : program\weekday = "Friday"
    Case 6 : program\weekday = "Saturday"
  EndSelect
EndProcedure

;============================================================================================================================
; Add an item to the end of any ListIconGadget display (NOT CURRENTLY USED)
;============================================================================================================================

Procedure AddToDisplay(Gadget.l, Text.s, IconItem.l)
  AddGadgetItem(Gadget.l, -1, Text.s, UseImage(iconItem))
EndProcedure

;============================================================================================================================
; Count the number of records in an SQLite database
;============================================================================================================================

Procedure CountRecords()
  If SQL3GetTable("Select Count(record) AS totalrecs FROM addresses", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0
      LastElement(SqlData.s())
      ProcedureReturn Val(StringField(SqlData.s(), 1, "|"))
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: Could not get the number of records in the database")
    ProcedureReturn 0
  EndIf  
EndProcedure

;============================================================================================================================
; Clear the windows event buffer to avoid greying out of forms
;============================================================================================================================

Procedure FlushEvents()
  While WindowEvent()
  Wend
EndProcedure

;============================================================================================================================
; Set the last line of a ListIconGadget
;============================================================================================================================

Procedure LastLine(Gadget.l)
  SendMessage_(GadgetID(Gadget.l), #LVM_ENSUREVISIBLE, CountGadgetItems(Gadget.l) -1,0) ; Make sure the current line is visible
EndProcedure

;============================================================================================================================
; Sort out the date and display it
;============================================================================================================================

Procedure SetDate(Windowid.l)
  newDate.dateStructure
  GetSystemTime_(@newDate)
  WeekDay.b = newDate\DayOfWeek
  Day.b     = newDate\Day
  Month.b   = newDate\Month
  Year.w    = newDate\Year
  CurrentDate.s = NameOfDay(WeekDay) + ", " + AddDateSuffix(Str(Day)) + ", " + NameOfMonth(Month - 1) + ", " + Str(Year)
  SetWindowTitle(Windowid.l, #CopyRight + "   --   Today is " + CurrentDate.s)
EndProcedure

;============================================================================================================================
; Custom statusbar routine
;============================================================================================================================

Procedure SetStat(Field.l, Message.s)
  StatusBarText(#StatusBar_mysqlitetest, Field.l, Message.s, 0)
EndProcedure

;============================================================================================================================
; Get data back from an SQLite database table and stuff it into a concatenated linked list Mostly El_Choni
;============================================================================================================================

Procedure.l SQL3GetTable(sSQLQuery.s, *Rows, *Cols, lDataBaseHandle.l)
  ClearList(SqlData.s())
  If CallCFunctionFast(sqlite3_get_table, lDataBaseHandle, sSQLQuery, @LResultsPtr, @LRows, @LCols, @ReturnValue) = #SQLITE3_OK
    PokeL(*Rows, LRows)                                     ; return number of rows/columns
    PokeL(*Cols, LCols)
    If LRows > -1 And LCols > 0
      Address.l  = LResultsPtr                              ; copy data into array
      For Row.l  = 1 To LRows
        For Col.l  = 0 To LCols - 1
          tempdata.s + PeekS(PeekL(Address + (((Row * LCols) + Col) * 4))) + "|"
        Next
       AddElement(SqlData.s())
       SqlData.s() = tempdata
       tempdata.s = ""
      Next
    EndIf
    CallCFunctionFast(sqlite3_free_table, LResultsPtr)      ; free table memory
    ProcedureReturn #True
  Else
    CallCFunctionFast(sqlite3_errmsg, @ReturnValue)
    Debug PeekS(ReturnValue)
    ProcedureReturn #False
  EndIf
EndProcedure  

;============================================================================================================================
; Find the handle to a specific child on a window. In this case, the status bar.
;============================================================================================================================

Procedure GetAllChildHandles(Winhandle)
  Childhandle = GetWindow_(Winhandle, #GW_CHILD)
  Repeat
    Namespace.s = Space(999)
    GetClassName_(Childhandle, Namespace.s, 999)
    If Namespace.s = "msctls_statusbar32"
      Form\Statushandle = Childhandle
    EndIf
    Childhandle = GetWindow_(Childhandle, #GW_HWNDNEXT)
  Until Childhandle = 0
EndProcedure

;============================================================================================================================
; Uncle Berikco's routine to properly replace single quotes with double for SQL passing
;============================================================================================================================

Procedure.s RepQuote(Instring.s)
  For i = 1 To Len(Instring.s)
    If Mid(Instring.s, i, 1) = "'"
      tmp.s = tmp.s + "''"
    Else
      tmp.s = tmp.s + Mid(Instring.s, i, 1)
    EndIf
  Next i
  ProcedureReturn tmp.s
EndProcedure

;============================================================================================================================
; Kill double quotes in strings for display purposes
;============================================================================================================================

Procedure.s KillQuote(Instring.s)
  ProcedureReturn ReplaceString(Instring.s, "''", "'", 1, 1)
EndProcedure

;============================================================================================================================
; Remove strings from left or right side of input string
;============================================================================================================================

Procedure.s Sremove(InString.s, Direction.s, Length.l)
  StringLen.l = Len(InString.s)
  Select Direction.s
    Case "L"  : ProcedureReturn = Right(InString.s, StringLen - length)
    Case "R"  : ProcedureReturn = Left(InString.s,  StringLen - length)
  EndSelect
EndProcedure

;===========================================================================================================================
; Write the errors to an error log file
;===========================================================================================================================

Procedure WriteError(Module.s)
  program\errorhandle = OpenFile(#PB_Any , program\errorlog)    ; Open the error log file
  CallCFunctionFast(sqlite3_errmsg, @ReturnValue)               ; Get the last sqlite error message
  FileSeek(Lof())                                               ; Seek to the end of the file
  WriteStringN("OpenADatabase " + PeekS(ReturnValue))           ; Write the error to the error log plus module name
  CloseFile(program\errorhandle)                                ; Close the error log
  program\errorhandle = -1                                      ; Reset the handle to negative value
EndProcedure

;===========================================================================================================================
; Set the heading of a ListIconGadget (Danilo)
;===========================================================================================================================

Procedure SetListIconColumnText(Gadget, index, HeaderText.s)
  lvc.LVCOLUMN
  lvc\mask    = #LVCF_TEXT
  lvc\pszText = HeaderText
  SendMessage_(GadgetID(Gadget), #LVM_SETCOLUMN, index, @lvc)
EndProcedure

;===========================================================================================================================
;  Get the heading of a ListIconGadget (Danilo)
;===========================================================================================================================

Procedure.s GetListIconColumnText(Gadget, index)
  lvc.LVCOLUMN
  lvc\mask       = #LVCF_TEXT
  lvc\pszText    = Space(255)
  lvc\cchTextMax = 255
  SendMessage_(GadgetID(Gadget), #LVM_GETCOLUMN, index, @lvc)
  ProcedureReturn PeekS(lvc\pszText)
EndProcedure

;============================================================================================================================
; Personal balloon tooltip window
;============================================================================================================================

Procedure MyBalloonTips(btWindow.l, btGadget.l, btText.s)
  ToolTipControl = CreateWindowEx_(0, "ToolTips_Class32", "", $D0000000 | $40, 0, 0, 0, 0, WindowID(btWindow), 0, GetModuleHandle_(0), 0)
  SendMessage_(ToolTipControl, 1044, 0, 0)
  SendMessage_(ToolTipControl, 1043, $F3D97A, 0)
  SendMessage_(ToolTipControl, 1048, 0, 180)
  Button.TOOLINFO\cbSize = SizeOf(TOOLINFO)
  Button\uFlags   = $11
  Button\hWnd     = GadgetID(btGadget)
  Button\uId      = GadgetID(btGadget)
  Button\lpszText = @btText
  SendMessage_(ToolTipControl, $0404, 0, Button)
EndProcedure

;===========================================================================================================================
; API procedure to replace Mr Skunk's INI file reading routine
;===========================================================================================================================

Procedure.s GetIniVal(IniSection.s, IniKey.s)                                   ; Procedure returns a string
  Empty.s = ""                                                                   ; Default value if nothing found
  ReturnSpace.s = Space(255)                                                     ; Make sure the variable has plenty of room
  IniData = GetPrivateProfileString_(IniSection.s, IniKey.s, Empty.s, @ReturnSpace.s, 255, program\inifile)
  ProcedureReturn ReturnSpace.s                                                ; Return the data to the calling line
EndProcedure

;===========================================================================================================================
; API procedure to replace Mr Skunk's INI file writing routine
;===========================================================================================================================

Procedure.l SetIniVal(IniSection.s, IniKey.s, IniValue.s)
  Result = WritePrivateProfileString_(IniSection, IniKey, IniValue, program\inifile)
  ProcedureReturn Result
EndProcedure

;===========================================================================================================================
; Initialise the SQLite dll, create the database and the table if they don't exist
;===========================================================================================================================

sqlite3_lib                 = LoadLibraryM(?sqlite3_dll)  ; Load the library from memory, don't write to disk

If sqlite3_lib
  sqlite3_open              = GetProcAddressM(sqlite3_lib, "sqlite3_open")
  sqlite3_exec              = GetProcAddressM(sqlite3_lib, "sqlite3_exec")
  sqlite3_close             = GetProcAddressM(sqlite3_lib, "sqlite3_close")
  sqlite3_errmsg            = GetProcAddressM(sqlite3_lib, "sqlite3_errmsg")
  sqlite3_get_table         = GetProcAddressM(sqlite3_lib, "sqlite3_get_table")
  sqlite3_free_table        = GetProcAddressM(sqlite3_lib, "sqlite3_free_table")
  sqlite3_changes           = GetProcAddressM(sqlite3_lib, "sqlite3_sqlite3_changes")
  sqlite3_last_insert_rowid = GetProcAddressM(sqlite3_lib, "sqlite3_last_insert_rowid")
  sqlite3_free              = GetProcAddressM(sqlite3_lib, "sqlite3_free")
  sqlite3_column_name       = GetProcAddressM(sqlite3_lib, "sqlite3_column_name")
  sqlite3_prepare           = GetProcAddressM(sqlite3_lib, "sqlite3_prepare")
  sqlite3_finalize          = GetProcAddressM(sqlite3_lib, "sqlite3_finalize")
Else
  MessageRequester("SQLite3 Error", "Could not initialise the sqlite3upx.dll library file, can't find it or load it")
  End
EndIf 

;===========================================================================================================================
; Callback for object and form resizing, colouring etc
;===========================================================================================================================

Procedure WindowCallback(WindowID, Message, wParam, lParam)
  ReturnValue = #PB_ProcessPureBasicEvents
  If Message = #WM_CTLCOLORSTATIC Or Message = #WM_CTLCOLOREDIT Or Message = #WM_CTLCOLORLISTBOX
    Select lParam
      Case GadgetID(#Gadget_mysqlitetest_lquery)
        SetBkMode_(wParam, #TRANSPARENT)
        SetTextColor_(wParam, $000000)
        ReturnValue = Yellow
      Case GadgetID(#Gadget_mysqlitetest_query)
        SetBkMode_(wParam, #TRANSPARENT)
        SetTextColor_(wParam, $000000)
        ReturnValue = Yellow
      Case GadgetID(#Gadget_mysqlitetest_ltables)
        SetBkMode_(wParam, #TRANSPARENT)
        SetTextColor_(wParam, $000000)
        ReturnValue = Yellow
      Case GadgetID(#Gadget_mysqlitetest_tables)
        SetBkMode_(wParam, #TRANSPARENT)
        SetTextColor_(wParam, $000000)
        ReturnValue = Yellow
      Case GadgetID(#Gadget_mysqlitetest_lcolumns)
        SetBkMode_(wParam, #TRANSPARENT)
        SetTextColor_(wParam, $000000)
        ReturnValue = Yellow
      Case GadgetID(#Gadget_mysqlitetest_columns)
        SetBkMode_(wParam, #TRANSPARENT)
        SetTextColor_(wParam, $000000)
        ReturnValue = Yellow
    EndSelect
  EndIf
  ProcedureReturn ReturnValue
EndProcedure

;===========================================================================================================================
; Main event handler
;===========================================================================================================================

If Window_mysqlitetest()

  ;----------------------------------------------------------------------------------------------------------
  ; Set ListIconGadget colours
  ;----------------------------------------------------------------------------------------------------------
  SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist), #LVM_SETBKCOLOR,     0, 16770015)
  SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist), #LVM_SETTEXTBKCOLOR, 0, 16770015)

  ;----------------------------------------------------------------------------------------------------------
  ; Setup any tool tips after the window has been created (Custom routine)
  ;----------------------------------------------------------------------------------------------------------
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_datalist,      "All returned data will be shown in this list with collumns automatically being added as needed")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_query,         "Type in a properly formatted SQL query in here or select a previous one from the list and press ENTER/RETURN to execute it")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_bgetdatabase,  "Left Mouse Click on this button to select a database to open")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_tables,        "Left Mouse Click on a table entry in this list to show the collumns that it contains")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_columns,       "Left Mouse Clicking on here does absolutely nothing yet!")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_bsave,         "Left Mouse Click on this button to save the returned data to a CSV format file on disk")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_helpbutton,    "Left Mouse Click on this button to show a help screen to the program user")
  MyBalloonTips(#Window_mysqlitetest, #Gadget_mysqlitetest_exitbutton,    "Left Mouse Click on this button to exit this program immediately")

  ;----------------------------------------------------------------------------------------------------------
  ; Add a return keyboard shortcut to enter queries and exit the program
  ;----------------------------------------------------------------------------------------------------------
  AddKeyboardShortcut(#Window_mysqlitetest, #PB_Shortcut_Return,               #Shortcut_mysqlitetest_return)
  AddKeyboardShortcut(#Window_mysqlitetest, #PB_Shortcut_Alt | #PB_Shortcut_X, #Shortcut_mysqlitetest_exit)

  ;----------------------------------------------------------------------------------------------------------
  ; Add the message and record statusbar icons
  ;----------------------------------------------------------------------------------------------------------
  StatusBarIcon(#StatusBar_mysqlitetest, #StatusBar_mysqlitetest_messages, UseImage(#Image_mysqlitetest_messages))
  StatusBarIcon(#StatusBar_mysqlitetest, #StatusBar_mysqlitetest_records,  UseImage(#Image_mysqlitetest_records))
  
  ;----------------------------------------------------------------------------------------------------------
  ; Standard windows callback for resizing, colouring etc
  ;----------------------------------------------------------------------------------------------------------
  SetWindowCallback(@WindowCallback())

  ;----------------------------------------------------------------------------------------------------------
  ; Get windows handle for tray hiding and other functions
  ;----------------------------------------------------------------------------------------------------------
  form\winhandle = WindowID(#Window_mysqlitetest)

  ;----------------------------------------------------------------------------------------------------------
  ; Find status bar handle and save it to Form\Statushandle
  ;----------------------------------------------------------------------------------------------------------
  GetAllChildHandles(form\winhandle)
  
  ;----------------------------------------------------------------------------------------------------------
  ; Change the status bar colour to whatever we want now that we have found the handle to it
  ;----------------------------------------------------------------------------------------------------------
  SendMessage_(form\statushandle, #SB_SETBKCOLOR, 0, Colour)
  
  ;----------------------------------------------------------------------------------------------------------
  ;Set the program day and date in the title bar
  ;----------------------------------------------------------------------------------------------------------
  SetDate(#Window_mysqlitetest)                                  ; Set current date on form title

  ;----------------------------------------------------------------------------------------------------------
  ; Let the user know that the database is open via the status bar
  ;----------------------------------------------------------------------------------------------------------
  SetStat(#StatusBar_mysqlitetest_messages, "Information: The sqlite3upx.dll library file was loaded, The SQLite 3.x environment is ready to go")
  SetStat(#StatusBar_mysqlitetest_records,  "Record(s)")
  
  ;----------------------------------------------------------------------------------------------------------
  ; Find the last used database directory in here
  ;----------------------------------------------------------------------------------------------------------
  program\lastdbdir = GetIniKey("Last Dir", "Last Database Dir",  "C:\", program\inifile)

  ;----------------------------------------------------------------------------------------------------------
  ; Load the last 10 sql queries if found
  ;----------------------------------------------------------------------------------------------------------

  For LoadQuery = 0 To 19                                      ; Load up 20 queries from the ini file
    TempGroup.s = "Query " + Str(LoadQuery)                     ; Need this temporary step or wrong value comes back
    TestVal.s = GetIniVal("Queries", TempGroup.s)               ; Get value into temporary variable
    If TestVal.s <> ""                                          ; Test to see if it's empty or not
      AddElement(SqlQuery.s())                                  ; If not empty, add to linked list that tracks it
      SqlQuery.s() = TestVal.s                                  ; 
      AddGadgetItem(#Gadget_mysqlitetest_query, -1, TestVal.s)  ; Also add it to the combo query box
    EndIf
  Next LoadQuery

  ;----------------------------------------------------------------------------------------------------------
  ; Set focus to the logical first gadget we are going to be using
  ;----------------------------------------------------------------------------------------------------------
  ActivateGadget(#Gadget_mysqlitetest_bgetdatabase)

  ;----------------------------------------------------------------------------------------------------------
  ; Set initial quit value to 0 so that program doesn't accidentally close
  ;----------------------------------------------------------------------------------------------------------
  program\progquit = 0

  Repeat
  
    If IsIconic_(Form\winhandle) <> 0                                       ; The window has been minimized
      HideWindow(#Window_mysqlitetest, 1)
      AddSysTrayIcon(1, form\winhandle, UseImage(#Image_mysqlitetest_program))
      SysTrayIconToolTip(1, "SQLite 3.xx Data retrieval in here!!!")
    EndIf

    Select WaitWindowEvent()
    
      Case #PB_Event_CloseWindow
        Select EventWindowID()
          Case #Window_mysqlitetest               : program\progquit = 1    ; Window close event happned so set quit flag
        EndSelect

      Case #PB_Event_Menu
        Select EventMenuID()
          Case #Shortcut_mysqlitetest_return      : Gosub CheckEnterKey     ; See if ENTER was pressed in query box
          Case #Shortcut_mysqlitetest_exit        : program\progquit = 1     ; Set the quit flag
        EndSelect
        
      Case #PB_Event_Gadget
        Select EventGadgetID()
          Case #Gadget_mysqlitetest_bgetdatabase  : Gosub OpenADatabase     ; Open a database to process
          Case #Gadget_mysqlitetest_tables        : Gosub GetColumnName     ; Get the columns of the highlighted table
          Case #Gadget_mysqlitetest_bsave         : Gosub SaveListToDisk    ; Save the sql dump to disk
          Case #Gadget_mysqlitetest_helpbutton    : Gosub ShowHelp          ; Show a help screen to the user
          Case #Gadget_mysqlitetest_exitbutton    : program\progquit = 1     ; Set the quit flag
        EndSelect

      Case #PB_Event_SysTray                                                 ; System tray events
         If EventType() = #PB_EventType_LeftClick
           RemoveSysTrayIcon(1)
           HideWindow(#Window_mysqlitetest, 0)
           SetForegroundWindow_(Form\winhandle)                               ; Un-hiding the window brings it to the front
         EndIf

    EndSelect
    
  Until program\progquit                                                      ; Keep going until the quit flag is set
  
  CloseWindow(#Window_mysqlitetest)                                           ; Close the program window
  
  SetIniKey("Last Dir", "Last Database Dir",  program\lastdbdir, program\inifile)

  ForEach SqlQuery.s()
    SetIniVal("Queries", "Query " + Str(ListIndex(SqlQuery.s())),  SqlQuery.s())
  Next

EndIf

End                                                                           ; End program, removes stub from memory

;===========================================================================================================================
OpenADatabase:                    ; Open a database to process
;===========================================================================================================================

  program\dbname = OpenFileRequester("Database to open", program\lastdbdir, "Database file (*.*)|*.*", 0)
  
  If program\dbname <> ""                                        ; Get last database path opened
    program\lastdbdir = GetPathPart(program\dbname)
  EndIf
  
  If CallCFunctionFast(sqlite3_open, program\dbname, @program\dbhandle) = #SQLITE3_OK
    program\dbopen = 1
    SetStat(#StatusBar_mysqlitetest_messages, "Info: The database " + program\dbname + " was opened successfully, program ready")
    Gosub GetTableNames                                          ; Get a list of the table names in the current database
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The database " + program\dbname + " could not be opened")
    WriteError("OpenADatabase")                                   ; Write an entry to the error log
  EndIf
  
Return

;===========================================================================================================================
GetTableNames:                    ; Get a list of the table names in the current database
;===========================================================================================================================

  If SQL3GetTable("Select name FROM sqlite_master WHERE type='table' ORDER BY name", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0                               ; Query worked, but did we get any data?
      ForEach SqlData.s()                                       ; Go through each line of data returned
        AddGadgetItem(#Gadget_mysqlitetest_tables, -1, RemoveString(SqlData.s(), "|", 0))     ; Get the returned table names
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no tables")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The table information could not be retrieved")  
    WriteError("GetTableNames")                                   ; Write an entry to the error log
  EndIf
  
Return

;===========================================================================================================================
GetColumnName:                    ; Get a list of columns in the currently highlighted table
;===========================================================================================================================

  program\table = GetGadgetItemText(#Gadget_mysqlitetest_tables, GetGadgetState(#Gadget_mysqlitetest_tables), 0)
  
  If SQL3GetTable("PRAGMA table_info(" + program\table + ")", @myRows, @myCols, program\dbhandle)
    If CountList(SqlData.s()) <> 0                               ; Query worked, but did we get any data?
      ClearGadgetItemList(#Gadget_mysqlitetest_columns)          ; If we did, clear the existing list first
      ForEach SqlData.s()                                       ; Go through each line of data returned
        AddGadgetItem(#Gadget_mysqlitetest_columns, -1, StringField(SqlData.s(), 2, "|"))
      Next
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no columns")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The column information could not be retrieved")  
    WriteError("GetColumnName")                                   ; Write an entry to the error log  EndIf
  EndIf
  
Return

;===========================================================================================================================
CheckEnterKey:                    ; See if ENTER was pressed in the query box and then run the query
;===========================================================================================================================

  If program\dbopen                                               ; Can't seem to get focus working here so doing it this way
   ;FocusID = GetFocus_()                                          ; Get the id of the window/object that has focus
   ;Select FocusID                                                 ; Use the id in a gadget selection
     ;Case GadgetID(#Gadget_mysqlitetest_query)                    ; Gadget is the query box
       program\query = GetGadgetText(#Gadget_mysqlitetest_query)  ; Get the text from the query box
       If program\query <> ""                                     ; Don't pass empty string to query maker
         Gosub SaveQuery                                          ; Save last 10 queries to disk
         Gosub RunDatabaseQuery                                   ; Reusable data return routine
       Else
         SetStat(#StatusBar_mysqlitetest_messages, "Error: You have to actually put something in to query!")
       EndIf
   ;EndSelect                                                     ; End the selection
  EndIf
  
Return

;===========================================================================================================================
SaveListToDisk:                   ; Save the sql dump to disk
;===========================================================================================================================

  If CreateFile(0, SaveFileRequester("Save returned query", "QueryDump.txt", "Text (*.txt)|*.txt|All files (*.*)|*.*", 0)) <> 0
    ColTitle.s = ""                                             ; Make sure this is blank or it gets filled before being used!
    For SaveHeadings = 0 To myCols - 1                          ; Go through every column in the list and save headings
      ColTitle.s + Chr(34) + GetListIconColumnText(#Gadget_mysqlitetest_datalist, SaveHeadings) + Chr(34) + ","
      MessageRequester(Str(SaveHeadings), ColTitle.s, #PB_MessageRequester_Ok )
    Next SaveHeadings
    WriteStringN(Sremove(ColTitle.s, "R", 1))                   ; Remove trailing comma. 'R' means from the right
    ColTitle.s = ""                                             ; Clear this afterwards, just in case
    OutString.s = ""                                            ; Make sure this is blank or it gets filled before being used!
    For ListItems = 0 To myRows - 1                             ; Go through items in the list
      For TotalColumns = 0 To myCols - 1                        ; Go through every column in the list
        FlushEvents()                                           ; We are reading the gadget so we need to flush events
        OutString.s + Chr(34) + GetGadgetItemText(#Gadget_mysqlitetest_datalist, ListItems, TotalColumns) + Chr(34) + ","
      Next TotalColumns
      SetStat(#StatusBar_mysqlitetest_records, "Saving Line " + Str(ListItems))
      WriteStringN(Sremove(OutString, "R", 1))                  ; Remove trailing comma. 'R' means from the right
      OutString.s = ""                                          ; Clear this afterwards, just in case
    Next ListItems
    CloseFile(0)
    SetStat(#StatusBar_mysqlitetest_messages, "Info: " + Str(CountGadgetItems(#Gadget_mysqlitetest_datalist)) + " Lines saved To disk")
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: Cannot save the list to disk, something went wrong")
  EndIf

Return

;===========================================================================================================================
RunDatabaseQuery:                 ; Run the database query now. Major improvements thanks to El_Choni!
;===========================================================================================================================

  CallCFunctionFast(sqlite3_prepare, program\dbhandle, program\query, Len(program\query), @Stmt, @Tail) ; Prepare for colnames
  
  If SQL3GetTable(program\query, @myRows, @myCols, program\dbhandle)      ; Run the query
    If CountList(SqlData.s()) <> 0
      ClearGadgetItemList(#Gadget_mysqlitetest_datalist)                  ; Clear previous items from the list
      SetStat(#StatusBar_mysqlitetest_messages, "Info: Removing existing collumns")
      For colremove = 1 To myCols - 1                                    ; Remove the columns from the previous query
        RemoveGadgetColumn(#Gadget_mysqlitetest_datalist, 1)
      Next colremove
      SetStat(#StatusBar_mysqlitetest_messages, "Info: Adding new collumns")
      For coladd = 1 To myCols - 1                                      ; Add number of columns equal to number of fields
        AddGadgetColumn(#Gadget_mysqlitetest_datalist, 1, "", 100)       ; Add the new colum to the ListIcon with a width of 100
      Next coladd
      SetStat(#StatusBar_mysqlitetest_messages, "Info: Fixing new collumn titles")
      For titlefix = 0 To myCols - 1
        ColTitle.s = PeekS(CallCFunctionFast(sqlite3_column_name, Stmt, titlefix)) ; Add title to collumn heading
        SetListIconColumnText(#Gadget_mysqlitetest_datalist, titlefix, ColTitle.s)
      Next titlefix                                                      ; Now do the next column
      SetStat(#StatusBar_mysqlitetest_messages, "Info: Please wait as I find all your requested data")
      ForEach SqlData.s()                                                ; Process each new item and add them to display
        FlushEvents()                                                     ; Flush window events to stop form greying out
        AddGadgetItem(#Gadget_mysqlitetest_datalist, -1, ReplaceString(SqlData.s(), "|", Chr(10), 1, 1))
      Next
      SetStat(#StatusBar_mysqlitetest_messages, "Info: Please wait while I auto resize the display to fit the data width")
      For WidthSet = 0 To myCols - 1                                    ; Auto set the field widths to biggest field
        SendMessage_(GadgetID(#Gadget_mysqlitetest_datalist), #LVM_SETCOLUMNWIDTH, WidthSet, #LVSCW_AUTOSIZE)
      Next WidthSet
      SetStat(#StatusBar_mysqlitetest_messages, "Info: The query matched " + Str(myRows) + " lines of data and " + Str(myCols) + " columns in each line")
      SetStat(#StatusBar_mysqlitetest_records, Str(myRows) + " Record(s)")
    Else
      SetStat(#StatusBar_mysqlitetest_messages, "Error: There is no data returned by the query, database has no data")
    EndIf
  Else
    SetStat(#StatusBar_mysqlitetest_messages, "Error: The database information could not be retrieved")  
    WriteError("RunDatabaseQuery")                                      ; Write an entry to the error log
  EndIf

Return

;===========================================================================================================================
SaveQuery:                        ; Save the last entered query to the stack
;===========================================================================================================================

  If CountList(SqlQuery.s()) = 20
    FirstElement(SqlQuery.s())
    DeleteElement(SqlQuery.s())
  EndIf
  
  AddElement(SqlQuery.s())

  SqlQuery.s() = program\query
  
  AddGadgetItem(#Gadget_mysqlitetest_query, -1, program\query)
  
Return

;===========================================================================================================================
ShowHelp:                         ; Show a help screen to the user
;===========================================================================================================================

Return


Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Hmm - did I miss the ini file somewhere?
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4791
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post by Fangbeast »

If not found, it should create it the first time you exit the program. Tell me if it doesn't.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Post Reply