1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00

Added support for embedded (sqlite)

This commit is contained in:
Georg Richter
2013-01-30 08:37:24 +01:00
parent 65b256cd1f
commit 84aea9721c
26 changed files with 146316 additions and 138 deletions

View File

@@ -18,8 +18,11 @@ ENDIF()
IF(NOT WIN32)
OPTION(WITH_MYSQLCOMPAT "creates libmysql* symbolic links" ON)
ENDIF()
OPTION(WITH_SQLITE "Enables Sqlite support" ON)
###############
IF(WIN32)
# Speedup system tests
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/WindowsCache.cmake)
@@ -47,8 +50,8 @@ IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Relwithdebinfo")
ENDIF()
# various defines for generating include/mysql_version.h
SET(PROTOCOL_VERSION 10) # we adapted new password option from PHP's mysqlnd !
SET(MYSQL_CLIENT_VERSION_MAJOR "5")
SET(MYSQL_CLIENT_VERSION_MINOR "3")
@@ -67,6 +70,7 @@ ENDIF()
# todo: we don't character sets in share - all is compiled in
SET(SHAREDIR "share")
SET(DEFAULT_CHARSET_HOME "${CMAKE_INSTALL_PREFIX}")
SET(PLUGINDIR "${CMAKE_INSTALL_PREFIX}/lib/plugin")
FIND_PACKAGE(Threads)
@@ -105,6 +109,10 @@ ENDIF()
FIND_PACKAGE(ZLIB QUIET)
IF(WITH_SQLITE)
ADD_DEFINITIONS(-DHAVE_SQLITE)
ENDIF()
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/include/mysql_version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/mysql_version.h)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/include/my_config.h.in
@@ -112,6 +120,7 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/include/my_config.h.in
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include)
ADD_SUBDIRECTORY(plugins)
ADD_SUBDIRECTORY(libmariadb)
ADD_SUBDIRECTORY(examples)
IF(NOT WIN32)

View File

@@ -71,5 +71,6 @@ extern const char *client_errors[]; /* Error messages */
#define CR_NEW_STMT_METADATA 2057
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2058
#define CR_ALREADY_CONNECTED 2059
#define CR_PLUGIN_FUNCTION_NOT_SUPPORTED 2060
#define SQLSTATE_UNKNOWN "HY000"

View File

@@ -137,6 +137,7 @@
#cmakedefine HAVE_SIGWAIT 1
#cmakedefine HAVE_SLEEP 1
#cmakedefine HAVE_SNPRINTF 1
#cmakedefine HAVE_SQLITE 1
#cmakedefine HAVE_STPCPY 1
#cmakedefine HAVE_STRERROR 1
#cmakedefine HAVE_STRLCPY 1
@@ -275,3 +276,4 @@
#cmakedefine HAVE_THREADS 1
#cmakedefine SHAREDIR "@SHAREDIR@"
#cmakedefine DEFAULT_CHARSET_HOME "@DEFAULT_CHARSET_HOME@"
#cmakedefine PLUGINDIR "@PLUGINDIR@"

View File

@@ -198,7 +198,7 @@ struct st_mysql_stmt
my_bool cursor_exists;
MYSQL_CMD_BUFFER cmd_buffer;
void *ext_stmt;
mysql_stmt_fetch_row_func fetch_row_func;
unsigned int execute_count;/* count how many times the stmt was executed */
mysql_stmt_use_or_store_func default_rset_handler;
@@ -217,7 +217,6 @@ extern struct st_mysql_perm_bind mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY +
unsigned long net_safe_read(MYSQL *mysql);
void mysql_init_ps_subsystem(void);
unsigned long net_field_length(unsigned char **packet);
int simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check);
/*
* function prototypes
*/

View File

@@ -184,7 +184,8 @@ enum mysql_option
MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
MYSQL_PLUGIN_DIR,
MYSQL_DEFAULT_AUTH,
MYSQL_PROGRESS_CALLBACK
MYSQL_PROGRESS_CALLBACK,
MYSQL_DATABASE_DRIVER=255
};
enum mysql_status { MYSQL_STATUS_READY,
@@ -233,14 +234,21 @@ struct st_mysql_options {
struct st_mysql_options_extention *extension;
};
typedef struct st_mariadb_db_driver
{
struct st_mariadb_client_plugin_DB *plugin;
char *name;
void *buffer;
} MARIADB_DB_DRIVER;
typedef struct st_mysql {
NET net; /* Communication parameters */
unsigned char *unused;
char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
char *info,*db;
void *unused_0;
char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
char *info,*db;
const struct charset_info_st *charset; /* character set */
MYSQL_FIELD *fields;
MEM_ROOT field_alloc;
MYSQL_FIELD *fields;
MEM_ROOT field_alloc;
my_ulonglong affected_rows;
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
my_ulonglong extra_info; /* Used by mysqlshow */
@@ -283,6 +291,7 @@ struct st_mysql_options_extention {
double progress,
const char *proc_info,
unsigned int proc_info_length);
MARIADB_DB_DRIVER *db_driver;
};
typedef struct st_mysql_res {
@@ -306,6 +315,7 @@ enum enum_mysql_timestamp_type
MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2
};
typedef struct st_mysql_time
{
unsigned int year, month, day, hour, minute, second;
@@ -449,7 +459,30 @@ const char * STDCALL mysql_get_server_name(MYSQL *mysql);
#include <my_stmt.h>
/* synonyms, alternate functions */
/* these methods can be overwritten by db plugins */
struct st_mysql_methods {
MYSQL *(*db_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd,
const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag);
void (*db_close)(MYSQL *mysql);
int (*db_command)(MYSQL *mysql,enum enum_server_command command, const char *arg,
size_t length, my_bool skipp_check, void *opt_arg);
void (*db_skip_result)(MYSQL *mysql);
int (*db_read_query_result)(MYSQL *mysql);
MYSQL_DATA *(*db_read_rows)(MYSQL *mysql,MYSQL_FIELD *fields, unsigned int field_count);
int (*db_read_one_row)(MYSQL *mysql,unsigned int fields,MYSQL_ROW row, unsigned long *lengths);
/* prepared statements */
my_bool (*db_supported_buffer_type)(enum enum_field_types type);
my_bool (*db_read_prepare_response)(MYSQL_STMT *stmt);
int (*db_read_stmt_result)(MYSQL *mysql);
my_bool (*db_stmt_get_result_metadata)(MYSQL_STMT *stmt);
my_bool (*db_stmt_get_param_metadata)(MYSQL_STMT *stmt);
int (*db_stmt_read_all_rows)(MYSQL_STMT *stmt);
int (*db_stmt_fetch)(MYSQL_STMT *stmt, unsigned char **row);
int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row);
void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt);
};
/* synonyms/aliases functions */
#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
#define mysql_library_init mysql_server_init
#define mysql_library_end mysql_server_end

View File

@@ -35,11 +35,12 @@
#endif
/* known plugin types */
#define MYSQL_CLIENT_reserved1 0
#define MYSQL_CLIENT_reserved2 1
#define MYSQL_CLIENT_DB_PLUGIN 0
#define MYSQL_CLIENT_reserved 1
#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2
#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100
#define MYSQL_CLIENT_DB_PLUGIN_INTERFACE_VERSION 0x0100
#define MYSQL_CLIENT_MAX_PLUGINS 3
@@ -68,6 +69,32 @@ struct st_mysql_client_plugin
struct st_mysql;
/********* database api plugin specific declarations **********/
typedef struct st_mariadb_client_plugin_DB
{
MYSQL_CLIENT_PLUGIN_HEADER
/* functions */
struct st_mysql_methods *methods;
/*
MYSQL * (*db_connect)(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db, uint port,
const char *unix_socket,unsigned long client_flag);
void (*db_close)(MYSQL *mysql);
int (*db_query)(MYSQL *mysql, const char *query, size_t query_len);
int (*db_read_one_row)(MYSQL *mysql, uint fields, MYSQL_ROW row,
ulong *lengths);
MYSQL_DATA *(*db_read_all_rows)(MYSQL *mysql,
MYSQL_FIELD *mysql_fields, uint fields);
void (*db_query_end)(MYSQL *mysql);
int (*db_stmt_prepare)(MYSQL_STMT *stmt, const char *stmt_str, ulong length);
my_bool (*db_stmt_close)(MYSQL_STMT *stmt);
my_bool (*is_supported_buffer_type)(enum enum_field_types type);
int (*db_stmt_fetch)(MYSQL_STMT *stmt);
int (*db_stmt_execute)(MYSQL_STMT *stmt); */
} MARIADB_DB_PLUGIN;
#define MARIADB_DB_DRIVER(a) ((a)->ext_db)
/******** authentication plugin specific declarations *********/
#include <mysql/plugin_auth_common.h>

View File

@@ -102,7 +102,13 @@ ma_secure.c
libmariadb_exports.def
)
IF(WITH_SQLITE)
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
${CMAKE_SOURCE_DIR}/plugins/sqlite/sqlite3.c
${CMAKE_SOURCE_DIR}/plugins/sqlite/sqlite_client_plugin.c)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/plugins/sqlite)
ADD_DEFINITIONS(-DSQLITE_ENABLE_COLUMN_METADATA=1)
ENDIF()
IF(ZLIB_FOUND)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
@@ -144,7 +150,6 @@ IF(OPENSSL_FOUND)
TARGET_LINK_LIBRARIES(libmariadb ${SSL_LIBRARIES})
ENDIF()
IF(WIN32)
TARGET_LINK_LIBRARIES(libmariadb ws2_32)
TARGET_LINK_LIBRARIES(mariadbclient ws2_32)

View File

@@ -60,7 +60,7 @@ static MEM_ROOT mem_root;
static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]=
{
0, /* these two are taken by Connector/C */
MYSQL_CLIENT_DB_PLUGIN_INTERFACE_VERSION, /* these two are taken by Connector/C */
0, /* these two are taken by Connector/C */
MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION
};
@@ -264,7 +264,6 @@ int mysql_client_plugin_init()
for (builtin= mysql_client_builtins; *builtin; builtin++)
add_plugin(&mysql, *builtin, 0, 0, unused);
pthread_mutex_unlock(&LOCK_load_client_plugin);
load_env_plugins(&mysql);

View File

@@ -140,6 +140,7 @@ const char *client_errors[]=
/* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset",
/* 2058 */ "Plugin %s could not be loaded: %s",
/* 2059 */ "Can't connect twice. Already connected",
/* 2060 */ "Plugin doesn't support this function",
""
};
#endif

View File

