Forráskód Böngészése

* Added a sanity check for MAX_ZENY (doesn't compile if too big).
* Redid the buildin_query_sql function. (fixes bugreport:81).

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11268 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS 17 éve
szülő
commit
b848357f20
4 módosított fájl, 85 hozzáadás és 49 törlés
  1. 3 0
      Changelog-Trunk.txt
  2. 2 2
      doc/script_commands.txt
  3. 5 0
      src/common/mmo.h
  4. 75 47
      src/map/script.c

+ 3 - 0
Changelog-Trunk.txt

@@ -3,6 +3,9 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2007/09/22
+	* Added a sanity check for MAX_ZENY (doesn't compile if too big).
+	* Redid the buildin_query_sql function. (fixes bugreport:81). [FlavioJS]
 2007/09/21
 	* itemdb.c/h using a static array of 32k struct item_data* entries (faster 
 	  itemdb loockup and a first step to remove map_session_data->inventory_data).

+ 2 - 2
doc/script_commands.txt

@@ -5871,9 +5871,9 @@ set @i, distance(100,200,101,202);
 
 ---------------------------------------
 
-*query_sql "your MySQL query", <array name>{,<array name>{;
+*query_sql "your MySQL query", <array variable> {,<array variable>, ...};
 
-Returns up to 127 values into array and return the number of row
+Puts up to 128 rows of values into the arrays and returns the number of rows.
 
 Example:
 set @nb, query_sql("select name,fame from `char` ORDER BY fame DESC LIMIT 5", @name$, @fame);

+ 5 - 0
src/common/mmo.h

@@ -497,4 +497,9 @@ enum {
 	JOB_SOUL_LINKER,
 };
 
+// sanity checks...
+#if MAX_ZENY > INT_MAX
+#error MAX_ZENY is too big
+#endif
+
 #endif /* _MMO_H_ */

+ 75 - 47
src/map/script.c

@@ -12113,73 +12113,101 @@ BUILDIN_FUNC(setd)
 BUILDIN_FUNC(query_sql)
 {
 #ifndef TXT_ONLY
-	int i, j, nb_rows;
-	struct { char* dst_var_name; char type; } row[32];
-	TBL_PC* sd = (st->rid) ? script_rid2sd(st) : NULL;
+	int i, j;
+	TBL_PC* sd = NULL;
+	const char* query;
+	struct script_data* data;
+	char* name;
+	int max_rows = 128;// maximum number of rows
+	int num_vars;
+	int num_cols;
 
-	const char* query = script_getstr(st,2);
-	if (SQL_ERROR == Sql_Query(mmysql_handle, query) )
+	// check target variables
+	for( i = 3; script_hasdata(st,i); ++i )
+	{
+		data = script_getdata(st, i);
+		if( data_isreference(data) && reference_tovariable(data) )
+		{// it's a variable
+			name = reference_getname(data);
+			if( not_server_variable(*name) && sd == NULL )
+			{// requires a player
+				sd = script_rid2sd(st);
+				if( sd == NULL )
+				{// no player attached
+					script_reportdata(data);
+					st->state = END;
+					return 1;
+				}
+			}
+			if( not_array_variable(*name) )
+				max_rows = 1;// not an array, limit to one row
+		}
+		else
+		{
+			ShowError("script:query_sql: not a variable\n");
+			script_reportdata(data);
+			st->state = END;
+			return 1;
+		}
+	}
+	num_vars = i - 3;
+
+	// Execute the query
+	query = script_getstr(st,2);
+	if( SQL_ERROR == Sql_Query(mmysql_handle, query) )
 	{
 		Sql_ShowDebug(mmysql_handle);
 		script_pushint(st, 0);
 		return 1;
 	}
 
-	// Count the number of rows to store
-	nb_rows = Sql_NumColumns(mmysql_handle);
-	//FIXME: what sick mind would write something like this?
-
-	// Can't store more row than variable
-	if (nb_rows > st->end - (st->start+3))
-		nb_rows = st->end - (st->start+3);
-
-	if (!nb_rows)
-	{
-		script_pushint(st,0);
-		return 0; // Nothing to store
+	if( Sql_NumRows(mmysql_handle) == 0 )
+	{// No data received
+		Sql_FreeResult(mmysql_handle);
+		script_pushint(st, 0);
+		return 0;
 	}
 
-	if (nb_rows > 32)
+	// Count the number of columns to store
+	num_cols = Sql_NumColumns(mmysql_handle);
+	if( num_vars < num_cols )
 	{
-		ShowWarning("buildin_query_sql: too many rows!\n");
-		script_pushint(st,0);
-		return 1;
+		ShowWarning("script:query_sql: Too many columns, discarting last %u columns.\n", (unsigned int)(num_cols-num_vars));
+		script_reportsrc(st);
 	}
-
-	memset(row, 0, sizeof(row));
-	// Verify argument types
-	for(j=0; j < nb_rows; j++)
+	else if( num_vars > num_cols )
 	{
-		if(!data_isreference(script_getdata(st, 3+j))){
-			ShowWarning("buildin_query_sql: Parameter %d is not a variable!\n", j);
-			script_pushint(st,0);
-			return 0;
-		} else {
-			// Store type of variable (string = 0/int = 1)
-			int num = st->stack->stack_data[st->start+3+j].u.num;
-			char* name = str_buf + str_data[num&0x00ffffff].str;
-			if(name[strlen(name)-1] != '$') {
-				row[j].type = 1;
-			}
-			row[j].dst_var_name = name;
-		}
+		ShowWarning("script:query_sql: Too many variables (%u extra).\n", (unsigned int)(num_vars-num_cols));
+		script_reportsrc(st);
 	}
+
 	// Store data
-	for (i = 0; i < 128 && SQL_SUCCESS == Sql_NextRow(mmysql_handle); i++)
+	for( i = 0; i < max_rows && SQL_SUCCESS == Sql_NextRow(mmysql_handle); ++i )
 	{
-		char* data;
-		Sql_GetData(mmysql_handle, j, &data, NULL);
-		for(j = 0; j < nb_rows; j++) {
-			if (row[j].type == 1)
-				setd_sub(st,sd, row[j].dst_var_name, i, (void *)atoi(data), script_getref(st,3+j));
+		for( j = 0; j < num_vars; ++j )
+		{
+			char* str = NULL;
+
+			if( j < num_cols )
+				Sql_GetData(mmysql_handle, j, &str, NULL);
+
+			data = script_getdata(st, j+3);
+			name = reference_getname(data);
+			if( is_string_variable(name) )
+				setd_sub(st, sd, name, i, (void *)(str?str:""), reference_getref(data));
 			else
-				setd_sub(st,sd, row[j].dst_var_name, i, (void *)data, script_getref(st,3+j));
+				setd_sub(st, sd, name, i, (void *)(str?atoi(str):0), reference_getref(data));
 		}
 	}
+	if( i == max_rows && max_rows < Sql_NumRows(mmysql_handle) )
+	{
+		ShowWarning("script:query_sql: Only %d/%u rows have been stored.\n", max_rows, (unsigned int)Sql_NumRows(mmysql_handle));
+		script_reportsrc(st);
+	}
+
 	// Free data
 	Sql_FreeResult(mmysql_handle);
-
-	script_pushint(st,i);
+	script_pushint(st, i);
 #else
 	//for TXT version, we always return -1
 	script_pushint(st,-1);