| 
      
      
      From: Carlos G.A. <car...@ho...> - 2002-07-01 09:39:39
      
     | 
| Hello:
I have made changes to the CVS sources for make that binary and text BLOB 
fields work under Visual Foxpro.
I made the test with a text BLOB field with 146948 characters and two binary 
BLOB fields wich cointains two images of
644 kb and 89,5 kb and it seems to work fine.
Here is the list of changes:
OdbcStatement.h:
1. Modified Binding struct
struct Binding {
	int		type;
	int		cType;
	int		sqlType;
	void		*pointer;
	SQLINTEGER	bufferLength;
//Suggested by R. Milharcic
	SQLINTEGER	dataOffset;
	bool		startedTransfer;
	bool		data_at_exec;
	SQLINTEGER	*indicatorPointer;
	};
2. Modified declaration of sqlParamData for:
	RETCODE sqlParamData(SQLPOINTER *ptr);
3. Returned declaration of setParameter to the original declaration:
	void setParameter (Binding *binding, int parameter);
4. Removed declarations of:
	RETCODE setParameters();	//Added 2002-06-04 RM
	void executeSQL();		//Added 2002-06-04 RM
OdbcStatement.cpp:
1. Removed definitions of:
	RETCODE setParameters();	//Added 2002-06-04 RM
	void executeSQL();		//Added 2002-06-04 RM
