CDBL_ComputeResult::CDBL_ComputeResult(CDBL_Connection& conn, DBPROCESS* cmd, unsigned int* res_stat) : CDBL_ResultBase(conn, cmd, res_stat) { m_ComputeId = DBROWTYPE(cmd); if (m_ComputeId == REG_ROW || m_ComputeId == NO_MORE_ROWS) { DATABASE_DRIVER_ERROR( "No compute row found." + GetDbgInfo(), 270000 ); } unsigned int col_num = Check(dbnumalts(cmd, m_ComputeId)); if (col_num < 1) { DATABASE_DRIVER_ERROR( "Compute id is invalid." + GetDbgInfo(), 270001 ); } m_CmdNum = DBCURCMD(cmd); m_ColFmt = new SDBL_ColDescr[col_num]; for (unsigned int n = 0; n < col_num; n++) { m_ColFmt[n].max_length = Check(dbaltlen(GetCmd(), m_ComputeId, n+1)); m_ColFmt[n].data_type = AltGetDataType(m_ComputeId, n + 1); int op = Check(dbaltop(GetCmd(), m_ComputeId, n + 1)); const char* s = op != -1 ? Check(dbprtype(op)) : "Unknown"; m_ColFmt[n].col_name = s ? s : ""; m_CachedRowInfo.Add( s ? s : "", Check(dbaltlen(GetCmd(), m_ComputeId, n+1)), AltGetDataType(m_ComputeId, n + 1) ); } m_1stFetch = true; }
static void print_results(DBPROCESS *dbproc) { static const char empty_string[] = ""; static const char dashes[] = "----------------------------------------------------------------" /* each line is 64 */ "----------------------------------------------------------------" "----------------------------------------------------------------" "----------------------------------------------------------------"; struct METADATA *metadata = NULL, return_status; struct DATA { char *buffer; int status; } *data = NULL; struct METACOMP { int numalts; struct METADATA *meta; struct DATA *data; } **metacompute = NULL; RETCODE erc; int row_code; int i, c, ret; int iresultset; int ncomputeids = 0, ncols = 0; /* * If using default column separator, we want columns to line up vertically, * so we use blank padding (STRINGBIND). * For any other separator, we use no padding. */ const int bindtype = (0 == strcmp(options.colsep, default_colsep))? STRINGBIND : NTBSTRINGBIND; /* * Set up each result set with dbresults() * This is more commonly implemented as a while() loop, but we're counting the result sets. */ fprintf(options.verbose, "%s:%d: calling dbresults: OK\n", options.appname, __LINE__); for (iresultset=1; (erc = dbresults(dbproc)) != NO_MORE_RESULTS; iresultset++) { if (erc == FAIL) { fprintf(stderr, "%s:%d: dbresults(), result set %d failed\n", options.appname, __LINE__, iresultset); return; } if (options.pivot.func) { const struct key_t *rk = &options.pivot.row_key, *ck = &options.pivot.col_key; erc = dbpivot(dbproc, rk->nkeys, rk->keys, ck->nkeys, ck->keys, options.pivot.func, options.pivot.val_col); } fprintf(options.verbose, "Result set %d\n", iresultset); /* Free prior allocations, if any. */ for (c=0; c < ncols; c++) { free(metadata[c].format_string); free(data[c].buffer); } free(metadata); metadata = NULL; free(data); data = NULL; ncols = 0; for (i=0; i < ncomputeids; i++) { for (c=0; c < metacompute[i]->numalts; c++) { free(metacompute[i]->meta[c].name); free(metacompute[i]->meta[c].format_string); } free(metacompute[i]->meta); free(metacompute[i]->data); free(metacompute[i]); } free(metacompute); metacompute = NULL; ncomputeids = 0; /* * Allocate memory for metadata and bound columns */ fprintf(options.verbose, "Allocating buffers\n"); ncols = dbnumcols(dbproc); metadata = (struct METADATA*) calloc(ncols, sizeof(struct METADATA)); assert(metadata); data = (struct DATA*) calloc(ncols, sizeof(struct DATA)); assert(data); /* metadata is more complicated only because there may be several compute ids for each result set */ fprintf(options.verbose, "Allocating compute buffers\n"); ncomputeids = dbnumcompute(dbproc); if (ncomputeids > 0) { metacompute = (struct METACOMP**) calloc(ncomputeids, sizeof(struct METACOMP*)); assert(metacompute); } for (i=0; i < ncomputeids; i++) { metacompute[i] = (struct METACOMP*) calloc(ncomputeids, sizeof(struct METACOMP)); assert(metacompute[i]); metacompute[i]->numalts = dbnumalts(dbproc, 1+i); fprintf(options.verbose, "%d columns found in computeid %d\n", metacompute[i]->numalts, 1+i); if (metacompute[i]->numalts > 0) { fprintf(options.verbose, "allocating column %d\n", 1+i); metacompute[i]->meta = (struct METADATA*) calloc(metacompute[i]->numalts, sizeof(struct METADATA)); assert(metacompute[i]->meta); metacompute[i]->data = (struct DATA*) calloc(metacompute[i]->numalts, sizeof(struct DATA)); assert(metacompute[i]->data); } } /* * For each column, get its name, type, and size. * Allocate a buffer to hold the data, and bind the buffer to the column. * "bind" here means to give db-lib the address of the buffer we want filled as each row is fetched. * TODO: Implement dbcoltypeinfo() for numeric/decimal datatypes. */ fprintf(options.verbose, "Metadata\n"); fprintf(options.verbose, "%-6s %-30s %-30s %-15s %-6s %-6s \n", "col", "name", "source", "type", "size", "varies"); fprintf(options.verbose, "%.6s %.30s %.30s %.15s %.6s %.6s \n", dashes, dashes, dashes, dashes, dashes, dashes); for (c=0; c < ncols; c++) { /* Get and print the metadata. Optional: get only what you need. */ char *name = dbcolname(dbproc, c+1); metadata[c].name = strdup(name ? (const char *) name : empty_string); name = dbcolsource(dbproc, c+1); metadata[c].source = (name)? name : empty_string; metadata[c].type = dbcoltype(dbproc, c+1); metadata[c].size = dbcollen(dbproc, c+1); assert(metadata[c].size != -1); /* -1 means indicates an out-of-range request*/ fprintf(options.verbose, "%6d %30s %30s %15s %6d %6d \n", c+1, metadata[c].name, metadata[c].source, dbprtype(metadata[c].type), metadata[c].size, dbvarylen(dbproc, c+1)); /* * 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?" */ metadata[c].width = get_printable_size(metadata[c].type, metadata[c].size); if (metadata[c].width < strlen(metadata[c].name)) metadata[c].width = strlen(metadata[c].name); ret = set_format_string(&metadata[c], (c+1 < ncols)? options.colsep : "\n"); if (ret <= 0) { fprintf(stderr, "%s:%d: asprintf(), column %d failed\n", options.appname, __LINE__, c+1); return; } /* * Bind the column to our variable. * We bind everything to strings, because we want db-lib to convert everything to strings for us. * If you're performing calculations on the data in your application, you'd bind the numeric data * to C integers and floats, etc. instead. * * It is not necessary to bind to every column returned by the query. * Data in unbound columns are simply never copied to the user's buffers and are thus * inaccesible to the application. */ if (metadata[c].width < INT_MAX) { data[c].buffer = calloc(1, 1 + metadata[c].width); /* allow for null terminator */ assert(data[c].buffer); erc = dbbind(dbproc, c+1, bindtype, 0, (BYTE *) data[c].buffer); if (erc == FAIL) { fprintf(stderr, "%s:%d: dbbind(), column %d failed\n", options.appname, __LINE__, c+1); return; } erc = dbnullbind(dbproc, c+1, &data[c].status); if (erc == FAIL) { fprintf(stderr, "%s:%d: dbnullbind(), column %d failed\n", options.appname, __LINE__, c+1); return; } } else { /* We don't bind text buffers, but use dbreadtext instead. */ data[c].buffer = NULL; } } /* * Get metadata and bind the columns for any compute rows. */ for (i=0; i < ncomputeids; i++) { fprintf(options.verbose, "For computeid %d:\n", 1+i); for (c=0; c < metacompute[i]->numalts; c++) { /* read metadata */ struct METADATA *meta = &metacompute[i]->meta[c]; int nby, iby; BYTE *bylist; char *colname, *bynames; int altcolid = dbaltcolid(dbproc, i+1, c+1); metacompute[i]->meta[c].type = dbalttype(dbproc, i+1, c+1); metacompute[i]->meta[c].size = dbaltlen(dbproc, i+1, c+1); /* * 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++) { if (metadata[c].width == INT_MAX) { /* TEXT/IMAGE */ BYTE *p = dbdata(dbproc, c+1); size_t len = dbdatlen(dbproc, c+1); if (len == 0) { fputs("NULL", stdout); } else { BYTE *pend = p + len; switch(dbcoltype(dbproc, c+1)) { case SYBTEXT: if (fwrite(p, len, 1, stdout) != 1) { perror("could not write to output file"); exit(EXIT_FAILURE); } break; default: /* image, binary */ fprintf(stdout, "0x"); for (; p < pend; p++) { printf("%02hx", (unsigned short int)*p); } break; } } fprintf(stdout, metadata[c].format_string, ""); /* col/row separator */ continue; } 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); }
void print_results(DBPROCESS *dbproc) { static const char empty_string[] = ""; static const char dashes[] = "----------------------------------------------------------------" /* each line is 64 */ "----------------------------------------------------------------" "----------------------------------------------------------------" "----------------------------------------------------------------"; struct METADATA *metadata = NULL, return_status; struct DATA { char *buffer; int status; } *data = NULL; struct METACOMP { int numalts; struct METADATA *meta; struct DATA *data; } **metacompute = NULL; RETCODE erc; int row_code; int i, c, ret; int iresultset; int ncomputeids = 0, ncols = 0; /* * Set up each result set with dbresults() * This is more commonly implemented as a while() loop, but we're counting the result sets. */ fprintf(options.verbose, "%s:%d: calling dbresults OK:\n", options.appname, __LINE__); for (iresultset=1; (erc = dbresults(dbproc)) != NO_MORE_RESULTS; iresultset++) { if (erc == FAIL) { fprintf(stderr, "%s:%d: dbresults(), result set %d failed\n", options.appname, __LINE__, iresultset); return; } fprintf(options.verbose, "Result set %d\n", iresultset); /* Free prior allocations, if any. */ fprintf(options.verbose, "Freeing prior allocations\n", iresultset); for (c=0; c < ncols; c++) { free(metadata[c].format_string); free(data[c].buffer); } free(metadata); metadata = NULL; free(data); data = NULL; ncols = 0; for (i=0; i < ncomputeids; i++) { for (c=0; c < metacompute[i]->numalts; c++) { free(metacompute[i]->meta[c].name); free(metacompute[i]->meta[c].format_string); } free(metacompute[i]->meta); free(metacompute[i]->data); free(metacompute[i]); } free(metacompute); metacompute = NULL; ncomputeids = 0; /* * Allocate memory for metadata and bound columns */ fprintf(options.verbose, "Allocating buffers\n", iresultset); ncols = dbnumcols(dbproc); metadata = (struct METADATA*) calloc(ncols, sizeof(struct METADATA)); assert(metadata); data = (struct DATA*) calloc(ncols, sizeof(struct DATA)); assert(data); /* metadata is more complicated only because there may be several compute ids for each result set */ fprintf(options.verbose, "Allocating compute buffers\n", iresultset); ncomputeids = dbnumcompute(dbproc); if (ncomputeids > 0) { metacompute = (struct METACOMP**) calloc(ncomputeids, sizeof(struct METACOMP*)); assert(metacompute); } for (i=0; i < ncomputeids; i++) { metacompute[i] = (struct METACOMP*) calloc(ncomputeids, sizeof(struct METACOMP)); assert(metacompute[i]); metacompute[i]->numalts = dbnumalts(dbproc, 1+i); fprintf(options.verbose, "%d columns found in computeid %d\n", metacompute[i]->numalts, 1+i); if (metacompute[i]->numalts > 0) { fprintf(options.verbose, "allocating column %d\n", 1+i); metacompute[i]->meta = (struct METADATA*) calloc(metacompute[i]->numalts, sizeof(struct METADATA)); assert(metacompute[i]->meta); metacompute[i]->data = (struct DATA*) calloc(metacompute[i]->numalts, sizeof(struct DATA)); assert(metacompute[i]->data); } } /* * For each column, get its name, type, and size. * Allocate a buffer to hold the data, and bind the buffer to the column. * "bind" here means to give db-lib the address of the buffer we want filled as each row is fetched. * TODO: Implement dbcoltypeinfo() for numeric/decimal datatypes. */ fprintf(options.verbose, "Metadata\n", iresultset); fprintf(options.verbose, "%-6s %-30s %-30s %-15s %-6s %-6s \n", "col", "name", "source", "type", "size", "varys"); fprintf(options.verbose, "%.6s %.30s %.30s %.15s %.6s %.6s \n", dashes, dashes, dashes, dashes, dashes, dashes); for (c=0; c < ncols; c++) { int width; /* Get and print the metadata. Optional: get only what you need. */ char *name = dbcolname(dbproc, c+1); metadata[c].name = (name)? name : empty_string; name = dbcolsource(dbproc, c+1); metadata[c].source = (name)? name : empty_string; metadata[c].type = dbcoltype(dbproc, c+1); metadata[c].size = dbcollen(dbproc, c+1); assert(metadata[c].size != -1); /* -1 means indicates an out-of-range request*/ fprintf(options.verbose, "%6d %30s %30s %15s %6d %6d \n", c+1, metadata[c].name, metadata[c].source, dbprtype(metadata[c].type), metadata[c].size, dbvarylen(dbproc, c+1)); /* * 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?" */ width = get_printable_size(metadata[c].type, metadata[c].size); if (width < strlen(metadata[c].name)) width = strlen(metadata[c].name); ret = set_format_string(&metadata[c], (c+1 < ncols)? " " : "\n"); if (ret <= 0) { fprintf(stderr, "%s:%d: asprintf(), column %d failed\n", options.appname, __LINE__, c+1); return; } /* * Bind the column to our variable. * We bind everything to strings, because we want db-lib to convert everything to strings for us. * If you're performing calculations on the data in your application, you'd bind the numeric data * to C integers and floats, etc. instead. * * It is not necessary to bind to every column returned by the query. * Data in unbound columns are simply never copied to the user's buffers and are thus * inaccesible to the application. */ data[c].buffer = calloc(1, metadata[c].size); assert(data[c].buffer); erc = dbbind(dbproc, c+1, STRINGBIND, -1, (BYTE *) data[c].buffer); if (erc == FAIL) { fprintf(stderr, "%s:%d: dbbind(), column %d failed\n", options.appname, __LINE__, c+1); return; } erc = dbnullbind(dbproc, c+1, &data[c].status); if (erc == FAIL) { fprintf(stderr, "%s:%d: dbnullbind(), column %d failed\n", options.appname, __LINE__, c+1); return; } } /* * Get metadata and bind the columns for any compute rows. */ for (i=0; i < ncomputeids; i++) { fprintf(options.verbose, "For computeid %d:\n", 1+i); for (c=0; c < metacompute[i]->numalts; c++) { /* read metadata */ struct METADATA *meta = &metacompute[i]->meta[c]; int nbylist, ibylist; BYTE *bylist; char *colname, bynames[256] = "by ("; int altcolid = dbaltcolid(dbproc, i+1, c+1); metacompute[i]->meta[c].type = dbalttype(dbproc, i+1, c+1); metacompute[i]->meta[c].size = dbaltlen(dbproc, i+1, c+1); /* * 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, &nbylist); for (ibylist=0; ibylist < nbylist; ibylist++) { int ret; char *s = strchr(bynames, '\0'); int remaining = bynames + sizeof(bynames) - s; assert(remaining > 0); ret = snprintf(s, remaining, "%s%s", dbcolname(dbproc, bylist[ibylist]), (ibylist+1 < nbylist)? ", " : ")"); if (ret <= 0) { fprintf(options.verbose, "Insufficient room to create name for column %d:\n", 1+c); break; } } if( altcolid == -1 ) { colname = "*"; } else { 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); ret = set_format_string(meta, (c+1 < metacompute[i]->numalts)? " " : "\n"); if (ret <= 0) { 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, (nbylist > 0)? bynames : ""); /* allocate buffer */ assert(metacompute[i]->data); metacompute[i]->data[c].buffer = calloc(1, metacompute[i]->meta[c].size); assert(metacompute[i]->data[c].buffer); /* bind */ erc = dbaltbind(dbproc, i+1, c+1, STRINGBIND, -1, 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", iresultset); /* Print the column headers to stderr to keep them separate from the data. */ for (c=0; c < ncols; c++) { char fmt[256] = "%-"; /* left justify the names */ strcat(fmt, &metadata[c].format_string[1]); fprintf(stderr, fmt, metadata[c].name); } /* Underline the column headers. */ for (c=0; c < ncols; c++) { fprintf(stderr, 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; 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(stderr, fmt, meta->name); } /* Underline the column headers. */ for (c=0; c < metacompute[row_code-1]->numalts; c++) { fprintf(stderr, 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 */ 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 (DBCOUNT(dbproc) > -1) fprintf(stderr, "%d rows affected\n", DBCOUNT(dbproc)); /* * 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); }
int main(int argc, char *argv[]) { int echo = 0; #ifdef notyet int print_statistics = 0; #endif int fipsflagger = 0; int perfstats = 0; int no_prompt = 0; int use_encryption = 0; int chained_transactions = 0; const char *cmdend = "go"; int headers = 0; char *columnwidth = NULL; const char *colseparator = " "; const char *lineseparator = "\n"; int timeout = 0; char *username = NULL; char *password = NULL; char *server = NULL; DBCHAR *char_set = NULL; const char *editor; char *hostname = NULL; char *sqlch; char *interfaces_filename = NULL; char *input_filename = NULL; char *output_filename = NULL; int logintime = -1; char *language = NULL; int size = 0; char *sybenv; DBPROCESS *dbproc; LOGINREC *login; char **ibuf = NULL; int ibuflines = 0; int printedlines; int i; char *line; int dbrc; char foobuf[512]; char *firstword; char *cp; int c; int errflg = 0; char *prbuf; int prbuflen; FILE *fp; FILE *tmpfp; FILE *tmpfp2; char *tfn; char tmpfn[256]; int num_cols; int selcol; int col; int collen; DBINT colid; const char *opname; char adbuf[512]; DBINT convlen; int printedcompute = 0; char adash; const char *database_name = NULL; int default_exit = EXIT_SUCCESS; setlocale(LC_ALL, ""); #ifdef __VMS /* Convert VMS-style arguments to Unix-style */ parse_vms_args(&argc, &argv); #endif editor = getenv("EDITOR"); if (!editor) { editor = getenv("VISUAL"); } if (!editor) { editor = "vi"; } opterr = 0; optarg = NULL; while (!errflg && (c = getopt(argc, argv, "eFgpnvXYa:c:D:E:h:H:i:I:J:l:m:o:P:s:S:t:U:w:y:z:A:")) != -1) { switch (c) { case 'e': echo = 1; break; case 'F': fipsflagger = 1; break; case 'g': errflg++; break; case 'p': errflg++; perfstats = 1; break; case 'n': no_prompt = 1; break; case 'v': puts("fisql, a free isql replacement by Nicholas S. Castellano"); exit(EXIT_SUCCESS); break; case 'X': /* XXX: We get a different error message than isql gives; neither seems * to work */ use_encryption = 1; break; case 'Y': chained_transactions = 1; break; case 'c': cmdend = optarg; break; case 'E': editor = optarg; break; case 'h': headers = atoi(optarg); break; case 'H': hostname = optarg; break; case 'i': input_filename = optarg; break; case 'I': interfaces_filename = optarg; break; case 'J': errflg++; break; case 'l': logintime = atoi(optarg); break; case 'm': global_errorlevel = atoi(optarg); break; case 'o': output_filename = optarg; break; case 'P': password = optarg; break; case 's': colseparator = optarg; break; case 'S': server = optarg; break; case 't': timeout = atoi(optarg); break; case 'U': username = optarg; break; case 'w': columnwidth = optarg; break; case 'y': /* XXX: this doesn't seem to be what isql does with -y...it doesn't * seem to do anything actually */ sybenv = (char *) xmalloc((strlen(optarg) + 8) * sizeof(char)); strcpy(sybenv, "SYBASE="); strcat(sybenv, optarg); putenv(sybenv); break; case 'z': language = optarg; break; case 'A': size = atoi(optarg); break; case 'D': database_name = optarg; break; default: errflg++; break; } } if (errflg) { fprintf(stderr, "usage: fisql [-e] [-F] [-g] [-p] [-n] [-v] [-X] [-Y]\n"); fprintf(stderr, "\t[-c cmdend] [-D database_name] [-E editor]\n"); fprintf(stderr, "\t[-h headers] [-H hostname] [-i inputfile]\n"); fprintf(stderr, "\t[-I interfaces_file] [-J client character set]\n"); fprintf(stderr, "\t[-l login_timeout] [-m errorlevel]\n"); fprintf(stderr, "\t[-o outputfile]\n"); fprintf(stderr, "\t[-P password] [-s colseparator] [-S server]\n"); fprintf(stderr, "\t[-t timeout] [-U username] [-w columnwidth]\n"); fprintf(stderr, "\t[-y sybase_dir] [-z language]\n"); exit(EXIT_FAILURE); } if (!(isatty(fileno(stdin)))) { no_prompt = 1; rl_outstream = fopen("/dev/null", "rw"); } rl_readline_name = "fisql"; rl_bind_key('\t', rl_insert); if (password == NULL) { password = (char *) xmalloc(READPASSPHRASE_MAXLEN); readpassphrase("Password: "******"r", stdin) == NULL) { /* XXX: sybase isql generates this error while parsing the options, * but doesn't redirect the input until after the Password: prompt */ /* lack of newline for bug-compatibility with isql */ fprintf(stderr, "Unable to open input file '%s'.", optarg); exit(EXIT_FAILURE); } } if (output_filename) { if (freopen(output_filename, "w", stdout) == NULL) { /* XXX: sybase isql generates this error while parsing the options, * but doesn't redirect the output until after the Password: prompt */ /* lack of newline for bug-compatibility with isql */ fprintf(stderr, "Unable to open output file '%s'.", output_filename); exit(EXIT_FAILURE); } } if (isatty(fileno(stdin))) { rl_outstream = stdout; } dbinit(); #if 0 #ifdef DBVERSION_100 dbsetversion(DBVERSION_100); #endif #endif if ((login = dblogin()) == NULL) { reset_term(); exit(EXIT_FAILURE); } dbmsghandle(msg_handler); dberrhandle(err_handler); DBSETLAPP(login, "fisql"); if (username) { DBSETLUSER(login, username); } DBSETLPWD(login, password); memset(password, 0, strlen(password)); if (char_set) { DBSETLCHARSET(login, char_set); } if (use_encryption) { DBSETLENCRYPT(login, TRUE); } if (hostname) { DBSETLHOST(login, hostname); } if (language) { DBSETLNATLANG(login, language); } if (size) { DBSETLPACKET(login, (short) size); } if (interfaces_filename) { dbsetifile(interfaces_filename); } dbsettime(timeout); if (logintime >= 0) { dbsetlogintime(logintime); } if ((dbproc = dbopen(login, server)) == NULL) { fprintf(stderr, "fisql: dbopen() failed.\n"); reset_term(); exit(EXIT_FAILURE); } dbsetopt(dbproc, DBPRLINESEP, lineseparator, strlen(lineseparator)); if (colseparator) { dbsetopt(dbproc, DBPRCOLSEP, colseparator, strlen(colseparator)); } if (columnwidth) { dbsetopt(dbproc, DBPRLINELEN, columnwidth, 0); } if (chained_transactions) { dbsetopt(dbproc, DBCHAINXACTS, NULL, 0); } if (fipsflagger) { dbsetopt(dbproc, DBFIPSFLAG, NULL, 0); } if (perfstats) { dbsetopt(dbproc, DBSTAT, "time", 0); } if (database_name) { dbuse(dbproc, database_name); } while (1) { if (sigsetjmp(restart, 1)) { if (ibuf) { for (i = 0; i < ibuflines; i++) { free(ibuf[i]); } ibuflines = 0; free(ibuf); ibuf = NULL; } fputc('\n', stdout); rl_on_new_line(); rl_reset_line_state(); } dbcancel(dbproc); signal(SIGINT, inactive_interrupt_handler); ibuf = (char **) xmalloc(sizeof(char *)); ibuflines = 0; while (1) { if (no_prompt) { foobuf[0] = '\0'; } else { sprintf(foobuf, "%d>> ", ibuflines + 1); } line = readline(foobuf); if (line == NULL) { line = "exit"; } for (cp = line; *cp && isspace((unsigned char) *cp); cp++) continue; if (*cp) { add_history(line); } if (!(strncasecmp(line, "!!", 2))) { int rv; cp = line + 2; switch (rv = system(cp)) { case 0: continue; case -1: fprintf(stderr, "Failed to execute `%s'\n", cp); continue; default: fprintf(stderr, "Command `%s' exited " "with code %d\n", cp, rv); continue; } } /* XXX: isql off-by-one line count error for :r not duplicated */ if (!(strncasecmp(line, ":r", 2))) { for (cp = line + 2; *cp && (isspace((unsigned char) *cp)); cp++) continue; tfn = cp; for (; *cp && !(isspace((unsigned char) *cp)); cp++) continue; *cp = '\0'; if ((fp = fopen(tfn, "r")) == NULL) { fprintf(stderr, "Operating system error: Failed to open %s.\n", tfn); continue; } tmpfp = rl_instream; tmpfp2 = rl_outstream; rl_instream = fp; rl_outstream = fopen("/dev/null", "w"); while ((line = readline("")) != NULL) { ibuf[ibuflines++] = line; ibuf = (char **) xrealloc(ibuf, (ibuflines + 1) * sizeof(char *)); } rl_instream = tmpfp; fclose(rl_outstream); rl_outstream = tmpfp2; fclose(fp); fputc('\r', stdout); fflush(stdout); continue; } firstword = (char *) xmalloc((strlen(line) + 1) * sizeof(char)); strcpy(firstword, line); for (cp = firstword; *cp; cp++) { if (isspace((unsigned char) *cp)) { *cp = '\0'; break; } } if ((!(strcasecmp(firstword, "exit"))) || (!(strcasecmp(firstword, "quit")))) { reset_term(); dbexit(); exit(default_exit); } if (!(strcasecmp(firstword, "reset"))) { for (i = 0; i < ibuflines; i++) { free(ibuf[i]); } ibuflines = 0; continue; } if (!(strcasecmp(firstword, cmdend))) { if (ibuflines == 0) { continue; } free(firstword); break; } if ((!(strcasecmp(firstword, "vi"))) || (!(strcasecmp(firstword, editor)))) { int tmpfd; strcpy(tmpfn, "/tmp/fisqlXXXXXX"); tmpfd = mkstemp(tmpfn); if ((fp = fdopen(tmpfd, "w")) == NULL) { perror("fisql"); reset_term(); dbexit(); exit(2); } if (ibuflines) { for (i = 0; i < ibuflines; i++) { fputs(ibuf[i], fp); fputc('\n', fp); free(ibuf[i]); } } else { for (i = 0; ((sqlch = dbgetchar(dbproc, i)) != NULL); i++) { fputc(*sqlch, fp); } } fclose(fp); if (!(strcmp(firstword, "vi"))) { edit("vi", tmpfn); } else { edit(editor, tmpfn); } ibuflines = 0; fp = fopen(tmpfn, "r"); tmpfp = rl_instream; rl_instream = fp; strcpy(foobuf, "1>> "); while ((line = readline(foobuf)) != NULL) { ibuf[ibuflines++] = line; sprintf(foobuf, "%d>> ", ibuflines + 1); ibuf = (char **) xrealloc(ibuf, (ibuflines + 1) * sizeof(char *)); } rl_instream = tmpfp; fclose(fp); fputc('\r', stdout); fflush(stdout); unlink(tmpfn); continue; } free(firstword); ibuf[ibuflines++] = line; ibuf = (char **) xrealloc(ibuf, (ibuflines + 1) * sizeof(char *)); } dbfreebuf(dbproc); for (i = 0; i < ibuflines; i++) { if (echo) { puts(ibuf[i]); } dbcmd(dbproc, ibuf[i]); dbcmd(dbproc, "\n"); free(ibuf[i]); } free(ibuf); ibuf = NULL; signal(SIGINT, active_interrupt_handler); dbsetinterrupt(dbproc, (void *) active_interrupt_pending, (void *) active_interrupt_servhandler); if (dbsqlexec(dbproc) == SUCCEED) { maybe_handle_active_interrupt(); while ((dbrc = dbresults(dbproc)) != NO_MORE_RESULTS) { printedlines = 0; #define USE_DBPRROW 0 #if USE_DBPRROW dbprhead(dbproc); dbprrow(dbproc); #else if ((dbrc == SUCCEED) && (DBROWS(dbproc) == SUCCEED)) { prbuflen = dbspr1rowlen(dbproc); prbuf = (char *) xmalloc(prbuflen * sizeof(char)); dbsprhead(dbproc, prbuf, prbuflen); fputs(prbuf, stdout); fputc('\n', stdout); dbsprline(dbproc, prbuf, prbuflen, '-'); fputs(prbuf, stdout); fputc('\n', stdout); maybe_handle_active_interrupt(); while ((dbrc = dbnextrow(dbproc)) != NO_MORE_ROWS) { if (dbrc == FAIL) { break; } if (dbrc != REG_ROW) { num_cols = dbnumalts(dbproc, dbrc); for (selcol = col = 1; col <= num_cols; col++) { colid = dbaltcolid(dbproc, dbrc, col); while (selcol < colid) { collen = get_printable_column_size(dbproc, selcol); for (i = 0; i < collen; i++) { putchar(' '); } selcol++; printf("%s", colseparator); } opname = dbprtype(dbaltop(dbproc, dbrc, col)); printf("%s", opname); collen = get_printable_column_size(dbproc, colid); collen -= strlen(opname); while (collen-- > 0) { putchar(' '); } selcol++; printf("%s", colseparator); } printf("%s", lineseparator); for (selcol = col = 1; col <= num_cols; col++) { colid = dbaltcolid(dbproc, dbrc, col); while (selcol < colid) { collen = get_printable_column_size(dbproc, selcol); for (i = 0; i < collen; i++) { putchar(' '); } selcol++; printf("%s", colseparator); } collen = get_printable_column_size(dbproc, colid); adash = '-'; for (i = 0; i < collen; i++) { putchar(adash); } selcol++; printf("%s", colseparator); } printf("%s", lineseparator); for (selcol = col = 1; col <= num_cols; col++) { colid = dbaltcolid(dbproc, dbrc, col); while (selcol < colid) { collen = get_printable_column_size(dbproc, selcol); for (i = 0; i < collen; i++) { putchar(' '); } selcol++; printf("%s", colseparator); } convlen = dbconvert(dbproc, dbalttype(dbproc, dbrc, col), dbadata(dbproc, dbrc, col), dbadlen(dbproc, dbrc, col), SYBCHAR, (BYTE *) adbuf, sizeof(adbuf)); printf("%.*s", (int) convlen, adbuf); collen = get_printable_column_size(dbproc, colid); collen -= convlen; while (collen-- > 0) { putchar(' '); } selcol++; printf("%s", colseparator); } printf("%s", lineseparator); printedcompute = 1; continue; } if (printedcompute || (headers && (printedlines >= headers) && ((printedlines % headers) == 0))) { fputc('\n', stdout); dbsprhead(dbproc, prbuf, prbuflen); fputs(prbuf, stdout); fputc('\n', stdout); dbsprline(dbproc, prbuf, prbuflen, '-'); fputs(prbuf, stdout); fputc('\n', stdout); printedcompute = 0; } printedlines++; dbspr1row(dbproc, prbuf, prbuflen); fputs(prbuf, stdout); fputc('\n', stdout); maybe_handle_active_interrupt(); } fputc('\n', stdout); free(prbuf); maybe_handle_active_interrupt(); } #endif if (dbrc != FAIL) { if ((DBCOUNT(dbproc) >= 0) || dbhasretstat(dbproc)) { if (DBCOUNT(dbproc) >= 0) { fprintf(stdout, "(%d rows affected", (int) DBCOUNT(dbproc)); if (dbhasretstat(dbproc)) { dbrc = dbretstatus(dbproc); fprintf(stdout, ", return status = %d", dbrc); } fprintf(stdout, ")\n"); } else { if (dbhasretstat(dbproc)) { dbrc = dbretstatus(dbproc); fprintf(stdout, "(return status = %d)\n", dbrc); } } } } } } else { /* Something failed, so change the default * exit status to reflect that. */ default_exit = EXIT_FAILURE; } } reset_term(); dbexit(); exit(EXIT_FAILURE); return (0); }
int main(int argc, char *argv[]) { LOGINREC *login; DBPROCESS *dbproc; int i; DBINT rowint; DBCHAR rowchar[2]; DBCHAR rowdate[32]; DBINT rowtype; DBINT computeint; DBCHAR computedate[32]; set_malloc_options(); read_login_info(argc, argv); fprintf(stdout, "Starting %s\n", argv[0]); /* Fortify_EnterScope(); */ dbinit(); dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); fprintf(stdout, "About to logon\n"); login = dblogin(); DBSETLPWD(login, PASSWORD); DBSETLUSER(login, USER); DBSETLAPP(login, "t0023"); fprintf(stdout, "About to open\n"); dbproc = dbopen(login, SERVER); if (strlen(DATABASE)) dbuse(dbproc, DATABASE); dbloginfree(login); fprintf(stdout, "creating table\n"); sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } fprintf(stdout, "insert\n"); sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } fprintf(stdout, "select\n"); sql_cmd(dbproc); dbsqlexec(dbproc); if (dbresults(dbproc) != SUCCEED) { failed = 1; fprintf(stdout, "Was expecting a result set.\n"); exit(1); } for (i = 1; i <= dbnumcols(dbproc); i++) printf("col %d is %s\n", i, dbcolname(dbproc, i)); fprintf(stdout, "binding row columns\n"); if (SUCCEED != dbbind(dbproc, 1, INTBIND, 0, (BYTE *) & rowint)) { failed = 1; fprintf(stderr, "Had problem with bind col1\n"); abort(); } if (SUCCEED != dbbind(dbproc, 2, STRINGBIND, 0, (BYTE *) rowchar)) { failed = 1; fprintf(stderr, "Had problem with bind col2\n"); abort(); } if (SUCCEED != dbbind(dbproc, 3, STRINGBIND, 0, (BYTE *) rowdate)) { failed = 1; fprintf(stderr, "Had problem with bind col3\n"); abort(); } fprintf(stdout, "testing compute clause 1\n"); if (dbnumalts(dbproc, 1) != 1) { failed = 1; fprintf(stderr, "Had problem with dbnumalts 1\n"); abort(); } if (dbalttype(dbproc, 1, 1) != SYBINT4) { failed = 1; fprintf(stderr, "Had problem with dbalttype 1, 1\n"); abort(); } if (dbaltcolid(dbproc, 1, 1) != 1) { failed = 1; fprintf(stderr, "Had problem with dbaltcolid 1, 1\n"); abort(); } if (dbaltop(dbproc, 1, 1) != SYBAOPSUM) { failed = 1; fprintf(stderr, "Had problem with dbaltop 1, 1\n"); abort(); } if (SUCCEED != dbaltbind(dbproc, 1, 1, INTBIND, 0, (BYTE *) & computeint)) { failed = 1; fprintf(stderr, "Had problem with dbaltbind 1, 1\n"); abort(); } fprintf(stdout, "testing compute clause 2\n"); if (dbnumalts(dbproc, 2) != 1) { failed = 1; fprintf(stderr, "Had problem with dbnumalts 2\n"); abort(); } if (dbalttype(dbproc, 2, 1) != SYBDATETIME) { failed = 1; fprintf(stderr, "Had problem with dbalttype 2, 1\n"); abort(); } if (dbaltcolid(dbproc, 2, 1) != 3) { failed = 1; fprintf(stderr, "Had problem with dbaltcolid 2, 1\n"); abort(); } if (dbaltop(dbproc, 2, 1) != SYBAOPMAX) { failed = 1; fprintf(stderr, "Had problem with dbaltop 2, 1\n"); abort(); } if (SUCCEED != dbaltbind(dbproc, 2, 1, STRINGBIND, -1, (BYTE *) computedate)) { failed = 1; fprintf(stderr, "Had problem with dbaltbind 2, 1\n"); abort(); } while ((rowtype = dbnextrow(dbproc)) != NO_MORE_ROWS) { if (rowtype == REG_ROW) { printf("gotten a regular row\n"); } if (rowtype == 1) { printf("gotten a compute row for clause 1\n"); printf("value of sum(col1) = %d\n", computeint); } if (rowtype == 2) { printf("gotten a compute row for clause 2\n"); printf("value of max(col3) = %s\n", computedate); } } dbexit(); fprintf(stdout, "%s %s\n", __FILE__, (failed ? "failed!" : "OK")); return failed ? 1 : 0; }