mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
mysql: refactor, comments, simplify (#18258)
This commit is contained in:
parent
010a5c26a0
commit
351b2e0e42
@ -14,9 +14,9 @@ struct C.MYSQL_FIELD {
|
||||
org_name &u8 // Original column name, if an alias
|
||||
table &u8 // Table of column if column was a field
|
||||
org_table &u8 // Org table name, if table was an alias
|
||||
db &u8 // Database for table
|
||||
db &u8 // Name of the database that the field comes from
|
||||
catalog &u8 // Catalog for table
|
||||
def &u8 // Default value (set by mysql_list_fields)
|
||||
def &u8 // Default value (set by `mysql_list_fields`)
|
||||
length int // Width of column (create length)
|
||||
max_length int // Max width for selected set
|
||||
name_length u32
|
||||
@ -26,78 +26,134 @@ struct C.MYSQL_FIELD {
|
||||
db_length u32
|
||||
catalog_length u32
|
||||
def_length u32
|
||||
flags u32 // Div flags
|
||||
flags u32 // Bit-flags that describe the field
|
||||
decimals u32 // Number of decimals in field
|
||||
charsetnr u32 // Character set
|
||||
@type int // Type of field. See mysql_com.h for types
|
||||
@type int // Type of field. See enums.v for types
|
||||
}
|
||||
|
||||
// C.mysql_init allocates or initializes a MYSQL object suitable for `mysql_real_connect()`.
|
||||
fn C.mysql_init(mysql &C.MYSQL) &C.MYSQL
|
||||
|
||||
// C.mysql_real_connect attempts to establish a connection to a MySQL server running on `host`.
|
||||
fn C.mysql_real_connect(mysql &C.MYSQL, host &char, user &char, passwd &char, db &char, port u32, unix_socket &char, client_flag ConnectionFlag) &C.MYSQL
|
||||
|
||||
// C.mysql_query executes the SQL statement pointed to by the null-terminated string `stmt_str`.
|
||||
fn C.mysql_query(mysql &C.MYSQL, q &u8) int
|
||||
|
||||
// C.mysql_use_result initiates a result set retrieval but does not actually read
|
||||
// the result set into the client like `mysql_store_result()` does.
|
||||
fn C.mysql_use_result(mysql &C.MYSQL)
|
||||
|
||||
// C.mysql_real_query executes the SQL statement pointed to by `stmt_str`,
|
||||
// a string length bytes long.
|
||||
fn C.mysql_real_query(mysql &C.MYSQL, q &u8, len u32) int
|
||||
|
||||
// C.mysql_select_db causes the database specified by `db` to become
|
||||
// the default (current) database on the connection specified by mysql.
|
||||
fn C.mysql_select_db(mysql &C.MYSQL, db &u8) int
|
||||
|
||||
// C.mysql_change_user changes the user and causes the database specified by `db` to become
|
||||
// the default (current) database on the connection specified by `mysql`.
|
||||
fn C.mysql_change_user(mysql &C.MYSQL, user &u8, password &u8, db &u8) bool
|
||||
|
||||
// C.mysql_affected_rows returns the number of rows changed, deleted,
|
||||
// or inserted by the last statement if it was an `UPDATE`, `DELETE`, or `INSERT`.
|
||||
fn C.mysql_affected_rows(mysql &C.MYSQL) u64
|
||||
|
||||
// C.mysql_options sets extra connect options and affects behavior for a connection.
|
||||
fn C.mysql_options(mysql &C.MYSQL, option int, arg voidptr) int
|
||||
|
||||
// C.mysql_get_option returns the current value of an option settable using `mysql_options()`.
|
||||
fn C.mysql_get_option(mysql &C.MYSQL, option int, arg voidptr) int
|
||||
|
||||
// C.mysql_list_tables returns a result set consisting of table names in the current database
|
||||
// that match the simple regular expression specified by the `wild` parameter.
|
||||
// `wild` may contain the wildcard characters `%` or `_`,
|
||||
// or may be a `NULL` pointer to match all tables.
|
||||
fn C.mysql_list_tables(mysql &C.MYSQL, wild &u8) &C.MYSQL_RES
|
||||
|
||||
// C.mysql_num_fields returns the number of columns in a result set.
|
||||
fn C.mysql_num_fields(res &C.MYSQL_RES) int
|
||||
|
||||
// C.mysql_num_rows returns the number of rows in the result set.
|
||||
fn C.mysql_num_rows(res &C.MYSQL_RES) u64
|
||||
|
||||
// C.mysql_autocommit sets autocommit mode on if `mode` is 1, off if `mode` is 0.
|
||||
fn C.mysql_autocommit(mysql &C.MYSQL, mode bool)
|
||||
|
||||
// C.mysql_refresh flush tables or caches, or resets replication server information.
|
||||
fn C.mysql_refresh(mysql &C.MYSQL, options u32) int
|
||||
|
||||
// C.mysql_reset_connection resets the connection to clear the session state.
|
||||
fn C.mysql_reset_connection(mysql &C.MYSQL) int
|
||||
|
||||
// C.mysql_ping checks whether the connection to the server is working.
|
||||
// Returns zero if the connection to the server is active. Nonzero if an error occurred.
|
||||
fn C.mysql_ping(mysql &C.MYSQL) int
|
||||
|
||||
// C.mysql_store_result reads the entire result of a query to the client,
|
||||
// allocates a `MYSQL_RES` structure, and places the result into this structure.
|
||||
// It is a synchronous function.
|
||||
fn C.mysql_store_result(mysql &C.MYSQL) &C.MYSQL_RES
|
||||
|
||||
// C.mysql_fetch_row retrieves the next row of a result set.
|
||||
fn C.mysql_fetch_row(res &C.MYSQL_RES) &&u8
|
||||
|
||||
// C.mysql_fetch_fields returns an array of all `MYSQL_FIELD` structures for a result set.
|
||||
// Each structure provides the field definition for one column of the result set.
|
||||
fn C.mysql_fetch_fields(res &C.MYSQL_RES) &C.MYSQL_FIELD
|
||||
|
||||
// C.mysql_free_result frees the memory allocated for a result set by `mysql_store_result()`,
|
||||
// `mysql_use_result()`, `mysql_list_dbs()`, and so forth.
|
||||
fn C.mysql_free_result(res &C.MYSQL_RES)
|
||||
|
||||
// C.mysql_real_escape_string creates a legal SQL string for use in an SQL statement.
|
||||
fn C.mysql_real_escape_string(mysql &C.MYSQL, to &u8, from &u8, len u64) u64
|
||||
|
||||
// fn C.mysql_real_escape_string_quote(mysql &C.MYSQL, to &byte, from &byte, len u64, quote byte) u64 (Don't exist in mariadb)
|
||||
|
||||
// C.mysql_close closes a previously opened connection.
|
||||
fn C.mysql_close(sock &C.MYSQL)
|
||||
|
||||
// INFO & VERSION
|
||||
// C.mysql_info retrieves a string providing information about the most recently executed statement.
|
||||
fn C.mysql_info(mysql &C.MYSQL) &u8
|
||||
|
||||
// C.mysql_get_host_info returns a string describing the type of connection in use,
|
||||
// including the server host name.
|
||||
fn C.mysql_get_host_info(mysql &C.MYSQL) &u8
|
||||
|
||||
// C.mysql_get_server_info returns a string that represents
|
||||
// the MySQL server version (for example, "8.0.33").
|
||||
fn C.mysql_get_server_info(mysql &C.MYSQL) &u8
|
||||
|
||||
// C.mysql_get_server_version returns an integer that represents the MySQL server version.
|
||||
// The value has the format `XYYZZ` where `X` is the major version,
|
||||
// `YY` is the release level (or minor version),
|
||||
// and `ZZ` is the sub-version within the release level:
|
||||
// `major_version*10000 + release_level*100 + sub_version`
|
||||
// For example, "8.0.33" is returned as 80033.
|
||||
fn C.mysql_get_server_version(mysql &C.MYSQL) u64
|
||||
|
||||
// C.mysql_get_client_version returns an integer that represents the MySQL client library version.
|
||||
// The value has the format `XYYZZ` where `X` is the major version,
|
||||
// `YY` is the release level (or minor version),
|
||||
// and `ZZ` is the sub-version within the release level:
|
||||
// `major_version*10000 + release_level*100 + sub_version`
|
||||
// For example, "8.0.33" is returned as 80033.
|
||||
fn C.mysql_get_client_version() u64
|
||||
|
||||
// C.mysql_get_client_info returns a string that represents
|
||||
// the MySQL client library version (for example, "8.0.33").
|
||||
fn C.mysql_get_client_info() &u8
|
||||
|
||||
// DEBUG & ERROR INFO
|
||||
// C.mysql_error returns a null-terminated string containing the error message
|
||||
// for the most recently invoked API function that failed.
|
||||
fn C.mysql_error(mysql &C.MYSQL) &u8
|
||||
|
||||
// C.mysql_errno returns the error code for the most recently invoked API function that can succeed or fail.
|
||||
fn C.mysql_errno(mysql &C.MYSQL) int
|
||||
|
||||
// C.mysql_dump_debug_info instructs the server to write debugging information to the error log.
|
||||
fn C.mysql_dump_debug_info(mysql &C.MYSQL) int
|
||||
|
||||
// C.mysql_debug does a `DBUG_PUSH` with the given string.
|
||||
fn C.mysql_debug(debug &u8)
|
||||
|
@ -1,6 +1,7 @@
|
||||
module mysql
|
||||
|
||||
// Need to check if mysqlclient is not there and use mariadb as alternative because newer system doesn't support mysql 8.0 as default
|
||||
// Need to check if `mysqlclient` is not there and use `mariadb` as alternative
|
||||
// because newer system doesn't support mysql 8.0 as default.
|
||||
|
||||
$if $pkgconfig('mysqlclient') {
|
||||
#pkgconfig mysqlclient
|
||||
|
@ -1,6 +1,7 @@
|
||||
module mysql
|
||||
|
||||
// MYSQL REFRESH FLAGS
|
||||
// MySQL refresh flags.
|
||||
// Docs: https://dev.mysql.com/doc/c-api/8.0/en/mysql-refresh.html
|
||||
pub const (
|
||||
refresh_grant = u32(C.REFRESH_GRANT)
|
||||
refresh_log = u32(C.REFRESH_LOG)
|
||||
|
@ -1,6 +1,6 @@
|
||||
module mysql
|
||||
|
||||
// FieldType is a list of all supported MYSQL field types
|
||||
// FieldType is a list of all supported MYSQL field types.
|
||||
pub enum FieldType {
|
||||
type_decimal
|
||||
type_tiny
|
||||
@ -35,7 +35,7 @@ pub enum FieldType {
|
||||
type_geometry
|
||||
}
|
||||
|
||||
// str returns a text representation of the field type `f`
|
||||
// str returns a text representation of the field type `f`.
|
||||
pub fn (f FieldType) str() string {
|
||||
return match f {
|
||||
.type_decimal { 'decimal' }
|
||||
@ -72,7 +72,8 @@ pub fn (f FieldType) str() string {
|
||||
}
|
||||
}
|
||||
|
||||
// get_len returns the length in bytes, for the given field type `f`
|
||||
// get_len returns the length in bytes, for the given field type `f`.
|
||||
// Should be deleted after the `time` type reimplementation.
|
||||
pub fn (f FieldType) get_len() u32 {
|
||||
return match f {
|
||||
.type_blob { 262140 }
|
||||
|
@ -3,7 +3,6 @@ module mysql
|
||||
// Values for the capabilities flag bitmask used by the MySQL protocol.
|
||||
// See more on https://dev.mysql.com/doc/dev/mysql-server/latest/group__group__cs__capabilities__flags.html#details
|
||||
pub enum ConnectionFlag {
|
||||
// CAN_HANDLE_EXPIRED_PASSWORDS = C.CAN_HANDLE_EXPIRED_PASSWORDS
|
||||
client_compress = C.CLIENT_COMPRESS
|
||||
client_found_rows = C.CLIENT_FOUND_ROWS
|
||||
client_ignore_sigpipe = C.CLIENT_IGNORE_SIGPIPE
|
||||
@ -14,7 +13,6 @@ pub enum ConnectionFlag {
|
||||
client_multi_statements = C.CLIENT_MULTI_STATEMENTS
|
||||
client_no_schema = C.CLIENT_NO_SCHEMA
|
||||
client_odbc = C.CLIENT_ODBC
|
||||
// client_optional_resultset_metadata = C.CLIENT_OPTIONAL_RESULTSET_METADATA
|
||||
client_ssl = C.CLIENT_SSL
|
||||
client_remember_options = C.CLIENT_REMEMBER_OPTIONS
|
||||
}
|
||||
@ -23,7 +21,6 @@ struct SQLError {
|
||||
MessageError
|
||||
}
|
||||
|
||||
// TODO: Documentation
|
||||
pub struct Connection {
|
||||
mut:
|
||||
conn &C.MYSQL = C.mysql_init(0)
|
||||
@ -36,29 +33,32 @@ pub mut:
|
||||
flag ConnectionFlag
|
||||
}
|
||||
|
||||
// connect - create a new connection to the MySQL server.
|
||||
// connect attempts to establish a connection to a MySQL server.
|
||||
pub fn (mut conn Connection) connect() !bool {
|
||||
instance := C.mysql_init(conn.conn)
|
||||
conn.conn = C.mysql_real_connect(instance, conn.host.str, conn.username.str, conn.password.str,
|
||||
conn.dbname.str, conn.port, 0, conn.flag)
|
||||
|
||||
if isnil(conn.conn) {
|
||||
return error_with_code(get_error_msg(instance), get_errno(instance))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// query - make an SQL query and receive the results.
|
||||
// `query()` cannot be used for statements that contain binary data;
|
||||
// query executes the SQL statement pointed to by the string `q`.
|
||||
// It cannot be used for statements that contain binary data;
|
||||
// Use `real_query()` instead.
|
||||
pub fn (conn Connection) query(q string) !Result {
|
||||
if C.mysql_query(conn.conn, q.str) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
res := C.mysql_store_result(conn.conn)
|
||||
return Result{res}
|
||||
|
||||
result := C.mysql_store_result(conn.conn)
|
||||
return Result{result}
|
||||
}
|
||||
|
||||
// use_result - reads the result of a query
|
||||
// use_result reads the result of a query
|
||||
// used after invoking mysql_real_query() or mysql_query(),
|
||||
// for every statement that successfully produces a result set
|
||||
// (SELECT, SHOW, DESCRIBE, EXPLAIN, CHECK TABLE, and so forth).
|
||||
@ -70,7 +70,7 @@ pub fn (conn Connection) use_result() {
|
||||
C.mysql_use_result(conn.conn)
|
||||
}
|
||||
|
||||
// real_query - make an SQL query and receive the results.
|
||||
// real_query makes an SQL query and receive the results.
|
||||
// `real_query()` can be used for statements containing binary data.
|
||||
// (Binary data may contain the `\0` character, which `query()`
|
||||
// interprets as the end of the statement string). In addition,
|
||||
@ -79,65 +79,73 @@ pub fn (mut conn Connection) real_query(q string) !Result {
|
||||
if C.mysql_real_query(conn.conn, q.str, q.len) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
res := C.mysql_store_result(conn.conn)
|
||||
return Result{res}
|
||||
|
||||
result := C.mysql_store_result(conn.conn)
|
||||
return Result{result}
|
||||
}
|
||||
|
||||
// select_db - change the default database for database queries.
|
||||
// select_db causes the database specified by `db` to become
|
||||
// the default (current) database on the connection specified by mysql.
|
||||
pub fn (mut conn Connection) select_db(dbname string) !bool {
|
||||
if C.mysql_select_db(conn.conn, dbname.str) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// change_user - change the mysql user for the connection.
|
||||
// change_user changes the mysql user for the connection.
|
||||
// Passing an empty string for the `dbname` parameter, resultsg in only changing
|
||||
// the user and not changing the default database for the connection.
|
||||
pub fn (mut conn Connection) change_user(username string, password string, dbname string) !bool {
|
||||
mut ret := true
|
||||
mut result := true
|
||||
|
||||
if dbname != '' {
|
||||
ret = C.mysql_change_user(conn.conn, username.str, password.str, dbname.str)
|
||||
result = C.mysql_change_user(conn.conn, username.str, password.str, dbname.str)
|
||||
} else {
|
||||
ret = C.mysql_change_user(conn.conn, username.str, password.str, 0)
|
||||
result = C.mysql_change_user(conn.conn, username.str, password.str, 0)
|
||||
}
|
||||
if !ret {
|
||||
if !result {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
return ret
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// affected_rows - return the number of rows changed/deleted/inserted
|
||||
// by the last `UPDATE`, `DELETE`, or `INSERT` query.
|
||||
// affected_rows returns the number of rows changed, deleted,
|
||||
// or inserted by the last statement if it was an `UPDATE`, `DELETE`, or `INSERT`.
|
||||
pub fn (conn &Connection) affected_rows() u64 {
|
||||
return C.mysql_affected_rows(conn.conn)
|
||||
}
|
||||
|
||||
// autocommit - turns on/off the auto-committing mode for the connection.
|
||||
// When it is on, then each query is commited right away.
|
||||
// autocommit turns on/off the auto-committing mode for the connection.
|
||||
// When it is on, then each query is committed right away.
|
||||
pub fn (mut conn Connection) autocommit(mode bool) {
|
||||
C.mysql_autocommit(conn.conn, mode)
|
||||
}
|
||||
|
||||
// tables - returns a list of the names of the tables in the current database,
|
||||
// tables returns a list of the names of the tables in the current database,
|
||||
// that match the simple regular expression specified by the `wildcard` parameter.
|
||||
// The `wildcard` parameter may contain the wildcard characters `%` or `_`.
|
||||
// If an empty string is passed, it will return all tables.
|
||||
// Calling `tables()` is similar to executing query `SHOW TABLES [LIKE wildcard]`.
|
||||
pub fn (conn &Connection) tables(wildcard string) ![]string {
|
||||
cres := C.mysql_list_tables(conn.conn, wildcard.str)
|
||||
if isnil(cres) {
|
||||
c_mysql_result := C.mysql_list_tables(conn.conn, wildcard.str)
|
||||
if isnil(c_mysql_result) {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
res := Result{cres}
|
||||
|
||||
result := Result{c_mysql_result}
|
||||
mut tables := []string{}
|
||||
for row in res.rows() {
|
||||
|
||||
for row in result.rows() {
|
||||
tables << row.vals[0]
|
||||
}
|
||||
|
||||
return tables
|
||||
}
|
||||
|
||||
// escape_string - creates a legal SQL string for use in an SQL statement.
|
||||
// escape_string creates a legal SQL string for use in an SQL statement.
|
||||
// The `s` argument is encoded to produce an escaped SQL string,
|
||||
// taking into account the current character set of the connection.
|
||||
pub fn (conn &Connection) escape_string(s string) string {
|
||||
@ -148,73 +156,77 @@ pub fn (conn &Connection) escape_string(s string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// set_option - sets extra connect options that affect the behavior of
|
||||
// set_option sets extra connect options that affect the behavior of
|
||||
// a connection. This function may be called multiple times to set several
|
||||
// options. To retrieve the current values for an option, use `get_option()`.
|
||||
pub fn (mut conn Connection) set_option(option_type int, val voidptr) {
|
||||
C.mysql_options(conn.conn, option_type, val)
|
||||
}
|
||||
|
||||
// get_option - return the value of an option, settable by `set_option`.
|
||||
// get_option returns the value of an option, settable by `set_option`.
|
||||
// https://dev.mysql.com/doc/c-api/5.7/en/mysql-get-option.html
|
||||
pub fn (conn &Connection) get_option(option_type int) !voidptr {
|
||||
ret := unsafe { nil }
|
||||
if C.mysql_get_option(conn.conn, option_type, &ret) != 0 {
|
||||
mysql_option := unsafe { nil }
|
||||
if C.mysql_get_option(conn.conn, option_type, &mysql_option) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
return ret
|
||||
|
||||
return mysql_option
|
||||
}
|
||||
|
||||
// refresh - flush the tables or caches, or resets replication server
|
||||
// refresh flush the tables or caches, or resets replication server
|
||||
// information. The connected user must have the `RELOAD` privilege.
|
||||
pub fn (mut conn Connection) refresh(options u32) !bool {
|
||||
if C.mysql_refresh(conn.conn, options) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// reset - resets the connection, and clear the session state.
|
||||
// reset resets the connection, and clear the session state.
|
||||
pub fn (mut conn Connection) reset() !bool {
|
||||
if C.mysql_reset_connection(conn.conn) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ping - pings a server connection, or tries to reconnect if the connection
|
||||
// ping pings a server connection, or tries to reconnect if the connection
|
||||
// has gone down.
|
||||
pub fn (mut conn Connection) ping() !bool {
|
||||
if C.mysql_ping(conn.conn) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// close - closes the connection.
|
||||
// close closes the connection.
|
||||
pub fn (mut conn Connection) close() {
|
||||
C.mysql_close(conn.conn)
|
||||
}
|
||||
|
||||
// info - returns information about the most recently executed query.
|
||||
// info returns information about the most recently executed query.
|
||||
// See more on https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html
|
||||
pub fn (conn &Connection) info() string {
|
||||
return resolve_nil_str(C.mysql_info(conn.conn))
|
||||
}
|
||||
|
||||
// get_host_info - returns a string describing the type of connection in use,
|
||||
// get_host_info returns a string describing the type of connection in use,
|
||||
// including the server host name.
|
||||
pub fn (conn &Connection) get_host_info() string {
|
||||
return unsafe { C.mysql_get_host_info(conn.conn).vstring() }
|
||||
}
|
||||
|
||||
// get_server_info - returns a string representing the MySQL server version.
|
||||
// get_server_info returns a string representing the MySQL server version.
|
||||
// For example, `8.0.24`.
|
||||
pub fn (conn &Connection) get_server_info() string {
|
||||
return unsafe { C.mysql_get_server_info(conn.conn).vstring() }
|
||||
}
|
||||
|
||||
// get_server_version - returns an integer, representing the MySQL server
|
||||
// get_server_version returns an integer, representing the MySQL server
|
||||
// version. The value has the format `XYYZZ` where `X` is the major version,
|
||||
// `YY` is the release level (or minor version), and `ZZ` is the sub-version
|
||||
// within the release level. For example, `8.0.24` is returned as `80024`.
|
||||
@ -222,26 +234,27 @@ pub fn (conn &Connection) get_server_version() u64 {
|
||||
return C.mysql_get_server_version(conn.conn)
|
||||
}
|
||||
|
||||
// dump_debug_info - instructs the server to write debugging information
|
||||
// dump_debug_info instructs the server to write debugging information
|
||||
// to the error log. The connected user must have the `SUPER` privilege.
|
||||
pub fn (mut conn Connection) dump_debug_info() !bool {
|
||||
if C.mysql_dump_debug_info(conn.conn) != 0 {
|
||||
return error_with_code(get_error_msg(conn.conn), get_errno(conn.conn))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// get_client_info - returns client version information as a string.
|
||||
// get_client_info returns client version information as a string.
|
||||
pub fn get_client_info() string {
|
||||
return unsafe { C.mysql_get_client_info().vstring() }
|
||||
}
|
||||
|
||||
// get_client_version - returns the client version information as an integer.
|
||||
// get_client_version returns the client version information as an integer.
|
||||
pub fn get_client_version() u64 {
|
||||
return C.mysql_get_client_version()
|
||||
}
|
||||
|
||||
// debug - does a `DBUG_PUSH` with the given string.
|
||||
// debug does a `DBUG_PUSH` with the given string.
|
||||
// `debug()` uses the Fred Fish debug library.
|
||||
// To use this function, you must compile the client library to support debugging.
|
||||
// See https://dev.mysql.com/doc/c-api/8.0/en/mysql-debug.html
|
||||
|
@ -3,54 +3,49 @@ module mysql
|
||||
import orm
|
||||
import time
|
||||
|
||||
// @select is used internally by V's ORM for processing `SELECT ` queries
|
||||
// @select is used internally by V's ORM for processing `SELECT ` queries.
|
||||
pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive {
|
||||
query := orm.orm_select_gen(config, '`', false, '?', 0, where)
|
||||
mut ret := [][]orm.Primitive{}
|
||||
mut result := [][]orm.Primitive{}
|
||||
mut stmt := db.init_stmt(query)
|
||||
stmt.prepare()!
|
||||
|
||||
mysql_stmt_binder(mut stmt, where)!
|
||||
mysql_stmt_binder(mut stmt, data)!
|
||||
mysql_stmt_bind_query_data(mut stmt, where)!
|
||||
mysql_stmt_bind_query_data(mut stmt, data)!
|
||||
|
||||
if data.data.len > 0 || where.data.len > 0 {
|
||||
stmt.bind_params()!
|
||||
}
|
||||
|
||||
mut status := stmt.execute()!
|
||||
num_fields := stmt.get_field_count()
|
||||
stmt.execute()!
|
||||
metadata := stmt.gen_metadata()
|
||||
fields := stmt.fetch_fields(metadata)
|
||||
mut dataptr := []&u8{}
|
||||
num_fields := stmt.get_field_count()
|
||||
mut data_pointers := []&u8{}
|
||||
|
||||
// Allocate memory for each column.
|
||||
for i in 0 .. num_fields {
|
||||
field := unsafe { fields[i] }
|
||||
match unsafe { FieldType(field.@type) } {
|
||||
.type_tiny {
|
||||
dataptr << unsafe { malloc(1) }
|
||||
data_pointers << unsafe { malloc(1) }
|
||||
}
|
||||
.type_short {
|
||||
dataptr << unsafe { malloc(2) }
|
||||
data_pointers << unsafe { malloc(2) }
|
||||
}
|
||||
.type_long {
|
||||
dataptr << unsafe { malloc(4) }
|
||||
.type_long, .type_float {
|
||||
data_pointers << unsafe { malloc(4) }
|
||||
}
|
||||
.type_longlong {
|
||||
dataptr << unsafe { malloc(8) }
|
||||
}
|
||||
.type_float {
|
||||
dataptr << unsafe { malloc(4) }
|
||||
}
|
||||
.type_double {
|
||||
dataptr << unsafe { malloc(8) }
|
||||
.type_longlong, .type_double {
|
||||
data_pointers << unsafe { malloc(8) }
|
||||
}
|
||||
.type_time, .type_date, .type_datetime, .type_time2, .type_datetime2 {
|
||||
dataptr << unsafe { malloc(sizeof(C.MYSQL_TIME)) }
|
||||
data_pointers << unsafe { malloc(sizeof(C.MYSQL_TIME)) }
|
||||
}
|
||||
.type_string, .type_var_string, .type_blob, .type_tiny_blob, .type_medium_blob,
|
||||
.type_long_blob {
|
||||
// Memory will be allocated later dynamically depending on the length of the value.
|
||||
dataptr << &u8(0)
|
||||
data_pointers << &u8(0)
|
||||
}
|
||||
else {
|
||||
return error('\'${unsafe { FieldType(field.@type) }}\' is not yet implemented. Please create a new issue at https://github.com/vlang/v/issues/new')
|
||||
@ -59,13 +54,14 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher
|
||||
}
|
||||
|
||||
lengths := []u32{len: int(num_fields), init: 0}
|
||||
stmt.bind_res(fields, dataptr, lengths, num_fields)
|
||||
stmt.bind_res(fields, data_pointers, lengths, num_fields)
|
||||
|
||||
mut types := config.types.clone()
|
||||
mut field_types := []FieldType{}
|
||||
if config.is_count {
|
||||
types = [orm.type_idx['u64']]
|
||||
}
|
||||
|
||||
// Map stores column indexes and their binds in order to extract values
|
||||
// for these columns separately, with individual memory allocation for each value.
|
||||
mut string_binds_map := map[int]C.MYSQL_BIND{}
|
||||
@ -85,6 +81,7 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher
|
||||
mysql_bind.buffer_type = C.MYSQL_TYPE_LONG
|
||||
}
|
||||
.type_time, .type_date, .type_datetime {
|
||||
// FIXME: Allocate memory for blobs dynamically.
|
||||
mysql_bind.buffer_type = C.MYSQL_TYPE_BLOB
|
||||
mysql_bind.buffer_length = FieldType.type_blob.get_len()
|
||||
}
|
||||
@ -102,37 +99,37 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher
|
||||
stmt.store_result()!
|
||||
|
||||
for {
|
||||
status = stmt.fetch_stmt()!
|
||||
// Fetch every row from the `select` result.
|
||||
status := stmt.fetch_stmt()!
|
||||
is_error := status == 1
|
||||
are_no_rows_to_fetch := status == mysql_no_data
|
||||
|
||||
if status == 1 || status == 100 {
|
||||
if is_error || are_no_rows_to_fetch {
|
||||
break
|
||||
}
|
||||
|
||||
// Fetch columns that should be allocated dynamically.
|
||||
for index, mut bind in string_binds_map {
|
||||
string_length := lengths[index] + 1
|
||||
dataptr[index] = unsafe { malloc(string_length) }
|
||||
bind.buffer = dataptr[index]
|
||||
data_pointers[index] = unsafe { malloc(string_length) }
|
||||
bind.buffer = data_pointers[index]
|
||||
bind.buffer_length = string_length
|
||||
bind.length = unsafe { nil }
|
||||
|
||||
stmt.fetch_column(bind, index)!
|
||||
}
|
||||
|
||||
data_list := buffer_to_primitive(dataptr, types, field_types)!
|
||||
ret << data_list
|
||||
result << data_pointers_to_primitives(data_pointers, types, field_types)!
|
||||
}
|
||||
|
||||
stmt.close()!
|
||||
|
||||
return ret
|
||||
return result
|
||||
}
|
||||
|
||||
// sql stmt
|
||||
|
||||
// insert is used internally by V's ORM for processing `INSERT ` queries
|
||||
pub fn (db Connection) insert(table string, data orm.QueryData) ! {
|
||||
mut converted_primitive_array := db.factory_orm_primitive_converted_from_sql(table,
|
||||
data)!
|
||||
mut converted_primitive_array := db.convert_query_data_to_primitives(table, data)!
|
||||
|
||||
converted_primitive_data := orm.QueryData{
|
||||
fields: data.fields
|
||||
@ -168,8 +165,6 @@ pub fn (db Connection) last_id() int {
|
||||
return id.rows()[0].vals[0].int()
|
||||
}
|
||||
|
||||
// DDL (table creation/destroying etc)
|
||||
|
||||
// create is used internally by V's ORM for processing table creation queries (DDL)
|
||||
pub fn (db Connection) create(table string, fields []orm.TableField) ! {
|
||||
query := orm.orm_table_gen(table, '`', true, 0, fields, mysql_type_from_v, false) or {
|
||||
@ -184,25 +179,33 @@ pub fn (db Connection) drop(table string) ! {
|
||||
mysql_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})!
|
||||
}
|
||||
|
||||
// mysql_stmt_worker executes the `query` with the provided `data` and `where` parameters
|
||||
// without returning the result.
|
||||
// This is commonly used for `INSERT`, `UPDATE`, `CREATE`, `DROP`, and `DELETE` queries.
|
||||
fn mysql_stmt_worker(db Connection, query string, data orm.QueryData, where orm.QueryData) ! {
|
||||
mut stmt := db.init_stmt(query)
|
||||
stmt.prepare()!
|
||||
mysql_stmt_binder(mut stmt, data)!
|
||||
mysql_stmt_binder(mut stmt, where)!
|
||||
|
||||
mysql_stmt_bind_query_data(mut stmt, data)!
|
||||
mysql_stmt_bind_query_data(mut stmt, where)!
|
||||
|
||||
if data.data.len > 0 || where.data.len > 0 {
|
||||
stmt.bind_params()!
|
||||
}
|
||||
|
||||
stmt.execute()!
|
||||
stmt.close()!
|
||||
}
|
||||
|
||||
fn mysql_stmt_binder(mut stmt Stmt, d orm.QueryData) ! {
|
||||
// mysql_stmt_bind_query_data binds all the fields of `q` to the `stmt`.
|
||||
fn mysql_stmt_bind_query_data(mut stmt Stmt, d orm.QueryData) ! {
|
||||
for data in d.data {
|
||||
stmt_binder_match(mut stmt, data)
|
||||
stmt_bind_primitive(mut stmt, data)
|
||||
}
|
||||
}
|
||||
|
||||
fn stmt_binder_match(mut stmt Stmt, data orm.Primitive) {
|
||||
// stmt_bind_primitive binds the `data` to the `stmt`.
|
||||
fn stmt_bind_primitive(mut stmt Stmt, data orm.Primitive) {
|
||||
match data {
|
||||
bool {
|
||||
stmt.bind_bool(&data)
|
||||
@ -242,18 +245,20 @@ fn stmt_binder_match(mut stmt Stmt, data orm.Primitive) {
|
||||
}
|
||||
time.Time {
|
||||
unix := int(data.unix)
|
||||
stmt_binder_match(mut stmt, unix)
|
||||
stmt_bind_primitive(mut stmt, unix)
|
||||
}
|
||||
orm.InfixType {
|
||||
stmt_binder_match(mut stmt, data.right)
|
||||
stmt_bind_primitive(mut stmt, data.right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn buffer_to_primitive(data_list []&u8, types []int, field_types []FieldType) ![]orm.Primitive {
|
||||
mut res := []orm.Primitive{}
|
||||
// data_pointers_to_primitives returns an array of `Primitive`
|
||||
// cast from `data_pointers` using `types`.
|
||||
fn data_pointers_to_primitives(data_pointers []&u8, types []int, field_types []FieldType) ![]orm.Primitive {
|
||||
mut result := []orm.Primitive{}
|
||||
|
||||
for i, data in data_list {
|
||||
for i, data in data_pointers {
|
||||
mut primitive := orm.Primitive(0)
|
||||
match types[i] {
|
||||
orm.type_idx['i8'] {
|
||||
@ -309,14 +314,15 @@ fn buffer_to_primitive(data_list []&u8, types []int, field_types []FieldType) ![
|
||||
return error('Unknown type ${types[i]}')
|
||||
}
|
||||
}
|
||||
res << primitive
|
||||
result << primitive
|
||||
}
|
||||
|
||||
return res
|
||||
return result
|
||||
}
|
||||
|
||||
// mysql_type_from_v converts the V type to the corresponding MySQL type.
|
||||
fn mysql_type_from_v(typ int) !string {
|
||||
str := match typ {
|
||||
sql_type := match typ {
|
||||
orm.type_idx['i8'], orm.type_idx['u8'] {
|
||||
'TINYINT'
|
||||
}
|
||||
@ -345,48 +351,48 @@ fn mysql_type_from_v(typ int) !string {
|
||||
'BOOLEAN'
|
||||
}
|
||||
else {
|
||||
''
|
||||
return error('Unknown type ${typ}')
|
||||
}
|
||||
}
|
||||
if str == '' {
|
||||
return error('Unknown type ${typ}')
|
||||
}
|
||||
return str
|
||||
|
||||
return sql_type
|
||||
}
|
||||
|
||||
fn (db Connection) factory_orm_primitive_converted_from_sql(table string, data orm.QueryData) ![]orm.Primitive {
|
||||
mut map_val := db.get_table_data_type_map(table)!
|
||||
|
||||
// adapt v type to sql time
|
||||
// convert_query_data_to_primitives converts the `data` representing the `QueryData`
|
||||
// into an array of `Primitive`.
|
||||
fn (db Connection) convert_query_data_to_primitives(table string, data orm.QueryData) ![]orm.Primitive {
|
||||
mut column_type_map := db.get_table_column_type_map(table)!
|
||||
mut converted_data := []orm.Primitive{}
|
||||
|
||||
for i, field in data.fields {
|
||||
match data.data[i].type_name() {
|
||||
'time.Time' {
|
||||
if map_val[field] == 'datetime' {
|
||||
converted_data << orm.Primitive((data.data[i] as time.Time).str())
|
||||
} else {
|
||||
converted_data << data.data[i]
|
||||
}
|
||||
}
|
||||
else {
|
||||
if data.data[i].type_name() == 'time.Time' {
|
||||
if column_type_map[field] == 'datetime' {
|
||||
converted_data << orm.Primitive((data.data[i] as time.Time).str())
|
||||
} else {
|
||||
converted_data << data.data[i]
|
||||
}
|
||||
} else {
|
||||
converted_data << data.data[i]
|
||||
}
|
||||
}
|
||||
|
||||
return converted_data
|
||||
}
|
||||
|
||||
fn (db Connection) get_table_data_type_map(table string) !map[string]string {
|
||||
data_type_querys := "SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '${table}'"
|
||||
mut map_val := map[string]string{}
|
||||
// get_table_column_type_map returns a map where the key represents the column name,
|
||||
// and the value represents its data type.
|
||||
fn (db Connection) get_table_column_type_map(table string) !map[string]string {
|
||||
data_type_query := "SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '${table}'"
|
||||
mut column_type_map := map[string]string{}
|
||||
results := db.query(data_type_query)!
|
||||
|
||||
results := db.query(data_type_querys)!
|
||||
db.use_result()
|
||||
|
||||
for row in results.rows() {
|
||||
map_val[row.vals[0]] = row.vals[1]
|
||||
column_type_map[row.vals[0]] = row.vals[1]
|
||||
}
|
||||
|
||||
unsafe { results.free() }
|
||||
return map_val
|
||||
|
||||
return column_type_map
|
||||
}
|
||||
|
@ -32,22 +32,22 @@ pub struct Field {
|
||||
type_ FieldType
|
||||
}
|
||||
|
||||
// fetch_row - fetches the next row from a result.
|
||||
// fetch_row fetches the next row from a result.
|
||||
pub fn (r Result) fetch_row() &&u8 {
|
||||
return C.mysql_fetch_row(r.result)
|
||||
}
|
||||
|
||||
// n_rows - returns the number of rows from a result.
|
||||
// n_rows returns the number of rows from a result.
|
||||
pub fn (r Result) n_rows() u64 {
|
||||
return C.mysql_num_rows(r.result)
|
||||
}
|
||||
|
||||
// n_fields - returns the number of columns from a result.
|
||||
// n_fields returns the number of columns from a result.
|
||||
pub fn (r Result) n_fields() int {
|
||||
return C.mysql_num_fields(r.result)
|
||||
}
|
||||
|
||||
// rows - returns array of rows, each containing an array of values,
|
||||
// rows returns array of rows, each containing an array of values,
|
||||
// one for each column.
|
||||
pub fn (r Result) rows() []Row {
|
||||
mut rows := []Row{}
|
||||
@ -66,7 +66,7 @@ pub fn (r Result) rows() []Row {
|
||||
return rows
|
||||
}
|
||||
|
||||
// maps - returns an array of maps, each containing a set of
|
||||
// maps returns an array of maps, each containing a set of
|
||||
// field name: field value pairs.
|
||||
pub fn (r Result) maps() []map[string]string {
|
||||
mut array_map := []map[string]string{}
|
||||
@ -82,7 +82,7 @@ pub fn (r Result) maps() []map[string]string {
|
||||
return array_map
|
||||
}
|
||||
|
||||
// fields - returns an array of fields/columns.
|
||||
// fields returns an array of fields/columns.
|
||||
// The definitions apply primarily for columns of results,
|
||||
// such as those produced by `SELECT` statements.
|
||||
pub fn (r Result) fields() []Field {
|
||||
@ -118,7 +118,7 @@ pub fn (r Result) fields() []Field {
|
||||
return fields
|
||||
}
|
||||
|
||||
// str - serializes the field
|
||||
// str serializes the field.
|
||||
pub fn (f Field) str() string {
|
||||
return '
|
||||
{
|
||||
@ -146,7 +146,7 @@ pub fn (f Field) str() string {
|
||||
'
|
||||
}
|
||||
|
||||
// free - frees the memory used by a result
|
||||
// free frees the memory used by a result.
|
||||
[unsafe]
|
||||
pub fn (r &Result) free() {
|
||||
C.mysql_free_result(r.result)
|
||||
|
@ -71,12 +71,12 @@ mut:
|
||||
res []C.MYSQL_BIND
|
||||
}
|
||||
|
||||
// str returns a text representation of the given mysql statement `s`
|
||||
// str returns a text representation of the given mysql statement `s`.
|
||||
pub fn (s &Stmt) str() string {
|
||||
return 'mysql.Stmt{ stmt: ${voidptr(s.stmt):x}, query: `${s.query}`, binds.len: ${s.binds.len}, res.len: ${s.res.len} }'
|
||||
}
|
||||
|
||||
// init_stmt creates a new statement, given the `query`
|
||||
// init_stmt creates a new statement, given the `query`.
|
||||
pub fn (db Connection) init_stmt(query string) Stmt {
|
||||
return Stmt{
|
||||
stmt: C.mysql_stmt_init(db.conn)
|
||||
@ -85,38 +85,44 @@ pub fn (db Connection) init_stmt(query string) Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
// prepare a statement for execution
|
||||
// prepare a statement for execution.
|
||||
pub fn (stmt Stmt) prepare() ! {
|
||||
res := C.mysql_stmt_prepare(stmt.stmt, stmt.query.str, stmt.query.len)
|
||||
if res != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(res)
|
||||
result := C.mysql_stmt_prepare(stmt.stmt, stmt.query.str, stmt.query.len)
|
||||
|
||||
if result != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(result)
|
||||
}
|
||||
}
|
||||
|
||||
// bind_params binds all the parameters in `stmt`
|
||||
// bind_params binds all the parameters in `stmt`.
|
||||
pub fn (stmt Stmt) bind_params() ! {
|
||||
res := C.mysql_stmt_bind_param(stmt.stmt, unsafe { &C.MYSQL_BIND(stmt.binds.data) })
|
||||
if res && stmt.get_error_msg() != '' {
|
||||
result := C.mysql_stmt_bind_param(stmt.stmt, unsafe { &C.MYSQL_BIND(stmt.binds.data) })
|
||||
|
||||
if result && stmt.get_error_msg() != '' {
|
||||
return stmt.error(1)
|
||||
}
|
||||
}
|
||||
|
||||
// execute executes the given `stmt` and waits for the result
|
||||
// execute executes the given `stmt` and waits for the result.
|
||||
pub fn (stmt Stmt) execute() !int {
|
||||
res := C.mysql_stmt_execute(stmt.stmt)
|
||||
if res != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(res)
|
||||
result := C.mysql_stmt_execute(stmt.stmt)
|
||||
|
||||
if result != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(result)
|
||||
}
|
||||
return res
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// next retrieves the next available result from the execution of `stmt`
|
||||
pub fn (stmt Stmt) next() !int {
|
||||
res := C.mysql_stmt_next_result(stmt.stmt)
|
||||
if res > 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(res)
|
||||
result := C.mysql_stmt_next_result(stmt.stmt)
|
||||
|
||||
if result != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(result)
|
||||
}
|
||||
return res
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// gen_metadata executes mysql_stmt_result_metadata over the given `stmt`
|
||||
@ -136,11 +142,13 @@ pub fn (stmt Stmt) fetch_fields(res &C.MYSQL_RES) &C.MYSQL_FIELD {
|
||||
// fetch_stmt fetches the next row in the result set. It returns the status of the execution of mysql_stmt_fetch .
|
||||
// See https://dev.mysql.com/doc/c-api/5.7/en/mysql-stmt-fetch.html
|
||||
pub fn (stmt Stmt) fetch_stmt() !int {
|
||||
res := C.mysql_stmt_fetch(stmt.stmt)
|
||||
if res !in [0, 100] && stmt.get_error_msg() != '' {
|
||||
return stmt.error(res)
|
||||
result := C.mysql_stmt_fetch(stmt.stmt)
|
||||
|
||||
if result !in [0, 100] && stmt.get_error_msg() != '' {
|
||||
return stmt.error(result)
|
||||
}
|
||||
return res
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// close disposes the prepared `stmt`. The statement becomes invalid, and should not be used anymore after this call.
|
||||
@ -150,6 +158,7 @@ pub fn (stmt Stmt) close() ! {
|
||||
if !C.mysql_stmt_close(stmt.stmt) && stmt.get_error_msg() != '' {
|
||||
return stmt.error(1)
|
||||
}
|
||||
|
||||
if !C.mysql_stmt_free_result(stmt.stmt) && stmt.get_error_msg() != '' {
|
||||
return stmt.error(1)
|
||||
}
|
||||
@ -162,6 +171,7 @@ fn (stmt Stmt) get_error_msg() string {
|
||||
// error returns a proper V error with a human readable description, given the error code returned by MySQL
|
||||
pub fn (stmt Stmt) error(code int) IError {
|
||||
msg := stmt.get_error_msg()
|
||||
|
||||
return &SQLError{
|
||||
msg: '${msg} (${code}) (${stmt.query})'
|
||||
code: code
|
||||
@ -262,8 +272,9 @@ pub fn (mut stmt Stmt) bind_res(fields &C.MYSQL_FIELD, dataptr []&u8, lengths []
|
||||
// bind_result_buffer binds one result value, by calling mysql_stmt_bind_result .
|
||||
// See https://dev.mysql.com/doc/c-api/8.0/en/mysql-stmt-bind-result.html
|
||||
pub fn (mut stmt Stmt) bind_result_buffer() ! {
|
||||
res := C.mysql_stmt_bind_result(stmt.stmt, unsafe { &C.MYSQL_BIND(stmt.res.data) })
|
||||
if res && stmt.get_error_msg() != '' {
|
||||
result := C.mysql_stmt_bind_result(stmt.stmt, unsafe { &C.MYSQL_BIND(stmt.res.data) })
|
||||
|
||||
if result && stmt.get_error_msg() != '' {
|
||||
return stmt.error(1)
|
||||
}
|
||||
}
|
||||
@ -277,9 +288,10 @@ pub fn (mut stmt Stmt) bind_result_buffer() ! {
|
||||
// and *before* calling fetch_stmt to fetch rows.
|
||||
// See https://dev.mysql.com/doc/c-api/8.0/en/mysql-stmt-store-result.html
|
||||
pub fn (mut stmt Stmt) store_result() ! {
|
||||
res := C.mysql_stmt_store_result(stmt.stmt)
|
||||
if res != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(res)
|
||||
result := C.mysql_stmt_store_result(stmt.stmt)
|
||||
|
||||
if result != 0 && stmt.get_error_msg() != '' {
|
||||
return stmt.error(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
module mysql
|
||||
|
||||
// get_error_msg - returns error message from MySQL instance.
|
||||
// get_error_msg returns error message from MySQL instance.
|
||||
fn get_error_msg(conn &C.MYSQL) string {
|
||||
return unsafe { C.mysql_error(conn).vstring() }
|
||||
}
|
||||
|
||||
// get_errno - returns error number from MySQL instance.
|
||||
// get_errno returns error number from MySQL instance.
|
||||
fn get_errno(conn &C.MYSQL) int {
|
||||
return C.mysql_errno(conn)
|
||||
}
|
||||
|
||||
// resolve_nil_str - returns an empty string if passed value is a nil pointer.
|
||||
// resolve_nil_str returns an empty string if passed value is a nil pointer.
|
||||
fn resolve_nil_str(ptr &u8) string {
|
||||
if isnil(ptr) {
|
||||
return ''
|
||||
|
Loading…
Reference in New Issue
Block a user