This is a fairly incomplete work.. but I have done things dramatically
differently than sybperl would. Given the nature of the language I
find it is easier to simply get ALL results & then muck with the rows
later as parts of the data. This is a subset of the functionality of a
Modula-3 interface to Sybase that I wrote.. I could send you that if
you are interested in a more complete picture.
#include <stdio.h>
#include <sybfront.h>
#include <sybdb.h>
#include <Py/allobjects.h>
#include <Py/modsupport.h>
static object *SybaseError; /* exception sybase.error */
typedef struct {
OB_HEAD
LOGINREC *login; /* login record */
DBPROCESS *dbproc; /* login record */
} sybdbobject;
extern typeobject SybDbtype; /* Forward */
static sybdbobject *
newsybdbobject(char *user, char *passwd, char *server)
{
sybdbobject *s;
s = NEWOBJ(sybdbobject, &SybDbtype);
if (s != NULL) {
s->login = dblogin();
if (user) {
(void)DBSETLUSER(s->login, user);
}
if (passwd) {
(void)DBSETLPWD(s->login, passwd);
}
if(!(s->dbproc = dbopen(s->login, server))) {
dbloginfree(s->login);
DEL(s);
return (NULL);
}
}
return s;
}
/* OBJECT FUNCTIONS: sybdb */
/* Common code for returning pending results */
static object
*getresults (DBPROCESS *dbp)
{
object *results;
object *list;
object *tuple;
object *o;
int retcode;
int cols;
int *fmt;
int i;
results = newlistobject(0);
while ((retcode = dbresults(dbp)) != NO_MORE_RESULTS) {
if (retcode == SUCCEED && DBROWS(dbp) == SUCCEED) {
list = newlistobject(0);
cols = dbnumcols(dbp);
fmt = (int *)malloc(sizeof(int) * cols);
for (i = 1; i <= cols; i++) {
switch(dbcoltype(dbp, i)) {
case SYBCHAR:
fmt[i-1] = SYBCHAR;
break;
case SYBINT1:
fmt[i-1] = SYBINT1;
break;
case SYBINT2:
fmt[i-1] = SYBINT2;
break;
case SYBINT4:
fmt[i-1] = SYBINT4;
break;
case SYBFLT8:
fmt[i-1] = SYBFLT8;
break;
}
}
while (dbnextrow(dbp) != NO_MORE_ROWS) {
tuple = newtupleobject(cols);
for (i = 1; i <= cols; i++) {
switch(fmt[i-1]) {
case SYBCHAR:
o = newsizedstringobject((char *)dbdata(dbp, i), dbdatlen(dbp, i));
settupleitem(tuple, i-1, o);
break;
case SYBINT1:
o = newintobject(*((char *)dbdata(dbp, i)));
settupleitem(tuple, i-1, o);
break;
case SYBINT2:
o = newintobject(*((short *)dbdata(dbp, i)));
settupleitem(tuple, i-1, o);
break;
case SYBINT4:
o = newintobject(*((int *)dbdata(dbp, i)));
settupleitem(tuple, i-1, o);
break;
case SYBFLT8:
o = newfloatobject(*((double *)dbdata(dbp, i)));
settupleitem(tuple, i-1, o);
break;
}
}
addlistitem(list,tuple);
}
free(fmt);
addlistitem(results,list);
}
}
return (results);
}
static object
*sybdb_sql (self, args)
object *self;
object *args;
{
char *sql;
DBPROCESS *dbp;
dbp = ((sybdbobject *)self)->dbproc;
err_clear ();
if (!getargs (args, "s", &sql)) {
return NULL;
}
dbcancel(dbp);
dbcmd(dbp, sql);
dbsqlexec(dbp);
return getresults(dbp);
}
static object
*sybdb_sp (self, args)
object *self;
object *args;
{
char *sp;
DBPROCESS *dbp;
object *spargs;
object *sparg;
object *results;
object *r;
int spargcnt;
int i;
int retstatus;
dbp = ((sybdbobject *)self)->dbproc;
err_clear ();
if (!getargs (args, "(sO)", &sp, &spargs)) {
return NULL;
}
dbcancel(dbp);
dbrpcinit(dbp, sp, 0);
if (is_tupleobject(spargs)) {
spargcnt=gettuplesize(spargs);
for (i=0; i < spargcnt; i++) {
sparg = gettupleitem(spargs,i);
if (is_intobject(sparg)) {
int i;
i = getintvalue(sparg);
dbrpcparam(dbp, NULL, 0, SYBINT4, -1, -1, &i);
} else if (is_floatobject(sparg)) {
double i;
i = getfloatvalue(sparg);
dbrpcparam(dbp, NULL, 0, SYBFLT8, -1, -1, &i);
} else if (is_stringobject(sparg)) {
dbrpcparam(dbp, NULL, 0, SYBCHAR, -1, getstringsize(sparg), getstringvalue(sparg));
} else {
err_setstr (SybaseError, "Could not handle paramaters to procedure.");
return NULL;
}
}
} else if (spargs != None) {
err_setstr (SybaseError, "Could not handle paramaters to procedure.");
return NULL;
}
dbrpcsend(dbp);
dbsqlok(dbp);
results = getresults(dbp);
retstatus = dbretstatus(dbp);
r = mkvalue("(iO)", retstatus, results);
DECREF(results);
return (r);
}
static struct methodlist sybdb_methods[] = {
{"sql", sybdb_sql},
{"sp", sybdb_sp},
{NULL, NULL} /* sentinel */
};
static void
sybdb_dealloc(s)
sybdbobject *s;
{
dbloginfree(s->login);
dbclose(s->dbproc);
DEL(s);
}
static object *
sybdb_getattr(s, name)
sybdbobject *s;
char *name;
{
return findmethod(sybdb_methods, (object *) s, name);
}
typeobject SybDbtype = {
OB_HEAD_INIT(&Typetype)
0,
"sybdb",
sizeof(sybdbobject),
0,
sybdb_dealloc, /*tp_dealloc*/
0, /*tp_print*/
sybdb_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: sybase */
static object
*sybase_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 *) newsybdbobject(user, passwd, server);
if (!db) {
/* XXX Should be setting some errstr stuff here based on sybase errors */
err_setstr (SybaseError, "Could not open connection to server.");
return NULL;
}
return db;
}
/* List of module functions */
static struct methodlist sybase_methods[]=
{
{"new", sybase_new},
{NULL, NULL} /* sentinel */
};
/* Module initialisation */
void initsybase ()
{
object *m, *d;
/* Create the module and add the functions */
m = initmodule ("sybase", sybase_methods);
/* Add some symbolic constants to the module */
d = getmoduledict (m);
SybaseError = newstringobject ("sybase.error");
if (SybaseError == NULL || dictinsert (d, "error", SybaseError) != 0) {
fatal ("can't define sybase.error");
}
/* Check for errors */
if (err_occurred ()){
fatal ("can't initialize module sybase");
}
}