/* $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/dbck/fix.dc,v 1.2 1996/06/02 07:42:32 ghudson Exp $
 *
 * User interface routines for dbck (Moira database consistency checker)
 *
 *  (c) Copyright 1988 by the Massachusetts Institute of Technology.
 *  For copying and distribution information, please see the file
 *  <mit-copyright.h>.
 */

#include <mit-copyright.h>
#include <moira.h>
#include <stdio.h>
#include "dbck.h"

EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
EXEC SQL INCLUDE sqlda;  /* SQL Descriptor Area */

#define SQLDA_RETVALS
typedef IISQLDA_TYPE(DBCK_SQLDA,DBCK_SQLDA_T,SQLDA_RETVALS);
DBCK_SQLDA_T SQLDA;

static char fix_qc_rcsid[] = "$Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/dbck/fix.dc,v 1.2 1996/06/02 07:42:32 ghudson Exp $";

EXEC SQL BEGIN DECLARE SECTION; 
char *_table;
char *_idfield;
char stmt_buf[500];
EXEC SQL END DECLARE SECTION; 

generic_ffunc(id)
EXEC SQL BEGIN DECLARE SECTION; 
int id;
EXEC SQL END DECLARE SECTION; 
{
    EXEC SQL BEGIN DECLARE SECTION; 
    int rowcount;
    EXEC SQL END DECLARE SECTION; 

/*  delete _table where _table._idfield = id */
    sprintf(stmt_buf,"DELETE FROM %s WHERE %s.%s = %d",
	    _table,_table,_idfield,id);
    EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
/*  inquire_equel(rowcount = "rowcount") */
    EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
    if (rowcount > 0)
      printf("%d entr%s deleted\n", rowcount, rowcount==1?"y":"ies");
    else
      printf("Not deleted\n");
    modified(_table);
}


generic_delete(sq, pfunc, table, idfield, preen)
struct save_queue *sq;
void (*pfunc)();
char *table, *idfield;
int preen;
{
    _table = table;
    _idfield = idfield;
    generic_fix(sq, pfunc, "Delete", generic_ffunc, preen);
}


single_delete(table, idfield, id)
char *table, *idfield;
int id;
{
    _table = table;
    _idfield = idfield;
    generic_ffunc(id);
}


zero_fix(tbl, zrfield, idfield, id)
EXEC SQL BEGIN DECLARE SECTION; 
char *tbl, *zrfield, *idfield;
int id;
EXEC SQL END DECLARE SECTION; 
{
    EXEC SQL BEGIN DECLARE SECTION; 
    int rowcount;
    EXEC SQL END DECLARE SECTION; 

/*  replace tbl (zrfield = 0) where table.idfield = id */
    sprintf(stmt_buf,"UPDATE %s SET %d = 0 WHERE %s.%s = %d",
	    tbl,zrfield,tbl,idfield,id);
    EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
/*  inquire_equel(rowcount = "rowcount") */
    EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
    if (rowcount > 0)
      printf("%d entr%s fixed\n", rowcount, rowcount==1?"y":"ies");
    else
      printf("Not fixed\n");
    modified(tbl);
}


int single_fix(msg, preen)
char *msg;
int preen;
{
    if (mode == MODE_PREEN)
      return(preen);

    switch (mode) {
    case MODE_ASK:
	if (!prompt(msg))
	  break;
    case MODE_YES:
	return(1);
	break;
    case MODE_NO:
	;
    }
    return(0);
}


generic_fix(sq, pfunc, msg, ffunc, preen)
struct save_queue *sq;
char *msg;
int (*pfunc)(), (*ffunc)();
int preen;
{
    int id;

    while (sq_get_data(sq, &id)) {
	if ((*pfunc)(id) == 0 && single_fix(msg, preen))
	  (*ffunc)(id);
    }
    sq_destroy(sq);
}


int prompt(msg)
char *msg;
{
    char buf[BUFSIZ];
    EXEC SQL BEGIN DECLARE SECTION; 
    extern int dcmenable;
    EXEC SQL END DECLARE SECTION; 

    while (1) {
	printf("%s (Y/N/Q)? ", msg);
	fflush(stdout);
	gets(buf);
	if (buf[0] == 'Y' || buf[0] == 'y')
	  return(1);
	if (buf[0] == 'N' || buf[0] == 'n')
	  return(0);
	if (buf[0] == 'Q' || buf[0] == 'q') {
	    if (prompt("Are you sure you want to quit")) {
		if (prompt("Save database changes")) {
/*		    end transaction */
		    EXEC SQL COMMIT WORK;
		    cleanup();
		    exit(0);
		} else {
/*		    abort */
		    EXEC SQL ROLLBACK WORK;
/*		    replace values (value = dcmenable)
 *		    	where values.name = "dcm_enable" */
		    EXEC SQL UPDATE numvalues SET value = :dcmenable
			WHERE name='dcm_enable';
/*		    exit */
		    /* No equivalent (?) */
		    exit(1);
		}
	    }
	}
    }
}


