#include #include #include #define FALSE 0 #define TRUE 1 typedef struct s_collist { char tabname[20]; char colname[20]; char attrib[50]; int b_drop; } st_collist; typedef struct s_idxlist { char idxname[20]; char idxtable[20]; char idxspec[255]; int b_unique; int b_drop; } st_idxlist; static char *get_token(); static char *get_name(); static void parse_file(); static void addlist(); static void addidxlist(); static void gendiff(); static void genidxdiff(); static void coldrops(); static void tabdrops(); static void idxdrops(); static void different(); static st_collist *orglist; static st_idxlist *idxlist; static char *outbuf, *outptr; static int orglistend = 0; static int idxlistend = 0; static int b_different = FALSE; /*********************************************************************** MAIN ***********************************************************************/ main(argc, argv) int argc; char **argv; { int filepos1, filepos2; if ((argc != 3 && argc != 4) || (argc == 4 && strcmp(argv[1], "-d"))) { printf("SCHEMADIFF V1.1 - Copyright (c) 1995 - Guy A. Molinari\n\n"); printf("Usage: schemadiff {-d} [srcfile] [destfile]\n"); printf(" : {-d} Don't drop tables/indexes (optional).\n"); printf(" : [srcfile] Source schema script.\n"); printf(" : [destfile] Destination schema script.\n"); printf(" : Differences are generated to standard output.\n\n"); exit(-1); } if (argc == 3) { filepos1 = 1; filepos2 = 2; } else { filepos1 = 2; filepos2 = 3; } orglist = (st_collist*) calloc(5000, sizeof(st_collist)); idxlist = (st_idxlist*) calloc(500, sizeof(st_idxlist)); outbuf = (char*) malloc(8192); if (orglist == NULL || idxlist == NULL || outbuf == NULL) { fprintf(stderr, "Memory allocation error.\n"); exit(-2); } outptr = outbuf; parse_file(argv[filepos1], addlist, addidxlist); parse_file(argv[filepos2], gendiff, genidxdiff); gendiff(NULL, NULL, NULL); if (argc == 3) { tabdrops(); idxdrops(); } free(orglist); free(idxlist); free(outbuf); if (b_different) exit(1); else exit(0); } /*********************************************************************** PARSE_FILE ***********************************************************************/ void parse_file(fname, actionfunc, indexfunc) char *fname; void (*actionfunc)(); void (*indexfunc)(); { char currtable[20]; char currcolumn[20]; char currattrib[50]; char currindex[20]; char currindextable[20]; char curridxspec[255]; char buf[255], *bufptr, *ptr2; int b_intable; int b_unique; int linecnt; FILE* fileptr; if((fileptr = fopen(fname, "r")) == NULL) { fprintf(stderr, "Error opening file: %s\n", fname); exit(-3); } /* parse table */ b_intable = FALSE; linecnt = 0; while(fgets(buf, 254, fileptr) != NULL) { linecnt++; if(!b_intable) { /* look for 'create table' */ if((bufptr = get_token(buf, "create table")) != NULL) { bufptr += strlen("create table"); memset(currtable, '\0', 1); if((bufptr = get_name(bufptr)) == NULL) { fprintf(stderr, "[%s.%d] Error: missing table name.\n", fname, linecnt); exit(-4); } else strcpy(currtable, bufptr); if(fgets(buf, 254, fileptr) != NULL) { linecnt++; if((bufptr = get_token(buf, "(")) != NULL) b_intable = TRUE; else { fprintf(stderr, "[%s.%d] Error: Missing '('.\n", fname, linecnt); exit(-5); } } else { fprintf(stderr, "[%s] End of file reached looking for '('.\n", fname); exit(-6); } } /* end if get_token("create table") */ } else /* if (!b_intable) */ { /* check for end of table definition */ if((bufptr = get_token(buf, ");")) != NULL) { b_intable = FALSE; strcpy(buf, "\n"); } else { /* get column name */ bufptr = buf; memset(currcolumn, '\0', 1); if((bufptr = get_name(bufptr)) == NULL) { fprintf(stderr, "[%s.%d] Error: missing column name.\n", fname, linecnt); exit(-7); } else strcpy(currcolumn, bufptr); bufptr += strlen(currcolumn) + 1; /* get attribute */ while(isspace(*bufptr)) bufptr++; strcpy(currattrib, bufptr); bufptr = currattrib; while(isprint(*bufptr)) bufptr++; *bufptr = '\0'; if(!strlen(currattrib)) { fprintf(stderr, "[%s.%d] Error: missing column attribute.\n", fname, linecnt); exit(-8); } bufptr = currattrib + strlen(currattrib) - 1; if (*bufptr == ',') *bufptr = '\0'; (*actionfunc)(currtable, currcolumn, currattrib); } /* if((bufptr = get_token(buf, ");")) != NULL) */ } /* end if (!b_intable) */ if(!b_intable) { if((bufptr = get_token(buf, "create index")) != NULL || (bufptr = get_token(buf, "create unique index")) != NULL) { if (!strncmp(bufptr, "create unique index", strlen("create unique index"))) { bufptr += strlen("create unique index"); b_unique = TRUE; } else { bufptr += strlen("create index"); b_unique = FALSE; } if ((bufptr = get_name(bufptr)) == NULL) { fprintf(stderr, "[%s.%d] Error: missing index name.\n", fname, linecnt); exit(-9); } else { strcpy(currindex, bufptr); bufptr += strlen(currindex) + 1; } if ((bufptr = get_token(bufptr, "on")) == NULL) { fprintf(stderr, "[%s.%d] Error: missing 'on' keyword.\n", fname, linecnt); exit(-10); } else bufptr += strlen("on") + 1; /* Get index table name */ if((bufptr = get_name(bufptr)) == NULL) { fprintf(stderr, "[%s.%d] Error: missing table name.\n", fname, linecnt); exit(-11); } else { strcpy(currindextable, bufptr); bufptr += strlen(currindextable) + 1; } /* Get index specifier */ ptr2 = curridxspec; while (*bufptr) { while (isspace(*bufptr)) bufptr++; while (!isspace(*bufptr) && *bufptr) *ptr2++ = *bufptr++; } *ptr2 = '\0'; /* is this line terminated */ if (*(ptr2 - 2) != ')' && *(ptr2 - 1) != ';') { if (fgets(buf, 254, fileptr) == NULL) { fprintf(stderr, "[%s] End of file reached in create index.\n", fname); exit(-12); } bufptr = buf; while (*bufptr) { while (isspace(*bufptr)) bufptr++; while (!isspace(*bufptr) && *bufptr) *ptr2++ = *bufptr++; } *ptr2 = '\0'; } (*indexfunc)(currindex, currindextable, curridxspec, b_unique); } /* end if ((bufptr = get_token(buf, "create index")) != NULL) */ } /* end if (check for create index) */ } /* end while(fgets "fileptr" */ if(b_intable) { fprintf(stderr, "[%s] End of file reached looking for ');'.\n", fname); exit(-13); } } /*********************************************************************** GET_TOKEN ***********************************************************************/ char* get_token(buf, token) char *buf; char *token; { char first = *token; char *chrpos; int i, len; chrpos = buf; while((chrpos = strchr(chrpos, (int) first)) != NULL) { if(!strncmp(chrpos, token, strlen(token))) return chrpos; chrpos++; } return NULL; } /*********************************************************************** GET_NAME ***********************************************************************/ char* get_name(buf) char* buf; { char *retbuf, *ptr2; while(isspace(*buf)) buf++; if(*buf == '"') { while(*buf != '.') buf++; buf++; } retbuf = buf; if(isalpha(*buf)) { while(isalnum(*buf) || *buf == '_') buf++; if (!isspace(*buf)) for (ptr2 = buf + strlen(buf) + 1; ptr2 > buf; ptr2--) *ptr2 = *(ptr2 - 1); *buf = '\0'; return retbuf; } else return NULL; } /*********************************************************************** ADDLIST ***********************************************************************/ void addlist(table, column, attrib) char *table, *column, *attrib; { strcpy(orglist[orglistend].tabname, table); strcpy(orglist[orglistend].colname, column); strcpy(orglist[orglistend].attrib, attrib); orglist[orglistend].b_drop = TRUE; orglistend++; } /*********************************************************************** ADDIDXLIST ***********************************************************************/ void addidxlist(idxname, idxtable, idxspec, b_unique) char *idxname, *idxtable, *idxspec; int b_unique; { strcpy(idxlist[idxlistend].idxname, idxname); strcpy(idxlist[idxlistend].idxtable, idxtable); strcpy(idxlist[idxlistend].idxspec, idxspec); idxlist[idxlistend].b_unique = b_unique; idxlist[idxlistend].b_drop = TRUE; idxlistend++; } /*********************************************************************** GENDIFF ***********************************************************************/ void gendiff(table, column, attrib) char *table, *column, *attrib; { static int colpos = 0; static char currtable[20]; static int b_create = FALSE; static int b_alter = FALSE; static int b_terminate = FALSE; int fndpos; if (strcmp(currtable, table)) { /* lookahead for drop columns */ if(colpos >= 0 && !strcmp(orglist[colpos].tabname, currtable) && !b_alter && orglistend > 0) { outptr += sprintf(outptr, "alter table %s\n", currtable); b_terminate = TRUE; } b_alter = FALSE; coldrops(currtable); strcpy(currtable, table); if(b_terminate) { different(); if(b_create) printf("\n );\n\n"); else { outptr -= 2; outptr += sprintf(outptr, ";\n\n"); printf("%s", outbuf); outptr = outbuf; } b_terminate = FALSE; } if ((colpos = findtable(table)) == -1 && table != NULL) { different(); b_create = TRUE; printf("create table %s\n", table); printf(" (\n"); printf(" %s %s", column, attrib); b_terminate = TRUE; } else b_create = FALSE; } else { if (b_create) { printf(",\n %s %s", column, attrib); b_terminate = TRUE; } } /* alter table mode */ if (colpos != -1 && column != NULL) { if (strcmp(orglist[colpos].colname, column) || strcmp(orglist[colpos].attrib, attrib)) { if(!b_alter) { b_alter = TRUE; outptr += sprintf(outptr, "alter table %s\n", table); b_terminate = TRUE; } if (strcmp(orglist[colpos].colname, column)) { if ((fndpos = findentry(table, column)) == -1) { if (strcmp(orglist[colpos].tabname, table)) outptr += sprintf(outptr, " add (%s %s),\n", column, attrib); else outptr += sprintf(outptr, " add (%s %s before %s),\n", column, attrib, orglist[colpos].colname); } else { /* skip over drop columns */ colpos = fndpos + 1; orglist[fndpos].b_drop = FALSE; } } else { outptr += sprintf(outptr, " modify (%s %s),\n", column, attrib); orglist[colpos].b_drop = FALSE; colpos++; } } else { orglist[colpos].b_drop = FALSE; colpos++; } } /* end if (strncmp(currtable, table, strlen(table))) */ } /*********************************************************************** GENIDXDIFF ***********************************************************************/ void genidxdiff(index, idxtable, idxspec, b_unique) char *index, *idxtable, *idxspec; int b_unique; { int fndpos; /* make sure all line termination has been done for table processing */ gendiff(NULL, NULL, NULL); if ((fndpos = findindex(index)) != -1) { idxlist[fndpos].b_drop = FALSE; if (strcmp(idxlist[fndpos].idxspec, idxspec) || idxlist[fndpos].b_unique != b_unique) { different(); printf("drop index %s;\n", index); if(b_unique) printf("create unique index %s on %s %s\n\n", index, idxtable, idxspec); else printf("create index %s on %s %s\n\n", index, idxtable, idxspec); } } else { different(); if(b_unique) printf("create unique index %s on %s %s\n\n", index, idxtable, idxspec); else printf("create index %s on %s %s\n\n", index, idxtable, idxspec); } } /*********************************************************************** COLDROPS ***********************************************************************/ void coldrops(table) char *table; { int listcnt; if ((listcnt = findtable(table)) != -1) { while (listcnt < orglistend && !strcmp(orglist[listcnt].tabname, table)) { if (orglist[listcnt].b_drop) { outptr += sprintf(outptr, " drop (%s),\n", orglist[listcnt].colname); } listcnt++; } } } /*********************************************************************** TABDROPS ***********************************************************************/ void tabdrops() { int listcnt, b_dropall, fndpos; char currtable[20]; memset(currtable, '\0', 1); /* Add a dummy entry in case last table in list needs to be dropped */ addlist("XXX", "XXX", "XXX"); for (listcnt = 0; listcnt < orglistend; listcnt++) { if (strcmp(orglist[listcnt].tabname, currtable)) { if (strlen(currtable)) { if (b_dropall) { different(); printf("drop table %s;\n\n", currtable); /* Cancel index drops for this table */ fndpos = -1; while ((fndpos = find_table_index(currtable, fndpos + 1)) != -1) idxlist[fndpos].b_drop = FALSE; } } b_dropall = TRUE; strcpy(currtable, orglist[listcnt].tabname); } if (!orglist[listcnt].b_drop && b_dropall) b_dropall = FALSE; } } /*********************************************************************** IDXDROPS ***********************************************************************/ void idxdrops() { int listcnt; for (listcnt = 0; listcnt < idxlistend; listcnt++) { if (idxlist[listcnt].b_drop) { different(); printf("drop index %s;\n\n", idxlist[listcnt].idxname); } } } /*********************************************************************** FINDENTRY ***********************************************************************/ int findentry(table, column) char *table, *column; { int i; for (i = 0; i < orglistend; i++) if (!strcmp(orglist[i].tabname, table) && !strcmp(orglist[i].colname, column)) return i; return -1; } /*********************************************************************** FINDTABLE ***********************************************************************/ int findtable(table) char *table; { int i; for (i = 0; i < orglistend; i++) if (!strcmp(orglist[i].tabname, table)) return i; return -1; } /*********************************************************************** FINDINDEX ***********************************************************************/ int findindex(index) char *index; { int i; for (i = 0; i < idxlistend; i++) if (!strcmp(idxlist[i].idxname, index)) return i; return -1; } /*********************************************************************** FIND_TABLE_INDEX(table, startpos) ***********************************************************************/ int find_table_index(table, startpos) char *table; int startpos; { int i; for (i = startpos; i < idxlistend; i++) if (!strcmp(idxlist[i].idxtable, table)) return i; return -1; } /*********************************************************************** DIFFERENT ***********************************************************************/ void different() { if(!b_different) { b_different = TRUE; printf("{ SCHEMADIFF Version 1.1 - Guy A. Molinari }\n"); printf("{ Copyright(c) 1995, All Rights Reserved }\n\n"); } }