Calling SQL from a Program

If you want a downloadable copy of the program without the explanation embedded in it, follow this link, it the programs are exactly the same. A reminder of how to compile and run all this appears at the end.

This example program shows all that is required to use SQL functions in a standard C program.
#include 
#include 
#include "/usr/local/include/mysql/mysql.h" 

void main(void)
{ MYSQL *sql;
  MYSQL_RES *r;
  MYSQL_ROW row;
The MYSQL data type is used to store a handle on a connection to the database server. A handle is made when you successfully connect, and must be provided as a parameter to every subsequent operation. It stores details of your connection, plus error messages and result codes. MYSQL_RES is a kind of cursor for walking through the results of a query row-by-row, and MYSQL_ROW is capable of storing one whole row. It is really just an array of strings, one for each field or column. Don't forget to replace the "xxxxxxxxxx" with a real password. Or even better, make the user type the password in, then it won't appear in the program source.
  int num_fields, i, j, notok;
  char *mypassword="xxxxxxxxxx";

  sql=mysql_real_connect(NULL, NULL, NULL, mypassword, 0, NULL, 0);
  if (sql==NULL)
  { printf("Failed to connect to server\n");
    exit(1); }
Before anything can be done, you must connect to the SQL server. mysql_real_connect does that. It returns a handle on your connection that must be provided as a parameter in all other calls. The first parameter should always be NULL. The second is a string, giving the internet address of the SQL server, NULL means use the computer that this program is running on (the "local host"). The third is your username (what you logged in as is the default). The fourth is your password (your SQL database password, not your unix login password). The next is the port number that the server is running on (zero means use the normal default). The next lets you specify a weird way to connect, and the final parameter lets you make small changes to the way answers are reported to you. The connect function returns 0 (which C understands as false) if it is successful.
  notok=mysql_select_db(sql,"class");
  if (notok)
  { printf("mysql_select_db failed: %s\n", mysql_error(sql));
    exit(1); }
  else 
    printf("selected database ok\n");
mysql_error returns a string describing and error that may have happened during the last operation. A similar function mysql_info returns a string describing the results of successful operations.

Once a connection is made, you must tell it which database to use. You have access to two databases, one with your username (which you can modify and mutilate as much as you like), and one called "class" which you can only read. mysql_select_db lets you change which database is being used.

Normally you should not just exit if there is an error. Close your connection (shown at the end of this example) and tidy up any messes your program has made first.

Next, we ask the server what tables are available in the current database. This works in exactly the same way as general queries, but is a little simpler to see, because it returns the result (a list of table names) as a list of rows each with just one field. The function mysql_list_tables asks the question "What tables have I got?":
  r=mysql_list_tables(sql, NULL);
  if (r==NULL)
  { printf("mysql_list_tables failed: %s\n", mysql_error(sql));
    exit(1); }
Immediately after any successful query, the function mysql_num_fields tells you how manu fields each row of the result has (i.e. how many columns in the result table). In this case, the answer must be 1, becuase we just asked for a list of table names. It does not tell you how many rows there are. However, there is a function called mysql_num_rows, used in exactly the same way, which does tell you how many rows to expect if you need to know.
  num_fields=mysql_num_fields(r);
  if (num_fields!=1)
  { printf("Something funny here!\n");
    exit(1); }
The next thing to do is to retrieve each row in turn, and print it. The function mysql_fetch_row retrieves the next row from a cursor. A row is just an array of strings (remember arrays are indexed starting from 0), so the little loop below whould print out all the table names.
  while (1)
  { row=mysql_fetch_row(r);
    if (row==NULL) break;
    printf("Table: %s\n", row[0]); }
A cursor occupies dynamic memory. If you don't realease it when you are finished with it, you will gradually strangle the system until it all falls down in a big ugly heap. mysql_free_result should always be used after every successful use of mysql_list_tables or any other function that returns a cursor.
  mysql_free_result(r);
Now we'll perform a more general query. Every main database operation is considered a query, even insert and update operations. Put the query in a string (no semicolon at the end) and give it to mysql_query. The result is again 0 for success.
  notok=mysql_query(sql, "select * from people where state='UT'");
  if (notok)
  { printf("mysql_query failed: %s\n", mysql_error(sql));
    exit(1); }
  else 
    printf("query accepted: %s\n", mysql_info(sql));
Unlike the list-tables special function, mysql_query does not return a cursor for inspecting the results until you explicitly ask for one. mysql_store_result, which is not a very suggestive name, asks for a cursor for the last query's results. It is used exactly in the same way as the previous one was. First we ask it how many fields each row will have, then we enter a loop fetching each row from the cursor, with an inner loop printing each field from the row.
  r=mysql_store_result(sql);
  if (r==NULL)
  { printf("mysql_store_result failed: %s\n", mysql_error(sql));
    exit(1); }
  printf("Utah Residents:\n");
  j=0;
  num_fields=mysql_num_fields(r);
  while (1)
  { row=mysql_fetch_row(r);
    if (row==NULL) break;
    j+=1;
    printf(" %2d: _", j);
    for (i=0; i<num_fields; i+=1)
    { printf("%s_", row[i]); }
    printf("\n"); }
  printf("total of %d results\n",j);
  mysql_free_result(r);
Don't forget the mysql_free_result again, to release the memory used by the cursor.

When you have no more queries to send, close the connection to the database with mysql_close and that's it.
  mysql_close(sql);
  printf("All done\n"); }


Compiling and running

The command to compile this kind of program must tell the compiler which special libraries to load, and where to look for them. You've got to get the command exactly right. Capitalisation is significant; don't add spaces where the don't belong. There are no digits in this command; anything that looks like a 1 (one) is really an l (little 'L'). Assuming that your program is in a file called db,c, this is the command to compile it:
    cc db.c -L/usr/local/lib/mysql -lm -lmysqlclient -o db
If it compiles successfully, just the command db will run it, and you should see something exactly like this:
selected database ok
Table: airports
Table: flights
Table: people
Table: reservations
query accepted: (null)
Utah Residents:
  1: _10055_F_Ms_Usffav_Kuk_16533 E 32nd Av_Sidemefville_UT_60034_319-674-3074_
  2: _10299_M_Mr_Spimkey_Auree_8030 Pas Pl_Lapefes_UT_60281_402-381-6923_
  3: _10415_F_Ms_Slech_Duellc_9444 E Ufu Av_Sidemefville_UT_60034_309-678-3018_
  4: _10435_F_Ms_Breyckly_Agleoch_6838 Agi Ln_Sidemefville_UT_60034_309-678-7656_
  5: _10454_M_Mr_Jehey_Kamd_3167 S Depos Rd_Picinaloria_UT_59540_907-458-3434_
  6: _10455_F_Mrs_Inad_Kamd_3167 S Depos Rd_Picinaloria_UT_59540_907-458-3434_
  7: _10658_M_Mr_Hiam_Quoezou_6554 NW Mago Blvd_Lapefes_UT_60281_402-381-4329_
  8: _10814_F_Ms_Iachu_Tresloomp_13495 NW 89th Blvd_Lapefes_UT_60281_402-383-2783_
  9: _11069_M_Mr_Dreesh_Frek_7857 NW Dega Blvd_Lapefes_UT_60281_402-381-0509_
 10: _11072_M_Mr_Shoadd_Ochliusnna_8480 E Erunu Av_Sidemefville_UT_60034_319-678-7032_
 11: _11073_F_Ms_Plieckweo_Ochliusnna_8480 E Erunu Av_Sidemefville_UT_60034_319-678-7032_
 12: _11074_M_Mr_Ub_Ochliusnna_8480 E Erunu Av_Sidemefville_UT_60034_319-678-7032_
 13: _11163_M_Mr_Skaymm_Pek_1986 Ocuf Ct_Obibapasville_UT_60528_513-898-5450_
 14: _11188_F_Miss_Queobbloi_Scang_2950 NW 133rd Blvd_Lapefes_UT_60281_412-385-8703_
 15: _11233_F_Miss_Braze_Ploydd_7364 E 142nd Av_Sidemefville_UT_60034_309-678-5212_
 16: _11508_F_Mrs_Mabo_Pod_14927 W 81st Ct_Iropol_UT_59787_218-961-4505_
 17: _11534_M_Mr_Kaupp_Fep_7421 NE Besegem Pl_Obibapasville_UT_60528_503-894-3412_
 18: _11535_F_Ms_Erai_Fep_7421 NE Besegem Pl_Obibapasville_UT_60528_907-450-1278_
 19: _11536_F_Ms_Ayme_Fep_7421 NE Besegem Pl_Obibapasville_UT_60528_907-450-1278_
 20: _11586_F_Ms_Keow_Floyfis_728 E Iti Av_Sidemefville_UT_60034_319-674-7096_
 21: _11630_F_Mrs_Jimoi_Rauxoamg_8966 Laf St_Picinaloria_UT_59540_907-458-9898_
 22: _11670_F_Mrs_Aiyillc_Ayldee_3305 Let St_Picinaloria_UT_59540_917-452-7274_
 23: _11914_M_Mr_Bwepoi_Uye_3674 E Ufi Av_Sidemefville_UT_60034_319-672-5638_
total of 23 results
All done