.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 1989-2005 SAP AG-2002$$Page %$
.tm 12
.hm 6
.hs 3
.tt 1 $SQL$Project Distributed Database System$VNI90C$
.tt 2 $$$
.tt 3 $$SQL_filter_main$1999-09-27$
***********************************************************
.nf

.nf

.nf

    ========== licence begin  GPL
    Copyright (c) 1989-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo


.fo


.fo
.nf
.sp
Module  :       SQL_filter_main
=========
.sp
Purpose :
.CM *-END-* purpose -------------------------------------
.sp
.cp 3
Define  :

.CM *-END-* define --------------------------------------
.sp ; .cp 3
Use     :

.CM *-END-* use -----------------------------------------
.sp ; .cp 3
Synonym :

.CM *-END-* synonym -------------------------------------
.sp ; .cp 3
Author  : FrankS, AxelM
.sp
.cp 3
Created : 1990-06-12
.sp
.cp 3
Version : 1994-08-08
.sp
.cp 3
Release :      Date : 1999-09-27
.sp
Release :      Date : 1999-09-27
.sp
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Specification:

.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Description:

.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:

.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.oc _/1
.CM -lll-
Code    :
/* PRETTY */

/*      vni90c                                                            */
/*                                                                        */
/*************************************************************
***                                                        ***
*** sql.cpc: Programm zum interaktiven Abarbeiten von      ***
***          SQL-Kommandos.                                ***
***                                                        ***
*** Modul:   sql.cpc                            ( vni90c ) ***
***                                                        ***
*** Benoetigte Files: sql.cpc                              ***
***                   argument.c                           ***
***                   form.c                               ***
***                   sql.h                                ***
***                                                        ***
*** Autor:   Detlef Engelbrecht                            ***
***          Frank Strassenburg                            ***
***                                                        ***
*** Datum:   12.06.1990                                    ***
***          08.03.1993                                    ***
***                                                        ***
*************************************************************/
#define sqlunicodec (42)
/*==========================================================================*/
short optionflag;  /* geoderte Flaginformationen */

/* Prottypes */
void fehler(int art);
void printout();
void getsetset();
void n90header(char *form, char *sepa);
void sofehler(int art, char *string);
void formdouble(double *zahl, int length, int frac, int art, int nwert,
char *darst, char *sepa, char *nvalue);

/* Statementnummerierung */
int stmntnr;

/* Fehler fuer Rollback */
int sqlfehler;

/* Globale Deklarationen */
sqlvartype *actvar;    /* Struktur fuer Ergebnisse                */
char ergebnis[32000];  /* Speicherbereich fuer alle char    Typen */
double derg[255];      /* Speicherbereich fuer alle double  Typen */
int ierg[255];         /* Speicherbereich fuer alle int     Typen */

FILE *fehlfile;        /* File fuer "stderr"           */
FILE *fp;              /* Protokolldatei               */

exec sql begin declare section;
char stmnt[32000];    /* Zu verarbeitendes Statement  */
char username  [65];  /* username                     */
char password  [65];  /* password                     */
char dbname    [65];  /* dbname                       */
char dbnode    [513]; /* hostname                     */
char xuserkey  [65];  /* xuserkey                     */
char language[41];    /* Language from set            */
char nullvalue[41];   /* Nullvalue from set           */
char sep[41];         /* Separator from set           */
char l_sep[41];       /* Length of Separator from set */
char decimalrep[41];  /* Format for decimals from set */
char dat[41];         /* Format for dates from set    */
char tim[41];         /* Format for time from set     */
char dattim[41];      /* Format for time and date     */
char ergebnistab[65]; /* benammte Ergebnismenge       */
exec sql end declare section;

/*==========================================================================*/

void   set_copyright ()
{
#define copyr1 "@(#) *** Copyright (c) 1989-2005 SAP AG                                       \0"
#define copyr2 "@(#)2000 - all rights reserved -                                   \0"
#define copyr3 "@(#)program property of SAP AG                                    *\0"

	char  cpr1 [ 68 ] , cpr2 [ 68 ] , cpr3 [ 68 ] ;

	strcpy ( cpr1 , copyr1 ) ;
	strcpy ( cpr2 , copyr2 ) ;
	strcpy ( cpr3 , copyr3 ) ;
}

