first cut at postgres support

This commit is contained in:
Vítor Santos Costa 2015-02-16 11:44:37 +00:00
parent 9895ec63d0
commit a24c90334f
9 changed files with 1371 additions and 129 deletions

View File

@ -21,7 +21,7 @@ YAPLIBDIR=@libdir@/Yap
#
CC=@CC@
YAP_EXTRAS=@YAP_EXTRAS@
CFLAGS= $(YAP_EXTRAS) @SHLIB_CFLAGS@ $(YAP_EXTRAS) $(DEFS) -I$(srcdir) -I../.. -I$(srcdir)/../../include -I$(srcdir)/../../H -I$(srcdir)/../../OPTYap -I$(srcdir)/../../os @MYDDAS_CPPFLAGS@
CFLAGS= $(YAP_EXTRAS) @SHLIB_CFLAGS@ $(YAP_EXTRAS) $(DEFS) -I$(srcdir) -I../.. -I$(srcdir)/../../include -I$(srcdir)/../../H -I$(srcdir)/../../OPTYap -I$(srcdir)/../../os @MYDDAS_CPPFLAGS@
LDFLAGS=@LDFLAGS@
#
#
@ -47,6 +47,7 @@ MYDDAS_HEADERS= \
MYDDAS_SOURCES= \
myddas_mysql.c \
myddas_odbc.c \
myddas_postgres.c \
myddas_sqlite3.c \
myddas_util.c \
myddas_initialization.c \
@ -59,8 +60,10 @@ MYDDAS_PROLOG= \
$(srcdir)/pl/myddas.ypp \
$(srcdir)/pl/myddas_assert_predicates.ypp \
$(srcdir)/pl/myddas_mysql.ypp \
$(srcdir)/pl/myddas_top_level.ypp \
$(srcdir)/pl/myddas_sqlite3.ypp \
$(srcdir)/pl/myddas_top_level.ypp \
$(srcdir)/pl/myddas_errors.ypp \
$(srcdir)/pl/myddas_postgres.ypp \
$(srcdir)/pl/myddas_prolog2sql.ypp \
$(srcdir)/pl/myddas_util_predicates.ypp \
$(srcdir)/pl/myddas_prolog2sql_optimizer.ypp
@ -72,7 +75,7 @@ SOBJS= myddas.@SO@
#in some systems we just create a single object, in others we need to
# create a libray
all: $(SOBJS)
all: $(SOBJS)
.PRECIOUS: %.o
@ -103,4 +106,3 @@ clean:
distclean: clean
rm -f Makefile

View File

