Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » U++ SQL » Is it possible to call a stored procedure with an output parameter?
Re: Is it possible to call a stored procedure with an output parameter? [message #35450 is a reply to message #35431] Fri, 17 February 2012 21:49 Go to previous messageGo to previous message
jjacksonRIAB is currently offline  jjacksonRIAB
Messages: 220
Registered: June 2011
Experienced Member
I tried to figure out how I could get this working in U++ but I can't get return values out of MSSQL.

So far under ODBC.cpp I made these changes:

struct Param {
    int    ctype;
    int    sqltype;
    String data;
    SQLLEN li;
    int    direction;
    };


Then I modified ODBCConnection::Execute and I'm still trying to get this to work:

    bool ODBCConnection::Execute()
    {
	bool isStoredProcedure = false;
	
	LLOG("Execute " << (void *)this << " " << (void *)session);
	if(session->hstmt == SQL_NULL_HANDLE)
		return false;
	if(IsCurrent())
		session->current = NULL;
	session->FlushConnections();
	last_insert_table.Clear();
	number.Clear();
	text.Clear();
	time.Clear();
	CParser p(statement);
	
	// parse for evidence of a stored procedure call
	if(p.Char('{'))
	{
		p.Spaces();
		
		if(p.Id("call") || p.Id("CALL")) {
			procedure_name = p.ReadId();
			isStoredProcedure = true;
			//Cout() << "Proc name: " << procedure_name << "\n";
		}
		
		SDWORD      cbValue5;
		SDWORD      cbValue4;
		
		SQLSMALLINT ParameterType = SQL_PARAM_INPUT;
		
		if(!IsOk(SQLProcedureColumns (
			session->hstmt,
			NULL,
			0,
			NULL,
			0,
			(SQLCHAR *)~procedure_name,
			procedure_name.GetLength(),
			NULL,
			0
			)))
		{
			SQLFreeStmt(session->hstmt, SQL_CLOSE);
			return false;		
		}
		
		char parameter_name [20];
		
		if(!IsOk(SQLBindCol(
			session->hstmt,
			4, // Column 5 returns column name
			SQL_C_CHAR,
			parameter_name,
			sizeof(parameter_name),
			&cbValue4
			)))
		{
		}
		
		if(!IsOk(SQLBindCol(
			session->hstmt,
			5, // Column 5 returns whether parameter is input or output
			SQL_C_SHORT,
			&ParameterType,
			0,
			&cbValue5
			)))
		{
		}
			
		int i = 0;
		while(SQLFetch(session->hstmt) == SQL_SUCCESS)
		{
			Param& p = param[i];
			
			switch (ParameterType)
		    {
		      case SQL_PARAM_INPUT:
		      case SQL_PARAM_OUTPUT:
		      case SQL_PARAM_INPUT_OUTPUT:
				p.direction = ParameterType;
				i++;	
		      	break;

		      default:
		        break;
		    }
		}
		
		if(IsCurrent()) session->current = NULL;
		session->FlushConnections();
		
		number.Clear();
		text.Clear();
		time.Clear();
	}
	
	if((p.Id("insert") || p.Id("INSERT")) && (p.Id("into") || p.Id("INTO")) && p.IsId())
		last_insert_table = p.ReadId();
	if(!IsOk(SQLPrepare(session->hstmt, (SQLCHAR *)~statement, statement.GetCount())))
		return false;
	parse = false;
	bparam = param;
	param.Clear();
	for(int i = 0; i < bparam.GetCount(); i++) {
		Param& p = bparam[i];
		SQLSMALLINT     DataType;
		SQLULEN         ParameterSize;
		SQLSMALLINT     DecimalDigits;
		SQLSMALLINT     Nullable;
				
		if(!IsOk(SQLDescribeParam(session->hstmt, i + 1, &DataType, &ParameterSize, &DecimalDigits, &Nullable)))
			return false;

		Cout() << "Param direction: " << p.direction << "\n";

		if(!IsOk(SQLBindParameter(session->hstmt, i + 1, p.direction, p.ctype, DataType,
			                          ParameterSize, DecimalDigits, (SQLPOINTER)~p.data, 
			                          p.data.GetLength(),
			                          &p.li))) { 
			 return false;                         
		}
		
	}
	SQLSMALLINT ncol;
	
	SQLExecute(session->hstmt);
	
	if(isStoredProcedure) {
   		while (SQLMoreResults(session->hstmt)!= SQL_NO_DATA );
	}
	
	if(/*!IsOk(SQLExecute(session->hstmt)) ||*/ !IsOk(SQLNumResultCols(session->hstmt, &ncol))) {
		
		SQLFreeStmt(session->hstmt, SQL_CLOSE);
		return false;
	}

	
	session->current = this;
	info.Clear();
	binary.Clear();
	for(int i = 1; i <= ncol; i++) {
		SQLCHAR      ColumnName[256];
		SQLSMALLINT  NameLength;
		SQLSMALLINT  DataType;
		SQLULEN      ColumnSize;
		SQLSMALLINT  DecimalDigits;
		SQLSMALLINT  Nullable;
		if(!IsOk(SQLDescribeCol(session->hstmt, i, ColumnName, 255, &NameLength, &DataType,
		                        &ColumnSize, &DecimalDigits, &Nullable)))
			return false;
		binary.Add(false);
		SqlColumnInfo& f = info.Add();
		f.nullable = Nullable != SQL_NO_NULLS;
		f.binary = false;
		f.precision = DecimalDigits;
		f.scale = 0;
		f.width = ColumnSize;
		f.name = (char *)ColumnName;
		switch(DataType) {
		case SQL_DECIMAL:
		case SQL_NUMERIC:
		case SQL_SMALLINT:
		case SQL_INTEGER:
		case SQL_REAL:
		case SQL_FLOAT:
		case SQL_DOUBLE:
		case SQL_BIT:
		case SQL_TINYINT:
			f.type = DOUBLE_V;
			break;
		case SQL_BIGINT:
			f.type = INT64_V;
			break;
		case SQL_TYPE_DATE:
		case SQL_TYPE_TIMESTAMP:
			f.type = TIME_V;
			break;
		case SQL_BINARY:
		case SQL_VARBINARY:
		case SQL_LONGVARBINARY:
			f.type = STRING_V;
			f.binary = true;
			binary.Top() = true;
			break;
		default:
			f.type = STRING_V;
			break;
		}
	}
	SQLLEN rc;
	SQLRowCount(session->hstmt, &rc);
	rowsprocessed = rc;

	return true;
    }


I am calling SQLProcedureColumns to find out whether a given bound column is an input column, output column, or bidirectional. They say this is an expensive call so I'm considering wrapping it in a different method that will cache those parameters for later. These changes also do not bind return values (yet), just output parameters.

The problem I'm having is that even after calling SQLMoreResults (after SQLExecute), the documentation says those bound parameters should be modified, yet they aren't being changed - I can look through and confirm that all the direction types are correct.

Where did I go wrong? Am I doing this stupidly?
 
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Previous Topic: questions about sqlArray
Next Topic: SQL problem
Goto Forum:
  


Current Time: Thu May 09 15:51:35 CEST 2024

Total time taken to generate the page: 0.01589 seconds