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/ |