mysql/mysql.md

546 lines
26 KiB
Markdown

## `local mysql = require'mysql'`
A complete, lightweight ffi binding of the mysql client library.
Works with both libmysql and [libmariadb].
## Summary
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
**[Initialization]**
`mysql.bind(['mysql'|'mariadb'|libname|clib]) -> mysql`
**[Connections]**
`mysql.connect(host, [user], [pass], [db], [charset], [port]) -> conn` connect to a mysql server
`mysql.connect(options_t) -> conn` connect to a mysql server
`conn:close()` close the connection
**[Queries]**
`conn:query(s)` execute a query
`conn:escape(s) -> s` escape an SQL string
**[Fetching results]**
`conn:store_result() -> result` get a cursor for buffered read ([manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-store-result.html))
`conn:use_result() -> result` get a cursor for unbuffered read ([manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-use-result.html))
`result:fetch([mode[, row_t]]) -> true, v1, v2, ... | row_t | nil` fetch the next row from the result
`result:rows([mode[, row_t]]) -> iterator() -> row_num, val1, val2, ...` row iterator
`result:rows([mode[, row_t]]) -> iterator() -> row_num, row_t` row iterator
`result:free()` free the cursor
`result:row_count() -> n` number of rows
`result:eof() -> true | false` check if no more rows
`result:seek(row_number)` seek to row number
**[Query info]**
`conn:field_count() -> n` number of result fields in the executed query
`conn:affected_rows() -> n` number of affected rows in the executed query
`conn:insert_id() -> n` the id of the autoincrement column in the executed query
`conn:errno() -> n` mysql error code (0 if no error) from the executed query
`conn:sqlstate() -> s`
`conn:warning_count() -> n` number of errors, warnings, and notes from executed query
`conn:info() -> s`
**[Field info]**
`result:field_count() -> n` number of fields in the result
`result:field_name(field_number) -> s` field name given field index
`result:field_type(field_number) -> type, length, unsigned, decimals` field type given field index
`result:field_info(field_number) -> info_t` field info table
`result:fields() -> iterator() -> i, info_t` field info iterator
**[Result bookmarks]**
`result:tell() -> bookmark` bookmark the current row for later seek
`result:seek(bookmark)` seek to a row bookmark
**[Multiple statement queries]**
`conn:next_result() -> true | false` skip to the next result set ([manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-next-result.html))
`conn:more_results() -> true | false` are there more result sets?
**[Prepared statements]**
`conn:prepare(query) -> stmt` prepare a query for multiple executions
`stmt:param_count() -> n` number of params
`stmt:exec()` execute a prepared statement
`stmt:store_result()` store all the resulted rows to the client
`stmt:fetch() -> true | false | true, 'truncated'` fetch the next row
`stmt:free_result()` free the current result buffers
`stmt:close()` close the statement
`stmt:next_result()` skip to the next result set
`stmt:row_count() -> n` number of rows in the result, if the result was stored
`stmt:affected_rows() -> n` number of affected rows after execution
`stmt:insert_id() -> n` the id of the autoincrement column after execution
`stmt:field_count() -> n` number of fields in the result after execution
`stmt:errno() -> n` mysql error code, if any, from the executed statement
`stmt:sqlstate() -> s`
`stmt:result_metadata() -> result` get a result for accessing the field info
`stmt:fields() -> iterator() -> i, info_t` iterate the result fields info
`stmt:reset()` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-reset.html)
`stmt:seek(row_number)` seek to row number
`stmt:tell() -> bookmark` get a bookmark in the current result
`stmt:seek(bookmark)` seek to a row bookmark in the current result
**[Prepared statements I/O]**
`stmt:bind_params(type1, ... | types_t) -> params` bind query parameters based on type definitions
`params:set(i, number | int64_t | uint64_t | true | false)` set an integer, float or bit param
`params:set(i, s[, size])` set a variable sized param
`params:set(i, cdata, size)` set a variable sized param
`params:set(i, {year=, month=, ...})` set a time/date param
`params:set_date(i, [year], [month], [day], [hour], [min], [sec], [frac])` set a time/date param
`stmt:write(param_number, data[, size])` send a long param in chunks
`stmt:bind_result([type1, ... | types_t | maxsize]) -> fields` bind query result fields based on type definitions
`fields:get(i) -> value` get the current row value of a field
`fields:get_datetime(i) -> year, month, day, hour, min, sec, frac` get the value of a date/time field directly
`fields:is_null(i) -> true | false` is field null?
`fields:is_truncated(i) -> true | false` was field value truncated?
**[Prepared statements settings]**
`stmt:update_max_length() -> true | false` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
`stmt:set_update_max_length(true | false)` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
`stmt:cursor_type() -> mysql.C.MYSQL_CURSOR_TYPE_*` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
`stmt:set_cursor_type('CURSOR_TYPE_...')` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
`stmt:set_cursor_type(mysql.C.MYSQL_CURSOR_TYPE_...)` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
`stmt:prefetch_rows() -> n` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
`stmt:set_prefetch_rows(stmt, n)` see [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html)
**[Connection info]**
`conn:set_charset(charset)` change the current charset
`conn:select_db(dbname)` change the current database
`conn:change_user(user, [pass], [db])` change the current user (and database)
`conn:set_multiple_statements(true | false)` enable/disable support for multiple statements
`conn:charset() -> s` get current charset's name
`conn:charset_info() -> info_t` get info about the current charset
`conn:ping() -> true | false` check if the connection is still alive
`conn:thread_id() -> id`
`conn:stat() -> s`
`conn:server_info() -> s`
`conn:host_info() -> s`
`conn:server_version() -> n`
`conn:proto_info() -> n`
`conn:ssl_cipher() -> s`
**[Transactions]**
`conn:commit()` commit the current transaction
`conn:rollback()` rollback the current transaction
`conn:set_autocommit([true | false])` enable/disable autocommit on the current connection
**[Reflection]**
`conn:list_dbs([wildcard]) -> result` return info about databases as a result object
`conn:list_tables([wildcard]) -> result` return info about tables as a result object
`conn:list_processes() -> result` return info about processes as a result object
**[Remote control]**
`conn:kill(pid)` kill a connection based on process id
`conn:shutdown([level])` shutdown the server
`conn:refresh(options)` flush tables or caches
`conn:dump_debug_info()` dump debug info in the log file
**[Client library info]**
`mysql.thread_safe() -> true | false` was the client library compiled as thread-safe?
`mysql.client_info() -> s`
`mysql.client_version() -> n`
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
## Features
* covers all of the functionality provided by the mysql C API
* all data types are supported with options for conversion
* prepared statements, avoiding dynamic allocations and format conversions when fetching rows
* all C calls are checked for errors and Lua errors are raised
* all C objects are tied to Lua's garbage collector
* lightweight OOP-style API using only `ffi.metatype`
* no external dependencies
## Example
~~~{.lua}
function print_help(search)
local mysql = require'mysql'
local conn = mysql.connect('localhost', 'root', nil, 'mysql', 'utf8')
conn:query("select name, description, example from help_topic where name like '" ..
conn:escape(search) .. "'")
local result = conn:store_result()
print('Found:')
for i,name in result:rows() do
print(' ' .. name)
end
print()
for i, name, description, example in result:rows() do
print(name)
print'-------------------------------------------'
print(description)
print'Example:'
print'-------------------------------------------'
print(example)
print()
end
result:free()
conn:close()
end
print_help'CONCAT%'
~~~
## Initialization
### `mysql.config(['mysql'|'mariadb'|libname|clib]) -> mysql`
Load the mysql client library to use (default is 'mysql').
This function is called on every module-level function.
Calling this function again is a no-op.
## Connections
### `mysql.connect(host, [user], [pass], [db], [charset], [port]) -> conn`
### `mysql.connect(options_t) -> conn`
Connect to a mysql server, optionally selecting a working database and charset.
In the second form, `options_t` is a table that besides `host`, `user`, `pass`, `db`, `charset`, `port`
can have the following fields:
* `unix_socket`: specify a unix socket filename to connect to
* `flags`: bit field corresponding to mysql [client_flag](http://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html) parameter
* can be a table of form `{CLIENT_... = true | false, ...}`, or
* a number of form `bit.bor(mysql.C.CLIENT_..., ...)`
* `options`: a table of form `{MYSQL_OPT_... = value, ...}`, containing options per [mysql_options()](http://dev.mysql.com/doc/refman/5.7/en/mysql-options.html) (values are properly converted from Lua types)
* `attrs`: a table of form `{attr = value, ...}` containing attributes to be passed to the server per [mysql_options4()](http://dev.mysql.com/doc/refman/5.7/en/mysql-options4.html)
* `key`, `cert`, `ca`, `cpath`, `cipher`: parameters used to establish a [SSL connection](http://dev.mysql.com/doc/refman/5.7/en/mysql-ssl-set.html)
### `conn:close()`
Close a mysql connection freeing all associated resources (otherwise called when `conn` is garbage collected).
## Queries
### `conn:query(s)`
Execute a query. If the query string contains multiple statements, only the first statement is executed
(see the section on multiple statements).
### `conn:escape(s) -> s`
Escape a value to be safely embedded in SQL queries. Assumes the current charset.
## Fetching results
### `conn:store_result() -> result`
Fetch all the rows in the current result set from the server and return a result object to read them one by one.
### `conn:use_result() -> result`
Return a result object that will fetch the rows in the current result set from the server on demand.
### `result:fetch([mode[, row_t]]) -> true, v1, v2, ... | row_t | nil`
Fetch and return the next row of values from the current result set. Returns nil if there are no more rows to fetch.
* the `mode` arg can contain any combination of the following letters:
* `"n"` - return values in a table with numeric indices as keys.
* `"a"` - return values in a table with field names as keys.
* `"s"` - do not convert numeric and time values to Lua types.
* the `row_t` arg is an optional table to store the row values in, instead of creating a new one on each fetch.
* options "a" and "n" can be combined to get a table with both numeric and field name indices.
* if `mode` is missing or if neither "a" nor "n" is specified, the values
are returned to the caller unpacked, after a first value that is always
true, to make it easy to distinguish between a valid `NULL` value in the
first column and eof.
* in "n" mode, the result table may contain `nil` values so `#row_t` and `ipairs(row_t)` are out; instead iterate from 1 to `result:field_count()`.
* in "a" mode, for fields with duplicate names only the last field will be present.
* if `mode` does not specify `"s"`, the following conversions are applied on the returned values:
* integer types are returned as Lua numbers, except bigint which is returned as an `int64_t` cdata (or `uint64` if unsigned).
* date/time types are returned as tables in the usual `os.date"*t"` format (date fields are missing for time-only types and viceversa).
* decimal/numeric types are returned as Lua strings.
* bit types are returned as Lua numbers, and as `uint64_t` for bit types larger than 48 bits.
* enum and set types are always returned as strings.
### `result:rows([mode[, row_t]]) -> iterator() -> row_num, val1, val2, ...`
### `result:rows([mode[, row_t]]) -> iterator() -> row_num, row_t`
Convenience iterator for fetching (or refetching) all the rows from the current result set. The `mode` arg
is the same as for `result:fetch()`, with the exception that in unpacked mode, the first `true` value is not present.
### `result:free()`
Free the result buffer (otherwise called when `result` is garbage collected).
### `result:row_count() -> n`
Return the number of rows in the current result set . This value is only correct if `result:store_result()` was
previously called or if all the rows were fetched, in other words if `result:eof()` is true.
### `result:eof() -> true | false`
Check if there are no more rows to fetch. If `result:store_result()` was previously called, then all rows were
already fetched, so `result:eof()` always returns `true` in this case.
### `result:seek(row_number)`
Seek back to a particular row number to refetch the rows from there.
## Query info
### `conn:field_count() -> n`
### `conn:affected_rows() -> n`
### `conn:insert_id() -> n`
### `conn:errno() -> n`
### `conn:sqlstate() -> s`
### `conn:warning_count() -> n`
### `conn:info() -> s`
Return various pieces of information about the previously executed query.
## Field info
### `result:field_count() -> n`
### `result:field_name(field_number) -> s`
### `result:field_type(field_number) -> type, length, decimals, unsigned`
### `result:field_info(field_number) -> info_t`
### `result:fields() -> iterator() -> i, info_t`
Return information about the fields (columns) in the current result set.
## Result bookmarks
### `result:tell() -> bookmark`
Get a bookmark to the current row to be later seeked into with `seek()`.
### `result:seek(bookmark)`
Seek to a previous saved row bookmark, or to a specific row number, fetching more rows as needed.
## Multiple statement queries
### `conn:next_result() -> true | false`
Skip over to the next result set in a multiple statement query, and make that the current result set.
Return true if there more result sets after this one.
### `conn:more_results() -> true | false`
Check if there are more result sets after this one.
## Prepared statements
Prepared statements are a way to run queries and retrieve results more efficiently from the database, in particular:
* parametrized queries allow sending query parameters in their native format, avoiding having to convert values into strings and escaping those strings.
* running the same query multiple times with different parameters each time allows the server to reuse the parsed query and possibly the query plan between runs.
* fetching the result rows in preallocated buffers avoids dynamic allocation on each row fetch.
The flow for prepared statements is like this:
* call `conn:prepare()` to prepare a query and get a statement object.
* call `stmt:bind_params()` and `stmt:bind_result()` to get the buffer objects for setting params and getting row values.
* run the query multiple times; each time:
* call `params:set()` for each param to set param values.
* call `stmt:exec()` to run the query.
* fetch the resulting rows one by one; for each row:
* call `stmt:fetch()` to get the next row (it returns false if it was the last row).
* call `fields:get()` to read the values of the fetched row.
* call `stmt:close()` to free the statement object and all the associated resources from the server and client.
### `conn:prepare(query) -> stmt, params`
Prepare a query for multiple execution and return a statement object.
### `stmt:param_count() -> n`
Number of parameters.
### `stmt:exec()`
Execute a prepared statement.
### `stmt:store_result()`
Fetch all the rows in the current result set from the server, otherwise the rows are fetched on demand.
### `stmt:fetch() -> true | false | true, 'truncated'`
Fetch the next row from the current result set. Use a binding buffer (see prepared statements I/O section)
to get the row values. If present, second value indicates that at least one of the rows were truncated because
the receiving buffer was too small for it.
### `stmt:free_result()`
Free the current result and all associated resources (otherwise the result is closed when the statement is closed).
### `stmt:close()`
Close a prepared statement and free all associated resources (otherwise the statement is closed when garbage collected).
### `stmt:next_result()`
Skip over to the next result set in a multiple statement query.
### `stmt:row_count() -> n`
### `stmt:affected_rows() -> n`
### `stmt:insert_id() -> n`
### `stmt:field_count() -> n`
### `stmt:errno() -> n`
### `stmt:sqlstate() -> s`
### `stmt:result_metadata() -> result`
### `stmt:fields() -> iterator() -> i, info_t`
Return various pieces of information on the executed statement.
### `stmt:reset()`
See [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-reset.html).
### `stmt:seek(row_number)`
### `stmt:tell() -> bookmark`
### `stmt:seek(bookmark)`
Seek into the current result set.
## Prepared statements I/O
### `stmt:bind_params(type1, ... | types_t) -> params`
Bind query parameters according to a list of type definitions (which can be given either packed or unpacked).
Return a binding buffer object to be used for setting parameters.
The types must be valid, fully specified SQL types, eg.
* `smallint unsigned` specifies a 16bit unsigned integer
* `bit(32)` specifies a 32bit bit field
* `varchar(200)` specifies a 200 byte varchar.
### `params:set(i, number | int64_t | uint64_t | true | false)`
### `params:set(i, s[, size])`
### `params:set(i, cdata, size)`
### `params:set(i, {year=, month=, ...})`
### `params:set_date(i, [year], [month], [day], [hour], [min], [sec], [frac])`
Set a parameter value.
* the first form is for setting integers and bit fields.
* the second and third forms are for setting variable-sized fields and decimal/numeric fields.
* the last forms are for setting date/time/datetime/timestamp fields.
* the null type cannot be set (raises an error if attempted).
### `stmt:write(param_number, data[, size])`
Send a parameter value in chunks (for long, var-sized values).
### `stmt:bind_result([type1, ... | types_t | maxsize]) -> fields`
Bind result fields according to a list of type definitions (same as for params).
Return a binding buffer object to be used for getting row values.
If no types are specified, appropriate type definitions will be created automatically as to minimize type conversions.
Variable-sized fields will get a buffer sized according to data type's maximum allowed size
and `maxsize` (which defaults to 64k).
### `fields:get(i) -> value`
### `fields:get_datetime(i) -> year, month, day, hour, min, sec, frac`
Get a row value from the last fetched row. The same type conversions as for `result:fetch()` apply.
### `fields:is_null(i) -> true | false`
Check if a value is null without having to get it if it's not.
### `fields:is_truncated(i) -> true | false`
Check if a value was truncated due to insufficient buffer space.
### `stmt:bind_result_types([maxsize]) -> types_t`
Return the list of type definitions that describe the result of a prepared statement.
## Prepared statements settings
### `stmt:update_max_length() -> true | false`
### `stmt:set_update_max_length(true | false)`
### `stmt:cursor_type() -> mysql.C.MYSQL_CURSOR_TYPE_*`
### `stmt:set_cursor_type('CURSOR_TYPE_...')`
### `stmt:set_cursor_type(mysql.C.MYSQL_CURSOR_TYPE_...)`
### `stmt:prefetch_rows() -> n`
### `stmt:set_prefetch_rows(stmt, n)`
See [manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-attr-set.html) for these.
## Connection info
### `conn:set_charset(charset)`
Change the current charset.
### `conn:select_db(dbname)`
Change the current database.
### `conn:change_user(user, [pass], [db])`
Change the current user and optionally select a database.
### `conn:set_multiple_statements(true | false)`
Enable or disable support for query strings containing multiple statements separated by a semi-colon.
### `conn:charset() -> s`
Get the current charset.
### `conn:charset_info() -> info_t`
Return a table of information about the current charset.
### `conn:ping() -> true | false`
Check if the connection to the server is still alive.
### `conn:thread_id() -> id`
### `conn:stat() -> s`
### `conn:server_info() -> s`
### `conn:host_info() -> s`
### `conn:server_version() -> n`
### `conn:proto_info() -> n`
### `conn:ssl_cipher() -> s`
Return various pieces of information about the connection and server.
## Transactions
### `conn:commit()`
### `conn:rollback()`
Commit/rollback the current transaction.
### `conn:set_autocommit([true | false])`
Set autocommit on the connection (set to true if no argument is given).
## Reflection
### `conn:list_dbs([wildcard]) -> result`
### `conn:list_tables([wildcard]) -> result`
### `conn:list_processes() -> result`
Return information about databases, tables and proceses as a stored result object that can be iterated etc.
using the methods of result objects. The optional `wild` parameter may contain the wildcard characters
`"%"` or `"_"`, similar to executing the query `SHOW DATABASES [LIKE wild]`.
## Remote control
### `conn:kill(pid)`
Kill a connection with a specific `pid`.
### `conn:shutdown([level])`
Shutdown the server. `SHUTDOWN` priviledge needed. The level argument is reserved for future versions of mysql.
### `conn:refresh(options)`
Flush tables or caches, or resets replication server information. `RELOAD` priviledge needed. Options are either
a table of form `{REFRESH_... = true | false, ...}` or a number of form `bit.bor(mysql.C.MYSQL_REFRESH_*, ...)` and
they are as described in the [mysql manual](http://dev.mysql.com/doc/refman/5.7/en/mysql-refresh.html).
### `conn:dump_debug_info()`
Instruct the server to dump debug info in the log file. `SUPER` priviledge needed.
## Client library info
### `mysql.thread_safe() -> true | false`
### `mysql.client_info() -> s`
### `mysql.client_version() -> n`
----
## TODO
* reader function for getting large blobs in chunks using
mysql_stmt_fetch_column: `stmt:chunks(i[, bufsize])` or `stmt:read()` ?