Rapid-Q Documentation by William Yu (c)1999 Chapter 14


14. Programming in MySQL

This chapter is a quick overview of what you can do with the QMYSQL component. It does not teach you about SQL or how to construct proper queries. It is assumed you have some prior knowledge of SQL, but not necessarily with MySQL.

14.1 Quick Introduction
MySQL is basically free for Unix and OS/2 platforms, but Rapid-Q only supports MySQL for Linux and Windows since my resources are limited to such machines. Under Windows, if you like MySQL, then you are required to pay a license fee after a 30 day trial period. Not to be confused with paying me of course, but if you want, I'll oblige. Why did I choose MySQL over other database servers? The reason is fairly simple, yet deserves some explanation anyway. MySQL is free, mostly, and it's multiplatform, which fits into Rapid-Q quite nicely. It's also easier for me to test, and quite simple to implement under Rapid-Q. It's fairly lightweight, fast, robust, and did I mention free? Perhaps in the future, other database servers will be supported, ie. through MyODBC or Window's ODBC.
    Required files:
  • MySQL serverversion 3.22.xx or better
  • Rapid-Q MySQL Libraries
  • MySQL Client if you don't want to run a server
After installing the MySQL server, test it to make sure it works (read their nice documentation and help files), you'll also need to copy LIBMYSQL.DLL (under Windows) and libmysqlclient.* (under Linux) to your library path directory. C:\WINDOWS\SYSTEM under Windows, and maybe /usr/lib under Linux (you can also just add a library path to the file instead of moving it). These library files are required by Rapid-Q, they should have come with your MySQL distribution, probably in C:\MYSQL\LIB and /usr/local/lib/mysql depending on your installation. If you already have MySQL installed, which is possible, make sure it's up to date, or if you have an SQL Administrator, check with the that person.

14.2 Connecting to MySQL
The introduction assumed that you wanted to install a MySQL server on your machine, but you can access a MySQL database from anywhere, as long as you have access of course. If you don't want to install a MySQL server (why wouldn't you?) then make sure you have the proper client libraries, ie. LIBMYSQL.DLL. To begin with, I'll assume you have the MySQL server installed. To connect to your local MySQL server is simple enough:
            DIM MySQL AS QMYSQL

            Host$ = ""
            User$ = ""
            Password$ = ""
            MySQL.Connect(Host$, User$, Password$)

            IF MySQL.Connected THEN PRINT "Successfully connected"
Change User$ and Password$ to suit your needs. Host$ can also take the value of "localhost" but is not necessary in this case. Now to connect to a remote MySQL server located, say, in allsql.com
            DIM MySQL AS QMYSQL

            Host$ = "allsql.com"
            User$ = "anonymous"
            Password$ = "guest"
            MySQL.Connect(Host$, User$, Password$)

            IF MySQL.Connected THEN PRINT "Successfully connected"
Most servers will use the standard MySQL port 3306, but if you know the exact port, then you can use the method RealConnect.
            DIM MySQL AS QMYSQL

            Host$ = "allsql.com"
            User$ = "anonymous"
            Password$ = "guest"
            Port% = 12345
            MySQL.RealConnect(Host$, User$, Password$, "", Port%, "", 0)

            IF MySQL.Connected THEN PRINT "Successfully connected"
See appendix section for the parameters of QMYSQL.RealConnect. It is suggested by the MySQL documentation that you use RealConnect instead of the using Connect.

14.3 How to perform queries and obtain the results
Write your queries like you would normally, for example, if you want to select everything from a certain table, say you have a table named user, then you can do this:
            DIM MySQL AS QMYSQL

            '' First connect to server

            '' Use database
            MySQL.SelectDB("mysql")

            '' Perform query
            MySQL.Query("select * from user")
The result of this query is stored internally, and sequentially. To obtain the result, you'll need to Fetch it. You can visualize a 2 dimensional table:
Since the result is stored sequentially, you have to fetch each row one at a time (not necessarily true, but assume we have no other choice). To do this is quite simple:
            WHILE MySQL.FetchRow       '' Get next row
                MySQL.FieldSeek(0)     '' Reset field position
                FOR I = 0 TO MySQL.FieldCount-1
                    PRINT MySQL.Row(I) '' Read current row element I
                NEXT
            WEND
MySQL.FetchRow fetches the next row. As long as there are still rows available to fetch, MySQL.FetchRow returns TRUE (non-zero number). MySQL.FieldCount is used to count how many fields per row there are in the current table. The rest is self explanatory.

14.4 Interfacing QMYSQL with QSTRINGGRID
As you may notice, it would be nice if the results could just be preloaded into a string grid instead of having to fetch everything and doing it manually. Unfortunately I haven't got any motivation to do this right now, but you can use this simple code until I get off my butt and implement it internally:
            SUB ExecuteQuery(MySQL AS QMYSQL, Grid AS QSTRINGGRID, Query AS STRING)
                IF MySQL.Query(Query) = 0 THEN
                   '' Failed to execute
                   EXIT SUB
                END IF

                DEFINT I = 0, J

                ''-- Write header
                Grid.ColCount = MySQL.FieldCount
                WHILE MySQL.FetchField
                   Grid.Cell(I,0) = MySQL.Field.Name
                   I++
                WEND

                Grid.RowCount = MySQL.RowCount+1
                J = 1
                WHILE MySQL.FetchRow       '' Get next row
                   MySQL.FieldSeek(0)      '' Reset field position
                   FOR I = 0 TO MySQL.FieldCount-1
                      Grid.Cell(I,J) = MySQL.Row(I)
                   NEXT
                   J++
               WEND
            END SUB

            ''-- Example
            ExecuteQuery(MySQL, MyGrid, "select * from user")
Obviously, you can interface QMYSQL with any component, or components, you want.

14.5 Storing and retrieving blobs
Blobs are just binary data that require special processing. Since blobs can contain NULL characters and other special characters that affect MySQL and Rapid-Q, you'll need to do some special processing with your binary data. Please note that blob sizes vary, depending on the field type. A BLOB, by default can hold up to 65535 bytes (a LONGBLOB should be able to handle 2^32-1 bytes). If you want to change the buffer size, you'll have to read up on it (max_allowed_packet). To store binary data, like images, you'll have to preprocess certain characters before you can send it over to your MySQL database.
            $INCLUDE "RAPIDQ.INC"

            DIM MySQL AS QMYSQL

            ''-- Connect to database code, etc...

            DIM File AS QFILESTREAM
            File.Open("test.bmp", fmOpenRead)

            ''-- Read file as binary, preserves NULL chars
            Buffer$ = File.ReadBinStr(File.Size)

            ''-- Here's the special processing
            ''-- Converts NULLs to \0 and others
            ProcessedBuffer$ = MySQL.EscapeString(Buffer$, File.Size)

            ''-- Insert blob in our table
            MySQL.Query("insert into MyImageTable values('Label 1', '" + _
                        ProcessedBuffer$ + "')")

            File.Close
            MySQL.Close
