Tracking of the node where the last COM_STMT_EXECUTE was sent allows
routing of all following COM_STMT_FETCH to the same node. This is required
for cursors to work.
MariaDB/MySQL does not support multiple active cursors so the
COM_STMT_FETCH will always refer to the latest COM_STMT_EXECUTE and using
a different ID goes against the protocol. If/when the support for multiple
active cursors is added, the tracking should be done for each
COM_STMT_EXECUTE statement. This should be relatively easily to achieve
but currently it is unnecessary.
Session commands that will not return a response can be completed
immediately. This requires some special code in the readwritesplit Backend
class implementation as well as a small addition to the Backend class
itself.
Since not all commands expect a response from the server, the queued query
routing function needs some adjustment. The routing of queued queries
should be attempted until a command which expects a response is found or
the queue is empty.
By properly handling these types of session commands, the router can
enable the execution of COM_STMT_CLOSE and COM_STMT_RESET on all
servers. This will prevent resource leakages in the server and allow
proper handling of COM_STMT type command.
If the internal ID is stored in the buffer when it is moving inside the
readwritesplit router, the RWBackend can manage the execution of all
commands with a statement ID by replacing the stored ID with the correct
value.
When a COM_STMT_EXECUTE or a COM_STMT_SEND_LONG_DATA command is executed,
the query type of the prepared statement is used. This allows read-only
prepared statements to be load balanced across slaves.
Mapping the handles returned to the client to a session command ID allows
the mapping of client handle to the backend specific handle. Currently,
the mapping is used for diagnostic output only.
The class manages both text and binary protocol prepared statement ID to
type mapping. The text protocol statements are mapped by their plaintext
name and the binary protocol statements are mapped by the session command
ID of the prepared statement.
By mapping the binary protocol prepared statement type to the session
command identifier, we can store the types for both styles of prepared
statements in a very similar manner. When the prepared statement handle is
received from the backend and is sent to the client, the client handle to
session command ID mapping can be done. This allows the mapping of both
client and backend PS handles to internal session command IDs.
The readwritesplit Backend implementation maps the returned PS handles to
session command identifiers. This allows the handles to be retrieven later
on when the prepared statements are executed.
The mxs_mysql_extract_ps_response function extracts the binary protocol
prepared statement components and stores them in a common structure.
The mxs_mysql_get_command extracts the command byte from a GWBUF object
containing a complete MySQL packet.
The firewall uses a bitmask for representing what operations a
particular rule should be applied to. Consquently it cannot use
the query classifier qc_query_op_t enumerator values as such,
as they are consecutive numbers.
The initial setting of sql_mode affects how MaxScale initially
behaves with respect to autocommit.
When 'set sql_mode=[default|oracle];" is encountered, the query
classifier and autocommit modes are adjusted accordingly.
The default sql mode must now be provided explicitly when the query
classifier is setup. This is in preparation for "sql_mode" becoming
a global configuration parameter of MaxScale.
That's where it belongs as it is only the mysql client protocol that
will use it. It's a bit unfortunate that the qc test program compare
now needs to include a file from a protocol module directory, but
the fact is that the query classifier implementation and the test
programs should actually be *under* the mysql client protocol module.
The current sql mode will be tracked in that variable. Since one
thread will handle multiple sessions, we need to track the sql mode
of a session, so that the sql mode of the query classifier can be
set whenever we handle a request of a particular session.
As the sql-mode will be managed by the client protocol, the data
can be private to it as well.
The parser is needed not only by mysql_client but also by the test
program of the qc-plugins, so it need to be available someplace
common.
Not that nice that both a qc-component and mysql_client will include
stuff from server/core/maxscale, but at least temporarily ok.
SetSqlModeParser is a custom parser for detecting "SET SQL_MODE=..."
statements. It will be used in mysql_client and the result will be
used for updating the sql_mode of a session (that is to be added).
Thereafter, whenever a statement arrives, the value of that sql_mode
will be used for setting the mode of the query_classifier.
A custom parser for detecting "set sql_mode=ORACLE" is needed
and writing that is C++ is more convenient than writing it in
C. Consequently, so as to be able to use that parser, mysql_client
must be compiled as C++.
EXPLAIN statements are no longer parsed completely as doing so makes
it hard to modify the grammar for the needs or Oracle SQL.
Consequently, for an EXPLAIN statement you now bascially only get the
type and the operation (the newly added QUERY_OP_EXPLAIN and QUERY_OP_SHOW).
The other information is not interesting and is related to
information_schema and similar tables.
Several filters use a match-or-ignore logic with two regular
expressions when filtering queries. This commit adds a convenience
function for this task. Also adds a convenience function for reading
several regular expression parameters at once, compiling them and
saving the code while checking for errors.
Also, use the new functions in QLA and CCR filters.
The test created a DCB of an unexpected type in an unexpected state with
an invalid file descriptor. This caused the test to fail due to a debug
assertion where the the validity of the file descriptor was asserted in
relation to the internal state of the DCB.
The two cases where the case-sensitive parser functions were used don't
appear to hold any special meaning. The case-insensitive function should
be used as it implements a superset of functionality compared to the
case-sensitive version.
There's no need to use Python 3 for the script and using it introduces
problems due to the poor availability of MySQL Connector/Python for
Python3.
ENUM, SET and DECIMAL values should have a length of -1 as the length is
meaningless for these types.
If a prepared statement response was collected into one buffer, it doesn't
need to be processed again. By jumping directly to the routing of the
collected result, we prevent the unnecessary splitting of buffers that
appears to happend with continuous preparations of prepared statements.
When a statement is being prepared, the type and name of the statement is
stored in the router session. If the name of a statement to be executed is
found in the map, the query type that stored in the map is used.
Providing helper functions for the commonly used parts of the server makes
code easier to read. It also removes any possibility for formatting
problems by moving the URI and name string handling inside the Backend
class.
Added helper functions that check various server states. This makes the
readwritesplit code easier to read as the function names convey the
intention better than the macro invokations.
Renamed variables to better represent the types of variables they
represent. Reordered some of the functions so that the functions don't
need to be declared before they are used.
Return values instead of objects. This removes the need to handle cases
where a reference to a "debug value" is returned.
Return SRWBackend values instead of passing output references. This
doubles as a false boolan return value when an empty reference is
returned.