[Gambas-devel] Change to gb.db.odbc to use ODBC Connection Strings.

ML d4t4full at ...176...
Wed Sep 16 16:36:19 CEST 2015


*On 2015-09-15 21:24, Benoît Minisini wrote:*
> *Le 14/09/2015 17:41, ML a écrit : *
>> Benoît,
>> Continuing here as you requested.
>> I found the problem in th driver that causes it to return 0 instead 
>> of -1 in the RowCount. The offending line and my patch:
>>    //20150914 - zxMarce: Do NOT mark the STMT as Scrollable; it makes 
>> SQLRowCount always return 0 rows instead of -1.
>>    //retcode = SQLSetStmtAttr(odbcres->odbcStatHandle, 
>> SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0);
>>    retcode = SQLSetStmtAttr(odbcres->odbcStatHandle, 
>> SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_NONSCROLLABLE, 0);
>> It just needed a constant change from SQL_SCROLLABLE to 
>> SQL_NONSCROLLABLE.
>> Looks like the intention was to make a proper driver, with forward 
>> and back scroll, but for some reason it was not completed.
>> Now the problem propagates to Result.MoveNext and Result.Available. 
>> They loop forever, even when there's no more data to fetch.
>> I made a further change in query_fill (removed a GB.Error that raised 
>> 'ODBC_NO_MORE_DATA' and added a return TRUE), but that did not get 
>> .MoveNext or .Available fixed:
>>    if((retcode2 == SQL_NO_DATA_FOUND) || (retcode2==SQL_NO_DATA))
>>    {
>>      //GB.Error("ODBC_END_OF_DATA!"); //20150914 - zxMarce: Removed 
>> so .MoveNext and .Available work?
>>      return TRUE; //20150914 - zxMarce: Try to make .MoveNext fail 
>> when no more data
>>    }
>> I think when we (you?) fix these problems, we will finally have a 
>> working Gambas ODBC subsystem.
>> Thanks,
> gb.db.odbc tells Gambas if he has a function to seek through a record 
> at line 564 (with the no_seek connection flag).
> But having that function does not mean that for a specific ODBC 
> driver, seeking is actually possible.
> In the query_fill() function at line 1152 you will see what the driver 
> does:
> - If the seek function exist, then:
>    - If the result has been marked scrollable successfully, then move 
> to the specified position.
>    - If the result is not scrollable, then move to the next record.
> - Otherwise, if the seek function does not exist, then move to the 
> next record. If moving to the next record was not requested ('next' 
> argument), then return TRUE (meaning an error).
> So, apparently, it's just Gambas that does not handle the no_seek 
> connection flag at the moment.
> And we should force the query count to be -1 when seeking is not 
> possible, whatever the reason (no seek function, or unscrollable query 
> result).

Benoît,

I've been investigating and came to the same conclusion you say 
regarding how the nested IFs work in query_fill.

Unfortunately, making no_seek TRUE is not the answer (tried it), but 
setting the ODBC Statement Handle's SQL_ATTR_CURSOR_SCROLLABLE attribute 
to SQL_NONSCROLLABLE instead of SQL_SCROLLABLE makes the trick of 
returning -1 as rowcount. I don't like forcing flag values because they 
may come in handy for other purposes later. On the other hand, the ODBC 
Statement Handle is created once per Connection.Exec call, so I'm more 
comfortable with changing that.

The problem that arises now is making Result.MoveNext (and preferably 
Result.Available also) work as it (they) should.

Changing the SCROLLABLE to NONSCROLLABLE achieves, then, 2 things:
1- The rowcount returned is -1.
2- The Result object has data and is not Null (with a rowcount=0 the 
Result object raises a "Result is not available" error).

Point 2 is what actually enables fetching data. The problem is now when 
all data has been retrieved: Result.Available is (still) TRUE and any 
subsequent Result.MoveNext raises an awful "ODBC_END_OF_DATA" error.
This not only forces the programmer to resort to convoluted techniques 
to fetch the data, it will also make any data-aware control fail if they 
rely on .MoveNext and .Available working.

What I did find, though, is that CResult.c is calling 
THIS->driver->Result.Fill and discarding the return value. Does not look 
wise, as the driver (at least gb.db.odbc) is actually returning whether 
the fill was or not successful.
I added another three changes to CResult.c that fixed the problem and 
made Result.Available work, but Result.MoveNext still raises the error, 
although trappable by Try res.MoveNext() in Gambas:

   //20150916 zxMarce: Make .Available depend on the result of driver's 
query_fill
   bool myUnavailable = FALSE;

   //20150916 zxMarce: Make .Available depend on the result of driver's 
query_fill
   /* THIS->driver->Result.Fill(&THIS->conn->db,
                                            THIS->handle,
                                            pos,
                                            THIS->buffer,
                                            (pos > 0) && (pos == 
(DELETE_MAP_virtual_to_real(THIS->dmap, THIS->pos) + 1))
                                           ); */
   myUnavailable = THIS->driver->Result.Fill(&THIS->conn->db,
THIS->handle,
                                                            pos,
THIS->buffer,
                                                            (pos > 0) && 
(pos == (DELETE_MAP_virtual_to_real(THIS->dmap, THIS->pos) + 1))
                                                           );

   //20150916 zxMarce: Make .Available depend on the result of driver's 
query_fill
   //THIS->available = TRUE;
   THIS->available = !myUnavailable;
   return FALSE;

I now can fetch data without resorting to unnecessary error handling, 
although fixing the error risen by Result.MoveNext and making it return 
TRUE instead is still pending.
I have to clean up the code a little bit and I think I can send it so 
you can check it.
I don't know if the "myUnavailable" patch above will break other 
drivers' functionality, and have no other databases than MSSQL to test.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gambas-basic.org/pipermail/devel/attachments/20150916/ef83fb4e/attachment.html>


More information about the Devel mailing list