🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

lua_newtable / lua_settable

Started by
10 comments, last by Ironica 20 years, 11 months ago
Hey guys =) This function crashes my program, but I don''t totally understand how to do it properly >.< Would like some help understanding it =) I''m getting really confused over calling lua_settable.

static int lua_sql(lua_State *L){
	if(lua_isstring(L, 1) && mysql != NULL){
		if(mysql_query(mysql, lua_tostring(L, 1))){
			output(lua_tostring(L, 1));
		}else{
			MYSQL_RES *result = mysql_store_result(mysql);
			MYSQL_ROW row;
			lua_newtable(L);
			int rowcount = 1;
			while(row = mysql_fetch_row(result)){
				lua_pushnumber(L, rowcount);
				lua_newtable(L);
				lua_settable(L, -3);
				int i = 0;
				while(row[i]){
					lua_pushnumber(L, i + 1);
					lua_pushstring(L, row[i]);
					lua_settable(L, -3);
					i++;
				}
				rowcount++;
			}
		}
	}
	lua_pop(L, 1);
	return 0;
}
mysql is a MYSQL*, and will be NULL, if there''s no connection to the database. Basically, this function is supposed to execute the arguement as a sql query. Then return a lua table, which contains any result from the database. I know it doesn''t do that yet, because I''m just testing it so far. Alrighty, let me explain what I think it does (or supposed to do). First checks there''s a connection to the database, and the arguement from Lua is a string. Then executes the arguement as sql query. If it fails, it outputs the query to my program window. If it works, it stores the result, and creates a Lua table on the stack. It loops over, fetching a row from the database. It pushes a number, which should be the key on the table. Then creates a new table, which should be the value of the first table. Then sets the table (that''s in the wrong place for a start, right?). Then loops through each field of the row, pushing the relevant key and value, and setting the table. Doesn''t bother returning it or anything, since it''s just a test. Someone explain to me when to call lua_settable? I should only call it once, once the table is complete, right? If so, that''s obviously the problem, calling it in the loop. Does it place alternate stack values as keys and values of the table? Could really do with some help understanding it =) hehe...
Advertisement
You really need to grab the docs and give them a thorough read

newtable() creates a new table and pushes it onto the stack.

settable() stores a value into the table. The stack must be setup so that the value is at the top of the stack and the key is just underneath the value.

So if you index on numbers:

lua_newtable(L)

lua_pushnumber(L,key)
lua_pushnumber(L,value)
lua_settable(L,-3)

settable pops both the key and value off the stack so after the above fragment the stack just has the table on the top.

I think you are being bitten by that popping. You new table is being popped after being added to the top level table so when you come to populate the inner table, the reference is no longer there (or at least I think that's what you're trying to do). I'm not 100% sure why it is crashing, although the logic isn't quite right, theres nothing that leaps out as a crash bug.

You probably want this sequence:

lua_newtable()  // top level tablefor each row r  lua_newtable() // push new table  lua_pushnumber(r)  lua_pushvalue(-2)  // get the new table and push a reference to the top  lua_settable(-4)  for each element i    lua_pushnumber(i)    lua_pushstring(element)<br>    lua_settable(-3)<br><br>  lua_pop(1)<br> </pre>     <br><br><SPAN CLASS=editedby>[edited by - JuNC on August 2, 2003 9:48:58 AM]</SPAN>
Right... Hehe, thanks for reply. I have been reading the docs, but I''m still having trouble understanding what lua_settable does. I think I understand what you''re saying, I''ll try it out, thanks =)


It''s quite straight forward as long as you know how the stack works. Imagine it like this:

Step 1 (newtable)

stack top: TABLErest of    ----- stack      ----- 


Step 2 (pushnumber key)

stack top: key           TABLE           -----           ----- 


Step 3 (pushnumber value)

stack top: value           key           TABLE           -----           ----- 


Step 4 (settable -3)

stack top: TABLE           -----           ----- 


etc.
Ahh thanks, that helped a lot =)
It no longer crashes, but execution of the Lua script fails >.<
MYSQL_RES *result = mysql_store_result(mysql);MYSQL_ROW row;lua_newtable(L); // 1int rowcount = 0;while(row = mysql_fetch_row(result)){	lua_pushnumber(L, rowcount); // 2	lua_newtable(L); // 3	lua_pushvalue(L, -1); // 4	lua_settable(L, -4); // 5	int i = 0;	while(row[i]){		lua_pushnumber(L, i); // 6		lua_pushstring(L, row[i]); // 7		lua_settable(L, -3); // 8		i++;	}	rowcount++;}

