Ukázka použití API knihovny glib-sql-wrapper

K napsání knihovny glib-sql-wrapper mě vedla potřeba velmi jednoduchého a čistého API pro komunikaci s různými DB, u kterého by se programátor neutrápil k smrti zbytečným psaním a ošetřováním chyb.

Redukovat frustraci je pro kreativní lidi velmi hodnotné, protože to uvolňuje energii na užitečnější vě­ci.

Když se zadíváte na kód uvedený níže, asi vás napadne, že tam chybí ošetření chyb a uvolnění paměti a proto to vypadá tak přehledně a jednoduše. Naštěstí se mýlíte. Kód má ošetření runtime chyb a správu paměti naprosto v pořádku. A v tom právě spočívá krása glib-sql-wrapper.

Pokud dojde k chybě, volání jakýchkoliv dalších funkcí bude glib-sql-wrapper ignorovat. Představte si například, že dojde k chybě hned při volání gs_connect(). Veškerá následující volání budou ignorována, gs_finish() vrátí –1 a ukázkový kód vypíše hlášku o selhání připojení k DB.

API se skládá z velmi malého jádra základních funkcí: vytvoření dotazu, předání dat dotazu, získání dat z dotazu, zrušení dotazu a z těchto funkcí jsou složeny všechny ostatní (např. gs_exec). Jednoduchost jádra knihovny také znamená, že lze knihovnu snadno doplnit o podporu pro další databázové A­PI.

/*
 * Written by Ondřej Jirman <megous@megous.com>, 2008.
 */

#include <stdio.h>
#include <unistd.h>
#include "gsqlw.h"

//#define DSN "pgsql:dbname=test host=localhost user=postgres password=heslo"
#define DSN "sqlite:.test.db"

int main(int ac, char* av[])
{
  gs_conn* conn;
  gs_query* q;
  char* username;
  char* password;

  /* connect */

  conn = gs_connect(DSN);

  /* begin transaction */

  gs_begin(conn);

  /* exec some simple queries */

  gs_exec(c, "CREATE TABLE users (username TEXT PRIMARY KEY, password TEXT NOT NULL)", NULL);
  gs_exec(c, "INSERT INTO users (username, password) VALUES ($1, $2)", "ss", "bob", "qwe");

  /* prepared query example */

  q = gs_query_new(conn, "INSERT INTO users (username, password) VALUES ($1, $2)");
  gs_query_put(q, "ss", "joe", "joe's secret");
  gs_query_put(q, "ss", "jim", "jim's secret");
  gs_query_put(q, "ss", "jane", "jane's secret");
  gs_query_free(q);

  /* select example */

  q = gs_query_new(conn, "SELECT username, password FROM users WHERE username LIKE $1");
  gs_query_put(q, "s", "%j");
  while (gs_query_get(q, "ss", &username, &password) == 0)
    g_print("user %s has password '%s'", username, password);
  gs_query_free(q);

  /* commit or handle errors */

  if (gs_finish(c) < 0)
    g_printerr("ERROR: %s\n", gs_get_errmsg(c));

  /* close connection */

  gs_disconnect(conn);

  return 0;
}

No není to krása? Máme dva objekty: připojení a dotaz. Připojení může být ve dvou stavech: v transakci a mimo. Dotazu můžeme data předávat a získávat je z něj. Vidíte to také? Každá funkce má svoje místo a žádná není zbytečná.