logo logo

 Back to main page

The NWNX Community Forum

 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
 
SQLFetch - Possible bug

 
Post new topic   Reply to topic    nwnx.org Forum Index -> Development
View previous topic :: View next topic  
Author Message
OVLD_NZ



Joined: 14 Nov 2006
Posts: 18

PostPosted: Fri Dec 08, 2006 5:04    Post subject: SQLFetch - Possible bug Reply with quote

SQLFetch doesn't appear to be stepping through the dataset rows.

Code:


SQLExecDirect("SELECT col1,col2,col3 FROM mytable WHERE id=1");
while(SQLFetch()==SQL_SUCCESS)
{
     int icol1=StringToInt(SQLGetData(1));
     int icol2=StringToInt(SQLGetData(2));
     string scol3=SQLGetData(3);
}


The query returns 2 rows affected, but the second time SQLFetch is called it returns SQL_ERROR.

From my understanding this should be working? Shouldn't it?
_________________
The World of Judur - The Shadow has Awoken
Back to top
View user's profile Send private message
caloup



Joined: 29 Sep 2006
Posts: 59
Location: albi (france)

PostPosted: Fri Dec 08, 2006 22:43    Post subject: Reply with quote

aren't you supposed to use :

Quote:

// Position cursor on next row of the resultset
// Call this before using SQLGetData().
// - Leave the parameter empty to advance to the next row.
// - Pass "NEXT" as parameter to fetch the first row of the
// next resultset (for statements that return multiple resultsets)
// returns: SQL_SUCCESS if there is a row
// SQL_ERROR if there are no more rows
int SQLFetch(string mode = " ");


SQLFetch("NEXT") in your case ?

(i ask but i don't know, i haven't understand yet how does it work)
Back to top
View user's profile Send private message
Papillon
x-man


Joined: 28 Dec 2004
Posts: 1060
Location: Germany

PostPosted: Fri Dec 08, 2006 22:44    Post subject: Reply with quote

It should, and it should return all rows that are matched by the query.

First of all, which DB plugin are you using ? Can you please give some more detailed examples (including data in the table, log file output, and so on) ?
_________________
Papillon
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
caloup



Joined: 29 Sep 2006
Posts: 59
Location: albi (france)

PostPosted: Sat Dec 09, 2006 0:05    Post subject: Reply with quote

and have you rename the database dll and ini that you don't need ?

for example, if you are using xp_mysql.dll : rename xp_sqlite.dll to off_xp_sqlite.dll and do the same for xp_sqlite.ini...

(in case of...)
Back to top
View user's profile Send private message
OVLD_NZ



Joined: 14 Nov 2006
Posts: 18

PostPosted: Sat Dec 09, 2006 5:39    Post subject: Reply with quote

The plugin I'm using is MySQL and yes sqlite is not being loaded. There's nothing in the log files, so not much point posting them. But here's the other information.

SQL to create table

Code:

