MyC Reference Manual
Introduction
MyC is a set of simple C routines intended to make programming applications for use with the MySQL database engine a bit easier, especially for those familiar with Microsoft’s DAO engine model (used with Microsoft Access and Microsoft Visual Basic).
MyC uses a similar model to access data within a database – OpenDatabase to open a database, OpenRecordset to open a result set, Move routines to move around within the result set, and AddNew/Edit and Update/Delete to add, edit or delete data within the database.
Current Version/Change Log
The current version of MyC is 0.0.1 ALPHA.
Restrictions
MyC is not intended to open more than one result set at a time – multiple result set support will be forthcoming in a future release.
If a result set does not have a unique key associated with each record, then the Delete() routine will cause only the first matching referenced record to be deleted. This is at variance with the DAO model, which will delete only the record currently referenced, which may or may not be the first matching record.
Currently, MyC will only run on Linux, but it should be straightforward to port to other UNIX variants. No attempt has been made to either port the code or write the code with an idea of porting to any Windows platform. I haven’t written C for Windows since Windows 2.1, so I haven’t a clue how difficult it would be, but the code doesn’t use anything approaching esoteric, so it shouldn’t be too difficult.
Neither Purify nor any other sort of memory leak checker has been run on MyC.
Please remember that this code is ALPHA, and is subject to change. It’s probably got bugs in it somewhere, and if you push the boundaries, you’ll probably find one or two. Test your code thoroughly, especially before putting this code into any sort of production environment. This code is provided with the hope that it will be useful, but without warranty. It works for me, I hope it works for you. I’ve got it running here, manipulating several databases – one with news headlines that’s got a web interface, one doing registration for a convention in Toronto in August (see
http://www.rcw139.ca for details), and one automatically archiving all incoming email addressed to me.Header Files
Currently, all MyC routines are included in one header file,"database.h". The name of this file is not critical and can be changed at any time to suit a particular site’s needs.
This file should be included first, and includes stdio.h and stdlib.h If "#define MYC_DEBUG" is placed before including database.h, then extensive debugging code will be written to the stderr stream.
Compiling
MyC programs are compiled the same way as other MySQL C API programs. For more information, see the MySQL Reference Manual at http://www.tcx.se.
Initialization
Calling OpenDatabase() with the name of the database to be opened, the host name, the user name, and the password will initialize the application and open the selected database. EOF is returned on failure, NULL is returned on success.
Calling OpenRecordset() with a valid SQL query string opens a result set that contains the results of the query. OpenRecordset() returns EOF on failure or NULL on success. The number of records in the result set can be obtained by calling RecordCount(), which returns the number of records in the result set as an unsigned integer.
Moving Around The Result Set
The result set can be traversed with MoveNext, MovePrev, MoveFirst, and MoveLast, which move to the next, previous, first, and last records in the result set, respectively. If the result set is not valid, these routines return EOF, otherwise, they return NULL.
Accessing Data
Data in the current row in a result set can be accessed by calling GetField or GetFieldN. GetField is called with the name of the field as an argument, and returns a character pointer to the data, or a character pointer to EOF on failure. GetFieldN works in a similar fashion, except that GetFieldN is called with the number of the desired field (origin 0).
Writing Data
Data can be written to a table in one of two ways – by either calling OpenRecordset() with an "INSERT INTO" or "UPDATE" query (or any other valid SQL statement, for that matter), or by use of the AddNew or Edit functions.
AddNew() is called with no arguments, and sets internal flags such that a subsequent call to Update() will generate an "INSERT INTO" SQL statement. Similarly, Edit() is also called with no arguments, and sets internal flags such that a subsequent call to Update() will generate an "UPDATE" SQL statement.
To set the individual fields, SetField, SetFieldN, or SetFieldB is used. SetField is called with two arguments – the name of the field to be set, and the value to set the named field. Similarly, SetFieldN is called with two arguments, but like GetFieldN, the first argument is the number of the field, rather than the name. SetFieldB is used with binary data, and will convert binary data ending with a NULL into a form that can be stored. Note that SetFieldB will overwrite the supplied value string. No provision is made for converting pure binary data, although one could call mysql_escape_string() and pass the returned pointer to SetField or SetFieldN.
It is important to note that SetField and similar routines store a pointer to the data to be written, not the actual data itself.
After all the fields are set, Update() is called with the name of the table to be updated. Update() returns EOF on failure or NULL on success.
After data is added to or updated in a table, sometimes it is useful to have the current record set reflect that changed data. Calling Refresh() will re-run the query run by the last OpenRecordset() (up to 4096 bytes) and is equivalent to calling OpenRecordset(), except that the current row is the same as before calling Refresh().
Deleting Data
Calling Delete() with the name of the affected table will delete the current row from the table. If there are rows with duplicate data, only the first row will be deleted.
Getting Information
Currently, the following information routines are suppported: RecordCount(), FieldCount(), AbsolutePosition(), and RecordsetEOF(). RecordCount returns an unsigned integer indicating the current number of records in the result set. FieldCount returns the number of fields in a row of the result set. FieldValue is called with the number of a field and returns its value, while FieldName is called with the number of a field and returns its name. AbsolutePosition returns the row number of the current row in the result set. RecordsetEOF returns either TRUE if there are no valid records in the result set or if the current row is at the end or the beginning of the result set and no valid records remain to be read from the record set. MoveLast and MoveFirst set RecordsetEOF to TRUE.
Putting It All Together
Applications are very easy to write with MyC. In the following examples, consider there exists a table called "test" in the database "mysql", consisting of 5 data records as follows:
+--------+-----+
| name | num |
+--------+-----+
| item 0 | 0 |
| item 1 | 1 |
| item 2 | 2 |
| item 3 | 3 |
| item 4 | 4 |
+--------+-----+
Consider, for example, an application to query a database and write all the data to the stdout stream:
#include "database.h"
main ()
{
int i;
OpenDatabase ("mysql", NULL, NULL, NULL);
OpenRecordset ("select * from test");
while (RecordsetEOF () != EOF)
{
for (i = 0; i < FieldCount (); i++)
printf ("%s\t", GetFieldN (i));
puts ("");
MoveNext ();
}
CloseRecordset ();
CloseDatabase ();
exit (0);
}
A slightly more complicated example will illustrate adding, changing, and deleting data. This example will build a table called "test", list all the data in the table, then scan the table, changing "item 3" to "item 5" and deleting "item 4":
#include "database.h"
main ()
{
int i;
char buf[10], buf2[5];
OpenDatabase ("mysql", NULL, NULL, NULL);
OpenRecordset ("delete from test");
CloseRecordset ();
/*
* populate the table
*/
OpenRecordset ("select * from test");
for (i = 0; i < 5; i++)
{
AddNew ();
sprintf (buf, "item %d", i);
sprintf (buf2, "%d", i);
SetField ("name", buf);
SetField ("num", buf2);
Update ("test");
}
/*
* make the current result set match what's in the database
*/
Refresh ();
MoveFirst ();
while (RecordsetEOF () != EOF)
{
for (i = 0; i < FieldCount (); i++)
printf ("%s\t", GetFieldN (i));
puts ("");
MoveNext ();
}
MoveFirst ();
/*
* change "item 3" in the database to "item 5".
* delete "item 4" from the database
*/
while (RecordsetEOF () != EOF)
{
printf ("Looking at '%s'\n", GetField ("name"));
if (strcmp (GetField ("name"), "item 3") == 0)
{
puts ("Changing data");
Edit ();
SetField ("name", "item 5");
Update ("test");
}
if (strcmp (GetField ("name"), "item 4") == 0)
{
puts ("Deleting data");
Delete ("test");
}
MoveNext ();
}
CloseRecordset ();
CloseDatabase ();
exit (0);
}
Author
The author of this package is Ed Carp. I can be reached at erc@pobox.com. My home page is www.pobox.com/~erc. I am a technical manager and commercial software developer, with extensive experience in managing projects end-to-end, as well as software development in C and VB.
Credits
Thanks to Monty and the crew at tcx.se for writing such an awesome database! If you’d like to know more about MySQL, please see their brag sheet at http://www.tcx.se/what-is-mysql.html.