I am using Delphi 6 and MS Sql (2005).
My application has been working perfectly with this driver for some time now. I've updated the drivers to the latest versions.
As part of an expansion of the capabilities of my app, I added a number of NvarChar fields to one of the tables. I coded in the new fields to the Delphi app and I can Write to the new fields just fine. However, if the new fields (and only the new fields - this doesn't happen with the original fields of that table) are 'full' (ie, a Nvarchar(2) field with 2 Chars of data) when I try to read the data back in, I get:
SQL_SUCCESS_WITH_INFO (01004) and the data is right truncated by 1 character.
I have studied the various field definitions and I see no difference in the original nvarchar fields of this table, and the ones that I've added.
I have also used MS Access to edit the data, and it operates just fine. It only seems to be OpenOdbc driver that doesn't like these fields for some reason.
Can anyone give me suggestion on where to look?
Thanks.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
+ fixed: checking result of call SQLGetData for next methods ("DbxOpenOdbc.pas"):
procedure TSqlCursorOdbc.DoFetchLateBoundData
procedure TSqlCursorOdbc.FetchLateBoundData
I have changed following analysis:
if OdbcRetcode <> OdbcApi.SQL_SUCCESS then
==>
if (OdbcRetcode <> OdbcApi.SQL_SUCCESS) or (OdbcRetcode <> OdbcApi.SQL_SUCCESS_WITH_INFO) then
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for such a fast reply and attempt to fix.
I installed the new driver, compiled the DLL and re-compiled my app.
Same issue.
It may be a red herring, but does the distinction of Added Fields (ALTER TABLE) somehow make a difference?
The fields I created when I originally designed this table do not exhibit this issue. Only fields that I recently added to this table are causing the problem.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I it is necessary more information:
- add in your project the module "DbxOpenOdbcStatic.pas" - now you will be able to debug "DbxOpenOdbc.pas"
- in what place occurs the error/exception? (number of the line in pas file)
- ? connection options
- ? table structure
- ? when application compiled with options: _DEBUG_;_TRACE_CALLS_ drivers sended debug information into log window(IDE, DebugView)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
procedureTSqlDriverOdbc.OdbcCheck;//(//CheckCode:SqlReturn;//constOdbcFunctionName:AnsiString;//HandleType:Smallint;//Handle:SqlHandle;//DbxConStmt:PDbxConStmt;//Connection:TSqlConnectionOdbc=nil;//Command:TSqlCommandOdbc=nil;//Cursor:TSqlCursorOdbc=nil;//maxErrorCount:Integer=0;//eTraceCat:TRACECat=cTDBXTraceFlags_none);begin{$IFDEF_TRACE_CALLS_}trytryLogEnterProc('TSqlDriverOdbc.OdbcCheck',['CheckCode =',CheckCode,'OdbcFunctionName =',OdbcFunctionName,'HandleType =',HandleType]);{$ENDIF_TRACE_CALLS_}caseCheckCodeofOdbcApi.SQL_SUCCESS:exit;OdbcApi.SQL_SUCCESS_WITH_INFO:begintryfOdbcErrorLines.Clear;fOdbcErrorLines.Add(string('SQL_SUCCESS_WITH_INFO returned from ODBC function '+OdbcFunctionName));RetrieveOdbcErrorInfo(CheckCode,HandleType,Handle,DbxConStmt,Connection,Command,Cursor,0,maxErrorCount,eTraceCat);====>>raiseEDbxODBCWarning.Create(fOdbcErrorLines.Text);
Here is the Event Log immediately prior to the error:
ODS::(0)~-:TSqlCursorOdbc.FetchLateBoundData;ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlCursorOdbc.getString,ExitInfo:Value=""IsBlank="True";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlCursorOdbc.getColumnType,Params:ColumnNumber="22";ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlCursorOdbc.getColumnType,ExitInfo:Type="fldZSTRING"SubType="";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlCursorOdbc.getString,Params:ColumnNumber="22";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlCursorOdbc.FetchLateBoundData,Params:ColNo="22";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlDriverOdbc.OdbcCheck,Params:CheckCode="0"OdbcFunctionName="SQLGetData("InspectCity")"HandleType="3";ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlDriverOdbc.OdbcCheck;ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlCursorOdbc.FetchLateBoundData;ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlCursorOdbc.getString,ExitInfo:Value=""IsBlank="False";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlCursorOdbc.getColumnType,Params:ColumnNumber="23";ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlCursorOdbc.getColumnType,ExitInfo:Type="fldZSTRING"SubType="";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlCursorOdbc.getString,Params:ColumnNumber="23";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlCursorOdbc.FetchLateBoundData,Params:ColNo="23";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlDriverOdbc.OdbcCheck,Params:CheckCode="1"OdbcFunctionName="SQLGetData("InspectState")"HandleType="3";ProcessAppraisal2.exe($180C)ODS::(0)->:TSqlDriverOdbc.RetrieveOdbcErrorInfo,Params:CheckCode="1"HandleType="3"Handle="$754770";ProcessAppraisal2.exe($180C)ODS::(0)~-:TSqlDriverOdbc.RetrieveOdbcErrorInfo;ProcessAppraisal2.exe($180C)Firstchanceexceptionat$74D3B727.ExceptionclassEDbxOdbcWarningwithmessage'SQL_SUCCESS_WITH_INFO returned from ODBC function SQLGetData("InspectState")ODBC Return Code: 1: SQL_SUCCESS_WITH_INFOODBC SqlState: 01004[Microsoft][ODBCSQLServerDriver]String data, right truncation'.ProcessAppraisal2.exe($180C)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
…
var
bUnicodeString, bTypeChanged: Boolean;
…
SQL_CHAR, SQL_VARCHAR, SQL_WCHAR, SQL_WVARCHAR, SQL_GUID:
begin
fDbxType := fldZSTRING;
bUnicodeString := ((fSqlType = SQL_WCHAR) or (fSqlType = SQL_WVARCHAR)) and
(fOwnerDbxConnection.fConnectionOptions = osOn);
if bUnicodeString then
begin
if fOwnerDbxDriver.fClientVersion >= 30 then
begin
fDbxType := fldWIDESTRING;
end
else
begin
fDbxSubType := fldstWIDEMEMO;
end;
fOdbcHostVarType := SQL_C_WCHAR;
if fSqlType = SQL_WCHAR then
fDbxSubType := fldstFIXED;
end
else if (fSqlType = SQL_CHAR) or (fSqlType = SQL_WCHAR) then
begin // Fixed length field
fOdbcHostVarType := SQL_C_CHAR;
fDbxSubType := fldstFIXED;
end
else
begin
fOdbcHostVarType := SQL_C_CHAR;
end;
if fColSize <= 0 then
begin
fColSize := 1;
// SQL SERVER 2005:
{
declare @content varchar(max)
select @content = 'hello world'
select content1 = @content
}
if (fOwnerDbxConnection.fOdbcDriverType in ) then
begin
fColSize := 8000;
end;
end;
{+2.03 INFORMIX LVARCHAR}
{ Vadim V.Lopushansky:
Fixed when error for mapping INFORMIX LVARCHAR type over native ODBC.
Example query: select amparam from sysindices
}
if ( (fColSize > 255) and
(fOwnerDbxConnection.fConnectionOptions = osOn) )
then
begin
fDbxType := fldBLOB;
if bUnicodeString then
fDbxSubType := fldstWIDEMEMO
else
fDbxSubType := fldstMEMO;
end;
if {((fOwnerCommand.fCommandBlobSizeLimitK>0) and (fColSize > fOwnerCommand.fCommandBlobSizeLimitK*1024)) or} (fColSize > COLUMN_BIND_SIZE_LIMIT) then
begin // large size:
if (fOwnerCommand.fCommandBlobSizeLimitK <= 0) then
begin
fOdbcLateBound := True;
end
else
begin
{ Vadim>???Vad>All if fColSize > 2 Gb ???
Informix native odbc supported fOdbcLateBound, but if not ?
DataDirect ODBC for this informix type return length 2048.
}
// trim column:
fColSize := 2048;
end;
end;
if fOdbcLateBound then
fIsBuffer := True;
bTypeChanged := False;
if (Self.fOwnerDbxConnection.fDbmsType = eDbmsTypeFlashFiler) and (fColSize = 4) then
begin
IntAttribute := OdbcApi.SQL_FALSE;
OdbcRetcode := SQLColAttributeInt(fHStmt, ColNo, SQL_DESC_AUTO_UNIQUE_VALUE,
nil, 0, nil, IntAttribute);
if {AutoIncr=} (OdbcRetcode = OdbcApi.SQL_SUCCESS) and (IntAttribute = SQL_TRUE) then
begin
bTypeChanged := True;
fDbxType := fldINT32;
fOdbcHostVarType := SQL_C_LONG;
fOdbcHostVarSize := SizeOf(SqlInteger);
fDbxSubType := fldstAUTOINC;
fIsBuffer := False;
end
else
if (OdbcRetcode = OdbcApi.SQL_SUCCESS) then
fOwnerDbxDriver.RetrieveOdbcErrorInfo(OdbcRetcode, SQL_HANDLE_STMT, fHStmt,
fOwnerCommand.fDbxConStmtInfo.fDbxConStmt, fOwnerDbxConnection, fOwnerCommand, nil, 1);
end;
if not bTypeChanged then
begin
fOdbcHostVarSize := fColSize + 1 + 1; // Add 1 for null terminator and 1 for spare :)
if fOdbcHostVarType = SQL_C_WCHAR then
fOdbcHostVarSize := fOdbcHostVarSize * SizeOf(WideChar);
(*
Field Size is very big (Firebird, IBPhoenix OpenSource ODBC Driver):
CREATE TABLE … (
…
LANGUAGE_REQ VARCHAR(15) CHARACTER SET NONE
);
*)
if fColSize > dsMaxStringSize then
begin // analog of SQL_LONGVARCHAR:
if bUnicodeString then
begin
fDbxType := fldWIDESTRING;
fDbxSubType := fldstMEMO;
fOdbcHostVarType := SQL_C_WCHAR;
end
else
begin
fDbxType := fldBLOB;
fDbxSubType := fldstMEMO;
fOdbcHostVarType := SQL_C_CHAR;
end;
if fOwnerCommand.fCommandBlobSizeLimitK > 0 then
// If BLOBSIZELIMIT specified, we early bind, just like normal column
// Otherwise get size and column data AFTER every row fetch, using SqlGetData
begin
fOdbcHostVarSize := fOwnerCommand.fCommandBlobSizeLimitK * 1024;
end
else
if (fOwnerDbxConnection.fOdbcDriverType <> eOdbcDriverTypeSQLite) then
begin
fOdbcLateBound := True;
end
else // SQL LITE:
begin
fOdbcHostVarSize := fColSize + 1;
if fOdbcHostVarType = SQL_C_WCHAR then
fOdbcHostVarSize := fOdbcHostVarSize * SizeOf(WideChar);
end;
if fOdbcLateBound then
fIsBuffer := True;
end;
end;
end;
…
SQL_LONGVARCHAR, SQL_WLONGVARCHAR:
begin
bUnicodeString := (fSqlType = SQL_WLONGVARCHAR) and
(fOwnerDbxConnection.fConnectionOptions = osOn);
if bUnicodeString then
begin
fDbxType := fldBLOB;
fDbxSubType := fldstWIDEMEMO;
fOdbcHostVarType := SQL_C_WCHAR;
end
else
begin
fDbxType := fldBLOB;
fDbxSubType := fldstMEMO;
fOdbcHostVarType := SQL_C_CHAR;
end;
if fOwnerCommand.fCommandBlobSizeLimitK > 0 then
// If BLOBSIZELIMIT specified, we early bind, just like normal column
// Otherwise get size and column data AFTER every row fetch, using SqlGetData
begin
fOdbcHostVarSize := fOwnerCommand.fCommandBlobSizeLimitK * 1024;
end
else
if (fOwnerDbxConnection.fOdbcDriverType <> eOdbcDriverTypeSQLite) then
fOdbcLateBound := True
else // SQL LITE:
fOdbcHostVarSize := fColSize;
//
fOdbcHostVarSize := fOdbcHostVarSize + 1 + 1; // Add 1 for null terminator and 1 for spare :)
if fOdbcHostVarType = SQL_C_WCHAR then
fOdbcHostVarSize := fOdbcHostVarSize * SizeOf(WideChar);
//
if fOdbcLateBound then
fIsBuffer := True;
if fColSize=0 then
fColSize := -1;
end;
…
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK. That last post confused me… I searched through the Code and added the Inc(fOdbcHostVarSize, 4); // ******* increase of buffer
Lines, but they don't look to be in the second code snippet you posted.
At any rate, I re-compiled with the two Inc(fOdbcHostVarSize, 4); // ******* increase of buffer statements and initial tests look good.
I'll need to test a few more things, but so far I think that has fixed it.
Question: Should I change 'AND' back to 'OR' on the FetchLateBoundData & DoFetchLateBoundData procedures?
Thanks,
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The Data Truncate issue looks to be resolved.
I have another issue 'Record Not Found or Changed by another user' when I try to write the data.
I am pretty sure that it's unrelated.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If this occurs for event, when old/new importance NULL/"", then decision possible. Some servers do not support transparent NULL and "".
Need testing with next connection options:
coNullStrParam=1
coEmptyStrParam=1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
For example: SQLITE ODBC does not support NULL for char types. For SQLITE happened to completely to exclude NULL:
"DbxOpenOdbc.pas"
function TSqlConnectionOdbc.RetrieveDriverName
…
eOdbcDriverTypeSQLite:
begin
…
fConnectionOptionsDrv := osOn; // ******** !!!
end;
…
function TSqlCommandOdbc.setParameter
…
if (bIsNull = 1) and (fOwnerDbxConnection.fDbmsType = eDbmsTypeSQLite) then // ******* !!!
begin { fOdbcDriverType = eOdbcDriverTypeSQLite }
fBindData := @fValue;
PWideChar(fBindData)^ := cNullWideChar;
end;
end;
fldINT32, fldUINT32:
…
function TSqlCursorOdbc.getString
…
if IsBlank then
begin
if bNotUnicodeString then
pDestA^ := cNullAnsiChar
else
pDestW^ := cNullWideChar;
if fOwnerDbxConnection.fDbmsType = eDbmsTypeSQLite then // ******* !!!
IsBlank := False;
end
else
…
"DbxOpenOdbc3.pas"
function TSqlCursorOdbc3.getWideString
…
if IsBlank then
begin
Value^ := cNullWideChar;
if TSqlConnectionOdbc3(fOwnerDbxConnection).fDbmsType = eDbmsTypeSQLite then // ******** !!!
IsBlank := False;
end
else
…
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK. Took me a while to sort out the iterations of this next problem.
I have tried both of the Params listed above (not together, but each separately) as well, as without.
I am able to 'Write' to any Table one time. The second time I try to write to the table, I get 'Record not found ….'
I have an older version of the App (compiled with an older version of the driver) that I can use to 'Reset' the record. With the older version of the driver, I can write to the record as many times as I like. As soon as I run the alpha driver, I can write to the record only once, regardless of the Param that I use.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is because after the first update the new values are not like in the database. See the event log (or sql monitor) of query to second update. See the updated values in log and in database. Try to "SELECT * from … where" a sample with such values as in the update query.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am using Delphi 6 and MS Sql (2005).
My application has been working perfectly with this driver for some time now. I've updated the drivers to the latest versions.
As part of an expansion of the capabilities of my app, I added a number of NvarChar fields to one of the tables. I coded in the new fields to the Delphi app and I can Write to the new fields just fine. However, if the new fields (and only the new fields - this doesn't happen with the original fields of that table) are 'full' (ie, a Nvarchar(2) field with 2 Chars of data) when I try to read the data back in, I get:
SQL_SUCCESS_WITH_INFO (01004) and the data is right truncated by 1 character.
I have studied the various field definitions and I see no difference in the original nvarchar fields of this table, and the ones that I've added.
I have also used MS Access to edit the data, and it operates just fine. It only seems to be OpenOdbc driver that doesn't like these fields for some reason.
Can anyone give me suggestion on where to look?
Thanks.
Version 3.2010.11.05
+ fixed: checking result of call SQLGetData for next methods ("DbxOpenOdbc.pas"):
procedure TSqlCursorOdbc.DoFetchLateBoundData
procedure TSqlCursorOdbc.FetchLateBoundData
I have changed following analysis:
if OdbcRetcode <> OdbcApi.SQL_SUCCESS then
==>
if (OdbcRetcode <> OdbcApi.SQL_SUCCESS) or (OdbcRetcode <> OdbcApi.SQL_SUCCESS_WITH_INFO) then
Thank you for such a fast reply and attempt to fix.
I installed the new driver, compiled the DLL and re-compiled my app.
Same issue.
It may be a red herring, but does the distinction of Added Fields (ALTER TABLE) somehow make a difference?
The fields I created when I originally designed this table do not exhibit this issue. Only fields that I recently added to this table are causing the problem.
I it is necessary more information:
- add in your project the module "DbxOpenOdbcStatic.pas" - now you will be able to debug "DbxOpenOdbc.pas"
- in what place occurs the error/exception? (number of the line in pas file)
- ? connection options
- ? table structure
- ? when application compiled with options: _DEBUG_;_TRACE_CALLS_ drivers sended debug information into log window(IDE, DebugView)
Line 3368:
ConnectionOptions:
Table Structure
It is necessary on level above than "procedure TSqlDriverOdbc.OdbcCheck;"
Here is the Event Log immediately prior to the error:
try to change (procedure TSqlCursorOdbc.FetchLateBoundData):
if OdbcRetcode <> OdbcApi.SQL_SUCCESS then
on
if (OdbcRetcode <> OdbcApi.SQL_SUCCESS)and(OdbcRetcode <> OdbcApi.SQL_SUCCESS_WITH_INFO) then
if (OdbcRetcode <> OdbcApi.SQL_SUCCESS) OR (OdbcRetcode <> OdbcApi.SQL_SUCCESS_WITH_INFO) then
AND :)
procedure TSqlCursorOdbc.DoFetchLateBoundData;//(OdbcRetcode: OdbcApi.SqlReturn;);
…
OdbcRetcode := SQLGetData(
fHStmt, fOdbcColNo, fOdbcHostVarType,
fOdbcHostVarAddress.Ptr, fOdbcHostVarSize, fColValueSizePtr);
if (OdbcRetcode <> OdbcApi.SQL_SUCCESS)and(OdbcRetcode <> OdbcApi.SQL_SUCCESS_WITH_INFO) then
OdbcCheck(OdbcRetcode, 'SQLGetData("'+StrAnsiStringParam(aOdbcBindCol.fColName)+'")');
fIsFetched := True;
end;
{$IFDEF _TRACE_CALLS_}
except on e: Exception do begin LogExceptProc('TSqlCursorOdbc.DoFetchLateBoundData', e); raise; end; end;
finally LogExitProc('TSqlCursorOdbc.DoFetchLateBoundData'); end;
{$ENDIF _TRACE_CALLS_}
end;
procedure TSqlCursorOdbc.FetchLateBoundData;//(ColNo: SqlUSmallint);
…
OdbcRetcode := SQLGetData(
fHStmt, fOdbcColNo, fOdbcHostVarType,
fOdbcHostVarAddress.Ptr, fOdbcHostVarSize, fColValueSizePtr);
if (OdbcRetcode <> OdbcApi.SQL_SUCCESS)and(OdbcRetcode <> OdbcApi.SQL_SUCCESS_WITH_INFO) then
OdbcCheck(OdbcRetcode, 'SQLGetData("'+StrAnsiStringParam(aOdbcBindCol.fColName)+'")');
fIsFetched := True;
end;
{$IFDEF _TRACE_CALLS_}
except on e: Exception do begin LogExceptProc('TSqlCursorOdbc.FetchLateBoundData', e); raise; end; end;
finally LogExitProc('TSqlCursorOdbc.FetchLateBoundData'); end;
{$ENDIF _TRACE_CALLS_}
end;
Changed to 'And' on FetchLateBoundData and DoFetchLateBoundData.
That got rid of the error message, but the data was still truncated.
By the way, thanks for all your help on this.
Possible insufficient size of the buffer for line
(procedure TSqlCursorOdbc.BindResultSet)
Physical bufffer length is assigned into fOdbcHostVarSize
Try (procedure TSqlCursorOdbc.BindResultSet)
case fSqlType of
…
SQL_CHAR, SQL_VARCHAR, SQL_WCHAR, SQL_WVARCHAR, SQL_GUID:
begin
…
Inc(fOdbcHostVarSize, 4); // ******* increase of buffer
end;
SQL_BINARY, SQL_VARBINARY:
…
SQL_LONGVARCHAR, SQL_WLONGVARCHAR:
begin
…
Inc(fOdbcHostVarSize, 4); // ******* increase of buffer
end;
SQL_LONGVARBINARY:
procedure TSqlCursorOdbc.BindResultSet;
…
var
bUnicodeString, bTypeChanged: Boolean;
…
SQL_CHAR, SQL_VARCHAR, SQL_WCHAR, SQL_WVARCHAR, SQL_GUID:
begin
fDbxType := fldZSTRING;
bUnicodeString := ((fSqlType = SQL_WCHAR) or (fSqlType = SQL_WVARCHAR)) and
(fOwnerDbxConnection.fConnectionOptions = osOn);
if bUnicodeString then
begin
if fOwnerDbxDriver.fClientVersion >= 30 then
begin
fDbxType := fldWIDESTRING;
end
else
begin
fDbxSubType := fldstWIDEMEMO;
end;
fOdbcHostVarType := SQL_C_WCHAR;
if fSqlType = SQL_WCHAR then
fDbxSubType := fldstFIXED;
end
else if (fSqlType = SQL_CHAR) or (fSqlType = SQL_WCHAR) then
begin // Fixed length field
fOdbcHostVarType := SQL_C_CHAR;
fDbxSubType := fldstFIXED;
end
else
begin
fOdbcHostVarType := SQL_C_CHAR;
end;
if fColSize <= 0 then
begin
fColSize := 1;
// SQL SERVER 2005:
{
declare @content varchar(max)
select @content = 'hello world'
select content1 = @content
}
if (fOwnerDbxConnection.fOdbcDriverType in ) then
begin
fColSize := 8000;
end;
end;
{+2.03 INFORMIX LVARCHAR}
{ Vadim V.Lopushansky:
Fixed when error for mapping INFORMIX LVARCHAR type over native ODBC.
Example query: select amparam from sysindices
}
if ( (fColSize > 255) and
(fOwnerDbxConnection.fConnectionOptions = osOn) )
then
begin
fDbxType := fldBLOB;
if bUnicodeString then
fDbxSubType := fldstWIDEMEMO
else
fDbxSubType := fldstMEMO;
end;
if {((fOwnerCommand.fCommandBlobSizeLimitK>0) and (fColSize > fOwnerCommand.fCommandBlobSizeLimitK*1024)) or} (fColSize > COLUMN_BIND_SIZE_LIMIT) then
begin // large size:
if (fOwnerCommand.fCommandBlobSizeLimitK <= 0) then
begin
fOdbcLateBound := True;
end
else
begin
{ Vadim>???Vad>All if fColSize > 2 Gb ???
Informix native odbc supported fOdbcLateBound, but if not ?
DataDirect ODBC for this informix type return length 2048.
}
// trim column:
fColSize := 2048;
end;
end;
if fOdbcLateBound then
fIsBuffer := True;
bTypeChanged := False;
if (Self.fOwnerDbxConnection.fDbmsType = eDbmsTypeFlashFiler) and (fColSize = 4) then
begin
IntAttribute := OdbcApi.SQL_FALSE;
OdbcRetcode := SQLColAttributeInt(fHStmt, ColNo, SQL_DESC_AUTO_UNIQUE_VALUE,
nil, 0, nil, IntAttribute);
if {AutoIncr=} (OdbcRetcode = OdbcApi.SQL_SUCCESS) and (IntAttribute = SQL_TRUE) then
begin
bTypeChanged := True;
fDbxType := fldINT32;
fOdbcHostVarType := SQL_C_LONG;
fOdbcHostVarSize := SizeOf(SqlInteger);
fDbxSubType := fldstAUTOINC;
fIsBuffer := False;
end
else
if (OdbcRetcode = OdbcApi.SQL_SUCCESS) then
fOwnerDbxDriver.RetrieveOdbcErrorInfo(OdbcRetcode, SQL_HANDLE_STMT, fHStmt,
fOwnerCommand.fDbxConStmtInfo.fDbxConStmt, fOwnerDbxConnection, fOwnerCommand, nil, 1);
end;
if not bTypeChanged then
begin
fOdbcHostVarSize := fColSize + 1 + 1; // Add 1 for null terminator and 1 for spare :)
if fOdbcHostVarType = SQL_C_WCHAR then
fOdbcHostVarSize := fOdbcHostVarSize * SizeOf(WideChar);
(*
Field Size is very big (Firebird, IBPhoenix OpenSource ODBC Driver):
CREATE TABLE … (
…
LANGUAGE_REQ VARCHAR(15) CHARACTER SET NONE
);
*)
if fColSize > dsMaxStringSize then
begin // analog of SQL_LONGVARCHAR:
if bUnicodeString then
begin
fDbxType := fldWIDESTRING;
fDbxSubType := fldstMEMO;
fOdbcHostVarType := SQL_C_WCHAR;
end
else
begin
fDbxType := fldBLOB;
fDbxSubType := fldstMEMO;
fOdbcHostVarType := SQL_C_CHAR;
end;
if fOwnerCommand.fCommandBlobSizeLimitK > 0 then
// If BLOBSIZELIMIT specified, we early bind, just like normal column
// Otherwise get size and column data AFTER every row fetch, using SqlGetData
begin
fOdbcHostVarSize := fOwnerCommand.fCommandBlobSizeLimitK * 1024;
end
else
if (fOwnerDbxConnection.fOdbcDriverType <> eOdbcDriverTypeSQLite) then
begin
fOdbcLateBound := True;
end
else // SQL LITE:
begin
fOdbcHostVarSize := fColSize + 1;
if fOdbcHostVarType = SQL_C_WCHAR then
fOdbcHostVarSize := fOdbcHostVarSize * SizeOf(WideChar);
end;
if fOdbcLateBound then
fIsBuffer := True;
end;
end;
end;
…
SQL_LONGVARCHAR, SQL_WLONGVARCHAR:
begin
bUnicodeString := (fSqlType = SQL_WLONGVARCHAR) and
(fOwnerDbxConnection.fConnectionOptions = osOn);
if bUnicodeString then
begin
fDbxType := fldBLOB;
fDbxSubType := fldstWIDEMEMO;
fOdbcHostVarType := SQL_C_WCHAR;
end
else
begin
fDbxType := fldBLOB;
fDbxSubType := fldstMEMO;
fOdbcHostVarType := SQL_C_CHAR;
end;
if fOwnerCommand.fCommandBlobSizeLimitK > 0 then
// If BLOBSIZELIMIT specified, we early bind, just like normal column
// Otherwise get size and column data AFTER every row fetch, using SqlGetData
begin
fOdbcHostVarSize := fOwnerCommand.fCommandBlobSizeLimitK * 1024;
end
else
if (fOwnerDbxConnection.fOdbcDriverType <> eOdbcDriverTypeSQLite) then
fOdbcLateBound := True
else // SQL LITE:
fOdbcHostVarSize := fColSize;
//
fOdbcHostVarSize := fOdbcHostVarSize + 1 + 1; // Add 1 for null terminator and 1 for spare :)
if fOdbcHostVarType = SQL_C_WCHAR then
fOdbcHostVarSize := fOdbcHostVarSize * SizeOf(WideChar);
//
if fOdbcLateBound then
fIsBuffer := True;
if fColSize=0 then
fColSize := -1;
end;
…
OK. That last post confused me… I searched through the Code and added the Inc(fOdbcHostVarSize, 4); // ******* increase of buffer
Lines, but they don't look to be in the second code snippet you posted.
At any rate, I re-compiled with the two Inc(fOdbcHostVarSize, 4); // ******* increase of buffer statements and initial tests look good.
I'll need to test a few more things, but so far I think that has fixed it.
Question: Should I change 'AND' back to 'OR' on the FetchLateBoundData & DoFetchLateBoundData procedures?
Thanks,
try load "dbxoodbc_3_2010_1105alpha1.7z"
how are you with our problem?
Sorry - Went to lunch :)
Getting ready to install/try alpha now.
Thanks
The Data Truncate issue looks to be resolved.
I have another issue 'Record Not Found or Changed by another user' when I try to write the data.
I am pretty sure that it's unrelated.
Have done several data imports with the alpha file and it seems to be working fine.
However, when doing secondary updates, I can only update if 'using 'upWhereChanged' not 'upWhereAll' like I normally do?
If this occurs for event, when old/new importance NULL/"", then decision possible. Some servers do not support transparent NULL and "".
Need testing with next connection options:
coNullStrParam=1
coEmptyStrParam=1
For example: SQLITE ODBC does not support NULL for char types. For SQLITE happened to completely to exclude NULL:
"DbxOpenOdbc.pas"
function TSqlConnectionOdbc.RetrieveDriverName
…
eOdbcDriverTypeSQLite:
begin
…
fConnectionOptionsDrv := osOn; // ******** !!!
end;
…
function TSqlCommandOdbc.setParameter
…
if (bIsNull = 1) and (fOwnerDbxConnection.fDbmsType = eDbmsTypeSQLite) then // ******* !!!
begin { fOdbcDriverType = eOdbcDriverTypeSQLite }
fBindData := @fValue;
PWideChar(fBindData)^ := cNullWideChar;
end;
end;
fldINT32, fldUINT32:
…
function TSqlCursorOdbc.getString
…
if IsBlank then
begin
if bNotUnicodeString then
pDestA^ := cNullAnsiChar
else
pDestW^ := cNullWideChar;
if fOwnerDbxConnection.fDbmsType = eDbmsTypeSQLite then // ******* !!!
IsBlank := False;
end
else
…
"DbxOpenOdbc3.pas"
function TSqlCursorOdbc3.getWideString
…
if IsBlank then
begin
Value^ := cNullWideChar;
if TSqlConnectionOdbc3(fOwnerDbxConnection).fDbmsType = eDbmsTypeSQLite then // ******** !!!
IsBlank := False;
end
else
…
coNullStrParam=1
coEmptyStrParam=1
not together, but apart:
OK. Took me a while to sort out the iterations of this next problem.
I have tried both of the Params listed above (not together, but each separately) as well, as without.
I am able to 'Write' to any Table one time. The second time I try to write to the table, I get 'Record not found ….'
I have an older version of the App (compiled with an older version of the driver) that I can use to 'Reset' the record. With the older version of the driver, I can write to the record as many times as I like. As soon as I run the alpha driver, I can write to the record only once, regardless of the Param that I use.
This is because after the first update the new values are not like in the database. See the event log (or sql monitor) of query to second update. See the updated values in log and in database. Try to "SELECT * from … where" a sample with such values as in the update query.