/*==========================================================================*/

/* Funktion zum Beschreiben der Ergebnismenge */
set_describe_area()
{
    int i, nrint, nrdouble, nrbyte;
    sqlvartype *actvar;

    memset (ergebnis, 0, sizeof (ergebnis));
    for(i=0,nrint=nrdouble=nrbyte=0;i<sqlda.sqln;i++)
    {
        if (nrbyte>sizeof(ergebnis)-1 || nrint>254 || nrdouble > 254)
	{
	if (strncmp(language,"DEU",3))
	    sofehler(1,"Internal overflow");
	else
	    sofehler(1,"Interner Ueberlauf");
        ende();
	}
        actvar = &sqlda.sqlvar[i];

        switch(( *actvar).coltype)
        {
        case sqlfloat: /* Float in Exponentialdarstellung */
        case sqlfixed: /* Decimal */
        case 29:       /* Smallint  */
        case 30:       /* Integer  */
            if(!(*actvar).colfrac)
            {
                ( *actvar).hostvartype = sqlvint4;
		( *actvar).hostvaraddr = (void *)&ierg[nrint++];
            }
            else
            {
                ( *actvar).hostvartype = sqlvreal8;
		( *actvar).hostvaraddr = (void *)&derg[nrdouble++];
            }
            break;
        case sqloldlonguni:
        case sqllonguni:
            (*actvar).collength = 160;
            (*actvar).collength++;
            (*actvar).hostvartype = sqlvunic;
            (*actvar).hostvaraddr = (void *)&ergebnis[nrbyte];
            nrbyte += (*actvar).collength;
            break;
	case sqlunicode: /* Doublebyte */
        case sqlvarunicode:
	    (*actvar).collength++;
	    (*actvar).collength *= 2;
            (*actvar).hostvartype = sqlvunic;
	    (*actvar).hostvaraddr = (void *)&ergebnis[nrbyte];
	    nrbyte += (*actvar).collength;
            break;
        case sqlchar:  /* Character */
        case sqlbyte:  /* Hexadezimaldarstellung */
        case sqldate:  /* Datum */
        case sqltime:  /* Zeit */
	case sqlvarchar:
	case sqlboolean:
	    (*actvar).collength++;
            (*actvar).hostvartype = sqlvchar;
	    (*actvar).hostvaraddr = (void *)&ergebnis[nrbyte];
	    nrbyte += (*actvar).collength;
            break;
        case sqloldlongchar:
        case sqllong:
        case sqllongbyte:
            (*actvar).collength = 80;
	    (*actvar).collength++;
            (*actvar).hostvartype = sqlvchar;
	    (*actvar).hostvaraddr = (void *)&ergebnis[nrbyte];
	    nrbyte += (*actvar).collength;
            break;
        default:
	    /*  sollte nicht vorkommen */
            printf ("\n\ninvalid type: %d\n\n",(*actvar).coltype);
            ende();
        }
    }
}

/*==========================================================================*/

main(argc, argv)
int argc;
char *argv[];
{
    int i, pos, rc, art;

    signal(SIGINT,SIG_IGN);

    dbname   [ 0 ] = '\0' ;
    dbnode   [ 0 ] = '\0' ;
    username [ 0 ] = '\0' ;
    password [ 0 ] = '\0' ;
    strcpy(xuserkey, "DEFAULT");
    pos = getargument (argc,argv);

    if (optionflag & PROTOKOLL) fehlfile=stdout;
    else fehlfile=stderr;

    /* Oeffne Protokolldatei */
    if (optionflag & PROTMODE)
    {
	if (!(fp=fopen("sql.prot","w")))
	{
	    perror("sql.prot");
	    exit(0);
	}
    }

    DBG (("main ( vni90c ) : username                       = >%s<\n",
			     username ))
    DBG (("main ( vni90c ) : password                       = >%s<\n",
			     password ))

    if ( strcmp ( dbname, "\0" ) || strcmp ( dbnode, "\0" )  )
    {
      exec sql set serverdb :dbname on :dbnode;
    }

    if ( strcmp ( username , "\0" ) || strcmp ( password , "\0" ) )
    {
	checkusername ( username );
	exec sql connect :username identified by :password key :xuserkey;

    }
    else {
      exec sql connect "" key :xuserkey;
    }

    if (sqlca.sqlcode)
    {
	if (optionflag & PROTMODE)
	{
	    fprintf(fp,"%d-> connect %s identified by %s\n",
		++stmntnr,username,password);
	    fehler(0);
	    ende();
	}
    }

    /* get set settings */
    getsetset();

    /* stdin lesen oder Argumente */
    if (pos < argc) /* Kommando wurde als Argument uebergeben */
    {
	for (;pos<argc;pos++)
	{
	    strcat(stmnt,argv[pos]);
	    strcat(stmnt," ");
	}
	if (optionflag & PROTOKOLL) printf("%s\n",stmnt);
	fflush(stdout);
	if (optionflag & PROTMODE)
	{
	    fprintf(fp,"%d-> %s\n",++stmntnr,stmnt);
	}
	art=analysestmnt(stmnt);
	ausfuehren(art);
    }
    else /* stdin lesen */
    {
	for (;;)
	{
	    unsigned    lgt ;
	    char        * linptr ;

	    if ( ! ( optionflag & BATCHMODE ) )
	    {
		fputs("> ",fehlfile);
		fflush(fehlfile);
	    }

	    lgt = 0 ;
	    while ( linptr = fgets(stmnt+lgt,sizeof(stmnt)-lgt,stdin) )
	    {
		lgt += strlen (stmnt+lgt);
		if ( stmnt[lgt-1] == '\n' ) lgt -- ;
		if ( stmnt[lgt-1] != 0x5c /*'\\'*/ ) break ;
		stmnt[lgt-1] = ' ';
		if ( lgt > (sizeof(stmnt) - 3) )
		{
		    fputs("command too long \n",fehlfile);
		    break ;
		}
	    }
	    if ( ! linptr ) break ;
	    if ( stmnt[lgt] == '\n' ) lgt ++ ; /* save last '\n' */
	    stmnt[lgt] = '\0' ;

	    if (optionflag & PROTOKOLL) printf("%s",stmnt);
	    fflush(stdout);
	    if (optionflag & PROTMODE)
	    {
		fprintf(fp,"%d-> %s",++stmntnr,stmnt);
	    }
	    art=analysestmnt(stmnt);
	    if (!*stmnt) continue;
	    if (ausfuehren(art)) break;
	}
	fputs("\n",fehlfile);
    }
    ende();
}

/*==========================================================================*/

/* Fuehrt das eigentliche Kommando aus */
ausfuehren(was)
int was;
{
    int rc;

    switch (was)
    {
    case EXIT:
	return(1);
    case SHELLCOM:
	rc=system(stmnt+1);
	if (!rc)
	{
	    sqlca.sqlcode = 0;
	    fehler(0);
	}
	else
	{
	    sprintf(stmnt,"%d: %s",rc,
		strncmp(language,"DEU",3)?"Error":"Fehler");
	    sofehler(0,stmnt);
	}
	return(0);
    case SELDIRECT:
        exec sql prepare sel from :stmnt;
        if (sqlca.sqlcode)
        {
	    fehler(0);
	    break;
        }
	exec sql describe sel;
	if (!sqlca.sqlcode) set_describe_area();
	if (!sqlca.sqlcode) exec sql execute sel using descriptor;
	if (!sqlca.sqlcode)
	{
	    if (!(optionflag & NOHEADER)) n90header(decimalrep,sep);
	    printout();
	}
        fehler(0);
	break;

    case SELECTNORMAL:
	exec sql prepare selnormal from :stmnt;
	exec sql describe selnormal;
	exec sql execute selnormal using descriptor ;


	if (!sqlca.sqlcode)
	{
	    sprintf(stmnt,"fetch %s using descriptor",ergebnistab);
	    exec sql prepare fet from :stmnt;
        }

	if (sqlca.sqlcode)
	{
	    fehler(0);
	    break;
	}

	exec sql describe  fet;
	set_describe_area();

	
	if (!(optionflag & NOHEADER))
	  n90header(decimalrep,sep);
	rc=0;
	while(!sqlca.sqlcode)
	{
	     exec sql execute fet using descriptor ;

	   if (sqlca.sqlcode)
	    {
		/* Wenn zumindest ein Satz bereits gefunden wurde */
		if (sqlca.sqlcode == 100 && rc) sqlca.sqlcode=0;
		break;
	    }
	    printout();
	    rc++;
	}
	fehler(0);
        break;
    case FETCH:
	if (strncmp(language,"DEU",3))
	    strcpy(stmnt,"Command not allowed");
	else
	    strcpy(stmnt,"Kommando nicht erlaubt");
	sofehler(1,stmnt);
	break;
    case COMMITWORK:
	/* zuruecksetzen der Transaktion bei Option -r */
        if ((optionflag & ROLLBACK) && sqlfehler)
	{
	    exec sql rollback work;
	    sqlfehler=0;
	    fehler(1);
	}
	else
	{
	    exec sql commit work;
	    fehler(0);
	}
	break;
    case ROLLBACKWORK:
	sqlfehler=0;
    default:
#ifdef READONLY
	if (strncmp(language,"DEU",3))
	    strcpy(stmnt,"Command not allowed in xsqlro!");
	else
	    strcpy(stmnt,"Kommando nicht erlaubt in xsqlro!");
	sofehler(1,stmnt);
#else
	exec sql prepare seldefault from :stmnt;
	exec sql execute seldefault ;
	fehler(0);
#endif
	break;
    }
    /* falls autocommit gewuenscht wird */
    if (!(optionflag & NOAUTOCOMMIT))
    {
	exec sql commit work;
	sqlfehler = 0;
    }
    return(0);
}

