/* ** Module: informixmodule.c ** ** Description: Informix library module for Python. ** ** Programmer: George Cutrell, george.cutrell@mci.com ** ** Date: 07/29/96 ** ** Compile Instructions: ** o Must have Informix CLI installed. ** o Add the following line to ../Modules/Setup: ** informix informixmodule.c -I$(INFORMIXDIR)/odbc/include -L$(INFORMIXDIR)/lib -lodbc -R$(INFORMIXDIR)/lib ** o Then, from the Modules subdirectory, perform the following: ** make -f Makefile.pre Makefile ** make clean ** make ** ** Notes: This implementation was modeled after the Sybase implementation except ** that results returned from a query are returned as a list of dictionary ** objects instead of a list of tuples. */ #include #include #include #include "allobjects.h" #include "modsupport.h" static object *InformixError; /* exception informix.error */ typedef struct { OB_HEAD HENV henv; /* Handle - Environment */ HDBC hdbc; /* Handle - Database connect */ HSTMT hstmt; /* Handle - SQL statement */ } infdbobject; extern typeobject InfDbtype; /* Forward */ #define MSG_LNG 256 /* Maximum message length */ int print_err(henv, hdbc, hstmt) HENV henv; HDBC hdbc; HSTMT hstmt; { RETCODE rc; /* general return code for API */ UCHAR szSqlState[MSG_LNG]; /* SQL state string */ SDWORD pfNativeError; /* Native error code */ UCHAR szErrorMsg[MSG_LNG]; /* Error msg text buffer pointer */ SWORD pcbErrorMsg; /* Error msg text Available bytes */ char msgtext[MSG_LNG]; /* message text work area */ rc = SQLError(henv, hdbc, hstmt, szSqlState, &pfNativeError, szErrorMsg, MSG_LNG, &pcbErrorMsg); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){ switch (rc){ case SQL_NO_DATA_FOUND: printf("SQLERROR() couldn't find text, RC=%d\n", rc); break; case SQL_ERROR: printf("SQLERROR() couldn't access text, RC=%d\n", rc); break; case SQL_INVALID_HANDLE: printf("SQLERROR() had invalid handle, RC=%d\n", rc); break; default: printf("SQLERROR() unknown return code, RC=%d\n", rc); break; } printf( msgtext ); /* display error message for user */ } else printf("{error} STATE=%s, CODE=%ld, MSG=%s\n", szSqlState, pfNativeError, szErrorMsg); return (1); /* TRUE is secondary return code */ } static infdbobject *newinfdbobject( user, passwd, server ) char *user; char *passwd; char *server; { infdbobject *s = NULL; RETCODE rc; s = NEWOBJ(infdbobject, &InfDbtype); if( s != NULL ){ rc = SQLAllocEnv(&s->henv); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(SQL_NULL_HENV, SQL_NULL_HDBC, SQL_NULL_HSTMT); return NULL; } rc = SQLAllocConnect(s->henv, &s->hdbc); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(s->henv, SQL_NULL_HDBC, SQL_NULL_HSTMT); return NULL; } if( user && passwd && server ){ rc = SQLConnect(s->hdbc, server, SQL_NTS, user, SQL_NTS, passwd, SQL_NTS); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(s->henv, s->hdbc, SQL_NULL_HSTMT); return NULL; } } else { DEL(s); return( NULL ); } } return s; } /* OBJECT FUNCTIONS: sybdb */ /* Function to return results in a dictionary instead of a list. The key will be the column name and value will be as you guessed a the column value */ typedef struct _colinfo{ UCHAR name[50]; SWORD len; SWORD type; UDWORD datalen; SWORD scale; SWORD nullable; } COLINFO; static object *getDictionaryResults (henvp, hdbcp, hstmtp) HENV *henvp; HDBC *hdbcp; HSTMT *hstmtp; { object *results; object *dictionary; object *row; object *o; int i,j; SWORD cols; RETCODE rc; COLINFO *pColInfo = NULL; SDWORD len; /* ** Determine number of columns in result set */ results = newlistobject(0); rc = SQLNumResultCols(hstmtp, &cols); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(henvp, hdbcp, hstmtp); return NULL; } if( cols == 0 ) return( results ); /* ** Get column description information */ pColInfo = (COLINFO *)malloc(sizeof(COLINFO)*cols); for(i=0; ihenv; hdbcp = ((infdbobject *)self)->hdbc; hstmtp = ((infdbobject *)self)->hstmt; rc = SQLAllocStmt(hdbcp, (HSTMT *)&hstmtp); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(henvp, hdbcp, SQL_NULL_HSTMT); return NULL; } err_clear (); if (!getargs (args, "s", &sql)) { return NULL; } rc = SQLCancel(hstmtp); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(henvp, hdbcp, SQL_NULL_HSTMT); return NULL; } rc = SQLExecDirect(hstmtp, sql, SQL_NTS); if (rc != SQL_SUCCESS & rc != SQL_SUCCESS_WITH_INFO){ print_err(henvp, hdbcp, hstmtp); return NULL; } results = getDictionaryResults(henvp, hdbcp, hstmtp); rc = SQLTransact(henvp, hdbcp, SQL_COMMIT); if (rc != SQL_SUCCESS ){ print_err(henvp, hdbcp, hstmtp); return NULL; } rc = SQLFreeStmt(hstmtp, SQL_CLOSE); if (rc != SQL_SUCCESS ){ print_err(henvp, hdbcp, hstmtp); return NULL; } rc = SQLFreeStmt(hstmtp, SQL_DROP); if (rc != SQL_SUCCESS ){ print_err(henvp, hdbcp, hstmtp); return NULL; } return( results ); } static struct methodlist infdb_methods[] = { {"sql", sybdb_sql}, {NULL, NULL} /* sentinel */ }; static void infdb_dealloc(s) infdbobject *s; { RETCODE rc; rc = SQLDisconnect(s->hdbc); /* Disconnect from the data source */ if (rc != SQL_SUCCESS ){ print_err(s->henv, s->hdbc, SQL_NULL_HSTMT); return; } rc = SQLFreeConnect(s->hdbc); /* Free the connection handle */ if (rc != SQL_SUCCESS ){ print_err(s->henv, s->hdbc, SQL_NULL_HSTMT); return; } rc = SQLFreeEnv(s->henv); /* Free the environment handle */ if (rc != SQL_SUCCESS ){ print_err(s->henv, SQL_NULL_HDBC, SQL_NULL_HSTMT); return; } DEL(s); } static object * infdb_getattr(s, name) infdbobject *s; char *name; { return findmethod(infdb_methods, (object *) s, name); } typeobject InfDbtype = { OB_HEAD_INIT(&Typetype) 0, "infdb", sizeof(infdbobject), 0, infdb_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ infdb_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ }; /* MODULE FUNCTIONS: informix */ static object *informix_new (self, args) object *self; /* Not used */ object *args; { char *user, *passwd, *server; object *db; err_clear (); if (!getargs (args, "(zzz)", &user, &passwd, &server)) { return NULL; } db = (object *) newinfdbobject(user, passwd, server); if (!db) { /* XXX Should be setting some errstr stuff here based on informix errors */ err_setstr (InformixError, "Could not open connection to server."); return NULL; } return db; } /* List of module functions */ static struct methodlist informix_methods[]= { {"new", informix_new}, {NULL, NULL} /* sentinel */ }; /* Module initialisation */ void initinformix () { object *m, *d; /* Create the module and add the functions */ m = initmodule ("informix", informix_methods); /* Add some symbolic constants to the module */ d = getmoduledict (m); InformixError = newstringobject ("informix.error"); if (InformixError == NULL || dictinsert (d, "error", InformixError) != 0) { fatal ("can't define informix.error"); } /* Check for errors */ if (err_occurred ()){ fatal ("can't initialize module informix"); } }