/* $Id$ * * User interface routines for dbck (Moira database consistency checker) * * (c) Copyright 1988-1998 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . */ #include #include #include "dbck.h" #include EXEC SQL INCLUDE sqlca; /* SQL Communications Area */ EXEC SQL INCLUDE sqlda; /* SQL Descriptor Area */ RCSID("$Header$"); EXEC SQL BEGIN DECLARE SECTION; char *_table; char *_idfield; char stmt_buf[500]; EXEC SQL END DECLARE SECTION; extern SQLDA *mr_sqlda; void generic_ffunc(void *id); void generic_ffunc(void *id) { int rowcount; sprintf(stmt_buf, "DELETE FROM %s WHERE %s.%s = %d", _table, _table, _idfield, (int)id); EXEC SQL EXECUTE IMMEDIATE :stmt_buf; rowcount = sqlca.sqlerrd[2]; if (rowcount > 0) printf("%d entr%s deleted\n", rowcount, rowcount == 1 ? "y" : "ies"); else printf("Not deleted\n"); modified(_table); } void generic_delete(struct save_queue *sq, int (*pfunc)(void *), char *table, char *idfield, int preen) { _table = table; _idfield = idfield; generic_fix(sq, pfunc, "Delete", generic_ffunc, preen); } void single_delete(char *table, char *idfield, int id) { _table = table; _idfield = idfield; generic_ffunc((void *)id); } void zero_fix(char *tbl, char *zrfield, char *idfield, int id) { int rowcount; sprintf(stmt_buf, "UPDATE %s SET %s = 0 WHERE %s.%s = %d", tbl, zrfield, tbl, idfield, id); EXEC SQL EXECUTE IMMEDIATE :stmt_buf; rowcount = sqlca.sqlerrd[2]; if (rowcount > 0) printf("%d entr%s fixed\n", rowcount, rowcount == 1 ? "y" : "ies"); else printf("Not fixed\n"); modified(tbl); } int single_fix(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; } void generic_fix(struct save_queue *sq, int (*pfunc)(void *), char *msg, void (*ffunc)(void *), int preen) { int id; while (sq_get_data(sq, &id)) { if ((*pfunc)((void *)id) == 0 && single_fix(msg, preen)) (*ffunc)((void *)id); } sq_destroy(sq); } int prompt(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")) { EXEC SQL COMMIT WORK; cleanup(); exit(0); } else { EXEC SQL ROLLBACK WORK; EXEC SQL UPDATE numvalues SET value = :dcmenable WHERE name = 'dcm_enable'; 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(char *object, char *tablename) { EXEC SQL BEGIN DECLARE SECTION; int value; char stmt_buf[256], out_buf[256]; EXEC SQL END DECLARE SECTION; int starting_value, errcode = 0; EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :object; if (sqlca.sqlerrd[2] != 1) return MR_NO_ID; starting_value = value; while (1) { if (value > MAX_ID_VALUE) value = MIN_ID_VALUE; sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = %d", object, tablename, object, value); EXEC SQL PREPARE inc_stmt FROM :stmt_buf; EXEC SQL DECLARE inc_crs CURSOR FOR inc_stmt; EXEC SQL OPEN inc_crs; mr_sqlda->N = 1; EXEC SQL DESCRIBE SELECT LIST FOR inc_stmt INTO mr_sqlda; mr_sqlda->N = mr_sqlda->F; mr_sqlda->V[0] = out_buf; mr_sqlda->T[0] = 97; mr_sqlda->L[0] = 255; EXEC SQL FETCH inc_crs USING DESCRIPTOR mr_sqlda; /* if we got an error from the FETCH, we have to preserve it or the close will reset it and the caller with think nothing happened */ if (sqlca.sqlcode) errcode = sqlca.sqlcode; EXEC SQL CLOSE inc_crs; if (errcode < 0) return MR_DBMS_ERR; if (errcode == 1403) break; value++; if (value == starting_value) return MR_NO_ID; } printf("setting ID %s to %d\n", object, value); EXEC SQL UPDATE numvalues SET value = :value WHERE name = :object; modified("values"); return MR_SUCCESS; } int generic_fix_id(char *tbl, char *idfield, char *txtfield, int oldid, char *name) { EXEC SQL BEGIN DECLARE SECTION; int rowcount, id; EXEC SQL END DECLARE SECTION; set_next_object_id(tbl, idfield); EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = :idfield; sprintf(stmt_buf, "UPDATE %s SET %s = %d WHERE %s = %d AND %s = '%s'", tbl, idfield, id, idfield, oldid, txtfield, name); EXEC SQL EXECUTE IMMEDIATE :stmt_buf; rowcount = sqlca.sqlerrd[2]; if (rowcount == 1) printf("Fixed\n"); else printf("Not fixed, rowcount = %d\n", rowcount); modified(tbl); return id; }