Since we're dealing with binary data, you have to be aware that we don't use LEN() or any other STRING processing functions with our binary data. Note that we can store text data in blob fields, in which case you can use any STRING processing functions you want. You may notice that MySQL.EscapeString converts the binary data to a usable format that can be passed to the MySQL database. Basically all it does is convert NULLs to '\0', ' to \', " to \", and CRLF to \r and \n respectively. Once parsed, the new string is returned which you can use in a query. So far so good, now we consider retrieving our blobs:
            $INCLUDE "RAPIDQ.INC"
            $INCLUDE "MYSQL.INC"

            DIM MySQL AS QMYSQL

            ''-- Connect to database code, etc...

            DIM File AS QFILESTREAM
            File.Open("out.bmp", fmCreate) ''-- Create new file

            ''-- Your query here
            MySQL.Query("select * from MyImageTable")

            WHILE MySQL.FetchRow
                MySQL.FieldSeek(0)
                MySQL.FetchLengths ''-- Required for binary data
                FOR I = 0 TO MySQL.NumField-1
                    MySQL.FetchField
                    IF MySQL.Field.Type = FIELD_TYPE_BLOB THEN
                        ''-- Read binary data from table
                        Buffer$ = MySQL.RowBlob(I, MySQL.Length(I))
                        File.WriteBinStr(Buffer$, MySQL.Length(I))
                    ELSE
                        Buffer$ = MySQL.Row(I)
                    END IF
                NEXT
            WEND

            File.Close
            MySQL.Close
Retrieving blobs from the database is a little more confusing than storing blobs. The first thing you have to note is that reading binary data and text strings are 2 different operations. Since text strings are NULL terminated, you don't have to worry about how many bytes to read, this is automatically calculated for you. However, since binary data can contain NULL characters, this makes reading blobs a little bit tricky. You have to fetch the lengths of each field, since we have blobs in our table, this is done by calling MySQL.FetchLengths for each row. Then to find out the length of each field, you use the internal array MySQL.Length(index%) which returns the length for field index%. Why do we have to do this? Because we need to know the size of our blob before we can read it in. To read binary data from our database, you use the specialized function MySQL.RowBlob(Row%, Bytes%) which returns a binary string. With this binary string, you can write the data to a file or memory, or manipulate the data directly. In the above example, we're just writing the data to a file.

14.6 Using LOADBLOB and SAVEBLOB
In the previous section, we uncovered the natural way of storing and retrieving blobs (binary data). However, there is an easier and faster way of doing the samething.
            ''-- Recall the natural way
            ProcessedBuffer$ = MySQL.EscapeString(Buffer$, File.Size)
            MySQL.Query("insert into MyImageTable values('Label 1', '" + _
                        ProcessedBuffer$ + "')")

            ''-- Using LOADBLOB instead
            ProcessedBuffer$ = MySQL.LoadBlob("test.bmp")
            MySQL.Query("insert into MyImageTable values('Label 1', '" + _
                        ProcessedBuffer$ + "')")
Using LOADBLOB eliminates the use of MySQL.EscapeString since it is just implemented internally for you. It simply takes a single argument (the name of the file to include), and returns the processed string. To retrieve a blob from the database and save it to a file, you can try this:
            WHILE MySQL.FetchRow
                MySQL.FieldSeek(0)
                '' MySQL.FetchLengths
                FOR I = 0 TO MySQL.NumField-1
                    MySQL.FetchField
                    IF MySQL.Field.Type = FIELD_TYPE_BLOB THEN
                        ''-- Save data to file
                        MySQL.SaveBlob(I, "temp.bmp")
                    ELSE
                        Buffer$ = MySQL.Row(I)
                    END IF
                NEXT
            WEND
In this instance we can ignore using MySQL.FetchLengths since it is, again, implemented internally for you. MySQL.SaveBlob takes two arguments. The first is the index (or field number if you will), and the second argument is the name of the file to save to. There are no return values associated with this function.

14.7 In conclusion
Using MySQL can save you a lot of time and effort, since you don't need to design your own database file structure, and searching is quite fast. Not to mention that MySQL is multiplatform, so you can use MySQL with Windows and Linux. If you already have prior knowledge with programming in MySQL, you'll probably notice some differences. For example,
            I = MySQL.SelectDB("mysql")
Under Rapid-Q, this function returns 0 if database cannot be opened, and a non-zero number otherwise. However, if you've used LIBMYSQL.DLL before, this function (called mysql_select_db) returns 0 on success and -1 on failure. So basically, just reverse your way of thinking when using Rapid-Q.


Prev ChapterContentsNext Chapter