/* ---------------------------------------------------------------------- (C) Copyright Marxmeier Software AG 2006,2007 Project: Eloquence database File: fwsql.c Function: fw log test Edit History: 29.05.2006, mike - creation 29.03.2007, rhg - code cleanup ---------------------------------------------------------------------- */ static const char RcsId[] = "$Id: fwsql.c,v 25.1 2008/04/23 13:41:32 mike Exp $"; #if defined(_WIN32) #include #endif #include #include #include #include #if defined(_WIN32) #include "getopt.h" #endif #include "fwutil.h" /*------------------------------------------------------------------------ module definitions ------------------------------------------------------------------------*/ #define DEFAULT_STATUS_FILE "fwsql.stat" /*------------------------------------------------------------------------ forward references ------------------------------------------------------------------------*/ static char *argv0; static void usage(void); static int sql_cb(int db_node_id, const char *db_name, const char *set_name, time_t timestamp, enum Fwu_OP op, unsigned int recno, int recsz, const void *bi_rec, const void *ai_rec); /*------------------------------------------------------------------------ main ------------------------------------------------------------------------*/ #if defined(_WIN32) HINSTANCE hInst; #endif int main(int argc, char *argv[]) { extern char *optarg; extern int optind, /* opterr, */ optopt; int c; int errflg; char *cfg_file; char *status_file; char *fwlog_generation; int print_status, verbose; #if defined(_WIN32) hInst = (HINSTANCE)GetModuleHandle(NULL); #endif /* ---------------------------------------- welcome ---------------------------------------- */ argv0 = argv[0]; if(argc == 2 && !strcmp(argv[1], "-help")) usage(); /* ---------------------------------------- handle commandline args ---------------------------------------- */ cfg_file = NULL; status_file = DEFAULT_STATUS_FILE; fwlog_generation = NULL; print_status = verbose = 0; errflg = 0; while( (c = getopt(argc,argv, "c:vSf:n:I")) != EOF ) { switch(c) { case 'c': cfg_file = optarg; break; case 'v': verbose++; Fwu_verbose(1); break; case 'S': Fwu_synconly(1); break; case 'f': status_file = optarg; break; case 'n': fwlog_generation = optarg; break; case 'I': print_status = 1; break; case ':': fprintf(stderr, "Option -%c requires an argument\n", optopt); errflg++; break; case '?': fprintf(stderr, "Unrecognized option: - %c\n", optopt); errflg++; break; default: errflg++; break; } } if( optind != argc ) { fprintf(stderr, "%s: Unexpected arguments\n", argv[0]); errflg++; } if( errflg ) usage(); if(print_status) { if(verbose) printf("%s:\n", status_file); Fwu_status(status_file, verbose); return 0; } /* ---------------------------------------- process fwlog ---------------------------------------- */ return Fwu_process(sql_cb, cfg_file, status_file, fwlog_generation); } /*------------------------------------------------------------------------ usage ------------------------------------------------------------------------*/ static void usage() { fprintf(stderr, "usage: %s [options]\n", argv0); fprintf(stderr, "options:\n"); fprintf(stderr, " -help - show usage (this list)\n"); fprintf(stderr, " -c cfg - server configuration file\n"); fprintf(stderr, " -v - verbose, display progress\n"); fprintf(stderr, " -S - synchronize on existing log, then exit\n"); fprintf(stderr, " -f statfile - status file (default: %s)\n", DEFAULT_STATUS_FILE); fprintf(stderr, " -n generation - initialize from forward-log generation\n"); fprintf(stderr, " -I - print status file (-v to output details)\n"); fprintf(stderr, "\n"); exit(2); } /*------------------------------------------------------------------------ various text conversion helper functions ------------------------------------------------------------------------*/ #define QUOTE '\'' #define BACKSLASH '\\' /* temporary conversion buffer */ static char cv_buf[8192]; /*------------------------------------------------------------------------ cv_string() - export string ------------------------------------------------------------------------*/ void cv_string(FILE *fp, const unsigned char *buf, size_t size) { const unsigned char *p = buf+size; while(size) { if(*--p != ' ' /* && *p != '\0' */) break; size--; } /* FIXME: mask switch characters ... */ fputc(QUOTE, fp); while(size--) { int ch = *buf++ & 0xff; if(ch < 0x20 /* || (ch >= 0x80 && ch <= 0xa0) || ch == 0xff */) fprintf(fp, "\\%03o", ch); else { if(ch == QUOTE || ch == BACKSLASH) fputc(BACKSLASH, fp); fputc(ch, fp); } } fputc(QUOTE, fp); } /*------------------------------------------------------------------------ cv_binary() - export binary ------------------------------------------------------------------------*/ void cv_binary(FILE *fp, const unsigned char *buf, size_t size) { const unsigned char *p = buf+size; while(size) { if(*--p != '\0') break; size--; } /* FIXME: mask switch characters ... */ fputc(QUOTE, fp); while(size--) { int ch = *buf++ & 0xff; if(ch < 0x20 /* || (ch >= 0x80 && ch <= 0xa0) || ch == 0xff */) fprintf(fp, "\\%03o", ch); else { if(ch == QUOTE || ch == BACKSLASH) fputc(BACKSLASH, fp); fputc(ch, fp); } } fputc(QUOTE, fp); } /*------------------------------------------------------------------------ cv_signed_int() - export integer value ------------------------------------------------------------------------*/ void cv_signed_int(FILE *fp, const unsigned char *buf, size_t size) { int over; over = Fwu_fmt_signed_int(cv_buf, sizeof(cv_buf), buf, size); assert(!over); fwrite(cv_buf, strlen(cv_buf), 1, fp); } /*------------------------------------------------------------------------ cv_unsigned_int() - export unsigned integer value ------------------------------------------------------------------------*/ void cv_unsigned_int(FILE *fp, const unsigned char *buf, size_t size) { int over; over = Fwu_fmt_unsigned_int(cv_buf, sizeof(cv_buf), buf, size); assert(!over); fwrite(cv_buf, strlen(cv_buf), 1, fp); } /*------------------------------------------------------------------------ cv_ieee_float() - export IEEE floating point ------------------------------------------------------------------------*/ void cv_ieee_float(FILE *fp, const unsigned char *buf, size_t size) { int over; over = Fwu_fmt_ieee_float(cv_buf, sizeof(cv_buf), buf, size); assert(!over); fwrite(cv_buf, strlen(cv_buf), 1, fp); } /*------------------------------------------------------------------------ cv_zoned() - export packed decimal ------------------------------------------------------------------------*/ int verify_zoned(const void *v_p, int v_len); void cv_zoned(FILE *fp, const unsigned char *buf, size_t size) { int over; if( verify_zoned(buf, size) ) { strcpy(cv_buf, "??"); } else { over = Fwu_fmt_zoned(cv_buf, sizeof(cv_buf), buf, size); assert(!over); } fwrite(cv_buf, strlen(cv_buf), 1, fp); } /* verify if zoned decimal value is valid returns 0 if valid, -1 if invalid */ int verify_zoned(const void *v_p, int v_len) { const unsigned char *vv_p = v_p; int dgt; assert(v_len > 0); dgt = vv_p[--v_len]; if(!( dgt >= '0' && dgt <= '9' /* unsigned digit */ || dgt == '{' /* positive zero */ || dgt == '}' /* negative zero */ || dgt >= 'A' && dgt <= 'T')) /* positive/negative digit */ return -1; while(v_len--) { dgt = *vv_p++; if(dgt < '0' || dgt > '9') return -1; /* invalid digit */ } return 0; } /*------------------------------------------------------------------------ cv_packed() - export packed decimal ------------------------------------------------------------------------*/ int verify_packed(const void *v_p, int v_len); void cv_packed(FILE *fp, const unsigned char *buf, size_t size) { int over; if( verify_packed(buf, size) ) { strcpy(cv_buf, "??"); } else { over = Fwu_fmt_packed(cv_buf, sizeof(cv_buf), buf, size); assert(!over); } fwrite(cv_buf, strlen(cv_buf), 1, fp); } /* verify if packed decimal value is valid returns 0 if valid, -1 if invalid */ int verify_packed(const void *v_p, int v_len) { int sign_nbl, last_dgt, byte, hn, ln; const unsigned char *vv_p = v_p; assert(v_len > 0); v_len--; sign_nbl = vv_p[v_len] & 0xf; last_dgt = vv_p[v_len] >> 4; /* sign_nbl is not checked, an invlaid value is assumed to indicate an unsigned value (as hinted in the docs) */ if(last_dgt > 9) return -1; /* invalid digit */ while(v_len--) { byte = *vv_p++; hn = byte >> 4; ln = byte & 0xf; if(hn > 9 || ln > 9) return -1; /* invalid digit */ } return 0; } void cv_item(int type, FILE *fp, const unsigned char *v_p, int v_len) { switch(type) { case 'X': case 'U': cv_string(fp, v_p, v_len); break; case 'B': cv_binary(fp, v_p, v_len); break; case 'I': cv_signed_int(fp, v_p, v_len); break; case 'K': cv_unsigned_int(fp, v_p, v_len); break; case 'E': cv_ieee_float(fp, v_p, v_len); break; case 'P': cv_packed(fp, v_p, v_len); break; case 'Z': cv_zoned(fp, v_p, v_len); break; default: fprintf(stderr, "Unexpected item type %x\n", type); abort(); } } /*------------------------------------------------------------------------ callback ------------------------------------------------------------------------*/ static int sql_cb(int db_node_id, const char *db_name, const char *set_name, time_t timestamp, enum Fwu_OP op, unsigned int recno, int recsz, const void *bi_rec, const void *ai_rec) { unsigned char *p; int i_type, i_count, i_size, ofs, first; unsigned int i_fmt; const char *i_name; switch (op) { // INSERT INTO n [(...)] VALUES(...); case Fwu_OP_PUT: printf("INSERT INTO %s.%s VALUES(%u,", db_name, set_name, recno); ofs = first = 0; while( Fwu_get_item(&i_name, &i_type, &i_size, &i_count, &i_fmt) ) { while(i_count--) { if(first++) printf(","); p = (unsigned char *)ai_rec + ofs; cv_item(i_type, stdout, p, i_size); ofs += i_size; } } assert(ofs == recsz); printf(");\n"); break; // UPDATE n SET a=b WHERE RECNO=n; case Fwu_OP_UPDATE: ofs = first = 0; while( Fwu_get_item(&i_name, &i_type, &i_size, &i_count, &i_fmt) ) { int i; for(i = 0; i < i_count; i++) { if(memcmp((char *)ai_rec+ofs, (char *)bi_rec+ofs, i_size)) { if(first++) printf(","); else printf("UPDATE %s.%s SET ", db_name, set_name); fputs(i_name, stdout); if(i_count > 1) printf("_%d", i+1); fputs("=", stdout); p = (unsigned char *)ai_rec + ofs; cv_item(i_type, stdout, p, i_size); } ofs += i_size; } } assert(ofs == recsz); if(first) printf(" WHERE RECNO=%u;\n", recno); break; // DELETE n WHERE RECNO=n; case Fwu_OP_DELETE: assert(bi_rec != NULL); assert(ai_rec == NULL); printf("DELETE FROM %s.%s WHERE RECNO=%u;\n", db_name, set_name, recno); break; default: fprintf(stderr, "unexpected image op #%d\n", op); abort(); } // fflush(stdout); return 0; }