Bug #35729 Incorrect nil value on read_query_result
Submitted: 1 Apr 2008 4:09 Modified: 17 Aug 2009 15:17
Reporter: Diego Medina Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Proxy: Core Severity:S1 (Critical)
Version:0.6.1, r511 OS:Any (Fedora 8, Mac OS X 10.5)
Assigned to: Jan Kneschke CPU Architecture:Any
Tags: mysqlproxy

[1 Apr 2008 4:09] Diego Medina
Description:
I am injecting a "show global status" command after each query the proxy gets.
and as I process the result inside the lua script, I get random nil (null) values.

But the real "show global status" never returns null values.

How to repeat:
I will attach a small lua file

once you have mysql-proxy running reading this lua file, from another shell run any sql command.

i.e.

shell>mysql -uroot -pguessthisone -h 127.0.0.1 -P4040 test -e "select now()";

Note, start the mysql-proxy daemon from another shell screen so that yo ucan see the output of it.

Suggested fix:
is the proxy reading the result too fast?
[1 Apr 2008 4:09] Diego Medina
minimun lua file to replicate error

Attachment: log.lua (text/x-lua), 711 bytes.

[1 Apr 2008 4:10] Diego Medina
Oh, when you get the error, the lua script will kill the proxy.
[1 Apr 2008 19:17] Sveta Smirnova
Thank you for the report.

Verified as described.

Field workaround set to "Partial", because one always can check value.
[1 Apr 2008 19:40] Diego Medina
Hi Sveta,

This also happens on 0.7.0 svn (from last week)

and, I am not sure if I understand "Field workaround set to "Partial""

do you mean to include in the lua script something like:

if row[1] == nil then
...do something else"
end

?

Thanks!
[1 Apr 2008 19:59] Sveta Smirnova
Diego,

thank you for the feedback.

I put last SVN revision to version field already.

And yes, I workaround like that you posted.
[3 Apr 2008 0:19] Jan Kneschke
A field of a SQL request can be NULL and we map that to nil in lua. A string concat doesn't support concat with a nil value, so you have to cast it.

Either use tostring() to turn it into something useful to concat or use string.format() [see lua manual]. 

  print("fields: " .. tostring(row[1]))  

or 

  print(("fields: %s"):format(row[1]))
[3 Apr 2008 2:25] Diego Medina
Hi Jan,

Thank you for taking the time, I understand that you can get NULL values from a SQL statement, the SQL statement I submitted with this bug is

show global status;

should I file a bug report with the server?

As when I run any sql to activate the lua script, I get NULL values (nil from Lua) in the "Name" field (like instead of getting the word "Updatime" I get nil.

(I changed the bug to open as I do not know if nobody would see it otherwise)

Thanks!

Diego Medina
[3 Apr 2008 3:42] Diego Medina
Me again, as this bug may be a bit difficult to prove, I came up with a new test case.

This new test case sends the "same" resultset to the proxy and to the mysql command line client.

So this (hopefully) will probe that the statement "SHOW GLOBAL STATUS" does not return NULL values.
[3 Apr 2008 3:43] Diego Medina
new test case

Attachment: log.lua (text/x-lua), 3.62 KiB.

[6 Jun 2008 16:26] Jan Kneschke
In valgrind I see:

we got a normal query: select @@version_comment limit 1

we got a normal query: SELECT 1
==20972== Invalid read of size 4
==20972==    at 0x411FDBF: proxy_resultset_rows_iter (query-handling.c:302)
==20972==    by 0x42B3901: luaD_precall (ldo.c:319)
==20972==    by 0x42B3D55: luaD_call (ldo.c:376)
==20972==    by 0x42BE024: luaV_execute (lvm.c:685)
==20972==    by 0x42B3D9F: luaD_call (ldo.c:377)
==20972==    by 0x42AF510: f_call (lapi.c:796)
==20972==    by 0x42B3462: luaD_rawrunprotected (ldo.c:116)
==20972==    by 0x42B34C7: luaD_pcall (ldo.c:461)
==20972==    by 0x42AF373: lua_pcall (lapi.c:817)
==20972==    by 0x428E23D: proxy_read_query_result (proxy-plugin.c:1629)
==20972==    by 0x4116E87: plugin_call (network-mysqld.c:634)
==20972==    by 0x4117342: network_mysqld_con_handle (network-mysqld.c:1204)
==20972==    by 0x429AA41: event_base_loop (in /usr/lib/libevent-1.3e.so.1.0.3)
==20972==    by 0x429AD34: event_base_dispatch (in /usr/lib/libevent-1.3e.so.1.0.3)
==20972==    by 0x4034747: chassis_mainloop (chassis-mainloop.c:165)
==20972==    by 0x8049F2C: main_cmdline (chassis.c:744)
==20972==    by 0x804A3E1: main (chassis.c:796)
==20972==  Address 0x438a3d4 is 4 bytes inside a block of size 12 free'd
==20972==    at 0x402265C: free (vg_replace_malloc.c:323)
==20972==    by 0x4083130: g_free (gmem.c:190)
==20972==    by 0x40980E6: g_slice_free1 (gslice.c:886)
==20972==    by 0x4055DC9: g_ptr_array_free (garray.c:400)
==20972==    by 0x4119718: network_mysqld_proto_fielddefs_free (network-mysqld-proto.c:515)
==20972==    by 0x411FFCC: proxy_resultset_free (query-handling.c:160)
==20972==    by 0x412000E: proxy_resultset_gc (query-handling.c:172)
==20972==    by 0x42B3901: luaD_precall (ldo.c:319)
==20972==    by 0x42B3D55: luaD_call (ldo.c:376)
==20972==    by 0x42B5462: GCTM (lgc.c:467)
==20972==    by 0x42B5522: singlestep (lgc.c:594)
==20972==    by 0x42B58DF: luaC_step (lgc.c:617)
==20972==    by 0x42BE024: luaV_execute (lvm.c:685)
==20972==    by 0x42B3D9F: luaD_call (ldo.c:377)
==20972==    by 0x42AF510: f_call (lapi.c:796)
==20972==    by 0x42B3462: luaD_rawrunprotected (ldo.c:116)
==20972==    by 0x42B34C7: luaD_pcall (ldo.c:461)
==20972==    by 0x42AF373: lua_pcall (lapi.c:817)
==20972==    by 0x428E23D: proxy_read_query_result (proxy-plugin.c:1629)
==20972==    by 0x4116E87: plugin_call (network-mysqld.c:634)
==20972==    by 0x4117342: network_mysqld_con_handle (network-mysqld.c:1204)
==20972==    by 0x429AA41: event_base_loop (in /usr/lib/libevent-1.3e.so.1.0.3)
==20972==    by 0x429AD34: event_base_dispatch (in /usr/lib/libevent-1.3e.so.1.0.3)
==20972==    by 0x4034747: chassis_mainloop (chassis-mainloop.c:165)
[7 Jul 2009 16:25] Jan Kneschke
revno: 746
committer: jan@mysql.com
branch nick: trunk
timestamp: Tue 2009-07-07 17:15:03 +0200
message:
  moved the implementation of GRef into the chassis
------------------------------------------------------------
revno: 745
committer: jan@mysql.com
branch nick: trunk
timestamp: Tue 2009-07-07 16:22:42 +0200
message:
  implemented a c-layer refcounting 
  
    the previous code used the Lua-later ref-counter (lua_pushvalue) which
    calls the __gc() functions if all references to a userdata are unused
      In our case we want to use the same c-structure for different lua
    metatables (row, fields, ...). To make that work, we use different 
    userdatas and metatables, but all reference the c-struct by pointing
    to a GRef that points to the real c-struct.
      The __gc() functions of the userdatas only call g_ref_unref() which
    for the last __gc() frees the c-struct.
------------------------------------------------------------
revno: 744
committer: jan@mysql.com
branch nick: trunk
timestamp: Tue 2009-07-07 16:18:55 +0200
message:
  extended the test to cover the fields too
------------------------------------------------------------
revno: 743
committer: jan@mysql.com
branch nick: trunk
timestamp: Tue 2009-07-07 14:47:55 +0200
message:
  fixed a "gc-too-early" that removed the userdata while a light-userdata was still 
  referencing it (fixes #35729)
  
    * instead of wrapping the resultset in a light userdata, just push the userdata
      again to let the GC see it is still referenced
------------------------------------------------------------
revno: 742
committer: jan@mysql.com
branch nick: trunk
timestamp: Tue 2009-07-07 12:53:01 +0200
message:
  added failing test case for #35729
[10 Jul 2009 11:53] Jan Kneschke
pushed as r694..698 to 0.7
[14 Jul 2009 20:33] Enterprise Tools JIRA Robot
Diego Medina writes: 
Verified fixed on 0.7.3
[17 Aug 2009 15:17] MC Brown
A note has been added to the 0.7.3 changelog: 

It was possible for the MySQL Proxy to incorrectly insert null values into the returned result set, even though non-null values were returned in the original query.
[19 May 2010 9:26] Mark Leith
This was actually fixed in 0.8.0, there was no 0.7.3 release in the end.