This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/packages/myddas/myddas_odbc.c
2014-10-02 23:24:04 +01:00

875 lines
27 KiB
C

/*************************************************************************
* *
* 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_odbc.c *
* Last rev: 22/03/05 *
* mods: *
* comments: Predicates for comunicating with ODBC drivers *
* *
*************************************************************************/
#if defined MYDDAS_ODBC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Yap.h"
#include "Yatom.h"
#include "myddas.h"
#include "cut_c.h"
#include <sql.h>
#include <sqlucode.h>
static Int null_id = 0;
static Int c_db_odbc_connect( USES_REGS1 );
static Int c_db_odbc_disconnect( USES_REGS1 );
static Int c_db_odbc_number_of_fields( USES_REGS1 );
static Int c_db_odbc_get_attributes_types( USES_REGS1 );
static Int c_db_odbc_query( USES_REGS1 );
static Int c_db_odbc_row( USES_REGS1 );
static Int c_db_odbc_row_cut( USES_REGS1 );
static Int c_db_odbc_get_fields_properties( USES_REGS1 );
static Int c_db_odbc_number_of_fields_in_query( USES_REGS1 );
static int
odbc_error(SQLSMALLINT type, SQLHANDLE hdbc, char *msg, char *print)
{
SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
SQLINTEGER NativeError;
SQLSMALLINT i=1, MsgLen;
SQLGetDiagRec(type, hdbc,i,SqlState,&NativeError,Msg, sizeof(Msg), &MsgLen);
fprintf(stderr,"%% error in SQLConnect: %s got error code %s\n%% SQL Message: %s\n", print, SqlState, Msg);
return FALSE;
}
static int
SQLALLOCHANDLE(SQLSMALLINT HandleType, SQLHANDLE hdbc, SQLHANDLE *outHandle, char *print)
{
SQLRETURN retcode;
retcode = SQLAllocHandle(HandleType,hdbc,outHandle);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
{
return odbc_error(HandleType, hdbc, "SQLAllocHandle(ENV)", print);
}
return TRUE;
}
static int
SQLSETENVATTR(SQLHENV henv, SQLINTEGER att, SQLPOINTER p, SQLINTEGER len, char *print)
{
SQLRETURN retcode;
retcode = SQLSetEnvAttr(henv,att,p,len);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
{
return odbc_error(SQL_HANDLE_ENV, henv, "SQLSetEnvAttr", print);
}
return TRUE;
}
static int SQLCONNECT(SQLHDBC hdbc,
SQLCHAR *driver,
SQLCHAR *user,
SQLCHAR *password,
char *print)
{
SQLRETURN retcode;
retcode = SQLConnect(hdbc,driver,SQL_NTS,user,SQL_NTS,password,SQL_NTS);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_DBC, hdbc, "SQLConnect", print);
return TRUE;
}
static int SQLEXECDIRECT(SQLHSTMT StatementHandle,
SQLCHAR * StatementText,
char *print)
{
SQLRETURN retcode;
retcode = SQLExecDirect(StatementHandle,StatementText,SQL_NTS);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, StatementHandle, "SQLExecDirect", print);
return TRUE;
}
static int SQLDESCRIBECOL(SQLHSTMT sth,
SQLSMALLINT colno,
SQLCHAR * colname,
SQLSMALLINT bflength,
SQLSMALLINT * nmlengthp,
SQLSMALLINT * dtptr,
SQLULEN * colszptr,
SQLSMALLINT * ddptr,
SQLSMALLINT * nullableptr,
char * print)
{
SQLRETURN retcode;
retcode = SQLDescribeCol(sth, colno, colname, bflength,
nmlengthp, dtptr, colszptr, ddptr,
nullableptr);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, sth, "SQLDescribeCol", print);
return TRUE;
}
static int SQLSETCONNECTATTR(SQLHDBC hdbc,
SQLINTEGER attr,
SQLPOINTER vptr,
SQLINTEGER slen,
char * print)
{
SQLRETURN retcode;
retcode = SQLSetConnectAttr(hdbc, attr, vptr, slen);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, hdbc, "SQLSetConnectAttr", print);
return TRUE;
}
static int SQLBINDCOL(SQLHSTMT sthandle,
SQLUSMALLINT colno,
SQLSMALLINT tt,
SQLPOINTER tvptr,
SQLLEN blen,
SQLLEN * strl,
char * print)
{
SQLRETURN retcode;
retcode = SQLBindCol(sthandle,colno,tt,tvptr,blen,strl);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, sthandle, "SQLBindCol", print);
return TRUE;
}
static int SQLNUMRESULTCOLS(SQLHSTMT sthandle,
SQLSMALLINT * ncols,
char * print)
{
SQLRETURN retcode;
retcode = SQLNumResultCols(sthandle,ncols);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, sthandle, "SQLNumResultCols", print);
return TRUE;
}
static int SQLCLOSECURSOR(SQLHSTMT sthandle,
char * print)
{
SQLRETURN retcode;
retcode = SQLCloseCursor(sthandle);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, sthandle, "SQLCloseCursor", print);
return TRUE;
}
#define SQLFETCH(A,print) \
{ \
SQLRETURN retcode; \
retcode = SQLFetch(A); \
if (retcode == SQL_NO_DATA) \
break; \
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) \
{ \
printf("Error in SQLFETCH: %s\n",print); \
return FALSE; \
} \
}
static int SQLGETDATA(SQLHSTMT sthandle,
SQLUSMALLINT Col_or_Param_Num,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr,
char * print)
{
SQLRETURN retcode;
retcode = SQLGetData(sthandle, Col_or_Param_Num,
TargetType, TargetValuePtr,
BufferLength, StrLen_or_IndPtr);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, sthandle, "SQLGetData", print);
return TRUE;
}
static int SQLDISCONNECT(SQLHSTMT sthandle,
char * print)
{
SQLRETURN retcode;
retcode = SQLDisconnect(sthandle);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_DBC, sthandle, "SQLDisconnect", print);
return TRUE;
}
static int SQLFREEHANDLE(SQLSMALLINT HandleType,
SQLHANDLE Handle,
char * print)
{
SQLRETURN retcode;
retcode = SQLFreeHandle(HandleType, Handle);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(HandleType, Handle, "SQLDisconnect", print);
return TRUE;
}
static int SQLPRIMARYKEYS(SQLHSTMT StatementHandle,
SQLCHAR * CatalogName,
SQLSMALLINT NameLength1,
SQLCHAR * SchemaName,
SQLSMALLINT NameLength2,
SQLCHAR * TableName,
SQLSMALLINT NameLength3,
char * print)
{
SQLRETURN retcode;
retcode = SQLPrimaryKeys(StatementHandle,
CatalogName, NameLength1,
SchemaName, NameLength2,
TableName, NameLength3
);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, StatementHandle, "SQLPrimaryKeys", print);
return TRUE;
}
/********************************************
NOT IN USE
static int SQLGETTYPEINFO(SQLHSTMT StatementHandle,
SQLSMALLINT DataType,
char * print)
{
SQLRETURN retcode;
retcode = SQLGetTypeInfo(StatementHandle, DataType);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, StatementHandle, "SQLGetTypeInfo", print);
return TRUE;
}
********************************************/
static int SQLCOLATTRIBUTE( SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLUSMALLINT FieldIdentifier,
SQLPOINTER CharacterAttributePtr,
SQLSMALLINT BufferLength,
SQLSMALLINT * StringLengthPtr,
SQLLEN * NumericAttributePtr,
char * print)
{
SQLRETURN retcode;
retcode = SQLColAttribute(StatementHandle,
ColumnNumber,
FieldIdentifier,
CharacterAttributePtr,
BufferLength,
StringLengthPtr,
NumericAttributePtr
);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return odbc_error(SQL_HANDLE_STMT, StatementHandle, "SQLColAttribute", print);
return TRUE;
}
/* Verificar tipo de dados*/
#define IS_SQL_INT(FIELD) FIELD == SQL_DECIMAL || \
FIELD == SQL_NUMERIC || \
FIELD == SQL_SMALLINT || \
FIELD == SQL_INTEGER || \
FIELD == SQL_TINYINT || \
FIELD == SQL_BIGINT
#define IS_SQL_FLOAT(FIELD) FIELD == SQL_FLOAT || \
FIELD == SQL_DOUBLE || \
FIELD == SQL_REAL
static Int
c_db_odbc_connect( USES_REGS1 ) {
Term arg_driver = Deref(ARG1);
Term arg_user = Deref(ARG2);
Term arg_passwd = Deref(ARG3);
Term arg_conn = Deref(ARG4);
MYDDAS_UTIL_CONNECTION new = NULL;
char *driver = AtomName(AtomOfTerm(arg_driver));
char *user = AtomName(AtomOfTerm(arg_user));
char *passwd = AtomName(AtomOfTerm(arg_passwd));
SQLHENV henv;
SQLHDBC hdbc;
/*Allocate environment handle */
if (!SQLALLOCHANDLE(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv, "connect"))
return FALSE;
/* Set the ODBC version environment attribute */
if (!SQLSETENVATTR(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0, "connect"))
return FALSE;
/* Allocate connection handle */
if (!SQLALLOCHANDLE(SQL_HANDLE_DBC, henv, &hdbc, "connect"))
return FALSE;
/* Set login timeout to 6 seconds. */
if (!SQLSETCONNECTATTR(hdbc, SQL_LOGIN_TIMEOUT,(SQLPOINTER) 6, 0, "connect"))
return FALSE;
/* Connect to data source */
if (!SQLCONNECT(hdbc,
(SQLCHAR*) driver,
(SQLCHAR*) user,
(SQLCHAR*) passwd, "connect"))
return FALSE;
if (!Yap_unify(arg_conn, MkIntegerTerm((Int)(hdbc))))
return FALSE;
else
{
/* Criar um novo no na lista de ligacoes*/
//new = add_connection(&TOP,hdbc,henv);
new = myddas_util_add_connection(hdbc,henv);
if (new == NULL){
fprintf(stderr,"Error: could not allocate list memory\n");
return FALSE;
}
return TRUE;
}
}
/* db_query: SQLQuery x ResultSet x Arity x BindList x Connection */
static Int
c_db_odbc_query( USES_REGS1 ) {
Term arg_sql_query = Deref(ARG1);
Term arg_result_set = Deref(ARG2);
Term arg_arity = Deref(ARG3);
Term arg_bind_list = Deref(ARG4);
Term arg_conn = Deref(ARG5);
SQLCHAR *sql = (SQLCHAR *)AtomName(AtomOfTerm(arg_sql_query));
SQLHDBC hdbc =(SQLHDBC) (IntegerOfTerm(arg_conn));
SQLHSTMT hstmt;
SQLSMALLINT type;
Int arity;
Int i;
/*Allocate an handle for the query*/
if (!SQLALLOCHANDLE(SQL_HANDLE_STMT, hdbc, &hstmt, "db_query"))
return FALSE;
/* Executes the query*/
if (!SQLEXECDIRECT(hstmt, sql, "db_query"))
return FALSE;
if (IsNonVarTerm(arg_arity)){
arity = IntegerOfTerm(arg_arity);
char *bind_space=NULL;
//const Int functor_arity=3;
const Short functor_arity=3;
Functor functor = Yap_MkFunctor(Yap_LookupAtom("bind"),functor_arity);
Term properties[functor_arity];
Term head,list=arg_bind_list;
SQLULEN ColumnSizePtr;
SQLLEN *data_info=NULL;
for (i=1;i<=arity;i++)
{
head = HeadOfTerm(list);
list = TailOfTerm(list);
if (!SQLDESCRIBECOL(hstmt,i,NULL,0,NULL,&type,&ColumnSizePtr,NULL,NULL,"db_query"))
return FALSE;
/* +1 because of '\0' */
bind_space = malloc(sizeof(char)*(ColumnSizePtr+1));
data_info = malloc(sizeof(SQLINTEGER));
if (!SQLBINDCOL(hstmt,i,SQL_C_CHAR,bind_space,(ColumnSizePtr+1),data_info,"db_query")) {
return FALSE;
}
properties[0] = MkIntegerTerm((Int)bind_space);
properties[2] = MkIntegerTerm((Int)data_info);
if (IS_SQL_INT(type))
properties[1]=MkAtomTerm(Yap_LookupAtom("integer"));
else if (IS_SQL_FLOAT(type))
properties[1]=MkAtomTerm(Yap_LookupAtom("real"));
else
properties[1]=MkAtomTerm(Yap_LookupAtom("string"));
Yap_unify(head,Yap_MkApplTerm(functor,functor_arity,properties));
continue;
}
}
if (!Yap_unify(arg_result_set, MkIntegerTerm((Int) hstmt)))
{
if (!SQLCLOSECURSOR(hstmt,"db_query"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_query"))
return FALSE;
return FALSE;
}
return TRUE;
}
static Int
c_db_odbc_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));
SQLHDBC hdbc =(SQLHDBC) (IntegerOfTerm(arg_conn));
SQLHSTMT hstmt;
char sql[256];
SQLSMALLINT number_fields;
sprintf(sql,"SELECT column_name from INFORMATION_SCHEMA.COLUMNS where table_name = \'%s\' group by column_name order by min(dtd_identifier)",relation);
if (!SQLALLOCHANDLE(SQL_HANDLE_STMT, hdbc, &hstmt, "db_number_of_fields"))
return FALSE;
if (!SQLEXECDIRECT(hstmt, (SQLCHAR *)sql, "db_number_of_fields"))
return FALSE;
/* Calcula o numero de campos*/
number_fields=0;
while(TRUE) {
SQLFETCH(hstmt,"db_number_of_fields");
number_fields++;
}
if (!SQLCLOSECURSOR(hstmt,"db_number_of_fields"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_number_of_fields"))
return FALSE;
if (!Yap_unify(arg_fields, MkIntegerTerm(number_fields)))
return FALSE;
return TRUE;
}
/* db_get_attributes_types: RelName x Connection -> TypesList */
static Int
c_db_odbc_get_attributes_types( USES_REGS1 ) {
Term arg_relation = Deref(ARG1);
Term arg_conn = Deref(ARG2);
Term arg_types_list = Deref(ARG3);
char *relation = AtomName(AtomOfTerm(arg_relation));
SQLHDBC hdbc =(SQLHDBC) (IntegerOfTerm(arg_conn));
SQLHSTMT hstmt;
char sql[256];
Term head, list;
list = arg_types_list;
sprintf(sql,"SELECT column_name,data_type FROM INFORMATION_SCHEMA.COLUMNS where table_name = \'%s\' group by column_name,data_type order by min(dtd_identifier)",relation);
if (!SQLALLOCHANDLE(SQL_HANDLE_STMT, hdbc, &hstmt, "db_get_attributes_types"))
return FALSE;
if (!SQLEXECDIRECT(hstmt, (SQLCHAR *)sql, "db_get_attributes_types"))
return FALSE;
while (TRUE)
{
SQLFETCH(hstmt, "db_get_attributes_types");
/* Tentar fazer de uma maneira que a gente consiga calcular o tamanho que o
nome do campo vai ocupar, assim podemos alocar memoria dinamicamente*/
sql[0]='\0';
if (!SQLGETDATA(hstmt, 1, SQL_C_CHAR, sql, 256, NULL, "db_get_attributes_types"))
return FALSE;
head = HeadOfTerm(list);
Yap_unify(head, MkAtomTerm(Yap_LookupAtom(sql)));
list = TailOfTerm(list);
head = HeadOfTerm(list);
list = TailOfTerm(list);
sql[0]='\0';
if (!SQLGETDATA(hstmt, 2, SQL_C_CHAR, sql, 256, NULL, "db_get_attributes_types"))
return FALSE;
if (strncmp(sql, "smallint",8) == 0 || strncmp(sql,"int",3) == 0 ||
strncmp(sql, "mediumint",9) == 0 || strncmp(sql, "tinyint",7) == 0 ||
strncmp(sql, "bigint",6) == 0 || strcmp(sql, "year") == 0)
Yap_unify(head, MkAtomTerm(Yap_LookupAtom("integer")));
else
if (strcmp(sql, "float") == 0 || strncmp(sql, "double",6) == 0
|| strcmp(sql, "real") == 0)
Yap_unify(head, MkAtomTerm(Yap_LookupAtom("real")));
else
Yap_unify(head, MkAtomTerm(Yap_LookupAtom("string")));
}
if (!SQLCLOSECURSOR(hstmt,"db_get_attributes_types"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_get_attributes_types"))
return FALSE;
return TRUE;
}
/* db_disconnect */
static Int
c_db_odbc_disconnect( USES_REGS1 ) {
Term arg_conn = Deref(ARG1);
SQLHDBC conn = (SQLHDBC) (IntegerOfTerm(arg_conn));
SQLHENV henv = myddas_util_get_odbc_enviromment(conn);
if ((myddas_util_search_connection(conn)) != NULL)
{
myddas_util_delete_connection(conn);
/* More information about this process on
msdn.microsoft.com*/
if (!SQLDISCONNECT(conn,"db_disconnect"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_DBC,conn,"db_disconnect"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_ENV,henv,"db_disconnect"))
return FALSE;
return TRUE;
}
else
return FALSE;
}
static Int
c_db_odbc_row_cut( USES_REGS1 ) {
SQLHSTMT hstmt = (SQLHSTMT) IntegerOfTerm(EXTRA_CBACK_CUT_ARG(Term,1));
if (!SQLCLOSECURSOR(hstmt,"db_row_cut"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_row_cut"))
return FALSE;
return TRUE;
}
static int
release_list_args(Term arg_list_args, Term arg_bind_list, const char *error_msg)
{
Term list = arg_list_args;
Term list_bind = arg_bind_list;
while (IsPairTerm(list_bind))
{
Term head_bind = HeadOfTerm(list_bind);
list = TailOfTerm(list);
list_bind = TailOfTerm(list_bind);
free((char *)IntegerOfTerm(ArgOfTerm(1,head_bind)));
free((SQLINTEGER *)IntegerOfTerm(ArgOfTerm(3,head_bind)));
}
return TRUE;
}
/* db_row: ResultSet x BindList x ListOfArgs -> */
static Int
c_db_odbc_row( USES_REGS1 ) {
Term arg_result_set = Deref(ARG1);
Term arg_bind_list = Deref(ARG2);
Term arg_list_args = Deref(ARG3);
SQLHSTMT hstmt = (SQLHSTMT) IntegerOfTerm(arg_result_set);
/* EXTRA_CBACK_ARG(ARIDADE,LOCAL_ONDE_COLOCAR_VALOR)*/
EXTRA_CBACK_ARG(3,1)=(CELL) MkIntegerTerm((Int)hstmt);
Term head, list, null_atom[1];
Term head_bind, list_bind;
SQLRETURN retcode = SQLFetch(hstmt);
if (retcode == SQL_NO_DATA)
{
if (!SQLCLOSECURSOR(hstmt,"db_row"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_row"))
return FALSE;
if (!release_list_args(arg_list_args, arg_bind_list, "db_row")) {
return FALSE;
}
cut_fail();
return FALSE;
}
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
{
printf("erro no SQLFETCH number of fields\n");
return FALSE;
}
char *bind_value=NULL;
Term type;
list = arg_list_args;
list_bind = arg_bind_list;
SQLINTEGER *data_info=NULL;
while (IsPairTerm(list_bind))
{
head = HeadOfTerm(list);
list = TailOfTerm(list);
head_bind = HeadOfTerm(list_bind);
list_bind = TailOfTerm(list_bind);
bind_value = (char *)IntegerOfTerm(ArgOfTerm(1,head_bind));
type = ArgOfTerm(2,head_bind);
data_info = (SQLINTEGER *)IntegerOfTerm(ArgOfTerm(3,head_bind));
if ((*data_info) == SQL_NULL_DATA){
null_atom[0] = MkIntegerTerm(null_id++);
if (!Yap_unify(head, Yap_MkApplTerm(Yap_MkFunctor(Yap_LookupAtom("null"),1),1,null_atom)))
continue;
}
else
{
if (!strcmp(AtomName(AtomOfTerm(type)),"integer"))
{
if (!Yap_unify(head, MkIntegerTerm(atol(bind_value))))
continue;
}
else if (!strcmp(AtomName(AtomOfTerm(type)),"real"))
{
if (!Yap_unify(head, MkFloatTerm(atof(bind_value))))
continue;
}
else if (!strcmp(AtomName(AtomOfTerm(type)),"string"))
{
if (!Yap_unify(head, MkAtomTerm(Yap_LookupAtom(bind_value))))
continue;
}
}
}
return TRUE;
}
/* Mudar esta funcao de forma a nao fazer a consulta, pois
no predicate db_sql_selet vai fazer duas vezes a mesma consutla*/
static Int
c_db_odbc_number_of_fields_in_query( USES_REGS1 ) {
Term arg_query = Deref(ARG1);
Term arg_conn = Deref(ARG2);
Term arg_fields = Deref(ARG3);
char *sql = AtomName(AtomOfTerm(arg_query));
SQLHDBC hdbc =(SQLHDBC) (IntegerOfTerm(arg_conn));
SQLHSTMT hstmt;
SQLSMALLINT number_cols=0;
if (!SQLALLOCHANDLE(SQL_HANDLE_STMT, hdbc, &hstmt,
"db_number_of_fields_in_query"))
return FALSE;
if (!SQLEXECDIRECT(hstmt ,(SQLCHAR *)sql,
"db_number_of_fields_in_query"))
return FALSE;
if (!SQLNUMRESULTCOLS(hstmt,&number_cols,
"db_number_of_fields_in_query"))
return FALSE;
if (!Yap_unify(arg_fields, MkIntegerTerm(number_cols))){
if (!SQLCLOSECURSOR(hstmt,"db_number_of_fields_in_query"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_number_of_fields_in_query"))
return FALSE;
return FALSE;
}
if (!SQLCLOSECURSOR(hstmt,"db_number_of_fields_in_query"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt, "db_number_of_fields_in_query"))
return FALSE;
return TRUE;
}
static Int
c_db_odbc_get_fields_properties( USES_REGS1 ) {
Term nome_relacao = Deref(ARG1);
Term arg_conn = Deref(ARG2);
Term fields_properties_list = Deref(ARG3);
Term head, list;
SQLCHAR *relacao = (SQLCHAR *)AtomName(AtomOfTerm(nome_relacao));
char sql[256];
char name[200];
Int i;
SQLSMALLINT num_fields=0;
SQLSMALLINT NullablePtr=0;
SQLLEN AutoIncrementPointer=0;
SQLHSTMT hstmt,hstmt2;
SQLHDBC hdbc =(SQLHDBC) (IntegerOfTerm(arg_conn));
/* LIMIT 0 -> We don't need the results of the query,
only the information about the fields of the relation*/
sprintf (sql,"SELECT * FROM `%s` LIMIT 0",relacao);
/*Allocate an handle for the query*/
if (!SQLALLOCHANDLE(SQL_HANDLE_STMT, hdbc, &hstmt, "db_get_fields_properties"))
return FALSE;
/* Executes the query*/
if (!SQLEXECDIRECT(hstmt ,(SQLCHAR *)sql, "db_get_fields_properties"))
return FALSE;
Functor functor = Yap_MkFunctor(Yap_LookupAtom("property"),4);
Term properties[4];
if (!SQLNUMRESULTCOLS(hstmt,&num_fields,
"db_get_fields_properties"))
return FALSE;
list = fields_properties_list;
SQLSMALLINT bind_prim_key;
// rows in odbc start at 1 :)
Short *null=(Short *)malloc(sizeof(Short)*(1+num_fields));
if (!SQLALLOCHANDLE(SQL_HANDLE_STMT, hdbc, &hstmt2, "db_get_fields_properties"))
return FALSE;
/* Executes the query*/
if (!SQLPRIMARYKEYS(hstmt2,NULL,0,NULL,0,relacao,SQL_NTS, "db_get_fields_properties"))
return FALSE;
/* Associates bind value for the 5 column*/
if (!SQLBINDCOL(hstmt2,5,SQL_C_SSHORT,&bind_prim_key,sizeof(SQLSMALLINT),NULL,
"db_get_fields_properties"))
return FALSE;
while(1)
{
SQLFETCH(hstmt2,"db_get_fields_properties");
null[bind_prim_key]=1;
}
if (!SQLCLOSECURSOR(hstmt2,"db_get_fields_properties"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt2, "db_get_fields_properties"))
return FALSE;
for (i=1;i<=num_fields;i++)
{
head = HeadOfTerm(list);
name[0]='\0';
SQLDESCRIBECOL(hstmt,i,(SQLCHAR *)name,200,NULL,NULL,NULL,NULL,&NullablePtr,
"db_get_fields_properties");
if (!SQLCOLATTRIBUTE(hstmt,i,SQL_DESC_AUTO_UNIQUE_VALUE,NULL,0,NULL,&AutoIncrementPointer,
"db_get_fields_properties"))
return FALSE;
properties[0] = MkAtomTerm(Yap_LookupAtom(name));
if (NullablePtr & SQL_NULLABLE)
properties[1] = MkIntegerTerm(1); //Can't be NULL
else
properties[1] = MkIntegerTerm(0);
if (null[i] == 1)
properties[2] = MkIntegerTerm(1); //It''s a primary key
else
properties[2] = MkIntegerTerm(0);
if (AutoIncrementPointer & SQL_TRUE)
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;
}
}
if (!SQLCLOSECURSOR(hstmt,"db_get_fields_properties"))
return FALSE;
if (!SQLFREEHANDLE(SQL_HANDLE_STMT, hstmt2, "db_get_fields_properties"))
return FALSE;
return TRUE;
}
void Yap_InitMYDDAS_ODBCPreds(void)
{
/* db_connect: Host x User x Passwd x Database x Connection */
Yap_InitCPred("c_db_odbc_connect", 4, c_db_odbc_connect, 0);
/* db_number_of_fields: Relation x Connection x NumberOfFields */
Yap_InitCPred("c_db_odbc_number_of_fields",3, c_db_odbc_number_of_fields, 0);
/* db_number_of_fields_in_query: SQLQuery x Connection x NumberOfFields */
Yap_InitCPred("c_db_odbc_number_of_fields_in_query",3, c_db_odbc_number_of_fields_in_query, 0);
/* db_get_attributes_types: Relation x TypesList */
Yap_InitCPred("c_db_odbc_get_attributes_types", 3, c_db_odbc_get_attributes_types, 0);
/* db_query: SQLQuery x ResultSet x Connection */
Yap_InitCPred("c_db_odbc_query", 5, c_db_odbc_query, 0);
/* db_disconnect: Connection */
Yap_InitCPred("c_db_odbc_disconnect", 1,c_db_odbc_disconnect, 0);
/* db_get_fields_properties: PredName x Connnection x PropertiesList */
Yap_InitCPred("c_db_odbc_get_fields_properties",3,c_db_odbc_get_fields_properties,0);
}
void Yap_InitBackMYDDAS_ODBCPreds(void)
{
/* db_row: ResultSet x ListOfArgs */
Yap_InitCPredBackCut("c_db_odbc_row", 3, sizeof(Int),
c_db_odbc_row,
c_db_odbc_row,
c_db_odbc_row_cut, 0);
}
#endif /*MYDDAS_ODBC*/