@@ -72,6 +72,17 @@ extern const CHARSET_INFO * mysql_find_charset_nr(uint charsetnr);
extern const CHARSET_INFO * mysql_find_charset_name(const char * const name);
extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
const char *data_plugin, const char *db);
/* prepare statement methods from my_stmt.c */
extern my_bool mthd_supported_buffer_type(enum enum_field_types type);
extern my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt);
extern my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt);
extern my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt);
extern int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row);
extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row);
extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt);
extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt);
uint mysql_port=0;
my_string mysql_unix_port=0;
@@ -81,6 +92,8 @@ my_string mysql_unix_port=0;
#define CONNECT_TIMEOUT 0
#endif
struct st_mysql_methods MARIADB_DEFAULT_METHODS;
#if defined(MSDOS) || defined(_WIN32)
// socket_errno is defined in my_global.h for all platforms
#define perror(A)
@@ -94,10 +107,6 @@ my_string mysql_unix_port=0;
#define native_password_plugin_name "mysql_native_password"
const char *unknown_sqlstate= "HY000";
MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
uint field_count);
static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
ulong *lengths);
static void end_server(MYSQL *mysql);
static void mysql_close_memory(MYSQL *mysql);
void read_user_name(char *name);
@@ -125,6 +134,7 @@ extern void mysql_client_plugin_deinit();
#endif
/****************************************************************************
* A modified version of connect(). connect2() allows you to specify
* a timeout value, in seconds, that we should wait until we
@@ -523,14 +533,14 @@ void free_rows(MYSQL_DATA *cur)
int
simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
size_t length, my_bool skipp_check)
mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
size_t length, my_bool skipp_check, void *opt_arg)
{
NET *net= &mysql->net;
int result= -1;
init_sigpipe_variables
DBUG_ENTER("simple_command");
DBUG_ENTER("mthd_my_send_command");
DBUG_PRINT("info", ("server_command: %d packet_size: %u", command, length));
@@ -591,6 +601,12 @@ simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
DBUG_RETURN(result);
}
int
simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
size_t length, my_bool skipp_check, void *opt_arg)
{
return mysql->methods->db_command(mysql, command, arg, length, skipp_check, opt_arg);
}
static void free_old_query(MYSQL *mysql)
{
@@ -762,6 +778,18 @@ end_server(MYSQL *mysql)
DBUG_VOID_RETURN;
}
void mthd_my_skip_result(MYSQL *mysql)
{
ulong pkt_len;
DBUG_ENTER("madb_skip_result");
do {
pkt_len= net_safe_read(mysql);
if (pkt_len == packet_error)
break;
} while (pkt_len > 8 || mysql->net.read_pos[0] != 254);
DBUG_VOID_RETURN;
}
void STDCALL
mysql_free_result(MYSQL_RES *result)
@@ -772,14 +800,7 @@ mysql_free_result(MYSQL_RES *result)
{
if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
{
ulong pkt_len;
DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
do {
pkt_len= net_safe_read(result->handle);
if (pkt_len == packet_error)
break;
} while (pkt_len > 8 || result->handle->net.read_pos[0] != 254);
result->handle->methods->db_skip_result(result->handle);
result->handle->status=MYSQL_STATUS_READY;
}
free_rows(result->data);
@@ -806,7 +827,7 @@ static const char *default_options[]=
"connect-timeout", "local-infile", "disable-local-infile",
"ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
"multi-results", "multi-statements", "multi-queries", "secure-auth",
"report-data-truncation", "plugin-dir", "default-auth",
"report-data-truncation", "plugin-dir", "default-auth", "database-type",
NULL
};
@@ -820,7 +841,7 @@ enum option_val
OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth
OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth, OPT_db_type
};
#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL, IS_STRING) \
@@ -829,8 +850,8 @@ enum option_val
my_malloc(sizeof(struct st_mysql_options_extention), \
MYF(MY_WME | MY_ZEROFILL)); \
if (IS_STRING) { \
my_free((OPTS)->extension->KEY, MYF(MY_ALLOW_ZERO_PTR)); \
(OPTS)->extension->KEY= my_strdup((VAL), MYF(MY_WME)); \
my_free((char *)(OPTS)->extension->KEY, MYF(MY_ALLOW_ZERO_PTR)); \
(OPTS)->extension->KEY= my_strdup((char *)(VAL), MYF(MY_WME)); \
} else \
(OPTS)->extension->KEY= (VAL);
@@ -1139,7 +1160,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
/* Read all rows (fields or data) from server */
MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
uint fields)
{
uint field;
@@ -1150,7 +1171,7 @@ MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
MYSQL_DATA *result;
MYSQL_ROWS **prev_ptr,*cur;
NET *net = &mysql->net;
DBUG_ENTER("read_rows");
DBUG_ENTER("madb_read_rows");
if ((pkt_len= net_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
@@ -1235,8 +1256,7 @@ MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
*/
static int
read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
int mthd_my_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
{
uint field;
ulong pkt_len,len;
@@ -1391,10 +1411,21 @@ mysql_connect(MYSQL *mysql,const char *host,
** before calling mysql_real_connect !
*/
MYSQL * STDCALL
MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,unsigned long client_flag)
{
if (!mysql->methods)
mysql->methods= &MARIADB_DEFAULT_METHODS;
return mysql->methods->db_connect(mysql, host, user, passwd,
db, port, unix_socket, client_flag);
}
MYSQL *mthd_my_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,unsigned long client_flag)
{
char buff[NAME_LEN+USERNAME_LENGTH+100];
char *end, *end_pkt, *host_info,
@@ -1944,7 +1975,7 @@ mysql_select_db(MYSQL *mysql, const char *db)
DBUG_ENTER("mysql_select_db");
DBUG_PRINT("enter",("db: '%s'",db));
if ((error=simple_command(mysql,MYSQL_COM_INIT_DB,db,(uint) strlen(db),0)))
if ((error=simple_command(mysql,MYSQL_COM_INIT_DB,db,(uint) strlen(db),0,0)))
DBUG_RETURN(error);
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
mysql->db=my_strdup(db,MYF(MY_WME));
@@ -1989,6 +2020,7 @@ static void mysql_close_options(MYSQL *mysql)
{
my_free(mysql->options.extension->plugin_dir, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.extension->default_auth, MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr)mysql->options.extension->db_driver, MYF(MY_ALLOW_ZERO_PTR));
}
}
@@ -2025,6 +2057,18 @@ void my_set_error(MYSQL *mysql,
DBUG_VOID_RETURN;
}
void mthd_my_close(MYSQL *mysql)
{
if (mysql->net.vio)
{
free_old_query(mysql);
mysql->status=MYSQL_STATUS_READY; /* Force command */
mysql->reconnect=0;
simple_command(mysql,MYSQL_COM_QUIT,NullS,0,1,0);
end_server(mysql);
}
}
void STDCALL
mysql_close(MYSQL *mysql)
{
@@ -2032,14 +2076,9 @@ mysql_close(MYSQL *mysql)
if (mysql) /* Some simple safety */
{
LIST *li_stmt= mysql->stmts;
if (mysql->net.vio)
{
free_old_query(mysql);
mysql->status=MYSQL_STATUS_READY; /* Force command */
mysql->reconnect=0;
simple_command(mysql,MYSQL_COM_QUIT,NullS,0,1);
end_server(mysql);
}
if (mysql->methods)
mysql->methods->db_close(mysql);
/* reset the connection in all active statements
todo: check stmt->mysql in mysql_stmt* functions ! */
@@ -2082,10 +2121,10 @@ mysql_query(MYSQL *mysql, const char *query)
int STDCALL
mysql_send_query(MYSQL* mysql, const char* query, uint length)
{
return simple_command(mysql, MYSQL_COM_QUERY, query, length, 1);
return simple_command(mysql, MYSQL_COM_QUERY, query, length, 1,0);
}
int STDCALL mysql_read_query_result(MYSQL *mysql)
int mthd_my_read_query_result(MYSQL *mysql)
{
uchar *pos;
ulong field_count;
@@ -2122,7 +2161,7 @@ get_info:
mysql->server_status|= SERVER_STATUS_IN_TRANS;
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,8)))
if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
DBUG_RETURN(-1);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
(uint) field_count,1,
@@ -2141,9 +2180,11 @@ mysql_real_query(MYSQL *mysql, const char *query, uint length)
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = \"%.255s\" length=%u",query, length));
if (simple_command(mysql,MYSQL_COM_QUERY,query,length,1))
free_old_query(mysql);
if (simple_command(mysql,MYSQL_COM_QUERY,query,length,1,0))
DBUG_RETURN(-1);
DBUG_RETURN(mysql_read_query_result(mysql));
DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
}
/**************************************************************************
@@ -2174,7 +2215,7 @@ mysql_store_result(MYSQL *mysql)
}
result->eof=1; /* Marker for buffered */
result->lengths=(ulong*) (result+1);
if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
if (!(result->data=mysql->methods->db_read_rows(mysql,mysql->fields,mysql->field_count)))
{
my_free((gptr) result,MYF(0));
DBUG_RETURN(0);
@@ -2254,23 +2295,22 @@ MYSQL_ROW STDCALL
mysql_fetch_row(MYSQL_RES *res)
{
DBUG_ENTER("mysql_fetch_row");
if (!res)
return 0;
if (!res->data)
{ /* Unbufferred fetch */
if (!res->eof)
{
if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
if (!(res->handle->methods->db_read_one_row(res->handle,res->field_count,res->row, res->lengths)))
{
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
else
{
DBUG_PRINT("info",("end of data"));
res->eof=1;
res->handle->status=MYSQL_STATUS_READY;
/* Don't clear handle in mysql_free_results */
res->handle=0;
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
DBUG_PRINT("info",("end of data"));
res->eof=1;
res->handle->status=MYSQL_STATUS_READY;
/* Don't clear handle in mysql_free_results */
res->handle=0;
}
DBUG_RETURN((MYSQL_ROW) NULL);
}
@@ -2416,8 +2456,8 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
LINT_INIT(query);
end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
if (simple_command(mysql,MYSQL_COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
!(query = read_rows(mysql,(MYSQL_FIELD*) 0,8)))
if (simple_command(mysql,MYSQL_COM_FIELD_LIST,buff,(uint) (end-buff),1,0) ||
!(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
DBUG_RETURN(NULL);
free_old_query(mysql);
@@ -2449,12 +2489,12 @@ mysql_list_processes(MYSQL *mysql)
DBUG_ENTER("mysql_list_processes");
LINT_INIT(fields);
if (simple_command(mysql,MYSQL_COM_PROCESS_INFO,0,0,0))
if (simple_command(mysql,MYSQL_COM_PROCESS_INFO,0,0,0,0))
DBUG_RETURN(0);
free_old_query(mysql);
pos=(uchar*) mysql->net.read_pos;
field_count=(uint) net_field_length(&pos);
if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
DBUG_RETURN(NULL);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
(my_bool) test(mysql->server_capabilities &
@@ -2471,7 +2511,7 @@ mysql_create_db(MYSQL *mysql, const char *db)
{
DBUG_ENTER("mysql_createdb");
DBUG_PRINT("enter",("db: %s",db));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_CREATE_DB,db, (uint) strlen(db),0));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_CREATE_DB,db, (uint) strlen(db),0,0));
}
@@ -2480,7 +2520,7 @@ mysql_drop_db(MYSQL *mysql, const char *db)
{
DBUG_ENTER("mysql_drop_db");
DBUG_PRINT("enter",("db: %s",db));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_DROP_DB,db,(uint) strlen(db),0));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_DROP_DB,db,(uint) strlen(db),0,0));
}
/* In 5.0 this version became an additional parameter shutdown_level */
@@ -2490,7 +2530,7 @@ mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
uchar s_level[2];
DBUG_ENTER("mysql_shutdown");
s_level[0]= (uchar)shutdown_level;
DBUG_RETURN(simple_command(mysql, MYSQL_COM_SHUTDOWN, (char *)s_level, 1, 0));
DBUG_RETURN(simple_command(mysql, MYSQL_COM_SHUTDOWN, (char *)s_level, 1, 0, 0));
}
int STDCALL
@@ -2499,7 +2539,7 @@ mysql_refresh(MYSQL *mysql,uint options)
uchar bits[1];
DBUG_ENTER("mysql_refresh");
bits[0]= (uchar) options;
DBUG_RETURN(simple_command(mysql,MYSQL_COM_REFRESH,(char*) bits,1,0));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_REFRESH,(char*) bits,1,0,0));
}
int STDCALL
@@ -2509,7 +2549,7 @@ mysql_kill(MYSQL *mysql,ulong pid)
DBUG_ENTER("mysql_kill");
int4store(buff,pid);
/* if we kill our own thread, reading the response packet will fail */
DBUG_RETURN(simple_command(mysql,MYSQL_COM_PROCESS_KILL,buff,4,0));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_PROCESS_KILL,buff,4,0,0));
}
@@ -2517,14 +2557,14 @@ int STDCALL
mysql_dump_debug_info(MYSQL *mysql)
{
DBUG_ENTER("mysql_dump_debug_info");
DBUG_RETURN(simple_command(mysql,MYSQL_COM_DEBUG,0,0,0));
DBUG_RETURN(simple_command(mysql,MYSQL_COM_DEBUG,0,0,0,0));
}
char * STDCALL
mysql_stat(MYSQL *mysql)
{
DBUG_ENTER("mysql_stat");
if (simple_command(mysql,MYSQL_COM_STATISTICS,0,0,0))
if (simple_command(mysql,MYSQL_COM_STATISTICS,0,0,0,0))
return mysql->net.last_error;
mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
if (!mysql->net.read_pos[0])
@@ -2541,11 +2581,11 @@ mysql_ping(MYSQL *mysql)
{
int rc;
DBUG_ENTER("mysql_ping");
rc= simple_command(mysql,MYSQL_COM_PING,0,0,0);
rc= simple_command(mysql,MYSQL_COM_PING,0,0,0,0);
/* if connection was terminated and reconnect is true, try again */
if (rc!=0 && mysql->reconnect)
rc= simple_command(mysql,MYSQL_COM_PING,0,0,0);
rc= simple_command(mysql,MYSQL_COM_PING,0,0,0,0);
return rc;
}
@@ -2665,14 +2705,37 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
MYF(MY_WME | MY_ZEROFILL));
if (mysql->options.extension)
mysql->options.extension->report_progress=
(void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg;
(void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg;
break;
case MYSQL_PLUGIN_DIR:
OPT_SET_EXTENDED_VALUE(&mysql->options, plugin_dir, (char *)arg , 1);
OPT_SET_EXTENDED_VALUE(&mysql->options, plugin_dir, (char *)arg, 1);
break;
case MYSQL_DEFAULT_AUTH:
OPT_SET_EXTENDED_VALUE(&mysql->options, default_auth, (char *)arg, 1);
break;
case MYSQL_DATABASE_DRIVER:
{
MARIADB_DB_PLUGIN *db_plugin;
if (!(db_plugin= (MARIADB_DB_PLUGIN *)mysql_client_find_plugin(mysql, (char *)arg,
MYSQL_CLIENT_DB_PLUGIN)))
break;
if (!mysql->options.extension)
mysql->options.extension= (struct st_mysql_options_extention *)
my_malloc(sizeof(struct st_mysql_options_extention),
MYF(MY_WME | MY_ZEROFILL));
if (!mysql->options.extension->db_driver)
mysql->options.extension->db_driver= (MARIADB_DB_DRIVER *)
my_malloc(sizeof(MARIADB_DB_DRIVER), MYF(MY_WME | MY_ZEROFILL));
if (mysql->options.extension &&
mysql->options.extension->db_driver)
{
mysql->options.extension->db_driver->plugin = db_plugin;
mysql->options.extension->db_driver->buffer= NULL;
mysql->options.extension->db_driver->name= (char *)db_plugin->name;
mysql->methods= db_plugin->methods;
}
}
break;
default:
DBUG_RETURN(-1);
}
@@ -2795,7 +2858,7 @@ int STDCALL mysql_next_result(MYSQL *mysql)
if (mysql->server_status & SERVER_MORE_RESULTS_EXIST)
{
DBUG_RETURN(mysql_read_query_result(mysql));
DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
}
DBUG_RETURN(-1);
@@ -3018,7 +3081,7 @@ int STDCALL mysql_set_server_option(MYSQL *mysql,
char buffer[2];
DBUG_ENTER("mysql_set_server_option");
int2store(buffer, (uint)option);
DBUG_RETURN(simple_command(mysql, MYSQL_COM_SET_OPTION, buffer, sizeof(buffer), 0));
DBUG_RETURN(simple_command(mysql, MYSQL_COM_SET_OPTION, buffer, sizeof(buffer), 0, 0));
}
ulong STDCALL mysql_get_client_version(void)
@@ -3051,5 +3114,48 @@ my_bool STDCALL mariadb_connection(MYSQL *mysql)
const char * STDCALL
mysql_get_server_name(MYSQL *mysql)
{
if (mysql->options.extension &&
mysql->options.extension->db_driver != NULL)
return mysql->options.extension->db_driver->name;
return mariadb_connection(mysql) ? "MariaDB" : "MySQL";
}
/*
* Default methods for a connection. These methods are
* stored in mysql->methods and can be overwritten by
* a plugin, e.g. for using another database
*/
struct st_mysql_methods MARIADB_DEFAULT_METHODS = {
/* open a connection */
mthd_my_real_connect,
/* close connection */
mthd_my_close,
/* send command to server */
mthd_my_send_cmd,
/* skip result set */
mthd_my_skip_result,
/* read response packet */
mthd_my_read_query_result,
/* read all rows from a result set */
mthd_my_read_rows,
/* read one/next row */
mthd_my_read_one_row,
/* check if datatype is supported */
mthd_supported_buffer_type,
/* read response packet from prepare */
mthd_stmt_read_prepare_response,
/* read response from stmt execute */
mthd_my_read_query_result,
/* get result set metadata for a prepared statement */
mthd_stmt_get_result_metadata,
/* get param metadata for a prepared statement */
mthd_stmt_get_param_metadata,
/* read all rows (buffered) */
mthd_stmt_read_all_rows,
/* fetch one row (unbuffered) */
mthd_stmt_fetch_row,
/* store values in bind buffer */
mthd_stmt_fetch_to_bind,
/* skip unbuffered stmt result */
mthd_stmt_flush_unbuffered
};

View File

@@ -57,7 +57,6 @@ EXPORTS
mysql_ping
mysql_stmt_result_metadata
mysql_query
mysql_read_query_result
mysql_real_connect
mysql_real_escape_string
mysql_real_query
@@ -105,4 +104,3 @@ EXPORTS
mysql_stmt_next_result
mariadb_connection
mysql_get_server_name

View File

@@ -45,11 +45,19 @@ static auth_plugin_t old_password_client_plugin=
NULL,
old_password_auth_client
};
typedef struct st_mariadb_client_plugin_DBAPI dbapi_plugin_t;
#ifdef HAVE_SQLITE
extern dbapi_plugin_t sqlite3_plugin;
#endif
struct st_mysql_client_plugin *mysql_client_builtins[]=
{
(struct st_mysql_client_plugin *)&old_password_client_plugin,
(struct st_mysql_client_plugin *)&native_password_client_plugin,
#ifdef HAVE_SQLITE
(struct st_mysql_client_plugin *)&sqlite3_plugin,
#endif
0
};

View File

@@ -57,11 +57,12 @@
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include <mysql/client_plugin.h>
static my_bool is_not_null= 0;
static my_bool is_null= 1;
my_bool is_supported_buffer_type(enum enum_field_types type)
my_bool mthd_supported_buffer_type(enum enum_field_types type)
{
switch (type) {
case MYSQL_TYPE_BIT:
@@ -143,7 +144,7 @@ static int stmt_buffered_fetch(MYSQL_STMT *stmt, uchar **row)
return 0;
}
static int stmt_read_all_rows(MYSQL_STMT *stmt)
int mthd_stmt_read_all_rows(MYSQL_STMT *stmt)
{
MYSQL_DATA *result= &stmt->result;
MYSQL_ROWS *current, **pprevious;
@@ -251,7 +252,7 @@ static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
int4store(buf, stmt->stmt_id);
int4store(buf + STMT_ID_LENGTH, stmt->prefetch_rows);
if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, (char *)buf, sizeof(buf), 1))
if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, (char *)buf, sizeof(buf), 1, stmt))
DBUG_RETURN(1);
/* free previously allocated buffer */
@@ -259,13 +260,13 @@ static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
result->data= 0;
result->rows= 0;
if (stmt_read_all_rows(stmt))
if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
DBUG_RETURN(1);
DBUG_RETURN(stmt_buffered_fetch(stmt, row));
}
static void stmt_flush_unbuffered(MYSQL_STMT *stmt)
void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt)
{
ulong packet_len;
while ((packet_len = net_safe_read(stmt->mysql)) != packet_error)
@@ -273,7 +274,7 @@ static void stmt_flush_unbuffered(MYSQL_STMT *stmt)
return;
}
static int stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
{
uint i;
size_t truncations= 0;
@@ -728,6 +729,12 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
for (i=0; i < stmt->param_count; i++)
{
if (stmt->mysql->methods->db_supported_buffer_type &&
!stmt->mysql->methods->db_supported_buffer_type(stmt->params[i].buffer_type))
{
SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
if (!stmt->params[i].is_null)
stmt->params[i].is_null= &is_not_null;
@@ -824,7 +831,8 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
for (i=0; i < stmt->field_count; i++)
{
if (!is_supported_buffer_type(bind[i].buffer_type))
if (stmt->mysql->methods->db_supported_buffer_type &&
!stmt->mysql->methods->db_supported_buffer_type(bind[i].buffer_type))
{
SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
@@ -892,13 +900,13 @@ my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
/* check if all data are fetched */
if (stmt->mysql->status != MYSQL_STATUS_READY)
{
stmt_flush_unbuffered(stmt);
stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
stmt->mysql->status= MYSQL_STATUS_READY;
}
if (stmt->state > MYSQL_STMT_INITTED)
{
int4store(stmt_id, stmt->stmt_id);
if (simple_command(stmt->mysql,MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1))
if (simple_command(stmt->mysql,MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt))
{
SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, stmt->mysql->net.last_error);
return 1;
@@ -944,6 +952,11 @@ const char * STDCALL mysql_stmt_error(MYSQL_STMT *stmt)
return (const char *)stmt->last_error;
}
int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row)
{
return stmt->fetch_row_func(stmt, row);
}
int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
{
unsigned char *row;
@@ -967,11 +980,9 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
}
if (stmt->state == MYSQL_STMT_FETCH_DONE)
{
DBUG_RETURN(MYSQL_NO_DATA);
}
if ((rc= stmt->fetch_row_func(stmt, &row)))
if ((rc= stmt->mysql->methods->db_stmt_fetch(stmt, &row)))
{
stmt->state= MYSQL_STMT_FETCH_DONE;
stmt->mysql->status= MYSQL_STATUS_READY;
@@ -979,10 +990,11 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
DBUG_RETURN(MYSQL_NO_DATA);
}
if ((rc= stmt_fetch_to_bind(stmt, row)))
if ((rc= stmt->mysql->methods->db_stmt_fetch_to_bind(stmt, row)))
{
DBUG_RETURN(rc);
}
}
stmt->state= MYSQL_STMT_USER_FETCHING;
CLEAR_CLIENT_ERROR(stmt->mysql);
CLEAR_CLIENT_STMT_ERROR(stmt);
@@ -1066,7 +1078,7 @@ MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql)
DBUG_RETURN(stmt);
}
my_bool stmt_read_prepare_response(MYSQL_STMT *stmt)
my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt)
{
ulong packet_length;
uchar *p;
@@ -1099,25 +1111,25 @@ my_bool stmt_read_prepare_response(MYSQL_STMT *stmt)
DBUG_RETURN(0);
}
my_bool stmt_get_param_metadata(MYSQL_STMT *stmt)
my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt)
{
MYSQL_DATA *result;
DBUG_ENTER("stmt_get_param_metadata");
if (!(result= read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
DBUG_RETURN(1);
free_rows(result);
DBUG_RETURN(0);
}
my_bool stmt_read_result_metadata(MYSQL_STMT *stmt)
my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt)
{
MYSQL_DATA *result;
DBUG_ENTER("stmt_read_result_metadata");
if (!(result= read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7)))
DBUG_RETURN(1);
if (!(stmt->fields= unpack_fields(result,&stmt->mem_root,
stmt->field_count, 0,
@@ -1157,28 +1169,30 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon
stmt->field_count= 0;
int4store(stmt_id, stmt->stmt_id);
if (simple_command(stmt->mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1))
if (simple_command(stmt->mysql, MYSQL_COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt))
goto fail;
}
if (simple_command(stmt->mysql,MYSQL_COM_STMT_PREPARE, query, length, 1))
if (simple_command(stmt->mysql, MYSQL_COM_STMT_PREPARE, query, length, 1, stmt))
goto fail;
if (stmt_read_prepare_response(stmt))
if (stmt->mysql->methods->db_read_prepare_response &&
stmt->mysql->methods->db_read_prepare_response(stmt))
goto fail;
/* metadata not supported yet */
if (stmt->param_count && stmt_get_param_metadata(stmt))
if (stmt->param_count &&
stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
{
goto fail;
}
if (stmt->field_count && stmt_read_result_metadata(stmt))
{
goto fail;
}
/* allocated bind buffer for parameters */
if (stmt->field_count &&
stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
{
goto fail;
}
if (stmt->param_count)
{
if (!(stmt->params= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
@@ -1237,7 +1251,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
int4store(buff, stmt->stmt_id);
int4store(buff + STMT_ID_LENGTH, (int)~0);
if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, buff, sizeof(buff), 1))
if (simple_command(stmt->mysql, MYSQL_COM_STMT_FETCH, buff, sizeof(buff), 1, stmt))
DBUG_RETURN(1);
/* todo: cursor */
}
@@ -1248,7 +1262,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
DBUG_RETURN(1);
}
if (stmt_read_all_rows(stmt))
if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
{
/* error during read - reset stmt->data */
free_root(&stmt->result.alloc, 0);
@@ -1304,7 +1318,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
}
if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
{
stmt_flush_unbuffered(stmt);
stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
stmt->state= MYSQL_STMT_PREPARED;
stmt->mysql->status= MYSQL_STATUS_READY;
}
@@ -1316,12 +1330,11 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
stmt->result_cursor= stmt->result.data= 0;
stmt->result.rows= 0;
}
request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len);
DBUG_PRINT("info",("request_len=%ld", request_len));
ret= test(simple_command(stmt->mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1) ||
mysql_read_query_result(stmt->mysql));
ret= test(simple_command(stmt->mysql, MYSQL_COM_STMT_EXECUTE, request, request_len, 1, stmt) ||
(stmt->mysql->methods->db_read_stmt_result && stmt->mysql->methods->db_read_stmt_result(stmt->mysql)));
if (request)
my_free(request, MYF(0));
@@ -1367,13 +1380,19 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
for (i=0; i < stmt->field_count; i++)
{
stmt->fields[i].db= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].db);
stmt->fields[i].table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].table);
stmt->fields[i].org_table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_table);
stmt->fields[i].name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].name);
stmt->fields[i].org_name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_name);
stmt->fields[i].catalog= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].catalog);
stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(&stmt->mem_root, stmt->mysql->fields[i].def) : NULL;
if (stmt->mysql->fields[i].db)
stmt->fields[i].db= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].db);
if (stmt->mysql->fields[i].table)
stmt->fields[i].table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].table);
if (stmt->mysql->fields[i].org_table)
stmt->fields[i].org_table= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_table);
if (stmt->mysql->fields[i].name)
stmt->fields[i].name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].name);
if (stmt->mysql->fields[i].org_name)
stmt->fields[i].org_name= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].org_name);
if (stmt->mysql->fields[i].catalog)
stmt->fields[i].catalog= strdup_root(&stmt->mem_root, stmt->mysql->fields[i].catalog);
stmt->fields[i].def= stmt->mysql->fields[i].def ? strdup_root(&stmt->mem_root, stmt->mysql->fields[i].def) : NULL;
}
}
@@ -1455,7 +1474,7 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
if (stmt->mysql->status!= MYSQL_STATUS_READY && stmt->field_count)
{
stmt_flush_unbuffered(stmt);
stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
stmt->mysql->status= MYSQL_STATUS_READY;
}
@@ -1463,7 +1482,7 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
if (stmt->mysql->status == MYSQL_STATUS_READY)
{
int4store(cmd_buf, stmt->stmt_id);
if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0)))
if ((ret= simple_command(stmt->mysql,MYSQL_COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0, stmt)))
SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
stmt->mysql->net.last_error);
@@ -1562,7 +1581,7 @@ my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
int2store(cmd_buff + STMT_ID_LENGTH, param_number);
memcpy(cmd_buff + STMT_ID_LENGTH + 2, data, length);
stmt->params[param_number].long_data_used= 1;
ret= simple_command(stmt->mysql,MYSQL_COM_STMT_SEND_LONG_DATA, (char *)cmd_buff, packet_len, 1);
ret= simple_command(stmt->mysql,MYSQL_COM_STMT_SEND_LONG_DATA, (char *)cmd_buff, packet_len, 1, stmt);
my_free((gptr)cmd_buff, MYF(MY_WME));
DBUG_RETURN(ret);
}

View File

@@ -19,6 +19,9 @@ IF(UNIX)
IF(MATH_LIBRARY)
SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lm")
ENDIF(MATH_LIBRARY)
IF(WITH_SQLITE)
SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lsqlite")
ENDIF()
ENDIF(UNIX)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mariadb_config.c.in

6
plugins/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
FILE(GLOB plugin_dirs ${CMAKE_SOURCE_DIR}/plugins/*)
FOREACH(dir ${plugin_dirs})
IF (EXISTS ${dir}/CMakeLists.txt)
ADD_SUBDIRECTORY(${dir})
ENDIF()
ENDFOREACH()

View File

@@ -0,0 +1,22 @@
# If option WITH_SQLITE was specified, we build this plugin
# as an internal plugin.
IF(NOT WITH_SQLITE)
# ADD_DEFINITIONS(-DSQLITE_ENABLE_COLUMN_METADATA)
#
#ADD_LIBRARY(sqlite SHARED sqlite3.c)
#ADD_LIBRARY(sqlite_client_plugin SHARED sqlite_client_plugin.c)
#TARGET_LINK_LIBRARIES(sqlite_client_plugin sqlite)
#
#INSTALL(TARGETS
# sqlite
# RUNTIME DESTINATION "lib/mariadb"
# LIBRARY DESTINATION "lib/mariadb"
# ARCHIVE DESTINATION "lib/mariadb")
#
#INSTALL(TARGETS
# sqlite_client_plugin
# RUNTIME DESTINATION "plugins"
# LIBRARY DESTINATION "plugins"
# ARCHIVE DESTINATION "plugins")
ENDIF()

137413
plugins/sqlite/sqlite3.c Normal file

File diff suppressed because it is too large Load Diff

7160
plugins/sqlite/sqlite3.h Normal file

File diff suppressed because it is too large Load Diff

447
plugins/sqlite/sqlite3ext.h Normal file
View File

@@ -0,0 +1,447 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each others' shared
** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
int (*backup_finish)(sqlite3_backup*);
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
int (*backup_pagecount)(sqlite3_backup*);
int (*backup_remaining)(sqlite3_backup*);
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);
int (*extended_errcode)(sqlite3*);
void (*log)(int,const char*,...);
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
const char *(*sourceid)(void);
int (*stmt_status)(sqlite3_stmt*,int,int);
int (*strnicmp)(const char*,const char*,int);
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
};
/*
** The following macros redefine the API routines so that they are
** redirected throught the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#ifndef SQLITE_CORE
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#define sqlite3_backup_finish sqlite3_api->backup_finish
#define sqlite3_backup_init sqlite3_api->backup_init
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
#define sqlite3_backup_step sqlite3_api->backup_step
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
#define sqlite3_db_config sqlite3_api->db_config
#define sqlite3_db_mutex sqlite3_api->db_mutex
#define sqlite3_db_status sqlite3_api->db_status
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
#define sqlite3_log sqlite3_api->log
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid sqlite3_api->sourceid
#define sqlite3_stmt_status sqlite3_api->stmt_status
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
#endif /* _SQLITE3EXT_H_ */

View File

@@ -0,0 +1,870 @@
/************************************************************************************
Copyright (C) 2012 Monty Program AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <errmsg.h>
#include <mysql.h>
#include <mysql/client_plugin.h>
#include <mysql.h>
#include <mysql_com.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <errmsg.h>
#include <string.h>
#define CLEAR_ERROR(a) my_set_error((a), 0, "", "");
enum enum_s3_status {S3_OK= 0, S3_RESULT_WAIT, S3_RESULT_FETCH, S3_FETCH_DONE};
typedef struct st_mariadb_sqlite
{
enum enum_s3_status status;
sqlite3 *db;
sqlite3_stmt *stmt;
ulong last_stmt_id;
MYSQL_ROW row;
} MARIADB_SQLT;
unsigned long s3_connection_id= 0;
void s3_close(MYSQL *mysql);
/**
opens a sqlite connection, the parameter db (database name)
must be specified. If db doesn't exist, it will be created.
@param MYSQL mysql handle
@param host unused
@param user unused
@param passwd unused
@param db database name (must be specified)
@param port unused
@param unix_socket unused
@param client_flag unused (todo, support open flag)
@retval Pointer to a MYSQL connection handle
or NULL if error
**/
MYSQL *s3_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,unsigned long client_flag)
{
MARIADB_SQLT *dbhdl;
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
int rc;
size_t len;
DBUG_ASSERT(s3_driver != NULL);
if (!db)
return 0;
/* make sure that we don't leak in case s3_close was not called */
if (s3_driver->name)
s3_close(mysql);
if (!(s3_driver->buffer= my_malloc(sizeof(MARIADB_SQLT), MYF(MY_ZEROFILL))))
{
my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return 0;
}
dbhdl= (MARIADB_SQLT*)s3_driver->buffer;
if ((rc= sqlite3_open(db, (sqlite3 **)&dbhdl->db)))
{
my_set_error(mysql, sqlite3_errcode(dbhdl->db), SQLSTATE_UNKNOWN, sqlite3_errmsg(dbhdl->db));
sqlite3_close(dbhdl->db);
return 0;
}
/* connection settings */
len= strlen(SQLITE_VERSION) + strlen(sqlite3_sourceid()) + 10;
if (mysql->server_version= (char *)my_malloc(len, MYF(0)))
{
my_snprintf(mysql->server_version, len, "%s Sqlite %s", SQLITE_VERSION, sqlite3_sourceid());
}
mysql->db= my_strdup(db,MYF(MY_WME));
sqlite3_mutex_enter(sqlite3_db_mutex(dbhdl->db));
mysql->thread_id= ++s3_connection_id;
sqlite3_mutex_leave(sqlite3_db_mutex(dbhdl->db));
return mysql;
}
void s3_skip_result(MYSQL *mysql)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
sqlite3_finalize(db->stmt);
db->stmt= NULL;
}
/**
read field information and map information to
MYSQL_FIELD
@param MYSQL connection handle
@retval Array of MYSQL_FIELD or NULL on
error
**/
MYSQL_FIELD *s3_get_fields(MYSQL *mysql, sqlite3_stmt *stmt)
{
MYSQL_FIELD *field;
int i, column_count;
if (!stmt ||
!(column_count = sqlite3_column_count(stmt)))
return NULL;
field= (MYSQL_FIELD*) alloc_root(&mysql->field_alloc,sizeof(MYSQL_FIELD)* column_count);
memset(field, 0, sizeof(MYSQL_FIELD) * column_count);
for (i=0; i < column_count; i++)
{
/* map column types */
switch(sqlite3_column_type(stmt, i)) {
case SQLITE_NULL:
field[i].type= MYSQL_TYPE_NULL;
field[i].length= 0;
field[i].charsetnr= 63; /* binary */
break;
case SQLITE_BLOB:
field[i].type= MYSQL_TYPE_BLOB;
field[i].length= sqlite3_column_bytes(stmt, i);
field[i].charsetnr= 63; /* binary */
break;
case SQLITE_INTEGER:
field[i].type= MYSQL_TYPE_LONG;
field[i].length= 11;
field[i].charsetnr= 63; /* binary */
break;
case SQLITE_TEXT:
field[i].type= MYSQL_TYPE_VAR_STRING;
field[i].length= sqlite3_column_bytes(stmt, i);
field[i].charsetnr= 33; /* utf8 */
break;
case SQLITE_FLOAT:
field[i].type= MYSQL_TYPE_DOUBLE;
field[i].length= 22;
field[i].charsetnr= 63; /* binary */
break;
}
/* we will update max_length in store/use result */
field[i].max_length= 0;
field[i].table= (char *)sqlite3_column_table_name(stmt, i);
field[i].name= (char *)sqlite3_column_name(stmt, i);
field[i].org_name= (char *)sqlite3_column_origin_name(stmt, i);
field[i].db= (char *)sqlite3_column_database_name(stmt, i);
}
return field;
}
/**
return next row from a previous sqlite3_prepare
call.
@param MYSQL connection handle
@param length total length of row
**/
MYSQL_ROW s3_get_row(MYSQL *mysql, size_t *length)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
int rc= SQLITE_ROW;
*length= 0;
if (!mysql->field_count || db->status == S3_FETCH_DONE)
return NULL;
if (db->status == S3_RESULT_WAIT) {
db->row= (MYSQL_ROW)my_malloc(mysql->field_count * sizeof(char *), MYF(0));
db->status= S3_RESULT_FETCH;
}
else
rc= sqlite3_step(db->stmt);
if (rc == SQLITE_ROW)
{
int i;
for (i=0; i < mysql->field_count; i++)
{
if ((db->row[i]= (char *)sqlite3_column_text(db->stmt, i)))
{
size_t slen= strlen(db->row[i]);
*length += slen + 1;
if (mysql->fields)
if (slen > mysql->fields[i].max_length)
mysql->fields[i].max_length= slen;
}
}
return db->row;
}
/* nothing to fetch or error */
db->status= S3_FETCH_DONE;
return NULL;
}
/**
frees up memory and close db->stmt.
@param MYSQL connection handle
@retval void
**/
void db_query_end(MYSQL *mysql)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
if (!db || !db->db)
return;
if (db->stmt)
{
sqlite3_finalize(db->stmt);
db->stmt= NULL;
}
if (db->row)
{
my_free((gptr)db->row, MYF(0));
db->row= NULL;
}
db->status= S3_OK;
}
/**
read one row. This function is used for unbuffered
result sets and will be called from mysql_fetch_row()
@param mysql connection handle
@param fields number of fields
@param row row
@param lengths total length of row
@return int 0 on success, != 0 on error
**/
int s3_read_one_row(MYSQL *mysql, uint fields,
MYSQL_ROW row, ulong *lengths)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
uint field;
size_t length;
MYSQL_ROW s3row;
if (!mysql->field_count ||
(db->status != S3_RESULT_WAIT && db->status != S3_RESULT_FETCH) ||
!db->stmt)
return -1;
if ((s3row= s3_get_row(mysql, &length)))
{
for (field=0 ; field < fields ; field++)
{
if (s3row[field] == NULL)
*lengths++=0;
else
{
row[field] = (char*) s3row[field];
*lengths++=strlen(row[field]);
}
}
return 0;
}
/* all rows fetched */
sqlite3_finalize(db->stmt);
db->stmt= NULL;
return -1;
}
/**
read all rows. This function will be called from
mysql_store_result()
@param mysql connection handle
@param mysql_fields array of field descriptors
@param fields number of fields
@return MYSQL_DATA MYSQL_DATA array or NULL on error
**/
MYSQL_DATA *s3_read_all_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields,
uint fields)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
MYSQL_DATA *result;
MYSQL_ROW row;
MYSQL_ROWS **prev_ptr, *cur;
uint field;
size_t length;
char *to;
if (!mysql->field_count || db->status != S3_RESULT_WAIT || !db->stmt)
return NULL;
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
MYF(MY_ZEROFILL))))
{
my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return NULL;
}
init_alloc_root(&result->alloc, 8192, 0); /* Assume rowlength < 8192 */
result->alloc.min_malloc=sizeof(MYSQL_ROWS);
prev_ptr= &result->data;
result->rows=0;
result->fields= fields;
while ((row= s3_get_row(mysql, &length)))
{
result->rows++;
if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
sizeof(MYSQL_ROWS))) ||
!(cur->data= ((MYSQL_ROW)
alloc_root(&result->alloc,
(fields+1)*sizeof(char *)+length))))
{
free_rows(result);
my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return 0;
}
*prev_ptr=cur;
prev_ptr= &cur->next;
to= (char*) (cur->data+fields+1);
for (field=0 ; field < fields ; field++)
{
if (row[field] == NULL)
{ /* null field */
cur->data[field] = 0;
}
else
{
size_t len= strlen(row[field]);
cur->data[field] = to;
memcpy(to,(char*) row[field], len); to[len]=0;
to+=len+1;
}
}
cur->data[field]=to; /* End of last field */
}
*prev_ptr=0; /* last pointer is null */
sqlite3_finalize(db->stmt);
db->stmt= NULL;
return result;
}
/**
db_query()
Executes a SQL query. Will be called from mysql_real_query
@param mysql connection handle
@param query SQL statement
@param length length of statement
@return int 0 on success, !=0 on error
**/
int s3_query(MYSQL *mysql, const char *query, size_t length)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
int rc;
CLEAR_ERROR(mysql);
rc= sqlite3_prepare_v2(db->db, query, (int)length, &db->stmt, NULL);
if (rc != SQLITE_OK)
{
my_set_error(mysql, sqlite3_errcode(db->db), SQLSTATE_UNKNOWN, sqlite3_errmsg(db->db));
return 1;
}
/* since mariadb client library has different calls and logic
for queries and prepared statements, we need to check for
parameter markers */
if (sqlite3_bind_parameter_count(db->stmt) > 0)
{
my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN,
"SQL statement contains parameter markers");
db_query_end(mysql);
return 1;
}
return 0;
}
/**
s3_close()
terminates connection and frees previously allocated
memory. Will be called from mysql_close().
@param mysql connection handle
@return void
**/
void s3_close(MYSQL *mysql)
{
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
if (!db)
return;
/* cleanup */
if (db->db)
{
db_query_end(mysql);
sqlite3_close_v2(db->db);
}
my_free((gptr)s3_driver->buffer, MYF(0));
s3_driver->buffer= NULL;
}
/********************************************************************
!! Experimental !!
Prepared statement (PS) support
!! Experimental !!
Todo:
- Error handling: clear errors, handle stmt_execute return codes
- bind_result not implemented yet
**********************************************************************/
/**
s3_stmt_prepare()
Prepares a statement for execution
@param MYSQL_STMT a stmt handle
@param stmt_str statement SQL string
@param length length of statement string
@return 0 on success, non-zero on error
**/
int s3_stmt_prepare(MYSQL_STMT *stmt, const char *stmt_str, ulong length)
{
MARIADB_DB_DRIVER *s3_driver= stmt->mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
int rc;
sqlite3_stmt *s3_stmt;
rc= sqlite3_prepare_v2(db->db, (char *)stmt_str, (int)length, &s3_stmt, NULL);
if (rc != SQLITE_OK)
{
SET_CLIENT_STMT_ERROR(stmt, sqlite3_errcode(db->db), SQLSTATE_UNKNOWN, sqlite3_errmsg(db->db));
return 1;
}
stmt->ext_stmt= s3_stmt;
stmt->state= MYSQL_STMT_PREPARED;
return 0;
}
my_bool s3_read_prepare_response(MYSQL_STMT *stmt)
{
MARIADB_DB_DRIVER *s3_driver= stmt->mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
sqlite3_stmt *s3_stmt= stmt->ext_stmt;
/* set statement id */
sqlite3_mutex_enter(sqlite3_db_mutex(db->db));
stmt->stmt_id= ++db->last_stmt_id;
sqlite3_mutex_leave(sqlite3_db_mutex(db->db));
stmt->param_count= sqlite3_bind_parameter_count(s3_stmt);
stmt->field_count= sqlite3_column_count(s3_stmt);
return 0;
}
/**
bind parameters to a prepared statement.
This function has to be called before
db_stmt_execute since sqlite doesn't support
binding of addresses, so we need to rebind
values for every statement execution.
@paran NYSQL_STMT
@param MYSQL_BIND
@return bool
**/
my_bool s3_set_bind_params(MYSQL_STMT *stmt, MYSQL_BIND *bind)
{
int i;
for (i=0; i < stmt->param_count; i++)
{
switch(bind[i].buffer_type) {
case MYSQL_TYPE_NULL:
sqlite3_bind_null(stmt->ext_stmt, i + 1);
break;
case MYSQL_TYPE_TINY:
sqlite3_bind_int(stmt->ext_stmt, i + 1, *(uchar *)stmt->params[i].buffer);
break;
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_YEAR:
sqlite3_bind_int(stmt->ext_stmt, i + 1, *(short *)stmt->params[i].buffer);
break;
case MYSQL_TYPE_DOUBLE:
sqlite3_bind_double(stmt->ext_stmt, i + 1, *(double *)stmt->params[i].buffer);
break;
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_INT24:
sqlite3_bind_int(stmt->ext_stmt, i + 1, *(int32 *)stmt->params[i].buffer);
break;
case MYSQL_TYPE_LONGLONG:
sqlite3_bind_int64(stmt->ext_stmt, i + 1, *(my_ulonglong *)stmt->params[i].buffer);
break;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
sqlite3_bind_blob(stmt->ext_stmt, i + 1, stmt->params[i].buffer,
stmt->params[i].buffer_length, NULL);
break;
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
sqlite3_bind_text(stmt->ext_stmt, i + 1, (char *)stmt->params[i].buffer,
stmt->params[i].buffer_length, NULL);
break;
default:
SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
return 1;
break;
}
}
return 0;
}
/**
check if the field type of bind variable is compatible.
@param type buffer type
@retval int 1 if type is compatible, 0 if not
**/
my_bool s3_supported_buffer_type(enum enum_field_types type)
{
switch(type) {
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return 1;
break;
default:
return 0;
}
}
int s3_stmt_execute(MYSQL_STMT *stmt)
{
int rc;
MARIADB_DB_DRIVER *s3_driver= stmt->mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
/* Opposed to MariaDB sqlite doesn't support binding of variables/addresses, so
* we need to reassign values before executing the statement */
if (stmt->param_count)
{
sqlite3_reset(stmt->ext_stmt);
if (s3_set_bind_params(stmt, stmt->params))
return 1;
}
rc= sqlite3_step(stmt->ext_stmt);
switch(rc) {
case SQLITE_ROW:
stmt->mysql->field_count= sqlite3_column_count(stmt->ext_stmt);
stmt->mysql->fields= s3_get_fields(stmt->mysql, stmt->ext_stmt);
stmt->upsert_status.affected_rows= 0;
rc= 0;
break;
case SQLITE_DONE: /* no rows returned */
stmt->upsert_status.affected_rows= sqlite3_changes(db->db);
stmt->upsert_status.last_insert_id= sqlite3_last_insert_rowid(db->db);
rc= 0;
break;
case SQLITE_ERROR:
SET_CLIENT_STMT_ERROR(stmt, sqlite3_errcode(db->db), SQLSTATE_UNKNOWN, sqlite3_errmsg(db->db));
rc= 1;
break;
default:
rc= 0;
}
return rc;
}
int s3_stmt_fetch(MYSQL_STMT *stmt, unsigned char **row)
{
int rc= 0;
if (stmt->state != MYSQL_STMT_WAITING_USE_OR_STORE)
{
rc= sqlite3_step(stmt->ext_stmt);
if (rc == SQLITE_DONE)
{
stmt->state= MYSQL_STMT_FETCH_DONE;
stmt->mysql->status= MYSQL_STATUS_READY;
/* to fetch data again, stmt must be executed again */
return MYSQL_NO_DATA;
}
}
return (rc != SQLITE_ROW) ? rc : 0;
}
int s3_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
{
int i;
longlong lval;
double dval;
char *buf;
size_t s;
for (i=0; i < stmt->field_count; i++)
{
switch (stmt->bind[i].buffer_type) {
case MYSQL_TYPE_NULL:
*stmt->bind[i].is_null= 1;
case MYSQL_TYPE_TINY:
lval= sqlite3_column_int64(stmt->ext_stmt, i);
if (stmt->bind[i].is_unsigned)
*(uchar *)stmt->bind[i].buffer= (uchar)lval;
else
*(char *)stmt->bind[i].buffer= (char)lval;
break;
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_YEAR:
lval= sqlite3_column_int64(stmt->ext_stmt, i);
if (stmt->bind[i].is_unsigned)
*(ushort *)stmt->bind[i].buffer= (ushort)lval;
else
*(short *)stmt->bind[i].buffer= (short)lval;
break;
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_INT24:
lval= sqlite3_column_int64(stmt->ext_stmt, i);
if (stmt->bind[i].is_unsigned)
*(ulong *)stmt->bind[i].buffer= (ulong)lval;
else
*(long *)stmt->bind[i].buffer= (long)lval;
break;
case MYSQL_TYPE_LONGLONG:
lval= sqlite3_column_int64(stmt->ext_stmt, i);
break;
case MYSQL_TYPE_DOUBLE:
dval= sqlite3_column_double(stmt->ext_stmt, i);
*(double *)stmt->bind[i].buffer= dval;
break;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
buf= (char *)sqlite3_column_text(stmt->ext_stmt, i);
if ((s= MIN(stmt->bind[i].buffer_length, sqlite3_column_bytes(stmt->ext_stmt, i))))
memcpy(stmt->bind[i].buffer, buf, s);
((char *)stmt->bind[i].buffer)[s]= 0;
break;
}
}
return 0;
}
my_bool s3_stmt_close(MYSQL_STMT *stmt)
{
int rc= sqlite3_finalize(stmt->ext_stmt);
return (rc == SQLITE_OK) ? 0 : 1;
}
int
s3_db_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
size_t length, my_bool skipp_check, void *opt_arg)
{
int rc= 1;
switch (command) {
case MYSQL_COM_QUERY:
rc= s3_query(mysql, arg, length);
break;
case MYSQL_COM_STMT_PREPARE:
{
MYSQL_STMT *stmt= (MYSQL_STMT *)opt_arg;
rc= s3_stmt_prepare(stmt, arg, length);
}
break;
case MYSQL_COM_STMT_EXECUTE:
{
MYSQL_STMT *stmt= (MYSQL_STMT *)opt_arg;
rc= s3_stmt_execute(stmt);
}
break;
case MYSQL_COM_STMT_CLOSE:
{
MYSQL_STMT *stmt= (MYSQL_STMT *)opt_arg;
s3_stmt_close(stmt);
}
break;
case MYSQL_COM_STMT_RESET:
{
MYSQL_STMT *stmt= (MYSQL_STMT *)opt_arg;
sqlite3_reset(stmt->ext_stmt);
}
break;
default:
if (!opt_arg)
my_set_error(mysql, CR_PLUGIN_FUNCTION_NOT_SUPPORTED, SQLSTATE_UNKNOWN, 0);
else
SET_CLIENT_STMT_ERROR((MYSQL_STMT *)opt_arg, CR_PLUGIN_FUNCTION_NOT_SUPPORTED, SQLSTATE_UNKNOWN, 0);
break;
}
return rc;
}
int s3_read_query_result(MYSQL *mysql)
{
int rc;
MARIADB_DB_DRIVER *s3_driver= mysql->options.extension->db_driver;
MARIADB_SQLT *db= (MARIADB_SQLT *)s3_driver->buffer;
mysql->field_count= sqlite3_column_count(db->stmt);
rc= sqlite3_step(db->stmt);
switch(rc) {
case SQLITE_ERROR:
case SQLITE_MISUSE:
case SQLITE_BUSY:
my_set_error(mysql, sqlite3_errcode(db->db), SQLSTATE_UNKNOWN, sqlite3_errmsg(db->db));
sqlite3_finalize(db->stmt);
db->stmt= NULL;
rc= 1;
break;
case SQLITE_ROW:
db->status= S3_RESULT_WAIT;
mysql->status = MYSQL_STATUS_GET_RESULT;
mysql->fields= s3_get_fields(mysql, db->stmt);
mysql->affected_rows= 0;
rc= 0;
break;
case SQLITE_DONE: /* no rows returned */
mysql->affected_rows= sqlite3_changes(db->db);
mysql->insert_id= sqlite3_last_insert_rowid(db->db);
mysql->status=MYSQL_STATUS_READY;
if (!mysql->field_count)
{
sqlite3_finalize(db->stmt);
db->stmt= NULL;
}
rc= 0;
break;
}
return rc;
}
my_bool s3_get_param_metadata(MYSQL_STMT *stmt)
{
return 0;
}
my_bool s3_get_result_metadata(MYSQL_STMT *stmt)
{
if (!(stmt->fields= s3_get_fields(stmt->mysql, stmt->ext_stmt)))
return 1;
return 0;
}
int s3_read_all_stmt_rows(MYSQL_STMT *stmt)
{
SET_CLIENT_STMT_ERROR(stmt, CR_PLUGIN_FUNCTION_NOT_SUPPORTED, SQLSTATE_UNKNOWN, 0);
return 1;
}
void s3_stmt_flush_unbuffered(MYSQL_STMT *stmt)
{
sqlite3_reset(stmt->ext_stmt);
}
int s3_read_stmt_result(MYSQL *mysql)
{
/* nothing to do */
return 0;
}
typedef struct st_mariadb_client_plugin_DB dbapi_plugin_t;
struct st_mysql_methods s3_methods = {
s3_connect,
s3_close,
s3_db_command,
s3_skip_result,
s3_read_query_result,
s3_read_all_rows,
s3_read_one_row,
s3_supported_buffer_type,
s3_read_prepare_response,
s3_read_stmt_result,
s3_get_result_metadata,
s3_get_param_metadata,
s3_read_all_stmt_rows,
s3_stmt_fetch,
s3_stmt_fetch_to_bind
};
dbapi_plugin_t sqlite3_plugin=
{
MYSQL_CLIENT_DB_PLUGIN,
MYSQL_CLIENT_DB_PLUGIN_INTERFACE_VERSION,
"sqlite",
"Georg Richter",
"Sqlite3 plugin for MariaDB client library",
{1, 0, 0},
NULL,
NULL,
&s3_methods
};

