/************************************************************************* * * * 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 && defined CUT_C #include #include #include #include "Yap.h" #include "Yatom.h" #include "myddas.h" #include "cut_c.h" #include #include static Int null_id = 0; STATIC_PROTO(Int c_db_odbc_connect,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_disconnect,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_number_of_fields,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_get_attributes_types,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_query,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_row,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_row_cut,( USES_REGS1 )); STATIC_PROTO(Int c_db_odbc_get_fields_properties,( USES_REGS1 )); STATIC_PROTO(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\'",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\'",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; //por causa de as rows em odbc começam em 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*/