/**
 ** set_next_object_id - set next object id in values table
 **
 ** Inputs: object - object name in values table and in objects
 **	    table - name of table objects are found in
 **
 ** - called before an APPEND operation to set the next object id to
 **   be used for the new record to the next free value
 **
 **/

int set_next_object_id(object, tablename)
    char *object;
    char *tablename;
{
    EXEC SQL BEGIN DECLARE SECTION; 
    char *name, *tbl;
    int rowcount, existence, value;
    EXEC SQL END DECLARE SECTION; 

    name = object;
    tbl = tablename;
/*  range of v is values
 *  repeat retrieve (value = v.#value) where v.#name = @name */
    EXEC SQL REPEATED SELECT value INTO :value FROM numvalues
	WHERE name = :name;
    EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
    if (rowcount != 1)
	return(MR_NO_ID);

/*  retrieve (existence = any(tbl.name where tbl.name = value)) */
    SQLDA.sqlvar[0].sqldata=(void *)&rowcount;
    sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s=%d",tbl,name,value);
    EXEC SQL PREPARE stmt INTO :&SQLDA USING NAMES FROM :stmt_buf; 
    if(sqlca.sqlcode)
	return(MR_INTERNAL);
    EXEC SQL DECLARE foo CURSOR FOR stmt;
    EXEC SQL OPEN foo;
    EXEC SQL FETCH foo USING DESCRIPTOR :&SQLDA;
    if (sqlca.sqlcode < 0) return(MR_INTERNAL);
    if (sqlca.sqlcode == 100) existence=0; else existence=1;
    EXEC SQL CLOSE foo;

    if (rowcount != 1)
	return(MR_NO_ID);
    while (existence) {
	value++;
	if (value > MAX_ID_VALUE)
	    value = MIN_ID_VALUE;
/*	retrieve (existence = any(tbl.name where tbl.name = value)) */
	sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s=%d",name,tbl,name,value);
	EXEC SQL PREPARE stmt INTO :&SQLDA USING NAMES FROM :stmt_buf; 
	if(sqlca.sqlcode)
	    return(MR_INTERNAL);
	EXEC SQL DECLARE bar CURSOR FOR stmt;
	EXEC SQL OPEN bar;
	EXEC SQL FETCH bar USING DESCRIPTOR :&SQLDA;
	if (sqlca.sqlcode != 0) break;
	EXEC SQL CLOSE bar;
    }
    EXEC SQL CLOSE bar; 

    printf("setting ID %s to %d\n", name, value);
/*  repeat replace v (#value = @value) where v.#name = @name */
    EXEC SQL REPEATED UPDATE numvalues SET value = :value
	WHERE name = :name;
    modified("values");
    return(MR_SUCCESS);
}


generic_fix_id(tbl, idfield, txtfield, oldid, name)
    EXEC SQL BEGIN DECLARE SECTION; 
    char *tbl;
    char *idfield;
    char *txtfield;
    int oldid;
    char *name;
    EXEC SQL END DECLARE SECTION; 
{
    EXEC SQL BEGIN DECLARE SECTION; 
    int rowcount, id, temp;
    EXEC SQL END DECLARE SECTION; 

    set_next_object_id(tbl, idfield);
/*  retrieve (id = values.value) where values.#name = idfield */
    EXEC SQL SELECT value INTO :id FROM numvalues
	WHERE name = :idfield;
/*  replace tbl (idfield = values.value) where values.#name = idfield and
 *	tbl.idfield = oldid and tbl.txtfield = name
 */
    EXEC SQL SELECT value INTO :temp FROM numvalues 
	WHERE name = :idfield;
    sprintf(stmt_buf,"UPDATE %s SET %s = %d WHERE %s=%d AND %s='%s'",
	    tbl,idfield,temp,idfield,oldid,txtfield,name);
    EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
    EXEC SQL INQUIRE_SQL(:rowcount = rowcount); 
    if (rowcount == 1)
      printf("Fixed\n");
    else
      printf("Not fixed, rowcount = %d\n", rowcount);
    modified(tbl);
    return(id);
}
