📄 bsqldb.c
字号:
/* * Jump through hoops to determine a useful name for the computed column * If the query says "compute count(c) by a,b", we get a "by list" indicating a & b. */ bylist = dbbylist(dbproc, c+1, &nby); bynames = strdup("by ("); for (iby=0; iby < nby; iby++) { char *s = NULL; int ret = asprintf(&s, "%s%s%s", bynames, dbcolname(dbproc, bylist[iby]), (iby+1 < nby)? ", " : ")"); if (ret < 0) { fprintf(options.verbose, "Insufficient room to create name for column %d:\n", 1+c); break; } free(bynames); bynames = s; } if( altcolid == -1 ) { colname = "*"; } else { assert(0 < altcolid && altcolid <= dbnumcols(dbproc)); colname = metadata[--altcolid].name; } asprintf(&metacompute[i]->meta[c].name, "%s(%s)", dbprtype(dbaltop(dbproc, i+1, c+1)), colname); assert(metacompute[i]->meta[c].name); metacompute[i]->meta[c].width = get_printable_size(metacompute[i]->meta[c].type, metacompute[i]->meta[c].size); if (metacompute[i]->meta[c].width < strlen(metacompute[i]->meta[c].name)) metacompute[i]->meta[c].width = strlen(metacompute[i]->meta[c].name); ret = set_format_string(meta, (c+1 < metacompute[i]->numalts)? options.colsep : "\n"); if (ret <= 0) { free(bynames); fprintf(stderr, "%s:%d: asprintf(), column %d failed\n", options.appname, __LINE__, c+1); return; } fprintf(options.verbose, "\tcolumn %d is %s, type %s, size %d %s\n", c+1, metacompute[i]->meta[c].name, dbprtype(metacompute[i]->meta[c].type), metacompute[i]->meta[c].size, (nby > 0)? bynames : ""); free(bynames); /* allocate buffer */ assert(metacompute[i]->data); metacompute[i]->data[c].buffer = calloc(1, metacompute[i]->meta[c].width); assert(metacompute[i]->data[c].buffer); /* bind */ erc = dbaltbind(dbproc, i+1, c+1, bindtype, -1, (BYTE*) metacompute[i]->data[c].buffer); if (erc == FAIL) { fprintf(stderr, "%s:%d: dbaltbind(), column %d failed\n", options.appname, __LINE__, c+1); return; } } } fprintf(options.verbose, "\n"); fprintf(options.verbose, "Data\n"); if (!options.fquiet) { /* Print the column headers to stderr to keep them separate from the data. */ for (c=0; c < ncols; c++) { fprintf(options.headers, metadata[c].format_string, metadata[c].name); } /* Underline the column headers. */ for (c=0; c < ncols; c++) { fprintf(options.headers, metadata[c].format_string, dashes); } } /* * Print the data to stdout. */ while ((row_code = dbnextrow(dbproc)) != NO_MORE_ROWS) { switch (row_code) { case REG_ROW: for (c=0; c < ncols; c++) { switch (data[c].status) { /* handle nulls */ case -1: /* is null */ /* TODO: FreeTDS 0.62 does not support dbsetnull() */ fprintf(stdout, metadata[c].format_string, "NULL"); break; case 0: /* case >1 is datlen when buffer is too small */ default: fprintf(stdout, metadata[c].format_string, data[c].buffer); break; } } break; case BUF_FULL: assert(row_code != BUF_FULL); break; case FAIL: fprintf(stderr, "bsqldb: fatal error: dbnextrow returned FAIL\n"); assert(row_code != FAIL); exit(EXIT_FAILURE); break; default: /* computeid */ fprintf(options.verbose, "Data for computeid %d\n", row_code); for (c=0; c < metacompute[row_code-1]->numalts; c++) { char fmt[256] = "%-"; struct METADATA *meta = &metacompute[row_code-1]->meta[c]; /* left justify the names */ strcat(fmt, &meta->format_string[1]); fprintf(options.headers, fmt, meta->name); } /* Underline the column headers. */ for (c=0; c < metacompute[row_code-1]->numalts; c++) { fprintf(options.headers, metacompute[row_code-1]->meta[c].format_string, dashes); } for (c=0; c < metacompute[row_code-1]->numalts; c++) { struct METADATA *meta = &metacompute[row_code-1]->meta[c]; struct DATA *data = &metacompute[row_code-1]->data[c]; switch (data->status) { /* handle nulls */ case -1: /* is null */ /* TODO: FreeTDS 0.62 does not support dbsetnull() */ fprintf(stdout, meta->format_string, "NULL"); break; case 0: /* case >1 is datlen when buffer is too small */ default: fprintf(stdout, meta->format_string, data->buffer); break; } } } } /* Check return status */ if (!options.fquiet) { fprintf(options.verbose, "Retrieving return status... "); if (dbhasretstat(dbproc) == TRUE) { fprintf(stderr, "Procedure returned %d\n", dbretstatus(dbproc)); } else { fprintf(options.verbose, "none\n"); } } /* * Get row count, if available. */ if (!options.fquiet) { if (DBCOUNT(dbproc) > -1) fprintf(stderr, "%d rows affected\n", DBCOUNT(dbproc)); else fprintf(stderr, "@@rowcount not available\n"); } /* * Check return parameter values */ fprintf(options.verbose, "Retrieving output parameters... "); if (dbnumrets(dbproc) > 0) { for (i = 1; i <= dbnumrets(dbproc); i++) { char parameter_string[1024]; return_status.name = dbretname(dbproc, i); fprintf(stderr, "ret name %d is %s\n", i, return_status.name); return_status.type = dbrettype(dbproc, i); fprintf(options.verbose, "\n\tret type %d is %d", i, return_status.type); return_status.size = dbretlen(dbproc, i); fprintf(options.verbose, "\n\tret len %d is %d\n", i, return_status.size); dbconvert(dbproc, return_status.type, dbretdata(dbproc, i), return_status.size, SYBVARCHAR, (BYTE *) parameter_string, -1); fprintf(stderr, "ret data %d is %s\n", i, parameter_string); } } else { fprintf(options.verbose, "none\n"); } } /* wend dbresults */ fprintf(options.verbose, "%s:%d: dbresults() returned NO_MORE_RESULTS (%d):\n", options.appname, __LINE__, erc);}static intget_printable_size(int type, int size) /* adapted from src/dblib/dblib.c */{ switch (type) { case SYBINTN: switch (size) { case 1: return 3; case 2: return 6; case 4: return 11; case 8: return 21; } case SYBINT1: return 3; case SYBINT2: return 6; case SYBINT4: return 11; case SYBINT8: return 21; case SYBVARCHAR: case SYBCHAR: return size; case SYBFLT8: return 11; /* FIX ME -- we do not track precision */ case SYBREAL: return 11; /* FIX ME -- we do not track precision */ case SYBMONEY: return 12; /* FIX ME */ case SYBMONEY4: return 12; /* FIX ME */ case SYBDATETIME: return 26; /* FIX ME */ case SYBDATETIME4: return 26; /* FIX ME */#if 0 /* seems not to be exported to sybdb.h */ case SYBBITN:#endif case SYBBIT: return 1; /* FIX ME -- not all types present */ default: return 0; }}/** * Build the column header format string, based on the column width. * This is just one solution to the question, "How wide should my columns be when I print them out?" */#define is_character_data(x) (x==SYBTEXT || x==SYBCHAR || x==SYBVARCHAR)static intset_format_string(struct METADATA * meta, const char separator[]){ int width, ret; const char *size_and_width; assert(meta); if(0 == strcmp(options.colsep, default_colsep)) { /* right justify numbers, left justify strings */ size_and_width = is_character_data(meta->type)? "%%-%d.%ds%s" : "%%%d.%ds%s"; width = get_printable_size(meta->type, meta->size); if (width < strlen(meta->name)) width = strlen(meta->name); ret = asprintf(&meta->format_string, size_and_width, width, width, separator); } else { /* For anything except the default two-space separator, don't justify the strings. */ ret = asprintf(&meta->format_string, "%%s%s", separator); } return ret;}static voidusage(const char invoked_as[]){ fprintf(stderr, "usage: %s \n" " [-U username] [-P password]\n" " [-S servername] [-D database]\n" " [-i input filename] [-o output filename] [-e error filename]\n" , invoked_as);}static void unescape(char arg[]){ char *p = arg; char escaped = '1'; /* any digit will do for an initial value */ while ((p = strchr(p, '\\')) != NULL) { switch (p[1]) { case '0': /* FIXME we use strlen() of field/row terminators, which obviously won't work here */ fprintf(stderr, "bsqldb, line %d: NULL terminators ('\\0') not yet supported.\n", __LINE__); escaped = '\0'; break; case 't': escaped = '\t'; break; case 'r': escaped = '\r'; break; case 'n': escaped = '\n'; break; case '\\': escaped = '\\'; break; default: break; } /* Overwrite the backslash with the intended character, and shift everything down one */ if (!isdigit((unsigned char) escaped)) { *p++ = escaped; memmove(p, p+1, 1 + strlen(p+1)); escaped = '1'; } }}LOGINREC *get_login(int argc, char *argv[], OPTIONS *options){ LOGINREC *login; int ch; extern char *optarg; assert(options && argv); options->appname = tds_basename(argv[0]); options->colsep = default_colsep; /* may be overridden by -t */ login = dblogin(); if (!login) { fprintf(stderr, "%s: unable to allocate login structure\n", options->appname); exit(1); } DBSETLAPP(login, options->appname); if (-1 == gethostname(options->hostname, sizeof(options->hostname))) { perror("unable to get hostname"); } else { DBSETLHOST(login, options->hostname); } while ((ch = getopt(argc, argv, "U:P:S:dD:i:o:e:t:hqv")) != -1) { switch (ch) { case 'U': DBSETLUSER(login, optarg); break; case 'P': DBSETLPWD(login, optarg); break; case 'S': options->servername = strdup(optarg); break; case 'd': case 'D': options->database = strdup(optarg); break; case 'i': options->input_filename = strdup(optarg); break; case 'o': options->output_filename = strdup(optarg); break; case 'e': options->error_filename = strdup(optarg); break; case 't': unescape(optarg); options->colsep = strdup(optarg); break; case 'h': options->headers = stdout; break; case 'q': options->fquiet = 1; break; case 'v': options->fverbose = 1; break; case '?': default: usage(options->appname); exit(1); } } if (!options->servername) { usage(options->appname); exit(1); } return login;}interr_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr){ if (dberr) { fprintf(stderr, "%s: Msg %d, Level %d\n", options.appname, dberr, severity); fprintf(stderr, "%s\n\n", dberrstr); } else { fprintf(stderr, "%s: DB-LIBRARY error:\n\t", options.appname); fprintf(stderr, "%s\n", dberrstr); } return INT_CANCEL;}intmsg_handler(DBPROCESS * dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line){ enum {changed_database = 5701, changed_language = 5703 }; if (msgno == changed_database || msgno == changed_language) return 0; if (msgno > 0) { fprintf(stderr, "Msg %ld, Level %d, State %d\n", (long) msgno, severity, msgstate); if (strlen(srvname) > 0) fprintf(stderr, "Server '%s', ", srvname); if (strlen(procname) > 0) fprintf(stderr, "Procedure '%s', ", procname); if (line > 0) fprintf(stderr, "Line %d", line); fprintf(stderr, "\n\t"); } fprintf(stderr, "%s\n", msgtext); if (severity > 10) { fprintf(stderr, "%s: error: severity %d >
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -