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 
 
Got the persistent script working but now have a mysql error

 
Post new topic   Reply to topic    nwnx.org Forum Index -> Database related
View previous topic :: View next topic  
Author Message
Frang



Joined: 22 May 2005
Posts: 32

PostPosted: Thu Nov 02, 2006 0:17    Post subject: Got the persistent script working but now have a mysql error Reply with quote

Here is the code. But for some reason it does the fetch to see if player has info but when it finds the info it skips the update process and tried to just dump the info to the database.

Code:

   // Looks for Player name in the data base
  string sSQL = "SELECT Player FROM   players   WHERE Player='" + sPlayer +
        "' AND Name='" + sName + "'";
        SQLExecDirect(sSQL);

   // if (SQLFirstRow() == SQL_SUCCESS)
       if (SQLFetch() == SQL_SUCCESS)
    {

     // If player name is found we update the info
      sSQL = "UPDATE players " +
        "SET Location='" + sLoc +
        "', Spells='" + sSpells +
        "', Feats='" + sFeats +
        "', HitPoints='" + IntToString(nHP) +
        "', Level='" + IntToString(nLevel) +
        "' WHERE Player='" + sPlayer +
        "' AND Name='" + sName + "'";
        SQLExecDirect(sSQL);
    }
    else
    {
        // If player is not found we dump new info to the database.
        sSQL = "INSERT INTO   players  (Player,Name,Location,Spells,Feats,HitPoints,Level) VALUES" +
            "('" + sPlayer + "','" + sName + "','" + sLoc + "','" + sSpells + "','" + sFeats + "','" + IntToString(nHP) + "','" + IntToString(nLevel) + "')";
        SQLExecDirect(sSQL);
     }
   }


and here is the nwnx_odbc log
Code:

o Got request: SELECT Player FROM   players   WHERE Player='Frang' AND Name='Frang The Vampire'
o Got request: INSERT INTO   players  (Player,Name,Location,Spells,Feats,HitPoints,Level) VALUES('Frang','Frang The Vampire','#AREA#GatewaytoRhun#POSITION_X#      39.172737122#POSITION_Y#      27.309722900#POSITION_Z#       1.000000000#ORIENTATION#      42.137847900#END#',' ',' 7:1 10:1 11:1 14:1 18:1 36:1 40:1 51:1 171:1 228:1 258:1 399:1 401:1 616:1 618:1 944:1 945:1 946:1 976:1 1001:1 ','141','23')
! SQL Error: [MySQL][ODBC 3.51 Driver][mysqld-4.1.21-community-nt]Duplicate entry 'Frang-Frang The Vampire' for key 1


anyone have any ideas?
Back to top
View user's profile Send private message
Grumalg



Joined: 04 Nov 2005
Posts: 70

PostPosted: Thu Nov 02, 2006 3:09    Post subject: Reply with quote

Your nwnx_odbc log text is showing you that the record you are attempting to insert already exists, thus the duplicate entry error. This means you nwscript code isn't detecting that the record already exists and switching between insert and update properly.

Your 'if' test isn't checking the returned field to see if 'Player' actually matches sPlayer. Remember that SQL_SUCCESS only indicates you got a result from the DB and no results from the query is a valid value.

Another approach would be to use 'SELECT COUNT(*)' with your WHERE clause which will return the number of records matching. Since NWNX only handles string data you'll have to CAST the COUNT(*) value as CHAR so it can pass through NWNX. If you don't already have it you should DL the MySQL documentation pdf which whill show you the CAST syntax.

However in either case you need to examine the contents of the first returned field in your 'if' decision to decide between INSERT and UPDATE.
Back to top
View user's profile Send private message
Frang



Joined: 22 May 2005
Posts: 32

PostPosted: Thu Nov 02, 2006 4:52    Post subject: Reply with quote

could I just change my check to something like this?
[code]

