Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

db_odbc raises errors when fetching large Oracle CLOBs #8

Open
alistairkeys opened this issue Nov 11, 2020 · 0 comments
Open

db_odbc raises errors when fetching large Oracle CLOBs #8

alistairkeys opened this issue Nov 11, 2020 · 0 comments

Comments

@alistairkeys
Copy link

The db_odbc package produces errors when fetching Oracle CLOB fields larger than 4K. Note that I've not confirmed the behaviour on other database types with equivalent large character types (e.g. TEXT) so they may also have the same issue.

Note that I'm not experienced with ODBC so take my findings below with a pinch of salt.

Example

Given a table with a CLOB field:

create table some_table ( some_big_clob CLOB );
insert into some_table values ( rpad('*', 4000, '*') ); 
update some_table set some_big_clob = some_big_clob || some_big_clob; 
commit;
import std/db_odbc

var db = open("foo", "bar", "baz", "qux")
try:
  echo db.getValue(sql"select some_big_clob from some_table")
finally:
  db.close()

Current Output

Error: 01004 [Oracle][ODBC]String data, right truncated.

Expected Output

The CLOB value in its entirety

Possible Solution

I think I've tracked it down to db_odbc not handling SQL_SUCCESS_WITH_INFO. This constant is specified in odbcsql but it's not referenced in db_odbc. The following seems to do the trick for the getValue call I'm using:

  1. change the sqlCheck procedure to check for [SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA] (i.e. add SQL_SUCCESS_WITH_INFO in there).
proc sqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} =
  ## Wrapper that raises [EDb] if ``resVal`` is neither SQL_SUCCESS or SQL_NO_DATA
  if resVal notIn [SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA]: dbError(db)
  1. amend the getRow proc to fetch again while it receives SQL_SUCCESS_WITH_INFO
      var fetchRes: TSqlSmallInt = SQL_SUCCESS_WITH_INFO
      while fetchRes == SQL_SUCCESS_WITH_INFO:
        buf[0] = '\0'
        fetchRes = SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
                               cast[cstring](buf.addr), 4095, sz.addr)
        db.sqlCheck(fetchRes)
        rowRes[colId-1] &= $(addr buf)

I can't guarantee the code above is reliable as I don't know if SQL_SUCCESS_WITH_INFO is exclusively used to indicate "you need to fetch again". I found ODBC documentation suggesting there are functions (SQLGetDiagRec or SQLGetDiagField) that can be called to get further information so the changes may be more involved than my example code suggests.

The sqlCheck proc is used in quite a few places and SQL_SUCCESS_WITH_INFO probably isn't relevant to most invocations.

There are several places in db_odbc that fetch rows. My example change above is simply the procedure I happened to be using when the error occurred and you may have to change other places in a similar fashion to fix them.

Additional Information

c:\>nim -v
Nim Compiler Version 1.4.0 [Windows: amd64]
Compiled at 2020-10-18
Copyright (c) 2006-2020 by Andreas Rumpf

active boot switches: -d:release

I'm using Windows 10 / Oracle 11g / Oracle Instant Client 19.

@ringabout ringabout transferred this issue from nim-lang/Nim Dec 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant