hyung-hwan
9fa26924c7
All checks were successful
continuous-integration/drone/push Build is passing
modifed mod-uci.h to be compilable at least - it's full of problems
1917 lines
49 KiB
C
1917 lines
49 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "mod-mysql.h"
|
|
|
|
#include <mysql.h>
|
|
#if !defined(MARIADB_VERSION_ID) && defined(MYSQL_VERSION_ID) && (MYSQL_VERSION_ID > 80000)
|
|
typedef bool my_bool;
|
|
#endif
|
|
|
|
#include "../lib/hawk-prv.h"
|
|
|
|
#if MYSQL_VERSION_ID < 50000
|
|
# define DUMMY_OPT_RECONNECT 31231 /* randomly chosen */
|
|
#endif
|
|
|
|
struct param_data_t
|
|
{
|
|
my_bool is_null;
|
|
union
|
|
{
|
|
my_ulonglong llv;
|
|
double dv;
|
|
struct
|
|
{
|
|
char* ptr;
|
|
unsigned long len;
|
|
} sv;
|
|
} u;
|
|
};
|
|
typedef struct param_data_t param_data_t;
|
|
typedef struct param_data_t res_data_t;
|
|
|
|
#define __IDMAP_NODE_T_DATA MYSQL* mysql; int connect_ever_attempted;
|
|
#define __IDMAP_LIST_T_DATA int errnum; hawk_ooch_t errmsg[256];
|
|
#define __IDMAP_LIST_T sql_list_t
|
|
#define __IDMAP_NODE_T sql_node_t
|
|
#define __INIT_IDMAP_LIST __init_sql_list
|
|
#define __FINI_IDMAP_LIST __fini_sql_list
|
|
#define __MAKE_IDMAP_NODE __new_sql_node
|
|
#define __FREE_IDMAP_NODE __free_sql_node
|
|
#include "../lib/idmap-imp.h"
|
|
|
|
#undef __IDMAP_NODE_T_DATA
|
|
#undef __IDMAP_LIST_T_DATA
|
|
#undef __IDMAP_LIST_T
|
|
#undef __IDMAP_NODE_T
|
|
#undef __INIT_IDMAP_LIST
|
|
#undef __FINI_IDMAP_LIST
|
|
#undef __MAKE_IDMAP_NODE
|
|
#undef __FREE_IDMAP_NODE
|
|
|
|
#define __IDMAP_NODE_T_DATA MYSQL_RES* res; unsigned int num_fields;
|
|
#define __IDMAP_LIST_T_DATA /* int errnum; */
|
|
#define __IDMAP_LIST_T res_list_t
|
|
#define __IDMAP_NODE_T res_node_t
|
|
#define __INIT_IDMAP_LIST __init_res_list
|
|
#define __FINI_IDMAP_LIST __fini_res_list
|
|
#define __MAKE_IDMAP_NODE __new_res_node
|
|
#define __FREE_IDMAP_NODE __free_res_node
|
|
#include "../lib/idmap-imp.h"
|
|
|
|
#undef __IDMAP_NODE_T_DATA
|
|
#undef __IDMAP_LIST_T_DATA
|
|
#undef __IDMAP_LIST_T
|
|
#undef __IDMAP_NODE_T
|
|
#undef __INIT_IDMAP_LIST
|
|
#undef __FINI_IDMAP_LIST
|
|
#undef __MAKE_IDMAP_NODE
|
|
#undef __FREE_IDMAP_NODE
|
|
|
|
#define __IDMAP_NODE_T_DATA MYSQL_STMT* stmt; MYSQL_BIND* param_binds; param_data_t* param_data; hawk_oow_t param_capa; MYSQL_BIND* res_binds; res_data_t* res_data; hawk_oow_t res_capa;
|
|
#define __IDMAP_LIST_T_DATA /* int errnum; */
|
|
#define __IDMAP_LIST_T stmt_list_t
|
|
#define __IDMAP_NODE_T stmt_node_t
|
|
#define __INIT_IDMAP_LIST __init_stmt_list
|
|
#define __FINI_IDMAP_LIST __fini_stmt_list
|
|
#define __MAKE_IDMAP_NODE __new_stmt_node
|
|
#define __FREE_IDMAP_NODE __free_stmt_node
|
|
#include "../lib/idmap-imp.h"
|
|
|
|
struct rtx_data_t
|
|
{
|
|
sql_list_t sql_list;
|
|
res_list_t res_list;
|
|
stmt_list_t stmt_list;
|
|
};
|
|
typedef struct rtx_data_t rtx_data_t;
|
|
|
|
static sql_node_t* new_sql_node (hawk_rtx_t* rtx, sql_list_t* sql_list)
|
|
{
|
|
sql_node_t* sql_node;
|
|
|
|
sql_node = __new_sql_node(rtx, sql_list);
|
|
if (!sql_node) return HAWK_NULL;
|
|
|
|
sql_node->mysql = mysql_init(HAWK_NULL);
|
|
if (!sql_node->mysql)
|
|
{
|
|
__free_sql_node (rtx, sql_list, sql_node);
|
|
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_ENOMEM, HAWK_T("unable to allocate a mysql object"));
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
return sql_node;
|
|
}
|
|
|
|
static void free_sql_node (hawk_rtx_t* rtx, sql_list_t* sql_list, sql_node_t* sql_node)
|
|
{
|
|
mysql_close (sql_node->mysql);
|
|
sql_node->mysql = HAWK_NULL;
|
|
__free_sql_node (rtx, sql_list, sql_node);
|
|
}
|
|
|
|
static res_node_t* new_res_node (hawk_rtx_t* rtx, res_list_t* res_list, MYSQL_RES* res)
|
|
{
|
|
res_node_t* res_node;
|
|
|
|
res_node = __new_res_node(rtx, res_list);
|
|
if (!res_node) return HAWK_NULL;
|
|
|
|
res_node->res = res;
|
|
res_node->num_fields = mysql_num_fields(res);
|
|
|
|
return res_node;
|
|
}
|
|
|
|
static void free_res_node (hawk_rtx_t* rtx, res_list_t* res_list, res_node_t* res_node)
|
|
{
|
|
mysql_free_result (res_node->res);
|
|
res_node->res = HAWK_NULL;
|
|
__free_res_node (rtx, res_list, res_node);
|
|
}
|
|
|
|
static stmt_node_t* new_stmt_node (hawk_rtx_t* rtx, stmt_list_t* stmt_list, MYSQL_STMT* stmt)
|
|
{
|
|
stmt_node_t* stmt_node;
|
|
|
|
stmt_node = __new_stmt_node(rtx, stmt_list);
|
|
if (!stmt_node) return HAWK_NULL;
|
|
|
|
stmt_node->stmt = stmt;
|
|
|
|
return stmt_node;
|
|
}
|
|
|
|
static void free_stmt_node (hawk_rtx_t* rtx, stmt_list_t* stmt_list, stmt_node_t* stmt_node)
|
|
{
|
|
mysql_stmt_close (stmt_node->stmt);
|
|
stmt_node->stmt = HAWK_NULL;
|
|
__free_stmt_node (rtx, stmt_list, stmt_node);
|
|
}
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static HAWK_INLINE sql_list_t* rtx_to_sql_list (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
hawk_rbt_pair_t* pair;
|
|
rtx_data_t* data;
|
|
pair = hawk_rbt_search((hawk_rbt_t*)fi->mod->ctx, &rtx, HAWK_SIZEOF(rtx));
|
|
HAWK_ASSERT (pair != HAWK_NULL);
|
|
data = (rtx_data_t*)HAWK_RBT_VPTR(pair);
|
|
return &data->sql_list;
|
|
}
|
|
|
|
static HAWK_INLINE sql_node_t* get_sql_list_node (sql_list_t* sql_list, hawk_int_t id)
|
|
{
|
|
if (id < 0 || id >= sql_list->map.high || !sql_list->map.tab[id]) return HAWK_NULL;
|
|
return sql_list->map.tab[id];
|
|
}
|
|
|
|
static HAWK_INLINE res_list_t* rtx_to_res_list (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
hawk_rbt_pair_t* pair;
|
|
rtx_data_t* data;
|
|
pair = hawk_rbt_search((hawk_rbt_t*)fi->mod->ctx, &rtx, HAWK_SIZEOF(rtx));
|
|
HAWK_ASSERT (pair != HAWK_NULL);
|
|
data = (rtx_data_t*)HAWK_RBT_VPTR(pair);
|
|
return &data->res_list;
|
|
}
|
|
|
|
static HAWK_INLINE res_node_t* get_res_list_node (res_list_t* res_list, hawk_int_t id)
|
|
{
|
|
if (id < 0 || id >= res_list->map.high || !res_list->map.tab[id]) return HAWK_NULL;
|
|
return res_list->map.tab[id];
|
|
}
|
|
|
|
|
|
static HAWK_INLINE stmt_list_t* rtx_to_stmt_list (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
hawk_rbt_pair_t* pair;
|
|
rtx_data_t* data;
|
|
pair = hawk_rbt_search((hawk_rbt_t*)fi->mod->ctx, &rtx, HAWK_SIZEOF(rtx));
|
|
HAWK_ASSERT (pair != HAWK_NULL);
|
|
data = (rtx_data_t*)HAWK_RBT_VPTR(pair);
|
|
return &data->stmt_list;
|
|
}
|
|
|
|
static HAWK_INLINE stmt_node_t* get_stmt_list_node (stmt_list_t* stmt_list, hawk_int_t id)
|
|
{
|
|
if (id < 0 || id >= stmt_list->map.high || !stmt_list->map.tab[id]) return HAWK_NULL;
|
|
return stmt_list->map.tab[id];
|
|
}
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static void set_error_on_sql_list (hawk_rtx_t* rtx, sql_list_t* sql_list, const hawk_ooch_t* errfmt, ...)
|
|
{
|
|
if (errfmt)
|
|
{
|
|
va_list ap;
|
|
va_start (ap, errfmt);
|
|
hawk_rtx_vfmttooocstr (rtx, sql_list->errmsg, HAWK_COUNTOF(sql_list->errmsg), errfmt, ap);
|
|
va_end (ap);
|
|
}
|
|
else
|
|
{
|
|
hawk_copy_oocstr (sql_list->errmsg, HAWK_COUNTOF(sql_list->errmsg), hawk_rtx_geterrmsg(rtx));
|
|
}
|
|
}
|
|
|
|
static int fnc_errmsg (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
hawk_val_t* retv;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
retv = hawk_rtx_makestrvalwithoocstr(rtx, sql_list->errmsg);
|
|
if (!retv) return -1;
|
|
|
|
hawk_rtx_setretval (rtx, retv);
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static sql_node_t* get_sql_list_node_with_arg (hawk_rtx_t* rtx, sql_list_t* sql_list, hawk_val_t* arg)
|
|
{
|
|
hawk_int_t id;
|
|
sql_node_t* sql_node;
|
|
|
|
if (hawk_rtx_valtoint(rtx, arg, &id) <= -1)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("illegal instance id"));
|
|
return HAWK_NULL;
|
|
}
|
|
else if (!(sql_node = get_sql_list_node(sql_list, id)))
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("invalid instance id - %zd"), (hawk_oow_t)id);
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
return sql_node;
|
|
}
|
|
|
|
static res_node_t* get_res_list_node_with_arg (hawk_rtx_t* rtx, sql_list_t* sql_list, res_list_t* res_list, hawk_val_t* arg)
|
|
{
|
|
hawk_int_t id;
|
|
res_node_t* res_node;
|
|
|
|
if (hawk_rtx_valtoint(rtx, arg, &id) <= -1)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("illegal result id"));
|
|
return HAWK_NULL;
|
|
}
|
|
else if (!(res_node = get_res_list_node(res_list, id)))
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("invalid result id - %zd"), (hawk_oow_t)id);
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
return res_node;
|
|
}
|
|
|
|
static stmt_node_t* get_stmt_list_node_with_arg (hawk_rtx_t* rtx, sql_list_t* sql_list, stmt_list_t* stmt_list, hawk_val_t* arg)
|
|
{
|
|
hawk_int_t id;
|
|
stmt_node_t* stmt_node;
|
|
|
|
if (hawk_rtx_valtoint(rtx, arg, &id) <= -1)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("illegal statement id"));
|
|
return HAWK_NULL;
|
|
}
|
|
else if (!(stmt_node = get_stmt_list_node(stmt_list, id)))
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("invalid statement id - %zd"), (hawk_oow_t)id);
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
return stmt_node;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/*
|
|
BEGIN {
|
|
mysql = mysql::open();
|
|
|
|
if (mysql::connect(mysql, "localhost", "username", "password", "database") <= -1)
|
|
{
|
|
print "connect error -", mysql::errmsg();
|
|
}
|
|
|
|
mysql::escape_string(mysql, "hawk", name);
|
|
if (mysql::query(mysql, sprintf("select * from mytable where name like '%%%s%%'", name)) <= -1)
|
|
{
|
|
print "query error -", mysql::errmsg();
|
|
}
|
|
|
|
result = mysql::store_result(mysql);
|
|
if (result <= -1)
|
|
{
|
|
print "store result error - ", mysql::errmsg();
|
|
}
|
|
|
|
while (mysql::fetch_row(result, row) > 0)
|
|
{
|
|
ncols = length(row);
|
|
for (i = 0; i < ncols; i++) print row[i];
|
|
print "----";
|
|
}
|
|
|
|
mysql::free_result(result);
|
|
|
|
mysql::close(mysql);
|
|
}
|
|
|
|
BEGIN {
|
|
mysql = mysql::open();
|
|
|
|
if (mysql::connect(mysql, "localhost", "username", "password", "database") <= -1)
|
|
{
|
|
print "connect error -", mysql::errmsg();
|
|
}
|
|
|
|
stmt = mysql::stmt_init(mysql);
|
|
if (stmt <= -1)
|
|
{
|
|
print "stmt initialization error - ", mysql::errmsg();
|
|
}
|
|
|
|
if (mysql::stmt_prepare(stmt, "select name,id,location from mytable where name like ?") <= -1)
|
|
{
|
|
print "stmt preparation error - ", mysql::errmsg();
|
|
}
|
|
|
|
result = mysql::stmt_execute(stmt, mysql::TYPE_STR, "%hawk%");
|
|
if (result <= -1)
|
|
{
|
|
print "statement execution error - ", mysql::errmsg();
|
|
}
|
|
|
|
while (mysql::stmt_fetch(result, name, id, loc) > 0)
|
|
{
|
|
print "name=", name, "id=", id, "location=", loc;
|
|
}
|
|
|
|
mysql::stmt_close (stmt);
|
|
mysql::close(mysql);
|
|
}
|
|
|
|
*/
|
|
|
|
static int fnc_open (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node = HAWK_NULL;
|
|
hawk_int_t ret = -1;
|
|
hawk_val_t* retv;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
|
|
sql_node = new_sql_node(rtx, sql_list);
|
|
if (sql_node) ret = sql_node->id;
|
|
else set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
|
|
/* ret may not be a statically managed number.
|
|
* error checking is required */
|
|
retv = hawk_rtx_makeintval(rtx, ret);
|
|
if (retv == HAWK_NULL)
|
|
{
|
|
if (sql_node) free_sql_node (rtx, sql_list, sql_node);
|
|
return -1;
|
|
}
|
|
|
|
hawk_rtx_setretval (rtx, retv);
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
free_sql_node (rtx, sql_list, sql_node);
|
|
ret = 0;
|
|
}
|
|
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
static int fnc_get_option (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
hawk_int_t id, tv;
|
|
union
|
|
{
|
|
unsigned int ui;
|
|
int b;
|
|
} v;
|
|
|
|
if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 1), &id) <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto oops;
|
|
}
|
|
|
|
switch (id)
|
|
{
|
|
case MYSQL_OPT_CONNECT_TIMEOUT:
|
|
case MYSQL_OPT_READ_TIMEOUT:
|
|
case MYSQL_OPT_WRITE_TIMEOUT:
|
|
/* unsigned int * */
|
|
if (mysql_get_option(sql_node->mysql, id, &v.ui) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_errstr(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
retv = hawk_rtx_makeintval(rtx, v.ui);
|
|
if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 2), retv) <= -1)
|
|
{
|
|
hawk_rtx_refupval(rtx, retv);
|
|
hawk_rtx_refdownval(rtx, retv);
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
break;
|
|
|
|
#if defined(DUMMY_OPT_RECONNECT)
|
|
case DUMMY_OPT_RECONNECT:
|
|
/* the system without MYSQL_OPT_RECONNECT available. return 1 all the time */
|
|
if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 2), hawk_rtx_makeintval(rtx, 1)) <= -1)
|
|
{
|
|
hawk_rtx_refupval(rtx, retv);
|
|
hawk_rtx_refdownval(rtx, retv);
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
break;
|
|
#else
|
|
case MYSQL_OPT_RECONNECT:
|
|
/* bool * */
|
|
if (mysql_get_option(sql_node->mysql, id, &v.b) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_errstr(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
retv = hawk_rtx_makeintval(rtx, v.b);
|
|
if (!retv) goto oops;
|
|
|
|
if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 2), retv) <= -1)
|
|
{
|
|
hawk_rtx_refupval(rtx, retv);
|
|
hawk_rtx_refdownval(rtx, retv);
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("unsupported option id - %zd"), (hawk_oow_t)id);
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int fnc_set_option (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
hawk_int_t id, tv;
|
|
void* vptr;
|
|
union
|
|
{
|
|
unsigned int ui;
|
|
int b;
|
|
} v;
|
|
|
|
if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 1), &id) <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
/* this function must not check sql_node->connect_ever_attempted */
|
|
|
|
switch (id)
|
|
{
|
|
case MYSQL_OPT_CONNECT_TIMEOUT:
|
|
case MYSQL_OPT_READ_TIMEOUT:
|
|
case MYSQL_OPT_WRITE_TIMEOUT:
|
|
/* unsigned int * */
|
|
if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 2), &tv) <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
v.ui = tv;
|
|
vptr = &v.ui;
|
|
break;
|
|
|
|
#if defined(DUMMY_OPT_RECONNECT)
|
|
case DUMMY_OPT_RECONNECT:
|
|
ret = 0;
|
|
goto done;
|
|
#else
|
|
case MYSQL_OPT_RECONNECT:
|
|
/* bool * */
|
|
if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 2), &tv) <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
v.b = tv;
|
|
vptr = &v.b;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("unsupported option id - %zd"), (hawk_oow_t)id);
|
|
goto done;
|
|
}
|
|
|
|
if (mysql_options(sql_node->mysql, id, vptr) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_connect (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
hawk_val_t* a1, * a2, * a3, * a4, * a6;
|
|
hawk_bch_t* host = HAWK_NULL;
|
|
hawk_bch_t* user = HAWK_NULL;
|
|
hawk_bch_t* pass = HAWK_NULL;
|
|
hawk_bch_t* db = HAWK_NULL;
|
|
hawk_int_t port = 0;
|
|
hawk_bch_t* usck = HAWK_NULL;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
hawk_oow_t nargs;
|
|
|
|
nargs = hawk_rtx_getnargs(rtx);
|
|
|
|
a1 = hawk_rtx_getarg(rtx, 1);
|
|
a2 = hawk_rtx_getarg(rtx, 2);
|
|
a3 = hawk_rtx_getarg(rtx, 3);
|
|
|
|
if (!(host = hawk_rtx_getvalbcstr(rtx, a1, HAWK_NULL)) ||
|
|
!(user = hawk_rtx_getvalbcstr(rtx, a2, HAWK_NULL)) ||
|
|
!(pass = hawk_rtx_getvalbcstr(rtx, a3, HAWK_NULL)))
|
|
{
|
|
arg_fail:
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
if (nargs >= 5)
|
|
{
|
|
a4 = hawk_rtx_getarg(rtx, 4);
|
|
if (!(db = hawk_rtx_getvalbcstr(rtx, a4, HAWK_NULL))) goto arg_fail;
|
|
if (nargs >= 6 && hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 5), &port) <= -1) goto arg_fail;
|
|
|
|
if (nargs >= 7)
|
|
{
|
|
a6 = hawk_rtx_getarg(rtx, 6);
|
|
if (!(usck = hawk_rtx_getvalbcstr(rtx, a6, HAWK_NULL))) goto arg_fail;
|
|
}
|
|
}
|
|
|
|
if (!mysql_real_connect(sql_node->mysql, host, user, pass, db, port, usck, 0))
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
sql_node->connect_ever_attempted = 1; /* doesn't matter if mysql_real_connect() failed */
|
|
goto done;
|
|
}
|
|
|
|
sql_node->connect_ever_attempted = 1;
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
if (usck) hawk_rtx_freevalbcstr (rtx, a6, usck);
|
|
if (db) hawk_rtx_freevalbcstr (rtx, a4, db);
|
|
if (pass) hawk_rtx_freevalbcstr (rtx, a3, pass);
|
|
if (user) hawk_rtx_freevalbcstr (rtx, a2, user);
|
|
if (host) hawk_rtx_freevalbcstr (rtx, a1, host);
|
|
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
#define ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node) \
|
|
do { \
|
|
if (!(sql_node)->connect_ever_attempted) \
|
|
{ \
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("not connected")); \
|
|
goto done; \
|
|
} \
|
|
} while(0)
|
|
|
|
static int fnc_ping (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
if (mysql_ping(sql_node->mysql) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_select_db (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
hawk_val_t* a1;
|
|
hawk_bch_t* db = HAWK_NULL;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
a1 = hawk_rtx_getarg(rtx, 1);
|
|
|
|
if (!(db = hawk_rtx_getvalbcstr(rtx, a1, HAWK_NULL))) { take_rtx_err = 1; goto done; }
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
if (mysql_select_db(sql_node->mysql, db) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
if (db) hawk_rtx_freevalbcstr (rtx, a1, db);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int fnc_autocommit (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
int v;
|
|
|
|
v = hawk_rtx_valtobool(rtx, hawk_rtx_getarg(rtx, 1));
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
if (mysql_autocommit(sql_node->mysql, v) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_commit (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
if (mysql_commit(sql_node->mysql) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_rollback (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
if (mysql_rollback(sql_node->mysql) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_affected_rows (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
my_ulonglong nrows;
|
|
hawk_val_t* vrows;
|
|
int n;
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
nrows = mysql_affected_rows(sql_node->mysql);
|
|
if (nrows == (my_ulonglong)-1)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
vrows = hawk_rtx_makeintval(rtx, nrows);
|
|
if (!vrows)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, vrows);
|
|
n = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 1), vrows);
|
|
hawk_rtx_refdownval (rtx, vrows);
|
|
if (n <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_insert_id (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
my_ulonglong nrows;
|
|
hawk_val_t* vrows;
|
|
int n;
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
nrows = mysql_insert_id(sql_node->mysql);
|
|
if (nrows == (my_ulonglong)-1)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
vrows = hawk_rtx_makeintval(rtx, nrows);
|
|
if (!vrows)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, vrows);
|
|
n = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 1), vrows);
|
|
hawk_rtx_refdownval (rtx, vrows);
|
|
if (n <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_escape_string (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
hawk_val_t* a1, *retv;
|
|
hawk_bch_t* qstr = HAWK_NULL;
|
|
hawk_bch_t* ebuf = HAWK_NULL;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
hawk_oow_t qlen;
|
|
int n;
|
|
|
|
a1 = hawk_rtx_getarg(rtx, 1);
|
|
|
|
qstr = hawk_rtx_getvalbcstr(rtx, a1, &qlen);
|
|
if (!qstr) { take_rtx_err = 1; goto done; }
|
|
|
|
ebuf = hawk_rtx_allocmem(rtx, (qlen * 2 + 1) * HAWK_SIZEOF(*qstr));
|
|
if (!ebuf) { take_rtx_err = 1; goto done; }
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
mysql_real_escape_string(sql_node->mysql, ebuf, qstr, qlen);
|
|
|
|
retv = hawk_rtx_makestrvalwithbcstr(rtx, ebuf);
|
|
if (!retv)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, retv);
|
|
n = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 2), retv);
|
|
hawk_rtx_refdownval (rtx, retv);
|
|
if (n <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
if (ebuf) hawk_rtx_freemem (rtx, ebuf);
|
|
if (qstr) hawk_rtx_freevalbcstr (rtx, a1, qstr);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_query (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
hawk_val_t* a1;
|
|
hawk_bch_t* qstr = HAWK_NULL;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
hawk_oow_t qlen;
|
|
a1 = hawk_rtx_getarg(rtx, 1);
|
|
|
|
qstr = hawk_rtx_getvalbcstr(rtx, a1, &qlen);
|
|
if (!qstr) { take_rtx_err = 1; goto done; }
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
if (mysql_real_query(sql_node->mysql, qstr, qlen) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
if (qstr) hawk_rtx_freevalbcstr (rtx, a1, qstr);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_store_result (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_node)
|
|
{
|
|
res_list_t* res_list;
|
|
res_node_t* res_node;
|
|
MYSQL_RES* res;
|
|
|
|
res_list = rtx_to_res_list(rtx, fi);
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
res = mysql_store_result(sql_node->mysql);
|
|
if (!res)
|
|
{
|
|
if (mysql_errno(sql_node->mysql) == 0)
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("no result"));
|
|
else
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
res_node = new_res_node(rtx, res_list, res);
|
|
if (!res_node)
|
|
{
|
|
mysql_free_result (res);
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = res_node->id;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_free_result (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
res_list_t* res_list;
|
|
res_node_t* res_node;
|
|
int ret = -1;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
res_list = rtx_to_res_list(rtx, fi);
|
|
res_node = get_res_list_node_with_arg(rtx, sql_list, res_list, hawk_rtx_getarg(rtx, 0));
|
|
if (res_node)
|
|
{
|
|
free_res_node (rtx, res_list, res_node);
|
|
ret = 0;
|
|
}
|
|
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_fetch_row (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
res_list_t* res_list;
|
|
res_node_t* res_node;
|
|
int ret = -1, take_rtx_err = 0;
|
|
hawk_val_t* row_map = HAWK_NULL;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
res_list = rtx_to_res_list(rtx, fi);
|
|
res_node = get_res_list_node_with_arg(rtx, sql_list, res_list, hawk_rtx_getarg(rtx, 0));
|
|
if (res_node)
|
|
{
|
|
MYSQL_ROW row;
|
|
unsigned int i;
|
|
hawk_val_t* row_val, * tmp;
|
|
int x;
|
|
|
|
row = mysql_fetch_row(res_node->res);
|
|
if (!row)
|
|
{
|
|
/* no more row in the result */
|
|
ret = 0;
|
|
goto done;
|
|
}
|
|
|
|
row_map = hawk_rtx_makemapval(rtx);
|
|
if (!row_map)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, row_map);
|
|
|
|
for (i = 0; i < res_node->num_fields; )
|
|
{
|
|
hawk_ooch_t key_buf[HAWK_SIZEOF(hawk_int_t) * 8 + 2];
|
|
hawk_oow_t key_len;
|
|
|
|
if (row[i])
|
|
{
|
|
/* TODO: consider using make multi byte string - hawk_rtx_makembsstr depending on user options or depending on column types */
|
|
row_val = hawk_rtx_makestrvalwithbcstr(rtx, row[i]);
|
|
if (!row_val)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
row_val = hawk_rtx_makenilval(rtx);
|
|
}
|
|
|
|
++i;
|
|
|
|
/* put it into the map */
|
|
key_len = hawk_int_to_oocstr(i, 10, HAWK_NULL, key_buf, HAWK_COUNTOF(key_buf)); /* TOOD: change this function to hawk_rtx_intxxxxx */
|
|
HAWK_ASSERT (key_len != (hawk_oow_t)-1);
|
|
|
|
hawk_rtx_refupval (rtx, row_val);
|
|
tmp = hawk_rtx_setmapvalfld(rtx, row_map, key_buf, key_len, row_val);
|
|
hawk_rtx_refdownval (rtx, row_val);
|
|
if (!tmp)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
x = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 1), row_map);
|
|
|
|
hawk_rtx_refdownval (rtx, row_map);
|
|
row_map = HAWK_NULL;
|
|
|
|
if (x <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = 1; /* indicate that there is a row */
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
if (row_map) hawk_rtx_refdownval (rtx, row_map);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
static int fnc_stmt_init (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
sql_node_t* sql_node;
|
|
|
|
int ret = -1;
|
|
int take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
sql_node = get_sql_list_node_with_arg(rtx, sql_list, hawk_rtx_getarg(rtx, 0));
|
|
if (sql_list)
|
|
{
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
MYSQL_STMT* stmt;
|
|
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
|
|
ENSURE_CONNECT_EVER_ATTEMPTED(rtx, sql_list, sql_node);
|
|
|
|
stmt = mysql_stmt_init(sql_node->mysql);
|
|
if (!stmt)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_error(sql_node->mysql));
|
|
goto done;
|
|
}
|
|
|
|
stmt_node = new_stmt_node(rtx, stmt_list, stmt);
|
|
if (!stmt_node)
|
|
{
|
|
mysql_stmt_close (stmt);
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = stmt_node->id;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_stmt_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
int ret = -1;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
stmt_node = get_stmt_list_node_with_arg(rtx, sql_list, stmt_list, hawk_rtx_getarg(rtx, 0));
|
|
if (stmt_node)
|
|
{
|
|
if (stmt_node->res_data)
|
|
{
|
|
if (stmt_node->res_binds)
|
|
{
|
|
/* the program guarantees thats res_binds is non-null if res_data is to have
|
|
* some valid data. so i do this clearance if res_binds is non-null */
|
|
hawk_oow_t i;
|
|
for (i = 0; i < stmt_node->res_capa; i++)
|
|
{
|
|
res_data_t* data = &stmt_node->res_data[i];
|
|
MYSQL_BIND* bind = &stmt_node->res_binds[i];
|
|
if ((bind->buffer_type == MYSQL_TYPE_STRING || bind->buffer_type == MYSQL_TYPE_BLOB) && data->u.sv.ptr)
|
|
{
|
|
hawk_rtx_freemem (rtx, data->u.sv.ptr);
|
|
data->u.sv.ptr = HAWK_NULL;
|
|
data->u.sv.len = 0;
|
|
}
|
|
}
|
|
}
|
|
hawk_rtx_freemem (rtx, stmt_node->res_data);
|
|
}
|
|
if (stmt_node->res_binds) hawk_rtx_freemem (rtx, stmt_node->res_binds);
|
|
|
|
|
|
if (stmt_node->param_data)
|
|
{
|
|
if (stmt_node->param_binds)
|
|
{
|
|
/* the program guarantees thats param_binds is non-null if param_data is to have
|
|
* some valid data. so i do this clearance if param_binds is non-null */
|
|
hawk_oow_t i;
|
|
for (i = 0; i < stmt_node->param_capa; i++)
|
|
{
|
|
param_data_t* data = &stmt_node->param_data[i];
|
|
MYSQL_BIND* bind = &stmt_node->param_binds[i];
|
|
if ((bind->buffer_type == MYSQL_TYPE_STRING || bind->buffer_type == MYSQL_TYPE_BLOB) && data->u.sv.ptr)
|
|
{
|
|
hawk_rtx_freemem (rtx, data->u.sv.ptr);
|
|
data->u.sv.ptr = HAWK_NULL;
|
|
data->u.sv.len = 0;
|
|
}
|
|
}
|
|
}
|
|
hawk_rtx_freemem (rtx, stmt_node->param_data);
|
|
}
|
|
if (stmt_node->param_binds) hawk_rtx_freemem (rtx, stmt_node->param_binds);
|
|
|
|
|
|
free_stmt_node (rtx, stmt_list, stmt_node);
|
|
ret = 0;
|
|
}
|
|
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_stmt_prepare (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
int ret = -1;
|
|
int take_rtx_err = 0;
|
|
hawk_val_t* a1;
|
|
hawk_bch_t* qstr = HAWK_NULL;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
stmt_node = get_stmt_list_node_with_arg(rtx, sql_list, stmt_list, hawk_rtx_getarg(rtx, 0));
|
|
if (stmt_node)
|
|
{
|
|
hawk_oow_t qlen;
|
|
|
|
a1 = hawk_rtx_getarg(rtx, 1);
|
|
|
|
qstr = hawk_rtx_getvalbcstr(rtx, a1, &qlen);
|
|
if (!qstr) { take_rtx_err = 1; goto done; }
|
|
|
|
if (mysql_stmt_prepare(stmt_node->stmt, qstr, qlen) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_stmt_error(stmt_node->stmt));
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
if (qstr) hawk_rtx_freevalbcstr (rtx, a1, qstr);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_stmt_execute (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
int ret = -1;
|
|
int take_rtx_err = 0;
|
|
MYSQL_RES* res_meta = HAWK_NULL;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
stmt_node = get_stmt_list_node_with_arg(rtx, sql_list, stmt_list, hawk_rtx_getarg(rtx, 0));
|
|
if (stmt_node)
|
|
{
|
|
hawk_oow_t nargs, nparams, i;
|
|
hawk_oow_t param_count;
|
|
|
|
nargs = hawk_rtx_getnargs(rtx);
|
|
nparams = (nargs - 1) / 2;
|
|
param_count = mysql_stmt_param_count(stmt_node->stmt);
|
|
if (nparams != param_count)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("invalid number of paramaters"));
|
|
goto done;
|
|
}
|
|
|
|
for (i = 0; i < stmt_node->param_capa; i++)
|
|
{
|
|
MYSQL_BIND* bind;
|
|
param_data_t* data;
|
|
|
|
bind = &stmt_node->param_binds[i];
|
|
data = &stmt_node->param_data[i];
|
|
|
|
if ((bind->buffer_type == MYSQL_TYPE_STRING || bind->buffer_type == MYSQL_TYPE_BLOB) && data->u.sv.ptr)
|
|
{
|
|
hawk_rtx_freemem (rtx, data->u.sv.ptr);
|
|
data->u.sv.ptr = HAWK_NULL;
|
|
data->u.sv.len = 0;
|
|
}
|
|
}
|
|
|
|
if (nparams > stmt_node->param_capa)
|
|
{
|
|
MYSQL_BIND* binds;
|
|
param_data_t* data;
|
|
|
|
binds = hawk_rtx_reallocmem(rtx, stmt_node->param_binds, HAWK_SIZEOF(MYSQL_BIND) * nparams);
|
|
if (!binds) { take_rtx_err = 1; goto done; }
|
|
stmt_node->param_binds = binds;
|
|
|
|
data = hawk_rtx_reallocmem(rtx, stmt_node->param_data, HAWK_SIZEOF(param_data_t) * nparams);
|
|
if (!data) { take_rtx_err = 1; goto done; }
|
|
stmt_node->param_data = data;
|
|
|
|
/* update the capacity only if both (re)allocations gets successful */
|
|
stmt_node->param_capa = nparams;
|
|
}
|
|
|
|
HAWK_MEMSET (stmt_node->param_binds, 0, HAWK_SIZEOF(MYSQL_BIND)* stmt_node->param_capa);
|
|
HAWK_MEMSET (stmt_node->param_data, 0, HAWK_SIZEOF(param_data_t)* stmt_node->param_capa);
|
|
|
|
for (i = 1; i < nargs; i += 2)
|
|
{
|
|
hawk_val_t* ta, * va;
|
|
hawk_oow_t j;
|
|
hawk_int_t type;
|
|
MYSQL_BIND* bind;
|
|
param_data_t* data;
|
|
|
|
ta = hawk_rtx_getarg(rtx, i);
|
|
va = hawk_rtx_getarg(rtx, i + 1);
|
|
j = (i >> 1);
|
|
|
|
if (hawk_rtx_valtoint(rtx, ta, &type) <= -1) { take_rtx_err = 1; goto done; }
|
|
|
|
bind = &stmt_node->param_binds[j];
|
|
data = &stmt_node->param_data[j];
|
|
|
|
switch (type)
|
|
{
|
|
case MYSQL_TYPE_LONG:
|
|
{
|
|
hawk_int_t iv;
|
|
|
|
if (hawk_rtx_valtoint(rtx, va, &iv) <= -1) { take_rtx_err = 1; goto done; }
|
|
data->u.llv = iv;
|
|
data->is_null = hawk_rtx_isnilval(rtx, va);
|
|
|
|
bind->buffer_type = MYSQL_TYPE_LONGLONG;
|
|
bind->buffer = &data->u.llv;
|
|
bind->is_null = &data->is_null;
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
{
|
|
hawk_flt_t fv;
|
|
|
|
if (hawk_rtx_valtoflt(rtx, va, &fv) <= -1) { take_rtx_err = 1; goto done; }
|
|
data->u.dv = fv;
|
|
data->is_null = hawk_rtx_isnilval(rtx, va);
|
|
|
|
bind->buffer_type = MYSQL_TYPE_DOUBLE;
|
|
bind->buffer = &data->u.dv;
|
|
bind->is_null = &data->is_null;
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
case MYSQL_TYPE_BLOB:
|
|
{
|
|
hawk_bch_t* ptr;
|
|
hawk_oow_t len;
|
|
|
|
ptr = hawk_rtx_valtobcstrdup(rtx, va, &len);
|
|
if (!ptr) { take_rtx_err = 1; goto done; }
|
|
|
|
data->u.sv.ptr = ptr;
|
|
data->u.sv.len = len;
|
|
data->is_null = hawk_rtx_isnilval(rtx, va);
|
|
|
|
bind->buffer_type = type;
|
|
bind->buffer = data->u.sv.ptr;
|
|
bind->length = &data->u.sv.len;
|
|
bind->is_null = &data->is_null;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("invalid value type"));
|
|
goto done;
|
|
}
|
|
|
|
}
|
|
|
|
if (mysql_stmt_bind_param(stmt_node->stmt, stmt_node->param_binds) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_stmt_error(stmt_node->stmt));
|
|
goto done;
|
|
}
|
|
|
|
if (mysql_stmt_execute(stmt_node->stmt) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_stmt_error(stmt_node->stmt));
|
|
goto done;
|
|
}
|
|
|
|
res_meta = mysql_stmt_result_metadata(stmt_node->stmt);
|
|
if (res_meta)
|
|
{
|
|
/* the statement will return results */
|
|
unsigned int ncols;
|
|
MYSQL_FIELD* cinfo;
|
|
|
|
MYSQL_BIND* bind;
|
|
res_data_t* data;
|
|
|
|
ncols = mysql_num_fields(res_meta);
|
|
cinfo = mysql_fetch_fields(res_meta);
|
|
|
|
for (i = 0; i < stmt_node->res_capa; i++)
|
|
{
|
|
MYSQL_BIND* bind;
|
|
res_data_t* data;
|
|
|
|
bind = &stmt_node->res_binds[i];
|
|
data = &stmt_node->res_data[i];
|
|
|
|
if ((bind->buffer_type == MYSQL_TYPE_STRING || bind->buffer_type == MYSQL_TYPE_BLOB) && data->u.sv.ptr)
|
|
{
|
|
hawk_rtx_freemem (rtx, data->u.sv.ptr);
|
|
data->u.sv.ptr = HAWK_NULL;
|
|
data->u.sv.len = 0;
|
|
}
|
|
}
|
|
|
|
if (ncols > stmt_node->res_capa)
|
|
{
|
|
MYSQL_BIND* binds;
|
|
res_data_t* data;
|
|
|
|
binds = hawk_rtx_reallocmem(rtx, stmt_node->res_binds, HAWK_SIZEOF(MYSQL_BIND) * ncols);
|
|
if (!binds) { take_rtx_err = 1; goto done; }
|
|
stmt_node->res_binds = binds;
|
|
|
|
data = hawk_rtx_reallocmem(rtx, stmt_node->res_data, HAWK_SIZEOF(res_data_t) * ncols);
|
|
if (!data) { take_rtx_err = 1; goto done; }
|
|
stmt_node->res_data = data;
|
|
|
|
/* update the capacity only if both (re)allocations gets successful */
|
|
stmt_node->res_capa = ncols;
|
|
}
|
|
|
|
HAWK_MEMSET (stmt_node->res_binds, 0, HAWK_SIZEOF(MYSQL_BIND)* stmt_node->res_capa);
|
|
HAWK_MEMSET (stmt_node->res_data, 0, HAWK_SIZEOF(res_data_t)* stmt_node->res_capa);
|
|
|
|
|
|
for (i = 0; i < ncols; i++)
|
|
{
|
|
/* TOOD: more types... */
|
|
bind = &stmt_node->res_binds[i];
|
|
data = &stmt_node->res_data[i];
|
|
|
|
switch(cinfo[i].type)
|
|
{
|
|
case MYSQL_TYPE_LONGLONG:
|
|
case MYSQL_TYPE_LONG:
|
|
case MYSQL_TYPE_SHORT:
|
|
case MYSQL_TYPE_TINY:
|
|
#if (MYSQL_VERSION_ID >= 50000)
|
|
case MYSQL_TYPE_BIT:
|
|
#endif
|
|
case MYSQL_TYPE_INT24:
|
|
bind->buffer_type = MYSQL_TYPE_LONGLONG;
|
|
bind->buffer = &data->u.llv;
|
|
break;
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
case MYSQL_TYPE_DOUBLE:
|
|
bind->buffer_type = MYSQL_TYPE_DOUBLE;
|
|
bind->buffer = &data->u.dv;
|
|
break;
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
#if (MYSQL_VERSION_ID >= 50000)
|
|
case MYSQL_TYPE_VARCHAR:
|
|
#endif
|
|
case MYSQL_TYPE_VAR_STRING:
|
|
bind->buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
res_string:
|
|
data->u.sv.ptr = hawk_rtx_allocmem(rtx, cinfo[i].length + 1);
|
|
if (!data->u.sv.ptr) { take_rtx_err = 1; goto done; }
|
|
data->u.sv.len = 0;
|
|
|
|
bind->buffer = data->u.sv.ptr;
|
|
bind->buffer_length = cinfo[i].length + 1;
|
|
bind->length = &data->u.sv.len;
|
|
break;
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
case MYSQL_TYPE_TINY_BLOB:
|
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
|
case MYSQL_TYPE_LONG_BLOB:
|
|
default: /* TOOD: i must not do this.... treat others properly */
|
|
bind->buffer_type = MYSQL_TYPE_BLOB;
|
|
goto res_string;
|
|
}
|
|
|
|
bind->is_null = &data->is_null;
|
|
}
|
|
|
|
if (mysql_stmt_bind_result(stmt_node->stmt, stmt_node->res_binds) != 0)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("%hs"), mysql_stmt_error(stmt_node->stmt));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (res_meta) mysql_free_result (res_meta);
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
static int fnc_stmt_fetch (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
int ret = -1;
|
|
int take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
stmt_node = get_stmt_list_node_with_arg(rtx, sql_list, stmt_list, hawk_rtx_getarg(rtx, 0));
|
|
if (stmt_node)
|
|
{
|
|
int n;
|
|
|
|
n = mysql_stmt_fetch(stmt_node->stmt);
|
|
if (n == MYSQL_NO_DATA) ret = 0; /* no more data */
|
|
else if (n == 0)
|
|
{
|
|
hawk_oow_t i, j, nargs;
|
|
MYSQL_BIND* bind;
|
|
res_data_t* data;
|
|
/* there is data */
|
|
|
|
nargs = hawk_rtx_getnargs(rtx);
|
|
/* TODO: argument count check */
|
|
|
|
for (i = 1; i < nargs; i++)
|
|
{
|
|
hawk_val_t* cv;
|
|
|
|
j = i - 1;
|
|
bind = &stmt_node->res_binds[j];
|
|
data = &stmt_node->res_data[j];
|
|
|
|
if (data->is_null) cv = hawk_rtx_makenilval(rtx);
|
|
else
|
|
{
|
|
switch (bind->buffer_type)
|
|
{
|
|
case MYSQL_TYPE_LONGLONG:
|
|
cv = hawk_rtx_makeintval(rtx, data->u.llv);
|
|
break;
|
|
case MYSQL_TYPE_DOUBLE:
|
|
cv = hawk_rtx_makefltval(rtx, data->u.dv);
|
|
break;
|
|
case MYSQL_TYPE_STRING:
|
|
cv = hawk_rtx_makestrvalwithbchars(rtx, data->u.sv.ptr, data->u.sv.len);
|
|
break;
|
|
case MYSQL_TYPE_BLOB:
|
|
cv = hawk_rtx_makembsvalwithbchars(rtx, data->u.sv.ptr, data->u.sv.len);
|
|
break;
|
|
|
|
default:
|
|
/* this must not happen */
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("internal error - invalid buffer_type %d"), (int)bind->buffer_type);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (!cv || hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, i), cv) <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
ret = 1; /* have data */
|
|
}
|
|
#if (MYSQL_VERSION_ID >= 50000)
|
|
else if (n == MYSQL_DATA_TRUNCATED)
|
|
{
|
|
set_error_on_sql_list (rtx, sql_list, HAWK_T("data truncated"));
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int fnc_stmt_affected_rows (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
int ret = -1;
|
|
int take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
stmt_node = get_stmt_list_node_with_arg(rtx, sql_list, stmt_list, hawk_rtx_getarg(rtx, 0));
|
|
if (stmt_node)
|
|
{
|
|
my_ulonglong nrows;
|
|
hawk_val_t* vrows;
|
|
int n;
|
|
|
|
nrows = mysql_stmt_affected_rows(stmt_node->stmt);
|
|
|
|
vrows = hawk_rtx_makeintval(rtx, nrows);
|
|
if (!vrows)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, vrows);
|
|
n = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 1), vrows);
|
|
hawk_rtx_refdownval (rtx, vrows);
|
|
if (n <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int fnc_stmt_insert_id (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
sql_list_t* sql_list;
|
|
stmt_list_t* stmt_list;
|
|
stmt_node_t* stmt_node;
|
|
int ret = -1;
|
|
int take_rtx_err = 0;
|
|
|
|
sql_list = rtx_to_sql_list(rtx, fi);
|
|
stmt_list = rtx_to_stmt_list(rtx, fi);
|
|
stmt_node = get_stmt_list_node_with_arg(rtx, sql_list, stmt_list, hawk_rtx_getarg(rtx, 0));
|
|
if (stmt_node)
|
|
{
|
|
my_ulonglong nrows;
|
|
hawk_val_t* vrows;
|
|
int n;
|
|
|
|
nrows = mysql_stmt_insert_id(stmt_node->stmt);
|
|
|
|
vrows = hawk_rtx_makeintval(rtx, nrows);
|
|
if (!vrows)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, vrows);
|
|
n = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 1), vrows);
|
|
hawk_rtx_refdownval (rtx, vrows);
|
|
if (n <= -1)
|
|
{
|
|
take_rtx_err = 1;
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
if (take_rtx_err) set_error_on_sql_list (rtx, sql_list, HAWK_NULL);
|
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
|
|
return 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
#define A_MAX HAWK_TYPE_MAX(int)
|
|
|
|
static hawk_mod_fnc_tab_t fnctab[] =
|
|
{
|
|
/* keep this table sorted for binary search in query(). */
|
|
{ HAWK_T("affected_rows"), { { 2, 2, HAWK_T("vr") }, fnc_affected_rows, 0 } },
|
|
{ HAWK_T("autocommit"), { { 2, 2, HAWK_NULL }, fnc_autocommit, 0 } },
|
|
{ HAWK_T("close"), { { 1, 1, HAWK_NULL }, fnc_close, 0 } },
|
|
{ HAWK_T("commit"), { { 1, 1, HAWK_NULL }, fnc_commit, 0 } },
|
|
{ HAWK_T("connect"), { { 4, 7, HAWK_NULL }, fnc_connect, 0 } },
|
|
{ HAWK_T("errmsg"), { { 0, 0, HAWK_NULL }, fnc_errmsg, 0 } },
|
|
{ HAWK_T("escape_string"), { { 3, 3, HAWK_T("vvr") }, fnc_escape_string, 0 } },
|
|
{ HAWK_T("fetch_row"), { { 2, 2, HAWK_T("vr") }, fnc_fetch_row, 0 } },
|
|
{ HAWK_T("free_result"), { { 1, 1, HAWK_NULL }, fnc_free_result, 0 } },
|
|
/*{ HAWK_T("get_option"), { { 3, 3, HAWK_T("vr") }, fnc_get_option, 0 } },*/
|
|
{ HAWK_T("insert_id"), { { 2, 2, HAWK_T("vr") }, fnc_insert_id, 0 } },
|
|
{ HAWK_T("open"), { { 0, 0, HAWK_NULL }, fnc_open, 0 } },
|
|
{ HAWK_T("ping"), { { 1, 1, HAWK_NULL }, fnc_ping, 0 } },
|
|
{ HAWK_T("query"), { { 2, 2, HAWK_NULL }, fnc_query, 0 } },
|
|
{ HAWK_T("rollback"), { { 1, 1, HAWK_NULL }, fnc_rollback, 0 } },
|
|
{ HAWK_T("select_db"), { { 2, 2, HAWK_NULL }, fnc_select_db, 0 } },
|
|
{ HAWK_T("set_option"), { { 3, 3, HAWK_NULL }, fnc_set_option, 0 } },
|
|
|
|
{ HAWK_T("stmt_affected_rows"), { { 2, 2, HAWK_T("vr") }, fnc_stmt_affected_rows, 0 } },
|
|
{ HAWK_T("stmt_close"), { { 1, 1, HAWK_NULL }, fnc_stmt_close, 0 } },
|
|
{ HAWK_T("stmt_execute"), { { 1, A_MAX, HAWK_NULL }, fnc_stmt_execute, 0 } },
|
|
{ HAWK_T("stmt_fetch"), { { 2, A_MAX, HAWK_T("vr") }, fnc_stmt_fetch, 0 } },
|
|
{ HAWK_T("stmt_init"), { { 1, 1, HAWK_NULL }, fnc_stmt_init, 0 } },
|
|
{ HAWK_T("stmt_insert_id"), { { 2, 2, HAWK_T("vr") }, fnc_stmt_insert_id, 0 } },
|
|
{ HAWK_T("stmt_prepare"), { { 2, 2, HAWK_NULL }, fnc_stmt_prepare, 0 } },
|
|
|
|
{ HAWK_T("store_result"), { { 1, 1, HAWK_NULL }, fnc_store_result, 0 } }
|
|
};
|
|
|
|
static hawk_mod_int_tab_t inttab[] =
|
|
{
|
|
/* keep this table sorted for binary search in query(). */
|
|
{ HAWK_T("OPT_CONNECT_TIMEOUT"), { MYSQL_OPT_CONNECT_TIMEOUT } },
|
|
{ HAWK_T("OPT_READ_TIMEOUT"), { MYSQL_OPT_READ_TIMEOUT } },
|
|
#if defined(DUMMY_OPT_RECONNECT)
|
|
{ HAWK_T("OPT_RECONNECT"), { DUMMY_OPT_RECONNECT } },
|
|
#else
|
|
{ HAWK_T("OPT_RECONNECT"), { MYSQL_OPT_RECONNECT } },
|
|
#endif
|
|
{ HAWK_T("OPT_WRITE_TIMEOUT"), { MYSQL_OPT_WRITE_TIMEOUT } },
|
|
|
|
{ HAWK_T("TYPE_BIN"), { MYSQL_TYPE_BLOB } },
|
|
{ HAWK_T("TYPE_FLT"), { MYSQL_TYPE_FLOAT } },
|
|
{ HAWK_T("TYPE_INT"), { MYSQL_TYPE_LONG } },
|
|
{ HAWK_T("TYPE_STR"), { MYSQL_TYPE_STRING } }
|
|
};
|
|
|
|
static int query (hawk_mod_t* mod, hawk_t* hawk, const hawk_ooch_t* name, hawk_mod_sym_t* sym)
|
|
{
|
|
if (hawk_findmodsymfnc_noseterr(hawk, fnctab, HAWK_COUNTOF(fnctab), name, sym) >= 0) return 0;
|
|
return hawk_findmodsymint(hawk, inttab, HAWK_COUNTOF(inttab), name, sym);
|
|
}
|
|
|
|
static int init (hawk_mod_t* mod, hawk_rtx_t* rtx)
|
|
{
|
|
hawk_rbt_t* rbt;
|
|
rtx_data_t data, * datap;
|
|
hawk_rbt_pair_t* pair;
|
|
|
|
rbt = (hawk_rbt_t*)mod->ctx;
|
|
|
|
HAWK_MEMSET (&data, 0, HAWK_SIZEOF(data));
|
|
pair = hawk_rbt_insert(rbt, &rtx, HAWK_SIZEOF(rtx), &data, HAWK_SIZEOF(data));
|
|
if (HAWK_UNLIKELY(!pair)) return -1;
|
|
|
|
datap = (rtx_data_t*)HAWK_RBT_VPTR(pair);
|
|
__init_sql_list (rtx, &datap->sql_list);
|
|
__init_res_list (rtx, &datap->res_list);
|
|
__init_stmt_list (rtx, &datap->stmt_list);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void fini (hawk_mod_t* mod, hawk_rtx_t* rtx)
|
|
{
|
|
hawk_rbt_t* rbt;
|
|
hawk_rbt_pair_t* pair;
|
|
|
|
rbt = (hawk_rbt_t*)mod->ctx;
|
|
|
|
/* garbage clean-up */
|
|
pair = hawk_rbt_search(rbt, &rtx, HAWK_SIZEOF(rtx));
|
|
if (pair)
|
|
{
|
|
rtx_data_t* data;
|
|
|
|
data = (rtx_data_t*)HAWK_RBT_VPTR(pair);
|
|
|
|
__fini_stmt_list (rtx, &data->stmt_list);
|
|
__fini_res_list (rtx, &data->res_list);
|
|
__fini_sql_list (rtx, &data->sql_list);
|
|
|
|
hawk_rbt_delete (rbt, &rtx, HAWK_SIZEOF(rtx));
|
|
}
|
|
}
|
|
|
|
static void unload (hawk_mod_t* mod, hawk_t* hawk)
|
|
{
|
|
hawk_rbt_t* rbt;
|
|
|
|
rbt = (hawk_rbt_t*)mod->ctx;
|
|
|
|
HAWK_ASSERT (HAWK_RBT_SIZE(rbt) == 0);
|
|
hawk_rbt_close (rbt);
|
|
/*mysql_library_end ();*/
|
|
}
|
|
|
|
int hawk_mod_mysql (hawk_mod_t* mod, hawk_t* hawk)
|
|
{
|
|
hawk_rbt_t* rbt;
|
|
|
|
mod->query = query;
|
|
mod->unload = unload;
|
|
|
|
mod->init = init;
|
|
mod->fini = fini;
|
|
|
|
rbt = hawk_rbt_open(hawk_getgem(hawk), 0, 1, 1);
|
|
if (HAWK_UNLIKELY(!rbt)) return -1;
|
|
|
|
hawk_rbt_setstyle (rbt, hawk_get_rbt_style(HAWK_RBT_STYLE_INLINE_COPIERS));
|
|
|
|
mod->ctx = rbt;
|
|
return 0;
|
|
}
|
|
|
|
HAWK_EXPORT int hawk_mod_mysql_init (int argc, char* argv[])
|
|
{
|
|
if (mysql_library_init(argc, argv, HAWK_NULL) != 0) return -1;
|
|
return 0;
|
|
}
|
|
|
|
HAWK_EXPORT void hawk_mod_mysql_fini (void)
|
|
{
|
|
mysql_library_end ();
|
|
}
|