@ -61,6 +61,20 @@ AC_ARG_WITH(sqlite3,
fi,
[yap_cv_sqlite3=/usr])
AC_ARG_WITH(postgres,
[ --with-postgres[[=DIR]] with an POSTGRES library],
if test "$withval" = yes; then
yap_cv_postgres=/usr
elif test "$withval" = no; then
yap_cv_postgres=no
else
yap_cv_postgres=$withval
LDFLAGS="$LDFLAGS -L${yap_cv_postgres}/lib "
CPPFLAGS="$CPPFLAGS -I${yap_cv_postgres}/include "
MYDDAS_CPPFLAGS="$MYDDAS_CPPFLAGS -I${yap_cv_postgres}/include "
fi,
[yap_cv_postgres=/usr])
AC_ARG_ENABLE(myddas-stats,
[ --enable-myddas-stats enable the MYDDAS library statistics support],
if test "$yap_cv_myddas" = no; then
@ -136,6 +150,18 @@ then
YAP_EXTRAS="$YAP_EXTRAS -DMYDDAS_SQLITE3"
fi
AC_CHECK_LIB(pq, PQconnectdbParams,
LIBS="-lpq $LIBS"
havelib=yes)
AC_CHECK_HEADERS(libpq-fe.h, [], [yap_cv_postgres="no"])
if test "$yap_cv_postgres" != no
then
use_myddas=true
YAP_EXTRAS="$YAP_EXTRAS -DMYDDAS_POSTGRES"
fi
if test "$myddasstats" = "yes"
then
YAP_EXTRAS="$YAP_EXTRAS -DMYDDAS_STATS"

View File

@ -39,7 +39,7 @@
#define IS_SQL_FLOAT(FIELD) FIELD == FIELD_TYPE_DECIMAL || \
FIELD == FIELD_TYPE_DOUBLE || \
FIELD == FIELD_TYPE_FLOAT
FIELD == FIELD_TYPE_FLOAT
#define IS_SQL_GEOMETRY(FIELD) FIELD == FIELD_TYPE_GEOMETRY
@ -62,31 +62,31 @@ void Yap_InitMYDDAS_MySQLPreds(void)
{
/* db_connect: Host x User x Passwd x Database x Connection x ERROR_CODE */
Yap_InitCPred("c_db_my_connect", 7, c_db_my_connect, 0);
/* db_number_of_fields: Relation x Connection x NumberOfFields */
Yap_InitCPred("c_db_my_number_of_fields",3, c_db_my_number_of_fields, 0);
Yap_InitCPred("c_db_my_number_of_fields",3, c_db_my_number_of_fields, 0);
/* db_get_attributes_types: Relation x TypesList */
Yap_InitCPred("c_db_my_get_attributes_types", 3, c_db_my_get_attributes_types, 0);
Yap_InitCPred("c_db_my_get_attributes_types", 3, c_db_my_get_attributes_types, 0);
/* db_query: SQLQuery x ResultSet x Connection */
Yap_InitCPred("c_db_my_query", 5, c_db_my_query, 0);
Yap_InitCPred("c_db_my_query", 5, c_db_my_query, 0);
/* db_disconnect: Connection */
Yap_InitCPred("c_db_my_disconnect", 1,c_db_my_disconnect, 0);
/* db_table_write: Result Set */
Yap_InitCPred("c_db_my_table_write", 1, c_db_my_table_write, 0);
Yap_InitCPred("c_db_my_table_write", 1, c_db_my_table_write, 0);
/* db_get_fields_properties: PredName x Connnection x PropertiesList*/
Yap_InitCPred("c_db_my_get_fields_properties",3,c_db_my_get_fields_properties,0);
Yap_InitCPred("c_db_my_get_next_result_set",2,c_db_my_get_next_result_set,0);
/* c_db_my_get_database: Connnection x DataBaseName */
Yap_InitCPred("c_db_my_get_database",2,c_db_my_get_database,0);
/* c_db_my_change_database: Connnection x DataBaseName */
Yap_InitCPred("c_db_my_change_database",2,c_db_my_change_database,0);
@ -105,13 +105,13 @@ void Yap_InitBackMYDDAS_MySQLPreds(void)
static Int
c_db_my_connect( USES_REGS1 ) {
Term arg_host = Deref(ARG1);
Term arg_host = Deref(ARG1);
Term arg_user = Deref(ARG2);
Term arg_passwd = Deref(ARG3);
Term arg_database = Deref(ARG4);
Term arg_port = Deref(ARG5);
Term arg_socket = Deref(ARG6);
Term arg_conn = Deref(ARG7);
Term arg_conn = Deref(ARG7);
MYSQL *conn;
@ -122,7 +122,7 @@ c_db_my_connect( USES_REGS1 ) {
char *passwd = AtomName(AtomOfTerm(arg_passwd));
char *database = AtomName(AtomOfTerm(arg_database));
Int port = IntegerOfTerm(arg_port);
char *socket;
if (IsNonVarTerm(arg_socket))
socket = AtomName(AtomOfTerm(arg_socket));
@ -136,7 +136,7 @@ c_db_my_connect( USES_REGS1 ) {
#endif
return FALSE;
}
if (mysql_real_connect(conn, host, user, passwd, database, port, socket, CLIENT_MULTI_STATEMENTS) == NULL) {
#ifdef DEBUG
printf("ERROR: ** c_db_my_connect ** error on connect\n");
@ -150,7 +150,7 @@ c_db_my_connect( USES_REGS1 ) {
{
/* Criar um novo no na lista de ligacoes*/
new = myddas_util_add_connection(conn,NULL,MYDDAS_API);
if (new == NULL){
#ifdef DEBUG
printf("ERROR: ** c_db_my_connect ** Error allocating memory\n");
@ -162,26 +162,26 @@ c_db_my_connect( USES_REGS1 ) {
}
/* db_query: SQLQuery x ResultSet x Connection */
static Int
static Int
c_db_my_query( USES_REGS1 ) {
Term arg_sql_query = Deref(ARG1);
Term arg_result_set = Deref(ARG2);
Term arg_conn = Deref(ARG3);
Term arg_mode = Deref(ARG4);
Term arg_arity = Deref(ARG5);
char *sql = AtomName(AtomOfTerm(arg_sql_query));
char *mode = AtomName(AtomOfTerm(arg_mode));
MYSQL *conn = (MYSQL *) (IntegerOfTerm(arg_conn));
MYSQL_RES *res_set;
MyddasInt length=strlen(sql);
#ifdef MYDDAS_STATS
#ifdef MYDDAS_STATS
MYDDAS_UTIL_CONNECTION node = myddas_util_search_connection(conn);
MyddasULInt count = 0;
/* Count the number of querys made to the server */
MyddasULInt number_querys;
MYDDAS_STATS_CON_GET_NUMBER_QUERIES_MADE(node,number_querys);
@ -193,89 +193,89 @@ c_db_my_query( USES_REGS1 ) {
processing the SQL Query */
MYDDAS_STATS_TIME start,end,total_time,diff;
start = myddas_stats_walltime();
#endif
#endif
/* Send query to server and process it */
if (mysql_real_query(conn, sql, length) != 0)
{
#ifdef DEBUG
printf("ERROR: **c_db_my_query** Error on query! %s\n",sql);
#endif
#endif
return FALSE;
}
#ifdef MYDDAS_STATS
#ifdef MYDDAS_STATS
/* Measure time spent by the MySQL Server
processing the SQL Query */
end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_CON_GET_TOTAL_TIME_DBSERVER(node,total_time);
/* Automacally updates the MYDDAS_STRUCTURE */
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_CON_GET_TOTAL_TIME_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_TOTAL_TIME_DBSERVER_COUNT(node,++count);
MYDDAS_STATS_TIME time = NULL;
MYDDAS_STATS_CON_GET_LAST_TIME_DBSERVER(node,time);
myddas_stats_move_time(diff,time);
MYDDAS_STATS_CON_GET_LAST_TIME_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_LAST_TIME_DBSERVER_COUNT(node,++count);
#endif
#endif
/* guardar os tuplos do lado do cliente */
if (strcmp(mode,"store_result")!=0) //True
res_set = mysql_use_result(conn);
else{
#ifdef MYDDAS_STATS
/* Measure time spent by the MySQL Server
transferring the result of the last query
back to the client */
start = myddas_stats_walltime();
#endif
#endif
res_set = mysql_store_result(conn);
#ifdef MYDDAS_STATS
/* Measure time spent by the MySQL Server
transferring the result of the last query
back to the client */
end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_CON_GET_TOTAL_TIME_TRANSFERING(node,total_time);
/* Automacally updates the MYDDAS_STRUCTURE */
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_CON_GET_TOTAL_TIME_TRANSFERING_COUNT(node,count);
MYDDAS_STATS_CON_SET_TOTAL_TIME_TRANSFERING_COUNT(node,++count);
time = NULL;
MYDDAS_STATS_CON_GET_LAST_TIME_TRANSFERING(node,time);
MYDDAS_STATS_CON_GET_LAST_TIME_TRANSFERING_COUNT(node,count);
MYDDAS_STATS_CON_SET_LAST_TIME_TRANSFERING_COUNT(node,++count);
myddas_stats_move_time(diff,time);
/* Measure the number of Rows returned from the server */
if (res_set != NULL)
{
/* With an INSERT statement, mysql_(use or store)_result()
returns a NULL pointer*/
/* This is only works if we use mysql_store_result */
MyddasUInt numberRows = mysql_num_rows(res_set);
MyddasUInt rows;
MYDDAS_STATS_CON_GET_TOTAL_ROWS(node,rows);
numberRows = numberRows + rows;
MYDDAS_STATS_CON_SET_TOTAL_ROWS(node,numberRows);
@ -289,7 +289,7 @@ c_db_my_query( USES_REGS1 ) {
total=0;
while ((row = mysql_fetch_row(res_set)) != NULL){
mysql_field_seek(res_set,0);
for(i=0;i<number_fields;i++){
if (row[i] != NULL)
total = total + strlen(row[i]);
@ -298,7 +298,7 @@ c_db_my_query( USES_REGS1 ) {
MYDDAS_STATS_CON_SET_LAST_BYTES_TRANSFERING_FROM_DBSERVER(node,total);
MYDDAS_STATS_CON_GET_LAST_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_LAST_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,++count);
MyddasUInt bytes = 0;
MYDDAS_STATS_CON_GET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER(node,bytes);
total = total + bytes;
@ -307,7 +307,7 @@ c_db_my_query( USES_REGS1 ) {
MYDDAS_STATS_CON_SET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,++count);
mysql_data_seek(res_set,0);
}
#endif
#endif
}
if (res_set == NULL)
@ -320,11 +320,11 @@ c_db_my_query( USES_REGS1 ) {
#endif
return FALSE;
}
if (!Yap_unify(arg_arity, MkIntegerTerm(mysql_num_fields(res_set)))){
return FALSE;
}
if (!Yap_unify(arg_result_set, MkIntegerTerm((Int) res_set)))
{
mysql_free_result(res_set);
@ -336,12 +336,12 @@ c_db_my_query( USES_REGS1 ) {
}
}
static Int
static Int
c_db_my_number_of_fields( USES_REGS1 ) {
Term arg_relation = Deref(ARG1);
Term arg_conn = Deref(ARG2);
Term arg_fields = Deref(ARG3);
char *relation = AtomName(AtomOfTerm(arg_relation));
MYSQL *conn = (MYSQL *) (IntegerOfTerm(arg_conn));
@ -359,14 +359,14 @@ c_db_my_number_of_fields( USES_REGS1 ) {
#endif
return FALSE;
}
/* guardar os tuplos do lado do cliente */
if ((res_set = mysql_store_result(conn)) == NULL)
{
#ifdef DEBUG
printf("ERROR: **c_db_my_number_of_fields** Error storing the query! %s\n",sql);
#endif
return FALSE;
}
@ -375,12 +375,12 @@ c_db_my_number_of_fields( USES_REGS1 ) {
return FALSE;
}
mysql_free_result(res_set);
return TRUE;
return TRUE;
}
/* db_get_attributes_types: RelName x Connection -> TypesList */
static Int
static Int
c_db_my_get_attributes_types( USES_REGS1 ) {
Term arg_relation = Deref(ARG1);
Term arg_conn = Deref(ARG2);
@ -424,26 +424,26 @@ c_db_my_get_attributes_types( USES_REGS1 ) {
list = TailOfTerm(list);
head = HeadOfTerm(list);
list = TailOfTerm(list);
if (strncmp(row[1], "smallint",8) == 0 || strncmp(row[1],"int",3) == 0 ||
strncmp(row[1], "mediumint",9) == 0 || strncmp(row[1], "tinyint",7) == 0 ||
strncmp(row[1], "bigint",6) == 0 || strcmp(row[1], "year") == 0)
Yap_unify(head, MkAtomTerm(Yap_LookupAtom("integer")));
else if (strcmp(row[1], "float") == 0 || strncmp(row[1], "double",6) == 0
else if (strcmp(row[1], "float") == 0 || strncmp(row[1], "double",6) == 0
|| strcmp(row[1], "real") == 0)
Yap_unify(head, MkAtomTerm(Yap_LookupAtom("real")));
else Yap_unify(head, MkAtomTerm(Yap_LookupAtom("string")));
}
mysql_free_result(res_set);
return TRUE;
}
/* db_disconnect */
static Int
c_db_my_disconnect( USES_REGS1 ) {
Term arg_conn = Deref(ARG1);
Term arg_conn = Deref(ARG1);
MYSQL *conn = (MYSQL *) IntegerOfTerm(arg_conn);
@ -453,29 +453,29 @@ c_db_my_disconnect( USES_REGS1 ) {
mysql_close(conn);
return TRUE;
}
else
else
{
return FALSE;
}
}
/* db_table_write: Result Set */
static Int
static Int
c_db_my_table_write( USES_REGS1 ) {
Term arg_res_set = Deref(ARG1);
MYSQL_RES *res_set = (MYSQL_RES *) IntegerOfTerm(arg_res_set);
myddas_util_table_write(res_set);
mysql_free_result(res_set);
return TRUE;
return TRUE;
}
static Int
c_db_my_row_cut( USES_REGS1 ) {
MYSQL_RES *mysql_res=NULL;
mysql_res = (MYSQL_RES *) IntegerOfTerm(EXTRA_CBACK_CUT_ARG(Term,1));
mysql_free_result(mysql_res);
return TRUE;
@ -490,46 +490,46 @@ c_db_my_row( USES_REGS1 ) {
MYDDAS_STATS_TIME start,end,total_time,diff;
MyddasULInt count = 0;
start = myddas_stats_walltime();
#endif
#endif
Term arg_result_set = Deref(ARG1);
Term arg_arity = Deref(ARG2);
Term arg_list_args = Deref(ARG3);
MYSQL_RES *res_set = (MYSQL_RES *) IntegerOfTerm(arg_result_set);
EXTRA_CBACK_ARG(3,1)=(CELL) MkIntegerTerm((Int)res_set);
MYSQL_ROW row;
MYSQL_FIELD *field;
Term head, list, null_atom[1];
Int i, arity;
arity = IntegerOfTerm(arg_arity);
while(TRUE)
{
if ((row = mysql_fetch_row(res_set)) != NULL)
{
mysql_field_seek(res_set,0);
mysql_field_seek(res_set,0);
list = arg_list_args;
for (i = 0; i < arity; i++)
{
/* Here we perform data type conversion. */
field = mysql_fetch_field(res_set);
head = HeadOfTerm(list);
list = TailOfTerm(list);
if (row[i] == NULL)
{
null_atom[0] = MkIntegerTerm(null_id++);
if (!Yap_unify(head, Yap_MkApplTerm(Yap_MkFunctor(Yap_LookupAtom("null"),1),1,null_atom)))
continue;
}
else
{
if (IS_SQL_INT(field->type))
if (IS_SQL_INT(field->type))
{
if (!Yap_unify(head, MkIntegerTerm(atoi(row[i]))))
continue;
@ -544,7 +544,7 @@ c_db_my_row( USES_REGS1 ) {
if (!Yap_unify(head, wkb2prolog(row[i])))
continue;
}
else
else
{
if (!Yap_unify(head, MkAtomTerm(Yap_LookupAtom(row[i]))))
continue;
@ -553,51 +553,51 @@ c_db_my_row( USES_REGS1 ) {
}
#ifdef MYDDAS_STATS
end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_GET_DB_ROW_FUNCTION(total_time);
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_GET_DB_ROW_FUNCTION_COUNT(count);
MYDDAS_STATS_SET_DB_ROW_FUNCTION_COUNT(++count);
MYDDAS_FREE(diff,struct myddas_stats_time_struct);
#endif /* MYDDAS_STATS */
return TRUE;
}
else
else
{
mysql_free_result(res_set);
#ifdef MYDDAS_STATS
end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_GET_DB_ROW_FUNCTION(total_time);
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_GET_DB_ROW_FUNCTION_COUNT(count);
MYDDAS_STATS_SET_DB_ROW_FUNCTION_COUNT(++count);
MYDDAS_FREE(diff,struct myddas_stats_time_struct);
#endif /* MYDDAS_STATS */
cut_fail(); /* This macro already does a return FALSE */
}
}
}
static Int
static Int
c_db_my_get_fields_properties( USES_REGS1 ) {
Term nome_relacao = Deref(ARG1);
Term arg_conn = Deref(ARG2);
@ -610,10 +610,10 @@ c_db_my_get_fields_properties( USES_REGS1 ) {
MYSQL_FIELD *fields;
MYSQL_RES *res_set;
MYSQL *conn = (MYSQL *) (IntegerOfTerm(arg_conn));
/* LIMIT 0 -> We only need the meta information about the fields
to know their properties, we don't need the results of the
to know their properties, we don't need the results of the
query*/
sprintf (sql,"SELECT * FROM `%s` LIMIT 0",relacao);
@ -627,66 +627,66 @@ c_db_my_get_fields_properties( USES_REGS1 ) {
#endif
return FALSE;
}
Functor functor = Yap_MkFunctor(Yap_LookupAtom("property"),4);
Term properties[4];
/* guardar os tuplos do lado do cliente */
/* nao precisamos do resultado, mas apenas no res_set */
/* para obter a informa<6D><61>o atrav<61>s do mysql_fetch_fields*/
res_set = mysql_store_result(conn);
num_fields = mysql_num_fields(res_set);
fields = mysql_fetch_fields(res_set);
list = fields_properties_list;
for (i=0;i<num_fields;i++)
{
head = HeadOfTerm(list);
properties[0] = MkAtomTerm(Yap_LookupAtom(fields[i].name));
if (fields[i].flags & NOT_NULL_FLAG)
properties[1] = MkIntegerTerm(1); //Can't be NULL
properties[1] = MkIntegerTerm(1); //Can't be NULL
else
properties[1] = MkIntegerTerm(0);
if (fields[i].flags & PRI_KEY_FLAG)
properties[2] = MkIntegerTerm(1); //It''s a primary key
if (fields[i].flags & PRI_KEY_FLAG)
properties[2] = MkIntegerTerm(1); //It''s a primary key
else
properties[2] = MkIntegerTerm(0);
if (fields[i].flags & AUTO_INCREMENT_FLAG)
properties[3] = MkIntegerTerm(1); //It's auto_incremented field
else
properties[3] = MkIntegerTerm(0);
list = TailOfTerm(list);
if (!Yap_unify(head, Yap_MkApplTerm(functor,4,properties))){
return FALSE;
}
}
mysql_free_result(res_set);
return TRUE;
}
/* c_db_my_get_next_result_set: Connection * NextResSet */
static Int
static Int
c_db_my_get_next_result_set( USES_REGS1 ) {
Term arg_conn = Deref(ARG1);
Term arg_next_res_set = Deref(ARG2);
MYSQL *conn = (MYSQL *) (IntegerOfTerm(arg_conn));
MYSQL_RES *res_set=NULL;
if (mysql_next_result(conn) == 0){
res_set = mysql_store_result(conn);
Yap_unify(arg_next_res_set, MkIntegerTerm((Int) res_set));
@ -694,21 +694,21 @@ c_db_my_get_next_result_set( USES_REGS1 ) {
return TRUE;
}
static Int
static Int
c_db_my_get_database( USES_REGS1 ) {
Term arg_con = Deref(ARG1);
Term arg_database = Deref(ARG2);
MYSQL *con = (MYSQL *) (IntegerOfTerm(arg_con));
if (!Yap_unify(arg_database,MkAtomTerm(Yap_LookupAtom(con->db))))
return FALSE;
return TRUE;
}
static Int
static Int
c_db_my_change_database( USES_REGS1 ) {
Term arg_con = Deref(ARG1);
Term arg_database = Deref(ARG2);

View File

@ -0,0 +1,888 @@
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: myddas_postgres.c *
* Last rev: 22/03/05 *
* mods: *
* comments: Predicates for comunicating with a pq database system *
* *
*************************************************************************/
#ifdef MYDDAS_POSTGRES
#include <libpq-fe.h>
#define BOOLOID 16
#define BYTEOID 17
#define CHAROID 18
#define NAMEOID 19
#define INT8OID 20
#define INT2OID 21
#define INT2VECTOROID 22
#define INT4OID 23
#define REGPROCOID 24
#define TEXTOID 25
#define OIDOID 26
#define TIDOID 27
#define XIDOID 28
#define CIDOID 29
#define OIDVECTOROID 30
#define JSONOID 114
#define XMLOID 142
#define PGNODETREEOID 194
#define POINTOID 600
#define LSEGOID 601
#define PATHOID 602
#define BOXOID 603
#define POLYGONOID 604
#define LINEOID 628
#define FLOAT4OID 700
#define FLOAT8OID 701
#define ABSTIMEOID 702
#define RELTIMEOID 703
#define TINTERVALOID 704
#define UNKNOWNOID 705
#define CIRCLEOID 718
#define CASHOID 790
#define MACADDROID 829
#define INETOID 869
#define CIDROID 650
#define INT2ARRAYOID 1005
#define INT4ARRAYOID 1007
#define TEXTARRAYOID 1009
#define OIDARRAYOID 1028
#define FLOAT4ARRAYOID 1021
#define ACLITEMOID 1033
#define CSTRINGARRAYOID 1263
#define BPCHAROID 1042
#define VARCHAROID 1043
#define DATEOID 1082
#define TIMEOID 1083
#define TIMESTAMPOID 1114
#define TIMESTAMPTZOID 1184
#define INTERVALOID 1186
#define TIMETZOID 1266
#define BITOID 1560
#define VARBITOID 1562
#define NUMERICOID 1700
#define REFCURSOROID 1790
#define REGPROCEDUREOID 2202
#define REGOPEROID 2203
#define REGOPERATOROID 2204
#define REGCLASSOID 2205
#define REGTYPEOID 2206
#define REGTYPEARRAYOID 2211
#define UUIDOID 2950
#define LSNOID 3220
#define TSVECTOROID 3614
#define GTSVECTOROID 3642
#define TSQUERYOID 3615
#define REGCONFIGOID 3734
#define REGDICTIONARYOID 3769
#define JSONBOID 3802
#define INT4RANGEOID 3904
#define RECORDOID 2249
#define RECORDARRAYOID 2287
#define CSTRINGOID 2275
#define ANYOID 2276
#define ANYARRAYOID 2277
#define VOIDOID 2278
#define TRIGGEROID 2279
#define EVTTRIGGEROID 3838
#define LANGUAGE_HANDLEROID 2280
#define INTERNALOID 2281
#define OPAQUEOID 2282
#define ANYELEMENTOID 2283
#define ANYNONARRAYOID 2776
#define ANYENUMOID 3500
#define FDW_HANDLEROID 3115
#define ANYRANGEOID 3831
#include "Yap.h"
#include "Yatom.h"
#include "YapText.h"
#include "cut_c.h"
#include "eval.h"
#include "myddas.h"
#ifdef MYDDAS_STATS
#include "myddas_structs.h"
#include "myddas_statistics.h"
#endif
#include "myddas_wkb2prolog.h"
#define CALL_POSTGRES(f) \
{ \
res = PQ ## f; \
if (PQstatus(db) != CONNECTION_OK) { \
fprintf(stderr, "Error %s when calling %s, line %d\n", \
PQerrorMessage(db), #f,__LINE__); \
exit (1); \
} \
PQclear(res); \
} \
#define GET_POSTGRES(f, res) \
{ \
res = PQ ## f; \
if (PQstatus(db) != CONNECTION_OK) { \
fprintf (stderr, "%s failed with status %s, line %d\n", \
#f, PQerrorMessage (db), __LINE__); \
exit (1); \
} \
} \
static Int NULL_id = 0;
typedef struct result_set {
PGconn *db;
PGresult *res;
const char *stmt;
int i ;
int nrows;
int ncols;
} resultSet;
void Yap_InitMYDDAS_PGPreds(void);
void Yap_InitBackMYDDAS_PGPreds(void);
static Int c_postgres_connect( USES_REGS1 );
static Int c_postgres_disconnect( USES_REGS1 );
static Int c_postgres_number_of_fields( USES_REGS1 );
static Int c_postgres_get_attributes_types( USES_REGS1 );
static Int c_postgres_query( USES_REGS1 );
static Int c_postgres_table_write( USES_REGS1 );
static Int c_postgres_row( USES_REGS1 );
static Int c_postgres_row_cut( USES_REGS1 );
static Int c_postgres_get_fields_properties( USES_REGS1 );
static Int c_postgres_get_next_result_set( USES_REGS1 );
static Int c_postgres_get_database( USES_REGS1 );
static Int c_postgres_change_database( USES_REGS1 );
void Yap_InitMYDDAS_PGPreds(void)
{
/* db_dbect: Host x User x Passwd x Database x dbection x ERROR_CODE */
Yap_InitCPred("c_postgres_connect", 7, c_postgres_connect, 0);
/* db_number_of_fields: Relation x connection x NumberOfFields */
Yap_InitCPred("c_postgres_number_of_fields",3, c_postgres_number_of_fields, 0);
/* db_get_attributes_types: Relation x TypesList */
Yap_InitCPred("c_postgres_get_attributes_types", 3, c_postgres_get_attributes_types, 0);
/* db_query: SQLQuery x ResultSet x conection */
Yap_InitCPred("c_postgres_query", 5, c_postgres_query, 0);
/* db_disconnect: connection */
Yap_InitCPred("c_postgres_disconnect", 1,c_postgres_disconnect, 0);
/* db_table_write: Result Set */
Yap_InitCPred("c_postgres_table_write", 1, c_postgres_table_write, 0);
/* db_get_fields_properties: PredName x connection x PropertiesList*/
Yap_InitCPred("c_postgres_get_fields_properties",3,c_postgres_get_fields_properties,0);
Yap_InitCPred("c_postgres_get_next_result_set",2,c_postgres_get_next_result_set,0);
/* c_postgres_get_database: connection x DataBaseName */
Yap_InitCPred("c_postgres_get_database",2,c_postgres_get_database,0);
/* c_postgres_change_database: connection x DataBaseName */
Yap_InitCPred("c_postgres_change_database",2,c_postgres_change_database,0);
}
void Yap_InitBackMYDDAS_PGPreds(void)
{
/* db_row: ResultSet x Arity x ListOfArgs */
Yap_InitCPredBackCut("c_postgres_row", 3, sizeof(Int),
c_postgres_row,
c_postgres_row,
c_postgres_row_cut, 0);
}
static Int
c_postgres_connect( USES_REGS1 ) {
int i=0;
Term arg_host = Deref(ARG1);
Term arg_user = Deref(ARG2);
Term arg_passwd = Deref(ARG3);
Term arg_database = Deref(ARG4);
Term arg_port = Deref(ARG5);
Term arg_socket = Deref(ARG6);
Term arg_conn = ARG7;
Term tempty = MkAtomTerm(Yap_LookupAtom(""));
Term tzero = MkIntTerm(0);
const char *keywords[8], *values[8];
char ports[16];
if (IsApplTerm(arg_host)) {
keywords[i] = "hostaddr";
values[i++] = RepAtom(AtomOfTerm(ArgOfTerm(1, arg_host)))->StrOfAE;
} else {
keywords[i] = "host";
values[i++] = RepAtom(AtomOfTerm(arg_host))->StrOfAE;
}
if (IsNonVarTerm(arg_user) && arg_user != tempty && IsAtomTerm(arg_user)) {
keywords[i] = "user";
values[i++] = RepAtom(AtomOfTerm(arg_user))->StrOfAE;
}
if (IsNonVarTerm(arg_user) && arg_passwd != tempty && IsAtomTerm(arg_passwd)) {
keywords[i] = "password";
values[i++] = RepAtom(AtomOfTerm(arg_passwd))->StrOfAE;
}
if (IsNonVarTerm(arg_user) && arg_database != tempty && IsAtomTerm(arg_database)) {
keywords[i] = "dbase";
values[i++] = RepAtom(AtomOfTerm(arg_database))->StrOfAE;
}
if (IsNonVarTerm(arg_user) && arg_port != tzero && IsIntTerm(arg_port)) {
keywords[i] = "port";
snprintf(ports, sizeof(ports)-1, "%d", (int)IntOfTerm(arg_port));
values[i++] = ports;
} else if (IsNonVarTerm(arg_socket) && arg_socket != tempty && IsIntTerm(arg_socket)) {
keywords[i] = "port";
values[i++] = RepAtom(AtomOfTerm(arg_database))->StrOfAE;
}
keywords[i] = NULL;
values[i++] = NULL;
/* Make a connection to the database */
PGconn *db = PQconnectdbParams(keywords, values, 0);
/* Check to see that the backend c onnection was successfully made */
if (PQstatus(db) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(db));
return FALSE;
}
if (!Yap_unify(arg_conn, MkAddressTerm(db)))
return FALSE;
else
{
/* Criar um novo no na lista de ligacoes*/
MYDDAS_UTIL_CONNECTION cnew = myddas_util_add_connection(db,NULL,MYDDAS_POSTGRES);
if (cnew == NULL){
#ifdef DEBUG
printf("ERROR: ** c_db_my_connect ** Error allocating memory\n");
#endif
return FALSE;
}
return TRUE;
}
}
static MYDDAS_STATS_TIME
myddas_stat_init_query( PGconn *db )
{
#ifdef MYDDAS_STATS
MYDDAS_UTIL_connecTION node = myddas_util_search_connection(db);
MyddasULInt count = 0;
/* Count the number of querys made to the server */
MyddasULInt number_querys;
MYDDAS_STATS_CON_GET_NUMBER_QUERIES_MADE(node,number_querys);
MYDDAS_STATS_CON_SET_NUMBER_QUERIES_MADE(node,++number_querys);
MYDDAS_STATS_CON_GET_NUMBER_QUERIES_MADE_COUNT(node,count);
MYDDAS_STATS_CON_SET_NUMBER_QUERIES_MADE_COUNT(node,++count);
/* Measure time spent by the PG Server
processing the SQL Query */
return myddas_stats_walltime();
#else
return NULL;
#endif
}
static MYDDAS_STATS_TIME
myddas_stat_end_query( MYDDAS_STATS_TIME start )
{
MYDDAS_STATS_TIME diff = NULL;
#ifdef MYDDAS_STATS
/* Measure time spent by the PG Server
processing the SQL Query */
MYDDAS_STATS_TIME end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_CON_GET_TOTAL_TIME_DBSERVER(node,total_time);
/* Automacally updates the MYDDAS_STRUCTURE */
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_CON_GET_TOTAL_TIME_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_TOTAL_TIME_DBSERVER_COUNT(node,++count);
MYDDAS_STATS_TIME time = NULL;
MYDDAS_STATS_CON_GET_LAST_TIME_DBSERVER(node,time);
myddas_stats_move_time(diff,time);
MYDDAS_STATS_CON_GET_LAST_TIME_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_LAST_TIME_DBSERVER_COUNT(node,++count);
#endif
return diff;
}
#ifdef MYDDAS_STATS
/* measure transfer time */
static void
myddas_stat_transfer_query( MYDDAS_STATS_TIME diff )
{
/* Measure time spent by the PG Server
transferring the result of the last query
back to the client */
start = myddas_stats_walltime();
/* Measure time spent by the PG Server
transferring the result of the last query
back to the client */
end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = MYDDAS_STATS_TIME_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_CON_GET_TOTAL_TIME_TRANSFERING(node,total_time);
/* Automacally updates the MYDDAS_STRUCTURE */
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_CON_GET_TOTAL_TIME_TRANSFERING_COUNT(node,count);
MYDDAS_STATS_CON_SET_TOTAL_TIME_TRANSFERING_COUNT(node,++count);
time = NULL;
MYDDAS_STATS_CON_GET_LAST_TIME_TRANSFERING(node,time);
MYDDAS_STATS_CON_GET_LAST_TIME_TRANSFERING_COUNT(node,count);
MYDDAS_STATS_CON_SET_LAST_TIME_TRANSFERING_COUNT(node,++count);
myddas_stats_move_time(diff,time);
/* Measure the number of Rows returned from the server */
if (res_set != NULL)
{
/* With an INSERT statement, PG_(use or store)_result()
returns a NULL pointer*/
/* This is only works if we use PG_store_result */
MyddasUInt numberRows = PG_num_rows(res_set);
MyddasUInt rows;
myddas_stat_transfer_query( diff );
MYDDAS_STATS_CON_GET_TOTAL_ROWS(node,rows);
numberRows = numberRows + rows;
MYDDAS_STATS_CON_SET_TOTAL_ROWS(node,numberRows);
MYDDAS_STATS_CON_GET_TOTAL_ROWS_COUNT(node,count);
MYDDAS_STATS_CON_SET_TOTAL_ROWS_COUNT(node,++count);
/* Calculate the ammount of data sent by the server */
MyddasUInt total,number_fields = PG_num_fields(res_set);
PG_ROW row;
MyddasULInt i;
total=0;
while ((row = PG_fetch_row(res_set)) != NULL){
PG_field_seek(res_set,0);
for(i=0;i<number_fields;i++){
if (row[i] != NULL)
total = total + strlen(row[i]);
}
}
MYDDAS_STATS_CON_SET_LAST_BYTES_TRANSFERING_FROM_DBSERVER(node,total);
MYDDAS_STATS_CON_GET_LAST_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_LAST_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,++count);
MyddasUInt bytes = 0;
MYDDAS_STATS_CON_GET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER(node,bytes);
total = total + bytes;
MYDDAS_STATS_CON_SET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER(node,total);
MYDDAS_STATS_CON_GET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,count);
MYDDAS_STATS_CON_SET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER_COUNT(node,++count);
}
}
#endif
/* db_query: SQLQuery x ResultSet x connection */
static Int
c_postgres_query( USES_REGS1 ) {
Term arg_sql_query = Deref(ARG1);
Term arg_result_set = Deref(ARG2);
Term arg_db = Deref(ARG3);
Term arg_mode = Deref(ARG4);
Term arg_arity = ARG5;
char *sql = AtomName(AtomOfTerm(arg_sql_query));
char *mode = AtomName(AtomOfTerm(arg_mode));
PGresult *res;
PGconn *db = AddressOfTerm(arg_db);
struct result_set *rs = malloc(sizeof( struct result_set));
if (!rs)
return FALSE;
rs->db = db;
rs->i = 0;
MYDDAS_STATS_TIME start, end;
start = myddas_stat_init_query( db );
const char *stmt = AtomName(Yap_LookupAtom(sql));
/* Send query to server and process it */
if (strcmp(mode,"store_result")!=0) {
// Leave data for extraction
CALL_POSTGRES (prepare(db, stmt, sql, 0, NULL) );
GET_POSTGRES (describePrepared(db, stmt) , res );
rs->stmt = stmt;
rs->res = NULL;
rs->nrows = -1;
rs->ncols = PQnfields(res);
if (!Yap_unify(arg_arity, MkIntegerTerm(rs->ncols)))
{
free(rs);
return FALSE;
}
if (!Yap_unify(arg_result_set, MkAddressTerm( rs)))
{
free(rs);
return FALSE;
}
return TRUE;
} else {
// construct an intermediate table, res_set
int nrows, ncols;
GET_POSTGRES (exec(db, sql), res );
end = myddas_stat_end_query( start );
ncols = PQnfields(res);
nrows = PQntuples(res);
//INSERT statements don't return any res_set
if (nrows == 0) {
return TRUE;
}
if (!Yap_unify(arg_arity, MkIntegerTerm(nrows))){
/*
* Should PGclear PGresult whenever it is no longer needed to avoid memory
* leaks
*/
free(rs);
PQclear(res);
return FALSE;
}
rs->stmt = NULL;
rs->res = res;
rs->nrows = nrows;
rs->ncols = ncols;
if (!Yap_unify(arg_result_set, MkAddressTerm( rs)))
{
free(rs);
PQclear(res);
return FALSE;
}
}
return TRUE;
}
static Int
c_postgres_number_of_fields( USES_REGS1 ) {
Term arg_relation = Deref(ARG1);
Term arg_db = Deref(ARG2);
Term arg_fields = ARG3;
char *relation = AtomName(AtomOfTerm(arg_relation));
PGconn *db = AddressOfTerm(arg_db);
const char *stmt;
PGresult *res;
char sql[256];
snprintf(sql, 255, "SELECT * FROM TABLE `%s`",relation);
// Leave data for extraction
stmt = AtomName(Yap_LookupAtom(sql));
CALL_POSTGRES (prepare(db, stmt, sql, 0, NULL) );
/* executar a query SQL */
int nrows = PQntuples(res);
PQclear( res );
return Yap_unify(arg_fields, MkIntegerTerm( nrows ));
}
/* db_get_attributes_types: RelName x connection -> TypesList */
static Int
c_postgres_get_attributes_types( USES_REGS1 ) {
Term arg_relation = Deref(ARG1);
Term arg_db = Deref(ARG2);
Term arg_types_list = Deref(ARG3);
Term list, head;
char *relation = AtomName(AtomOfTerm(arg_relation));
PGconn *db = AddressOfTerm(arg_db);
char sql[256];
int row;
PGresult *res;
const char *stmt;
Int rc = TRUE;
sprintf(sql,"SELECT * FROM TABLE `%s`",relation);
// Leave data for extraction
GET_POSTGRES (prepare(db, stmt, sql, 0, NULL), res );
/* executar a query SQL */
int cols = PQnfields( res ), col;
list = arg_types_list;
for (col = 0; col < cols; col++)
{
const char *tm;
head = HeadOfTerm(list);
rc = (
rc && Yap_unify(head, MkAtomTerm(Yap_LookupAtom(PQfname(res, col))) ) );
list = TailOfTerm(list);
head = HeadOfTerm(list);
list = TailOfTerm(list);
Oid type = PQftype(res, col);
switch(type) {
case BYTEOID:
case CHAROID:
case INT2OID:
case INT4OID:
case INT8OID:
tm = "integer";
break;
case FLOAT4OID:
case FLOAT8OID:
tm = "real";
break;
case NAMEOID:
tm = "atom";
break;
case TEXTOID:
tm = "string";
break;
default:
tm = "unknown type";
break;
}
if (!Yap_unify(head, MkAtomTerm(Yap_LookupAtom(tm))) )
rc = FALSE;
}
PQclear( res );
return rc;
}
/* db_disconnect */
static Int
c_postgres_disconnect( USES_REGS1 ) {
Term arg_db = Deref(ARG1);
PGconn *db = AddressOfTerm(arg_db);
if ((myddas_util_search_connection(db)) != NULL)
{
myddas_util_delete_connection(db);
PQfinish(db);
return TRUE;
}
else
{
return FALSE;
}
}
/* db_table_write: Result Set */
static Int
c_postgres_table_write( USES_REGS1 ) {
/*
Term arg_res_set = Deref(ARG1);
PG_RES *res_set = (PG_RES *) IntegerOfTerm(arg_res_set);
mydas_util_table_write(res_set);
PG_free_result(res_set);
*/
return TRUE;
}
static Int
c_postgres_get_fields_properties( USES_REGS1 ) {
Term nome_relacao = Deref(ARG1);
Term arg_db = Deref(ARG2);
Term fields_properties_list = Deref(ARG3);
Term head, list;
PGresult *res;
char *relation = AtomName(AtomOfTerm(nome_relacao));
char sql[256];
Int num_fields,i;
PGconn *db = AddressOfTerm(arg_db);
sprintf(sql,"\\d+ `%s`",relation);
GET_POSTGRES (exec(db, sql), res );
#if MYDDAS_STATS
end = myddas_stat_end_query( start );
#endif
Functor functor = Yap_MkFunctor(Yap_LookupAtom("property"),4);
list = fields_properties_list;
num_fields = PQntuples(res);
int coln;
const char *propname;
if (( coln = PQfnumber(res,"Column")) < 0)
return FALSE;
if (( propname = PQfname(res,2)) == NULL)
return FALSE;
if (!strstr(propname, "Table") || !strstr(propname, "Modifiers") )
return FALSE;
for (i=0;i<num_fields;i++)
{
Term properties[4];
head = HeadOfTerm(list);
if (!PQgetisnull(res, i, coln)) {
const char *col = PQgetvalue(res, i, coln);
properties[0] = MkAtomTerm(Yap_LookupAtom(col));
}
if (!PQgetisnull(res, i, 2)) {
const char *props = PQgetvalue(res, i, 2);
properties[1] = MkIntegerTerm(strstr(props, "not null") != NULL); //Can't be NULL
properties[2] = MkIntegerTerm(strstr(props, "prim") != NULL); //Can't be NULL
properties[3] = MkIntegerTerm(strstr(props, "nextval") != NULL); //Can't be NULL
}
list = TailOfTerm(list);
if (!Yap_unify(head, Yap_MkApplTerm(functor,4,properties))){
return FALSE;
}
}
PQclear(res);
return TRUE;
}
/* c_postgres_get_next_result_set: connection * NextResSet */
static Int
c_postgres_get_next_result_set( USES_REGS1 ) {
//Term arg_db = Deref(ARG1);
//Term arg_next_res_set = Deref(ARG2);
//PGconn *db = AddressOfTerm(arg_db);
return FALSE;
}
static Int
c_postgres_get_database( USES_REGS1 ) {
Term arg_con = Deref(ARG1);
Term arg_database = Deref(ARG2);
if (!Yap_unify(arg_database,arg_con))
return FALSE;
return TRUE;
}
static Int
c_postgres_change_database( USES_REGS1 ) {
/* no-op for now */
return TRUE;
}
static Int
c_postgres_row_cut( USES_REGS1 ) {
struct result_set *res_set=NULL;
PGconn *db = res_set->db;
res_set = AddressOfTerm(EXTRA_CBACK_CUT_ARG(Term,1));
PQclear( res_set->res );
PQfinish( db );
free(res_set);
return TRUE;
}
#define cvt( s ) cvt__( s PASS_REGS )
static Term
cvt__(const char *s USES_REGS) {
return Yap_CharsToTDQ( s, CurrentModule PASS_REGS);
}
/* db_row: ResultSet x Arity_ListOfArgs x ListOfArgs -> */
static Int
c_postgres_row( USES_REGS1 ) {
#ifdef MYDDAS_STATS
/* Measure time used by the */
/* c_postgres_row function */
//MYDDAS_STATS_TIME start,end,total_time,diff;
MyddasULInt count = 0;
MYDDAS_STATS_TIME start, end;
start = myddas_stats_walltime();
#endif
Term arg_result_set = Deref(ARG1);
Term arg_arity = Deref(ARG2);
Term arg_list_args = Deref(ARG3);
Int rc = TRUE;
if (IsVarTerm( arg_result_set ) ) {
if (!c_postgres_query( PASS_REGS1 ) ) {
cut_fail();
}
arg_result_set = Deref(ARG1);
EXTRA_CBACK_ARG(3,1)= arg_result_set ;
EXTRA_CBACK_ARG(3,2)= MkIntegerTerm(0) ;
}
struct result_set *res_set = AddressOfTerm(arg_result_set);
Term head, list, NULL_atom[1];
Int arity;
list = arg_list_args;
arity = IntegerOfTerm(arg_arity);
PGconn *db = res_set->db;
if (res_set->stmt == NULL ) {
CACHE_REGS
Int i= IntegerOfTerm(EXTRA_CBACK_CUT_ARG(Term,2)), j;
Int rc = true;
// data needs to be copied to Prolog
// row by row
#ifdef MYDDAS_STATS
MYDDAS_STATS_TIME diff;
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
#endif
for (j = 0; j < arity; j++)
{
/* Ts -> List */
const char *field = PQgetvalue(res_set->res, i, j);
head = HeadOfTerm(list);
list = TailOfTerm(list);
rc = (rc && Yap_unify(head, cvt( field )) );
}
if (rc) {
EXTRA_CBACK_ARG(3,2)= MkIntegerTerm(i+1);
return rc;
}
#ifdef MYDDAS_STATS
myddas_stat_transfer_query( diff );
#endif
cut_fail();
}
// busy-waiting
if (!PQsetnonblocking(res_set->db, 1)) {
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(db));
return FALSE;
}
if (!PQsendQueryPrepared(res_set->db, res_set->stmt, 0, NULL, NULL, NULL, 0)) {
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(db));
return FALSE;
}
PGresult *res;
while((res = PQgetResult(res_set->db)) != NULL);
int i;
if (i == res_set->nrows) {
// no more data
PQfinish( res_set->db );
free(res_set);
#ifdef MYDDAS_STATS
end = myddas_stats_walltime();
MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_GET_DB_ROW_FUNCTION(total_time);
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_GET_DB_ROW_FUNCTION_COUNT(count);
MYDDAS_STATS_SET_DB_ROW_FUNCTION_COUNT(++count);
MYDDAS_FREE(diff,struct myddas_stats_time_struct);
#endif /* MYDDAS_STATS */
cut_fail(); /* This macro already does a return FALSE */
} else if (i < res_set->nrows) {
list = arg_list_args;
Term tf;
int j;
for (j = 0; j < arity; j++)
{
/* convert data types here */
head = HeadOfTerm(list);
list = TailOfTerm(list);
if (!PQgetisnull(res, i, j)) {
const char *col = PQgetvalue(res, i, j);
tf = MkAtomTerm(Yap_LookupAtom(col));
} else {
NULL_atom[0] = MkIntegerTerm(NULL_id++);
tf = Yap_MkApplTerm(Yap_MkFunctor(Yap_LookupAtom("NULL"),1),1,NULL_atom);
}
}
if (!Yap_unify(head, tf))
rc = FALSE;
#ifdef MYDDAS_STATS
end = myddas_stats_walltime();
myddas_stats_subtract_time(diff,end,start);
diff = myddas_stats_time_copy_to_final(diff);
MYDDAS_FREE(end,struct myddas_stats_time_struct);
MYDDAS_FREE(start,struct myddas_stats_time_struct);
MYDDAS_STATS_GET_DB_ROW_FUNCTION(total_time);
myddas_stats_add_time(total_time,diff,total_time);
MYDDAS_STATS_GET_DB_ROW_FUNCTION_COUNT(count);
MYDDAS_STATS_SET_DB_ROW_FUNCTION_COUNT(++count);
MYDDAS_FREE(diff,struct myddas_stats_time_struct);
#endif /* MYDDAS_STATS */
} return rc;
}
#endif /* MYDDAS_PG */

View File

@ -313,7 +313,7 @@ c_sqlite3_query( USES_REGS1 ) {
/* Send query to server and process it */
if (strcmp(mode,"store_result")!=0) {
// Leave data for extraction
printf(" SQL 0: %s\n", sql);
printf(" SQL 0: %s\n", sql);
CALL_SQLITE (prepare_v2(db, sql, -1, &stmt, NULL) );
rs->stmt = stmt;
rs->res_set = NULL;
@ -385,7 +385,7 @@ c_sqlite3_number_of_fields( USES_REGS1 ) {
sprintf(sql,"SELECT * FROM `%s`",relation);
/* executar a query SQL */
printf(" SQL 1: %s\n", sql);
printf(" SQL 1: %s\n", sql);
CALL_SQLITE (prepare_v2(db, sql, -1, &stmt, NULL) );
int fields = sqlite3_column_count( stmt );
@ -415,7 +415,7 @@ c_sqlite3_get_attributes_types( USES_REGS1 ) {
sprintf(sql,"SELECT * FROM `%s`",relation);
/* executar a query SQL */
printf(" SQL 3: %s\n", sql);
printf(" SQL 3: %s\n", sql);
CALL_SQLITE (prepare_v2(db, sql, -1, &stmt, NULL) );
int fields = sqlite3_column_count( stmt );
@ -512,7 +512,7 @@ c_sqlite3_get_fields_properties( USES_REGS1 ) {
sprintf(sql,"SELECT * FROM `%s`",relation);
/* executar a query SQL */
printf(" SQL 4: %s\n", sql);
printf(" SQL 4: %s\n", sql);
CALL_SQLITE (prepare_v2(db, sql, -1, &stmt, NULL) );
Functor functor = Yap_MkFunctor(Yap_LookupAtom("property"),4);
@ -595,7 +595,7 @@ c_sqlite3_change_database( USES_REGS1 ) {
static Int
c_sqlite3_row_cut( USES_REGS1 ) {
struct result_set *res_set=NULL;
res_set = AddressOfTerm(CBACK_CUT_ARG(1));
sqlite3 *db = res_set->db;
CALL_SQLITE( finalize( res_set->stmt ) );

View File

@ -40,7 +40,8 @@ typedef enum myddas_api {
API_MYSQL = 0,
API_ODBC = 1,
API_SQLITE3 = 2,
API_POSTGRES } MYDDAS_API;
API_POSTGRES =3
} MYDDAS_API;
struct myddas_list_connection {
void *connection;

View File

@ -884,6 +884,20 @@ db_open(mysql,Connection,Host/Db,User,Password) :-
db_open(mysql,Connection,Host/Db/0/_,User,Password). % 0 is default port and Var to be NULL, the default socket
#endif
#ifdef MYDDAS_POSTGRES
db_open(postgres,Connection,Host/Db/Port/Socket,User,Password) :- !,
'$error_checks'(db_open(postgres,Connection,Host/Db/Port/Socket,User,Password)),
c_db_my_connect(Host,User,Password,Db,Port,Socket,Con),
set_value(Connection,Con).
db_open(postgres,Connection,Host/Db/Port,User,Password) :-
integer(Port),!,
db_open(postgres,Connection,Host/Db/Port/_,User,Password). % Var to be NULL, the default socket
db_open(postgres,Connection,Host/Db/Socket,User,Password) :- !,
db_open(postgres,Connection,Host/Db/0/Socket,User,Password). % 0 is default port
db_open(postgres,Connection,Host/Db,User,Password) :-
db_open(postgres,Connection,Host/Db/0/_,User,Password). % 0 is default port and Var to be NULL, the default socket
#endif
#ifdef MYDDAS_ODBC
db_open(odbc,Connection,ODBCEntry,User,Password) :-
'$error_checks'(db_open(odbc,Connection,ODBCEntry,User,Password)),
@ -916,6 +930,10 @@ db_close(Connection) :-
c_db_connection_type(Con,ConType),
( ConType == mysql ->
c_db_my_disconnect(Con)
;ConType == postgres ->
c_postgres_disconnect(Con)
;ConType == sqlite3 ->
c_sqlite3_disconnect(Con)
;
c_db_odbc_disconnect(Con)
),
@ -1016,6 +1034,12 @@ db_sql(Connection,SQL,LA):-
( ConType == mysql ->
db_my_result_set(Mode),
c_db_my_query(SQL,ResultSet,Con,Mode,Arity)
;ConType == postgres ->
postgres_result_set(Mode),
c_postgres_query(SQL,ResultSet,Con,Mode,Arity)
;ConType == sqlite3 ->
sqlite3_result_set(Mode),
c_sqlite3_query(SQL,ResultSet,Con,Mode,Arity)
;
c_db_odbc_number_of_fields_in_query(SQL,Con,Arity)
),
@ -1119,6 +1143,12 @@ db_assert(Connection,PredName):-
( ConType == mysql ->
db_my_result_set(Mode),
c_db_my_query(SQL,_,Con,Mode,_)
;ConType == postgres ->
postgres_result_set(Mode),
c_postgres_query(SQL,_,Con,Mode,_)
;ConType == sqlite3 ->
sqlite3_result_set(Mode),
c_sqlite3_query(SQL,_,Con,Mode,_)
;
c_db_odbc_query(SQL,_,_,_,Con)
).
@ -1142,6 +1172,12 @@ db_create_table(Connection,TableName,FieldsInf):-
( ConType == mysql ->
db_my_result_set(Mode),
c_db_my_query(FinalSQL,_,Con,Mode,_)
;ConType == posgres ->
postgres_result_set(Mode),
c_postsgres_query(FinalSQL,_,Con,Mode,_)
;ConType == sqlite3 ->
sqlite3_result_set(Mode),
c_sqlite3_query(FinalSQL,_,Con,Mode,_)
;
c_db_odbc_query(FinalSQL,_,_,_,Con)
).
@ -1248,6 +1284,10 @@ db_number_of_fields(Connection,RelationName,Arity) :-
c_db_connection_type(Con,ConType),
( ConType == mysql ->
c_db_my_number_of_fields(RelationName,Con,Arity)
;ConType == postgres ->
c_postgres_number_of_fields(RelationName,Con,Arity)
;ConType == sqlite3 ->
c_sqlite3_number_of_fields(RelationName,Con,Arity)
;
c_db_odbc_number_of_fields(RelationName,Con,Arity)
).

View File

@ -240,9 +240,12 @@ table_arity( Con, ConType, RelationName, Arity ) :-
( ConType == mysql ->
c_db_my_number_of_fields(RelationName,Con,Arity)
;
ConType == odbc ->
c_db_odbc_number_of_fields(RelationName,Con,Arity)
ConType == postgres ->
c_postgres_number_of_fields(RelationName,Con,Arity)
;
ConType == odbc ->
c_db_odbc_number_of_fields(RelationName,Con,Arity)
;
c_sqlite3_number_of_fields(RelationName,Con,Arity))
.
@ -250,6 +253,9 @@ table_arity( Con, ConType, RelationName, Arity ) :-
table_attributes( mysql, Con, RelationName, TypesList ) :-
c_db_my_get_attributes_types(RelationName,Con,TypesList).
table_attributes( postgres, Con, RelationName, TypesList ) :-
c_postgres_get_attributes_types(RelationName,Con,TypesList).
table_attributes( odbc, Con, RelationName, TypesList ) :-
c_db_odbc_get_attributes_types(RelationName,Con,TypesList).
@ -268,6 +274,16 @@ table_access_predicate( mysql, Con, Arity, P, LA, M,
!,
c_db_my_row(ResultSet,Arity,LA) ))).
table_access_predicate( postgres, Con, Arity, P, LA, M,
( P :- M:('$copy_term_nv'(P,[],G,_),
translate(G,G,Code),
queries_atom(Code,FinalSQL),
db_my_result_set(Mode),
'$write_or_not'(FinalSQL),
c_postgres_query(FinalSQL,ResultSet,Con,Mode,_),
!,
c_postgsres_row(ResultSet,Arity,LA) ))).
table_access_predicate( sqlite3, Con, Arity, P, LA, M,
( P :- M:('$copy_term_nv'(P,[],G,_),
translate(G,G,Code),
@ -299,6 +315,15 @@ table_insert( mysql, Con, RelationName, TypesList, Predicate, LA,
c_db_my_query(SQL,_,Con,Mode,_)))
).
table_insert( postgres, Con, RelationName, TypesList, Predicate, LA,
( Predicate :- myddas_assert_predicates:
( '$get_values_for_insert'(TypesList,LA,ValuesList),
'$make_atom'(['INSERT INTO `',RelationName,'` VALUES ('|ValuesList],SQL),
postgres_result_set(Mode),
'$write_or_not'(SQL),
c_postgres_query(SQL,_,Con,Mode,_)))
).
table_insert( sqlite3, Con, RelationName, TypesList, Predicate, LA,
( Predicate :- myddas_assert_predicates:
( '$get_values_for_insert'(TypesList,LA,ValuesList),
@ -329,6 +354,18 @@ table_view( mysql, Con, CopyView, CopyGoal, Arity, LA, M,
!,
c_db_my_row(ResultSet,Arity,LA) ))).
table_view( postgres, Con, CopyView, CopyGoal, Arity, LA, M,
( CopyView :-
M:( '$copy_term_nv'(CopyView,[],ProjT,Dic),
'$copy_term_nv'(CopyGoal,Dic,NG,_),
translate(ProjT,NG,Code),
queries_atom(Code,FinalSQL),
db_my_result_set(Mode),
'$write_or_not'(FinalSQL),
c_postgres_query(FinalSQL,ResultSet,Con,Mode,_),
!,
c_postgres_row(ResultSet,Arity,LA) ))).
table_view( odbc, Con, CopyView, CopyGoal, Arity, LA, M,
( CopyView :-
M:( '$copy_term_nv'(CopyView,[],ProjT,Dic),

View File

@ -0,0 +1,248 @@
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: myddas_postgres.yap *
* Last rev: *
* mods: *
* comments: Postgres Predicates *
* *
*************************************************************************/
#ifdef MYDDAS_POSTGRES
:- module(myddas_postgres,[
postgres_result_set/1,
postgres_datalog_describe/1,
postgres_datalog_describe/2,
postgres_describe/3,
postgres_describe/2,
postgres_datalog_show_tables/1,
postgres_datalog_show_tables/0,
postgres_show_tables/2,
postgres_show_tables/1,
postgres_show_database/2,
postgres_show_databases/2,
postgres_show_databases/1,
postgres_change_database/2,
postgres_call_procedure/4,
postgres_call_procedure/3,
postgres_sql_mode/1,
postgres_sql_mode/2,
postgres_sql_mode/1,
postgres_sql_mode/2
]).
:- use_module(myddas,[
postgres_sql/3
]).
:- use_module(myddas_errors,[
'$error_checks'/1
]).
:- use_module(myddas_util_predicates,[
'$get_value'/2,
'$make_atom'/2,
'$make_atom_args'/2,
'$make_a_list'/2,
'$write_or_not'/1
]).
%--------------------------------------------------------
% Public Predicates
%--------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_result_set/1
%
%
postgres_result_set(X):-
var(X),!,
get_value(postgres_result_set,X).
postgres_result_set(use_result):-
set_value(postgres_result_set,use_result).
postgres_result_set(store_result):-
set_value(postgres_result_set,store_result).
%default value
:- postgres_result_set(store_result).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_describe/2
%
%
postgres_datalog_describe(Relation):-
postgres_datalog_describe(myddas,Relation).
postgres_datalog_describe(Connection,Relation) :-
'$error_checks'(postgres_datalog_describe(Relation,Connection)),
'$get_value'(Connection,Conn),
'$make_atom'(['DESCRIBE ',Relation],SQL),
postgres_result_set(Mode),
c_postgres_query(SQL,ResultSet,Conn,Mode,_),
c_postgres_table_write(ResultSet).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_describe/3
% postgres_describe/2
% gives the results of the DESCRIBE statement
% by backtracking
postgres_describe(Relation,TableInfo) :-
postgres_describe(myddas,Relation,TableInfo).
postgres_describe(Connection,Relation,tableinfo(A1,A2,A3,A4,A5,A6)) :-
'$error_checks'(postgres_describe(Relation,Connection,_)),
'$get_value'(Connection,Conn),
'$make_atom'(['DESCRIBE ',Relation],SQL),
postgres_result_set(Mode),
'$write_or_not'(SQL),
c_postgres_query(SQL,ResultSet,Conn,Mode,_),
!,c_postgres_row(ResultSet,6,[A1,A2,A3,A4,A5,A6]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_datalog_show_tables/1
%
%
postgres_datalog_show_tables:-
postgres_datalog_show_tables(myddas).
postgres_datalog_show_tables(Connection) :-
'$error_checks'(postgres_show_tables(Connection)),
'$get_value'(Connection,Conn),
postgres_result_set(Mode),
'$write_or_not'('SHOW TABLES'),
c_postgres_query('SHOW TABLES',ResultSet,Conn,Mode,_),
c_postgres_table_write(ResultSet).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_show_tables/2
% postgres_show_tables/1
% gives the results of the SHOW TABLES statement
% by backtracking
postgres_show_tables(Table) :-
postgres_show_tables(myddas,Table).
postgres_show_tables(Connection,table(Table)) :-
'$error_checks'(postgres_show_tables(Connection)),
'$get_value'(Connection,Conn),
postgres_result_set(Mode),
'$write_or_not'('SHOW TABLES'),
c_postgres_query('SHOW TABLES',ResultSet,Conn,Mode,_),
!,c_postgres_row(ResultSet,1,[Table]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_show_database/2
%
%
postgres_show_database(Connection,Database) :-
'$error_checks'(postgres_show_database(Connection,Database)),
'$get_value'(Connection,Con),
c_postgres_get_database(Con,Database).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_show_databases/2
%
%
postgres_show_databases(Connection,database(Databases)) :-
%'$error_checks'(postgres_show_databases(Connection,Database)),
'$get_value'(Connection,Conn),
postgres_result_set(Mode),
'$write_or_not'('SHOW DATABASES'),
c_postgres_query('SHOW DATABASES',ResultSet,Conn,Mode,_),
!,c_postgres_row(ResultSet,1,[Databases]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_show_databases/1
% TODO Error Checks
%
postgres_show_databases(Connection) :-
'$error_checks'(postgres_show_databases(Connection)),
'$get_value'(Connection,Conn),
postgres_result_set(Mode),
'$write_or_not'('SHOW DATABASES'),
c_postgres_query('SHOW DATABASES',ResultSet,Conn,Mode,_),
c_postgres_table_write(ResultSet).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_change_database/2
%
%
postgres_change_database(Connection,Database) :-
'$error_checks'(postgres_change_database(Connection,Database)),
'$get_value'(Connection,Con),
'$make_atom'(['USE ',Database],SQL),
'$write_or_not'(SQL),
c_postgres_change_database(Con,Database).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_call_procedure/4
% postgres_call_procedure/3
% postgres_call_procedure(+,+,+,?)
% Only support in Postgres 5.0 an above
% Called procedure must return results via Postgres result set
postgres_call_procedure(Procedure,Args,Result) :-
postgres_call_procedure(myddas,Procedure,Args,Result).
postgres_call_procedure(Connection,Procedure,Args,LA) :-
'$error_checks'(postgres_call_procedure(Connection,Procedure,Args,LA)),
'$make_atom_args'(Args,ArgsSQL),
'$make_atom'(['CALL ',Procedure,'(',ArgsSQL,')'],SQL),
postgres_sql(Connection,SQL,LA).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% postgres_sql_mode/1
% postgres_sql_mode/2
% Possible values : traditional,ansi,strict_trans_tables or '' (empty)
postgres_sql_mode(SQLMode):-
postgres_sql_mode(SQLMode).
postgres_sql_mode(Connection,SQLMode):-
postgres_sql_mode(Connection,SQLMode).
postgres_sql_mode(SQLMode):-
postgres_sql_mode(myddas,SQLMode).
postgres_sql_mode(Connection,SQLMode):-
var(SQLMode),!,
'$error_checks'(postgres_sql_mode(Connection,SQLMode)),
get_value(Connection,Con),
c_postgres_connection_type(Con,postgres), %must be a postgres connection
postgres_sql(Connection,'SELECT @@session.sql_mode',[SQLMode]).
postgres_sql_mode(Connection,SQLMode):-
'$error_checks'(postgres_sql_mode(Connection,SQLMode)),
get_value(Connection,Con),
c_postgres_connection_type(Con,postgres), %must be a postgres connection
'$make_atom'(['SET SESSION sql_mode=`',SQLMode,'`'],FinalSQL),
'$write_or_not'(FinalSQL),
postgres_result_set(Mode),
c_postgres_query(FinalSQL,_,Con,Mode,_).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif /* MYDDAS_POSTGRES*/