View File

@@ -21,7 +21,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/unittest/mytap)
SET(API_TESTS "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
"sp" "result" "connection" "misc" "ssl" "ps_new")
"sp" "result" "connection" "misc" "ssl" "ps_new" "sqlite3")
FOREACH(API_TEST ${API_TESTS})
ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)

View File

@@ -33,6 +33,7 @@ static int basic_connect(MYSQL *mysql)
{
MYSQL_ROW row;
MYSQL_RES *res;
MYSQL_FIELD *field;
int rc;
MYSQL *my= mysql_init(NULL);
@@ -45,6 +46,7 @@ static int basic_connect(MYSQL *mysql)
check_mysql_rc(rc, my);
res= mysql_store_result(my);
field= mysql_fetch_fields(res);
FAIL_IF(!res, mysql_error(my));
while ((row= mysql_fetch_row(res)) != NULL)

View File

@@ -815,7 +815,7 @@ struct my_tests_st my_tests[] = {
{"test_bug29692", test_bug29692, TEST_CONNECTION_NEW, CLIENT_FOUND_ROWS, NULL, NULL},
{"test_bug31418", test_bug31418, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_bug6081", test_bug6081, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_frm_bug", test_frm_bug, TEST_CONNECTION_NEW, 0, NULL, NULL},
// {"test_frm_bug", test_frm_bug, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_wl4166_1", test_wl4166_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_wl4166_2", test_wl4166_2, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_wl4166_3", test_wl4166_3, TEST_CONNECTION_NEW, 0, NULL, NULL},

View File

@@ -365,13 +365,14 @@ int check_variable(MYSQL *mysql, char *variable, char *value)
MYSQL *test_connect(struct my_tests_st *test) {
MYSQL *mysql;
char query[255];
int i= 1;
if (!(mysql = mysql_init(NULL))) {
diag("%s", "mysql_init failed - exiting");
return(NULL);
}
mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, "1");
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&i);
/* option handling */
if (test && test->options) {
@@ -388,9 +389,8 @@ MYSQL *test_connect(struct my_tests_st *test) {
i++;
}
}
if (!(mysql_real_connect(mysql, hostname, username, password,
NULL, port, socketname, (test) ? test->connect_flags:0)))
schema, port, socketname, (test) ? test->connect_flags:0)))
{
diag("Couldn't establish connection to server %s. Error (%d): %s",
hostname, mysql_errno(mysql), mysql_error(mysql));

View File

@@ -3709,6 +3709,55 @@ static int test_bug53311(MYSQL *mysql)
return OK;
}
#define PREPARE_SQL "EXPLAIN SELECT t1.*, t2.* FROM test AS t1, test AS t2"
static int test_metadata(MYSQL *mysql)
{
int rc;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE test(id INT, label CHAR(1), PRIMARY KEY(id)) ENGINE=MYISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO test(id, label) VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')");
check_mysql_rc(rc, mysql);
printf("Client=%s\n", mysql_get_client_info());
printf("Server=%s\n", mysql_get_server_info(mysql));
{
MYSQL_STMT * stmt = mysql_stmt_init(mysql);
if (!stmt) {
fprintf(stderr, "Failed to init stmt: Error: %s\n", mysql_error(mysql));
goto end;
}
if (mysql_stmt_prepare(stmt, PREPARE_SQL, sizeof(PREPARE_SQL) - 1)) {
fprintf(stderr, "Failed to prepare stmt: Error: %s\n", mysql_stmt_error(stmt));
goto end2;
}
if (mysql_stmt_execute(stmt)) {
fprintf(stderr, "Failed to execute stmt: Error: %s\n", mysql_stmt_error(stmt));
goto end2;
}
{
MYSQL_FIELD * field = NULL;
MYSQL_RES * res = mysql_stmt_result_metadata(stmt);
if (!res) {
fprintf(stderr, "Failed to get metadata: Error: %s\n", mysql_stmt_error(stmt));
goto end2;
}
while ((field = mysql_fetch_field(res))) {
printf("name=%s\n", field->name);
printf("catalog=%s\n", field->catalog);
}
mysql_free_result(res);
}
end2:
mysql_stmt_close(stmt);
}
end:
return 0;
}
static int test_conc_5(MYSQL *mysql)
{

View File

@@ -215,7 +215,6 @@ static int test_ssl_threads(MYSQL *mysql)
static int test_phpbug51647(MYSQL *my)
{
int rc;
MYSQL* mysql;
if (check_skip_ssl())