/*==========================================================================*/

/* Fehlerausgabefunktion */
void fehler(int art)
{
    if (art)
    {
        fputs("* work rolled back\n",fehlfile);
	if (optionflag & PROTMODE)
	{
	    fputs("* work rolled back\n",fp);
	}
    }
    else
    {
        if (sqlca.sqlcode)
        {
            fprintf(fehlfile,"* %d: %s\n",sqlca.sqlcode,sqlca.sqlerrmc);
	    if (optionflag & PROTMODE)
	    {
		fprintf(fp,"* %d: %s\n",sqlca.sqlcode,sqlca.sqlerrmc);
	    }
	    sqlfehler |= sqlca.sqlcode;
        }
        else
        {
	    fprintf(fehlfile,"* Ok\n");
	    if (optionflag & PROTMODE)
	    {
		fprintf(fp,"* Ok\n");
	    }
        }
    }
    fflush(fehlfile);
    if (optionflag & PROTMODE)
    {
	fflush(fp);
    }
}

/*==========================================================================*/

/* Ausgabe der gefundenen Werte */
void printout()
{
    int i;

    for(i = 0; i < sqlda.sqln; i++)
    {
        actvar = &sqlda.sqlvar[i];
	
	if ( optionflag & COLUMNFORM )
	{
	    /* print column name */
	    printf ( "%-18.18s%s" , (*actvar).colname , sep );
	}

        switch(( *actvar).hostvartype)
        {
        case sqlvint4:   /* Integer */
            formint((*actvar).hostvaraddr,(*actvar).collength,
		(*actvar).hostindicator,decimalrep,sep,nullvalue);
	    break;
        case sqlvreal8:  /* Double */
            formdouble((double*)(*actvar).hostvaraddr,
		(*actvar).collength,(*actvar).colfrac,
		(*actvar).coltype,(*actvar).hostindicator,decimalrep,
		sep,nullvalue);
            break;
        case sqlvchar:  /* Charactertypen */
	    switch((*actvar).coltype)
	    {
	    case sqlchar:  /* Characterdarstellung */
	    case sqloldlongchar:
	    case sqlvarchar :
	    case sqlboolean :
	    case sqllong    :  /* sqllong */
		formchar((*actvar).hostvaraddr,(*actvar).collength,
		    (*actvar).hostindicator,sep,nullvalue);
		break;
	    case sqlunicode: /* Doublebyte wird ignoriert */
                formdoublebyte((*actvar).hostvaraddr,
		    (*actvar).collength,(*actvar).hostindicator,
		    sep,nullvalue);
		break;
	    case sqlbyte:  /* Hexdezimaldarstellung fuer Byte */
	    case 20     :  /* sqllongbyte */
	    case sqloldlongbyte :
                formbyte((*actvar).hostvaraddr,(*actvar).collength,
		    (*actvar).hostindicator,sep,nullvalue);
		break;
	    case sqldate:  /* Datum */
                formdatum((*actvar).hostvaraddr,dat,
		    (*actvar).hostindicator,sep,nullvalue);
		break;
	    case sqltime:  /* Zeit */
                formdatum((*actvar).hostvaraddr,tim,
		    (*actvar).hostindicator,sep,nullvalue);
                break;
	    }
            break;
	case sqlunicodec:
	  formASCIIstring((*actvar).hostvaraddr,
			  (*actvar).collength,(*actvar).hostindicator,
			  sep,nullvalue);
          break;
        default: /* Nicht bekannter Typ */
	    /*  sollte nicht vorkommen */
            printf ("invalid type %d!\n",( *actvar).hostvartype);
            ende();
        }

	if ( optionflag & COLUMNFORM )
	{
	    putchar ( '\n' ); /* print newline */
	}

    }

    if ( optionflag & COLUMNFORM )
    {
	/* print separation line */
	for ( i = 0 ; i < 78 ; i ++ ) putchar ( '-' );
	putchar ( '\n' ); /* print newline */
    }
    else
    {
	puts(""); /* Nach jedem Satz Newline */
    }
    fflush(stdout);
}

