WL#8177: SQL service API
Affects: Server-5.7
—
Status: Complete
Goal of this WL is to allow to run SQL queries and get the result in the current thread or obtained from Session service (WL#7947). Note. Due to limitation of underlying work (WL#7126) execution of prepared statements won't be supported. When that limitation would be lifted, PS will automatically become available via this service.
The goal fo this WL is to provide a service to allow plugins to run server commands, SQL queries among them. This WL consists of several parts: 1) A service to run commands There are two parts of it: one handles the protocol through which server interacts with the plugin and another actually runs commands. struct my_cmd_service { /* Initialize protocol and returns its handler on success @param protocol_cbs Struct of callbacks to interact with server @param ctx Plugin's context, an opaque pointer that will be passed to callbacks. Might be NULL. */ MYSQL_PROTOCOL (*init_protocol)(const struct protocol_cbs *cbs, void *ctx); /* Free protocol @param protocol Protocol handler to free @details Frees protocol, its handler becomes invalid, attempt to use it would likely result in a crash. */ void (*free_protocol)(MYSQL_PROTOCOL protocol); /* Execute a server command. @param thd Session handler obtained via Session service @param protocol Protocol handler @param command Command needs to be executed @param data Command's arguments @returns true an error occured false success */ int (*run_command)(MYSQL_THD thd, MYSQL_PROTOCOL protocol enum_server_command command, COM_DATA *data); }; A plugin might allocate as many protocols with different callback functions as it needs, e.g one protocol with different callback functions and context for each command it wants to run. Having obtained thd and protocol a plugin can run commands by means of the run_command() function, which is the service's wrapper for do_command() function. After it's called, the plugin should provide server, via callback functions, the command it wants to run and arguments to it. Here is an example session of a COM_QUERY with "SELECT ..." query: Server | Plugin --------------------------------+----------------------------- | calls run_command() run_command() | switches thd and protocol | server's dispatch_command() | calls callbacks: | ... execution ... | ... sending metadata ... | start_result_metadata(...) | field_metadata(...) ... same for each field sent ... | end_result_metadata(...) | ... sending result ... | start_row(...) | get_xxx(...) ... same for each field, xxx is type according to metadata ... | end_row(...) ... same for each row, until all rows are sent ... | handle_ok(...) | run_command() returns | 2) Struct holding callback functions for interaction with server. It consists of several logical parts: 1) getting metadata from server 2) getting data from server 3) getting execution status struct sql_protocol_cbs { /*** Getting metadata ***/ /* Indicates beginning of metadata for the result set @param ctx Plugin's context @param num_cols Number of fields being sent @param resultcs Charset of the result set @returns true an error occured, server will abort the command false ok */ int (*start_result_metadata)(void *ctx, uint num_cols, const CHARSET_INFO *resultcs); /* Field metadata is provided via this callback @param ctx Plugin's context @param field Field's metadata (see field.h) @param charset Field's charset @returns true an error occured, server will abort the command false ok */ int (*field_metadata)(void *ctx, Send_field *field, const CHARSET_INFO *charset); /* Indicates end of metadata for the result set @param ctx Plugin's context @returns true an error occured, server will abort the command false ok */ int (*end_result_metadata)(void *ctx); /* Indicates the beginning of a new row in the result set @param ctx Plugin's context @returns true an error occured, server will abort the command false ok */ int (*start_row)(void *ctx); /* Indicates the end of the current row in the result set @param ctx Plugin's context @returns true an error occured, server will abort the command false ok */ int (*end_row)(void *ctx); /* An error occured during execution @details This callback indicates that an error occureded during command execution and the partial row should be dropped. Server will raise error and return. @param ctx Plugin's context @returns true an error occured, server will abort the command false ok */ void (*abort_row)(void *ctx); /* Return client's capabilities (see mysql_com.h, CLIENT_*) @param ctx Plugin's context @return Bitmap of client's capabilities */ ulonglong (*get_client_caps)(void *ctx); /****** Getting data ******/ /* Receive NULL value from server @param ctx Plugin's context @returns true an error occured, server will abort the command false ok */ int (*get_null)(void * ctx); /* Get TINY/SHORT/LONG value from server @param ctx Plugin's context @param value Value received @note In order to know which type exactly was received, the plugin must track the metadata that was sent just prior to the result set. @returns true an error occured, server will abort the command false ok */ int (*get_integer)(void * ctx, longlong value); /* Get LONGLONG value from server @param ctx Plugin's context @param value Value received @param unsigned_flag TRUE <=> value is unsigned @returns true an error occured, server will abort the command false ok */ int (*get_longlong)(void * ctx, longlong value, bool unsigned_flag); /* Receive DECIMAL value from server @param ctx Plugin's context @param value Value received @returns true an error occured, server will abort the command false ok */ int (*get_decimal)(void * ctx, const my_decimal * value); /* Get FLOAT/DOUBLE from server @param ctx Plugin's context @param value Value received @param decimals Number of decimals @note In order to know which type exactly was received, the plugin must track the metadata that was sent just prior to the result set. @returns true an error occured, server will abort the command false ok */ int (*get_double)(void * ctx, double value, uint32 decimals); /* Get DATE value from server @param ctx Plugin's context @param value Value received @returns true an error occured during storing, server will abort the command false ok */ int (*get_date)(void * ctx, const MYSQL_TIME * value); /* Get TIME value from server @param ctx Plugin's context @param value Value received @param decimals Number of decimals @returns true an error occured during storing, server will abort the command false ok */ int (*get_time)(void * ctx, const MYSQL_TIME * value, uint decimals); /* Get DATETIME value from server @param ctx Plugin's context @param value Value received @param decimals Number of decimals @returns true an error occured during storing, server will abort the command false ok */ int (*get_datetime)(void * ctx, const MYSQL_TIME * value, uint decimals); /* Get STRING value from server @param ctx Plugin's context @param value Value received @param length Value's length @param valuecs Value's charset @returns true an error occured, server will abort the command false ok */ int (*get_string)(void * ctx, const char * const value, size_t length, const CHARSET_INFO * const valuecs); /* Get field text or binary from server @param ctx Plugin's context @param field Proto_field received (see WL#7126) @details This method should call either Proto_field::send_text() or Proto_field::send_binary, depending on the desired result. Field will send itself in either text of binary form by calling one of get_xxx() callback functions above. @returns true an error occured, server will abort the command false ok */ int (*get_field)(void *ctx, Proto_field *field); /****** Getting execution status ******/ /* Command ended with success @param ctx Plugin's context @param server_status Status of server (see mysql_com.h, SERVER_STATUS_*) @param statement_warn_count Number of warnings thrown during execution @param affected_rows Number of rows affected by the command @param last_insert_id Last insert id being assigned during execution @param message A message from server */ void (*handle_ok)(void * ctx, uint server_status, uint statement_warn_count, ulonglong affected_rows, ulonglong last_insert_id, const char * const message); /* Command ended with ERROR @param ctx Plugin's context @param sql_errno Error code @param err_msg Error message @param sqlstate SQL state correspongin to the error code */ void (*handle_error)(void * ctx, uint sql_errno, const char * const err_msg, const char * const sqlstate); /* Session was shutdown while command was running @param ctx Plugin's context */ void (*shutdown)(void *ctx); /* Checks if the connection is functioning @param ctx Plugin's context @return 1 alive 0 dead */ int (*connection_alive)(void *ctx); } All callback functions are plain mapping to Protocol's actual methods. Callback pointers might be NULL, in such case they will be ignored. Since the service would use the provided protocol, handle_ok/handle_error callback functions effectively will overload ones provided for session service. It's up to the plugin whether to use same or different functions for handle_error/handle_ok callback functions.
Dealing with Protocol ===================== In order to communicate with caller plugin, a new class Protocol_callback is introduced. It's derived from Protocol. This class is a mere proxy, passing all its methods to appropriate callbacks provided at initialization, and isn't visible to the plugin. Exceptions to 1:1 method-callback mapping: .) store_tiny(), store_short(), store_long() are all calling get_integer() .) store_float(), store_double() are both calling get_double() .) get_client_caps() should cache plugin's capabilities, has_client_cap() should use that cache instead of asking the plugin. .) send_eof() should call handle_ok(). Command execution ================= Prior executing a command the service should do following: 1) Ensure that THD provided exists in server's thread list. Returns error otherwise. 2) For non-daemon plugins backup current_thd 3) Set THD provided by plugin 4) Backup default protocol and set plugin's one To actually execute the command, dispatch_command() is called. After returning from do_command() service should rollback changes it made: 1) restore default protocol 2) for non-daemon plugins - restore original current_thd
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.