4242#define TIMEOUT_INFINITY 365 * 86400 * 100.0
4343static const char mysql_driver_label [] = "__tnt_mysql_driver" ;
4444
45+ static int luaL_nil_ref = LUA_REFNIL ;
46+
47+ /**
48+ * Push ffi's NULL (cdata<void *>: NULL) onto the stack.
49+ * Can be used as replacement of nil in Lua tables.
50+ * @param L stack
51+ */
52+ static inline void
53+ luaL_pushnull (struct lua_State * L )
54+ {
55+ lua_rawgeti (L , LUA_REGISTRYINDEX , luaL_nil_ref );
56+ }
57+
4558struct mysql_connection {
4659 MYSQL * raw_conn ;
4760 int use_numeric_result ;
61+ int keep_null ;
4862};
4963
5064/*
@@ -169,11 +183,23 @@ lua_mysql_field_type_to_string(enum enum_field_types type)
169183 return mysql_field_type_strs [hash ];
170184}
171185
172- /* Push value retrieved from mysql field to lua stack */
186+ /**
187+ * Push value retrieved from mysql field to lua stack.
188+ *
189+ * When `data` is NULL, `field` and len` parameters are
190+ * ignored and Lua nil or LuaJIT FFI NULL is pushed.
191+ */
173192static void
174- lua_mysql_push_value (struct lua_State * L , MYSQL_FIELD * field ,
175- void * data , unsigned long len )
193+ lua_mysql_push_value (struct lua_State * L , MYSQL_FIELD * field , void * data ,
194+ unsigned long len , int keep_null )
176195{
196+ /*
197+ * Field type isn't MYSQL_TYPE_NULL actually in case of
198+ * Lua's nil passed as value.
199+ * Example: 'conn:execute('SELECT ? AS x', nil)'.
200+ */
201+ if (data == NULL )
202+ field -> type = MYSQL_TYPE_NULL ;
177203 switch (field -> type ) {
178204 case MYSQL_TYPE_TINY :
179205 case MYSQL_TYPE_SHORT :
@@ -188,7 +214,10 @@ lua_mysql_push_value(struct lua_State *L, MYSQL_FIELD *field,
188214 }
189215
190216 case MYSQL_TYPE_NULL :
191- lua_pushnil (L );
217+ if (keep_null == 1 )
218+ luaL_pushnull (L );
219+ else
220+ lua_pushnil (L );
192221 break ;
193222
194223 case MYSQL_TYPE_LONGLONG : {
@@ -239,10 +268,8 @@ lua_mysql_fetch_result(struct lua_State *L)
239268 unsigned long * len = mysql_fetch_lengths (result );
240269 unsigned col_no ;
241270 for (col_no = 0 ; col_no < num_fields ; ++ col_no ) {
242- if (!row [col_no ])
243- continue ;
244- lua_mysql_push_value (L , fields + col_no ,
245- row [col_no ], len [col_no ]);
271+ lua_mysql_push_value (L , fields + col_no , row [col_no ],
272+ len [col_no ], conn -> keep_null );
246273 if (conn -> use_numeric_result ) {
247274 /* Assign to a column number. */
248275 lua_rawseti (L , -2 , col_no + 1 );
@@ -350,16 +377,16 @@ lua_mysql_stmt_push_row(struct lua_State *L)
350377 unsigned long col_count = lua_tonumber (L , 1 );
351378 MYSQL_BIND * results = (MYSQL_BIND * )lua_topointer (L , 2 );
352379 MYSQL_FIELD * fields = (MYSQL_FIELD * )lua_topointer (L , 3 );
380+ int keep_null = lua_tointeger (L , 4 );
353381
354382 lua_newtable (L );
355383 unsigned col_no ;
356384 for (col_no = 0 ; col_no < col_count ; ++ col_no ) {
357- if ( * results [col_no ].is_null )
358- continue ;
385+ void * data = * results [col_no ].is_null ? NULL :
386+ results [ col_no ]. buffer ;
359387 lua_pushstring (L , fields [col_no ].name );
360- lua_mysql_push_value (L , fields + col_no ,
361- results [col_no ].buffer ,
362- * results [col_no ].length );
388+ lua_mysql_push_value (L , fields + col_no , data ,
389+ * results [col_no ].length , keep_null );
363390 lua_settable (L , -3 );
364391 }
365392 return 1 ;
@@ -371,7 +398,7 @@ lua_mysql_stmt_push_row(struct lua_State *L)
371398static int
372399lua_mysql_execute_prepared (struct lua_State * L )
373400{
374- MYSQL * raw_conn = lua_check_mysqlconn (L , 1 )-> raw_conn ;
401+ struct mysql_connection * conn = lua_check_mysqlconn (L , 1 );
375402 size_t len ;
376403 const char * sql = lua_tolstring (L , 2 , & len );
377404 int ret_count = 0 , fail = 0 , error = 0 ;
@@ -389,7 +416,7 @@ lua_mysql_execute_prepared(struct lua_State *L)
389416 lua_pushnumber (L , 0 );
390417 lua_newtable (L );
391418 ret_count = 2 ;
392- stmt = mysql_stmt_init (raw_conn );
419+ stmt = mysql_stmt_init (conn -> raw_conn );
393420 if ((error = !stmt ))
394421 goto done ;
395422 error = mysql_stmt_prepare (stmt , sql , len );
@@ -467,7 +494,8 @@ lua_mysql_execute_prepared(struct lua_State *L)
467494 lua_pushnumber (L , col_count );
468495 lua_pushlightuserdata (L , result_binds );
469496 lua_pushlightuserdata (L , fields );
470- if ((fail = lua_pcall (L , 3 , 1 , 0 )))
497+ lua_pushinteger (L , conn -> keep_null );
498+ if ((fail = lua_pcall (L , 4 , 1 , 0 )))
471499 goto done ;
472500 lua_settable (L , -3 );
473501 ++ row_idx ;
@@ -476,7 +504,7 @@ lua_mysql_execute_prepared(struct lua_State *L)
476504
477505done :
478506 if (error )
479- ret_count = lua_mysql_push_error (L , raw_conn );
507+ ret_count = lua_mysql_push_error (L , conn -> raw_conn );
480508 if (values )
481509 free (values );
482510 if (param_binds )
@@ -592,9 +620,9 @@ mysql_wait_for_io(my_socket socket, my_bool is_read, int timeout)
592620static int
593621lua_mysql_connect (struct lua_State * L )
594622{
595- if (lua_gettop (L ) < 6 ) {
623+ if (lua_gettop (L ) < 7 ) {
596624 luaL_error (L , "Usage: mysql.connect(host, port, user, "
597- "password, db, use_numeric_result)" );
625+ "password, db, use_numeric_result, keep_null )" );
598626 }
599627
600628 const char * host = lua_tostring (L , 1 );
@@ -603,6 +631,7 @@ lua_mysql_connect(struct lua_State *L)
603631 const char * pass = lua_tostring (L , 4 );
604632 const char * db = lua_tostring (L , 5 );
605633 const int use_numeric_result = lua_toboolean (L , 6 );
634+ const int keep_null = lua_toboolean (L , 7 );
606635
607636 MYSQL * raw_conn , * tmp_raw_conn = mysql_init (NULL );
608637 if (!tmp_raw_conn ) {
@@ -650,6 +679,7 @@ lua_mysql_connect(struct lua_State *L)
650679 * conn_p = conn ;
651680 (* conn_p )-> raw_conn = raw_conn ;
652681 (* conn_p )-> use_numeric_result = use_numeric_result ;
682+ (* conn_p )-> keep_null = keep_null ;
653683 luaL_getmetatable (L , mysql_driver_label );
654684 lua_setmetatable (L , -2 );
655685
@@ -679,6 +709,10 @@ luaopen_mysql_driver(lua_State *L)
679709 if (mysql_library_init (0 , NULL , NULL ))
680710 luaL_error (L , "Failed to initialize mysql library" );
681711
712+ /* Create NULL constant. */
713+ * (void * * ) luaL_pushcdata (L , luaL_ctypeid (L , "void *" )) = NULL ;
714+ luaL_nil_ref = luaL_ref (L , LUA_REGISTRYINDEX );
715+
682716 static const struct luaL_Reg methods [] = {
683717 {"execute_prepared" , lua_mysql_execute_prepared },
684718 {"execute" , lua_mysql_execute },
0 commit comments