CREATE TABLE  `judur`.`gd_quest_reward` (
  `rewardid` int(10) unsigned NOT NULL auto_increment,
  `taskid` int(10) unsigned NOT NULL default '0',
  `rewardtype` int(10) unsigned NOT NULL default '0',
  `reward` text NOT NULL,
  `questid` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`rewardid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


NWN Script

Code:

SQLExecDirect("SELECT rewardtype,reward FROM gd_quest_reward WHERE taskid=1");
while(SQLFetch()==SQL_SUCCESS)
{
     int rewardtype=StringToInt(SQLGetData(1));
     string reward =SQLGetData(2);
}


The data in gd_quest_reward is:

Code:

rewardid,taskid,rewardtype,reward,questid
1, 1, 1, '200', 1
2, 2, 2, 'ju_i_rulirs_pick', 1
3, 1, 1, '200', 1

_________________
The World of Judur - The Shadow has Awoken
Back to top
View user's profile Send private message
Grumalg



Joined: 04 Nov 2005
Posts: 70

PostPosted: Sat Dec 09, 2006 6:58    Post subject: Reply with quote

While I haven't tested your specific code I can make some observations just from looking at it.

Your table definition uses a lot of numeric fields. Since NWNX is limited to passing string data by the nature of the hooking mechanism this may be your problem. It's true that MySQL will do a certain amount of implicit type casting under the right conditions, just don't think it will do it correctly as you are useing it. I normally use VARCHAR(n) or CHAR(n) fields to store n digit numbers and do IntToString on writes and StringToInt on reads for numeric data.

Your 'reward' field is TEXT, do you really want to reserve 64kb per field? This too would benefit for useing VARCHAR or CHAR datatype.

Your primary key index is pretty useless, and you have no index at all on the 'taskid' field. You'd get faster performance with an index on 'taskid' since you use it in WHERE clause matching. Note that you cannot make 'taskid' a primary key as it contains non-unique values, but you can make it an ordinary index. There is no requirement that a table must have a primary key at all.

--- Grumalg ---
Back to top
View user's profile Send private message
OVLD_NZ



Joined: 14 Nov 2006
Posts: 18

PostPosted: Sat Dec 09, 2006 8:26    Post subject: Reply with quote

Well, I know I can optimize the table better. But I don't see that as the problem here.

The code will read the first row fine, but fails to goto the next row when I call SQL_Fetch(). Which returns SQL_ERROR.

I can try converting everything to VARCHAR and see what happens, but I don't think it'll solve the problem.
_________________
The World of Judur - The Shadow has Awoken
Back to top
View user's profile Send private message
Grumalg



Joined: 04 Nov 2005
Posts: 70

PostPosted: Sat Dec 09, 2006 10:15    Post subject: Reply with quote

My TEXT field and indexing comments didn't apply to your problem. They were just meant to be helpful in general.

I'm not saying you haven't encountered a bug. But attempting to SELECT a numeric field through nwnx could be causeing your problems. Nwnx has never supported returning numbers as binary. By definition everything must be passed back and forth in string form.

Getting a bit more detailed, when you SELECT a numeric field in a table MySQL returns the binary form of the number. When you call SQLGetData(), nwnx grabs the returned bytes and stuffs them into a local string on the module. SQLGetData() then returns the contents of that local string. Your code then takes those bytes and passes them to StringToInt. Since these bytes are binary instead of characters, it's entirely possible that either StringToInt or GetLocalString is chokeing on them. It may be that only certain byte values cause a problem. In that case, it would appear to work on some values and not on others. It's also possible that nwnx itself has some trouble with the multiple binary returns though it's intended to be transparent. However, it's not meant to be used that way, so you can't really say thats a bug.

If you really need the data in the table to be an actual number instead of a number stored as a string, you'd need to CAST such fields into CHAR within the SELECT statement to get them through nwnx. Since that approach entails additional overhead in conversions general practice is to store numbers as strings except for special cases.

It's a bit different when you are writing to the database. You still do need to pass the number down in string form, but MySQL recognizes that you are trying to put a string into a number field and does the conversion automatically if the string can be converted. This is an example of 'implicit' type casting

If you try passing everything through as string and still it doesn't work, then you may have found a bug.

-- Grumalg ---
Back to top
View user's profile Send private message
caloup



Joined: 29 Sep 2006
Posts: 59
Location: albi (france)

PostPosted: Sat Dec 09, 2006 10:48    Post subject: Reply with quote

I think you could try to order your table by taskid before reading the data (but it's just an idea to try if that do anything...)
Back to top
View user's profile Send private message
OVLD_NZ



Joined: 14 Nov 2006
Posts: 18

PostPosted: Sat Dec 09, 2006 12:10    Post subject: Reply with quote

Problem solved Very Happy

Within the while loop I was performing another database query and of course it resets the dataset. After removing the inner query it works fine. Even with INTEGER fields in the database.

I just needed you guys to make me look harder.
_________________
The World of Judur - The Shadow has Awoken
Back to top
View user's profile Send private message
Papillon
x-man


Joined: 28 Dec 2004
Posts: 1060
Location: Germany

PostPosted: Sat Dec 09, 2006 12:18    Post subject: Reply with quote

I tried your code and table definition and it works for me.

Code:

   WriteTimestampedLogEntry("Quest rewards with taskid=1:");
   SQLExecDirect("SELECT rewardtype,reward FROM gd_quest_reward WHERE taskid=1");
   while(SQLFetch()==SQL_SUCCESS)
   {
      WriteTimestampedLogEntry("Type=" + SQLGetData(1) + ", reward=" + SQLGetData(2) + ".");
   }    


Result:

Code:

[Sat Dec 09 11:09:19] Quest rewards with taskid=1:
[Sat Dec 09 11:09:19] Type= 1, reward=200.
[Sat Dec 09 11:09:19] Type= 1, reward=200.


Please try this debug version of xp_mysql and post the relevant portion of the log file. Note that you have to delete the normal DLL and rename the ini file to xp_mysqld.ini for this to work. You might want to check nwnx.txt and make sure that it is really the debug version that is beeing loaded.

The log should look like this:

Code:
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, EXEC, SELECT rewardtype,reward FROM gd_quest_reward WHERE taskid=1)
Trace: (TRACE_VERBOSE) * function=EXEC
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, FETCH,  )
Trace: (TRACE_VERBOSE) * function=FETCH
Trace: (TRACE_VERBOSE) * Fetch returns a row.
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, GETDATA!0, ...................................)
Trace: (TRACE_VERBOSE) * function=GETDATA
Trace: (TRACE_VERBOSE) * parameter1=0
Trace: (TRACE_VERBOSE) * GetData: Get column 0, buffer size 128 bytes
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, GETDATA!1, ...................................)
Trace: (TRACE_VERBOSE) * function=GETDATA
Trace: (TRACE_VERBOSE) * parameter1=1
Trace: (TRACE_VERBOSE) * GetData: Get column 1, buffer size 128 bytes
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, FETCH,  )
Trace: (TRACE_VERBOSE) * function=FETCH
Trace: (TRACE_VERBOSE) * Fetch returns a row.
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, GETDATA!0, ...................................)
Trace: (TRACE_VERBOSE) * function=GETDATA
Trace: (TRACE_VERBOSE) * parameter1=0
Trace: (TRACE_VERBOSE) * GetData: Get column 0, buffer size 128 bytes
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, GETDATA!1, ...................................)
Trace: (TRACE_VERBOSE) * function=GETDATA
Trace: (TRACE_VERBOSE) * parameter1=1
Trace: (TRACE_VERBOSE) * GetData: Get column 1, buffer size 128 bytes
Trace: (TRACE_VERBOSE) * Plugin DoRequest(0x3ef0e20, FETCH,  )
Trace: (TRACE_VERBOSE) * function=FETCH
Trace: (TRACE_VERBOSE) * Fetch returns no row.

_________________
Papillon
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Grinning Fool



Joined: 12 Feb 2005
Posts: 264

PostPosted: Sat Dec 09, 2006 20:05    Post subject: Reply with quote

Quote:
Getting a bit more detailed, when you SELECT a numeric field in a table MySQL returns the binary form of the number. When you call SQLGetData(), nwnx grabs the returned bytes and stuffs them into a local string on the module.

I'm not sure this is right -- all of the native mysql APIs handle returned data in string format. A row is returned as MYSQL_ROW, which is char ** -- an array holding individual column values. The conversion here is done before the application sees the data.

Too, when doing joins between multiple tables, it is generally more efficient join on integer values than on varchars, especially if the varchars are more than a few bytes long.
_________________
Khalidine, a NWN2 persistent world

Looking for volunteers.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> Development All times are GMT + 2 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group