if(SQLFetch() == sPlayer || sName) // if you retrieved an entry
{
{/code}
Back to top
View user's profile Send private message
Grumalg



Joined: 04 Nov 2005
Posts: 70

PostPosted: Thu Nov 02, 2006 5:41    Post subject: Reply with quote

I think you don't understand SQLFetch() fully. SQLFetch() takes the DB returned result and places it in a buffer. When SQLFetch() returns SQL_SUCCESS it means there was no error, and a return of SQL_ERROR means there was an error executing the SQL statement. Neither of these have anything to do with what the returned data contains.

A SQL statement that does not return any data (i.e. there was no matching record), does not result in a SQL_ERROR return from SQLFetch(). You have to look at the data itself in the buffer via SQLGetData(n), where 'n' is the 'one' based field number being returned, to know what was actually returned. In the case where your SQL doesn't result in any returned data SQLGetData(1) will contain a null string. However a null string return isn't *always* conclusive because it's possible for a DB field to actually contain a null string as legitimate data.

In cases where you *know* there will never be a field containing a null string in your table, testing SQLGetData(1) for null string is enough to tell there was no matching record. If your data allows a null string in a field then fetching SELECT CAST(COUNT(*) AS CHAR) becomes useful as SQLGetData(1) will then contain a string of '0' for no matching records or a value of say '1' if there was one matching record (or some other number as string if more than one record matched).
Back to top
View user's profile Send private message
odenien



Joined: 26 Sep 2005
Posts: 37

PostPosted: Thu Nov 02, 2006 14:27    Post subject: Reply with quote

My code snips I showed you had SQLGetData being called only if SQLFetch was successful. That is why you have to initalize the playername and tag and check for empty or PlayID for zero. If the fetch fails or if the get data fails then, it assumes the player you are trying to find is not in the player table.
Back to top
View user's profile Send private message MSN Messenger
Grumalg



Joined: 04 Nov 2005
Posts: 70

PostPosted: Fri Nov 03, 2006 3:03    Post subject: Reply with quote

A SQL statement that doesn't match any records is not an error.

You have to examine the fetched data with SQLGetData to determine if any data was actually returned. I see no SQLGetData calls at all in the above code. Your 'if' that switches between INSERT and UPDATE should be based on examining the contents of the 'Player' field.

Most of the time I ignore the return value of SQLFetch. Once you have known working SQL statements an error from SQLFetch only tells you the DB engine has failed. Since there isn't really anything you can do about handleing that in nw script other than writeing it to the log, as you can't code to fix the problem. Thus I *usually* ignore return values from SQLFetch except for special cases.

Your 'if' should look more like this:

SQLExecDirect(sSQL);
SQLFetch();
sFound = SQLGetData(1);
if (sFound == sPlayer) // sPlayer is found to exist
{
--update--
}
else // sPlayer didn't exist
{
---insert---
}

This works because if the record doesn't exist SQLGetData(1) will be a null string.
Back to top
View user's profile Send private message
odenien



Joined: 26 Sep 2005
Posts: 37

PostPosted: Fri Nov 03, 2006 14:45    Post subject: Reply with quote

I don't think NWNX2 handles it the same as normal query engines. I always remembered the data coming back as an empty string.
Back to top
View user's profile Send private message MSN Messenger
tayls25



Joined: 16 Dec 2006
Posts: 5

PostPosted: Fri Feb 16, 2007 3:12    Post subject: Reply with quote

I'm experiencing the same problem in nwnx4 with a SetPersistentCampaignString call..... based on this argument, are you saying the code in the sql_include is wrong?

Are you saying that the following is wrong? Because I've pulled this right out of the sql_include:

void SetPersistentString(object oObject, string sVarName, string sValue, int iExpiration =
0, string sTable = "pwdata")
{
string sPlayer;
string sTag;

if (GetIsPC(oObject))
{
sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oObject));
sTag = SQLEncodeSpecialChars(GetName(oObject));
}
else
{
sPlayer = "~";
sTag = GetTag(oObject);
}

sVarName = SQLEncodeSpecialChars(sVarName);
sValue = SQLEncodeSpecialChars(sValue);

string sSQL = "SELECT player FROM " + sTable + " WHERE player='" + sPlayer +
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);

if (SQLFetch() == SQL_SUCCESS)
{
// row exists

sSQL = "UPDATE " + sTable + " SET val='" + sValue +
"',expire=" + IntToString(iExpiration) + " WHERE player='" + sPlayer +
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
SQLExecDirect(sSQL);
}
else
{
// row doesn't exist
sSQL = "INSERT INTO " + sTable + " (player,tag,name,val,expire) VALUES" +
"('" + sPlayer + "','" + sTag + "','" + sVarName + "','" +
sValue + "'," + IntToString(iExpiration) + ")";
SQLExecDirect(sSQL);
}
}



-------------------------------

should it be something like:

if (!(SQLGetData(1) == ""))
Back to top
View user's profile Send private message
tayls25



Joined: 16 Dec 2006
Posts: 5

PostPosted: Fri Feb 16, 2007 18:44    Post subject: Reply with quote

Well that didn't work either. I ended up getting it to work by rearranging the insert and update order, and removing the conditional.

so now the script inserts, if it gets a key violation, it just fails on that statement, then it updates. If the insert happened, it just updates the record anyhow.

It's not ideal, but I suppose it works.

If anyone has a better suggestion to make this work, I'd appreciate hearing it.
Back to top
View user's profile Send private message
Grumalg



Joined: 04 Nov 2005
Posts: 70

PostPosted: Sat Feb 17, 2007 9:06    Post subject: Reply with quote

tayls25 wrote:
so now the script inserts, if it gets a key violation, it just fails on that statement, then it updates. If the insert happened, it just updates the record anyhow.


The disadvantage of this approach is that you *always* have to do two DB calls which is slower.

Part of the problem with SQL_SUCCESS and SQL_ERROR is that the names imply things which aren't necessarily true. The comment text for what they mean has changed over time. I think the names stay the same for older code compatiability.

Now SQL_SUCCESS is real solid, you asked for data, you got it, your golden.

But SQL_ERROR is somewhat ambiguous. Basically it says the fetch didn't get any data back. Unfortunately, this could occur for a number of reasons. Maybe there was no data from your SQL query, maybe you SQL command has an error in it, maybe NWNX lost connection to the DB engine, maybe the table is corrupted, maybe the DB engine has gone down. With a SQL_ERROR result you can't distinguish which of these may have occured.

Now don't get me wrong, relying on SQL_ERROR can be real reliable under the right circumstances as most of the above rarely happens. There's a lot of code out there that uses it and works well.

There is another approach which does remove the ambiguouity with SQL_ERROR. That is to use 'CAST(COUNT(*) AS CHAR)' as the first field selected in your SELECT statement. When you do this you always get data back (and a SQL_SUCCESS result) even if the SELECTED data doesn't otherwise exist, because the COUNT return is always present.

Selecting COUNT(*) returns the number of records matching your SELECT. doing CAST(COUNT(*) AS CHAR) is to convert that number into a string so nwnx can pass it back.

When this approach is used and the record you are testing for doesn't exist, you do still get data back as the COUNT will be zero and show up as a '0' when you do SQLGetDATA(1). That means a SQL_ERROR result from SQLFetch is a real error if it occurs. The count approach also offers the benefit of checking if there are more than one matching records.

--- Grumalg ---
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> Database related 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