2. Remove comments in executeStatement and made a new implementation of it:
RETCODE OdbcStatement::executeStatement()
{
	parameterNeedData = -1;
	for (int n = 0; n < numberParameters; ++n)
	{
		Binding *binding = parameters + n;
		if ( ( binding->pointer || binding->indicatorPointer ) && binding->type != 
SQL_PARAM_OUTPUT )
			if( *binding->indicatorPointer == SQL_DATA_AT_EXEC || 
*binding->indicatorPointer < SQL_LEN_DATA_AT_EXEC_OFFSET )
				return SQL_NEED_DATA;
			else
				setParameter (binding, n + 1);
	}
	if (callableStatement)
		for (int n = 0; n < numberParameters; ++n)
			{
			Binding *binding = parameters + n;
			if (binding->pointer && binding->type != SQL_PARAM_INPUT)
				callableStatement->registerOutParameter (n + 1, binding->sqlType);
			}
	statement->execute();
	connection->transactionStarted();
	if (callableStatement)
		for (int n = 0; n < numberParameters; ++n)
			{
			Binding *binding = parameters + n;
			if (binding->pointer && binding->type != SQL_PARAM_INPUT)
				setValue (binding, n + 1);
			}
	getResultSet();
	return SQL_SUCCESS;
}
3. New implementation for sqlParamData and sqlPutData:
RETCODE OdbcStatement::sqlParamData(SQLPOINTER *ptr)
{
	RETCODE retcode = sqlSuccess();
	clearErrors();
	for (int n = 0; n < numberParameters; ++n)
	{
		Binding *binding = parameters + n;
		if( binding->indicatorPointer && !binding->startedTransfer &&
			( *binding->indicatorPointer == SQL_DATA_AT_EXEC || 
*binding->indicatorPointer < SQL_LEN_DATA_AT_EXEC_OFFSET ) )
		{
			parameterNeedData = n;
			*ptr = binding->pointer;
			binding->data_at_exec = true;
			switch (binding->cType)
			{
				case SQL_C_CHAR:
				{
					if ( !binding->startedTransfer )
					{
						binding->startedTransfer = true;
						*binding->indicatorPointer = 0;
						statement->beginClobDataTransfer(n+1);
					}
					return SQL_NEED_DATA;
				}
				break;
				case SQL_C_BINARY:
				{
					if ( !binding->startedTransfer )
					{
						binding->startedTransfer = true;
						*binding->indicatorPointer = 0;
						statement->beginBlobDataTransfer(n+1);
					}
					return SQL_NEED_DATA;
				}
				break;
			}
		}
		else
		{
			if (binding->startedTransfer)
			{
				binding->startedTransfer = false;
				if(binding->data_at_exec)
					switch (binding->cType)
					{
						case SQL_C_CHAR:
							statement->endClobDataTransfer();
							break;
						case SQL_C_BINARY:
							statement->endBlobDataTransfer();
							break;
					}
			}
		}
	}
	try
		{
		retcode = executeStatement();
		}
	catch (SQLException& exception)
		{
		postError ("HY000", exception);
		retcode = SQL_ERROR;
		}
	if (retcode && retcode != SQL_SUCCESS_WITH_INFO)
		return retcode;
	return sqlSuccess();
}
RETCODE OdbcStatement::sqlPutData (SQLPOINTER value, SQLINTEGER valueSize)
{
	if (parameterNeedData == -1)
		return sqlReturn (SQL_ERROR, "HY010", "Function sequence error :: 
OdbcStatement::sqlPutData");
    if (parameterNeedData >= numberParameters)
		return sqlReturn (SQL_ERROR, "HY000", "General error :: 
OdbcStatement::sqlPutData");
    Binding *binding = parameters + parameterNeedData;
    if (!binding)
		return sqlReturn (SQL_ERROR, "HY000", "General error :: 
OdbcStatement::sqlPutData");
	if (valueSize == SQL_NULL_DATA)
	{
		*binding->indicatorPointer = SQL_NULL_DATA;
		return SQL_SUCCESS;
	}
	switch (binding->cType)
	{
		case SQL_C_CHAR:
		{
			if(valueSize == SQL_NTS)
				valueSize = strlen( (char*)value );
			*binding->indicatorPointer += valueSize;
			statement->putClobSegmentData (valueSize, value);
		}
		break;
		case SQL_C_BINARY:
		{
			*binding->indicatorPointer += valueSize;
			statement->putBlobSegmentData (valueSize, value);
		}
		break;
	}
	return sqlSuccess();
}
4. Changes in setParameter for manage data at exec parameters:
void OdbcStatement::setParameter(Binding * binding, int parameter)
{
	clearErrors();
	if (binding && binding->indicatorPointer && *(binding->indicatorPointer) == 
SQL_NULL_DATA)
		{
		statement->setNull(parameter, 0);
		return;
		}
	try
		{
		switch (binding->cType)
			{
			case SQL_C_CHAR:
			{
				if (!binding->data_at_exec)
					switch( *binding->indicatorPointer )
					{
						case SQL_NTS:
							statement->setString (parameter, (char*) binding->pointer );
							break;
						default:
							statement->setString (parameter, (char*) binding->pointer, 
*binding->indicatorPointer );
							break;
					}
			}
			break;
			case SQL_C_SHORT:
			case SQL_C_SSHORT:
			case SQL_C_USHORT:
				statement->setShort (parameter, *(short*) binding->pointer);
				break;
			case SQL_C_LONG:
			case SQL_C_SLONG:
			case SQL_C_ULONG:
				statement->setInt (parameter, *(long*) binding->pointer);
				break;
			case SQL_C_FLOAT:
				statement->setFloat (parameter, *(float*) binding->pointer);
				break;
			case SQL_C_DOUBLE:
				statement->setDouble (parameter, *(double*) binding->pointer);
				break;
			case SQL_C_TINYINT:
			case SQL_C_STINYINT:
			case SQL_C_UTINYINT:
				statement->setByte (parameter, *(char*) binding->pointer);
				break;
			case SQL_C_SBIGINT:
			case SQL_C_UBIGINT:
				statement->setLong (parameter, *(QUAD*) binding->pointer);
				break;
			case SQL_C_TYPE_TIMESTAMP:
				{
				OdbcDateTime converter;
				tagTIMESTAMP_STRUCT *var = (tagTIMESTAMP_STRUCT*) binding->pointer;
/*	Orig.
// this is obsolete ... I want more days ;-)
				DateTime dateTime;
				converter.convert (var, &dateTime);
				statement->setDate (parameter, dateTime);
*/
//From B. Schulte
				TimeStamp timestamp;
		        converter.convert (var, ×tamp);
				statement->setTimestamp ( parameter, timestamp);
				}
				break;
			case SQL_C_TYPE_DATE:
				{
				OdbcDateTime converter;
				tagDATE_STRUCT *var = (tagDATE_STRUCT*) binding->pointer;
				DateTime dateTime;
				converter.convert (var, &dateTime);
				statement->setDate (parameter, dateTime);
				}
				break;
			case SQL_C_TYPE_TIME:
				{
				tagTIME_STRUCT *var = (tagTIME_STRUCT*) binding->pointer;
				SqlTime dateTime;
				dateTime.timeValue = var->hour * 60 * 60 + var->minute * 60 + 
var->second;
				statement->setTime (parameter, dateTime);
				}
				break;
			case SQL_C_BINARY:
				if (!binding->data_at_exec)
					statement->setBytes(parameter, *(binding->indicatorPointer), 
binding->pointer);
				break;
			case SQL_C_BIT:
			//case SQL_C_BOOKMARK:
			//case SQL_C_VARBOOKMARK:
			case SQL_C_NUMERIC:
			//case SQL_C_GUID:
				//break;
			default:
				postError (new OdbcError (0, "HYC00", "Optional feature not 
implemented"));
				return;
			}
		}
	catch (SQLException& exception)
		{
		postError ("HY000", exception);
		return;
		}
}
Connection.h
1. Changed this declarations
    virtual void        beginDataTransfer(int index) = 0;
    virtual void        putSegmentData (int length, const void *bytes) = 0;
    virtual void        endDataTransfer() = 0;
for :
    virtual void        beginBlobDataTransfer(int index) = 0;
    virtual void        putBlobSegmentData (int length, const void *bytes) = 
0;
    virtual void        endBlobDataTransfer() = 0;
And added 3 new declarations:
    virtual void        beginClobDataTransfer(int index) = 0;
    virtual void        putClobSegmentData (int length, const void *bytes) = 
0;
    virtual void        endClobDataTransfer() = 0;
IscPreparedStatement.h:
1. Add this at line 44:
class AsciiBlob;
2. Add this at end of class declaration ( under BinaryBlob              
*segmentBlob; )
	AsciiBlob				*segmentClob;
3. Changed this declarations
    virtual void        beginDataTransfer(int index);
    virtual void        putSegmentData (int length, const void *bytes);
    virtual void        endDataTransfer();
for :
    virtual void        beginBlobDataTransfer(int index);
    virtual void        putBlobSegmentData (int length, const void *bytes);
    virtual void        endBlobDataTransfer();
And added 3 new declarations:
    virtual void        beginClobDataTransfer(int index) = 0;
    virtual void        putClobSegmentData (int length, const void *bytes) = 
0;
    virtual void        endClobDataTransfer() = 0;
IscPreparedStatement.cpp
1.  Change definitions of
    virtual void        beginDataTransfer(int index);
    virtual void        putSegmentData (int length, const void *bytes);
    virtual void        endDataTransfer();
for
void IscPreparedStatement::beginBlobDataTransfer(int index)
{
    if (segmentBlob)
        endBlobDataTransfer();
    segmentBlob = new BinaryBlob();
    getParameter (index - 1)->setValue (segmentBlob);
}
void IscPreparedStatement::putBlobSegmentData(int length, const void* bytes)
{
	if (segmentBlob)
	    segmentBlob->putSegment (length, (char*) bytes, true);
}
void IscPreparedStatement::endBlobDataTransfer()
{
	if (segmentBlob)
	{
		segmentBlob->release();
		segmentBlob = NULL;
	}
}
And added 3 news definitions:
void IscPreparedStatement::beginClobDataTransfer(int index)
{
	if (segmentClob)
        endClobDataTransfer();
    segmentClob = new AsciiBlob();
	getParameter (index - 1)->setValue (segmentClob);
}
void IscPreparedStatement::putClobSegmentData(int length, const void* bytes)
{
	if( segmentClob )
		segmentClob->putSegment (length, (char*) bytes, true);
}
void IscPreparedStatement::endClobDataTransfer()
{
	if( segmentClob )
	{
		segmentClob->release();
		segmentClob = NULL;
	}
}
IscCallableStatement.h:
1. Changed this declarations
    virtual void        beginDataTransfer(int index);
    virtual void        putSegmentData (int length, const void *bytes);
    virtual void        endDataTransfer();
for :
    virtual void        beginBlobDataTransfer(int index);
    virtual void        putBlobSegmentData (int length, const void *bytes);
    virtual void        endBlobDataTransfer();
And added 3 new declarations:
    virtual void        beginClobDataTransfer(int index) = 0;
    virtual void        putClobSegmentData (int length, const void *bytes) = 
0;
    virtual void        endClobDataTransfer() = 0;
IscCallableStatement.cpp:
1.  Change definitions of
    virtual void        beginDataTransfer(int index);
    virtual void        putSegmentData (int length, const void *bytes);
    virtual void        endDataTransfer();
for
// Added by RM 2002-06-04
void IscCallableStatement::beginBlobDataTransfer(int index)
{
    Parent::beginBlobDataTransfer(index);
}
// Added by RM 2002-06-04
void IscCallableStatement::putBlobSegmentData (int length, const void 
*bytes)
{
    Parent::putBlobSegmentData(length, bytes);
}
// Added by RM 2002-06-04
void IscCallableStatement::endBlobDataTransfer()
{
    Parent::endBlobDataTransfer();
}
And added 3 news definitions:
void IscCallableStatement::beginClobDataTransfer(int index)
{
    Parent::beginClobDataTransfer(index);
}
void IscCallableStatement::putClobSegmentData (int length, const void 
*bytes)
{
    Parent::putClobSegmentData(length, bytes);
}
void IscCallableStatement::endClobDataTransfer()
{
    Parent::endClobDataTransfer();
}
BinaryBlob.cpp
1. Return the use of use count to the original way for make that AsciiBlob 
and BinaryBlob works equal with useCount.
BinaryBlob::BinaryBlob()
{
//	useCount = 0;
	useCount = 1;
	offset = 0;
	populated = true;
}
BinaryBlob::BinaryBlob(int minSegmentSize) : Stream (minSegmentSize)
{
//	useCount = 0;
	useCount = 1;
	offset = 0;
	populated = true;
}
#ifdef ENGINE
BinaryBlob::BinaryBlob(Database * db, long recNumber, long sectId)
{
//	useCount = 0;
	useCount = 1;
	offset = 0;
	populated = false;
	database = db;
	recordNumber = recNumber;
	sectionId = sectId;
}
#endif
BinaryBlob::BinaryBlob(Clob * blob)
{
//	useCount = 0;
	useCount = 1;
	Stream::putSegment (blob);
}
int BinaryBlob::release()
{
//	if (--useCount <= 0)
	if (--useCount == 0)
		{
		delete this;
		return 0;
		}
	return useCount;
}
Best regards
Carlos Guzmán Álvarez
Vigo-España
_________________________________________________________________
MSN. Más Útil cada Día. http://www.msn.es/intmap/
 |