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 
 
NWN server crashes after writing to the DB

 
Post new topic   Reply to topic    nwnx.org Forum Index -> General Discussion
View previous topic :: View next topic  
Author Message
PaithanQuindiniar



Joined: 12 Feb 2005
Posts: 4

PostPosted: Sat Feb 12, 2005 23:49    Post subject: NWN server crashes after writing to the DB Reply with quote

We're running NWNX2 with a MySQL database and implemented KPB's banking system (for NWNX of course).
I added a bit of code to the banking script, that writes a string in the DB containing all items stored in the vault of a player (just for info, to see what players have stored in their vaults --> big brother Twisted Evil ). The DB field is a TEXT type one. Now everything has been working okay, until suddenly the server starts crashing when using the vault. After some testing, I noticed, that it crashes when the string containing the items becomes rather long - 27 items (including name, stack size and tag) was my limit during testing. I runned the query in the DB control program with a text of over 1000 characters and that works. So it seems, that NWN (or NWNX?) has a problem with string of bigger size ...

Does anybody have any ideas?? I'd really appreciate some help here (it has cost me already about 5 hours, just to figure this bit out, so I thought, I'd ask the experts! Question )
Back to top
View user's profile Send private message MSN Messenger
Lanthar D'Alton



Joined: 10 Feb 2005
Posts: 100

PostPosted: Sun Feb 13, 2005 2:33    Post subject: Sure... Reply with quote

NWNX was coded for 8*128 characters... 1024. That means you'll need to limit yourself to that many letters. I'd suggest you make it run in a loop that sends the data in each time the string hits just less than 1024... Just always call a DELETE FROM big_brother_table WHERE player='name' or whatever beforehand, then put all your entries in as a set of strings instead of one big one.

-Lanthar
Back to top
View user's profile Send private message Visit poster's website AIM Address MSN Messenger
PaithanQuindiniar



Joined: 12 Feb 2005
Posts: 4

PostPosted: Sun Feb 13, 2005 3:11    Post subject: Reply with quote

Okay ... I'll give that a try ... Smile

One more question though. I tried the query

UPDATE big_brother_table SET val=CONCAT(val, 'new data') WHERE playerID=1 AND name='stored items'

for each item. I figured, that way, the DB access is always done with only one item information string (name, tag, stack size) and the "attaching" handled by the DB itself. Why isn't this approach successful? Question
Back to top
View user's profile Send private message MSN Messenger
Lanthar D'Alton



Joined: 10 Feb 2005
Posts: 100

PostPosted: Sun Feb 13, 2005 6:48    Post subject: Well.... Reply with quote

I'd say it failed before because your string was too long.

Now however, there will be multiple rows for a given player, and you will need to delete them all, then add new ones. Updates for that sort of thing would be pointless. You'd only repeatedly update the first row.

Egads. Actually, that's a TERRIBLE method (just reread it). You really should consider that you are doing one call per item for what may be hundreds of items... I'd advise that you do the string concatenation in the server and send a string in then instead... but then, I don't know how slow the server might be about concatenation. It depends on how the reallocation of the string is done when you add two together....

anyway, I'd try it the way I suggested. concatenate the string into something just less then 1024, then send to the db... concatenate the next string, send to db... but use inserts.
Code:

//given resrefs are limited to 16 letters
//and you are storing a comma delineated list (1 per)
//and the rest of your query is say... 100 letters...
//and we add 1 for a null terminator...
//max_items= (1+100 + X * (16+1) ) < 1024
//and that means X = 54

object oItem=GetFirstItemInInventory(chest_or_whatever);
while(oItem!=OBJECT_INVALID)
{
   string sItemInfoSet="";
   int i=0;
   for(i=0; i < X && oItem!=OBJECT_INVALID; i++)
   {
      string sItem=gettag(oItem);
      sItemInfoSet=sItemInfoSet+sItem;
      oItem = GetNextItemInInventory(chest_or_whatever);
   }
   string sQuery="INSERT INTO big_brother_info(playernumber, sItemset) VALUES( '"+sPlayerNum+"','"+sItem+"')";
   SQLExecDirect(sQuery);
}

something like that...
Back to top
View user's profile Send private message Visit poster's website AIM Address MSN Messenger
PaithanQuindiniar



Joined: 12 Feb 2005
Posts: 4

PostPosted: Sun Feb 13, 2005 12:15    Post subject: Reply with quote

Hm okay ... still, I'm wondering why the next thing doesn't work (sorry for being such a pain in the *** about this! Embarassed ). I'm gonna try with the exact example:

In the KPB system (as you might or might not know), all items you put in a chest are stored on an invisible creature when you walk away from the chest. This creature object then is stored in a NWN campaign database. So my problem is, that there's no way to see, what players got stored in the chest (i.e. the creature object in the NWN database).

To manage this, I wrote the following bit of code, which builds a string sItems. While the original banking code cycles through the player's items in his inventory, my code attaches a string with name, tag and stack size of the item, every time the original code finds an item and copies it to the invisible creature's.

The original code:

Code:

        if (GetIsObjectValid(oCreature))
        {
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oCreature);
            object oCopy;
            object oItem = GetFirstItemInInventory(oStorage);

            while(GetIsObjectValid(oItem))
            {
                oCopy = CopyItem(oItem, oCreature);
                oItem = GetNextItemInInventory(oStorage);
            }

            int iRet = StoreCampaignObject(PPIS_DB_NAME, sID, oCreature);


