Example #1
0
size_t CDBL_ParamResult::ReadItem(void* buffer, size_t buffer_size,
                                  bool* is_null)
{
    if ((unsigned int) m_CurrItem >= GetDefineParams().GetNum()) {
        if (is_null)
            *is_null = true;
        return 0;
    }

    const BYTE* d_ptr = Check(dbretdata(GetCmd(), m_CurrItem + 1));
    DBINT d_len = Check(dbretlen (GetCmd(), m_CurrItem + 1));

    if (d_ptr == 0 || d_len < 1) { // NULL value
        ++m_CurrItem;
        m_Offset = 0;
        if (is_null)
            *is_null = true;
        return 0;
    }

    if (is_null)
        *is_null = false;
    if ((size_t) (d_len - m_Offset) < buffer_size) {
        buffer_size = d_len - m_Offset;
    }

    memcpy(buffer, d_ptr + m_Offset, buffer_size);
    m_Offset += buffer_size;
    if (m_Offset >= (size_t) d_len) {
        m_Offset = 0;
        ++m_CurrItem;
    }
    return buffer_size;
}
Example #2
0
EDB_Type CDBL_Result::RetGetDataType(int n)
{
    switch (Check(dbrettype(GetCmd(), n))) {
    case SYBBINARY:    return (Check(dbretlen(GetCmd(), n)) > 255)? eDB_LongBinary :
                                                        eDB_VarBinary;
    case SYBBIT:       return eDB_Bit;
    case SYBCHAR:      return (Check(dbretlen(GetCmd(), n)) > 255)? eDB_LongChar :
                                                        eDB_VarChar;
    case SYBDATETIME:  return eDB_DateTime;
    case SYBDATETIME4: return eDB_SmallDateTime;
    case SYBINT1:      return eDB_TinyInt;
    case SYBINT2:      return eDB_SmallInt;
    case SYBINT4:      return eDB_Int;
    case SYBFLT8:      return eDB_Double;
    case SYBREAL:      return eDB_Float;
    default:           return eDB_UnsupportedType;
    }
}
Example #3
0
// Aux. for CDBL_ParamResult::GetItem()
// CDB_Image and CDB_Text are not handled by this function ...
CDB_Object* CDBL_Result::RetGetItem(int item_no,
                                    SDBL_ColDescr* fmt,
                                    CDB_Object* item_buff)
{
    EDB_Type b_type = item_buff ? item_buff->GetType() : eDB_UnsupportedType;
    const BYTE* d_ptr = Check(dbretdata(GetCmd(), item_no));
    DBINT d_len = Check(dbretlen (GetCmd(), item_no));
    CDB_Object* val = s_GenericGetItem(fmt->data_type, item_buff,
                                       b_type, d_ptr, d_len);
    if (!val) {
        DATABASE_DRIVER_ERROR( "Unexpected result type." + GetDbgInfo(), 230004 );
    }
    return val;
}
Example #4
0
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;
}
Example #5
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;
}
Example #6
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);
}
Example #7
0
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);
}
Example #8
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;
}