/*==========================================================================*/

/* Settings holen */
void getsetset()
{
    register char *ptr;
    int i, laenge;
    /* Temporaere Zwischenvariable zum Merken von evtl.
       bereits gesetzten Werten, die als Parameter ueber-
       geben wurden */
    char tmp_nullvalue[41];   /* Nullvalue from set           */
    char tmp_sep[41];         /* Separator from set           */
    char tmp_decimalrep[41];  /* Format for decimals from set */
    char tmp_dat[41];         /* Format for dates from set    */
    char tmp_tim[41];         /* Format for time from set     */

    /* Merken gesetzter Werte */
    strcpy(tmp_nullvalue,nullvalue);
    strcpy(tmp_sep,sep);
    strcpy(tmp_decimalrep,decimalrep);
    strcpy(tmp_dat,dat);
    strcpy(tmp_tim,tim);

    DBG (("getsetset       : REL 311\n", 0 ))
    exec sql select direct language, nullvalue, decimalrep,
	dat, tim, sep, l_sep into :language,
	:nullvalue, :decimalrep, :dat, :tim, :sep, :l_sep
	from sysdba.set_r key username=USER;

    if ( sqlca.sqlcode == 100 )
    {
	exec sql select direct language, nullvalue, decimalrep,
	    dat, tim, sep, l_sep into :language,
	    :nullvalue, :decimalrep, :dat, :tim, :sep, :l_sep
	    from sysdba.set_r key username=SYSDBA ;
    }

    /* Falls Fehler, Setzen von Defaultwerten */
    if (sqlca.sqlcode)
    {
	DBG (("getsetset       : Fehler beim Lesen von \"set_r\"\n", 0 ))
	strcpy(sep," | ");
        strcpy(language,"ENG");
        strcpy(nullvalue,"?");
        strcpy(decimalrep,",.");
        strcpy(dat,"00-11-22");
        strcpy(tim,"00:11:22");
    }
    else
    {
	char tmp[41];

	/* Abfragen ob Separator auf standard */
        strcpy(tmp,sep);
	for(ptr=tmp;*ptr;ptr++)
	    if (islower(*ptr)) *ptr=_toupper(*ptr);
	if (!strcmp(tmp,"STANDARD")) strcpy(sep," | ");
	else
	{
	    /* an Separator wieder Blanks hinten ranhaengen */
	    laenge=atoi(l_sep);
	    i=strlen(sep);
	    for(ptr=sep+i;i<laenge;i++,ptr++) *ptr=' ';
	    *ptr = '\0';
        }
#ifdef REL30
	strcpy ( dattim , dat ) ;
	DBG (("getsetset       : dattim                         = >%s<\n",
				 dattim ))
	checkdtform ( dattim ) ;
#endif
    }

    /* Zuruecksetzen gemerkter gesetzter Werte */
    if (*tmp_nullvalue) strcpy(nullvalue,tmp_nullvalue);
    if (*tmp_sep) strcpy(sep,tmp_sep);
    if (*tmp_decimalrep) strcpy(decimalrep,tmp_decimalrep);
    if (*tmp_dat) strcpy(dat,tmp_dat);
    if (*tmp_tim) strcpy(tim,tmp_tim);
    reformdate(dat);
    reformtime(tim);
}

/*==========================================================================*/

/* Ausgabe des headers fuer die Spaltenbezeichnung */
void n90header(char *form, char *sepa)
{
    int i, length, geslength=0;

    for(i = 0; i < sqlda.sqln; i++)
    {
        actvar = &sqlda.sqlvar[i];
	length=(*actvar).collength;
        switch((*actvar).hostvartype)
        {
        case sqlvint4:   /* Integer */
            length = getnumlength(length,form,0);
	    break;

        case sqlvreal8:  /* Double */
	    switch((*actvar).coltype)
            {
            case sqlfloat:
                length += 6;
		break;
            case sqlfixed:
		length -= (*actvar).colfrac;
		length = getnumlength(length,form,1);
		length += (*actvar).colfrac;
	    }
            break;
        case sqlvchar:  /* Charactertypen */
        case sqlunicodec:  /* Charactertypen */
	    length--;
	    switch((*actvar).coltype)
	    {
	    case sqlunicode: /* Doublebyte wird ignoriert */
	    case sqlbyte:  /* Hexdezimaldarstellung fuer Byte */
	    case 20     :  /* sqllongbyte */
	    case sqloldlongbyte :
                length *= 2;
		break;
	    case sqlchar:  /* Characterdarstellung */
	    case sqllong:  /* sqllong */
	    case sqlvarchar :
	    case sqlboolean :
	    case sqloldlongchar:
		break;
	    case sqldate:  /* Datum */
                length=strlen(dat);
		break;
	    case sqltime:  /* Zeit */
                length=strlen(tim);
	    }
            break;
        default: /* Nicht bekannter Typ */
	    /*  sollte nicht vorkommen */
            printf ("invalid type %d!\n",(*actvar).hostvartype);
            ende();
        }
	if (length)
	{
	    printf("%-*.*s%s",length,(length>18)?18:length,
				(*actvar).colname,sep);
	    geslength += length + strlen(sepa);
	}
    }
    puts(""); /* Nach Header Newline */
    for (i=0;i<geslength;i++) printf("-"); /* Unterstrich */
    puts(""); /* Nach Unterstrich Newline */
}

/*==========================================================================*/

/* Formatierte Darstellung von Doubles */
void formdouble(double *zahl, int length, int frac, int art, int nwert,
char *darst, char *sepa, char *nvalue)
{
    char rc[40];
    char *ptr;
    int korr;

    *rc='\0';
    switch(art)
    {
    case sqlfloat: /* Exponentialdarstellung bei Floats */
        length += 6;
	if (nwert < 0)
	    sprintf(rc,"%*.*s%s",length,length,nvalue,sepa);
	else
	{
	    sprintf(rc,"%*.*E%s",length,length-7,*zahl,sepa);
	    for (ptr=rc;*ptr;ptr++)
		if (*ptr=='.') *ptr = darst[1];
	}
        printf("%s",rc);
        break;
    case sqlfixed: /* Normale Darstellung von Fixed */
	if (nwert < 0) *rc = '\0';
	else sprintf(rc,"%f",*zahl);
        formnumber(rc,darst,sepa,nvalue,length,frac,nwert);
    }
}

/*==========================================================================*/

/* Ausgabe sonstiger Fehler */
void sofehler(int art, char *string)
{
    /* Falls art != 0, auch Ausgabe auf fehlfile */
    if (art) fprintf(fehlfile,"* %s\n",string);
    if (optionflag & PROTMODE)
    {
	fprintf(fp,"* %s\n",string);
    }
}

/*==========================================================================*/

ende()
{
    int rc;

    if ((optionflag & ROLLBACK) && sqlfehler)
    {
        exec sql rollback work release;
	fehler(1);
    }
    else exec sql commit work release;
    if (optionflag & PROTMODE)
    {
	fclose(fp);
    }
    exit(0);
}

.CM *-END-* code ----------------------------------------
.sp 2
***********************************************************
*-PRETTY-*  statements    :        xxxx
*-PRETTY-*  lines of code :        yyyy
*-PRETTY-*  lines in file :        zzzz
.pa
