Login, query and retreive data from a MySQL server, direct
Posted: Wed Sep 15, 2004 3:11 pm
Code updated For 5.20+
Read the comments at the top of the code. You need the libmsql.dll library in the same dir as this code.
Read the comments at the top of the code. You need the libmsql.dll library in the same dir as this code.
Code: Select all
;==============================================================================================================================
; Please note that all the MySQL direct database code I found in the PureBasic forum, done by Max2 and not by me. He has
; given me permission to use it as I see fit in a tutorial and it is hoped that this mini program will help someone get to
; grips with using MySQL server queries directly, without having to install either an ODBC driver or having to go through
; the ODBC control panel to setup a database each time.
;
; I only put this program together using his code, no big thing. Use it as you see fit.
;
; *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 Mx2 and (me too maybe???). If you don't like it, I don't want to know. Fang.
;==============================================================================================================================
; Predefine my global structure types so I don't have to keep adding the type throughout the program
;==============================================================================================================================
dbHnd.l
SQL.s
row.s
i.l
j.l
affRows.l
fieldNum.l
rowsNum.l
;==============================================================================================================================
; Any global variables my programs need, particularly the aliases MySQL library functions
;==============================================================================================================================
Global CFF_MySQL_Init.l, CFF_MySQL_ERRNO.l
Global CFF_MySQL_ERROR.l, CFF_MySQL_Real_Connect.l
Global CFF_MySQL_Real_Query.l, CFF_MySQL_Store_Result.l
Global CFF_MySQL_Field_Count.l, CFF_MySQL_Use_Result.l
Global CFF_MySQL_Fetch_Row.l, CFF_MySQL_Fetch_Lengths.l
Global CFF_MySQL_Free_Result.l, CFF_MySQL_Close.l
;==============================================================================================================================
; Get the current directory. May be used for various functions
;==============================================================================================================================
CurrentDir.s = Space(512)
Result = GetCurrentDirectory_(Len(CurrentDir), @CurrentDir)
;==============================================================================================================================
; Specific constans for the MySQL functions
;==============================================================================================================================
#libmysql = 1
#MySQL_CLIENT_COMPRESS = 32
;============================================================================================================================
; Main window title which we will overwrite with other information
;============================================================================================================================
#MainTitle = "MySQL - "
;============================================================================================================================
; Constants
;============================================================================================================================
Enumeration 1
#Window_mysqltest
EndEnumeration
#WindowIndex = #PB_Compiler_EnumerationValue
Enumeration 1
#Gadget_mysqltest_mainframe
#Gadget_mysqltest_datalist
#Gadget_mysqltest_controlframe
#Gadget_mysqltest_querylabel
#Gadget_mysqltest_querybox
#Gadget_mysqltest_loginframe
#Gadget_mysqltest_hostlabel
#Gadget_mysqltest_hostbox
#Gadget_mysqltest_userlabel
#Gadget_mysqltest_userbox
#Gadget_mysqltest_passwordlabel
#Gadget_mysqltest_passwordbox
#Gadget_mysqltest_databaselabel
#Gadget_mysqltest_databasebox
#Gadget_mysqltest_portlabel
#Gadget_mysqltest_portbox
#Gadget_mysqltest_savelogin
#Gadget_mysqltest_dumpbutton
#Gadget_mysqltest_otherframe
#Gadget_mysqltest_helpbutton
#Gadget_mysqltest_exitbutton
#Gadget_mysqltest_clearlist
#Gadget_mysqltest_return
EndEnumeration
#GadgetIndex = #PB_Compiler_EnumerationValue
;==============================================================================================================================
; Program window
;==============================================================================================================================
Procedure.l Window_mysqltest()
If OpenWindow(#Window_mysqltest,175,0,800,555,#MainTitle,#PB_Window_ScreenCentered|#PB_Window_Invisible)
AddKeyboardShortcut(#Window_mysqltest, #PB_Shortcut_Return, #Gadget_mysqltest_return)
FrameGadget3D(#Gadget_mysqltest_mainframe,0,0,640,510,"")
ListIconGadget(#Gadget_mysqltest_datalist,5,10,630,495,"itemslist",1000,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
GadgetToolTip(#Gadget_mysqltest_datalist,"All items returned from a properly formatted SQL query will end up in this list and be cleared in the next call")
FrameGadget3D(#Gadget_mysqltest_controlframe,0,510,640,45,"")
TextGadget(#Gadget_mysqltest_querylabel,10,530,60,15,"SQL Query")
StringGadget(#Gadget_mysqltest_querybox,70,525,470,20,"")
GadgetToolTip(#Gadget_mysqltest_querybox,"Type in a properly formatted SQL query in here and press ENTER/RETURN to execute it")
FrameGadget3D(#Gadget_mysqltest_loginframe,645,0,155,510,"")
TextGadget(#Gadget_mysqltest_hostlabel,655,15,135,15,"Host IP or host name")
StringGadget(#Gadget_mysqltest_hostbox,655,30,135,20,"")
GadgetToolTip(#Gadget_mysqltest_hostbox,"Type in the name of the system that hosts the database or the IP version")
TextGadget(#Gadget_mysqltest_userlabel,655,55,135,15,"User name")
StringGadget(#Gadget_mysqltest_userbox,655,70,135,20,"",#PB_String_LowerCase)
GadgetToolTip(#Gadget_mysqltest_userbox,"Type in the name of the user who is registered for use with that database")
TextGadget(#Gadget_mysqltest_passwordlabel,655,95,135,15,"Password")
StringGadget(#Gadget_mysqltest_passwordbox,655,110,135,20,"",#PB_String_Password|#PB_String_LowerCase)
GadgetToolTip(#Gadget_mysqltest_passwordbox,"Type in the login password of the user that is registered for use with that database")
TextGadget(#Gadget_mysqltest_databaselabel,655,135,135,15,"Database name")
StringGadget(#Gadget_mysqltest_databasebox,655,150,135,20,"",#PB_String_LowerCase)
GadgetToolTip(#Gadget_mysqltest_databasebox,"Type in the name of the database that you wish to access on the remote system")
TextGadget(#Gadget_mysqltest_portlabel,655,175,135,15,"Port number")
StringGadget(#Gadget_mysqltest_portbox,655,190,135,20,"",#PB_String_Numeric)
GadgetToolTip(#Gadget_mysqltest_portbox,"Type in the port number that the database server allows queries on")
CheckBoxGadget(#Gadget_mysqltest_savelogin,655,220,135,15,"Save current login")
GadgetToolTip(#Gadget_mysqltest_savelogin,"Check this box if you want to save the current login to be auto-loaded next time you start this program")
ButtonGadget(#Gadget_mysqltest_dumpbutton,655,480,135,20,"Dump list to disk")
GadgetToolTip(#Gadget_mysqltest_dumpbutton,"press this button to dump the results of the query to a disk file")
FrameGadget3D(#Gadget_mysqltest_otherframe,645,510,155,45,"")
ButtonGadget(#Gadget_mysqltest_helpbutton,655,525,60,20,"Help")
GadgetToolTip(#Gadget_mysqltest_helpbutton,"press this button to show any help file linked to this program")
ButtonGadget(#Gadget_mysqltest_exitbutton,730,525,60,20,"Exit")
GadgetToolTip(#Gadget_mysqltest_exitbutton,"press this button to exit this program immediately")
CheckBoxGadget(#Gadget_mysqltest_clearlist,550,530,80,15,"Clear list")
GadgetToolTip(#Gadget_mysqltest_clearlist,"Select this button to clear the list before the next SQL query")
HideWindow(#Window_mysqltest,0)
ProcedureReturn WindowID(#Window_mysqltest)
EndIf
EndProcedure
;==============================================================================================================================
; All of the aliased MySQL library routines and the library loader
;==============================================================================================================================
Procedure MySQL_Init()
Shared CurrentDir.s
If OpenLibrary(#libmysql, CurrentDir.s + "\libmySQL.dll")
CFF_MySQL_Init = GetFunction(#libmysql, "mysql_init")
CFF_MySQL_ErrNo = GetFunction(#libmysql, "mysql_errno")
CFF_MYSQL_Error = GetFunction(#libmysql, "mysql_error")
CFF_MySQL_Real_Connect = GetFunction(#libmysql, "mysql_real_connect")
CFF_MySQL_Real_Query = GetFunction(#libmysql, "mysql_real_query")
CFF_MySQL_Store_Result = GetFunction(#libmysql, "mysql_store_result")
CFF_MySQL_Field_Count = GetFunction(#libmysql, "mysql_field_count")
CFF_MySQL_Use_Result = GetFunction(#libmysql, "mysql_use_result")
CFF_MySQL_Fetch_Row = GetFunction(#libmysql, "mysql_fetch_row")
CFF_MySQL_Fetch_Lengths = GetFunction(#libmysql, "mysql_fetch_lengths")
CFF_MySQL_Free_Result = GetFunction(#libmysql, "mysql_free_result")
CFF_MySQL_Close = GetFunction(#libmysql, "mysql_close")
ProcedureReturn CallFunctionFast (CFF_MySQL_Init, dbHnd)
EndIf
EndProcedure
Procedure.s MySQL_GetError(db_ID, requester)
Protected Errormsg.s, i.l, Error.l
If CallFunctionFast(CFF_MySQL_ErrNo, db_ID) > 0
*Error = CallFunctionFast(CFF_MySQL_Error, db_ID)
Errormsg = PeekS(*Error)
If requester
SetWindowTitle(#Window_mysqltest, #MainTitle + Errormsg)
EndIf
EndIf
ProcedureReturn Errormsg
EndProcedure
Procedure MySQL_Real_Connect(dbHnd, host.s, user.s, password.s, db.s, port.l, options.l)
ProcedureReturn CallFunctionFast(CFF_MySQL_Real_Connect, dbHnd, @host, @user, @password.s, @db, port, 0, options)
EndProcedure
Procedure MySQL_Real_Query(dbHnd, Query.s)
ProcedureReturn CallFunctionFast(CFF_MySQL_Real_Query, dbHnd, @Query, Len(Query))
EndProcedure
Procedure MySQL_Store_Result(dbHnd)
ProcedureReturn CallFunctionFast(CFF_MySQL_Store_Result, dbHnd)
EndProcedure
Procedure MySQL_Field_Count(dbHnd)
ProcedureReturn CallFunctionFast(CFF_MySQL_Field_Count, dbHnd)
EndProcedure
Procedure MySQL_Use_Result(dbHnd)
ProcedureReturn CallFunctionFast(CFF_MySQL_Use_Result, dbHnd)
EndProcedure
Procedure MySQL_Fetch_Row (*mysqlResult)
ProcedureReturn CallFunctionFast(CFF_MySQL_Fetch_Row, *mysqlResult)
EndProcedure
Procedure MySQL_Fetch_Lengths (*mysqlResult)
ProcedureReturn CallFunctionFast (CFF_MySQL_Fetch_Lengths, *mysqlResult)
EndProcedure
Procedure MySQL_Free_Result (*mysqlResult)
ProcedureReturn CallFunctionFast(CFF_MySQL_Free_Result, *mysqlResult)
EndProcedure
Procedure MySQL_Close (dbHnd)
CallFunctionFast(CFF_MySQL_Close, dbHnd)
EndProcedure
;============================================================================================================================
; Try to initialise the database environment (Procedure MySQL_Init())
;============================================================================================================================
dbHnd = MySQL_Init()
If dbHnd
libOpened = 1 ; Tell all routines that the library was opened okay
Else
libOpened = 0
Message = MessageRequester("Critical Error", "libmysql.dll not found in programs' startup directory")
End
EndIf
;============================================================================================================================
; Main Program Loop
;============================================================================================================================
If Window_mysqltest()
quitmysqltest = 0 ; Set the program quit semaphore
Gosub LoadLastLogin ; Load the last login if it exists
Repeat ; Now start checking for all window and gadget events
EventID = WaitWindowEvent()
Select EventID
Case #PB_Event_CloseWindow
If EventWindow() = #Window_mysqltest
quitmysqltest = 1
EndIf
Case #PB_Event_Menu
Select EventMenu()
Case #Gadget_mysqltest_return : Gosub CheckEnter ; Was Enter pressed in the query box?
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #Gadget_mysqltest_dumpbutton : Gosub DumpListToDisk
Case #Gadget_mysqltest_helpbutton
Case #Gadget_mysqltest_exitbutton : quitmysqltest = 1
EndSelect
EndSelect
Until quitmysqltest
Gosub SaveCurrentLogin ; Save the current login if the checkbox is selected
CloseWindow(#Window_mysqltest)
EndIf
End
;============================================================================================================================
; Load the last login saved by the user if there was one
;============================================================================================================================
LoadLastLogin:
If OpenFile(0, "LastLogin.txt") <> 0
SetGadgetText(#Gadget_mysqltest_hostbox, ReadString(0))
SetGadgetText(#Gadget_mysqltest_userbox, ReadString(0))
SetGadgetText(#Gadget_mysqltest_passwordbox, ReadString(0))
SetGadgetText(#Gadget_mysqltest_databasebox, ReadString(0))
SetGadgetText(#Gadget_mysqltest_portbox, ReadString(0))
If ReadString(0) = "1"
SetGadgetState(#Gadget_mysqltest_savelogin, 1)
EndIf
CloseFile(0)
SetWindowTitle(#Window_mysqltest, #MainTitle + "Last saved login loaded")
EndIf
Return
;============================================================================================================================
; Save the current login details if the user has selected the checkbox
;============================================================================================================================
SaveCurrentLogin:
If GetGadgetState(#Gadget_mysqltest_savelogin) = 1
If CreateFile(0, "LastLogin.txt") <> 1
WriteStringN(0,GetGadgetText(#Gadget_mysqltest_hostbox))
WriteStringN(0,GetGadgetText(#Gadget_mysqltest_userbox))
WriteStringN(0,GetGadgetText(#Gadget_mysqltest_passwordbox))
WriteStringN(0,GetGadgetText(#Gadget_mysqltest_databasebox))
WriteStringN(0,GetGadgetText(#Gadget_mysqltest_portbox))
WriteStringN(0,"1")
CloseFile(0)
EndIf
EndIf
Return
;============================================================================================================================
; Check if the ENTER key was pressed in the SQL query box
;============================================================================================================================
CheckEnter:
FocusID = GetFocus_() ; Get the id of the window/object that has focus
Select FocusID ; Use the id in a gadget selection
Case GadgetID(#Gadget_mysqltest_querybox) ; Gadget is the barcode box
Query.s = GetGadgetText(#Gadget_mysqltest_querybox) ; Get the text from the barcode box
Gosub ConnectToDatabase ; Reusable data return routine
EndSelect ; End the selection
;============================================================================================================================
; Try to connect to the database
;============================================================================================================================
ConnectToDatabase:
If libOpened
host.s = GetGadgetText(#Gadget_mysqltest_hostbox)
user.s = GetGadgetText(#Gadget_mysqltest_userbox)
passwd.s = GetGadgetText(#Gadget_mysqltest_passwordbox)
db.s = GetGadgetText(#Gadget_mysqltest_databasebox)
port.l = Val(GetGadgetText(#Gadget_mysqltest_portbox))
If MySQL_Real_Connect(dbHnd, host, user, passwd, db, port.l, 32) <> 0
SetWindowTitle(#Window_mysqltest, #MainTitle + "Connected and getting your data, please wait")
Gosub GetSqlData
Else
MySQL_GetError(dbHnd, 1)
Connect.l = 0
EndIf
Else
SetWindowTitle(#Window_mysqltest, #MainTitle + "SQL library was never loaded so we cannot connect to the database!!")
EndIf
Return
;============================================================================================================================
; Retrieve and display the data to the user now
;============================================================================================================================
GetSqlData:
If GetGadgetState(#Gadget_mysqltest_clearlist) = 1
ClearGadgetItems(#Gadget_mysqltest_datalist)
EndIf
Result = MySQL_Real_Query (dbHnd, Query.s) ; Run the given query
If Result ; If the query didn't work, give an error
MySQL_GetError(dbHnd, 1)
Else
;----------------------------------------------------------------------------------------------
*mysqlResult = MySQL_Use_Result(dbHnd) ; If data returned, use the result
If *mysqlResult = 0
If MySQL_Field_Count(dbHnd) ; No fields are returned so that's an error
MySQL_GetError(dbHnd, 1)
Else
MySQL_GetError(dbHnd, 1) ; Fields are returned, so no error but query didn't return data
EndIf
Else
;----------------------------------------------------------------------------------------------
affRows = CallFunction(#libmysql,"mysql_affected_rows",dbHnd) ; How many rows affected
fieldNum = CallFunction(#libmysql,"mysql_num_fields", *mysqlResult) ; How many fields
rowsNum = CallFunction(#libmysql,"mysql_num_rows", *mysqlResult) ; How many rows
;--------------------------------------------------------------------------------------------
Repeat ; Sequentially process all returned data
*mysqlRow = MySQL_Fetch_Row(*mysqlResult)
If *mysqlRow <> 0
*mysqlLen = MySQL_Fetch_Lengths(*mysqlResult)
row = ""
For j = 1 To fieldNum ; Length of given field
length = PeekL(*mysqlLen + 4 * (j - 1))
fieldptr = PeekL(*mysqlRow + 4 * (j - 1))
If fieldptr > 0
content.s = PeekS(fieldptr, length)
Else
content = "NULL" ; Zero pointer returned means empty field
EndIf
row = row + content + ";" ; Debug content (individual collumns)
Next j
AddGadgetItem(#Gadget_mysqltest_datalist, -1, row) ; Dump the row to the listbox
EndIf
Until *mysqlRow = 0
result = MySQL_Free_Result(*mysqlResult)
MySQL_Close(dbHnd) ; Close the database when no longer needed
;--------------------------------------------------------------------------------------------
EndIf
;----------------------------------------------------------------------------------------------
EndIf
SetWindowTitle(#Window_mysqltest, #MainTitle + "Found all matching data, nothing left to do.")
Return
;============================================================================================================================
; Dump the list to disk at the users' request
;============================================================================================================================
DumpListToDisk:
Lines.l = CountGadgetItems(#Gadget_mysqltest_datalist) ; How many lines to save
DumpList.s = SaveFileRequester("Save returned query", "QueryDump.txt", "Text (*.txt)|*.txt|All files (*.*)|*.*", 0)
If CreateFile(0, DumpList.s) <> 0
For ListItems = 0 To Lines - 1
CurrentLine.s = GetGadgetItemText(#Gadget_mysqltest_datalist, ListItems, 0)
WriteStringN(0,CurrentLine.s)
Next ListItems
CloseFile(0)
EndIf
Return