The original code with the big brother code included:

Code:

        if (GetIsObjectValid(oCreature))
        {
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oCreature);
            object oCopy;
            object oItem = GetFirstItemInInventory(oStorage);

            //added by Paithan
            DeletePersistentVariable(oPC, "Stored Item (nr) (tag)", "big_brother_info");
            string sItems = "(player has no items stored)";           
            SetPersistentString(oPC, "Stored Item (nr) (tag)", sItems, 0, "big_brother_info");
            if(GetIsObjectValid(oItem)) {
                sItems = GetName(oItem);
                if(GetItemStackSize(oItem) > 1)
                    sItems += " (" + IntToString(GetItemStackSize(oItem)) + ")";
                sItems += " (" + GetTag(oItem) + ")";
                SetPersistentString(oPC, "Stored Item (nr) (tag)", sItems, 0, "big_brother_info");
            }

            while(GetIsObjectValid(oItem))
            {
                oCopy = CopyItem(oItem, oCreature);
                oItem = GetNextItemInInventory(oStorage);

                // added by Paithan
                if(GetIsObjectValid(oItem)) {
                    sItems = "\n" + GetName(oItem);
                    if(GetItemStackSize(oItem) > 1)
                        sItems += " (" + IntToString(GetItemStackSize(oItem)) + ")";
                    sItems += " (" + GetTag(oItem) + ")";
                    AppendPersistentString(oPC, "Stored Item (nr) (tag)", sItems, 0, "big_brother_info");
                }
            }

            int iRet = StoreCampaignObject(PPIS_DB_NAME, sID, oCreature);


with AppendPersistentString() making the following query:

Code:

sSQL = "UPDATE " + sTable + " SET val=CONCAT(val, '" + sValue +
            "'),expire=" + IntToString(iExpiration) + " WHERE playerID=" + sPlayerID +
            " AND name='" + sVarName + "'";


The entry in the DB looks thereafter like this:

Cloudkill (Cloudkill)
Finger of Death (FingerofDeath)
Leather Armor (NW_AARCL001)
Thieves~ Tools +1 (NW_IT_PICKS001)
Standard Rover Armor (StandardRoverArmor)
Torch (NW_IT_TORCH001)
Dagger (NW_WSWDG001)
Finger of Death (FingerofDeath)
Improved Elf Light Armor (ImprovedElfLightArmor)
Woodsman Outfit (NW_CLOTH001)
Minor Spike Trap Kit (NW_IT_TRAP001)
Border Legion Short Sword - Improved (BLShortSwordImproved)
Enhanced Borderlands Arrows (87) (EnhancedBorderlandsArrows)
Improved Elf Longbow (ImprovedElfLongbow)
Improved Elf Short Sword (ImprovedElfShortSword)
Improved Elf Arrows (93) (ImprovedElfArrows)
Rover Arrows - Fine (99) (RoverArrowsFine)
Cloudkill (Cloudkill)
Knowledge Book - The Gnome Language (LearningBookGnome)
Knowledge Book - The Troll Language (LanguageBookTroll)
Potion of Cure Light Wounds (3) (NW_IT_MPOTION001)
Torch (NW_IT_TORCH001)
Minor Spike Trap Kit (NW_IT_TRAP001)
Leather Armor (NW_AARCL001)
Woodsman Outfit (NW_CLOTH001)

This works for about 27 items ...

Okay, now I got the point, where you say, that queries have to be limited to 1024 characters, but what I don't get is, why doesn't the CONCAT function work? If I send a string in the DB, let's say

INSERT INTO big_brother_info(playernumber, sItemset) VALUES(1,'Knowledge Book - The Gnome Language (LearningBookGnome)')

and I then append another sItem string to it with CONCAT, isn't the appending supposed to be done in the MySQL DB itself, without even using the NWNX connection (except for the sending of the new string that has to be appended), meaning that the query will never have more than 1024 characters, unless the sItem variable itself is > 1024? Question

Thanks!
Back to top
View user's profile Send private message MSN Messenger
Papillon
x-man


Joined: 28 Dec 2004
Posts: 1060
Location: Germany

PostPosted: Sun Feb 13, 2005 18:05    Post subject: Reply with quote

You can increase the amount of a data a single row can hold by using a bigger ODBC SPACER in aps_include. For Windows, the maximum should be 64KByte per Row.

Anyway, it should never crash, even if you go over the limit. Do you think you could create a small package that helps me reproducing the problem ?

Which OS btw ?
_________________
Papillon
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
PaithanQuindiniar



Joined: 12 Feb 2005
Posts: 4

PostPosted: Sun Feb 13, 2005 18:39    Post subject: Reply with quote

Hi there! (Thanks for the replies by the way!)

I can arrange a sample mod alright - going to need until saturday, since next week I have a skiing trip planned Rolling Eyes I'll send it as soon as I can!

We're running Win XP (or Win2K on my computer, which results in the same problem) ...
Back to top
View user's profile Send private message MSN Messenger
Papillon
x-man


Joined: 28 Dec 2004
Posts: 1060
Location: Germany

PostPosted: Sun Feb 13, 2005 20:29    Post subject: Reply with quote

Oh yes, forgot to ask which version and which plugins you are running.
_________________
Papillon
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> General Discussion 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