/* Duplicated in result.c */ static VALUE rb_tinytds_return_code(VALUE self) { GET_CLIENT_WRAPPER(self); if (cwrap->client && dbhasretstat(cwrap->client)) { return LONG2NUM((long)dbretstatus(cwrap->client)); } else { return Qnil; } }
int main(int argc, char **argv) { char cmd[1024]; LOGINREC *login; DBPROCESS *dbproc; int i; char teststr[1024]; int erc, failed = 0; char *retname = NULL; int rettype = 0, retlen = 0; set_malloc_options(); read_login_info(argc, argv); fprintf(stdout, "Start\n"); add_bread_crumb(); dbinit(); add_bread_crumb(); dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); fprintf(stdout, "About to logon\n"); add_bread_crumb(); login = dblogin(); DBSETLPWD(login, PASSWORD); DBSETLUSER(login, USER); DBSETLAPP(login, "t0022"); fprintf(stdout, "About to open\n"); add_bread_crumb(); dbproc = dbopen(login, SERVER); if (strlen(DATABASE)) dbuse(dbproc, DATABASE); add_bread_crumb(); dbloginfree(login); add_bread_crumb(); fprintf(stdout, "Dropping proc\n"); add_bread_crumb(); dbcmd(dbproc, "if object_id('t0022') is not null drop proc t0022"); add_bread_crumb(); dbsqlexec(dbproc); add_bread_crumb(); while ((erc = dbresults(dbproc)) == SUCCEED) { fprintf(stdout, "dbresult succeeded dropping procedure\n"); while ((erc = dbnextrow(dbproc)) == SUCCEED) { fprintf(stdout, "dbnextrow returned spurious rows dropping procedure\n"); assert(0); /* dropping a procedure returns no rows */ } assert(erc == NO_MORE_ROWS); } assert(erc == NO_MORE_RESULTS); add_bread_crumb(); fprintf(stdout, "creating proc\n"); dbcmd(dbproc, "create proc t0022 (@b int out) as\nbegin\n select @b = 42\n return 66\nend\n"); if (dbsqlexec(dbproc) == FAIL) { add_bread_crumb(); fprintf(stdout, "Failed to create proc t0022.\n"); exit(1); } while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) { assert(erc != FAIL); while ((erc = dbnextrow(dbproc)) == SUCCEED) { assert(0); /* creating a procedure returns no rows */ } assert(erc == NO_MORE_ROWS); } sprintf(cmd, "declare @b int\nexec t0022 @b = @b output\n"); fprintf(stdout, "%s\n", cmd); dbcmd(dbproc, cmd); dbsqlexec(dbproc); add_bread_crumb(); while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) { if (erc == FAIL) { add_bread_crumb(); fprintf(stdout, "Was expecting a result set.\n"); exit(1); } while ((erc = dbnextrow(dbproc)) == SUCCEED) { assert(0); /* procedure returns no rows */ } assert(erc == NO_MORE_ROWS); } add_bread_crumb(); #if defined(DBTDS_7_0) && defined(DBTDS_8_0) && defined(DBTDS_9_0) if ((dbnumrets(dbproc) == 0) && ((DBTDS(dbproc) == DBTDS_7_0) || (DBTDS(dbproc) == DBTDS_8_0) || (DBTDS(dbproc) == DBTDS_9_0))) { fprintf(stdout, "WARNING: Received no return parameters from server!\n"); fprintf(stdout, "WARNING: This is likely due to a bug in Microsoft\n"); fprintf(stdout, "WARNING: SQL Server 7.0 SP3 and later.\n"); fprintf(stdout, "WARNING: Please try again using TDS protocol 4.2.\n"); dbcmd(dbproc, "drop proc t0022"); dbsqlexec(dbproc); while (dbresults(dbproc) != NO_MORE_RESULTS) { /* nop */ } dbexit(); free_bread_crumb(); exit(0); } #endif for (i = 1; i <= dbnumrets(dbproc); i++) { add_bread_crumb(); retname = dbretname(dbproc, i); printf("ret name %d is %s\n", i, retname); rettype = dbrettype(dbproc, i); printf("ret type %d is %d\n", i, rettype); retlen = dbretlen(dbproc, i); printf("ret len %d is %d\n", i, retlen); dbconvert(dbproc, rettype, dbretdata(dbproc, i), retlen, SYBVARCHAR, (BYTE*) teststr, -1); printf("ret data %d is %s\n", i, teststr); add_bread_crumb(); } if ((retname == NULL) || strcmp(retname, "@b")) { fprintf(stdout, "Was expecting a retname to be @b.\n"); exit(1); } if (strcmp(teststr, "42")) { fprintf(stdout, "Was expecting a retdata to be 42.\n"); exit(1); } if (rettype != SYBINT4) { fprintf(stdout, "Was expecting a rettype to be SYBINT4 was %d.\n", rettype); exit(1); } if (retlen != 4) { fprintf(stdout, "Was expecting a retlen to be 4.\n"); exit(1); } fprintf(stdout, "Dropping proc\n"); add_bread_crumb(); dbcmd(dbproc, "drop proc t0022"); add_bread_crumb(); dbsqlexec(dbproc); add_bread_crumb(); while (dbresults(dbproc) != NO_MORE_RESULTS) { /* nop */ } /* * Chapter 2: test for resultsets containing only a return status */ fprintf(stdout, "Dropping proc t0022a\n"); dbcmd(dbproc, "if object_id('t0022a') is not null drop proc t0022a"); dbsqlexec(dbproc); while ((erc = dbresults(dbproc)) == SUCCEED) { fprintf(stdout, "dbresult succeeded dropping procedure\n"); while ((erc = dbnextrow(dbproc)) == SUCCEED) { fprintf(stdout, "dbnextrow returned spurious rows dropping procedure\n"); assert(0); /* dropping a procedure returns no rows */ } assert(erc == NO_MORE_ROWS); } assert(erc == NO_MORE_RESULTS); fprintf(stdout, "creating proc t0022a\n"); dbcmd(dbproc, "create proc t0022a (@b int) as\nreturn @b\n"); if (dbsqlexec(dbproc) == FAIL) { fprintf(stdout, "Failed to create proc t0022a.\n"); exit(1); } while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) { assert(erc != FAIL); while ((erc = dbnextrow(dbproc)) == SUCCEED) { assert(0); /* creating a procedure returns no rows */ } assert(erc == NO_MORE_ROWS); } sprintf(cmd, "exec t0022a 17 exec t0022a 1024\n"); fprintf(stdout, "%s\n", cmd); dbcmd(dbproc, cmd); dbsqlexec(dbproc); for (i=1; (erc = dbresults(dbproc)) != NO_MORE_RESULTS; i++) { enum {expected_iterations = 2}; DBBOOL fret; DBINT status; if (erc == FAIL) { fprintf(stdout, "t0022a failed for some reason.\n"); exit(1); } printf("procedure returned %srows\n", DBROWS(dbproc)==SUCCEED? "" : "no "); while ((erc = dbnextrow(dbproc)) == SUCCEED) { assert(0); /* procedure returns no rows */ } assert(erc == NO_MORE_ROWS); fret = dbhasretstat(dbproc); printf("procedure has %sreturn status\n", fret==TRUE? "" : "no "); assert(fret == TRUE); status = dbretstatus(dbproc); printf("return status %d is %d\n", i, (int) status); switch (i) { case 1: assert(status == 17); break; case 2: assert(status == 1024); break; default: assert(i <= expected_iterations); } } assert(erc == NO_MORE_RESULTS); fprintf(stdout, "Dropping proc t0022a\n"); dbcmd(dbproc, "drop proc t0022a"); dbsqlexec(dbproc); while (dbresults(dbproc) != NO_MORE_RESULTS) { /* nop */ } /* end chapter 2 */ add_bread_crumb(); dbexit(); add_bread_crumb(); fprintf(stdout, "dblib %s on %s\n", (failed ? "failed!" : "okay"), __FILE__); free_bread_crumb(); return failed ? 1 : 0; }
int main(int argc, char **argv) { LOGINREC *login; DBPROCESS *dbproc; RETPARAM save_param, save_varchar_tds7_param, save_nvarchar_tds7_param; char teststr[8000+1], abbrev_data[10+3+1], *output; char *retname = NULL; int i, failed = 0; int rettype = 0, retlen = 0, return_status = 0; char proc[] = "#t0022"; char *proc_name = proc; int num_resultset = 0, num_empty_resultset = 0; int num_params = 6; static const char dashes30[] = "------------------------------"; static const char *dashes5 = dashes30 + (sizeof(dashes30) - 5), *dashes20 = dashes30 + (sizeof(dashes30) - 20); RETCODE erc, row_code; set_malloc_options(); memset(&save_param, 0, sizeof(save_param)); memset(&save_varchar_tds7_param, 0, sizeof(save_varchar_tds7_param)); memset(&save_nvarchar_tds7_param, 0, sizeof(save_nvarchar_tds7_param)); read_login_info(argc, argv); printf("Starting %s\n", argv[0]); dbinit(); dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); printf("About to logon\n"); login = dblogin(); DBSETLPWD(login, PASSWORD); DBSETLUSER(login, USER); DBSETLAPP(login, "rpc"); dberrhandle(ignore_err_handler); DBSETLPACKET(login, -1); dberrhandle(syb_err_handler); printf("About to open %s.%s\n", SERVER, DATABASE); dbproc = dbopen(login, SERVER); if (strlen(DATABASE)) dbuse(dbproc, DATABASE); dbloginfree(login); printf("Check if server support long identifiers\n"); sql_cmd(dbproc); i = 103; dbsetuserdata(dbproc, (BYTE*) &i); dbsqlexec(dbproc); while (dbresults(dbproc) != NO_MORE_RESULTS) while (dbnextrow(dbproc) != NO_MORE_ROWS) continue; dbsetuserdata(dbproc, NULL); if (i == 0) { fprintf(stderr, "This server does not support long identifiers\n"); dbexit(); return 0; } dberrhandle(ignore_err_handler); dbmsghandle(ignore_msg_handler); printf("trying to create a temporary stored procedure\n"); if (FAIL == init_proc(dbproc, proc_name)) { num_params = 4; printf("trying to create a permanent stored procedure\n"); if (FAIL == init_proc(dbproc, ++proc_name)) exit(EXIT_FAILURE); } dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); printf("Created procedure %s\n", proc_name); /* set up and send the rpc */ printf("executing dbrpcinit\n"); erc = dbrpcinit(dbproc, proc_name, 0); /* no options */ if (erc == FAIL) { fprintf(stderr, "Failed line %d: dbrpcinit\n", __LINE__); failed = 1; } for (pb = bindings, i = 0; pb < bindings + sizeof(bindings)/sizeof(bindings[0]); pb++, i++) { printf("executing dbrpcparam for %s\n", pb->name); if (num_params == 4 && (i == 3 || i == 4)) continue; if ((erc = dbrpcparam(dbproc, pb->name, pb->status, pb->type, pb->maxlen, pb->datalen, pb->value)) == FAIL) { fprintf(stderr, "Failed line %d: dbrpcparam\n", __LINE__); failed++; } } printf("executing dbrpcsend\n"); param_data5 = 0x11223344; erc = dbrpcsend(dbproc); if (erc == FAIL) { fprintf(stderr, "Failed line %d: dbrpcsend\n", __LINE__); exit(1); } /* wait for it to execute */ printf("executing dbsqlok\n"); erc = dbsqlok(dbproc); if (erc == FAIL) { fprintf(stderr, "Failed line %d: dbsqlok\n", __LINE__); exit(1); } /* retrieve outputs per usual */ printf("fetching results\n"); while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) { printf("fetched resultset %d %s:\n", 1+num_resultset, erc==SUCCEED? "successfully":"unsuccessfully"); if (erc == SUCCEED) { const int ncol = dbnumcols(dbproc); int empty_resultset = 1, c; enum {buflen=1024, nbuf=5}; char bound_buffers[nbuf][buflen] = { "one", "two", "three", "four", "five" }; ++num_resultset; for( c=0; c < ncol && c < nbuf; c++ ) { printf("column %d (%s) is %d wide, ", c+1, dbcolname(dbproc, c+1), colwidth(dbproc, c+1)); printf("buffer initialized to '%s'\n", bound_buffers[c]); } for( c=0; c < ncol && c < nbuf; c++ ) { erc = dbbind(dbproc, c+1, STRINGBIND, 0, (BYTE *) bound_buffers[c]); if (erc == FAIL) { fprintf(stderr, "Failed line %d: dbbind\n", __LINE__); exit(1); } printf("%-*s ", colwidth(dbproc, c+1), dbcolname(dbproc, c+1)); } printf("\n"); while ((row_code = dbnextrow(dbproc)) != NO_MORE_ROWS) { empty_resultset = 0; if (row_code == REG_ROW) { int c; for( c=0; c < ncol && c < nbuf; c++ ) { printf("%-*s ", colwidth(dbproc, c+1), bound_buffers[c]); } printf("\n"); } else { /* not supporting computed rows in this unit test */ failed = 1; fprintf(stderr, "Failed. Expected a row\n"); exit(1); } } printf("row count %d\n", (int) dbcount(dbproc)); printf("hasretstatus %d\n", dbhasretstat(dbproc)); if (num_resultset == 4 && !dbhasretstat(dbproc)) { fprintf(stderr, "dbnextrow should have set hasretstatus after last recordset\n"); exit(1); } if (empty_resultset) ++num_empty_resultset; } else { fprintf(stderr, "Expected a result set.\n"); exit(1); } } /* while dbresults */ /* check return status */ printf("retrieving return status...\n"); if (dbhasretstat(dbproc) == TRUE) { printf("%d\n", return_status = dbretstatus(dbproc)); } else { printf("none\n"); } /* * Check output parameter values */ if (dbnumrets(dbproc) != num_params) { /* dbnumrets missed something */ fprintf(stderr, "Expected %d output parameters.\n", num_params); exit(1); } printf("retrieving output parameters...\n"); printf("%-5s %-20s %5s %6s %-30s\n", "param", "name", "type", "length", "data"); printf("%-5s %-20s %5s %5s- %-30s\n", dashes5, dashes20, dashes5, dashes5, dashes30); for (i = 1; i <= dbnumrets(dbproc); i++) { retname = dbretname(dbproc, i); rettype = dbrettype(dbproc, i); retlen = dbretlen(dbproc, i); dbconvert(dbproc, rettype, dbretdata(dbproc, i), retlen, SYBVARCHAR, (BYTE*) teststr, -1); if(retlen <= 10) { output = teststr; } else { memcpy(abbrev_data, teststr, 10); sprintf(&abbrev_data[10], "..."); output = abbrev_data; } printf("%-5d %-20s %5d %6d %-30s\n", i, retname, rettype, retlen, output); save_retparam(&save_param, retname, teststr, rettype, retlen); if (i == 4) { save_retparam(&save_varchar_tds7_param, retname, teststr, rettype, retlen); } if (i == 5) { save_retparam(&save_nvarchar_tds7_param, retname, teststr, rettype, retlen); } } /* * Test the last parameter for expected outcome */ if ((save_param.name == NULL) || strcmp(save_param.name, bindings[5].name)) { fprintf(stderr, "Expected retname to be '%s', got ", bindings[5].name); if (save_param.name == NULL) fprintf(stderr, "<NULL> instead.\n"); else fprintf(stderr, "'%s' instead.\n", save_param.name); exit(1); } if (strcmp(save_param.value, "3")) { fprintf(stderr, "Expected retdata to be 3.\n"); exit(1); } if (save_param.type != SYBINT4) { fprintf(stderr, "Expected rettype to be SYBINT4 was %d.\n", save_param.type); exit(1); } if (save_param.len != 4) { fprintf(stderr, "Expected retlen to be 4.\n"); exit(1); } if (num_params == 6) { /* * Test name, size, contents of the VARCHAR(8000) output parameter */ if ((save_varchar_tds7_param.name == NULL) || strcmp(save_varchar_tds7_param.name, bindings[3].name)) { fprintf(stderr, "Expected retname to be '%s', got ", bindings[3].name); if (save_varchar_tds7_param.name == NULL) fprintf(stderr, "<NULL> instead.\n"); else fprintf(stderr, "'%s' instead.\n", save_varchar_tds7_param.name); exit(1); } if (save_varchar_tds7_param.type != SYBVARCHAR) { fprintf(stderr, "Expected rettype to be SYBVARCHAR was %d.\n", save_varchar_tds7_param.type); exit(1); } if (save_varchar_tds7_param.len != 8000) { fprintf(stderr, "Expected retlen to be 8000 was %d.\n", save_varchar_tds7_param.len); exit(1); } /* * Test name, size, contents of the NVARCHAR(4000) output parameter */ if ((save_nvarchar_tds7_param.name == NULL) || strcmp(save_nvarchar_tds7_param.name, bindings[4].name)) { fprintf(stderr, "Expected retname to be '%s', got ", bindings[4].name); if (save_varchar_tds7_param.name == NULL) fprintf(stderr, "<NULL> instead.\n"); else fprintf(stderr, "'%s' instead.\n", save_nvarchar_tds7_param.name); exit(1); } if (save_nvarchar_tds7_param.len != 4000) { fprintf(stderr, "Expected retlen to be 4000 was %d.\n", save_nvarchar_tds7_param.len); exit(1); } } if(42 != return_status) { fprintf(stderr, "Expected status to be 42.\n"); exit(1); } printf("Good: Got 6 output parameters and 1 return status of %d.\n", return_status); /* Test number of result sets */ if (num_resultset != 4) { fprintf(stderr, "Expected 4 resultset got %d.\n", num_resultset); exit(1); } if (num_empty_resultset != 1) { fprintf(stderr, "Expected an empty resultset got %d.\n", num_empty_resultset); exit(1); } printf("Good: Got %d resultsets and %d empty resultset.\n", num_resultset, num_empty_resultset); printf("Dropping procedure\n"); sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) != NO_MORE_RESULTS) { /* nop */ } dbexit(); printf("%s %s\n", __FILE__, (failed ? "failed!" : "OK")); free_retparam(&save_param); free_retparam(&save_varchar_tds7_param); free_retparam(&save_nvarchar_tds7_param); return failed ? 1 : 0; }
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; RETPARAM save_param; int i, r; char teststr[1024]; int failed = 0; char *retname = NULL; int rettype = 0, retlen = 0; int return_status = 0; char proc[] = "#t0022", param0[] = "@null_input", param1[] = "@first_type", param2[] = "@nullout", param3[] = "@nrows", param4[] = "@c"; char *proc_name = proc; char param_data1[64]; int param_data2; int param_data3; RETCODE erc, row_code; int num_resultset = 0; int num_empty_resultset = 0; static const char dashes5[] = "-----", dashes15[] = "---------------", dashes30[] = "------------------------------"; set_malloc_options(); memset(&save_param, 0, sizeof(save_param)); read_login_info(argc, argv); fprintf(stdout, "Start\n"); add_bread_crumb(); dbinit(); add_bread_crumb(); dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); fprintf(stdout, "About to logon\n"); add_bread_crumb(); login = dblogin(); DBSETLPWD(login, PASSWORD); DBSETLUSER(login, USER); DBSETLAPP(login, "#t0022"); dberrhandle(ignore_err_handler); DBSETLPACKET(login, -1); dberrhandle(syb_err_handler); fprintf(stdout, "About to open %s.%s\n", SERVER, DATABASE); add_bread_crumb(); dbproc = dbopen(login, SERVER); if (strlen(DATABASE)) dbuse(dbproc, DATABASE); add_bread_crumb(); dbloginfree(login); add_bread_crumb(); add_bread_crumb(); dberrhandle(ignore_err_handler); dbmsghandle(ignore_msg_handler); printf("trying to create a temporary stored procedure\n"); if (FAIL == init_proc(dbproc, proc_name)) { printf("trying to create a permanent stored procedure\n"); if (FAIL == init_proc(dbproc, ++proc_name)) exit(EXIT_FAILURE); } dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); fprintf(stdout, "Created procedure %s\n", proc_name); /* set up and send the rpc */ printf("executing dbrpcinit\n"); erc = dbrpcinit(dbproc, proc_name, 0); /* no options */ if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcinit\n"); failed = 1; } printf("executing dbrpcparam\n"); erc = dbrpcparam(dbproc, param0, DBRPCRETURN, SYBCHAR, /*maxlen= */ -1, /* datlen= */ 0, NULL); if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcparam\n"); failed = 1; } printf("executing dbrpcparam\n"); erc = dbrpcparam(dbproc, param1, DBRPCRETURN, SYBCHAR, /*maxlen= */ sizeof(param_data1), /* datlen= */ 0, (BYTE *) & param_data1); if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcparam\n"); failed = 1; } printf("executing dbrpcparam\n"); erc = dbrpcparam(dbproc, param2, DBRPCRETURN, SYBINT4, /*maxlen= */ -1, /* datalen= */ 0, (BYTE *) & param_data2); if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcparam\n"); failed = 1; } printf("executing dbrpcparam\n"); erc = dbrpcparam(dbproc, param3, DBRPCRETURN, SYBINT4, /*maxlen= */ -1, /* datalen= */ -1, (BYTE *) & param_data3); if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcparam\n"); failed = 1; } /* test for strange parameters using input */ printf("executing dbrpcparam\n"); erc = dbrpcparam(dbproc, param4, 0, SYBVARCHAR, /*maxlen= */ 0, /* datalen= */ 0, NULL); if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcparam\n"); failed = 1; } printf("executing dbrpcsend\n"); param_data3 = 0x11223344; erc = dbrpcsend(dbproc); if (erc == FAIL) { fprintf(stderr, "Failed: dbrpcsend\n"); exit(1); } /* wait for it to execute */ printf("executing dbsqlok\n"); erc = dbsqlok(dbproc); if (erc == FAIL) { fprintf(stderr, "Failed: dbsqlok\n"); exit(1); } add_bread_crumb(); /* retrieve outputs per usual */ r = 0; while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) { if (erc == SUCCEED) { const int ncols = dbnumcols(dbproc); int empty_resultset = 1; ++num_resultset; printf("bound 1 of %d columns ('%s') in result %d.\n", ncols, dbcolname(dbproc, 1), ++r); dbbind(dbproc, 1, STRINGBIND, 0, (BYTE *) teststr); printf("\t%s\n\t-----------\n", dbcolname(dbproc, 1)); while ((row_code = dbnextrow(dbproc)) != NO_MORE_ROWS) { empty_resultset = 0; if (row_code == REG_ROW) { printf("\t%s\n", teststr); } else { /* not supporting computed rows in this unit test */ failed = 1; fprintf(stderr, "Failed. Expected a row\n"); exit(1); } } printf("row count %d\n", (int) dbcount(dbproc)); if (empty_resultset) ++num_empty_resultset; } else { add_bread_crumb(); fprintf(stderr, "Expected a result set.\n"); exit(1); } } /* while dbresults */ /* check return status */ printf("retrieving return status...\n"); if (dbhasretstat(dbproc) == TRUE) { printf("%d\n", return_status = dbretstatus(dbproc)); } else { printf("none\n"); } /* * Check output parameter values */ if (dbnumrets(dbproc) < 4) { /* dbnumrets missed something */ fprintf(stderr, "Expected 4 output parameters.\n"); exit(1); } printf("retrieving output parameters...\n"); printf("%-5s %-15s %5s %6s %-30s\n", "param", "name", "type", "length", "data"); printf("%-5s %-15s %5s %5s- %-30s\n", dashes5, dashes15, dashes5, dashes5, dashes30); for (i = 1; i <= dbnumrets(dbproc); i++) { add_bread_crumb(); retname = dbretname(dbproc, i); rettype = dbrettype(dbproc, i); retlen = dbretlen(dbproc, i); dbconvert(dbproc, rettype, dbretdata(dbproc, i), retlen, SYBVARCHAR, (BYTE*) teststr, -1); printf("%-5d %-15s %5d %6d %-30s\n", i, retname, rettype, retlen, teststr); add_bread_crumb(); save_retparam(&save_param, retname, teststr, rettype, retlen); } /* * Test the last parameter for expected outcome */ if ((save_param.name == NULL) || strcmp(save_param.name, param3)) { fprintf(stderr, "Expected retname to be '%s', got ", param3); if (save_param.name == NULL) fprintf(stderr, "<NULL> instead.\n"); else fprintf(stderr, "'%s' instead.\n", save_param.name); exit(1); } if (strcmp(save_param.value, "3")) { fprintf(stderr, "Expected retdata to be 3.\n"); exit(1); } if (save_param.type != SYBINT4) { fprintf(stderr, "Expected rettype to be SYBINT4 was %d.\n", save_param.type); exit(1); } if (save_param.len != 4) { fprintf(stderr, "Expected retlen to be 4.\n"); exit(1); } if(42 != return_status) { fprintf(stderr, "Expected status to be 42.\n"); exit(1); } printf("Good: Got 4 output parameters and 1 return status of %d.\n", return_status); /* Test number of result sets */ if (num_resultset != 3) { fprintf(stderr, "Expected 3 resultset got %d.\n", num_resultset); exit(1); } if (num_empty_resultset != 1) { fprintf(stderr, "Expected an empty resultset got %d.\n", num_empty_resultset); exit(1); } printf("Good: Got %d resultsets and %d empty resultset.\n", num_resultset, num_empty_resultset); add_bread_crumb(); fprintf(stdout, "Dropping procedure\n"); add_bread_crumb(); sprintf(cmd, "DROP PROCEDURE %s", proc_name); dbcmd(dbproc, cmd); add_bread_crumb(); dbsqlexec(dbproc); add_bread_crumb(); while (dbresults(dbproc) != NO_MORE_RESULTS) { /* nop */ } add_bread_crumb(); dbexit(); add_bread_crumb(); fprintf(stdout, "dblib %s on %s\n", (failed ? "failed!" : "okay"), __FILE__); free_bread_crumb(); free(save_param.name); free(save_param.value); return failed ? 1 : 0; }
RETCODE CDBL_Connection::x_Results(DBPROCESS* pLink) { unsigned int x_Status = 0x1; unique_ptr<CDB_Result> dbres; unique_ptr<impl::CResult> res; while ((x_Status & 0x1) != 0) { if ((x_Status & 0x20) != 0) { // check for return parameters from exec x_Status ^= 0x20; int n; if (GetResultProcessor() && (n = Check(dbnumrets(pLink))) > 0) { res.reset(new CDBL_ParamResult(*this, pLink, n)); dbres.reset(Create_Result(*res)); GetResultProcessor()->ProcessResult(*dbres); dbres.reset(); res.reset(); } continue; } if ((x_Status & 0x40) != 0) { // check for ret status x_Status ^= 0x40; if (GetResultProcessor() && Check(dbhasretstat(pLink))) { res.reset(new CDBL_StatusResult(*this, pLink)); dbres.reset(Create_Result(*res)); GetResultProcessor()->ProcessResult(*dbres); dbres.reset(); res.reset(); } continue; } if ((x_Status & 0x10) != 0) { // we do have a compute result res.reset(new CDBL_ComputeResult(*this, pLink, &x_Status)); dbres.reset(Create_Result(*res)); if(GetResultProcessor()) { GetResultProcessor()->ProcessResult(*dbres); } else { while(dbres->Fetch()) continue; } dbres.reset(); res.reset(); } RETCODE rc = Check(dbresults(pLink)); switch (rc) { case SUCCEED: x_Status |= 0x60; if (DBCMDROW(pLink) == SUCCEED) { // we could get rows in result if(!GetResultProcessor()) { while(1) { switch(Check(dbnextrow(pLink))) { case NO_MORE_ROWS: case FAIL: case BUF_FULL: break; default: continue; } break; } continue; } if (Check(dbnumcols(pLink)) == 1) { int ct = Check(dbcoltype(pLink, 1)); if ((ct == SYBTEXT) || (ct == SYBIMAGE)) { res.reset(new CDBL_BlobResult(*this, pLink)); } } if ( !res.get() ) res.reset(new CDBL_RowResult(*this, pLink, &x_Status)); dbres.reset(Create_Result(*res)); GetResultProcessor()->ProcessResult(*dbres); dbres.reset(); res.reset(); } else { continue; } case NO_MORE_RESULTS: x_Status = 2; break; default: return FAIL; } break; } return SUCCEED; }