Initial import
This commit is contained in:
parent
efc80b939e
commit
e933ec7618
45
Makefile
Normal file
45
Makefile
Normal file
|
@ -0,0 +1,45 @@
|
|||
PACKAGE = libDatabase
|
||||
VERSION = 0.0.0
|
||||
SUBDIRS = src
|
||||
RM ?= rm -f
|
||||
LN ?= ln -f
|
||||
TAR ?= tar -czvf
|
||||
|
||||
|
||||
all: subdirs
|
||||
|
||||
subdirs:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE)) || exit; done
|
||||
|
||||
clean:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit; done
|
||||
|
||||
distclean:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) distclean) || exit; done
|
||||
|
||||
dist:
|
||||
$(RM) -r -- $(PACKAGE)-$(VERSION)
|
||||
$(LN) -s -- . $(PACKAGE)-$(VERSION)
|
||||
@$(TAR) $(PACKAGE)-$(VERSION).tar.gz -- \
|
||||
$(PACKAGE)-$(VERSION)/src/database.c \
|
||||
$(PACKAGE)-$(VERSION)/src/Makefile \
|
||||
$(PACKAGE)-$(VERSION)/src/project.conf \
|
||||
$(PACKAGE)-$(VERSION)/src/database/pgsql.c \
|
||||
$(PACKAGE)-$(VERSION)/src/database/sqlite2.c \
|
||||
$(PACKAGE)-$(VERSION)/src/database/sqlite3.c \
|
||||
$(PACKAGE)-$(VERSION)/src/database/template.c \
|
||||
$(PACKAGE)-$(VERSION)/src/database/Makefile \
|
||||
$(PACKAGE)-$(VERSION)/src/database/database.h \
|
||||
$(PACKAGE)-$(VERSION)/src/database/project.conf \
|
||||
$(PACKAGE)-$(VERSION)/Makefile \
|
||||
$(PACKAGE)-$(VERSION)/config.h \
|
||||
$(PACKAGE)-$(VERSION)/project.conf
|
||||
$(RM) -- $(PACKAGE)-$(VERSION)
|
||||
|
||||
install:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) install) || exit; done
|
||||
|
||||
uninstall:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) uninstall) || exit; done
|
||||
|
||||
.PHONY: all subdirs clean distclean dist install uninstall
|
10
config.h
Normal file
10
config.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#define PACKAGE "libDatabase"
|
||||
#define VERSION "0.0.0"
|
||||
|
||||
#ifndef PREFIX
|
||||
# define PREFIX "/usr/local"
|
||||
#endif
|
||||
|
||||
#ifndef LIBDIR
|
||||
# define LIBDIR PREFIX "/lib"
|
||||
#endif
|
6
project.conf
Normal file
6
project.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
package=libDatabase
|
||||
version=0.0.0
|
||||
config=h
|
||||
|
||||
subdirs=src
|
||||
dist=Makefile,config.h
|
44
src/Makefile
Normal file
44
src/Makefile
Normal file
|
@ -0,0 +1,44 @@
|
|||
SUBDIRS = database
|
||||
TARGETS = database.o
|
||||
PREFIX = /usr/local
|
||||
DESTDIR =
|
||||
BINDIR = $(PREFIX)/bin
|
||||
SBINDIR = $(PREFIX)/sbin
|
||||
CC ?= cc
|
||||
CPPFLAGSF?=
|
||||
CPPFLAGS?=
|
||||
CFLAGSF = -W -fPIC
|
||||
CFLAGS = -Wall -g -O2 -pedantic
|
||||
RM ?= rm -f
|
||||
LN ?= ln -f
|
||||
MKDIR ?= mkdir -p
|
||||
INSTALL ?= install
|
||||
|
||||
|
||||
all: subdirs $(TARGETS)
|
||||
|
||||
subdirs:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE)) || exit; done
|
||||
|
||||
database.o_OBJS = database.o
|
||||
database.o_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS)
|
||||
|
||||
database.o: database.c database/database.h
|
||||
$(CC) $(database.o_CFLAGS) -c database.c
|
||||
|
||||
clean:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit; done
|
||||
$(RM) -- $(database.o_OBJS)
|
||||
|
||||
distclean:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) distclean) || exit; done
|
||||
$(RM) -- $(database.o_OBJS)
|
||||
$(RM) -- $(TARGETS)
|
||||
|
||||
install: $(TARGETS)
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) install) || exit; done
|
||||
|
||||
uninstall:
|
||||
@for i in $(SUBDIRS); do (cd $$i && $(MAKE) uninstall) || exit; done
|
||||
|
||||
.PHONY: all subdirs clean distclean install uninstall
|
115
src/database.c
Normal file
115
src/database.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Database libDatabase */
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <System.h>
|
||||
#include "database/database.h"
|
||||
#include "../config.h"
|
||||
|
||||
|
||||
/* Database */
|
||||
/* private */
|
||||
/* types */
|
||||
struct _Database
|
||||
{
|
||||
Plugin * plugin;
|
||||
DatabasePluginDefinition * dplugin;
|
||||
DatabasePlugin * database;
|
||||
};
|
||||
|
||||
|
||||
/* public */
|
||||
/* functions */
|
||||
/* database_new */
|
||||
Database * database_new(char const * engine, Config * config,
|
||||
char const * section)
|
||||
{
|
||||
Database * database;
|
||||
|
||||
if((database = object_new(sizeof(*database))) == NULL)
|
||||
return NULL;
|
||||
memset(database, 0, sizeof(*database));
|
||||
if((database->plugin = plugin_new(LIBDIR, PACKAGE, "database",
|
||||
engine)) == NULL
|
||||
|| (database->dplugin = plugin_lookup(database->plugin,
|
||||
"database")) == NULL
|
||||
|| (database->database = database->dplugin->init(config,
|
||||
section)) == NULL)
|
||||
{
|
||||
database_delete(database);
|
||||
return NULL;
|
||||
}
|
||||
return database;
|
||||
}
|
||||
|
||||
|
||||
/* database_delete */
|
||||
void database_delete(Database * database)
|
||||
{
|
||||
if(database->plugin != NULL)
|
||||
plugin_delete(database->plugin);
|
||||
object_delete(database);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* database_get_last_id */
|
||||
int database_get_last_id(Database * database)
|
||||
{
|
||||
return database->dplugin->get_last_id(database->database);
|
||||
}
|
||||
|
||||
|
||||
/* database_prepare_new */
|
||||
DatabaseStatement * database_prepare_new(
|
||||
Database * database, char const * query)
|
||||
{
|
||||
return database->dplugin->prepare_new(database->database, query);
|
||||
}
|
||||
|
||||
|
||||
/* database_prepare_delete */
|
||||
void database_prepare_delete(Database * database,
|
||||
DatabaseStatement * statement)
|
||||
{
|
||||
database->dplugin->prepare_delete(database->database, statement);
|
||||
}
|
||||
|
||||
|
||||
/* database_prepare_query */
|
||||
int database_prepare_query(Database * database,
|
||||
DatabaseStatement * statement,
|
||||
DatabaseCallback callback, void * data, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, data);
|
||||
ret = database->dplugin->prepare_query(database->database, statement,
|
||||
callback, data, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* database_query */
|
||||
int database_query(Database * database, char const * query,
|
||||
DatabaseCallback callback, void * data)
|
||||
{
|
||||
return database->dplugin->query(database->database, query, callback,
|
||||
data);
|
||||
}
|
80
src/database/Makefile
Normal file
80
src/database/Makefile
Normal file
|
@ -0,0 +1,80 @@
|
|||
TARGETS = pgsql.so sqlite2.so sqlite3.so template.so
|
||||
PREFIX = /usr/local
|
||||
DESTDIR =
|
||||
LIBDIR = $(PREFIX)/lib
|
||||
CC ?= cc
|
||||
CPPFLAGSF?=
|
||||
CPPFLAGS?=
|
||||
CFLAGSF = -W -fPIC
|
||||
CFLAGS = -Wall -g -O2 -pedantic
|
||||
AR ?= ar
|
||||
RANLIB ?= ranlib
|
||||
CCSHARED?= $(CC) -shared
|
||||
RM ?= rm -f
|
||||
LN ?= ln -f
|
||||
MKDIR ?= mkdir -p
|
||||
INSTALL ?= install
|
||||
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
pgsql_OBJS = pgsql.o
|
||||
pgsql_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) -I `pg_config --includedir` $(CFLAGSF) $(CFLAGS)
|
||||
pgsql_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) -L `pg_config --libdir` -Wl,-rpath,`pg_config --libdir` `pg_config --libs` -lpq
|
||||
|
||||
pgsql.so: $(pgsql_OBJS)
|
||||
$(CCSHARED) -o pgsql.so $(pgsql_OBJS) $(pgsql_LDFLAGS)
|
||||
|
||||
sqlite2_OBJS = sqlite2.o
|
||||
sqlite2_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) `pkg-config --cflags sqlite`
|
||||
sqlite2_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) `pkg-config --libs sqlite`
|
||||
|
||||
sqlite2.so: $(sqlite2_OBJS)
|
||||
$(CCSHARED) -o sqlite2.so $(sqlite2_OBJS) $(sqlite2_LDFLAGS)
|
||||
|
||||
sqlite3_OBJS = sqlite3.o
|
||||
sqlite3_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) `pkg-config --cflags sqlite3`
|
||||
sqlite3_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) `pkg-config --libs sqlite3`
|
||||
|
||||
sqlite3.so: $(sqlite3_OBJS)
|
||||
$(CCSHARED) -o sqlite3.so $(sqlite3_OBJS) $(sqlite3_LDFLAGS)
|
||||
|
||||
template_OBJS = template.o
|
||||
template_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS)
|
||||
template_LDFLAGS = $(LDFLAGSF) $(LDFLAGS)
|
||||
|
||||
template.so: $(template_OBJS)
|
||||
$(CCSHARED) -o template.so $(template_OBJS) $(template_LDFLAGS)
|
||||
|
||||
pgsql.o: pgsql.c database.h
|
||||
$(CC) $(pgsql_CFLAGS) -c pgsql.c
|
||||
|
||||
sqlite2.o: sqlite2.c database.h
|
||||
$(CC) $(sqlite2_CFLAGS) -c sqlite2.c
|
||||
|
||||
sqlite3.o: sqlite3.c database.h
|
||||
$(CC) $(sqlite3_CFLAGS) -c sqlite3.c
|
||||
|
||||
template.o: template.c database.h
|
||||
$(CC) $(template_CFLAGS) -c template.c
|
||||
|
||||
clean:
|
||||
$(RM) -- $(pgsql_OBJS) $(sqlite2_OBJS) $(sqlite3_OBJS) $(template_OBJS)
|
||||
|
||||
distclean: clean
|
||||
$(RM) -- $(TARGETS)
|
||||
|
||||
install: $(TARGETS)
|
||||
$(MKDIR) $(DESTDIR)$(LIBDIR)/Database/database
|
||||
$(INSTALL) -m 0644 -- pgsql.so $(DESTDIR)$(LIBDIR)/Database/database/pgsql.so
|
||||
$(MKDIR) $(DESTDIR)$(LIBDIR)/Database/database
|
||||
$(INSTALL) -m 0644 -- sqlite2.so $(DESTDIR)$(LIBDIR)/Database/database/sqlite2.so
|
||||
$(MKDIR) $(DESTDIR)$(LIBDIR)/Database/database
|
||||
$(INSTALL) -m 0644 -- sqlite3.so $(DESTDIR)$(LIBDIR)/Database/database/sqlite3.so
|
||||
|
||||
uninstall:
|
||||
$(RM) -- $(DESTDIR)$(LIBDIR)/Database/database/pgsql.so
|
||||
$(RM) -- $(DESTDIR)$(LIBDIR)/Database/database/sqlite2.so
|
||||
$(RM) -- $(DESTDIR)$(LIBDIR)/Database/database/sqlite3.so
|
||||
|
||||
.PHONY: all clean distclean install uninstall
|
88
src/database/database.h
Normal file
88
src/database/database.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Database libDatabase */
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#ifndef LIBDATABASE_DATABASE_DATABASE_H
|
||||
# define LIBDATABASE_DATABASE_DATABASE_H
|
||||
|
||||
# include <stdarg.h>
|
||||
# include <System.h>
|
||||
|
||||
|
||||
/* Database */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef enum _DatabaseType
|
||||
{
|
||||
DT_INTEGER = 0,
|
||||
DT_TIMESTAMP,
|
||||
DT_VARCHAR
|
||||
} DatabaseType;
|
||||
|
||||
typedef struct _Database Database;
|
||||
typedef struct _DatabaseStatement DatabaseStatement;
|
||||
|
||||
typedef int (*DatabaseCallback)(void * data, int argc, char ** argv,
|
||||
char ** columns);
|
||||
|
||||
typedef struct _DatabasePlugin DatabasePlugin;
|
||||
|
||||
typedef struct _DatabasePluginDefinition
|
||||
{
|
||||
char const * name;
|
||||
char const * description;
|
||||
/* essential */
|
||||
DatabasePlugin * (*init)(Config * config, char const * section);
|
||||
void (*destroy)(DatabasePlugin * plugin);
|
||||
/* accessors */
|
||||
int (*get_last_id)(DatabasePlugin * plugin);
|
||||
/* useful */
|
||||
int (*query)(DatabasePlugin * plugin, char const * query,
|
||||
DatabaseCallback callback, void * data);
|
||||
/* prepared statements */
|
||||
DatabaseStatement * (*prepare_new)(DatabasePlugin * plugin,
|
||||
char const * query);
|
||||
void (*prepare_delete)(DatabasePlugin * plugin,
|
||||
DatabaseStatement * statement);
|
||||
int (*prepare_query)(DatabasePlugin * plugin,
|
||||
DatabaseStatement * statement,
|
||||
DatabaseCallback callback, void * data,
|
||||
va_list args);
|
||||
} DatabasePluginDefinition;
|
||||
|
||||
|
||||
/* public */
|
||||
/* functions */
|
||||
Database * database_new(char const * engine, Config * config,
|
||||
char const * section);
|
||||
void database_delete(Database * database);
|
||||
|
||||
/* accessors */
|
||||
int database_get_last_id(Database * database);
|
||||
|
||||
/* useful */
|
||||
DatabaseStatement * database_prepare_new(
|
||||
Database * database, char const * query);
|
||||
void database_prepare_delete(Database * database,
|
||||
DatabaseStatement * statement);
|
||||
int database_prepare_query(Database * database,
|
||||
DatabaseStatement * statement,
|
||||
DatabaseCallback callback, void * data, ...);
|
||||
|
||||
int database_query(Database * database, char const * query,
|
||||
DatabaseCallback callback, void * data);
|
||||
|
||||
#endif /* !LIBDATABASE_DATABASE_DATABASE_H */
|
376
src/database/pgsql.c
Normal file
376
src/database/pgsql.c
Normal file
|
@ -0,0 +1,376 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Database libDatabase */
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <System.h>
|
||||
#include "database.h"
|
||||
|
||||
|
||||
/* PgSQL */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _DatabasePlugin
|
||||
{
|
||||
PGconn * handle;
|
||||
Oid last;
|
||||
} PgSQL;
|
||||
|
||||
typedef struct _DatabaseStatement
|
||||
{
|
||||
PGresult * res;
|
||||
char * query;
|
||||
} PgSQLStatement;
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* useful */
|
||||
static int _pgsql_process(PgSQL * pgsql, PGresult * res,
|
||||
DatabaseCallback callback, void * data);
|
||||
|
||||
|
||||
/* protected */
|
||||
/* prototypes */
|
||||
/* plug-in */
|
||||
static PgSQL * _pgsql_init(Config * config, char const * section);
|
||||
static void _pgsql_destroy(PgSQL * pgsql);
|
||||
|
||||
static int _pgsql_get_last_id(PgSQL * pgsql);
|
||||
|
||||
static int _pgsql_query(PgSQL * pgsql, char const * query,
|
||||
DatabaseCallback callback, void * data);
|
||||
|
||||
static PgSQLStatement * _pgsql_prepare_new(PgSQL * pgsql, char const * query);
|
||||
static void _pgsql_prepare_delete(PgSQL * pgsql, PgSQLStatement * statement);
|
||||
static int _pgsql_prepare_query(PgSQL * pgsql, PgSQLStatement * statement,
|
||||
DatabaseCallback callback, void * data, va_list args);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
DatabasePluginDefinition database =
|
||||
{
|
||||
"PostgreSQL",
|
||||
NULL,
|
||||
_pgsql_init,
|
||||
_pgsql_destroy,
|
||||
_pgsql_get_last_id,
|
||||
_pgsql_query,
|
||||
_pgsql_prepare_new,
|
||||
_pgsql_prepare_delete,
|
||||
_pgsql_prepare_query
|
||||
};
|
||||
|
||||
|
||||
/* protected */
|
||||
/* functions */
|
||||
/* plug-in */
|
||||
/* pgsql_init */
|
||||
static void _init_append(char * buf, size_t size, char const * variable,
|
||||
char const * value);
|
||||
|
||||
static PgSQL * _pgsql_init(Config * config, char const * section)
|
||||
{
|
||||
PgSQL * pgsql;
|
||||
char buf[256] = "";
|
||||
|
||||
if((pgsql = object_new(sizeof(*pgsql))) == NULL)
|
||||
return NULL;
|
||||
pgsql->last = InvalidOid;
|
||||
/* build the connection string */
|
||||
_init_append(buf, sizeof(buf), "user", config_get(config, section,
|
||||
"username"));
|
||||
_init_append(buf, sizeof(buf), "password", config_get(config, section,
|
||||
"password"));
|
||||
_init_append(buf, sizeof(buf), "dbname", config_get(config, section,
|
||||
"database"));
|
||||
_init_append(buf, sizeof(buf), "host", config_get(config, section,
|
||||
"hostname"));
|
||||
_init_append(buf, sizeof(buf), "port", config_get(config, section,
|
||||
"port"));
|
||||
/* connect to the database */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, buf);
|
||||
#endif
|
||||
if((pgsql->handle = PQconnectdb(buf)) == NULL
|
||||
|| PQstatus(pgsql->handle) != CONNECTION_OK)
|
||||
{
|
||||
error_set_code(1, "%s", (pgsql->handle != NULL)
|
||||
? PQerrorMessage(pgsql->handle)
|
||||
: "Unable to obtain the connection string");
|
||||
_pgsql_destroy(pgsql);
|
||||
return NULL;
|
||||
}
|
||||
return pgsql;
|
||||
}
|
||||
|
||||
static void _init_append(char * buf, size_t size, char const * variable,
|
||||
char const * value)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if(value == NULL)
|
||||
return;
|
||||
len = strlen(buf);
|
||||
snprintf(&buf[len], size - len, "%s%s=%s", (len > 0) ? " " : "",
|
||||
variable, value);
|
||||
}
|
||||
|
||||
|
||||
/* pgsql_destroy */
|
||||
static void _pgsql_destroy(PgSQL * pgsql)
|
||||
{
|
||||
if(pgsql->handle != NULL)
|
||||
PQfinish(pgsql->handle);
|
||||
object_delete(pgsql);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* pgsql_get_last_id */
|
||||
static int _pgsql_get_last_id(PgSQL * pgsql)
|
||||
{
|
||||
/* FIXME use currval() of the relevant instead */
|
||||
if(pgsql->last == InvalidOid)
|
||||
return -1;
|
||||
return pgsql->last;
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* pgsql_prepare_new */
|
||||
static void _prepare_new_adapt(char * q);
|
||||
|
||||
static PgSQLStatement * _pgsql_prepare_new(PgSQL * pgsql,
|
||||
char const * query)
|
||||
{
|
||||
PgSQLStatement * statement;
|
||||
char * q;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, query);
|
||||
#endif
|
||||
if((statement = object_new(sizeof(*statement))) == NULL)
|
||||
return NULL;
|
||||
statement->query = strdup(query);
|
||||
statement->res = NULL;
|
||||
q = strdup(query);
|
||||
if(statement->query == NULL || q == NULL)
|
||||
{
|
||||
free(q);
|
||||
_pgsql_prepare_delete(pgsql, statement);
|
||||
return NULL;
|
||||
}
|
||||
/* adapt the statement for PostgreSQL */
|
||||
_prepare_new_adapt(q);
|
||||
if((statement->res = PQprepare(pgsql->handle, query, q, 0, NULL))
|
||||
== NULL
|
||||
|| PQresultStatus(statement->res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
error_set_code(1, "%s", PQerrorMessage(pgsql->handle));
|
||||
_pgsql_prepare_delete(pgsql, statement);
|
||||
return NULL;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
static void _prepare_new_adapt(char * query)
|
||||
{
|
||||
int i;
|
||||
char * p;
|
||||
int j;
|
||||
size_t len;
|
||||
int c;
|
||||
|
||||
/* FIXME this only works for up to 9 arguments */
|
||||
for(i = 0; (p = strchr(query, ':')) != NULL; i++)
|
||||
{
|
||||
*(p++) = '$';
|
||||
*(p++) = '1' + i;
|
||||
for(j = 0; isalpha((c = p[j])) || p[j] == '_'; j++);
|
||||
len = strlen(p) + 1;
|
||||
memmove(p, &p[j], len - j);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() => \"%s\"\n", __func__, query);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* pgsql_prepare_delete */
|
||||
static void _pgsql_prepare_delete(PgSQL * pgsql,
|
||||
PgSQLStatement * statement)
|
||||
{
|
||||
PQclear(statement->res);
|
||||
free(statement->query);
|
||||
object_delete(statement);
|
||||
}
|
||||
|
||||
|
||||
/* pgsql_prepare_query */
|
||||
static int _pgsql_prepare_query(PgSQL * pgsql, PgSQLStatement * statement,
|
||||
DatabaseCallback callback, void * data, va_list args)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t cnt;
|
||||
int type;
|
||||
char const * name;
|
||||
long l;
|
||||
char buf[32];
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
char const * s;
|
||||
char ** v = NULL;
|
||||
char ** p;
|
||||
size_t i;
|
||||
PGresult * res;
|
||||
|
||||
/* FIXME this assumes the same order as in the prepared statement */
|
||||
for(cnt = 0; ret == 0 && (type = va_arg(args, int)) != -1; cnt++)
|
||||
{
|
||||
name = va_arg(args, char const *);
|
||||
if((p = realloc(v, sizeof(*v) * (cnt + 1))) == NULL)
|
||||
{
|
||||
ret = -error_set_code(1, "%s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
v = p;
|
||||
v[cnt] = NULL;
|
||||
switch(type)
|
||||
{
|
||||
case DT_INTEGER:
|
||||
l = va_arg(args, long);
|
||||
snprintf(buf, sizeof(buf), "%ld", l);
|
||||
v[cnt] = strdup(buf);
|
||||
break;
|
||||
case DT_TIMESTAMP:
|
||||
t = va_arg(args, time_t);
|
||||
if(gmtime_r(&t, &tm) == NULL)
|
||||
break;
|
||||
if(strftime(buf, sizeof(buf), "%Y-%m-%d"
|
||||
" %H:%M:%S", &tm) == 0)
|
||||
break;
|
||||
v[cnt] = strdup(buf);
|
||||
break;
|
||||
case DT_VARCHAR:
|
||||
s = va_arg(args, char const *);
|
||||
v[cnt] = strdup(s);
|
||||
break;
|
||||
default:
|
||||
errno = ENOSYS;
|
||||
break;
|
||||
}
|
||||
if(v[cnt] == NULL)
|
||||
ret = -error_set_code(1, "%s", strerror(errno));
|
||||
}
|
||||
if(ret != 0)
|
||||
{
|
||||
for(i = 0; i < cnt; i++)
|
||||
free(v[i]);
|
||||
free(v);
|
||||
return ret;
|
||||
}
|
||||
pgsql->last = InvalidOid;
|
||||
res = PQexecPrepared(pgsql->handle, statement->query, cnt, v, NULL,
|
||||
NULL, 0);
|
||||
for(i = 0; i < cnt; i++)
|
||||
free(v[i]);
|
||||
free(v);
|
||||
ret = _pgsql_process(pgsql, res, callback, data);
|
||||
PQclear(res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* pgsql_query */
|
||||
static int _pgsql_query(PgSQL * pgsql, char const * query,
|
||||
DatabaseCallback callback, void * data)
|
||||
{
|
||||
int ret;
|
||||
PGresult * res;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, query);
|
||||
#endif
|
||||
pgsql->last = InvalidOid;
|
||||
if((res = PQexec(pgsql->handle, query)) == NULL)
|
||||
{
|
||||
error_set_code(1, "%s", PQerrorMessage(pgsql->handle));
|
||||
PQclear(res);
|
||||
return -1;
|
||||
}
|
||||
ret = _pgsql_process(pgsql, res, callback, data);
|
||||
PQclear(res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* useful */
|
||||
/* pgsql_process */
|
||||
static int _pgsql_process(PgSQL * pgsql, PGresult * res,
|
||||
DatabaseCallback callback, void * data)
|
||||
{
|
||||
char ** columns;
|
||||
char ** fields;
|
||||
size_t cnt;
|
||||
size_t i;
|
||||
int n;
|
||||
int j;
|
||||
|
||||
if(PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
pgsql->last = PQoidValue(res);
|
||||
return 0;
|
||||
}
|
||||
else if(PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
error_set_code(1, "%s", PQerrorMessage(pgsql->handle));
|
||||
return -1;
|
||||
}
|
||||
cnt = PQnfields(res);
|
||||
columns = malloc(sizeof(*columns) * cnt); /* XXX may fail */
|
||||
fields = malloc(sizeof(*fields) * cnt); /* XXX may fail */
|
||||
/* obtain the names of the columns */
|
||||
for(i = 0; i < cnt; i++)
|
||||
{
|
||||
columns[i] = PQfname(res, i);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() %zu/%zu \"%s\"\n", __func__, i + 1,
|
||||
cnt, columns[i]);
|
||||
#endif
|
||||
}
|
||||
n = PQntuples(res);
|
||||
for(j = 0; j < n; j++)
|
||||
{
|
||||
/* obtain the values of the fields */
|
||||
for(i = 0; i < cnt; i++)
|
||||
fields[i] = PQgetvalue(res, j, i);
|
||||
/* call the callback */
|
||||
callback(data, cnt, fields, columns);
|
||||
}
|
||||
free(fields);
|
||||
free(columns);
|
||||
return 0;
|
||||
}
|
41
src/database/project.conf
Normal file
41
src/database/project.conf
Normal file
|
@ -0,0 +1,41 @@
|
|||
targets=pgsql,sqlite2,sqlite3,template
|
||||
cflags_force=-W -fPIC
|
||||
cflags=-Wall -g -O2 -pedantic
|
||||
dist=Makefile,database.h
|
||||
|
||||
[pgsql]
|
||||
type=plugin
|
||||
cppflags=-I `pg_config --includedir`
|
||||
ldflags=-L `pg_config --libdir` -Wl,-rpath,`pg_config --libdir` `pg_config --libs` -lpq
|
||||
sources=pgsql.c
|
||||
install=$(LIBDIR)/Database/database
|
||||
|
||||
[pgsql.c]
|
||||
depends=database.h
|
||||
|
||||
[sqlite2]
|
||||
type=plugin
|
||||
cflags=`pkg-config --cflags sqlite`
|
||||
ldflags=`pkg-config --libs sqlite`
|
||||
sources=sqlite2.c
|
||||
install=$(LIBDIR)/Database/database
|
||||
|
||||
[sqlite2.c]
|
||||
depends=database.h
|
||||
|
||||
[sqlite3]
|
||||
type=plugin
|
||||
cflags=`pkg-config --cflags sqlite3`
|
||||
ldflags=`pkg-config --libs sqlite3`
|
||||
sources=sqlite3.c
|
||||
install=$(LIBDIR)/Database/database
|
||||
|
||||
[sqlite3.c]
|
||||
depends=database.h
|
||||
|
||||
[template]
|
||||
type=plugin
|
||||
sources=template.c
|
||||
|
||||
[template.c]
|
||||
depends=database.h
|
205
src/database/sqlite2.c
Normal file
205
src/database/sqlite2.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Database libDatabase */
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <sqlite.h>
|
||||
#include <System.h>
|
||||
#include "database.h"
|
||||
|
||||
|
||||
/* SQLite2 */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _DatabasePlugin
|
||||
{
|
||||
sqlite * handle;
|
||||
} SQLite2;
|
||||
|
||||
typedef struct _DatabaseStatement
|
||||
{
|
||||
char * query;
|
||||
} SQLite2Statement;
|
||||
|
||||
|
||||
/* protected */
|
||||
/* prototypes */
|
||||
/* plug-in */
|
||||
static SQLite2 * _sqlite2_init(Config * config, char const * section);
|
||||
static void _sqlite2_destroy(SQLite2 * pgsql);
|
||||
|
||||
static int _sqlite2_get_last_id(SQLite2 * pgsql);
|
||||
|
||||
static int _sqlite2_query(SQLite2 * pgsql, char const * query,
|
||||
DatabaseCallback callback, void * data);
|
||||
|
||||
static SQLite2Statement * _sqlite2_prepare_new(SQLite2 * pgsql,
|
||||
char const * query);
|
||||
static void _sqlite2_prepare_delete(SQLite2 * pgsql, SQLite2Statement * statement);
|
||||
static int _sqlite2_prepare_query(SQLite2 * sqlite,
|
||||
SQLite2Statement * statement, DatabaseCallback callback,
|
||||
void * data, va_list args);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
DatabasePluginDefinition database =
|
||||
{
|
||||
"SQLite2",
|
||||
NULL,
|
||||
_sqlite2_init,
|
||||
_sqlite2_destroy,
|
||||
_sqlite2_get_last_id,
|
||||
_sqlite2_query,
|
||||
_sqlite2_prepare_new,
|
||||
_sqlite2_prepare_delete,
|
||||
_sqlite2_prepare_query
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* _sqlite2_init */
|
||||
static SQLite2 * _sqlite2_init(Config * config, char const * section)
|
||||
{
|
||||
SQLite2 * sqlite;
|
||||
char const * name;
|
||||
char * error = NULL;
|
||||
|
||||
if((sqlite = object_new(sizeof(*sqlite))) == NULL)
|
||||
return NULL;
|
||||
sqlite->handle = NULL;
|
||||
if((name = config_get(config, section, "filename")) != NULL
|
||||
&& (sqlite->handle = sqlite_open(name, 0, &error))
|
||||
== NULL)
|
||||
{
|
||||
error_set_code(1, "%s: %s", name, (error != NULL) ? error
|
||||
: "Unknown error");
|
||||
free(error);
|
||||
}
|
||||
/* check for errors */
|
||||
if(sqlite->handle == NULL)
|
||||
{
|
||||
_sqlite2_destroy(sqlite);
|
||||
return NULL;
|
||||
}
|
||||
return sqlite;
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite2_destroy */
|
||||
static void _sqlite2_destroy(SQLite2 * sqlite)
|
||||
{
|
||||
if(sqlite->handle != NULL)
|
||||
sqlite_close(sqlite->handle);
|
||||
object_delete(sqlite);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* _sqlite2_get_last_id */
|
||||
static int _sqlite2_get_last_id(SQLite2 * sqlite)
|
||||
{
|
||||
/* FIXME really implement */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* _sqlite2_prepare_new */
|
||||
static SQLite2Statement * _sqlite2_prepare_new(SQLite2 * sqlite,
|
||||
char const * query)
|
||||
{
|
||||
SQLite2Statement * statement;
|
||||
|
||||
if((statement = object_new(sizeof(*statement))) == NULL)
|
||||
return NULL;
|
||||
/* XXX this version of SQLite2 doesn't support prepared statements */
|
||||
statement->query = string_new(query);
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite2_prepare_delete */
|
||||
static void _sqlite2_prepare_delete(SQLite2 * sqlite, SQLite2Statement * statement)
|
||||
{
|
||||
string_delete(statement->query);
|
||||
object_delete(statement);
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite2_prepare_query */
|
||||
static int _sqlite2_prepare_query(SQLite2 * sqlite,
|
||||
SQLite2Statement * statement, DatabaseCallback callback,
|
||||
void * data, va_list args)
|
||||
{
|
||||
int type = -1;
|
||||
char const * name;
|
||||
char const * s;
|
||||
char * query = NULL;
|
||||
sqlite_vm * vm;
|
||||
const char * tail = NULL;
|
||||
char * error = NULL;
|
||||
|
||||
/* FIXME really implement */
|
||||
while((type = va_arg(args, int)) != -1)
|
||||
{
|
||||
name = va_arg(args, char const *);
|
||||
switch(type)
|
||||
{
|
||||
case DT_VARCHAR:
|
||||
s = va_arg(args, char const *);
|
||||
/* FIXME implement */
|
||||
break;
|
||||
}
|
||||
}
|
||||
query = statement->query; /* XXX remove once really implemented */
|
||||
if(sqlite_compile(sqlite->handle, query, &tail, &vm, &error)
|
||||
!= SQLITE_OK)
|
||||
{
|
||||
error_set_code(1, "%s", error);
|
||||
free(error);
|
||||
return -1;
|
||||
}
|
||||
/* ignore errors */
|
||||
if(sqlite_finalize(vm, &error) != SQLITE_OK)
|
||||
free(error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite2_query */
|
||||
static int _sqlite2_query(SQLite2 * sqlite, char const * query,
|
||||
DatabaseCallback callback, void * data)
|
||||
{
|
||||
int ret;
|
||||
char * error = NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, query);
|
||||
#endif
|
||||
ret = (sqlite_exec(sqlite->handle, query, callback, data, &error)
|
||||
== SQLITE_OK) ? 0 : -error_set_code(1, "%s",
|
||||
(error != NULL) ? error : "Unknown error");
|
||||
if(error != NULL)
|
||||
free(error);
|
||||
return ret;
|
||||
}
|
336
src/database/sqlite3.c
Normal file
336
src/database/sqlite3.c
Normal file
|
@ -0,0 +1,336 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Database libDatabase */
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sqlite3.h>
|
||||
#include <System.h>
|
||||
#include "database.h"
|
||||
|
||||
|
||||
/* SQLite3 */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _DatabasePlugin
|
||||
{
|
||||
sqlite3 * handle;
|
||||
} SQLite3;
|
||||
|
||||
typedef struct _DatabaseStatement
|
||||
{
|
||||
sqlite3_stmt * stmt;
|
||||
} SQLite3Statement;
|
||||
|
||||
|
||||
/* protected */
|
||||
/* prototypes */
|
||||
/* plug-in */
|
||||
static SQLite3 * _sqlite3_init(Config * config, char const * section);
|
||||
static void _sqlite3_destroy(SQLite3 * sqlite3);
|
||||
|
||||
static int _sqlite3_get_last_id(SQLite3 * sqlite3);
|
||||
|
||||
static int _sqlite3_query(SQLite3 * sqlite3, char const * query,
|
||||
DatabaseCallback callback, void * data);
|
||||
|
||||
static SQLite3Statement * _sqlite3_prepare_new(SQLite3 * sqlite3,
|
||||
char const * query);
|
||||
static void _sqlite3_prepare_delete(SQLite3 * sqlite3,
|
||||
SQLite3Statement * statement);
|
||||
static int _sqlite3_prepare_query(SQLite3 * sqlite3,
|
||||
SQLite3Statement * statement, DatabaseCallback callback,
|
||||
void * data, va_list args);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
DatabasePluginDefinition database =
|
||||
{
|
||||
"SQLite3",
|
||||
NULL,
|
||||
_sqlite3_init,
|
||||
_sqlite3_destroy,
|
||||
_sqlite3_get_last_id,
|
||||
_sqlite3_query,
|
||||
_sqlite3_prepare_new,
|
||||
_sqlite3_prepare_delete,
|
||||
_sqlite3_prepare_query
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* _sqlite3_init */
|
||||
static SQLite3 * _sqlite3_init(Config * config, char const * section)
|
||||
{
|
||||
SQLite3 * sqlite3;
|
||||
char const * name;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, section);
|
||||
#endif
|
||||
if((sqlite3 = object_new(sizeof(*sqlite3))) == NULL)
|
||||
return NULL;
|
||||
sqlite3->handle = NULL;
|
||||
if((name = config_get(config, section, "filename")) != NULL
|
||||
&& sqlite3_open(name, &sqlite3->handle) != SQLITE_OK)
|
||||
error_set_code(1, "%s: %s", name, (sqlite3->handle != NULL)
|
||||
? sqlite3_errmsg(sqlite3->handle)
|
||||
: "Unknown error");
|
||||
if(sqlite3->handle == NULL)
|
||||
{
|
||||
_sqlite3_destroy(sqlite3);
|
||||
return NULL;
|
||||
}
|
||||
return sqlite3;
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite3_destroy */
|
||||
static void _sqlite3_destroy(SQLite3 * sqlite3)
|
||||
{
|
||||
if(sqlite3->handle != NULL)
|
||||
sqlite3_close(sqlite3->handle);
|
||||
object_delete(sqlite3);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* _sqlite3_get_last_id */
|
||||
static int _sqlite3_get_last_id(SQLite3 * sqlite3)
|
||||
{
|
||||
/* FIXME really implement */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* _sqlite3_prepare_new */
|
||||
static SQLite3Statement * _sqlite3_prepare_new(SQLite3 * sqlite3,
|
||||
char const * query)
|
||||
{
|
||||
SQLite3Statement * statement;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, query);
|
||||
#endif
|
||||
if((statement = object_new(sizeof(*statement))) == NULL)
|
||||
return NULL;
|
||||
if(sqlite3_prepare_v2(sqlite3->handle, query, -1, &statement->stmt,
|
||||
NULL) != SQLITE_OK)
|
||||
{
|
||||
error_set_code(1, "%s", sqlite3_errmsg(sqlite3->handle));
|
||||
object_delete(statement);
|
||||
return NULL;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite3_prepare_delete */
|
||||
static void _sqlite3_prepare_delete(SQLite3 * sqlite3,
|
||||
SQLite3Statement * statement)
|
||||
{
|
||||
/* XXX ignore errors */
|
||||
sqlite3_finalize(statement->stmt);
|
||||
object_delete(statement);
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite3_prepare_query */
|
||||
static int _sqlite3_prepare_query(SQLite3 * sqlite3,
|
||||
SQLite3Statement * statement, DatabaseCallback callback,
|
||||
void * data, va_list args)
|
||||
{
|
||||
int ret = 0;
|
||||
int type;
|
||||
char const * name;
|
||||
int i;
|
||||
int cnt;
|
||||
int argc;
|
||||
char ** argv;
|
||||
char ** columns;
|
||||
char ** p;
|
||||
long l;
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
char buf[32];
|
||||
char const * s;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
||||
#endif
|
||||
sqlite3_reset(statement->stmt);
|
||||
while(ret == 0 && (type = va_arg(args, int)) != -1)
|
||||
{
|
||||
name = va_arg(args, char const *);
|
||||
if((i = sqlite3_bind_parameter_index(statement->stmt, name))
|
||||
== 0)
|
||||
{
|
||||
ret = -error_set_code(1, "%s", "Unknown parameter");
|
||||
break;
|
||||
}
|
||||
switch(type)
|
||||
{
|
||||
case DT_INTEGER:
|
||||
l = va_arg(args, long);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() %s=\"%ld\"\n",
|
||||
__func__, name, l);
|
||||
#endif
|
||||
if(sqlite3_bind_int(statement->stmt, i, l)
|
||||
== SQLITE_OK)
|
||||
break;
|
||||
ret = -error_set_code(1, "%s", sqlite3_errmsg(
|
||||
sqlite3->handle));
|
||||
break;
|
||||
case DT_TIMESTAMP:
|
||||
t = va_arg(args, time_t);
|
||||
if(gmtime_r(&t, &tm) == NULL)
|
||||
break;
|
||||
if(strftime(buf, sizeof(buf), "%Y-%m-%d"
|
||||
" %H:%M:%S", &tm) == 0)
|
||||
{
|
||||
ret = -error_set_code(1, "%s", strerror(
|
||||
errno));
|
||||
break;
|
||||
}
|
||||
if(sqlite3_bind_text(statement->stmt, i, buf,
|
||||
-1, SQLITE_TRANSIENT)
|
||||
== SQLITE_OK)
|
||||
break;
|
||||
ret = -error_set_code(1, "%s", sqlite3_errmsg(
|
||||
sqlite3->handle));
|
||||
break;
|
||||
case DT_VARCHAR:
|
||||
s = va_arg(args, char const *);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() %s=\"%s\" (%d)\n",
|
||||
__func__, name, s, i);
|
||||
#endif
|
||||
if(sqlite3_bind_text(statement->stmt, i, s, -1,
|
||||
SQLITE_STATIC)
|
||||
== SQLITE_OK)
|
||||
break;
|
||||
ret = -error_set_code(1, "%s", sqlite3_errmsg(
|
||||
sqlite3->handle));
|
||||
break;
|
||||
default:
|
||||
ret = -error_set_code(1, "%s (%d)",
|
||||
"Unsupported type", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
/* return directly if there are no results */
|
||||
if((argc = sqlite3_column_count(statement->stmt)) == 0)
|
||||
{
|
||||
/* FIXME should really execute until done */
|
||||
if(sqlite3_step(statement->stmt) != SQLITE_DONE)
|
||||
ret = -error_set_code(1, "%s", sqlite3_errmsg(
|
||||
sqlite3->handle));
|
||||
return ret;
|
||||
}
|
||||
/* pre-allocate the results */
|
||||
argv = malloc(sizeof(*argv) * argc);
|
||||
columns = malloc(sizeof(*columns) * argc);
|
||||
if(argv == NULL || columns == NULL)
|
||||
{
|
||||
free(argv);
|
||||
free(columns);
|
||||
return -error_set_code(1, "%s", strerror(errno));
|
||||
}
|
||||
/* obtain the column names */
|
||||
for(i = 0; i < argc; i++)
|
||||
/* XXX cast or duplicate name */
|
||||
columns[i] = sqlite3_column_origin_name(statement->stmt, i);
|
||||
for(cnt = 0; (i = sqlite3_step(statement->stmt)) == SQLITE_ROW; cnt++)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() cnt=%d\n", __func__, cnt);
|
||||
#endif
|
||||
/* reset the result line */
|
||||
memset(argv, 0, sizeof(*argv) * argc);
|
||||
for(i = 0; (type = sqlite3_column_type(statement->stmt, i))
|
||||
!= SQLITE_NULL; i++)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SQLITE_INTEGER:
|
||||
l = sqlite3_column_int(statement->stmt,
|
||||
i);
|
||||
snprintf(buf, sizeof(buf), "%ld", l);
|
||||
s = buf;
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
s = (char const *)sqlite3_column_text(
|
||||
statement->stmt, i);
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
case SQLITE_FLOAT:
|
||||
default:
|
||||
/* FIXME really implement */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() i=%d\n",
|
||||
__func__, i);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
p = &argv[i];
|
||||
/* XXX check errors */
|
||||
*p = strdup(s);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() argv[%d]=\"%s\"\n",
|
||||
__func__, i, argv[i]);
|
||||
#endif
|
||||
}
|
||||
if(ret == 0 && callback != NULL)
|
||||
/* FIXME really implement the callback */
|
||||
callback(data, argc, argv, columns);
|
||||
for(i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
}
|
||||
free(argv);
|
||||
free(columns);
|
||||
if(ret == 0 && i != SQLITE_DONE)
|
||||
ret = -error_set_code(1, "%s", sqlite3_errmsg(sqlite3->handle));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* _sqlite3_query */
|
||||
int _sqlite3_query(SQLite3 * sqlite3, char const * query,
|
||||
DatabaseCallback callback, void * data)
|
||||
{
|
||||
int ret;
|
||||
char * error = NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, query);
|
||||
#endif
|
||||
ret = (sqlite3_exec(sqlite3->handle, query, callback, data, &error)
|
||||
== SQLITE_OK) ? 0 : -error_set_code(1, "%s",
|
||||
(error != NULL) ? error : "Unknown error");
|
||||
if(error != NULL)
|
||||
sqlite3_free(error);
|
||||
return ret;
|
||||
}
|
166
src/database/template.c
Normal file
166
src/database/template.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Database libDatabase */
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <System.h>
|
||||
#include "database.h"
|
||||
|
||||
|
||||
/* Template */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _DatabasePlugin
|
||||
{
|
||||
void * handle;
|
||||
} Template;
|
||||
|
||||
typedef struct _DatabaseStatement
|
||||
{
|
||||
char * query;
|
||||
} TemplateStatement;
|
||||
|
||||
|
||||
/* protected */
|
||||
/* prototypes */
|
||||
/* plug-in */
|
||||
static Template * _template_init(Config * config, char const * section);
|
||||
static void _template_destroy(Template * pgsql);
|
||||
|
||||
static int _template_get_last_id(Template * pgsql);
|
||||
|
||||
static int _template_query(Template * pgsql, char const * query,
|
||||
DatabaseCallback callback, void * data);
|
||||
|
||||
static TemplateStatement * _template_prepare_new(Template * pgsql,
|
||||
char const * query);
|
||||
static void _template_prepare_delete(Template * pgsql, TemplateStatement * statement);
|
||||
static int _template_prepare_query(Template * template,
|
||||
TemplateStatement * statement, DatabaseCallback callback,
|
||||
void * data, va_list args);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
DatabasePluginDefinition database =
|
||||
{
|
||||
"Template",
|
||||
NULL,
|
||||
_template_init,
|
||||
_template_destroy,
|
||||
_template_get_last_id,
|
||||
_template_query,
|
||||
_template_prepare_new,
|
||||
_template_prepare_delete,
|
||||
_template_prepare_query
|
||||
};
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* _template_init */
|
||||
static Template * _template_init(Config * config, char const * section)
|
||||
{
|
||||
Template * template;
|
||||
|
||||
if((template = object_new(sizeof(*template))) == NULL)
|
||||
return NULL;
|
||||
template->handle = NULL;
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
/* _template_destroy */
|
||||
static void _template_destroy(Template * template)
|
||||
{
|
||||
object_delete(template);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* _template_get_last_id */
|
||||
static int _template_get_last_id(Template * template)
|
||||
{
|
||||
/* FIXME really implement */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* _template_prepare_new */
|
||||
static TemplateStatement * _template_prepare_new(Template * template,
|
||||
char const * query)
|
||||
{
|
||||
TemplateStatement * statement;
|
||||
|
||||
if((statement = object_new(sizeof(*statement))) == NULL)
|
||||
return NULL;
|
||||
statement->query = string_new(query);
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
/* _template_prepare_delete */
|
||||
static void _template_prepare_delete(Template * template, TemplateStatement * statement)
|
||||
{
|
||||
string_delete(statement->query);
|
||||
object_delete(statement);
|
||||
}
|
||||
|
||||
|
||||
/* _template_prepare_query */
|
||||
static int _template_prepare_query(Template * template,
|
||||
TemplateStatement * statement, DatabaseCallback callback,
|
||||
void * data, va_list args)
|
||||
{
|
||||
int type = -1;
|
||||
char const * name;
|
||||
char const * s;
|
||||
void * p;
|
||||
|
||||
/* FIXME really implement */
|
||||
while((type = va_arg(args, int)) != -1)
|
||||
{
|
||||
name = va_arg(args, char const *);
|
||||
switch(type)
|
||||
{
|
||||
case DT_VARCHAR:
|
||||
s = va_arg(args, char const *);
|
||||
/* FIXME implement */
|
||||
break;
|
||||
default:
|
||||
p = va_arg(args, void *);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* _template_query */
|
||||
static int _template_query(Template * template, char const * query,
|
||||
DatabaseCallback callback, void * data)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, query);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
12
src/project.conf
Normal file
12
src/project.conf
Normal file
|
@ -0,0 +1,12 @@
|
|||
subdirs=database
|
||||
targets=database.o
|
||||
cflags_force=-W -fPIC
|
||||
cflags=-Wall -g -O2 -pedantic
|
||||
dist=Makefile
|
||||
|
||||
[database.o]
|
||||
type=object
|
||||
sources=database.c
|
||||
|
||||
[database.c]
|
||||
depends=database/database.h
|
Loading…
Reference in New Issue
Block a user