If I call lua_newtable again, before pushing the key, that seems to crash it =/
Ok, let me see. I labelled those functions, step 1 - 8. I''ll see if I can understand what the stack looks like each time...

1:
Table

2:
Key
Table

3:
Table (value)
Key
Table

4:
reference to Table (value)
Table (value)
Key
Table

5:
reference to Table (value)
Table

6:
Key
reference to Table (value)
Table

7:
Value
Key
reference to Table (value)
Table

8:
reference to Table (value)
Table

Hmm... Does lua_settable set the 1st 2 stack values after the table as key and value? Or does it take the last 2 stack values?
settable always takes the top two values off the stack. Your step 4 needs to be rearranged because you are using two table references:

reference to Table (value)
Table (value)
Key <- this will remain after the settable call
Table

Whereas what you want is:

reference to Table (value)
Key
Table (value) <- this will remain after the settable call
Table

(which is how I originally wrote it). Your actual diagram of the stack is correct for your code, but the logic is still screwed up.

Note also that everytime you finish one of the inner tables you should pop the top of the stack.
This is how I would write the function, assuming I have understood correctly what you''re trying to do:

static int lua_sql(lua_State *L){		if(lua_isstring(L, 1) && mysql != NULL)	{				if(mysql_query(mysql, lua_tostring(L, 1)))		{						output(lua_tostring(L, 1));				}		else		{						MYSQL_RES *result = mysql_store_result(mysql);						MYSQL_ROW row;			lua_newtable(L);						int rowcount = 1;						while(row = mysql_fetch_row(result))			{								lua_newtable(L); // new inner table								lua_pushnumber(L, rowcount); // key								lua_pushvalue(L,-2); // value				lua_settable(L, -4); // refer to the top level table				int i = 0;				while(row[i])				{					lua_pushnumber(L, i + 1); // key in inner table					lua_pushstring(L, row[i]); // value for inner table						lua_settable(L, -3); // refer to inner table						i++;				}				lua_pop(L,1); // done with inner table, remove it so top level table is on top of stack				rowcount++;			}		}	}	lua_pop(L, 1);		return 0;}
Thanks. Makes a lot of sense, but it crashes =/ Can''t understand why.
I''ll just make sure you understand what I''m trying to do...

I basically wanna export the row into Lua. But I''m trying to make an array of rows, or a 2 dimensional array of fields.
I honestly can''t see why it should be crashing, although I haven''t tested the code I''m sure the Lua API isn''t at fault here, have you definitely narrowed it down to something being done in the Lua code? Could the MySQL code be crashing?
Yup, it was >.< sorry hehe. I just got out of the deep, and got back in via the shallow end. It kinda threw me off when I moved that lua_pushvalue, started to think it was my Lua code that was at fault. My function now looks like this:
static int lua_sql(lua_State *L){	if(lua_isstring(L, 1) && mysql != NULL){		if(mysql_query(mysql, lua_tostring(L, 1))){			output(lua_tostring(L, 1));		}else{			MYSQL_RES *result = mysql_store_result(mysql);			MYSQL_ROW row;			lua_newtable(L);			int rowcount = 1;			while(row = mysql_fetch_row(result)){				lua_newtable(L);				lua_pushnumber(L, rowcount);				lua_pushvalue(L, -2);				lua_settable(L, -4);				unsigned int fields = mysql_num_fields(result);				for(int i = 0; i < fields; i++){					lua_pushnumber(L, i + 1);					lua_pushstring(L, row[i]);					output(row[i]);					lua_settable(L, -3);				}				lua_pop(L, 1);				rowcount++;			}		}	}	lua_pop(L, 1);	return 1;}

It doesn't crash, and each field is definately being extracted from the database, because I'm outputting it there, as a test. Now it seems that the tables aren't created properly >.< The way it should work is like this:
db = sqlexec("SELECT * FROM tbl_mytable")db[1][1] -- row 1, field 1db[1][2] -- row 1, field 2-- etcdb[2][1] -- row 2, field 1-- etc etc    

Can you see where it's going wrong? I can't >.<

Edit - Just added in that other lua_pop. But now, the value it returns is a string, which is the arguement in the first place! Hehe, I think I might get it right in a minute.

[edited by - Ironica on August 2, 2003 8:28:56 PM]

This topic is closed to new replies.

Advertisement