home *** CD-ROM | disk | FTP | other *** search
- static char SccsId[] = "@(#)sybperl.c 1.5 9/9/91";
- /************************************************************************/
- /* Copyright 1991 by Michael Peppler and ITF Management SA */
- /* */
- /* Full ownership of this software, and all rights pertaining to */
- /* the for-profit distribution of this software, are retained by */
- /* Michael Peppler and ITF Management SA. You are permitted to */
- /* use this software without fee. This software is provided "as */
- /* is" without express or implied warranty. You may redistribute */
- /* this software, provided that this copyright notice is retained, */
- /* and that the software is not distributed for profit. If you */
- /* wish to use this software in a profit-making venture, you must */
- /* first license this code and its underlying technology from */
- /* ITF Management SA. */
- /* */
- /* Bottom line: you can have this software, you can use it, you */
- /* can give it away. You just can't sell any or all parts of it */
- /* without prior permission from Harris Corporation. */
- /************************************************************************/
-
- /* sybase.c
- *
- * Call Sybase DB-Library functions from Perl.
- * Written by Michael Peppler (mpeppler@itf.ch)
- * ITF Management SA, 13 rue de la Fontaine
- * CH-1204 Geneva, Switzerland
- * Tel: (+4122) 312 1311 Fax: (+4122) 312 1322
- */
-
-
- /*
- * The Perl/Sybase savestr() conflict.
- * Both Perl and Sybase DB-Library have a function called savestr().
- * This creates a problem when calling dbcmd() and dbuse(). There are
- * several ways to work around this, one of which is to #define
- * BROKEN_DBCMD, which enables some code that I've written to simulate
- * dbcmd() locally. See Makefile and BUGS for details.
- */
- #include "EXTERN.h"
- #include "perl.h"
- #undef MAX
- #undef MIN
-
- #if !defined(VERSION3)
- #define str_2static(s) str_2mortal(s)
- #endif
-
- #include <sybfront.h>
- #include <sybdb.h>
- #include <syberror.h>
-
- #include "patchlevel.h"
-
- extern int wantarray;
-
- char *savestr();
-
-
- /*
- * The variables that the Sybase routines set, and that you may want
- * to test in your Perl script. These variables are READ-ONLY.
- */
- static enum uservars
- {
- UV_SUCCEED, /* Returns SUCCEED */
- UV_FAIL, /* Returns FAIL */
- UV_NO_MORE_ROWS, /* Returns NO_MORE_ROWS */
- UV_NO_MORE_RESULTS, /* Returns NO_MORE_RESULTS */
- UV_ComputeId, /* Returns the compute id of the row (in dbnextrow()) */
- UV_SybperlVer, /* Returns Sybperl Version/Patchlevel */
- };
-
- /*
- * User subroutines that we have implemented. I've found that I can do
- * all the stuff I want to with this subset of DB-Library. Let me know
- * if you implement further routines.
- * The names are self-explanatory.
- */
- static enum usersubs
- {
- US_dblogin, /* This also performs a dbopen() */
- US_dbopen,
- US_dbclose,
- US_dbcmd,
- US_dbsqlexec,
- US_dbresults,
- US_dbnextrow,
- US_dbcancel,
- US_dbcanquery,
- US_dbexit,
- US_dbuse,
- };
-
- #define MAX_DBPROCS 25 /* Change this if you really want your perl script to talk to */
- /* more than 25 dataserver connections at a time ...*/
-
- static LOGINREC *login;
- static DBPROCESS *dbproc[MAX_DBPROCS];
- static int exitCalled = 0; /* Set to 1 if dbexit() has been called. */
- static int ComputeId;
-
- static int usersub();
- static int userset();
- static int userval();
- static int err_handler(), msg_handler();
-
- int userinit()
- {
- init_sybase();
- }
-
- int
- init_sybase()
- {
- struct ufuncs uf;
- char *filename = "sybase.c";
-
- if (dbinit() == FAIL) /* initialize dblibrary */
- exit(ERREXIT);
- /*
- * Install the user-supplied error-handling and message-handling routines.
- * They are defined at the bottom of this source file.
- */
- dberrhandle(err_handler);
- dbmsghandle(msg_handler);
-
- uf.uf_set = userset;
- uf.uf_val = userval;
-
- #define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf)
-
- MAGICVAR("SUCCEED", UV_SUCCEED);
- MAGICVAR("FAIL",UV_FAIL);
- MAGICVAR("NO_MORE_ROWS", UV_NO_MORE_ROWS);
- MAGICVAR("NO_MORE_RESULTS", UV_NO_MORE_RESULTS);
- MAGICVAR("ComputeId", UV_ComputeId);
- MAGICVAR("SybperlVer", UV_SybperlVer);
-
- make_usub("dblogin", US_dblogin, usersub, filename);
- make_usub("dbopen", US_dbopen, usersub, filename);
- make_usub("dbclose", US_dbclose, usersub, filename);
- make_usub("dbcmd", US_dbcmd, usersub, filename);
- make_usub("dbsqlexec", US_dbsqlexec, usersub, filename);
- make_usub("dbresults", US_dbresults, usersub, filename);
- make_usub("dbnextrow", US_dbnextrow, usersub, filename);
- make_usub("dbcancel", US_dbcancel, usersub, filename);
- make_usub("dbcanquery", US_dbcanquery, usersub, filename);
- make_usub("dbexit", US_dbexit, usersub, filename);
- make_usub("dbuse", US_dbuse, usersub, filename);
-
- }
-
- static int
- usersub(ix, sp, items)
- int ix;
- register int sp;
- register int items;
- {
- STR **st = stack->ary_array + sp;
- ARRAY *ary = stack;
- register int i;
- register STR *Str; /* used in str_get and str_gnum macros */
- int inx = -1; /* Index into dbproc[] array. Passed as first parameter to nearly all &dbxxx() calls */
-
- if(exitCalled)
- fatal("&dbexit() has been called. Access to Sybase impossible.");
-
- switch (ix)
- {
- case US_dblogin:
- if (items > 2)
- fatal("Usage: &dblogin([user[,pwd]])");
- if (login)
- fatal("&dblogin() called twice.");
- else
- {
- int retval;
-
- login = dblogin();
- if(items)
- {
- DBSETLUSER(login, (char *)str_get(st[1]));
- if(items > 1)
- DBSETLPWD(login, (char *)str_get(st[2]));
- }
-
- dbproc[0] = dbopen(login, NULL);
- str_numset(st[0], (double) 0);
- }
- break;
- case US_dbopen:
- if (items != 0)
- fatal("Usage: $dbproc = &dbopen;");
- else
- {
- int j;
-
- for(j = 0; j < MAX_DBPROCS; ++j)
- if(dbproc[j] == NULL)
- break;
- if(j == MAX_DBPROCS)
- fatal("&dbopen: No more dbprocs available.");
- dbproc[j] = dbopen(login, NULL);
- str_numset(st[0], (double) j);
- }
- break;
- case US_dbclose:
- if (items != 1)
- fatal("Usage: $ret = &dbclose($dbproc);");
- else
- {
- inx = getDbProc(st[1]);
-
- dbclose(dbproc[inx]);
- dbproc[inx] = (DBPROCESS *)NULL;
- }
- break;
- case US_dbcancel:
- if (items != 1)
- fatal("Usage: &dbcancel($dbproc)");
- else
- {
- int retval;
- #if defined(BROKEN_DBCMD)
- DBSTRING *ptr;
- DBSTRING *old;
- #endif
- inx = getDbProc(st[1]);
-
- retval = dbcancel(dbproc[inx]);
- str_numset(st[0], (double) retval);
- #if defined(BROKEN_DBCMD)
- ptr = dbproc[inx]->dbcmdbuf;
- while(ptr)
- {
- old = ptr;
- ptr = ptr->strnext;
- free(old->strtext);
- free(old);
- }
- dbproc[inx]->dbcmdbuf = NULL;
- #endif
- }
- break;
-
- case US_dbcanquery:
- if (items != 1)
- fatal("Usage: &dbcanquery($dbproc)");
- else
- {
- int retval;
- inx = getDbProc(st[1]);
-
- retval = dbcanquery(dbproc[inx]);
- str_numset(st[0], (double) retval);
- }
- break;
-
- case US_dbexit:
- if (items != 0)
- fatal("Usage: &dbexit()");
- else
- {
- dbexit(dbproc[0]);
- exitCalled++;
- str_numset(st[0], (double) 1);
- }
- break;
-
- case US_dbuse:
- if (items != 2)
- fatal("Usage: &dbuse($dbproc, $database)");
- else
- {
- #if defined(BROKEN_DBCMD)
- /*
- * Why doesn't this $@#! dbuse() call not work from within
- * Perl????? (So we emulate it here, but I sure can't
- * guarantee anything about portability to future versions
- * of DB-Library!
- */
- DBSTRING *new;
- DBSTRING *sav;
- char *strdup();
- char buff[256];
- int ret;
-
- inx = getDbProc(st[1]);
-
- strcpy(buff, "use ");
- strcat(buff, (char *)str_get(st[2]));
- sav = dbproc[inx]->dbcmdbuf;
-
- new = (DBSTRING *)calloc(1,sizeof(DBSTRING));
- new->strtext = (BYTE *)strdup((char *)buff);
- new->strtotlen = strlen(new->strtext)+1;
- dbproc[inx]->dbcmdbuf = new;
-
- ret = dbsqlexec(dbproc[inx]);
- ret = dbresults(dbproc[inx]);
- while((ret = dbnextrow(dbproc[inx])) != NO_MORE_ROWS)
- ;
-
- free(new->strtext);
- free(new);
-
- dbproc[inx]->dbcmdbuf = sav;
- str_numset(st[0], (double) SUCCEED);
- #else
- int retval;
- char str[255];
- strcpy(str, (char *)str_get(st[2]));
- inx = getDbProc(st[1]);
-
- retval = dbuse(dbproc[inx], str);
- str_numset(st[0], (double) retval);
- #endif
- }
- break;
-
- case US_dbsqlexec:
- if (items != 1)
- fatal("Usage: &dbsqlexec($dbproc)");
- else
- {
- int retval;
- inx = getDbProc(st[1]);
-
- retval = dbsqlexec(dbproc[inx]);
- str_numset(st[0], (double) retval);
- }
- break;
-
- case US_dbresults:
- if (items != 1)
- fatal("Usage: &dbresults($dbproc)");
- else
- {
- int retval;
- inx = getDbProc(st[1]);
-
- retval = dbresults(dbproc[inx]);
- str_numset(st[0], (double) retval);
- #if defined(BROKEN_DBCMD)
- if(retval==NO_MORE_RESULTS)
- {
- DBSTRING *ptr = dbproc[inx]->dbcmdbuf;
- DBSTRING *old;
-
- while(ptr)
- {
- old = ptr;
- ptr = ptr->strnext;
- free(old->strtext);
- free(old);
- }
- dbproc[inx]->dbcmdbuf = NULL;
- }
- #endif
- }
- break;
-
- case US_dbcmd:
- if (items != 2)
- fatal("Usage: &dbcmd($dbproc, $str)");
- else
- {
- int retval;
- #if defined(BROKEN_DBCMD)
- DBSTRING *ptr;
- DBSTRING *new, *old;
- char *strdup();
- #endif
- inx = getDbProc(st[1]);
-
- #if defined(BROKEN_DBCMD)
- ptr = dbproc[inx]->dbcmdbuf;
-
- new = (DBSTRING *)calloc(1,sizeof(DBSTRING));
- new->strtext = (BYTE *)strdup((char *)str_get(st[2]));
- new->strtotlen = strlen(new->strtext)+1;
- if(!ptr)
- dbproc[inx]->dbcmdbuf = new;
- else
- {
- while(ptr->strnext)
- ptr = ptr->strnext;
- ptr->strnext = new;
- }
- #else
- retval = dbcmd(dbproc[inx], (char *)str_get(st[2]));
- #endif
- str_numset(st[0], (double) retval);
- }
- break;
-
- case US_dbnextrow:
- if (items != 1)
- fatal("Usage: @arr = &dbnextrow($dbproc)");
- else
- {
- int retval;
- inx = getDbProc(st[1]);
-
- --sp; /* otherwise you get an empty element at the beginning of the results array! */
-
- retval = dbnextrow(dbproc[inx]);
- if(retval == REG_ROW)
- {
- char buff[1024], *p;
- BYTE *data;
- int col, type, numcols = dbnumcols(dbproc[inx]);
- int len;
- DBFLT8 tmp;
-
- ComputeId = 0;
-
- for(col = 1, buff[0] = 0; col <= numcols; ++col)
- {
- type = dbcoltype(dbproc[inx], col);
- len = dbdatlen(dbproc[inx],col);
- data = (BYTE *)dbdata(dbproc[inx],col);
- if(!data && !len)
- {
- strcpy(buff,"NULL");
- }
- else
- {
- switch(type)
- {
- case SYBCHAR:
- strncpy(buff,data,len);
- buff[len] = 0;
- break;
- case SYBINT1:
- case SYBBIT: /* a bit is at least a byte long... */
- sprintf(buff,"%u",*(unsigned char *)data);
- break;
- case SYBINT2:
- sprintf(buff,"%d",*(short *)data);
- break;
- case SYBINT4:
- sprintf(buff,"%d",*(long *)data);
- break;
- case SYBFLT8:
- sprintf(buff,"%.6f",*(double *)data);
- break;
- case SYBMONEY:
- dbconvert(dbproc[inx], SYBMONEY, data,-1,SYBFLT8,&tmp,-1);
- sprintf(buff,"%.6f",tmp);
- break;
- case SYBDATETIME:
- dbconvert(dbproc[inx], SYBDATETIME, data,-1,SYBCHAR,buff,-1);
- break;
- default:
- /* ignored at the moment... */
- break;
- }
- }
- (void)astore(ary,++sp,str_2static(str_make(buff,0)));
- }
- }
- if (retval > 0)
- {
- char buff[1024], *p;
- BYTE *data;
- int col, type, numcols;
- int len;
- DBFLT8 tmp;
-
- ComputeId = retval;
- numcols = dbnumalts(dbproc[inx], ComputeId);
-
- for(col = 1, buff[0] = 0; col <= numcols; ++col)
- {
- type = dbalttype(dbproc[inx], ComputeId, col);
- len = dbadlen(dbproc[inx], ComputeId, col);
- data = (BYTE *)dbadata(dbproc[inx], ComputeId, col);
- if(!data && !len)
- {
- strcpy(buff,"NULL");
- }
- else
- {
- switch(type)
- {
- case SYBCHAR:
- strncpy(buff,data,len);
- buff[len] = 0;
- break;
- case SYBINT1:
- case SYBBIT: /* a bit is at least a byte long... */
- sprintf(buff,"%d",*(char *)data);
- break;
- case SYBINT2:
- sprintf(buff,"%d",*(short *)data);
- break;
- case SYBINT4:
- sprintf(buff,"%d",*(long *)data);
- break;
- case SYBFLT8:
- sprintf(buff,"%.6f",*(double *)data);
- break;
- case SYBMONEY:
- dbconvert(dbproc[inx], SYBMONEY, data,-1,SYBFLT8,&tmp,-1);
- sprintf(buff,"%.6f",tmp);
- break;
- case SYBDATETIME:
- dbconvert(dbproc[inx], SYBDATETIME, data,-1,SYBCHAR,buff,-1);
- break;
- default:
- /* ignored at the moment... */
- break;
- }
- }
- (void)astore(ary,++sp,str_2static(str_make(buff,0)));
- }
- }
- #if defined(BROKEN_DBCMD)
- /*
- * We can't rely on dbcmd(),dbresults() etc. to clean up
- * the dbcmdbuf linked list, so we have to it ourselves...
- */
- if(retval == NO_MORE_ROWS && !DBMORECMDS(dbproc[inx]))
- {
- DBSTRING *ptr = dbproc[inx]->dbcmdbuf;
- DBSTRING *new, *old;
-
- while(ptr)
- {
- old = ptr;
- ptr = ptr->strnext;
- free(old->strtext);
- free(old);
- }
- dbproc[inx]->dbcmdbuf = NULL;
- }
- #endif
- }
- break;
-
- default:
- fatal("Unimplemented user-defined subroutine");
- }
- return sp;
- }
-
- /*
- * Return the value of a userdefined variable. These variables are all
- * READ-ONLY in Perl.
- */
- static int
- userval(ix, str)
- int ix;
- STR *str;
- {
- char buff[24];
-
- switch (ix)
- {
- case UV_SUCCEED:
- str_numset(str, (double)SUCCEED);
- break;
- case UV_FAIL:
- str_numset(str, (double)FAIL);
- break;
- case UV_NO_MORE_ROWS:
- str_numset(str, (double)NO_MORE_ROWS);
- break;
- case UV_NO_MORE_RESULTS:
- str_numset(str, (double)NO_MORE_RESULTS);
- break;
- case UV_ComputeId:
- str_numset(str, (double)ComputeId);
- break;
- case UV_SybperlVer:
- sprintf(buff, "%d.%3.3d", VERSION, PATCHLEVEL);
- str_set(str, buff);
- break;
- }
- return 0;
- }
-
- static int
- userset(ix, str) /* Not used. None of these variables are user-settable */
- int ix;
- STR *str;
- {
- return 0;
- }
-
-
- /*ARGSUSED*/
- static int err_handler(dbprocl, severity, dberr, oserr, dberrstring, oserrstr)
- DBPROCESS *dbprocl;
- int severity;
- int dberr;
- int oserr;
- char *dberrstring;
- char *oserrstr;
- {
- if ((dbprocl == NULL) || (DBDEAD(dbprocl)))
- return(INT_EXIT);
- else
- {
- fprintf(stderr,"DB-Library error:\n\t%s\n", dberrstring);
-
- if (oserr != DBNOERR)
- fprintf(stderr,"Operating-system error:\n\t%s\n", oserrstr);
-
- return(INT_CANCEL);
- }
- }
-
- /*ARGSUSED*/
-
- static int msg_handler(dbprocl, msgno, msgstate, severity, msgtext, srvname, procname, Line)
- DBPROCESS *dbprocl;
- DBINT msgno;
- int msgstate;
- int severity;
- char *msgtext;
- char *srvname;
- char *procname;
- DBUSMALLINT Line;
- {
- if(msgno != 5701) /* Ignore 'Changed database context' messages */
- {
- fprintf (stderr,"Msg %ld, Level %d, State %d\n",
- msgno, severity, msgstate);
- if (strlen(srvname) > 0)
- fprintf (stderr,"Server '%s', ", srvname);
- if (strlen(procname) > 0)
- fprintf (stderr,"Procedure '%s', ", procname);
- if (Line > 0)
- fprintf (stderr,"Line %d", Line);
-
- fprintf(stderr,"\n\t%s\n", msgtext);
- }
-
- if(severity)
- exit(-1);
-
- return(0);
- }
-
- /*
- * Get the index into the dbproc[] array from a Perl STR datatype.
- * Check that the index is reasonably valid...
- */
- int getDbProc(Str)
- STR *Str;
- {
- int ix = (int)str_gnum(Str);
-
- if(ix < 0 || ix >= MAX_DBPROCS)
- fatal("$dbproc parameter is out of range.");
- return ix;
- }
-
-
-