From 3494caaaf6ef10e1e58fff8dca739d958c488268 Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Fri, 2 Sep 2016 20:59:04 +1000 Subject: [PATCH 01/79] Updated the XAPI functions comments documentation --- include/mysql_xapi.h | 3609 ++++++++++++++++++++++-------------------- 1 file changed, 1851 insertions(+), 1758 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 7476b361b..2b183f489 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -20,10 +20,14 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ +*/ -/*! \file mysqlx_cc.h -* MySQL Connector/C 7.0 +/** + @file mysqlx_cc.h + Main header for MySQL Connector/C++ X API. + + This header should be included by C and C++ code which uses the X API + of MySQL Connector/C++ */ #ifndef MYSQL_XAPI_H @@ -42,8 +46,8 @@ extern "C" { */ #ifdef _WIN32 -#pragma comment(lib,"ws2_32") -#endif + #pragma comment(lib, "ws2_32") + #endif // FIXME #define STDCALL @@ -57,15 +61,17 @@ extern "C" { typedef char object_id[16]; typedef object_id* MYSQLX_GUID; -/*! @brief MYSQLX API - * @details Macro definition to indicate a function/operation successful end - */ +/** + @brief MYSQLX API + @details Macro definition to indicate a function/operation successful end +*/ #define RESULT_OK 0 -/*! @brief MYSQLX API - * @details Macro definition to indicate a function/operation end with an error - or mysqlx_error() should be called to get more details - */ +/** + @brief MYSQLX API + @details Macro definition to indicate a function/operation end with an error + or mysqlx_error() should be called to get more details +*/ #define RESULT_NULL 16 #define RESULT_INFO 32 #define RESULT_WARNING 64 @@ -90,101 +96,123 @@ typedef object_id* MYSQLX_GUID; */ #define MYSQLX_ERROR_INDEX_OUT_OF_RANGE_MSG "Index is out of range" -/* Opaque structures */ -/*! @brief MYSQLX API - * @details structure for obtaining the error information from the session - * and statement operations (see mysqlx_error()) + +/* Opaque structures*/ +/** + @brief MYSQLX API + @details structure for obtaining the error information from the session + and statement operations (see mysqlx_error()) */ + typedef struct mysqlx_error_struct mysqlx_error_t; -/*! @brief MYSQLX API - * @details structure containing the session context after the session is - * established (see mysqlx_get_session()) - */ + +/** + @brief MYSQLX API + @details structure containing the session context after the session is + established (see mysqlx_get_session()) +*/ + typedef struct mysqlx_session_struct mysqlx_session_t; -/*! @brief MYSQLX API - * @details structure containing the connection options for the session before - * the connection is established (see mysqlx_get_session_from_url()) - */ + +/** + @brief MYSQLX API + @details structure containing the connection options for the session before + the connection is established (see mysqlx_get_session_from_options()) +*/ + typedef struct mysqlx_session_options_struct mysqlx_session_options_t; -/*! @brief MYSQLX API - * @details structure containing the schema context - * (see mysqlx_get_schema()) - */ + +/** + @brief MYSQLX API + @details structure containing the schema context + (see mysqlx_get_schema()) +*/ + typedef struct mysqlx_schema_struct mysqlx_schema_t; -/*! @brief MYSQLX API - * @details structure containing the collection context - * (see mysqlx_get_collection()) - */ + +/** + @brief MYSQLX API + @details structure containing the collection context + (see mysqlx_get_collection()) +*/ + typedef struct mysqlx_collection_struct mysqlx_collection_t; -/*! @brief MYSQLX API - * @details structure containing the table context - * (see mysqlx_get_collection()) - */ + +/** + @brief MYSQLX API + @details structure containing the table context + (see mysqlx_get_table()) +*/ typedef struct mysqlx_table_struct mysqlx_table_t; -/*! @brief MYSQLX API - * @details structure containing the context of the statement operation. See - * mysqlx_sql_new(), mysqlx_table_select_new(), mysqlx_table_insert_new(), - * mysqlx_table_update_new(), mysqlx_table_delete_new(), - * mysqlx_collection_find_new(), mysqlx_collection_modify_new(), mysqlx_collection_add_new(), - * mysqlx_collection_remove_new() - */ + +/** + @brief MYSQLX API + @details structure containing the context of the statement operation. See + mysqlx_sql_new(), mysqlx_table_select_new(), mysqlx_table_insert_new(), + mysqlx_table_update_new(), mysqlx_table_delete_new(), + mysqlx_collection_find_new(), mysqlx_collection_modify_new(), + mysqlx_collection_add_new(), mysqlx_collection_remove_new() +*/ + typedef struct mysqlx_stmt_struct mysqlx_stmt_t; -/*! @brief NOT IMPLEMENTED - * Using of this structure is temporarily suspended - */ -typedef struct mysqlx_doc_struct mysqlx_doc_t; -/*! @brief MYSQLX API - * @details structure representing a row from a table resultset - * (see mysqlx_row_fetch_one()) - */ +/** + @brief MYSQLX API + @details structure representing a row from a table resultset + (see mysqlx_row_fetch_one()) +*/ + typedef struct mysqlx_row_struct mysqlx_row_t; -/*! @brief MYSQLX API - * @details Structure representing the result context along with the buffered - * rows/documents (see mysqlx_execute(), mysqlx_store_result(), - * mysqlx_row_fetch_one(), mysqlx_doc_fetch_one(), mysqlx_next_result()) - */ +/** + @brief MYSQLX API + @details Structure representing the result context along with the buffered + rows/documents (see mysqlx_execute(), mysqlx_store_result(), + mysqlx_row_fetch_one(), mysqlx_json_fetch_one(), mysqlx_next_result()) +*/ + typedef struct mysqlx_result_struct mysqlx_result_t; -/*! + +/** * \enum mysqlx_data_type_t * The data type identifiers used in MYSQLX API */ + typedef enum mysqlx_data_type_enum { MYSQLX_TYPE_UNDEFINED = 0, - /* Coulmn types as defined in protobuf (mysqlx_resultset.proto) */ - MYSQLX_TYPE_SINT = 1, /*!< 64-bit signed integer number type */ - MYSQLX_TYPE_UINT = 2, /*!< 64-bit unsigned integer number type */ - MYSQLX_TYPE_DOUBLE = 5, /*!< Floating point double number type */ - MYSQLX_TYPE_FLOAT = 6, /*!< Floating point float number type */ - MYSQLX_TYPE_BYTES = 7, /*!< Bytes array type */ - MYSQLX_TYPE_TIME = 10, /*!< Time type */ - MYSQLX_TYPE_DATETIME = 12,/*!< Datetime type */ - MYSQLX_TYPE_SET = 15, /*!< Set type */ - MYSQLX_TYPE_ENUM = 16,/*!< Enum type */ - MYSQLX_TYPE_BIT = 17, /*!< Bit type */ - MYSQLX_TYPE_DECIMAL = 18,/*!< Decimal type */ - - /* Column types from DevAPI (no number constants assigned, just names) */ - MYSQLX_TYPE_BOOL = 19,/*!< Bool type */ - MYSQLX_TYPE_JSON = 20,/*!< JSON type */ - MYSQLX_TYPE_STRING = 21,/*!< String type */ - MYSQLX_TYPE_GEOMETRY = 22,/*!< Geometry type*/ - MYSQLX_TYPE_TIMESTAMP= 23,/*!< Timestamp type*/ - - MYSQLX_TYPE_NULL = 100, /*!< NULL value */ - MYSQLX_TYPE_EXPR = 101 /*!< Expression type */ + /* Coulmn types as defined in protobuf (mysqlx_resultset.proto)*/ + MYSQLX_TYPE_SINT = 1, /**< 64-bit signed integer number type*/ + MYSQLX_TYPE_UINT = 2, /**< 64-bit unsigned integer number type*/ + MYSQLX_TYPE_DOUBLE = 5, /**< Floating point double number type*/ + MYSQLX_TYPE_FLOAT = 6, /**< Floating point float number type*/ + MYSQLX_TYPE_BYTES = 7, /**< Bytes array type*/ + MYSQLX_TYPE_TIME = 10, /**< Time type*/ + MYSQLX_TYPE_DATETIME = 12,/**< Datetime type*/ + MYSQLX_TYPE_SET = 15, /**< Set type*/ + MYSQLX_TYPE_ENUM = 16,/**< Enum type*/ + MYSQLX_TYPE_BIT = 17, /**< Bit type*/ + MYSQLX_TYPE_DECIMAL = 18,/**< Decimal type*/ + + /* Column types from DevAPI (no number constants assigned, just names)*/ + MYSQLX_TYPE_BOOL = 19,/**< Bool type*/ + MYSQLX_TYPE_JSON = 20,/**< JSON type*/ + MYSQLX_TYPE_STRING = 21,/**< String type*/ + MYSQLX_TYPE_GEOMETRY = 22,/**< Geometry type*/ + MYSQLX_TYPE_TIMESTAMP= 23,/**< Timestamp type*/ + + MYSQLX_TYPE_NULL = 100, /**< NULL value*/ + MYSQLX_TYPE_EXPR = 101 /**< Expression type*/ } mysqlx_data_type_t; #define PARAM_SINT(A) (void*)MYSQLX_TYPE_SINT, (int64_t)A @@ -198,16 +226,25 @@ typedef enum mysqlx_data_type_enum #define PARAM_END (void*)0 -/*! - * \enum mysqlx_sort_direction_t - * Enumerating sort directions in sorting operations such as ORDER BY + +/** + \enum mysqlx_sort_direction_t + Enumerating sort directions in sorting operations such as ORDER BY */ + typedef enum mysqlx_sort_direction_enum { - SORT_ORDER_ASC = 1, /*!< Ascending sorting (Default) */ - SORT_ORDER_DESC = 2 /*!< Descending sorting */ + SORT_ORDER_ASC = 1, /**< Ascending sorting (Default)*/ + SORT_ORDER_DESC = 2 /**< Descending sorting*/ } mysqlx_sort_direction_t; + +/** +* \enum mysqlx_opt_type_t +* Enumerating session options for using in mysqlx_session_option_get() +* and mysqlx_session_option_set() functions +*/ + typedef enum mysqlx_opt_type_enum { MYSQLX_OPT_HOST = 1, @@ -217,2102 +254,2158 @@ typedef enum mysqlx_opt_type_enum MYSQLX_OPT_DB = 5 } mysqlx_opt_type_t; -/*! @brief MYSQLX API - * - * @details Establish a session using string options provided as function parameters - * - * - * @param host server host address - * @param port port number - * @param user user name - * @param password password - * @param password default database name - * @param[out] out_error if error happens during connect the error message - * is returned through this parameter - * @param[out] err_code if error happens during connect the error code - * is returned through this parameter - * - * @return Pointer to mysqlx_session_t structure if connection is success, - * otherwise and the error is returned through - * the error [OUT] parameter - * - * @note The mysqlx_session_t pointer returned by the function must be - * properly closed using mysqlx_session_close() - * @note This type of session does not support executing plain SQL queries - */ + +/** + @brief MYSQLX API + + @details Establish a session using string options provided as function parameters + + @param host server host address + @param port port number + @param user user name + @param password password + @param password default database name + @param[out] out_error if error happens during connect the error message + is returned through this parameter + @param[out] err_code if error happens during connect the error code + is returned through this parameter + + @return Pointer to mysqlx_session_t structure if connection is success, + otherwise and the error is returned through + the error [OUT] parameter + + @note The mysqlx_session_t pointer returned by the function must be + properly closed using mysqlx_session_close() + @note This type of session does not support executing plain SQL queries +*/ + mysqlx_session_t * STDCALL mysqlx_get_session(const char *host, int port, const char *user, const char *password, const char *database, char out_error[MYSQLX_MAX_ERROR_LEN], int *err_code); -/*! @brief MYSQLX API - * - * @details Establish a session using connection string - * as "user:pass@host:port - * - * @param conn_string character connection string - * @param[out] out_error if error happens during connect the error message - * is returned through this parameter - * @param[out] err_code if error happens during connect the error code - * is returned through this parameter - * - * @return Pointer to mysqlx_session_t structure if connection is success, - * otherwise and the error is returned through - * the error [OUT] parameter - * - * @note The mysqlx_session_t pointer returned by the function must be - * properly closed using mysqlx_session_close() - * @note This type of session does not support executing plain SQL queries - */ + +/** + @brief MYSQLX API + + @details Establish a session using connection string + as "user:pass@host:port + + @param conn_string character connection string + @param[out] out_error if error happens during connect the error message + is returned through this parameter + @param[out] err_code if error happens during connect the error code + is returned through this parameter + + @return Pointer to mysqlx_session_t structure if connection is success, + otherwise and the error is returned through + the error [OUT] parameter + + @note The mysqlx_session_t pointer returned by the function must be + properly closed using mysqlx_session_close() + @note This type of session does not support executing plain SQL queries +*/ + mysqlx_session_t * STDCALL mysqlx_get_session_from_url(const char *conn_string, char out_error[MYSQLX_MAX_ERROR_LEN], int *err_code); -/*! @brief MYSQLX API - * - * @details Establish a session using mysqlx_session_options_t structure - * - * @param opt pointer to mysqlx_session_options_t structure containing - * the connection parameters - * @param[out] out_error if error happens during connect the error message - * is returned through this parameter - * @param[out] err_code if error happens during connect the error code - * is returned through this parameter - * - * @return Pointer to mysqlx_session_t structure if connection is success, - * otherwise and the error is returned through - * the error [OUT] parameter - * - * @note The mysqlx_session_t pointer returned by the function must be - * properly closed using mysqlx_session_close() - * @note This type of session does not support executing plain SQL queries - */ + +/** + @brief MYSQLX API + + @details Establish a session using mysqlx_session_options_t structure + + @param opt pointer to mysqlx_session_options_t structure containing + the connection parameters + @param[out] out_error if error happens during connect the error message + is returned through this parameter + @param[out] err_code if error happens during connect the error code + is returned through this parameter + + @return Pointer to mysqlx_session_t structure if connection is success, + otherwise and the error is returned through + the error [OUT] parameter + + @note The mysqlx_session_t pointer returned by the function must be + properly closed using mysqlx_session_close() + @note This type of session does not support executing plain SQL queries +*/ + mysqlx_session_t * STDCALL mysqlx_get_session_from_options(mysqlx_session_options_t *opt, char out_error[MYSQLX_MAX_ERROR_LEN], int *err_code); -/*! @brief MYSQLX API - * - * @details Establish a node session using string options provided as - * function parameters. A node session connects only to one - * mysqld node at a time - * - * @param host server host address - * @param port port number - * @param user user name - * @param password password - * @param database default database name - * @param[out] out_error if error happens during connect the error message - * is returned through this parameter - * @param[out] err_code if error happens during connect the error code - * is returned through this parameter - * - * @return Pointer to mysqlx_session_t structure if connection is success, - * otherwise and the error is returned through - * the error [OUT] parameter - * - * @note The mysqlx_session_t pointer returned by the function must be - * properly closed using mysqlx_session_close() - * @note This type of session supports executing plain SQL queries - */ + +/** + @brief MYSQLX API + + @details Establish a node session using string options provided as + function parameters. A node session connects only to one + mysqld node at a time + + @param host server host address + @param port port number + @param user user name + @param password password + @param database default database name + @param[out] out_error if error happens during connect the error message + is returned through this parameter + @param[out] err_code if error happens during connect the error code + is returned through this parameter + + @return Pointer to mysqlx_session_t structure if connection is success, + otherwise and the error is returned through + the error [OUT] parameter + + @note The mysqlx_session_t pointer returned by the function must be + properly closed using mysqlx_session_close() + @note This type of session supports executing plain SQL queries +*/ + mysqlx_session_t * STDCALL mysqlx_get_node_session(const char *host, int port, const char *user, const char *password, const char *database, char out_error[MYSQLX_MAX_ERROR_LEN], int *err_code); -/*! @brief MYSQLX API - * - * @details Establish a node session using connection string - * as "user:pass@host:port. A node session connects only to one - * mysqld node at a time. - * - * @param conn_string character connection string - * @param[out] out_error if error happens during connect the error message - * is returned through this parameter - * @param[out] err_code if error happens during connect the error code - * is returned through this parameter - * - * @return Pointer to mysqlx_session_t structure if connection is success, - * otherwise and the error is returned through - * the error [OUT] parameter - * - * @note The mysqlx_session_t pointer returned by the function must be - * properly closed using mysqlx_session_close() - * @note This type of session supports executing plain SQL queries - */ + +/** + @brief MYSQLX API + + @details Establish a node session using connection string + as "user:pass@host:port. A node session connects only to one + mysqld node at a time. + + @param conn_string character connection string + @param[out] out_error if error happens during connect the error message + is returned through this parameter + @param[out] err_code if error happens during connect the error code + is returned through this parameter + + @return Pointer to mysqlx_session_t structure if connection is success, + otherwise and the error is returned through + the error [OUT] parameter + + @note The mysqlx_session_t pointer returned by the function must be + properly closed using mysqlx_session_close() + @note This type of session supports executing plain SQL queries +*/ + mysqlx_session_t * STDCALL mysqlx_get_node_session_from_url(const char *conn_string, char out_error[MYSQLX_MAX_ERROR_LEN], int *err_code); -/*! @brief MYSQLX API - * - * @details Establish a node session using mysqlx_session_options_t structure - * - * @param opt pointer to mysqlx_session_options_t structure containing - * the connection parameters - * @param[out] out_error if error happens during connect the error message - * is returned through this parameter - * @param[out] err_code if error happens during connect the error code - * is returned through this parameter - * - * @return Pointer to mysqlx_session_t structure if connection is success, - * otherwise and the error is returned through - * the error [OUT] parameter - * - * @note The mysqlx_session_t pointer returned by the function must be - * properly closed using mysqlx_session_close() - * @note This type of session supports executing plain SQL queries - */ + +/** + @brief MYSQLX API + + @details Establish a node session using mysqlx_session_options_t structure + + @param opt pointer to mysqlx_session_options_t structure containing + the connection parameters + @param[out] out_error if error happens during connect the error message + is returned through this parameter + @param[out] err_code if error happens during connect the error code + is returned through this parameter + + @return Pointer to mysqlx_session_t structure if connection is success, + otherwise and the error is returned through + the error [OUT] parameter + + @note The mysqlx_session_t pointer returned by the function must be + properly closed using mysqlx_session_close() + @note This type of session supports executing plain SQL queries +*/ + mysqlx_session_t * STDCALL mysqlx_get_node_session_from_options(mysqlx_session_options_t *opt, char out_error[MYSQLX_MAX_ERROR_LEN], int *err_code); -/*! @brief MYSQLX API - * - * @details Closing the session. This function must be called by the user - * to prevent memory leaks. - * - * @param session Pointer to mysqlx_session_t handler to close + +/** + @brief MYSQLX API + + @details Closing the session. This function must be called by the user + to prevent memory leaks. + + @param session Pointer to mysqlx_session_t handler to close */ + void STDCALL mysqlx_session_close(mysqlx_session_t *session); -/* brief NOT IMPLEMENTED - * - * @details Closing the session. This function must be called by the user - * to prevent memory leaks. - * - * @param session Pointer to mysqlx_session_t handler to close - * - * @return session status - * -int STDCALL mysqlx_session_status(mysqlx_session_t *session); + +/** + @brief MYSQLX API + + @details check the session validity + + @param session Pointer to mysqlx_session_t handle to check + + @return 1 - if the session is valid, 0 - if the session is not valid + + @note the function checks only the internal session status without sending + anything to the server. +*/ + +int STDCALL +mysqlx_session_valid(mysqlx_session_t *sess); + + +/** + @brief MYSQLX API + + @details Create a statement handle for a plain SQL query. + The query supports parameters and placeholders that can be + added later using mysqlx_stmt_bind() function + + @param sess session handler + @param query SQL query + @param length length of the query + + @return statement handle containing the results and/or error. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the SQL query the returned statement has to be + given to mysqlx_execute() */ -/*! @brief MYSQLX API - * - * @details Create a statement handler for a plain SQL query. - * The query supports parameters and placeholders that can be - * added later using mysqlx_stmt_bind() function - * - * @param sess session handler - * @param query SQL query - * @param length length of the query - * - * @return - * statement handler containing the results and/or error. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the SQL query the returned statement has to be - * given to mysqlx_execute() - */ mysqlx_stmt_t * STDCALL mysqlx_sql_new(mysqlx_session_t *sess, const char *query, uint32_t length); -/* brief MYSQLX API - * - * @details Create a statement handler for SQL query with parameters - * - * @param sess session handler - * @param format SQL query format string with parameter markers as in printf() - * @param length length of the query - * @param ... parameter values of the types corresponding to the format string - * - * @return - * statement handler containing the results and/or error. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the SQL query the returned statement has to be - given to mysqlx_execute() -mysqlx_stmt_t * STDCALL -mysqlx_sql_query_v(mysqlx_session_t *sess, const char *format, - uint32_t length, ...); -*/ -// Operations +/** + @brief MYSQLX API -/*! @brief MYSQLX API - * - * @details Start new table SELECT operation without actually executing it. - * - * @param table table handle - * - * @return - * STMT handler for the newly created SELECT operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the SQL query the returned STMT has to be + @details Start new table SELECT operation without actually executing it. + + @param table table handle + + @return Statement handle for the newly created SELECT operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the SQL query the returned Statement has to be given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_table_select_new(mysqlx_table_t *table); -/* - All variadic parameters table functions must close the list of items with NULL value - mysqlx_set_select_items() - mysqlx_set_select_order_by() - mysqlx_set_select_group_by() - mysqlx_set_insert_columns() - mysqlx_set_insert_rows() - mysqlx_set_update_set() - mysqlx_set_update_order_by() - mysqlx_set_delete_order_by() - Same is for the collection functions: -*/ +/** + @brief MYSQLX API + @details Setting projections (items to select or find) defined as column + names, values, constants or expressions. + operation. See mysqlx_set_where() + + @param stmt pointer to statement structure for which the projections are set + @param ... - variable parameters list consisting of character strings + that define projections. The list is terminated by PARAM_END: + proj_1, ..., proj_n, PARAM_END + (PARAM_END marks the end of projectins items list) + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note This function can be only called for the table SELECT or collection + FIND operations (see mysqlx_table_select_new() and + mysqlsx_collection_find_new()) + */ -/*! @brief MYSQLX API - * @details Setting projections (items to select or find) defined as column - * names, values, constants or expressions. - * operation. See mysqlx_set_where() - * - * @param crud pointer to statement structure for which the projections are set - * @param ... - variable parameters list consisting of character strings - * that define projections. The list is terminated by PARAM_END: - * proj_1, ..., proj_n, PARAM_END - * (PARAM_END marks the end of projectins items list) - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note This function can be only called for the table SELECT or collection - * FIND operations (see mysqlx_table_select_new() and - * mysqlsx_collection_find_new()) - * */ int STDCALL mysqlx_set_items(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * @details a macro defining a function for setting projections for SELECT - * operation. See mysqlx_set_items() - * */ + +/** + @brief MYSQLX API + @details a macro defining a function for setting projections for SELECT + operation. See mysqlx_set_items() + */ + #define mysqlx_set_select_items mysqlx_set_items -/*! @brief MYSQLX API - * @details a macro defining a function for setting WHERE for SELECT - * operation. See mysqlx_set_where() - * */ +/** + @brief MYSQLX API + @details a macro defining a function for setting WHERE for SELECT + operation. See mysqlx_set_where() + */ + #define mysqlx_set_select_where mysqlx_set_where -/*! @brief MYSQLX API - * @details a macro defining a function for setting ORDER BY for SELECT - * operation. See mysqlx_set_order_by() - * */ + +/** + @brief MYSQLX API + @details a macro defining a function for setting ORDER BY for SELECT + operation. See mysqlx_set_order_by() + */ + #define mysqlx_set_select_order_by mysqlx_set_order_by + /* brief MYSQLX API - * @details a macro defining a function for setting HAVING for SELECT - * operation. See mysqlx_set_having() - * + @details a macro defining a function for setting HAVING for SELECT + operation. See mysqlx_set_having() + + #define mysqlx_set_select_having mysqlx_set_having +*/ + + +/** + @brief MYSQLX API + @details a macro defining a function for setting LIMIT for SELECT + operation. See mysqlx_set_limit_and_offset() */ -/*! @brief MYSQLX API - * @details a macro defining a function for setting LIMIT for SELECT - * operation. See mysqlx_set_limit_and_offset() - * */ #define mysqlx_set_select_limit_and_offset mysqlx_set_limit_and_offset -/*! @brief MYSQLX API - * - * @details - * Limit given statement operation to rows/documents that satisfy given WHERE clause: - * - for select/find operations limit the returned rows/documents, - * - for update/modify/delete/remove operations limit the rows/documents - * affected by the operations. - * - * Operations supported by this function: - * SELECT, FIND, UPDATE, MODIFY, DELETE, REMOVE - * Calling it for INSERT or ADD will result in an error - * - * @param crud pointer to statement structure - * @param where_expr character string containing WHERE clause, - * which will be parsed as required - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note this function can be be used directly, but for the convenience - * the code can use the specialized macros for a specific operation. - * For SELECT operation the user code should use - * mysqlx_set_select_where() macros that map the - * corresponding mysqlx_set_where() function. - * This way the unsupported operations will not be used. - */ -int STDCALL mysqlx_set_where(mysqlx_stmt_t *stmt, const char *where_expr); -/*! @brief MYSQLX API - * - * @details Set ORDER BY clause for statement operation - * Operations supported by this function: - * SELECT, FIND, UPDATE, MODIFY, DELETE, REMOVE - * Calling it for INSERT or ADD will result in an error - * - * @param crud - pointer to statement structure - * @param ... - variable parameters list consisting of (expression, direction) pairs - * terminated by PARAM_END: - * expr_1, direction_1, ..., expr_n, direction_n, PARAM_END - * (PARAM_END marks the end of parameters list) - * Each expression computes value used to sort - * the rows/documents in ascending or descending order, - * as determined by direction constant - * (list the direction enum names). - * Special attention must be paid to the expression - * strings because the empty string "" or NULL will be treated - * as the end of sequence - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note this function can be be used directly, but for the convenience - * the code can use the specialized macros for a specific operation. - * For SELECT operation the user code should use - * mysqlx_set_select_order_by() macros that map the - * corresponding mysqlx_set_order_by() function. - * This way the unsupported operations will not be used. - */ -int STDCALL mysqlx_set_order_by(mysqlx_stmt_t *stmt, ...); +/** + @brief MYSQLX API -/* brief NOT IMPLEMENTED - * - * @details Set GROUP BY clause for statement operation - * Operations supported by SELECT. - * Calling it for INSERT or ADD will result in an error - * - * @param crud - pointer to statement structure - * @param expr - expression computing value used to group rows/documents - * @param ... - variable parameters list consisting of expressions - * terminated by PARAM_END: - * expr_1, ..., expr_n, PARAM_END - * (PARAM_END marks the end of parameters list) - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * -int STDCALL mysqlx_set_select_group_by(mysqlx_stmt_t *stmt, const char *expr, ...); // NOT IMPLEMENTED + @details Limit given statement operation to rows/documents that satisfy + given WHERE clause: + - for select/find operations limit the returned rows/documents, + - for update/modify/delete/remove operations limit + the rows/documents affected by the operations. + + Operations supported by this function: + SELECT, FIND, UPDATE, MODIFY, DELETE, REMOVE + Calling it for INSERT or ADD will result in an error + + @param stmt pointer to statement structure + @param where_expr character string containing WHERE clause, + which will be parsed as required + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note this function can be be used directly, but for the convenience + the code can use the specialized macros for a specific operation. + For SELECT operation the user code should use + mysqlx_set_select_where() macros that map the + corresponding mysqlx_set_where() function. + This way the unsupported operations will not be used. */ -/* brief NOT IMPLEMENTED - * - * @note On the implementation stage the function can change its name, - * parameters or return type - * -int STDCALL mysqlx_set_having(mysqlx_stmt_t *stmt, const char *criteria); // NOT IMPLEMENTED +int STDCALL mysqlx_set_where(mysqlx_stmt_t *stmt, const char *where_expr); + + +/** + @brief MYSQLX API + + @details Set ORDER BY clause for statement operation + Operations supported by this function: + SELECT, FIND, UPDATE, MODIFY, DELETE, REMOVE + Calling it for INSERT or ADD will result in an error + + @param stmt - pointer to statement structure + @param ... - variable parameters list consisting of (expression, direction) pairs + terminated by PARAM_END: + expr_1, direction_1, ..., expr_n, direction_n, PARAM_END + (PARAM_END marks the end of parameters list) + Each expression computes value used to sort + the rows/documents in ascending or descending order, + as determined by direction constant + (list the direction enum names). + Special attention must be paid to the expression + strings because the empty string "" or NULL will be treated + as the end of sequence + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note this function can be be used directly, but for the convenience + the code can use the specialized macros for a specific operation. + For SELECT operation the user code should use + mysqlx_set_select_order_by() macros that map the + corresponding mysqlx_set_order_by() function. + This way the unsupported operations will not be used. */ -/*! @brief MYSQLX API - * - * @details Set LIMIT and OFFSET for statement operations which work on ranges of rows/documents: - * - for slect/find operations limit the number of returned rows/documents, - * - for update/delete limit the number of documents affected by the operation. - * - * Operations supported by this function: - * SELECT, FIND - use both LIMIT and OFFSET - * UPDATE, MODIFY, DELETE, REMOVE - use only LIMIT - * - * Calling it for INSERT or ADD will result in an error - * - * @param crud pointer to statement structure - * @param row_count the number of result rows to return - * @param offset the number of rows to skip before starting counting - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note this function can be be used directly, but for the convenience - * the code can use the specialized macros for a specific operation. - * For SELECT operation the user code should use - * mysqlx_set_select_limit_and_offset() macros that map the - * corresponding mysqlx_set_limit_and_offset() function. - * This way the unsupported operations will not be used. - * - * @note Each call to this function replaces previously set LIMIT +int STDCALL mysqlx_set_order_by(mysqlx_stmt_t *stmt, ...); + + +/** + @brief MYSQLX API + + @details Set LIMIT and OFFSET for statement operations which work on ranges of rows/documents: + - for slect/find operations limit the number of returned rows/documents, + - for update/delete limit the number of documents affected by the operation. + + Operations supported by this function: + SELECT, FIND - use both LIMIT and OFFSET + UPDATE, MODIFY, DELETE, REMOVE - use only LIMIT + + Calling it for INSERT or ADD will result in an error + + @param stmt pointer to statement structure + @param row_count the number of result rows to return + @param offset the number of rows to skip before starting counting + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note this function can be be used directly, but for the convenience + the code can use the specialized macros for a specific operation. + For SELECT operation the user code should use + mysqlx_set_select_limit_and_offset() macros that map the + corresponding mysqlx_set_limit_and_offset() function. + This way the unsupported operations will not be used. + + @note Each call to this function replaces previously set LIMIT */ + int STDCALL mysqlx_set_limit_and_offset(mysqlx_stmt_t *stmt, uint64_t row_count, uint64_t offset); -/*! @brief NOT IMPLEMENTED - * - * @details Start new table INSERT operation without actually executing it. - * for this parameter. - * @param table table handle - * - * @return - * STMT handle for the newly created INSERT operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the SQL query the returned STMT has to be + +/** + @brief MYSQLX API + + @details Start new table INSERT operation without actually executing it. + for this parameter. + @param table table handle + + @return + Statement handle for the newly created INSERT operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the SQL query the returned Statement has to be given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_table_insert_new(mysqlx_table_t *table); -/*! @brief MYSQLX API - * - * @details The function provides the column names for the statement INSERT. - * User code must ensure that the column values are correct - * because the names are not validated until receiving the query on - * the server side after executing mysqlx_execute(). - * - * @param crud pointer to CRUD - * @param ... - variable parameters list consisting of column names - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note This function can only be called after mysqlx_set_insert_columns() - * which defines the column names and their types - * @note Each new call clears the list of column for a given CRUD - * if it was set earlier + +/** + @brief MYSQLX API + + @details The function provides the column names for the statement INSERT. + User code must ensure that the column values are correct + because the names are not validated until receiving the query on + the server side after executing mysqlx_execute(). + + @param stmt pointer to the statement handle + @param ... - variable parameters list consisting of column names + @return RESULT_OK - on success; RESULT_ERR - on error + + @note This function can only be called after mysqlx_set_insert_columns() + which defines the column names and their types + @note Each new call clears the list of column for a given statement + if it was set earlier */ + int STDCALL mysqlx_set_insert_columns(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * - * @details The function provides the row data for the statement INSERT. - * User code must ensure that the number of values and the order they are specified - * in the parameters is the same as the number of columns and their order in - * mysqlx_set_insert_columns(), which defines the column names for INSERT. - * However, mysqlx_set_insert_columns() can be skipped. In this case the number - * of columns and their order must correspond to the same in the table being - * inserted. - * - * @param crud pointer to CRUD - * @param ... - variable parameters list consisting of (type, value) pairs - * terminated by PARAM_END. The pairs must be listed in the order they - * appear in the list of columns - * For MYSQLX_TYPE_BYTES the function will expect three parameters - * instead of two as for all other types: - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note This function can only be called after mysqlx_set_insert_columns() - * which defines the column names and their types - * @note Each new call provides the row values for the new row, which - * can be used for multi-row inserts + +/** + @brief MYSQLX API + + @details The function provides the row data for the statement INSERT. + User code must ensure that the number of values and the order they are specified + in the parameters is the same as the number of columns and their order in + mysqlx_set_insert_columns(), which defines the column names for INSERT. + However, mysqlx_set_insert_columns() can be skipped. In this case the number + of columns and their order must correspond to the same in the table being + inserted. + + @param stmt pointer to the statement handle + @param ... - variable parameters list consisting of (type, value) pairs + terminated by PARAM_END. The pairs must be listed in the order they + appear in the list of columns + For MYSQLX_TYPE_BYTES the function will expect three parameters + instead of two as for all other types: + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note This function can only be called after mysqlx_set_insert_columns() + which defines the column names and their types + @note Each new call provides the row values for the new row, which + can be used for multi-row inserts */ + int STDCALL mysqlx_set_insert_row(mysqlx_stmt_t *stmt, ...); -/* brief MYSQLX API - * - * @details The function provides the columns data for the statement INSERT. - * User code must ensure that the number of values in the parameters corresponds - * to the number of columns in the table because this is not checked - * until receiving the query on the server side. - * - * @param crud pointer to CRUD - * @param ... - variable parameters list consisting of (name, type) pairs - * terminated by PARAM_END: - * - * name_1, type_id1, name_2, type_id2, ..., name_n, type_id_n, PARAM_END - * (PARAM_END marks the end of parameters list). - * - * type_id is the numeric identifier, which helps to determine the type - * of the value provided as the next parameter. The user code must - * ensure that type_id corresponds to the actual value type. Otherwise, - * the value along with and all sequential types and values are most - * likely to be corrupted. - * - * allowed types are listed in mysqlx_data_type_t enum. - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note Each new call resets the row values set by the previous call to - * mysqlx_set_insert_columns() - * -int STDCALL -mysqlx_set_insert_columns(mysqlx_stmt_t *stmt, ...); // NOT IMPLEMENTED -*/ -/*! @brief MYSQLX API - * - * @details Start new table UPDATE operation without actually executing it. - * - * @param table table name - * - * @return - * STMT handle for the newly created UPDATE operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the SQL query the returned STMT has to be - * given to mysqlx_execute() +/** + @brief MYSQLX API + + @details Start new table UPDATE operation without actually executing it. + + @param table table name + + @return STMT handle for the newly created UPDATE operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the SQL query the returned STMT has to be + given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_table_update_new(mysqlx_table_t *table); -/*! @brief MYSQLX API - * - * @details Set values for the columns in the UPDATE statement. - * - * @param crud - pointer to statement structure - * @param ... - variable parameters list consisting of triplets - * - * representing column names, value types and values as - * expressions.The list is terminated by PARAM_END: - * column_1, type_1, val_1, ..., column_n, type_n, val_n, PARAM_END - * (PARAM_END marks the end of parameters list) - * The value type is defined in mysqlx_data_type_t enum. - * If the value is to be computed on the server side the type - * has to be set to MYSQLX_TYPE_EXPR. The value (expression) - * should be specified as a character string expression. - * For MYSQLX_TYPE_BYTES the function will expect four parameters - * instead of three as for all other types: - * - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note All fields and their corresponding expressions must be set in one call - * otherwise the next call to this function will reset all parameters to - * their new values. - */ + +/** + @brief MYSQLX API + + @details Set values for the columns in the UPDATE statement. + + @param stmt - pointer to statement structure + @param ... - variable parameters list consisting of triplets + + representing column names, value types and values as + expressions.The list is terminated by PARAM_END: + column_1, type_1, val_1, ..., column_n, type_n, val_n, PARAM_END + (PARAM_END marks the end of parameters list) + The value type is defined in mysqlx_data_type_t enum. + If the value is to be computed on the server side the type + has to be set to MYSQLX_TYPE_EXPR. The value (expression) + should be specified as a character string expression. + For MYSQLX_TYPE_BYTES the function will expect four parameters + instead of three as for all other types: + + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note All fields and their corresponding expressions must be set in one call + otherwise the next call to this function will reset all parameters to + their new values. +*/ + int STDCALL mysqlx_set_update_values(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * @details a macro defining a function for setting WHERE clause for UPDATE - * operation. See mysqlx_set_where() - * */ + +/** + @brief MYSQLX API + @details a macro defining a function for setting WHERE clause for UPDATE + operation. See mysqlx_set_where() + */ + #define mysqlx_set_update_where mysqlx_set_where -/*! @brief MYSQLX API - * @details a macro defining a function for setting LIMIT for UPDATE - * operation. See mysqlx_set_limit_and_offset() - * */ -#define mysqlx_set_update_limit(CRUD, LIM) mysqlx_set_limit_and_offset(CRUD, LIM, 0) -/*! @brief MYSQLX API - * @details a macro defining a function for setting ORDER BY clause for UPDATE - * operation. See mysqlx_set_oder_by() - * */ +/** + @brief MYSQLX API + @details a macro defining a function for setting LIMIT for UPDATE + operation. See mysqlx_set_limit_and_offset() + */ + +#define mysqlx_set_update_limit(STMT, LIM) mysqlx_set_limit_and_offset(STMT, LIM, 0) + + +/** + @brief MYSQLX API + @details a macro defining a function for setting ORDER BY clause for UPDATE + operation. See mysqlx_set_oder_by() + */ + #define mysqlx_set_update_order_by mysqlx_set_order_by // Functios for DELETE (some functions from SELECT are reused) -/*! @brief MYSQLX API - * - * @details Start new table DELETE operation without actually executing it. - * - * @param table table handle - * - * @return - * STMT handle for the newly created DELETE operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the SQL query the returned STMT has to be - * given to mysqlx_execute() + +/** + @brief MYSQLX API + + @details Start new table DELETE operation without actually executing it. + + @param table table handle + + @return STMT handle for the newly created DELETE operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the SQL query the returned STMT has to be + given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_table_delete_new(mysqlx_table_t *table); -/*! @brief MYSQLX API - * @details a macro defining a function for setting WHERE clause for DELETE - * operation. See mysqlx_set_where() - * */ + +/** + @brief MYSQLX API + @details a macro defining a function for setting WHERE clause for DELETE + operation. See mysqlx_set_where() + */ + #define mysqlx_set_delete_where mysqlx_set_where -/*! @brief MYSQLX API - * @details a macro defining a function for setting LIMIT for DELETE - * operation. See mysqlx_set_limit_and_offset() - * */ -#define mysqlx_set_delete_limit(CRUD, LIM) mysqlx_set_limit_and_offset(CRUD, LIM, 0) +/** + @brief MYSQLX API + @details a macro defining a function for setting LIMIT for DELETE + operation. See mysqlx_set_limit_and_offset() + */ -/*! @brief MYSQLX API - * @details a macro defining a function for setting ORDER BY for DELETE - * operation. See mysqlx_set_order_by() - * */ -#define mysqlx_set_delete_order_by mysqlx_set_order_by +#define mysqlx_set_delete_limit(STMT, LIM) mysqlx_set_limit_and_offset(STMT, LIM, 0) -/*! @brief MYSQLX API - * - * @details Execute a statement created by mysqlx_table_select_new(), - * mysqlx_table_insert_new(), mysqlx_table_update_new(), - * mysqlx_table_delete_new(), mysqlx_sql_new(), etc. - * - * @param crud pointer to statement structure - * - * @return A MYSQL_RESULT handle that can be used to access results - * of the operation. Returned handle is valid until the CRUD - * handle is freed (when session is closed or explicitly with - * mysqlx_free()) or until another call to mysqlx_execute() - * on the same statement handle is made. It is also possible to close - * a RESULT hanlde and free all resources used by it earlier with - * mysqlx_result_free() call. - * On error NULL is returned. The error is set for statement handler. +/** + @brief MYSQLX API + @details a macro defining a function for setting ORDER BY for DELETE + operation. See mysqlx_set_order_by() */ + +#define mysqlx_set_delete_order_by mysqlx_set_order_by + + +/** + @brief MYSQLX API + + @details Execute a statement created by mysqlx_table_select_new(), + mysqlx_table_insert_new(), mysqlx_table_update_new(), + mysqlx_table_delete_new(), mysqlx_sql_new(), etc. + + @param stmt pointer to statement structure + + @return A MYSQL_RESULT handle that can be used to access results + of the operation. Returned handle is valid until the statement + handle is freed (when session is closed or explicitly with + mysqlx_free()) or until another call to mysqlx_execute() + on the same statement handle is made. It is also possible to close + a RESULT hanlde and free all resources used by it earlier with + mysqlx_result_free() call. + On error NULL is returned. The error is set for statement handler. +*/ + mysqlx_result_t * STDCALL mysqlx_execute(mysqlx_stmt_t *stmt); -/*! @brief MYSQLX_API - * - * @details Rows/documents contained in a result must be fetched in a timely fashion. - * Failing to do that can result in an error and lost access to the - * remaining part of the result. This function can store complete result - * in memory so it can be accessed at any time, as long as mysqlx_result_t - * handle is valid. - * - * @param result result handler used for obtaining and buffering the result - * @param[out] num number of records buffered - * - * @return RESULT_OK - on success; RESULT_ERR - on error. If the error occurred - * it can be retrieved by mysqlx_error() function. - * - * @note Even in case of an error some rows/documents might be buffered if they - * were retrieved before the error occurred. - */ + +/** + @brief MYSQLX_API + + @details Rows/documents contained in a result must be fetched in a timely fashion. + Failing to do that can result in an error and lost access to the + remaining part of the result. This function can store complete result + in memory so it can be accessed at any time, as long as mysqlx_result_t + handle is valid. + + @param result result handler used for obtaining and buffering the result + @param[out] num number of records buffered + + @return RESULT_OK - on success; RESULT_ERR - on error. If the error occurred + it can be retrieved by mysqlx_error() function. + + @note Even in case of an error some rows/documents might be buffered if they + were retrieved before the error occurred. +*/ + int STDCALL mysqlx_store_result(mysqlx_result_t *result, size_t *num); -/*! @brief MYSQLX API - * - * @details Create a schema - * - * @param sess session handler - * @param schema the name of the schema to be created - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * The error handle can be obtained from the session - * using mysqlx_error() function + +/** + @brief MYSQLX API + + @details Create a schema + + @param sess session handler + @param schema the name of the schema to be created + + @return RESULT_OK - on success; RESULT_ERR - on error + The error handle can be obtained from the session + using mysqlx_error() function */ + int STDCALL mysqlx_schema_create(mysqlx_session_t *sess, const char *schema); -/*! @brief MYSQLX API - * - * @details Drop a schema - * - * @param sess session handler - * @param schema the name of the schema to be dropped - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * The error handle can be obtained from the session - * using mysqlx_error() function + +/** + @brief MYSQLX API + + @details Drop a schema + + @param sess session handler + @param schema the name of the schema to be dropped + + @return RESULT_OK - on success; RESULT_ERR - on error + The error handle can be obtained from the session + using mysqlx_error() function */ + int STDCALL mysqlx_schema_drop(mysqlx_session_t *sess, const char *schema); -/*! @brief MYSQLX API - * - * @details Drop a table - * - * @param schema schema handle - * @param table the name of the table to drop - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * The error handle can be obtained from the session - * using mysqlx_error() function + +/** + @brief MYSQLX API + + @details Drop a table + + @param schema schema handle + @param table the name of the table to drop + + @return RESULT_OK - on success; RESULT_ERR - on error + The error handle can be obtained from the session + using mysqlx_error() function */ + int STDCALL mysqlx_table_drop(mysqlx_schema_t *schema, const char *table); -/*! @brief MYSQLX API - * - * @details Drop a view - * - * @param schema schema handle - * @param view the name of the view to drop - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * The error handle can be obtained from the session - * using mysqlx_error() function +/** + @brief MYSQLX API + + @details Drop a view + + @param schema schema handle + @param view the name of the view to drop + + @return RESULT_OK - on success; RESULT_ERR - on error + The error handle can be obtained from the session + using mysqlx_error() function */ + int STDCALL mysqlx_view_drop(mysqlx_schema_t *schema, const char *view); -/*! @brief MYSQLX API - * - * @details Create a new collection in a specified schema - * - * @param schema schema handle - * @param collection collection name to create - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * The error handle can be obtained from the session - * using mysqlx_error() function + +/** + @brief MYSQLX API + + @details Create a new collection in a specified schema + + @param schema schema handle + @param collection collection name to create + + @return RESULT_OK - on success; RESULT_ERR - on error + The error handle can be obtained from the session + using mysqlx_error() function */ + int STDCALL mysqlx_collection_create(mysqlx_schema_t *schema, const char *collection); -/*! @brief MYSQLX API - * - * @details Drop an existing collection in a specified schema - * - * @param schema schema handle - * @param collection collection name to drop - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * The error handle can be obtained from the session - * using mysqlx_error() function + +/** + @brief MYSQLX API + + @details Drop an existing collection in a specified schema + + @param schema schema handle + @param collection collection name to drop + + @return RESULT_OK - on success; RESULT_ERR - on error + The error handle can be obtained from the session + using mysqlx_error() function */ + int STDCALL mysqlx_collection_drop(mysqlx_schema_t *schema, const char *collection); -/*! @brief MYSQLX API - * - * @details Create a new STMT operation for adding a new collection - * - * @param collection collection handle - * - * @return - * STMT handle for the newly created ADD operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the operation the returned STMT has to be - * given to mysqlx_execute() + +/** + @brief MYSQLX API + + @details Create a new STMT operation for adding a new collection + + @param collection collection handle + + @return STMT handle for the newly created ADD operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the operation the returned STMT has to be + given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_collection_add_new(mysqlx_collection_t *collection); -/*! @brief MYSQLX API - * - * @details The function provides the document data for the statement ADD as - * JSON document like "{ key_1: value_1, ..., key_N: value_N }" - * User code must ensure the validity of the document because it is - * not checked until receiving the query on the server side. - * - * @param crud pointer to CRUD - * @param json_doc - the character string describing JSON document to add - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note This function can only be called after mysqlx_collection_add_new() - * which creates a new statement operation - * @note Each new call provides the values for the new document, which - * can be used for multi-document add operations + +/** + @brief MYSQLX API + + @details The function provides the document data for the statement ADD as + JSON document like "{ key_1: value_1, ..., key_N: value_N }" + User code must ensure the validity of the document because it is + not checked until receiving the query on the server side. + + @param stmt pointer to the statement handle + @param json_doc - the character string describing JSON document to add + @return RESULT_OK - on success; RESULT_ERR - on error + + @note This function can only be called after mysqlx_collection_add_new() + which creates a new statement operation + @note Each new call provides the values for the new document, which + can be used for multi-document add operations */ + int STDCALL mysqlx_set_add_document(mysqlx_stmt_t *stmt, const char *json_doc); -/*! @brief MYSQLX API - * - * @details Find a document in a collection - * - * @param collection collection handle - * - * @return - * STMT handle for the newly created FIND operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the operation the returned STMT has to be - * given to mysqlx_execute() + +/** + @brief MYSQLX API + + @details Find a document in a collection + + @param collection collection handle + + @return STMT handle for the newly created FIND operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the operation the returned STMT has to be + given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_collection_find_new(mysqlx_collection_t *collection); -/*! @brief MYSQLX API - * @details Setting projections (items to select or find) defined as column - * names, values, constants or expressions. - * operation. See mysqlx_set_where() - * - * @param crud pointer to statement structure for which the projections are set - * @param proj projection specification describing JSON document projections as - * "{proj1: expr1, proj2: expr2}". - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note This function can be only called for the collection - * FIND operations (see mysqlsx_collection_find_new()) - * */ + +/** + @brief MYSQLX API + @details Setting projections (items to select or find) defined as column + names, values, constants or expressions. + operation. See mysqlx_set_where() + + @param stmt pointer to statement structure for which the projections are set + @param proj projection specification describing JSON document projections as + "{proj1: expr1, proj2: expr2}". + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note This function can be only called for the collection + FIND operations (see mysqlsx_collection_find_new()) + */ + int STDCALL mysqlx_set_find_projection(mysqlx_stmt_t *stmt, const char *proj); -/*! @brief MYSQLX API - * @details a macro defining a function for setting criteria for FIND - * operation. See mysqlx_set_where() - * */ + +/** + @brief MYSQLX API + @details a macro defining a function for setting criteria for FIND + operation. See mysqlx_set_where() + */ + #define mysqlx_set_find_criteria mysqlx_set_where -/*! @brief MYSQLX API - * @details a macro defining a function for setting LIMIT for DELETE - * operation. See mysqlx_set_limit_and_offset() - * */ -#define mysqlx_set_find_limit_and_offset(CRUD, LIM, OFFS) mysqlx_set_limit_and_offset(CRUD, LIM, OFFS) -/*! @brief MYSQLX API - * @details a macro defining a function for setting ORDER BY for SELECT - * operation. See mysqlx_set_order_by() - * */ +/** + @brief MYSQLX API + @details a macro defining a function for setting LIMIT for DELETE + operation. See mysqlx_set_limit_and_offset() + */ + +#define mysqlx_set_find_limit_and_offset(STMT, LIM, OFFS) mysqlx_set_limit_and_offset(STMT, LIM, OFFS) + + +/** + @brief MYSQLX API + @details a macro defining a function for setting ORDER BY for SELECT + operation. See mysqlx_set_order_by() + */ + #define mysqlx_set_find_order_by mysqlx_set_order_by -/*! @brief MYSQLX API - * - * @details for binding values for parametrized queries. - * User code must ensure that the number of values in bind is the same - * as the number of parameters in the query because this is not checked - * until receiving the query on the server side. - * - * @param crud pointer to CRUD - * @param ... variable parameters list, which has different structure for SQL - * no-SQL (CRUD) operations. - * For SQL operation it is consisting of (type, value) pairs - * terminated by PARAM_END: - * - * type_id1, value1, type_id2, value2, ..., type_id_n, value_n, PARAM_END - * (PARAM_END marks the end of parameters list). - * - * For statement SELECT, INSERT, UPDATE, DELETE, FIND, ADD, MODIFY and REMOVE - * operations the parameters come as triplets (param_name, type, value). - * - * name1, type_id1, value1, name2, type_id2, value2, ..., - * namen, type_id_n, value_n, PARAM_END - * (PARAM_END marks the end of parameters list). - * - * type_id is the numeric identifier, which helps to determine the type - * of the value provided as the next parameter. The user code must - * ensure that type_id corresponds to the actual value type. Otherwise, - * the value along with and all sequential types and values are most - * likely to be corrupted. - * It is recommended to use PARAM_ macros to keep the list integrity: - * PARAM_UINT(), PARAM_SINT(), PARAM_FLOAT(), PARAM_DOUBLE(), PARAM_STRING(), - * PARAM_BYTES(), PARAM_EXPR() for different data types instead of - * (MYSQLX_TYPE_, value) pairs. - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note Each new call resets the binds set by the previous call to - * mysqlx_stmt_bind() + +/** + @brief MYSQLX API + + @details for binding values for parametrized queries. + User code must ensure that the number of values in bind is the same + as the number of parameters in the query because this is not checked + until receiving the query on the server side. + + @param stmt pointer to the statement handle + @param ... variable parameters list, which has different structure for SQL + no-SQL operations. + For SQL operation it is consisting of (type, value) pairs + terminated by PARAM_END: + + type_id1, value1, type_id2, value2, ..., type_id_n, value_n, PARAM_END + (PARAM_END marks the end of parameters list). + + For statement SELECT, INSERT, UPDATE, DELETE, FIND, ADD, MODIFY and REMOVE + operations the parameters come as triplets (param_name, type, value). + + name1, type_id1, value1, name2, type_id2, value2, ..., + namen, type_id_n, value_n, PARAM_END + (PARAM_END marks the end of parameters list). + + type_id is the numeric identifier, which helps to determine the type + of the value provided as the next parameter. The user code must + ensure that type_id corresponds to the actual value type. Otherwise, + the value along with and all sequential types and values are most + likely to be corrupted. + It is recommended to use PARAM_ macros to keep the list integrity: + PARAM_UINT(), PARAM_SINT(), PARAM_FLOAT(), PARAM_DOUBLE(), PARAM_STRING(), + PARAM_BYTES(), PARAM_EXPR() for different data types instead of + (MYSQLX_TYPE_, value) pairs. + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note Each new call resets the binds set by the previous call to + mysqlx_stmt_bind() */ + int STDCALL mysqlx_stmt_bind(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * - * @details Create a Collection MODIFY operation - * - * @param collection collection handle - * - * @return - * STMT handle for the newly created FIND operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the MODIFY query the returned STMT has to be - * given to mysqlx_execute() + +/** + @brief MYSQLX API + + @details Create a Collection MODIFY operation + + @param collection collection handle + + @return Statement handle for the newly created FIND operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the MODIFY query the returned Statement has to be + given to mysqlx_execute() */ + mysqlx_stmt_t * STDCALL mysqlx_collection_modify_new(mysqlx_collection_t *collection); -/*! @brief MYSQLX API - * @details Set fields in a document to the designated JSON values. - * - * @param crud pointer to statement initated for Collectin MODIFY operation - * @ ... list of parameters that come as triplets - * - * Each triplet represents a value inside a document that can - * be located by field_path. The value_type is the type identifier - * for the data type of value (see mysqlx_data_type_t enum) - * The list is terminated by PARAM_END. - * For MYSQLX_TYPE_BYTES there will be one extra parameter specifying - * the length of the binary data: - * - * - * @note For the convenience the code can use PARAM_XXXX(val) macros - * instead of MYSQLX_TYPE_XXXX, val. - * - * @return RESULT_OK - on success; RESULT_ERR - on error - */ + +/** + @brief MYSQLX API + @details Set fields in a document to the designated JSON values. + + @param stmt pointer to statement initated for Collectin MODIFY operation + @ ... list of parameters that come as triplets + + Each triplet represents a value inside a document that can + be located by field_path. The value_type is the type identifier + for the data type of value (see mysqlx_data_type_t enum) + The list is terminated by PARAM_END. + For MYSQLX_TYPE_BYTES there will be one extra parameter specifying + the length of the binary data: + + + @note For the convenience the code can use PARAM_XXXX(val) macros + instead of MYSQLX_TYPE_XXXX, val. + + @return RESULT_OK - on success; RESULT_ERR - on error +*/ + int STDCALL mysqlx_set_modify_set(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * @details Unset fields in a document - * - * @param crud pointer to statement initated for Collectin MODIFY operation - * @param ... list of the documents fields paths that should be unset. Each - * entry in this list is a character string. - * The list is terminated by PARAM_END. - * - * @return RESULT_OK - on success; RESULT_ERR - on error - */ + +/** + @brief MYSQLX API + @details Unset fields in a document + + @param stmt pointer to statement initated for Collectin MODIFY operation + @param ... list of the documents fields paths that should be unset. Each + entry in this list is a character string. + The list is terminated by PARAM_END. + + @return RESULT_OK - on success; RESULT_ERR - on error +*/ + int STDCALL mysqlx_set_modify_unset(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * @details Insert elements into an array in a document - * - * @param crud pointer to statement initated for Collectin MODIFY operation - * @param ... list of parameters that come as triplets - * - * Each triplet represents a value inside a document that can - * be located by field_path. The value_type is the type identifier - * for the data type of value (see mysqlx_data_type_t enum) - * The list is terminated by PARAM_END. - * - * @note For the convenience the code can use PARAM_XXXX(val) macros - * instead of MYSQLX_TYPE_XXXX, val. - * - * @return RESULT_OK - on success; RESULT_ERR - on error - */ + +/** + @brief MYSQLX API + @details Insert elements into an array in a document + + @param stmt pointer to statement initated for Collectin MODIFY operation + @param ... list of parameters that come as triplets + + Each triplet represents a value inside a document that can + be located by field_path. The value_type is the type identifier + for the data type of value (see mysqlx_data_type_t enum) + The list is terminated by PARAM_END. + + @note For the convenience the code can use PARAM_XXXX(val) macros + instead of MYSQLX_TYPE_XXXX, val. + + @return RESULT_OK - on success; RESULT_ERR - on error +*/ + int STDCALL mysqlx_set_modify_array_insert(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * @details Append to an array in a document - * - * @param crud pointer to statement initated for Collectin MODIFY operation - * @param ... list of parameters that come as triplets - * - * The list is terminated by PARAM_END. - * - * @note For the convenience the code can use PARAM_XXXX(val) macros - * instead of MYSQLX_TYPE_XXXX, val. - * - * @return RESULT_OK - on success; RESULT_ERR - on error - */ + +/** + @brief MYSQLX API + @details Append to an array in a document + + @param stmt pointer to statement initated for Collectin MODIFY operation + @param ... list of parameters that come as triplets + + The list is terminated by PARAM_END. + + @note For the convenience the code can use PARAM_XXXX(val) macros + instead of MYSQLX_TYPE_XXXX, val. + + @return RESULT_OK - on success; RESULT_ERR - on error +*/ + int STDCALL mysqlx_set_modify_array_append(mysqlx_stmt_t *stmt, ...); -/*! @brief MYSQLX API - * @details Delete element in an array in a document - * - * @param crud pointer to statement initated for Collectin MODIFY operation - * @param ... list of array elements paths that should be deleted from their arrays - * The list is terminated by PARAM_END. - * - * @return RESULT_OK - on success; RESULT_ERR - on error - */ + +/** + @brief MYSQLX API + @details Delete element in an array in a document + + @param stmt pointer to statement initated for Collectin MODIFY operation + @param ... list of array elements paths that should be deleted from their arrays + The list is terminated by PARAM_END. + + @return RESULT_OK - on success; RESULT_ERR - on error +*/ + int mysqlx_set_modify_array_delete(mysqlx_stmt_t *stmt, ...); + +/** + @brief MYSQLX API + @details a macro defining a function for setting WHERE for MODIFY + operation. See mysqlx_set_where() +*/ + #define mysqlx_set_modify_criteria mysqlx_set_where -/*! @brief MYSQLX API - * @details Remove a document from a collection - * - * @param collection collection handle - * - * @return - * STMT handle for the newly created REMOVE operation. - * NULL can be returned only in case when there are problems - * allocating memory, which normally should not happen. - * It is very unlikely for this function to end with the error - * because it does not do any parsing, parameters checking etc. - * - * @note To actually execute the REMOVE query the returned STMT has to be - * given to mysqlx_execute() - */ + +/** + @brief MYSQLX API + @details Remove a document from a collection + + @param collection collection handle + + @return STMT handle for the newly created REMOVE operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the REMOVE query the returned STMT has to be + given to mysqlx_execute() +*/ + mysqlx_stmt_t * STDCALL mysqlx_collection_remove_new(mysqlx_collection_t *collection); -/*! @brief MYSQLX API - * @details a macro defining a function for setting WHERE for REMIVE - * operation. See mysqlx_set_where() - * */ + +/** + @brief MYSQLX API + @details a macro defining a function for setting WHERE for REMOVE + operation. See mysqlx_set_where() + */ + #define mysqlx_set_remove_criteria mysqlx_set_where -/*! @brief MYSQLX API - * @details a macro defining a function for setting ORDER BY for REMOVE - * operation. See mysqlx_set_order_by() - * */ -#define mysqlx_set_remove_order_by mysqlx_set_order_by -/*! @brief MYSQLX API - * @details a macro defining a function for setting LIMIT for REMOVE - * operation. See mysqlx_set_limit_and_offset() - * */ -#define mysqlx_set_remove_limit_and_offset mysqlx_set_limit_and_offset +/** + @brief MYSQLX API + @details a macro defining a function for setting ORDER BY for REMOVE + operation. See mysqlx_set_order_by() + */ -// Rows and documents +#define mysqlx_set_remove_order_by mysqlx_set_order_by -/*! @brief MYSQLX API - * @details Fetch one row from the result and advance to the next row - * - * @param res pointer to the result structure - * - * @return pointer to mysqlx_row_t or NULL if no more rows left or if an error - * occurred. In case of an error it can be retrieved using - * mysqlx_error() or mysqlx_error_message(). - * - * @note The previously fetched row and its data will become invalid. -*/ -mysqlx_row_t * STDCALL mysqlx_row_fetch_one(mysqlx_result_t *res); -/*! @brief MYSQLX API - * @details Fetch one JSON document as a character string - * - * @param res pointer to the result structure - * @param[out] out_length the total number of bytes in the json string - * can be NULL, in that case nothing is returned through - * this parameter and user must ensure the data is correctly - * interpreted - * - * @return pointer to character JSON string or NULL if no more rows left. - * No need to free this data as it is tied and freed with the row - * handler. - * +/** + @brief MYSQLX API + @details a macro defining a function for setting LIMIT for REMOVE + operation. See mysqlx_set_limit_and_offset() */ -const char * STDCALL mysqlx_json_fetch_one(mysqlx_result_t *res, size_t *out_length); -/* - * @brief Fetch one document from the result and advance to - * the next document - * - * @param res pointer to the result structure - * - * @return pointer to mysqlx_doc_t or NULL if no more rows left - */ -//mysqlx_doc_t * STDCALL mysqlx_doc_fetch_one(mysqlx_result_t *res); +#define mysqlx_set_remove_limit_and_offset mysqlx_set_limit_and_offset -/* brief MYSQLX API - * - * @details Get a 64-bit unsigned int number from a document. It is important to - * pay attention to the signed/unsigned type. Attemptining to call this - * function for data of the wrong type will result in error or - * wrong data being retrieved - * - * @param doc pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * @param key character string key to find the right value - * @param[out] val the pointer to a variable of the 64-bit unsigned integer - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error -*/ -//int STDCALL mysqlx_doc_get_uint(mysqlx_doc_t *doc, const char *key, uint64_t *out); +// Rows and documents -/* brief MYSQLX API - * - * @details Get a 64-bit signed int number from a document. It is important to - * pay attention to the signed/unsigned type. Attemptining to call this - * function for data of the wrong type will result in error or - * wrong data being retrieved - * - * @param doc pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * @param key character string key to find the right value - * @param[out] val the pointer to a variable of the 64-bit signed integer - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error -*/ -//int STDCALL mysqlx_doc_get_sint(mysqlx_doc_t *doc, const char *key, int64_t *out); -/* brief MYSQLX API - * - * @details Get a float number from a document. It is important to - * pay attention to the data type. Attemptining to call this - * function for data of the wrong type will result in error or - * wrong data being retrieved - * - * @param doc pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * @param key character string key to find the right value - * @param[out] val the pointer to a variable of the float - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error -*/ -//int STDCALL mysqlx_doc_get_float(mysqlx_doc_t *doc, const char *key, float *out); +/** + @brief MYSQLX API + @details Fetch one row from the result and advance to the next row -/* brief MYSQLX API - * - * @details Get a double number from a document. It is important to - * pay attention to the data type. Attemptining to call this - * function for data of the wrong type will result in error or - * wrong data being retrieved - * - * @param doc pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * @param key character string key to find the right value - * @param[out] val the pointer to a variable of the double - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error -*/ -//int STDCALL mysqlx_doc_get_double(mysqlx_doc_t *doc, const char *key, double *out); + @param res pointer to the result structure -/* brief MYSQLX API - * - * @details Write resulting bytes into a pre-allocated buffer - * - * @param doc pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * @param key character string key to find the right value - * @param offset the number of bytes to skip before reading them from source document - * @param[out] buf the buffer allocated on the user side in which to write data - * @param[in,out] buf_len pointer to variable holding the length of the buffer [IN], - * the number of bytes actually written into the buffer [OUT] - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error -*/ -//int STDCALL mysqlx_doc_get_bytes(mysqlx_doc_t *doc, const char *key, uint64_t offset, -// void *out, size_t *buf_len); + @return pointer to mysqlx_row_t or NULL if no more rows left or if an error + occurred. In case of an error it can be retrieved using + mysqlx_error() or mysqlx_error_message(). -/* brief MYSQLX API - * - * @details Write resulting character string into a pre-allocated buffer - * - * @param row pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * @param key character string key to find the right value - * @param offset the number of bytes to skip before reading them from source document - * @param[out] buf the buffer allocated on the user side in which to write data - * @param[in,out] buf_len pointer to variable holding the length of the buffer [IN], - * the number of bytes actually written into the buffer [OUT] - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error + @note The previously fetched row and its data will become invalid. */ -//int STDCALL mysqlx_doc_get_str(mysqlx_doc_t *doc, const char *key, uint64_t offset, -// char *out, size_t *buf_len); -/* brief MYSQLX API - * - * @details Get character string keys from the current document. The keys are fetched - * one by one. Each call to this function gets the next key until all keys - * are returned. The keys sequence is not ordered. - * - * @param doc pointer to the mysqlx_doc_t structure returned by mysqlx_doc_fetch_one() - * to get data from - * - * @return NULL-terminated character string key or NULL if all keys had been - * already returned by the previous calls -*/ -//char* STDCALL mysqlx_doc_get_key(mysqlx_doc_t *doc); +mysqlx_row_t * STDCALL mysqlx_row_fetch_one(mysqlx_result_t *res); -/* brief MYSQLX API - * - * @details Checks if the specific key exists in the document - * - * @param doc pointer to the mysqlx_doc_t structure to check for keys - * @param key character string key to check - * - * @return true if the key exists, false otherwise -*/ -//bool STDCALL mysqlx_doc_key_exists(mysqlx_doc_t *doc, const char *key); -/* brief MYSQLX API - * - * @details Return the type identifier for the value with the specified - * key - * - * @param doc pointer to the mysqlx_doc_t structure to check for values - * @param key character string key to find the value - * - * @return 16-bit unsigned int number with the column type identifier - * (see mysqlx_data_type_t enum). If the value with the specified key - * does not exist or the error happens the function returns - * MYSQLX_TYPE_UNDEFINED +/** + @brief MYSQLX API + @details Fetch one JSON document as a character string + + @param res pointer to the result structure + @param[out] out_length the total number of bytes in the json string + can be NULL, in that case nothing is returned through + this parameter and user must ensure the data is correctly + interpreted + + @return pointer to character JSON string or NULL if no more JSON's left. + No need to free this data as it is tied and freed with the result + handle. */ -//uint16_t STDCALL mysqlx_doc_get_type(mysqlx_doc_t *doc, const char *key); +const char * STDCALL mysqlx_json_fetch_one(mysqlx_result_t *res, size_t *out_length); + + +/** + @brief MYSQLX_API + + @details This function is used to process replies containing multiple result sets. + Each time it is called the function reads the next result set. + + @param result result handle containing the statement execute results + + @return RESULT_OK - on success; RESULT_NULL when there is no more results; + RESULT_ERR - on error +*/ -/*! @brief MYSQLX_API - * - * @details This function is used to process replies containing multiple result sets. - * Each time it is called the function reads the next result set. - * - * @param result result handle containing the statement execute results - * - * @return RESULT_OK - on success; RESULT_NULL when there is no more results; - * RESULT_ERR - on error - * - */ int STDCALL mysqlx_next_result(mysqlx_result_t *res); -/*! @brief MYSQLX API - * - * @details Get number of rows affected by the last operation - * - * @param res pointer to the result structure returned by mysqlx_execute() - * - * @return 64-bit unsigned int number containing the number of affected rows + +/** + @brief MYSQLX API + + @details Get number of rows affected by the last operation + + @param res pointer to the result structure returned by mysqlx_execute() + + @return 64-bit unsigned int number containing the number of affected rows */ + uint64_t STDCALL mysqlx_get_affected_count(mysqlx_result_t *res); // Metadata -/*! @brief MYSQLX API - * - * @details Get column type identifier - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return 16-bit unsigned int number with the column type identifier - * (see mysqlx_data_type_t enum) +/** + @brief MYSQLX API + + @details Get column type identifier + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return 16-bit unsigned int number with the column type identifier + (see mysqlx_data_type_t enum) */ + uint16_t STDCALL mysqlx_column_get_type(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column collation number - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return 16-bit unsigned int number with the column collation number + +/** + @brief MYSQLX API + + @details Get column collation number + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return 16-bit unsigned int number with the column collation number */ + uint16_t STDCALL mysqlx_column_get_collation(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column length - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return 32-bit unsigned int number indicating the maximum data length + +/** + @brief MYSQLX API + + @details Get column length + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return 32-bit unsigned int number indicating the maximum data length */ + uint32_t STDCALL mysqlx_column_get_length(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column precision - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return 16-bit unsigned int number of digits after the decimal point + +/** + @brief MYSQLX API + + @details Get column precision + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return 16-bit unsigned int number of digits after the decimal point */ + uint16_t STDCALL mysqlx_column_get_precision(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column flags - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return 32-bit unsigned int number containing column flags + +/** + @brief MYSQLX API + + @details Get column flags + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return 32-bit unsigned int number containing column flags */ + uint32_t STDCALL mysqlx_column_get_flags(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get the number of columns in the result - * - * @param res pointer to the result structure returned by mysqlx_execute() - * - * @return the number of columns + +/** + @brief MYSQLX API + + @details Get the number of columns in the result + + @param res pointer to the result structure returned by mysqlx_execute() + + @return the number of columns */ + uint32_t STDCALL mysqlx_column_get_count(mysqlx_result_t *res); -/*! @brief MYSQLX API - * - * @details Get column name - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return character string containing the column name + +/** + @brief MYSQLX API + + @details Get column name + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return character string containing the column name */ + const char * STDCALL mysqlx_column_get_name(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column original name - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return character string containing the column original name + +/** + @brief MYSQLX API + + @details Get column original name + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return character string containing the column original name */ + const char * STDCALL mysqlx_column_get_original_name(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column table - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return character string containing the column table name + +/** + @brief MYSQLX API + + @details Get column table + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return character string containing the column table name */ + const char * STDCALL mysqlx_column_get_table(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column original table - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return character string containing the column original table + +/** + @brief MYSQLX API + + @details Get column original table + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return character string containing the column original table */ + const char * STDCALL mysqlx_column_get_original_table(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column schema - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return character string containing the column schema + +/** + @brief MYSQLX API + + @details Get column schema + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return character string containing the column schema */ + const char * STDCALL mysqlx_column_get_schema(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Get column name - * - * @param res pointer to the result structure returned by mysqlx_execute() - * @param pos zero-based column number - * - * @return character string containing the column name + +/** + @brief MYSQLX API + + @details Get column name + + @param res pointer to the result structure returned by mysqlx_execute() + @param pos zero-based column number + + @return character string containing the column name */ + const char * STDCALL mysqlx_column_get_catalog(mysqlx_result_t *res, uint32_t pos); -/*! @brief MYSQLX API - * - * @details Write resulting bytes into a pre-allocated buffer - * - * @param row pointer to the row structure returned by mysqlx_row_fetch_one() - * to get bytes from - * @param col zero-based column number - * @param offset the number of bytes to skip before reading them from source row - * @param[out] buf the buffer allocated on the user side in which to write data - * @param[in,out] buf_len pointer to variable holding the length of the buffer [IN], - * the number of bytes actually written into the buffer [OUT] - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error + +/** + @brief MYSQLX API + + @details Write resulting bytes into a pre-allocated buffer + + @param row pointer to the row structure returned by mysqlx_row_fetch_one() + to get bytes from + @param col zero-based column number + @param offset the number of bytes to skip before reading them from source row + @param[out] buf the buffer allocated on the user side in which to write data + @param[in,out] buf_len pointer to variable holding the length of the buffer [IN], + the number of bytes actually written into the buffer [OUT] + + @return RESULT_OK - on success; RESULT_NULL when the value is NULL; + RESULT_ERR - on error */ + int STDCALL mysqlx_get_bytes(mysqlx_row_t* row, uint32_t col, uint64_t offset, void *buf, size_t *buf_len); -/*! @brief MYSQLX API - * - * @details Get a 64-bit unsigned int number. It is important to pay attention - * to the signed/unsigned type of the column. Attemptining to call this - * function for a column with the signed integer type will result - * in wrong data being retrieved - * - * @param row pointer to the row structure returned by mysqlx_row_fetch_one() - * to get bytes from - * @param col zero-based column number - * @param[out] val the pointer to a variable of the 64-bit unsigned integer - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error + +/** + @brief MYSQLX API + + @details Get a 64-bit unsigned int number. It is important to pay attention + to the signed/unsigned type of the column. Attemptining to call this + function for a column with the signed integer type will result + in wrong data being retrieved + + @param row pointer to the row structure returned by mysqlx_row_fetch_one() + to get bytes from + @param col zero-based column number + @param[out] val the pointer to a variable of the 64-bit unsigned integer + type in which to write the data + + @return RESULT_OK - on success; RESULT_NULL when the value is NULL; + RESULT_ERR - on error */ + int STDCALL mysqlx_get_uint(mysqlx_row_t* row, uint32_t col, uint64_t* val); -/*! @brief MYSQLX API - * - * @details Get a 64-bit signed int number. It is important to pay attention - * to the signed/unsigned type of the column. Attemptining to call this - * function for a column with the unsigned integer type will result - * in wrong data being retrieved - * - * @param row pointer to the row structure returned by mysqlx_row_fetch_one() - * to get bytes from - * @param col zero-based column number - * @param[out] val the pointer to a variable of the 64-bit signed integer - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error + +/** + @brief MYSQLX API + + @details Get a 64-bit signed int number. It is important to pay attention + to the signed/unsigned type of the column. Attemptining to call this + function for a column with the unsigned integer type will result + in wrong data being retrieved + + @param row pointer to the row structure returned by mysqlx_row_fetch_one() + to get bytes from + @param col zero-based column number + @param[out] val the pointer to a variable of the 64-bit signed integer + type in which to write the data + + @return RESULT_OK - on success; RESULT_NULL when the value is NULL; + RESULT_ERR - on error */ + int STDCALL mysqlx_get_sint(mysqlx_row_t* row, uint32_t col, int64_t* val); -/*! @brief MYSQLX API - * - * @details Get a float number. It is important to pay attention - * to the type of the column. Attemptining to call this - * function for a column with the type different from float will result - * in wrong data being retrieved - * - * @param row pointer to the row structure returned by mysqlx_row_fetch_one() - * to get bytes from - * @param col zero-based column number - * @param[out] val the pointer to a variable of the float - * type in which to write the data - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error + +/** + @brief MYSQLX API + + @details Get a float number. It is important to pay attention + to the type of the column. Attemptining to call this + function for a column with the type different from float will result + in wrong data being retrieved + + @param row pointer to the row structure returned by mysqlx_row_fetch_one() + to get bytes from + @param col zero-based column number + @param[out] val the pointer to a variable of the float + type in which to write the data + + @return RESULT_OK - on success; RESULT_NULL when the value is NULL; + RESULT_ERR - on error */ + int STDCALL mysqlx_get_float(mysqlx_row_t* row, uint32_t col, float* val); -/*! @brief MYSQLX API - * - * @details Get a double number. It is important to pay attention - * to the type of the column. Attemptining to call this - * function for a column with the type different from double will result - * in wrong data being retrieved - * - * @param row pointer to the row structure returned by mysqlx_row_fetch_one() - * to get bytes from - * @param col zero-based column number - * @param[out] val the pointer to a variable of the double - * type in which to write the data. - * - * @return RESULT_OK - on success; RESULT_NULL when the value is NULL; - * RESULT_ERR - on error + +/** + @brief MYSQLX API + + @details Get a double number. It is important to pay attention + to the type of the column. Attemptining to call this + function for a column with the type different from double will result + in wrong data being retrieved + + @param row pointer to the row structure returned by mysqlx_row_fetch_one() + to get bytes from + @param col zero-based column number + @param[out] val the pointer to a variable of the double + type in which to write the data. + + @return RESULT_OK - on success; RESULT_NULL when the value is NULL; + RESULT_ERR - on error */ + int STDCALL mysqlx_get_double(mysqlx_row_t* row, uint32_t col, double *val); -/*! @brief MYSQLX API - * - * @details Free the result explicitly, otherwise it will be done automatically - * when statement handler is destroyed. - * - * @param res the result handler, which should be freed - * - * @note make sure this function is called if the result handler is going to be - * re-used + +/** + @brief MYSQLX API + + @details Free the result explicitly, otherwise it will be done automatically + when statement handler is destroyed. + + @param res the result handler, which should be freed + + @note make sure this function is called if the result handler is going to be + re-used */ + void STDCALL mysqlx_result_free(mysqlx_result_t *res); -/*! @brief MYSQLX API - * - * @details Get the last error from the object - * - * @param obj the object handle to extract the error information from. - * Supported types are mysqlx_session_t, mysqlx_session_options_t, - * mysqlx_schema_t, mysqlx_collection_t, mysqlx_table_t, - * mysqlx_stmt_t, mysqlx_result_t, mysqlx_row_t, mysqlx_error_t - * - * @return the error handle or NULL if there is no errors. + +/** + @brief MYSQLX API + + @details Get the last error from the object + + @param obj the object handle to extract the error information from. + Supported types are mysqlx_session_t, mysqlx_session_options_t, + mysqlx_schema_t, mysqlx_collection_t, mysqlx_table_t, + mysqlx_stmt_t, mysqlx_result_t, mysqlx_row_t, mysqlx_error_t + + @return the error handle or NULL if there is no errors. */ + mysqlx_error_t * STDCALL mysqlx_error(void *obj); -/*! @brief MYSQLX API - * - * @details Get the error message from the object - * - * @param obj the object handle to extract the error information from. - * Supported types are mysqlx_session_t, mysqlx_session_options_t, - * mysqlx_schema_t, mysqlx_collection_t, mysqlx_table_t, - * mysqlx_stmt_t, mysqlx_result_t, mysqlx_row_t, mysqlx_error_t - * - * @return the character string or NULL if there is no errors. + +/** + @brief MYSQLX API + + @details Get the error message from the object + + @param obj the object handle to extract the error information from. + Supported types are mysqlx_session_t, mysqlx_session_options_t, + mysqlx_schema_t, mysqlx_collection_t, mysqlx_table_t, + mysqlx_stmt_t, mysqlx_result_t, mysqlx_row_t, mysqlx_error_t + + @return the character string or NULL if there is no errors. */ + const char * STDCALL mysqlx_error_message(void *obj); -/*! @brief MYSQLX API - * - * @details Get the error message from the object - * - * @param obj the object handle to extract the error information from. - * Supported types are mysqlx_session_t, mysqlx_session_options_t, - * mysqlx_schema_t, mysqlx_collection_t, mysqlx_table_t, - * mysqlx_stmt_t, mysqlx_result_t, mysqlx_row_t, mysqlx_error_t - * - * @return the error number or 0 if no error + +/** + @brief MYSQLX API + + @details Get the error message from the object + + @param obj the object handle to extract the error information from. + Supported types are mysqlx_session_t, mysqlx_session_options_t, + mysqlx_schema_t, mysqlx_collection_t, mysqlx_table_t, + mysqlx_stmt_t, mysqlx_result_t, mysqlx_row_t, mysqlx_error_t + + @return the error number or 0 if no error */ + unsigned int STDCALL mysqlx_error_num(void *obj); -/*! @brief MYSQLX API - * @details Free the statement handler explicitly, otherwise it will be done automatically - * when statement the session is closed. - * - * @param crud the statement handler, which should be freed - * - * @note make sure this function is called if the crud handler is going to be - * re-used - * @todo - * implement book-keeping to be able to free the lower-level objects - * by freeing the higher-level ones +/** + @brief MYSQLX API + + @details Free the statement handle explicitly, otherwise it will be done + automatically when statement the session is closed. + + @param stmt the statement handler, which should be freed + + @note make sure this function is called if the statement handle + variable is going to be re-used */ + void STDCALL mysqlx_free(mysqlx_stmt_t *stmt); -/*! @brief MYSQLX API - * - * @details Execute a plain SQL query. - * - * @param sess session handle - * @param query SQL query - * @param length length of the query. For NULL-terminated query strings - * MYSQLX_NULL_TERMINATED can be specified instead of the - * actual length - * - * @return - * Result handle containing the results of the query. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - */ + +/** + @brief MYSQLX API + + @details Execute a plain SQL query. + + @param sess session handle + @param query SQL query + @param length length of the query. For NULL-terminated query strings + MYSQLX_NULL_TERMINATED can be specified instead of the + actual length + + @return Result handle containing the results of the query. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query +*/ + mysqlx_result_t * STDCALL mysqlx_sql(mysqlx_session_t *sess, const char *query, size_t query_len); -/*! @brief MYSQLX API - * - * @details Execute a plain SQL query with parameters - * - * @param sess session handle - * @param query SQL query - * @param length length of the query. For NULL-terminated query strings - * MYSQLX_NULL_TERMINATED can be specified instead of the - * actual length - * @param ... - variable parameters list consisting of (type, value) pairs - * terminated by PARAM_END: - * - * type_id1, value1, type_id2, value2, ..., type_id_n, value_n, PARAM_END - * (PARAM_END marks the end of parameters list). - * - * type_id is the numeric identifier, which helps to determine the type - * of the value provided as the next parameter. The user code must - * ensure that type_id corresponds to the actual value type. Otherwise, - * the value along with and all sequential types and values are most - * likely to be corrupted. - * Allowed types are listed in mysqlx_data_type_t enum. - * The MYSQLX API defines the convenience macros that help to specify - * the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, - * PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING. - * - * @return Result handle containing the results of the query. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - */ + +/** + @brief MYSQLX API + + @details Execute a plain SQL query with parameters + + @param sess session handle + @param query SQL query + @param length length of the query. For NULL-terminated query strings + MYSQLX_NULL_TERMINATED can be specified instead of the + actual length + @param ... - variable parameters list consisting of (type, value) pairs + terminated by PARAM_END: + + type_id1, value1, type_id2, value2, ..., type_id_n, value_n, PARAM_END + (PARAM_END marks the end of parameters list). + + type_id is the numeric identifier, which helps to determine the type + of the value provided as the next parameter. The user code must + ensure that type_id corresponds to the actual value type. Otherwise, + the value along with and all sequential types and values are most + likely to be corrupted. + Allowed types are listed in mysqlx_data_type_t enum. + The MYSQLX API defines the convenience macros that help to specify + the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, + PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING. + + @return Result handle containing the results of the query. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query +*/ mysqlx_result_t * STDCALL mysqlx_sql_param(mysqlx_session_t *sess, const char *query, size_t query_len, ...); -/*! @brief MYSQLX API - * - * @details Execute a table SELECT statement operation with a WHERE clause. - * All columns will be selected. - * - * @param table table handle - * @param criteria a WHERE clause for SELECT - * - * @return Result handle containing the results of the query. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Execute a table SELECT statement operation with a WHERE clause. + All columns will be selected. + + @param table table handle + @param criteria a WHERE clause for SELECT + + @return Result handle containing the results of the query. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_table_select(mysqlx_table_t *table, const char *criteria); -/*! @brief MYSQLX API - * - * @details Start and execute a table SELECT statement operation with a WHERE, - * ORDER BY and LIMIT clauses - * - * @param table table handle - * @param criteria a WHERE clause for SELECT - * @param row_count a number of rows for LIMIT - * @param offset an offset for LIMIT - * @param ... - variable parameters list consisting of (expression, direction) pairs - * terminated by PARAM_END: - * expr_1, direction_1, ..., expr_n, direction_n, PARAM_END - * (PARAM_END marks the end of parameters list) - * Each expression computes value used to sort - * the rows/documents in ascending or descending order, - * as determined by direction constant - * (list the direction enum names). - * Special attention must be paid to the expression - * strings because the empty string "" or NULL will be treated - * as the end of sequence - * - * @return Result handle containing the results of the query. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Start and execute a table SELECT statement operation with a WHERE, + ORDER BY and LIMIT clauses + + @param table table handle + @param criteria a WHERE clause for SELECT + @param row_count a number of rows for LIMIT + @param offset an offset for LIMIT + @param ... - variable parameters list consisting of (expression, direction) pairs + terminated by PARAM_END: + expr_1, direction_1, ..., expr_n, direction_n, PARAM_END + (PARAM_END marks the end of parameters list) + Each expression computes value used to sort + the rows/documents in ascending or descending order, + as determined by direction constant + (list the direction enum names). + Special attention must be paid to the expression + strings because the empty string "" or NULL will be treated + as the end of sequence + + @return Result handle containing the results of the query. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_table_select_limit(mysqlx_table_t *table, const char *criteria, uint64_t row_count, uint64_t offset, ...); -/*! @brief MYSQLX API - * - * @details Start and execute a table INSERT operation one row at a time - * - * @param table table handle - * @param ... list of column-value specifications consisting of - * triplets. The list - * should be terminated using PARAM_END. - * Allowed value types are listed in mysqlx_data_type_t enum. - * The MYSQLX API defines the convenience macros that help to specify - * the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, - * PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING: - * ..., "col_uint", PARAM_UINT(uint_val), - * "col_blob", PARAM_BYTES(byte_buf, buf_len), - * PARAM_END - * - * @return Result handle containing the result. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Start and execute a table INSERT operation one row at a time + + @param table table handle + @param ... list of column-value specifications consisting of + triplets. The list + should be terminated using PARAM_END. + Allowed value types are listed in mysqlx_data_type_t enum. + The MYSQLX API defines the convenience macros that help to specify + the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, + PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING: + ..., "col_uint", PARAM_UINT(uint_val), + "col_blob", PARAM_BYTES(byte_buf, buf_len), + PARAM_END + + @return Result handle containing the result. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_table_insert(mysqlx_table_t *table, ...); -/*! @brief MYSQLX API - * - * @details Start and execute a table UPDATE operation - * - * @param table table handle - * @param criterie the WHERE clause for UPDATE - * @param ... list of column-value specifications consisting of - * triplets. The list - * should be terminated using PARAM_END. - * Allowed value types are listed in mysqlx_data_type_t enum. - * The MYSQLX API defines the convenience macros that help to specify - * the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, - * PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING, PARAM_EXPR: - * ..., "col_uint", PARAM_EXPR("col_uint * 100"), - * "col_blob", PARAM_BYTES(byte_buf, buf_len), - * PARAM_END - * - * @return Result handle containing the result. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Start and execute a table UPDATE operation + + @param table table handle + @param criterie the WHERE clause for UPDATE + @param ... list of column-value specifications consisting of + triplets. The list + should be terminated using PARAM_END. + Allowed value types are listed in mysqlx_data_type_t enum. + The MYSQLX API defines the convenience macros that help to specify + the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, + PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING, PARAM_EXPR: + ..., "col_uint", PARAM_EXPR("col_uint * 100"), + "col_blob", PARAM_BYTES(byte_buf, buf_len), + PARAM_END + + @return Result handle containing the result. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_table_update(mysqlx_table_t *table, const char *criteria, ...); -/*! @brief MYSQLX API - * - * @details Execute a table DELETE statement operation with a WHERE clause - * - * @param table table handle - * @param criteria a WHERE clause for DELETE - * - * @return Result handle containing the result. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Execute a table DELETE statement operation with a WHERE clause + + @param table table handle + @param criteria a WHERE clause for DELETE + + @return Result handle containing the result. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_table_delete(mysqlx_table_t *table, const char *criteria); -/*! @brief MYSQLX API - * - * @details Execute a collection FIND statement operation with a specific find - * criteria. - * - * @param collection collection handle - * @param criteria criteria for finding documents - * - * @return Result handle containing the results of FIND. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Execute a collection FIND statement operation with a specific find + criteria. + + @param collection collection handle + @param criteria criteria for finding documents + + @return Result handle containing the results of FIND. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_collection_find(mysqlx_collection_t *collection, const char *criteria); -/*! @brief MYSQLX API - * - * @details Execute adding a set of new documents into a collection. - * The document is defined by a JSON string like - * "{ key_1: value_1, ..., key_N: value_N }" - * - * @param collection collection handle - * @param ... list of parameters containing the character JSON strings - * describing documents to be added. Each parameter - * is a separate document. The list has to be terminated by - * PARAM_END macro - * - * @return Result handle containing the result of ADD. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query + +/** + @brief MYSQLX API + + @details Execute adding a set of new documents into a collection. + The document is defined by a JSON string like + "{ key_1: value_1, ..., key_N: value_N }" + + @param collection collection handle + @param ... list of parameters containing the character JSON strings + describing documents to be added. Each parameter + is a separate document. The list has to be terminated by + PARAM_END macro + + @return Result handle containing the result of ADD. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query */ + mysqlx_result_t * STDCALL mysqlx_collection_add(mysqlx_collection_t *collection, ...); -/*! @brief MYSQLX API - * @details Set JSON values in a document using collection MODIFY operation. - * - * @param collection collection handle - * @param criteria criteria for modifying documents - * @param ... list of parameters that come as triplets - * - * Each triplet represents a value inside a document that can - * be located by field_path. The value_type is the type identifier - * for the data type of value (see mysqlx_data_type_t enum) - * The list is terminated by PARAM_END. - * For MYSQLX_TYPE_BYTES there will be one extra parameter specifying - * the length of the binary data: - * - * The MYSQLX API defines the convenience macros that help to specify - * the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, - * PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING, PARAM_EXPR: - * ..., "a_key", PARAM_STRING("New Text Value"), - * "b_key", PARAM_EXPR("b_key-1000"), - * PARAM_END - * - * @return Result handle containing the result of the operation - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - */ + +/** + @brief MYSQLX API + @details Set JSON values in a document using collection MODIFY operation. + + @param collection collection handle + @param criteria criteria for modifying documents + @param ... list of parameters that come as triplets + + Each triplet represents a value inside a document that can + be located by field_path. The value_type is the type identifier + for the data type of value (see mysqlx_data_type_t enum) + The list is terminated by PARAM_END. + For MYSQLX_TYPE_BYTES there will be one extra parameter specifying + the length of the binary data: + + The MYSQLX API defines the convenience macros that help to specify + the types and values: See PARAM_SINT, PARAM_UINT, PARAM_FLOAT, + PARAM_DOUBLE, PARAM_BYTES, PARAM_STRING, PARAM_EXPR: + ..., "a_key", PARAM_STRING("New Text Value"), + "b_key", PARAM_EXPR("b_key-1000"), + PARAM_END + + @return Result handle containing the result of the operation + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query +*/ + mysqlx_result_t * STDCALL mysqlx_collection_modify_set(mysqlx_collection_t *collection, const char *criteria, ...); -/*! @brief MYSQLX API - * @details Unset a field in a document using MODIFY operation - * - * @param collection collection handle - * @param criteria criteria for modifying documents - * @param ... list of field paths that should be unset. - * The list end is marked using PARAM_END - * - * @return Result handle containing the result of the operation - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - */ + +/** + @brief MYSQLX API + @details Unset a field in a document using MODIFY operation + + @param collection collection handle + @param criteria criteria for modifying documents + @param ... list of field paths that should be unset. + The list end is marked using PARAM_END + + @return Result handle containing the result of the operation + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query +*/ + mysqlx_result_t * STDCALL mysqlx_collection_modify_unset(mysqlx_collection_t *collection, const char *criteria, ...); -/*! @brief MYSQLX API - * @details Remove a document from a collection that satisfies a given - * criteria - * - * @param collection collection handle - * @param criteria criteria for removing documents - * - * @return Result handle containing the result of the operation - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - */ + +/** + @brief MYSQLX API + @details Remove a document from a collection that satisfies a given + criteria + + @param collection collection handle + @param criteria criteria for removing documents + + @return Result handle containing the result of the operation + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query +*/ + mysqlx_result_t * STDCALL mysqlx_collection_remove(mysqlx_collection_t *collection, const char*criteria); -/*! @brief MYSQLX API - * - * @details Get a list of schemas - * - * @param sess pointer to the current session handle - * @param schema_pattern schema name pattern to search. - * Giving NULL for this parameter is equivalent to "%" and will - * result in searching for all schemas - * - * @return Result handle containing the result. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - * @note the list of schema names is returned as a set of rows. Therefore, - * the functins such as mysqlx_store_result() and mysqlx_row_fetch_one() - * could be used. + +/** + @brief MYSQLX API + + @details Get a list of schemas + + @param sess pointer to the current session handle + @param schema_pattern schema name pattern to search. + Giving NULL for this parameter is equivalent to "%" and will + result in searching for all schemas + + @return Result handle containing the result. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query + @note the list of schema names is returned as a set of rows. Therefore, + the functins such as mysqlx_store_result() and mysqlx_row_fetch_one() + could be used. */ + mysqlx_result_t * STDCALL mysqlx_get_schemas(mysqlx_session_t *sess, const char *schema_pattern); -/*! @brief MYSQLX API - * - * @details Get a list of tables and views - * - * @param schema schema handle - * @param table_pattern table name pattern to search. - * Giving NULL for this parameter is equivalent to "%" and will - * result in searching for all tables in the given schema - * @param get_views flag specifying whether view names should be included - * into the result. 0 - do not show views (only table names are in - * the result), 1 - show views (table and view names are in the result) - * - * @return Result handle containing the result. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - * - * @note the list of table/view names is returned as a set of rows. Therefore, - * the functins such as mysqlx_store_result() and mysqlx_row_fetch_one() - * could be used. - * - * @note this function does not return table names that represent collections. - * use mysqlx_get_collections() function for getting collections. + +/** + @brief MYSQLX API + + @details Get a list of tables and views + + @param schema schema handle + @param table_pattern table name pattern to search. + Giving NULL for this parameter is equivalent to "%" and will + result in searching for all tables in the given schema + @param get_views flag specifying whether view names should be included + into the result. 0 - do not show views (only table names are in + the result), 1 - show views (table and view names are in the result) + + @return Result handle containing the result. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query + + @note the list of table/view names is returned as a set of rows. Therefore, + the functins such as mysqlx_store_result() and mysqlx_row_fetch_one() + could be used. + + @note this function does not return table names that represent collections. + use mysqlx_get_collections() function for getting collections. */ + mysqlx_result_t * STDCALL mysqlx_get_tables(mysqlx_schema_t *schema, const char *table_pattern, int get_views); -/*! @brief MYSQLX API - * - * @details Get a list of collections - * - * @param schema handle - * @param col_pattern collection name pattern to search. - * Giving NULL for this parameter is equivalent to "%" and will - * result in searching for all collections in the given schema - * - * @return Result handle containing the result. - * NULL is returned only in case of an error. The error details - * can be obtained using mysqlx_error() function - * - * @note mysqlx_execute() is not needed to execute the query - * @note the list of table/view names is returned as a set of rows. Therefore, - * the functins such as mysqlx_store_result() and mysqlx_row_fetch_one() - * could be used. + +/** + @brief MYSQLX API + + @details Get a list of collections + + @param schema handle + @param col_pattern collection name pattern to search. + Giving NULL for this parameter is equivalent to "%" and will + result in searching for all collections in the given schema + + @return Result handle containing the result. + NULL is returned only in case of an error. The error details + can be obtained using mysqlx_error() function + + @note mysqlx_execute() is not needed to execute the query + @note the list of table/view names is returned as a set of rows. Therefore, + the functins such as mysqlx_store_result() and mysqlx_row_fetch_one() + could be used. */ + mysqlx_result_t * STDCALL mysqlx_get_collections(mysqlx_schema_t *schema, const char *col_pattern); -/*! @brief MYSQLX API - * - * @details Get the number of warnings generated by an operation - * - * @param res Pointer to mysqlx_result_t handle to get warnings from - * - * @return the number of warnings returned in the result structure +/** + @brief MYSQLX API + + @details Get the number of warnings generated by an operation + + @param res Pointer to mysqlx_result_t handle to get warnings from + + @return the number of warnings returned in the result structure */ + unsigned int STDCALL mysqlx_result_warning_count(mysqlx_result_t *res); -/*! @brief MYSQLX API - * - * @details Get the next warning from the result. The warning pointer returned - * by a previous call is invalidated. - * - * @param res Pointer to mysqlx_result_t handle to get warnings from - * - * @return the mysqlx_error_t structure containing info about a warning or - * NULL if there is no more warnings left to return. + +/** + @brief MYSQLX API + + @details Get the next warning from the result. The warning pointer returned + by a previous call is invalidated. + + @param res Pointer to mysqlx_result_t handle to get warnings from + + @return the mysqlx_error_t structure containing info about a warning or + NULL if there is no more warnings left to return. */ + mysqlx_error_t * STDCALL mysqlx_result_next_warning(mysqlx_result_t *res); -/*! @brief MYSQLX API - * - * @details Get the value generated by the last insert in the table - * with auto_increment primary key - * - * @param res Pointer to mysqlx_result_t handle to get the auto increment - * - * @return the auto incremented value - * - * @note with multi-row inserts the function returns the value generated - * for the first row +/** + @brief MYSQLX API + + @details Get the value generated by the last insert in the table + with auto_increment primary key + + @param res Pointer to mysqlx_result_t handle to get the auto increment + + @return the auto incremented value + + @note with multi-row inserts the function returns the value generated + for the first row */ + uint64_t STDCALL mysqlx_get_auto_increment_value(mysqlx_result_t *res); -/*! @brief MYSQLX API - * - * @details Begin a transaction for the session - * - * @param sess Pointer to mysqlx_session_t structure - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note statement operation will belong to the transaction when - * it is actually executed after the transaction began, but before - * it is committed or rolled back even if this statement operation - * was created before mysqlx_transaction_begin() call + +/** + @brief MYSQLX API + + @details Begin a transaction for the session + + @param sess Pointer to mysqlx_session_t structure + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note statement operation will belong to the transaction when + it is actually executed after the transaction began, but before + it is committed or rolled back even if this statement operation + was created before mysqlx_transaction_begin() call */ + int STDCALL mysqlx_transaction_begin(mysqlx_session_t *sess); -/*! @brief MYSQLX API - * - * @details Commit a transaction for the session - * - * @param sess Pointer to mysqlx_session_t structure - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note statement operation will belong to the transaction when - * it is actually executed after the transaction began, but before - * it is committed or rolled back even if this statement operation - * was created before mysqlx_transaction_begin() call + +/** + @brief MYSQLX API + + @details Commit a transaction for the session + + @param sess Pointer to mysqlx_session_t structure + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note statement operation will belong to the transaction when + it is actually executed after the transaction began, but before + it is committed or rolled back even if this statement operation + was created before mysqlx_transaction_begin() call */ + int STDCALL mysqlx_transaction_commit(mysqlx_session_t *sess); -/*! @brief MYSQLX API - * - * @details Rollback a transaction for the session - * - * @param sess Pointer to mysqlx_session_t structure - * - * @return RESULT_OK - on success; RESULT_ERR - on error - * - * @note statement operation will belong to the transaction when - * it is actually executed after the transaction began, but before - * it is committed or rolled back even if this statement operation - * was created before mysqlx_transaction_begin() call + +/** + @brief MYSQLX API + + @details Rollback a transaction for the session + + @param sess Pointer to mysqlx_session_t structure + + @return RESULT_OK - on success; RESULT_ERR - on error + + @note statement operation will belong to the transaction when + it is actually executed after the transaction began, but before + it is committed or rolled back even if this statement operation + was created before mysqlx_transaction_begin() call */ + int STDCALL mysqlx_transaction_rollback(mysqlx_session_t *sess); -/*! @brief MYSQLX API - * - * @details Get UUIDs for the documents added to the collection - * by the last ADD operation. The function can be used for - * the multi-document inserts. In this case each new generated - * UUID is returned by a new call to mysqlx_fetch_doc_id(). - * - * @param result Pointer to mysqlx_result_t structure returned after - * executing the ADD operation - * - * @return Character string containing a generated UUID corresponding - * to a document previously added to a collection; NULL - if - * all UUIDs for all added documents have been returned - * - * @note The UUID result string is valid as long as the result handle is valid. - * Starting a new operation will invalidate it. + +/** + @brief MYSQLX API + + @details Get UUIDs for the documents added to the collection + by the last ADD operation. The function can be used for + the multi-document inserts. In this case each new generated + UUID is returned by a new call to mysqlx_fetch_doc_id(). + + @param result Pointer to mysqlx_result_t structure returned after + executing the ADD operation + + @return Character string containing a generated UUID corresponding + to a document previously added to a collection; NULL - if + all UUIDs for all added documents have been returned + + @note The UUID result string is valid as long as the result handle is valid. + Starting a new operation will invalidate it. */ + const char * STDCALL mysqlx_fetch_doc_id(mysqlx_result_t *result); -int STDCALL -mysqlx_session_valid(mysqlx_session_t *sess); /* brief MYSQLX API - * - * @details Allocate a mysqlx_session_options_t structure - * - * @return pointer to a newly allocated mysqlx_session_options_t structure - * - * @note The mysqlx_session_options_t structure allocated by - * mysqlx_session_options_new() must be eventually freed by - * mysqlx_free_options() to prevent memory leaks - */ + + @details Allocate a mysqlx_session_options_t structure + + @return pointer to a newly allocated mysqlx_session_options_t structure + + @note The mysqlx_session_options_t structure allocated by + mysqlx_session_options_new() must be eventually freed by + mysqlx_free_options() to prevent memory leaks +*/ + mysqlx_session_options_t * STDCALL mysqlx_session_options_new(); + /* brief MYSQLX API - * - * @details Free a mysqlx_session_options_t structure - * - * @param opt pointer to a mysqlx_session_options_t structure - * that has to be freed - */ + + @details Free a mysqlx_session_options_t structure + + @param opt pointer to a mysqlx_session_options_t structure + that has to be freed +*/ + void STDCALL mysqlx_free_options(mysqlx_session_options_t *opt); + /* brief MYSQLX API - * - * @details Set a value into a mysqlx_session_options_t structure - * - * @param opt mysqlx_session_options_t structure - * @param type option type to set (see mysqlx_opt_type_t enum) - * @param ... option value/values to set (the function can set more - * than one value) - * - * @return RESULT_OK if option was sucessfully set; RESULT_ERROR - * is set otherwise (use mysqlx_error() to get the error - * information) - */ + + @details Set a value into a mysqlx_session_options_t structure + + @param opt mysqlx_session_options_t structure + @param type option type to set (see mysqlx_opt_type_t enum) + @param ... option value/values to set (the function can set more + than one value) + + @return RESULT_OK if option was sucessfully set; RESULT_ERROR + is set otherwise (use mysqlx_error() to get the error + information) +*/ + int STDCALL mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, ...); + /* brief MYSQLX API - * - * @details Get a value from a mysqlx_session_options_t structure - * - * @param opt mysqlx_session_options_t structure - * @param type option type to get (see mysqlx_opt_type_t enum) - * @param ...[out] pointer to a buffer where to return the requested - * value - * - * @return RESULT_OK if option was sucessfully read; RESULT_ERROR - * is set otherwise (use mysqlx_error() to get the error - * information) - */ + + @details Get a value from a mysqlx_session_options_t structure + + @param opt mysqlx_session_options_t structure + @param type option type to get (see mysqlx_opt_type_t enum) + @param ...[out] pointer to a buffer where to return the requested + value + + @return RESULT_OK if option was sucessfully read; RESULT_ERROR + is set otherwise (use mysqlx_error() to get the error + information) +*/ + int STDCALL mysqlx_session_option_get(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, ...); + /* brief MYSQLX API - * - * @details Get a schema object and check if it esixts on the server - * - * @param sess the session handle mysqlx_session_t - * @param schema_name name of the schema - * @param check flag to verify if the schema with the given name - * exists on the server (1 - check, 0 - do not check) - * - * @return mysqlx_schema_t structure containing the schema context or NULL - * if an error occurred or the schema does not exist on the server - */ + + @details Get a schema object and check if it esixts on the server + + @param sess the session handle mysqlx_session_t + @param schema_name name of the schema + @param check flag to verify if the schema with the given name + exists on the server (1 - check, 0 - do not check) + + @return mysqlx_schema_t structure containing the schema context or NULL + if an error occurred or the schema does not exist on the server +*/ + mysqlx_schema_t * STDCALL mysqlx_get_schema(mysqlx_session_t *sess, const char *schema_name, unsigned int check); + /* brief MYSQLX API - * - * @details Get a collection object and check if it esixts in the schema - * - * @param schema the schema handle mysqlx_schema_t - * @param col_name name of the collection - * @param check flag to verify if the collection with the given name - * exists in the schema (1 - check, 0 - do not check) - * - * @return mysqlx_collection_t structure containing the collection context or NULL - * if an error occurred or the collection does not exist in the schema - */ + + @details Get a collection object and check if it esixts in the schema + + @param schema the schema handle mysqlx_schema_t + @param col_name name of the collection + @param check flag to verify if the collection with the given name + exists in the schema (1 - check, 0 - do not check) + + @return mysqlx_collection_t structure containing the collection context or NULL + if an error occurred or the collection does not exist in the schema +*/ + mysqlx_collection_t * STDCALL mysqlx_get_collection(mysqlx_schema_t *schema, const char *col_name, unsigned int check); /* brief MYSQLX API - * - * @details Get a table object and check if it esixts in the schema - * - * @param schema the schema handle mysqlx_schema_t - * @param tab_name name of the table - * @param check flag to verify if the table with the given name - * exists in the schema (1 - check, 0 - do not check) - * - * @return mysqlx_table_t structure containing the collection context or NULL - * if an error occurred or the table does not exist in the schema - */ + + @details Get a table object and check if it esixts in the schema + + @param schema the schema handle mysqlx_schema_t + @param tab_name name of the table + @param check flag to verify if the table with the given name + exists in the schema (1 - check, 0 - do not check) + + @return mysqlx_table_t structure containing the collection context or NULL + if an error occurred or the table does not exist in the schema +*/ + mysqlx_table_t * STDCALL mysqlx_get_table(mysqlx_schema_t *schema, const char *tab_name, unsigned int check); @@ -2321,4 +2414,4 @@ mysqlx_get_table(mysqlx_schema_t *schema, const char *tab_name, } #endif -#endif /* __MYSQLX_H__ */ \ No newline at end of file +#endif /* __MYSQLX_H__*/ \ No newline at end of file From b036b98136c723233e64cee99ed4fe8a15125067 Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Wed, 7 Sep 2016 19:04:05 +1000 Subject: [PATCH 02/79] Fix for collection _id --- xapi/crud.cc | 11 +++++- xapi/result.cc | 2 +- xapi/row.cc | 49 +++++++++++++++++-------- xapi/row_internal.h | 21 ++++++++--- xapi/tests/xapi-t.cc | 6 ++-- xapi/tests/xapi_crud-t.cc | 76 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 23 deletions(-) diff --git a/xapi/crud.cc b/xapi/crud.cc index efba73dc0..8d2d68ff9 100644 --- a/xapi/crud.cc +++ b/xapi/crud.cc @@ -733,7 +733,16 @@ int mysqlx_stmt_t::add_document(const char *json_doc) because in the future this function can support multiple arguments */ m_doc_source.add_new_doc(); - m_doc_source.add_doc_value(json_doc); + try + { + m_doc_source.add_doc_value(json_doc); + } + catch (...) + { + // Something went wrong when parsing the JSON, remove the new doc + m_doc_source.remove_last_row(); + throw; + } return res; } diff --git a/xapi/result.cc b/xapi/result.cc index 955cc76d4..671dbb5a0 100644 --- a/xapi/result.cc +++ b/xapi/result.cc @@ -364,7 +364,7 @@ mysqlx_doc_t *mysqlx_result_t::read_doc() Row_processor row_proc(&row); if (m_cursor->get_row(row_proc)) { - m_doc_set.push_back(new mysqlx_doc_t(row)); + m_doc_set.push_back(new mysqlx_doc_t(row.get_col_data(0))); return m_doc_set[0]; } else if(m_reply.entry_count()) diff --git a/xapi/row.cc b/xapi/row.cc index 8e5bab992..89fed79e5 100644 --- a/xapi/row.cc +++ b/xapi/row.cc @@ -142,11 +142,9 @@ cdk::bytes mysqlx_row_t::get_col_data(cdk::col_count_t pos) { return m_row_data[pos]->get_data(); } - -mysqlx_doc_t::mysqlx_doc_struct(mysqlx_row_t &row) : m_crud(row.get_result().get_crud()), - m_bytes(row.get_col_data(0)), - m_json_doc(m_bytes) - { } +mysqlx_doc_t::mysqlx_doc_struct(cdk::bytes data) : m_bytes(data), +m_json_doc(m_bytes) +{ } void Value_item::process_any(cdk::Any::Processor &prc) const { @@ -189,17 +187,37 @@ void Row_item::process(cdk::Value_processor &prc) const void Row_item::generate_uuid() { uuid_type uuid; - ::generate_uuid(uuid); - char buf[sizeof(uuid_type)*2 + 1]; - const char digits[17] = {"0123456789ABCDEF"}; - for (size_t i = 0; i < sizeof(uuid); ++i) + /* + Create a local copy of a document structure just to get _id + if it was provided by a user inside JSON + */ + mysqlx_doc_t doc(m_str.data()); + + if (doc.key_exists("_id")) { - buf[i*2] = digits[((unsigned char)uuid[i]) & 0x0F]; - buf[i*2 + 1] = digits[((unsigned char)uuid[i] >> 4) ]; + std::string str_id = doc.get_string("_id"); + if (str_id.length() > sizeof(uuid_type)* 2) + throw Mysqlx_exception("Specified UUID is too long"); + m_uuid = str_id; + } + else + { + if (!doc.count()) + m_empty_doc = true; // do not add "," before _id + + ::generate_uuid(uuid); + char buf[sizeof(uuid_type)* 2 + 1]; + const char digits[17] = { "0123456789ABCDEF" }; + + for (size_t i = 0; i < sizeof(uuid); ++i) + { + buf[i * 2] = digits[((unsigned char)uuid[i]) & 0x0F]; + buf[i * 2 + 1] = digits[((unsigned char)uuid[i] >> 4)]; + } + buf[sizeof(uuid_type)* 2] = 0; // put a string termination + m_uuid = buf; } - buf[sizeof(uuid_type)*2] = 0; // put a string termination - m_uuid = buf; } // Process method for table projections @@ -279,7 +297,10 @@ void Doc_source::process(Processor &prc) const std::string s = it->get_string(); s.erase(s.rfind('}')); std::stringstream sstream; - sstream << ", \"_id\": \"" << it->get_uuid() << "\"}"; + if (!it->is_empty_doc()) + sstream << ", "; + + sstream << "\"_id\": \"" << it->get_uuid() << "\"}"; s.append(sstream.str()); cdk::bytes b = s; cdk::safe_prc(prc)->scalar()->val()->value(cdk::TYPE_DOCUMENT, diff --git a/xapi/row_internal.h b/xapi/row_internal.h index 0cb6abb85..5be6e8c22 100644 --- a/xapi/row_internal.h +++ b/xapi/row_internal.h @@ -256,15 +256,17 @@ typedef struct mysqlx_doc_struct : public Mysqlx_diag throw Mysqlx_exception("Key does not exist!"); return m_map.at(key); } + + size_t count() + { return m_map.size(); } }; - mysqlx_stmt_t &m_crud; cdk::bytes m_bytes; JSON_doc m_json_doc; public: - mysqlx_doc_struct(mysqlx_row_t &row); + mysqlx_doc_struct(cdk::bytes data); uint64_t get_uint(const cdk::string key) { return m_json_doc.get_val(key).get_uint(); } @@ -290,6 +292,8 @@ typedef struct mysqlx_doc_struct : public Mysqlx_diag bool key_exists(const cdk::string key) { return m_json_doc.key_exists(key); } + size_t count() + { return m_json_doc.count(); } } mysqlx_doc_t; @@ -441,19 +445,22 @@ class Projection_list : public cdk::Projection, public cdk::Expression::Document class Row_item : public Value_item { std::string m_uuid; + bool m_empty_doc; public: // Constructor template for other types - template Row_item(T val) : Value_item(val) {} + template Row_item(T val) : Value_item(val), m_empty_doc(false) {} // Default constructor for NULL values - Row_item() : Value_item() {} + Row_item() : Value_item(), m_empty_doc(false) {} void process(cdk::Value_processor &prc) const; void generate_uuid(); std::string get_uuid() const { return m_uuid; }; + + bool is_empty_doc() const { return m_empty_doc; } }; class Source_base @@ -478,6 +485,12 @@ class Source_base add_new_row(); } + void remove_last_row() + { + if (m_rows.size()) + m_rows.erase(m_rows.begin() + m_rows.size() - 1); + } + // Clear the list void clear() { m_row_num = 0; m_rows.clear(); } size_t row_count() const { return m_rows.size(); } diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 8b1ceff49..268b23686 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -478,11 +478,11 @@ TEST_F(xapi, transaction_test) EXPECT_TRUE((table = mysqlx_get_table(schema, "transact_tab", 1)) != NULL); EXPECT_EQ(RESULT_OK, mysqlx_transaction_begin(get_session())); - SESS_CHECK( res = mysqlx_table_insert(table, "a", PARAM_SINT(200), PARAM_END)); + SESS_CHECK(res = mysqlx_table_insert(table, "a", PARAM_SINT(200), PARAM_END)); EXPECT_EQ(RESULT_OK, mysqlx_transaction_commit(get_session())); // Check how the row was inserted after committing the transaction - SESS_CHECK( res = mysqlx_table_select(table, "a > 0")); + SESS_CHECK(res = mysqlx_table_select(table, "a > 0")); while ((row = mysqlx_row_fetch_one(res)) != NULL) { @@ -496,7 +496,7 @@ TEST_F(xapi, transaction_test) EXPECT_EQ(RESULT_OK, mysqlx_transaction_rollback(get_session())); // Check how the row was not deleted after rolling back the transaction - SESS_CHECK( res = mysqlx_table_select(table, "a > 0")); + SESS_CHECK(res = mysqlx_table_select(table, "a > 0")); while ((row = mysqlx_row_fetch_one(res)) != NULL) { diff --git a/xapi/tests/xapi_crud-t.cc b/xapi/tests/xapi_crud-t.cc index 33518e5d3..827e74950 100644 --- a/xapi/tests/xapi_crud-t.cc +++ b/xapi/tests/xapi_crud-t.cc @@ -1932,3 +1932,79 @@ TEST_F(xapi_bugs, collection_null_test) EXPECT_TRUE(strstr(json_string, "null") != NULL); // it is unset } } + +TEST_F(xapi_bugs, collection_id_test) +{ + SKIP_IF_NO_XPLUGIN + + mysqlx_result_t *res; + mysqlx_stmt_t *stmt; + mysqlx_schema_t *schema; + mysqlx_collection_t *collection; + + const char * json_string = NULL; + size_t json_len = 0; + int i = 0; + const char *id; + char id_buf[3][128]; + + + AUTHENTICATE(); + + mysqlx_schema_create(get_session(), "cc_crud_test"); + + EXPECT_TRUE((schema = mysqlx_get_schema(get_session(), "cc_crud_test", 1)) != NULL); + EXPECT_EQ(RESULT_OK, mysqlx_collection_create(schema, "collection_id")); + EXPECT_TRUE((collection = mysqlx_get_collection(schema, "collection_id", 1)) != NULL); + + RESULT_CHECK(stmt = mysqlx_collection_add_new(collection)); + + // empty document + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{}")); + + // Normal document with auto-generated _id + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"a_key\" : 100}")); + + // Document with _id specified by user + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"a_key\" : 200, \"_id\" : \"111222333\"}")); + + // Document with invalid _id specified by user, expect error + EXPECT_EQ(RESULT_ERROR, mysqlx_set_add_document(stmt, "{\"a_key\" : 300, \"_id\" : \"000000000000000000000000000000000011122223333\"}")); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + while ((id = mysqlx_fetch_doc_id(res)) != NULL) + { + strcpy(id_buf[i], id); + ++i; + } + + RESULT_CHECK(stmt = mysqlx_collection_find_new(collection)); + EXPECT_EQ(RESULT_OK, mysqlx_set_find_order_by(stmt, "a_key", SORT_ORDER_ASC, PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + i = 0; + while ((json_string = mysqlx_json_fetch_one(res, &json_len)) != NULL) + { + if (json_string) + printf("\n[json: %s]", json_string); + + EXPECT_TRUE(strstr(json_string, id_buf[i]) != NULL); + + switch (i) + { + case 0: // just _id in the JSON + EXPECT_TRUE(strstr(json_string, "a_key") == NULL); + break; + case 1: // { "a_key" : 100} + EXPECT_TRUE(strstr(json_string, "\"a_key\": 100") != NULL); + break; + case 2: // { "a_key" : 200, "_id" : "111222333"} + EXPECT_TRUE(strstr(json_string, "\"a_key\": 200") != NULL); + break; + default: // no more documents in the result + FAIL(); + } + + ++i; + } +} From 498c51188acec5242c03334ee81e4b711a74e89f Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Thu, 3 Nov 2016 23:51:30 +1100 Subject: [PATCH 03/79] Support for SSL connections in X API --- include/mysql_xapi.h | 7 +++++-- xapi/mysqlx.cc | 4 ++++ xapi/mysqlx_cc_internal.h | 12 +++++++++++- xapi/tests/xapi-t.cc | 24 ++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 1eb370aea..5ea023377 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -324,7 +324,8 @@ typedef enum mysqlx_opt_type_enum MYSQLX_OPT_PORT = 2, MYSQLX_OPT_USER = 3, MYSQLX_OPT_PWD = 4, - MYSQLX_OPT_DB = 5 + MYSQLX_OPT_DB = 5, + MYSQLX_OPT_SSL_ENABLE = 6 } mysqlx_opt_type_t; @@ -355,6 +356,7 @@ mysqlx_opt_type_t; @note The session returned by the function must be properly closed using `mysqlx_session_close()`. @note This type of session does not support executing plain SQL queries. + @note This function always establishes connection with SSL enabled @ingroup xapi_sess */ @@ -368,7 +370,7 @@ mysqlx_get_session(const char *host, int port, const char *user, /** Create a session using connection string or URL. - Connection sting has the form `"user:pass\@host:port"`, valid URL + Connection sting has the form `"user:pass\@host:port/?option"`, valid URL is like a connection string with a `mysqlx://` prefix. @param conn_string character connection string @@ -440,6 +442,7 @@ mysqlx_get_session_from_options(mysqlx_session_options_t *opt, @note The session returned by the function must be properly closed using `mysqlx_session_close()`. @note This type of session supports executing plain SQL queries + @note This function always establishes connection with SSL enabled @ingroup xapi_sess */ diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index e284de3f1..c037a84cb 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -1684,6 +1684,10 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, char_data = ""; opt->set_database(char_data); break; + case MYSQLX_OPT_SSL_ENABLE: + uint_data = va_arg(args, unsigned int); + opt->set_tls(uint_data > 0); + break; default: opt->set_diagnostic("Invalid option value", 0); rc = RESULT_ERROR; diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 70eee6c67..c0e7f68bc 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -373,13 +373,15 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, mysqlx_session_options_struct(const std::string host, unsigned short port, const std::string usr, const std::string *pwd, - const std::string *db) : + const std::string *db, bool ssl_enable = true) : cdk::ds::Options(usr, pwd), m_host(host), m_port(port ? port : DEFAULT_MYSQLX_PORT), m_tcp(NULL) { if (db) set_database(*db); + + set_tls(ssl_enable); } mysqlx_session_options_struct(const std::string &conn_str) : m_tcp(NULL) @@ -421,6 +423,14 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, void path(const std::string &path) { set_database(path); } + void key_val(const std::string& key) + { + if (key.compare("ssl-enable") == 0) + { + set_tls(true); + } + } + std::string get_host() { return m_host; } unsigned int get_port() { return m_port; } std::string get_user() { return m_usr; } diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index dacbc81ad..846e3a3ad 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -319,6 +319,7 @@ TEST_F(xapi, conn_string_test) char conn_error[MYSQLX_MAX_ERROR_LEN] = { 0 }; char conn_str[1024]; int conn_err_code = 0; + bool ssl_enable = false; const char *xplugin_port = getenv("XPLUGIN_PORT"); const char *xplugin_usr = getenv("XPLUGIN_USER"); const char *xplugin_pwd = getenv("XPLUGIN_PASSWORD"); @@ -342,6 +343,8 @@ TEST_F(xapi, conn_string_test) else sprintf(conn_str, "%s@%s:%d", xplugin_usr, xplugin_host, port); +DO_CONNECT: + local_sess = mysqlx_get_node_session_from_url(http://github.com/conn_str,%20conn_error,%20&conn_err_code); if (!local_sess) @@ -362,6 +365,15 @@ TEST_F(xapi, conn_string_test) EXPECT_STREQ("foo", data); cout << "ROW DATA: " << data << " " << endl; } + + mysqlx_session_close(local_sess); + + if (!ssl_enable) + { + ssl_enable = true; + strcat(conn_str, "/?ssl-enable"); + goto DO_CONNECT; + } } @@ -371,6 +383,7 @@ TEST_F(xapi, conn_options_test) unsigned int port = 0; unsigned int port2 = 0; + unsigned int ssl_enable = 0; char conn_error[MYSQLX_MAX_ERROR_LEN] = { 0 }; int conn_err_code = 0; const char *xplugin_port = getenv("XPLUGIN_PORT"); @@ -411,6 +424,8 @@ TEST_F(xapi, conn_options_test) EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_PORT, &port2)); EXPECT_EQ(true, port == port2); +DO_CONNECT: + local_sess = mysqlx_get_node_session_from_options(opt, conn_error, &conn_err_code); if (!local_sess) @@ -432,6 +447,15 @@ TEST_F(xapi, conn_options_test) EXPECT_STREQ("foo", data); cout << "ROW DATA: " << data << " " << endl; } + + mysqlx_session_close(local_sess); + if (!ssl_enable) + { + ssl_enable = 1; + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_ENABLE, ssl_enable)); + goto DO_CONNECT; + } + mysqlx_free_options(opt); } From d5338a90886a27dc082215afb9a53ce8c0db6290 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 28 Oct 2016 16:15:48 +0200 Subject: [PATCH 04/79] CDK: Fix public header dependencies and other refactorings. Make sure that the "general" CDK headers do not use types defined in more "specific" headers like cdk/mysqlx/*.h or cdk/protocol/*.h. The biggest change is to redefine cdk::Doc_path interface which, before the change, was taken from the protocol headers. Now it is a separate interface following the visitor pattern where document path components are reported via processor callbacks. The code was updated to the new cdk::Doc_path interface, including the parser. On that occasion a couple of tweaks to the document path parsing logic was made. Also, the Token_op_base class was made a common base of the Expr_parser<> template (as these methods are used everywhere). --- cdk/core/tests/session_crud-t.cc | 14 +- cdk/include/mysql/cdk/api/document.h | 200 +++++ cdk/include/mysql/cdk/api/expression.h | 3 + cdk/include/mysql/cdk/api/query.h | 73 +- cdk/include/mysql/cdk/common.h | 32 +- cdk/include/mysql/cdk/mysqlx/session.h | 23 +- cdk/include/mysql/cdk/protocol/mysqlx.h | 31 +- .../protocol/{mysqlx_expr.h => mysqlx/expr.h} | 31 +- .../mysql/cdk/protocol/mysqlx/traits.h | 25 + cdk/include/mysql/cdk/session.h | 7 +- cdk/mysqlx/converters.h | 65 +- cdk/mysqlx/delayed_op.h | 25 +- cdk/parser/expr_parser.cc | 782 ++++++++++++------ cdk/parser/expr_parser.h | 437 +++------- cdk/parser/parser.h | 118 ++- cdk/parser/tests/parser-t.cc | 188 +++-- cdk/protocol/mysqlx/builders.h | 2 +- cdk/protocol/mysqlx/tests/expr.h | 9 +- cdk/protocol/mysqlx/tests/test.h | 15 +- 19 files changed, 1253 insertions(+), 827 deletions(-) rename cdk/include/mysql/cdk/protocol/{mysqlx_expr.h => mysqlx/expr.h} (95%) create mode 100644 cdk/include/mysql/cdk/protocol/mysqlx/traits.h diff --git a/cdk/core/tests/session_crud-t.cc b/cdk/core/tests/session_crud-t.cc index 9f8f074d2..8270ead58 100644 --- a/cdk/core/tests/session_crud-t.cc +++ b/cdk/core/tests/session_crud-t.cc @@ -795,10 +795,16 @@ class Path private: - unsigned length() const { return m_path.size(); } - Type get_type(unsigned pos) const { return MEMBER; } - const string* get_name(unsigned pos) const { return &m_path.at(pos); } - const uint32_t* get_index(unsigned) const { return NULL; } + void process(Processor &prc) const + { + prc.list_begin(); + + for (size_t pos = 0; pos < m_path.size(); ++pos) + safe_prc(prc)->list_el()->member(m_path[pos]); + + prc.list_end(); + } + }; diff --git a/cdk/include/mysql/cdk/api/document.h b/cdk/include/mysql/cdk/api/document.h index d3846ab2f..cef3ed983 100644 --- a/cdk/include/mysql/cdk/api/document.h +++ b/cdk/include/mysql/cdk/api/document.h @@ -31,6 +31,7 @@ namespace cdk { namespace api { + /** Documents over processor PRC ============================ @@ -165,11 +166,176 @@ class Doc_base : public Expr_base< Doc_processor > }; +/* + Document path specification is a list of items, each to be processed + with Doc_path_processor to describe one element of the path. +*/ + +class Doc_path_processor +{ +public: + + typedef cdk::api::string string; + typedef uint32_t index_t; + + // Path element is name of document field. + + virtual void member(const string &name) =0; + + // Path element "*". + + virtual void any_member() =0; + + // Path element is at given position within an array. + + virtual void index(index_t) =0; + + // Path element "[*]". + + virtual void any_index() =0; + + // Path element "**". + + virtual void any_path() =0; +}; + +typedef Expr_list< Expr_base > Doc_path; + + }} // cdk::api namespace cdk { +class Doc_path_storage + : public api::Doc_path + , public api::Doc_path::Processor + , api::Doc_path_processor +{ +public: + + enum Type { + MEMBER, + MEMBER_ASTERISK, + ARRAY_INDEX, + ARRAY_INDEX_ASTERISK, + DOUBLE_ASTERISK + }; + +protected: + + struct Path_el + { + Type m_type; + string m_name; + uint32_t m_idx; + }; + + std::vector m_path; + +public: + + // Access to path data + + size_t length() const + { + return m_path.size(); + } + + bool is_empty() const + { + return 0 == length(); + } + + const Path_el& get_el(size_t pos) const + { + return m_path.at(pos); + } + + void clear() + { + m_path.clear(); + } + + // Doc_path + + void process(Processor &prc) const + { + prc.list_begin(); + + for (size_t pos = 0; pos < m_path.size(); ++pos) + { + api::Doc_path_processor *eprc = prc.list_el(); + if (eprc) + { + const Path_el &el = m_path[pos]; + switch (el.m_type) + { + case MEMBER: eprc->member(el.m_name); break; + case MEMBER_ASTERISK: eprc->any_member(); break; + case ARRAY_INDEX: eprc->index(el.m_idx); break; + case ARRAY_INDEX_ASTERISK: eprc->any_index(); break; + case DOUBLE_ASTERISK: eprc->any_path(); break; + } + } + } + + prc.list_end(); + } + + + // List_processor + + Path_el *m_el; + + Element_prc* list_el() + { + m_path.push_back(Path_el()); + m_el = &m_path.back(); + return this; + } + +private: + + // Doc_path_processor + + void member(const string &name) + { + assert(m_el); + m_el->m_type = MEMBER; + m_el->m_name = name; + } + + void any_member() + { + assert(m_el); + m_el->m_type = MEMBER_ASTERISK; + } + + void index(index_t pos) + { + assert(m_el); + m_el->m_type = ARRAY_INDEX; + m_el->m_idx = pos; + } + + void any_index() + { + assert(m_el); + m_el->m_type = ARRAY_INDEX_ASTERISK; + } + + void any_path() + { + assert(m_el); + m_el->m_type = DOUBLE_ASTERISK; + } +}; + +} // cdk + + +namespace cdk { template struct Safe_prc< cdk::api::Any_processor > @@ -231,6 +397,40 @@ struct Safe_prc< cdk::api::Doc_processor > }; + +template<> +struct Safe_prc + : Safe_prc_base +{ + typedef Safe_prc_base Base; + using Base::Processor; + typedef Processor::string string; + typedef Processor::index_t index_t; + + Safe_prc(Processor *prc) : Base(prc) + {} + + Safe_prc(Processor &prc) : Base(&prc) + {} + + using Base::m_prc; + + void member(const string &name) + { return m_prc ? m_prc->member(name) : (void)NULL; } + + void any_member() + { return m_prc ? m_prc->any_member() : (void)NULL; } + + void index(index_t ind) + { return m_prc ? m_prc->index(ind) : (void)NULL; } + + void any_index() + { return m_prc ? m_prc->any_index() : (void)NULL; } + + void any_path() + { return m_prc ? m_prc->any_path() : (void)NULL; } +}; + } #endif diff --git a/cdk/include/mysql/cdk/api/expression.h b/cdk/include/mysql/cdk/api/expression.h index 44bdc86f8..3824c885d 100644 --- a/cdk/include/mysql/cdk/api/expression.h +++ b/cdk/include/mysql/cdk/api/expression.h @@ -31,6 +31,9 @@ namespace cdk { namespace api { +using foundation::string; + + /* Expressions =========== diff --git a/cdk/include/mysql/cdk/api/query.h b/cdk/include/mysql/cdk/api/query.h index 9f9e85270..b7c878de9 100644 --- a/cdk/include/mysql/cdk/api/query.h +++ b/cdk/include/mysql/cdk/api/query.h @@ -28,6 +28,7 @@ #define CDK_API_QUERY_H #include "expression.h" +#include "document.h" #include "../foundation/types.h" namespace cdk { @@ -119,43 +120,6 @@ class Projection {}; - -/* - Document path specification is a list of items, each to be processed - with Doc_path_processor to describe one element of the path. -*/ - -class Doc_path_processor -{ -public: - - typedef cdk::api::string string; - typedef uint32_t index_t; - - // Path element is name of document field. - - virtual void member(const string &name) =0; - - // Path element "*". - - virtual void any_member() =0; - - // Path element is at given position within an array. - - virtual void index(index_t) =0; - - // Path element "[*]". - - virtual void any_index() =0; - - // Path element "**". - - virtual void any_path() =0; -}; - -typedef Expr_list< Expr_base > Doc_path; - - /* Columns specification specifies table columns into which table insert operation should insert values. It is a list @@ -191,41 +155,6 @@ typedef Expr_list< Expr_base > Columns; namespace cdk { -template<> -struct Safe_prc - : Safe_prc_base -{ - typedef Safe_prc_base Base; - using Base::Processor; - typedef Processor::string string; - typedef Processor::index_t index_t; - - Safe_prc(Processor *prc) : Base(prc) - {} - - Safe_prc(Processor &prc) : Base(&prc) - {} - - using Base::m_prc; - - void member(const string &name) - { return m_prc ? m_prc->member(name) : (void)NULL; } - - void any_member() - { return m_prc ? m_prc->any_member() : (void)NULL; } - - void index(index_t ind) - { return m_prc ? m_prc->index(ind) : (void)NULL; } - - void any_index() - { return m_prc ? m_prc->any_index() : (void)NULL; } - - void any_path() - { return m_prc ? m_prc->any_path() : (void)NULL; } -}; - - - template<> struct Safe_prc : Safe_prc_base diff --git a/cdk/include/mysql/cdk/common.h b/cdk/include/mysql/cdk/common.h index 91aba6fbb..6d440eaa4 100644 --- a/cdk/include/mysql/cdk/common.h +++ b/cdk/include/mysql/cdk/common.h @@ -29,13 +29,10 @@ #include "api/obj_ref.h" #include "api/expression.h" #include "api/document.h" -#include "protocol/mysqlx.h" +#include "api/query.h" -namespace cdk { -using protocol::mysqlx::row_count_t; -using protocol::mysqlx::col_count_t; -using protocol::mysqlx::charset_id_t; +namespace cdk { /* @@ -153,6 +150,14 @@ class Column_info virtual length_t decimals() const =0; }; +/* + Note: These types are compatible with the X protocol. +*/ + +typedef uint64_t row_count_t; +typedef uint32_t col_count_t; +typedef uint64_t charset_id_t; + struct Traits { @@ -166,6 +171,7 @@ struct Traits }; + typedef api::Meta_data Meta_data; @@ -284,7 +290,7 @@ class Expr_processor; typedef api::Any Expression; typedef api::Expr_list Expr_list; -using cdk::protocol::mysqlx::api::Doc_path; +using api::Doc_path; class Expr_processor { @@ -314,8 +320,11 @@ class Expr_processor virtual Args_prc* op(const char*) =0; virtual Args_prc* call(const Object_ref&) =0; + // TODO: consider changing ref() so that they return doc path processor + virtual void ref(const Column_ref&, const Doc_path*) =0; virtual void ref(const Doc_path&) =0; + virtual void param(const string&) =0; virtual void param(uint16_t) =0; virtual void var(const string&) =0; @@ -502,6 +511,17 @@ class Doc_source {}; +/* + Classes for describing statement parameters + =========================================== +*/ + +typedef cdk::api::Limit Limit; +typedef cdk::api::Order_by Order_by; +typedef cdk::api::Sort_direction Sort_direction; +typedef cdk::api::Doc_base Param_source; + + /* Classes for describing update operations ======================================== diff --git a/cdk/include/mysql/cdk/mysqlx/session.h b/cdk/include/mysql/cdk/mysqlx/session.h index 4233a4c24..373d24c3c 100644 --- a/cdk/include/mysql/cdk/mysqlx/session.h +++ b/cdk/include/mysql/cdk/mysqlx/session.h @@ -28,7 +28,6 @@ #include #include #include "common.h" -#include PUSH_SYS_WARNINGS #include @@ -316,25 +315,20 @@ typedef std::map Mdata_storage; // --------------------------------------------------------- +/* + Note: other Session implementations might need to translate genric + cdk types to something that is specific to the implementation. +*/ using cdk::Row_source; using cdk::Projection; +using cdk::Limit; +using cdk::Order_by; +using cdk::Sort_direction; +using cdk::Param_source; typedef Session Reply_init; -/* - TODO: Make these generic cdk interfaces (defined in cdk/common.h) - that are used by cdk::mysqlx as is (so, the other way around). - - Note: other Session implementations might need to translate genric - cdk interfaces to something that is specific to the implementation. -*/ - -typedef cdk::api::Doc_base Param_source; -typedef cdk::api::Limit Limit; -typedef cdk::api::Order_by Order_by; -typedef cdk::api::Sort_direction Sort_direction; - class Reply; class Cursor; class SessionAuthInterface; @@ -489,6 +483,7 @@ class Session const Order_by *order_by = NULL, const Limit* = NULL, const Param_source * = NULL); + Reply_init &table_delete(const Table_ref&, const Expression *expr = NULL, const Order_by *order_by = NULL, diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index 51dd25323..435a68371 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -37,13 +37,18 @@ #include "../foundation.h" #include "../foundation/opaque_impl.h" #include "../api/query.h" -#include "mysqlx_expr.h" +#include "mysqlx/traits.h" +#include "mysqlx/expr.h" namespace cdk { namespace protocol { namespace mysqlx { +using cdk::foundation::byte; +using cdk::foundation::bytes; +using cdk::foundation::string; + /* Enumerations which define message type codes used by the protocol. @@ -607,6 +612,7 @@ Protocol_server::Protocol_server(C &conn) static_cast(new Protocol::Stream::Impl(conn))) {} + /* Callback interfaces to be implemented by message processor objects ================================================================== @@ -663,8 +669,9 @@ class Processor_base { public: - typedef foundation::byte byte; - typedef foundation::string string; + typedef protocol::mysqlx::byte byte; + typedef protocol::mysqlx::string string; + typedef protocol::mysqlx::msg_type_t msg_type_t; /* Called when message header is received. The type of the message stored @@ -766,6 +773,8 @@ class Error_processor : public Processor_base { public: + typedef protocol::mysqlx::sql_state_t sql_state_t; + virtual void error(unsigned int /*code*/, short int /*severity*/, sql_state_t /*sql_state*/, const string &/*msg*/) {} @@ -804,6 +813,10 @@ class Stmt_processor : public Error_processor class Row_processor : public Error_processor { public: + + typedef protocol::mysqlx::row_count_t row_count_t; + typedef protocol::mysqlx::col_count_t col_count_t; + virtual bool row_begin(row_count_t /*row*/) { return true; } virtual void row_end(row_count_t /*row*/) {} @@ -828,6 +841,9 @@ class Mdata_processor : public Error_processor { public: + typedef protocol::mysqlx::col_count_t col_count_t; + typedef protocol::mysqlx::charset_id_t charset_id_t; + virtual void col_count(col_count_t) {} virtual void col_type(col_count_t /*pos*/, unsigned short /*type*/) {} virtual void col_name(col_count_t /*pos*/, @@ -875,6 +891,10 @@ class Result_processor class SessionState_processor { public: + + typedef protocol::mysqlx::row_count_t row_count_t; + typedef protocol::mysqlx::insert_id_t insert_id_t; + enum row_stats_t { ROWS_AFFECTED, ROWS_FOUND, ROWS_MATCHED }; enum trx_event_t { COMMIT, ROLLBACK }; @@ -914,7 +934,10 @@ class Update_processor { public: - typedef api::Expression::Processor Expr_prc; + typedef protocol::mysqlx::string string; + typedef protocol::mysqlx::api::Db_obj Db_obj; + typedef protocol::mysqlx::api::Doc_path Doc_path; + typedef protocol::mysqlx::api::Expression::Processor Expr_prc; virtual void target_name(const string&) = 0; virtual void target_table(const api::Db_obj&) = 0; diff --git a/cdk/include/mysql/cdk/protocol/mysqlx_expr.h b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h similarity index 95% rename from cdk/include/mysql/cdk/protocol/mysqlx_expr.h rename to cdk/include/mysql/cdk/protocol/mysqlx/expr.h index 5eb872bd0..207ca1daf 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx_expr.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h @@ -54,40 +54,22 @@ */ -#include "../foundation.h" -#include "../api/expression.h" -#include "../api/document.h" - -namespace cdk { -namespace protocol { -namespace mysqlx { - -// These are temporary type declarations -// TODO: remove when the types are defined - -typedef uint32_t stmt_id_t; -typedef uint32_t cursor_id_t; -typedef uint64_t row_count_t; -typedef uint32_t col_count_t; -// Note: protocol uses 64bit numbers for collation ids -typedef uint64_t charset_id_t; -typedef uint64_t insert_id_t; - -typedef int64_t sint64_t; -using ::uint64_t; - -}}} +#include "../../foundation.h" +#include "../../api/expression.h" +#include "../../api/document.h" +#include "traits.h" namespace cdk { namespace protocol { namespace mysqlx { -namespace api { using cdk::foundation::byte; using cdk::foundation::bytes; using cdk::foundation::string; +namespace api { + /* Any value (scalar, document or array) @@ -248,7 +230,6 @@ class Doc_path { public: - enum Type { MEMBER = 1, MEMBER_ASTERISK = 2, diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/traits.h b/cdk/include/mysql/cdk/protocol/mysqlx/traits.h new file mode 100644 index 000000000..ded9571bb --- /dev/null +++ b/cdk/include/mysql/cdk/protocol/mysqlx/traits.h @@ -0,0 +1,25 @@ + +#ifndef MYSQL_CDK_PROTOCOL_MYSQLX_TRAITS_H +#define MYSQL_CDK_PROTOCOL_MYSQLX_TRAITS_H + +namespace cdk { +namespace protocol { +namespace mysqlx { + +// These are temporary type declarations +// TODO: remove when the types are defined + +typedef uint32_t stmt_id_t; +typedef uint32_t cursor_id_t; +typedef uint64_t row_count_t; +typedef uint32_t col_count_t; +// Note: protocol uses 64bit numbers for collation ids +typedef uint64_t charset_id_t; +typedef uint64_t insert_id_t; + +typedef int64_t sint64_t; +using ::uint64_t; + +}}} + +#endif diff --git a/cdk/include/mysql/cdk/session.h b/cdk/include/mysql/cdk/session.h index 09fa3398d..17ce53950 100644 --- a/cdk/include/mysql/cdk/session.h +++ b/cdk/include/mysql/cdk/session.h @@ -29,15 +29,10 @@ #include "api/transaction.h" #include "data_source.h" #include "reply.h" -#include "mysqlx.h" +#include "common.h" namespace cdk { -using cdk::mysqlx::Param_source; -using cdk::mysqlx::Limit; -using cdk::mysqlx::Order_by; - - /* Session class diff --git a/cdk/mysqlx/converters.h b/cdk/mysqlx/converters.h index 7b127aea5..79384420b 100644 --- a/cdk/mysqlx/converters.h +++ b/cdk/mysqlx/converters.h @@ -26,9 +26,10 @@ #define CDK_MYSQLX_CONVERTERS_H #include -#include +#include #include + namespace cdk { namespace mysqlx { @@ -160,6 +161,53 @@ typedef Expr_conv_base< // ------------------------------------------------------------------------- +struct Doc_path_storage + : public cdk::Doc_path_storage + , public protocol::mysqlx::api::Doc_path +{ + typedef protocol::mysqlx::api::Doc_path Proto_path; + typedef cdk::Doc_path_storage Storage; + + // Proto_path interface + + unsigned length() const + { + size_t len = cdk::Doc_path_storage::length(); + assert(len <= std::numeric_limits::max()); + return (unsigned)len; + } + + Proto_path::Type get_type(unsigned pos) const + { + switch (get_el(pos).m_type) + { + case Storage::MEMBER: return Proto_path::MEMBER; + case Storage::MEMBER_ASTERISK: return Proto_path::MEMBER_ASTERISK; + case Storage::ARRAY_INDEX: return Proto_path::ARRAY_INDEX; + case Storage::ARRAY_INDEX_ASTERISK: return Proto_path::ARRAY_INDEX_ASTERISK; + case Storage::DOUBLE_ASTERISK: return Proto_path::DOUBLE_ASTERISK; + } + + // Quiet compile warning. + assert(false); + return Proto_path::Type(0); + } + + const cdk::string* get_name(unsigned pos) const + { + const Path_el &el = get_el(pos); + return Storage::MEMBER == el.m_type ? &el.m_name : NULL; + } + + const uint32_t* get_index(unsigned pos) const + { + const Path_el &el = get_el(pos); + return Storage::ARRAY_INDEX == el.m_type ? &el.m_idx : NULL; + } + +}; + + struct Expr_prc_converter_base; typedef Any_prc_converter Expr_prc_converter; @@ -204,7 +252,14 @@ struct Expr_prc_converter_base Args_prc* call(const api::Object_ref&); void ref(const api::Column_ref&, const Doc_path*); - void ref(const Doc_path &path) { m_proc->id(path); } + + void ref(const Doc_path &path) + { + Doc_path_storage dp; + path.process(dp); + m_proc->id(dp); + } + void param(const string &name) { m_proc->placeholder(name); } void param(uint16_t pos) { m_proc->placeholder(pos); } void var(const string &name) { m_proc->var(name); } @@ -302,7 +357,11 @@ Expr_prc_converter_base::ref(const api::Column_ref &col, const Doc_path *path) set_db_obj(*col.table()); const protocol::mysqlx::api::Db_obj *table= (col.table() ? this : NULL); if (NULL != path) - m_proc->id(col.name(), table, *path); + { + Doc_path_storage dp; + path->process(dp); + m_proc->id(col.name(), table, dp); + } else m_proc->id(col.name(), table); } diff --git a/cdk/mysqlx/delayed_op.h b/cdk/mysqlx/delayed_op.h index 123a720bc..7f34e9cd3 100644 --- a/cdk/mysqlx/delayed_op.h +++ b/cdk/mysqlx/delayed_op.h @@ -26,6 +26,7 @@ #define CDK_MYSQLX_DELAYED_OP_H #include +#include #include #include "converters.h" @@ -671,8 +672,7 @@ class Update_prc_converter virtual void remove(const Doc_path *path) { - if (path) - m_proc->target_path(*path); + report_path(path); m_proc->update_op(protocol::mysqlx::update_op::ITEM_REMOVE); } @@ -685,9 +685,7 @@ class Update_prc_converter { Prc_to::Expr_prc *prc; - if (path) - m_proc->target_path(*path); - + report_path(path); if (flags & Update_processor::NO_INSERT) prc = m_proc->update_op(protocol::mysqlx::update_op::ITEM_REPLACE); @@ -700,7 +698,6 @@ class Update_prc_converter prc = m_proc->update_op(path ? protocol::mysqlx::update_op::ITEM_SET : protocol::mysqlx::update_op::SET); - if (!prc) return NULL; @@ -711,8 +708,7 @@ class Update_prc_converter Expr_prc* array_insert(const Doc_path *path) { - if (path) - m_proc->target_path(*path); + report_path(path); Prc_to::Expr_prc *prc = m_proc->update_op(protocol::mysqlx::update_op::ARRAY_INSERT); @@ -726,8 +722,7 @@ class Update_prc_converter Expr_prc* array_append(const Doc_path *path) { - if (path) - m_proc->target_path(*path); + report_path(path); Prc_to::Expr_prc *prc = m_proc->update_op(protocol::mysqlx::update_op::ARRAY_APPEND); @@ -739,6 +734,16 @@ class Update_prc_converter return &m_conv; } + void report_path(const Doc_path *path) + { + if (path) + { + Doc_path_storage dp; + path->process(dp); + if (!dp.is_empty()) + m_proc->target_path(dp); + } + } }; diff --git a/cdk/parser/expr_parser.cc b/cdk/parser/expr_parser.cc index 08942117d..bca4a9733 100644 --- a/cdk/parser/expr_parser.cc +++ b/cdk/parser/expr_parser.cc @@ -143,8 +143,7 @@ Expression::Processor* ignore_if(Expression::Processor *prc) bool Expr_parser_base::do_parse(It &first, const It &last, Processor *prc) { - Token_op_base::m_first = &first; - Token_op_base::m_last = last; + Token_op_base::set_tokens(first, last); /* if prc is NULL, ignore the parsed expression instead of storing it @@ -372,33 +371,50 @@ Expr_parser_base::parse_function_call(const cdk::api::Table_ref &func, Scalar_pr is rewritten as: columnIdent ::= schemaQualifiedIdent columnIdent1 - columnIdent1 ::= ('.' ident)? ('->' ( columnIdentDocPath | "'" columnIdentDocPath "'" ))? + columnIdent1 ::= ('.' ident)? ('->' ( columnIdentDocPath + | "'" columnIdentDocPath "'" ))? columnIdentDocPath ::= documentField // but require DOLLAR prefix */ -void Expr_parser_base::parse_schema_ident() +/* + Parse a schema-qualified identifier and store it as table/schema + name of m_col_ref member. Schema name is optional. + + If types is not NULL then types of the consumed tokens are stored in this + array. +*/ + +void Expr_parser_base::parse_schema_ident(Token::TokenType (*types)[2]) { + if (types) + { + (*types)[0] = peek_token().get_type(); + // Reset the other entry in case we are not looking at more tokens. + (*types)[1] = Token::TokenType(0); + } const cdk::string &name = get_ident(); + m_col_ref.m_table_ref.set(name); + if (cur_token_type_is(Token::DOT)) { consume_token(Token::DOT); + if (types) + (*types)[1] = peek_token().get_type(); m_col_ref.m_table_ref.set(get_ident(), name); } - else - m_col_ref.m_table_ref.set(name); } -void Expr_parser_base::parse_column_ident() +void Expr_parser_base::parse_column_ident(Path_prc *prc) { parse_schema_ident(); - parse_column_ident1(); + parse_column_ident1(prc); } -void Expr_parser_base::parse_column_ident1() +void Expr_parser_base::parse_column_ident1(Path_prc *prc) { if (cur_token_type_is(Token::DOT)) { @@ -417,9 +433,6 @@ void Expr_parser_base::parse_column_ident1() m_col_ref.set(m_col_ref.table()->name()); } - // Clear Document path - m_path.clear(); - if (cur_token_type_is(Token::ARROW)) { consume_token(Token::ARROW); @@ -432,14 +445,13 @@ void Expr_parser_base::parse_column_ident1() It last = toks.end(); Expr_parser_base path_parser(first, last, m_parser_mode); // TODO: Translate parse errors - path_parser.parse_document_field(true); + path_parser.parse_document_field(prc, true); if (first != last) throw Error("Invalid quotted path component"); - m_path = path_parser.m_path; } else { - parse_document_field(); + parse_document_field(prc, true); } } @@ -450,63 +462,77 @@ void Expr_parser_base::parse_column_ident1() /** + The original grammar was: + documentField ::= ID documentPath? | DOLLAR documentPath + + Which makes "*", "**.foo" or "*.foo" not valid field specifications + while "$[3]" is a valid specification. + + We modify the grammar so that "$[..]" is not valid while "*.." or "**.." + are valid: + + documentField ::= + | DOLLAR documentPathLeadingDot + | documentPath + + The grammar of documentPath was adjusted so that the first + path item can not be an array item ("[n]" or "[*]") and we can request + a leading DOT before member items (see parse_document_path()). + + If prefix is true, only the first form starting with DOLLAR prefix is + accepted. */ -void Doc_path_parser_base::parse_document_field() +void Expr_parser_base::parse_document_field(Path_prc *prc, bool prefix) { - //Clear Doc_path obj - m_path.clear(); - if (cur_token_type_is(Token::DOLLAR)) { consume_token(Token::DOLLAR); - - } else if (!cur_token_type_is(Token::DOT) && - !cur_token_type_is(Token::LSQBRACKET) && - !cur_token_type_is(Token::DOUBLESTAR)) - { - /* - Special case, starting with MEMBER - - On this case, we check if documentPath starts with DOT, LSQBRACKET or - DOUBLESTAR. If not, it is parsed as ID - */ - - parse_docpath_member(); + if (!parse_document_path(prc, true)) // require DOT before members + throw_error("Document path expected"); + return; } - parse_document_path(false); + if (prefix) + throw_error("Expected DOLLAR to start a document path"); + + if (!parse_document_path(prc, false)) + throw_error("Document path expected"); } -/** - documentField ::= ID documentPath? | DOLLAR documentPath - If prefix is true, only second form starting with DOLLAR prefix is - accepted. +/* + Parse a document field path with a given initial member segment. */ -void Expr_parser_base::parse_document_field(bool prefix) +void Expr_parser_base::parse_document_field(const string &first, Path_prc *prc) { - if (cur_token_type_is(Token::ID) && !prefix) - { - return parse_document_path(consume_token(Token::ID)); - } + Safe_prc sprc = prc; - if (cur_token_type_is(Token::DOLLAR)) - { - consume_token(Token::DOLLAR); - return parse_document_path(); - } + sprc->list_begin(); + sprc->list_el()->member(first); + parse_document_path1(prc); + sprc->list_end(); +} +/* + Parse a document field path with given 2 initial member segment. +*/ +void Expr_parser_base::parse_document_field(const string &first, + const string &second, + Path_prc *prc) +{ + Safe_prc sprc = prc; - throw Error( - (boost::format("Expr parser: Expected token type IDENT or DOLLAR in JSON path" - " at token pos %d") % get_token_pos()).str()); + sprc->list_begin(); + sprc->list_el()->member(first); + sprc->list_el()->member(second); + parse_document_path1(prc); + sprc->list_end(); } - /** Original Grammar: @@ -526,92 +552,247 @@ void Expr_parser_base::parse_document_field(bool prefix) ID | STRING1 - This grammar has been re-written to equivalent one + This grammar has few flaws: + + 1. It allows a document path to start with array location, which is not + correct - array locations should be possible only after a path to some + array member. + + 2. It always requires a DOT befre a member element, but in some contexts + we want a document path like "foo.bar.baz" to start without a dot. + + To deal with this the grammar has been changed and require_dot parameter + has been added. Modified grammar: + + documentPath ::= documentPathFirstItem documentPathItem* - documentPath ::= documentPathItem+ + documentPathFirstItem ::= + | DOT? documentPathMember + | DOUBLESTAR documentPathItem ::= - | DOUBLESTAR - | LSQBRACKET documentPathArrayLoc RSQBRACKET - | DOT MUL - | DOT documentPathMember + | DOT documentPathMember + | DOUBLESTAR + | documentPathArray + + documentPathMember ::= + | MUL + | ID + | STRING1 + + docuemntPathArray ::= LSQBRACKET documentPathArrayLoc RSQBRACKET documentPathArrayLoc ::= - | MUL - | INT + | MUL + | INT - documentPathMember ::= - ID - | STRING1 + Parameter require_dot tells if the initial dot is required or not. - A check that DOUBLESTAR is not last element of a path is done separately. + A check that DOUBLESTAR is not last element of a path is done separately. - */ + Returns true if a valid document path was parsed and reported, false if the + current token did not start a valid document path. + + Note: If false is returned then nothing is reported to the processor (not + even an empty list). +*/ -void Doc_path_parser_base::parse_document_path(bool clear) +bool Expr_parser_base::parse_document_path(Path_prc *prc, bool require_dot) { - if (clear) - m_path.clear(); + /* + Below we call methods like parse_docpath_member() which expect a document + path element processor. Our path processor prc is a list processor. So, + before we report the first path element we must call prc->list_begin() and + prc->list_el(). The problem is that when calling parse_docpath_member() + we might not know yet if there is any path to report or not -- only inside + parse_docpath_member() it will become evident. + + The Path_el_reporter wrapper around path processor solves this problem by + deffering the initial list_begin() call and the list_el() calls to the + moment when a path element is reported. If no path elements are reported + then list_begin() or list_el() will not be called. Similar, call to + list_end() will be forwarded to the wrapped processor only if list_begin() + was called before. + */ - while (true) + struct Path_el_reporter + : public Path_prc + , public Path_prc::Element_prc { - if (cur_token_type_is(Token::DOT)) + Safe_prc m_prc; + bool m_started; + + void list_begin() { - consume_token(Token::DOT); - if (cur_token_type_is(Token::MUL)) - { - consume_token(Token::MUL); - m_path.add(Doc_path::MEMBER_ASTERISK); - } - else - { - parse_docpath_member(); - } + if (!m_started) + m_prc->list_begin(); + m_started = true; } - else if (cur_token_type_is(Token::LSQBRACKET)) + + void list_end() { - consume_token(Token::LSQBRACKET); - parse_docpath_array_loc(); - consume_token(Token::RSQBRACKET); + if (m_started) + m_prc->list_end(); } - else if (cur_token_type_is(Token::DOUBLESTAR)) + + Element_prc* list_el() { - consume_token(Token::DOUBLESTAR); - m_path.add(Doc_path::DOUBLE_ASTERISK); + return this; } - else + + // Element_prc + + void member(const string &name) { - break; + list_begin(); + m_prc->list_el()->member(name); + } + + void any_member() + { + list_begin(); + m_prc->list_el()->any_member(); + } + + void index(index_t ind) + { + list_begin(); + m_prc->list_el()->index(ind); } + + void any_index() + { + list_begin(); + m_prc->list_el()->any_index(); + } + + void any_path() + { + list_begin(); + m_prc->list_el()->any_path(); + } + + Path_el_reporter(Path_prc *prc) + : m_prc(prc), m_started(false) + {} } - unsigned int size = m_path.length(); - if (size > 0 && (m_path.get_type(size - 1) == Doc_path::DOUBLE_ASTERISK)) + el_reporter(prc); + + // documentPathFirstItem + + bool double_star = false; + + if (cur_token_type_is(Token::DOUBLESTAR)) { - throw Error((boost::format("Expr parser: JSON path may not end in '**' at %d") % get_token_pos()).str()); + consume_token(Token::DOUBLESTAR); + double_star = true; + el_reporter.any_path(); + } + else + { + if (cur_token_type_is(Token::DOT)) + { + consume_token(Token::DOT); + if (!parse_docpath_member(&el_reporter)) + unexpected_token(peek_token(), "Document path"); + } + else if (require_dot) + { + return false; + } + else + { + if (!parse_docpath_member(&el_reporter)) + return false; + } } -} -void Doc_path_parser_base::parse_document_path(const cdk::string &first) -{ - m_path.clear(); - m_path.add(Doc_path::MEMBER, first); - parse_document_path(false); + // the rest of the path + + bool ret = parse_document_path1(&el_reporter); + + if (!ret && double_star) + throw_error("Document path ending in '**'"); + + el_reporter.list_end(); + + return true; } -void Doc_path_parser_base::parse_document_path(const cdk::string &first, - const cdk::string &second) + +/* + Parse a reminder of a document path after the first item, that is, a possibly + empty sequence of documentPathItem strings. + + The items are reported to the given Path_prc without calling list_begin() or + list_end() (which is assumed to be done by the caller). + + Returns true if at least one path item component was parsed. +*/ + +bool Expr_parser_base::parse_document_path1(Path_prc *prc) { - m_path.clear(); - m_path.add(Doc_path::MEMBER, first); - m_path.add(Doc_path::MEMBER, second); - parse_document_path(false); + Safe_prc sprc = prc; + + /* + These Booleans are used to detect if we are at the beginning of the path + and if there was a "**" component at the end of it. + */ + + bool double_star; + bool last_double_star = false; + bool has_item = false; + + for (double_star = false; true; + last_double_star =double_star, + double_star =false, + has_item = true) + { + if (!tokens_available()) + break; + + const Token &t = peek_token(); + + switch (t.get_type()) + { + case Token::DOT: + consume_token(Token::DOT); + if (!parse_docpath_member(sprc->list_el())) + unexpected_token(peek_token(), + "when looking for a document path element"); + continue; + + case Token::DOUBLESTAR: + consume_token(Token::DOUBLESTAR); + sprc->list_el()->any_path(); + double_star = true; + continue; + + case Token::LSQBRACKET: + consume_token(Token::LSQBRACKET); + parse_docpath_array_loc(sprc->list_el()); + consume_token(Token::RSQBRACKET); + continue; + + default: + break; + } + + break; + } + + if (last_double_star) + throw_error("Document path ending in '**'"); + + return has_item; } /** documentPathMember ::= - ID - | STRING1 + | MUL + | ID + | STRING1 TODO: Does STRING1 differ from plain STRING in any way? @@ -619,27 +800,37 @@ void Doc_path_parser_base::parse_document_path(const cdk::string &first, are otherwise treated by tokenizer as reserved, are treated as normal identifiers. */ -void Doc_path_parser_base::parse_docpath_member() +bool Expr_parser_base::parse_docpath_member(Path_prc::Element_prc *prc) { - const Token &t = get_token(); + const Token &t = peek_token(); switch (t.get_type()) { + case Token::MUL: + if (prc) + prc->any_member(); + break; + case Token::ID: case Token::LSTRING: - - m_path.add(Doc_path::MEMBER, t.get_text()); + if (prc) + prc->member(t.get_text()); break; default: if (t.is_reserved_word()) - m_path.add(Doc_path::MEMBER, t.get_text()); - else - throw Error( - (boost::format("Expr parser: Expected token type IDENT or LSTRING in JSON path" - " at token pos %d") % get_token_pos()).str()); + { + if (prc) + prc->member(t.get_text()); + break; + } + + return false; } + + get_token(); // consume the token + return true; } @@ -648,18 +839,20 @@ void Doc_path_parser_base::parse_docpath_member() MUL | INT */ -void Doc_path_parser_base::parse_docpath_array_loc() +void Expr_parser_base::parse_docpath_array_loc(Path_prc::Element_prc *prc) { if (cur_token_type_is(Token::MUL)) { consume_token(Token::MUL); - m_path.add(Doc_path::ARRAY_INDEX_ASTERISK); + if (prc) + prc->any_index(); } else if (cur_token_type_is(Token::LINTEGER)) { const std::string& value = consume_token(Token::LINTEGER); uint32_t v = boost::lexical_cast(value.c_str(), value.size()); - m_path.add(Doc_path::ARRAY_INDEX, v); + if (prc) + prc->index(v); } else { @@ -675,6 +868,70 @@ void Doc_path_parser_base::parse_docpath_array_loc() // ------------------------------------------------------------------------- +bool column_ref_from_path(cdk::Doc_path &path, parser::Column_ref &column) +{ + struct Path_prc + : public cdk::Doc_path::Processor + , public cdk::Doc_path::Processor::Element_prc + { + unsigned m_len; + parser::Column_ref &m_col; + bool m_ret; + + Element_prc* list_el() + { + return this; + } + + void member(const string &name) + { + switch (m_len++) + { + case 0: m_col.set(name); break; + case 1: m_col.set(name, m_col.name()); break; + case 2: + assert(m_col.table()); + m_col.m_table_ref.set(m_col.name(), m_col.table()->name()); + m_col.set_name(name); + break; + default: + // Too many path elements + m_ret = false; + } + } + + void index(uint32_t) + { + m_ret = false; + } + + void any_member() + { + m_ret = false; + } + + void any_index() + { + m_ret = false; + } + + void any_path() + { + m_ret = false; + } + + Path_prc(parser::Column_ref &col) + : m_len(0), m_col(col), m_ret(true) + {} + } + prc(column); + + path.process(prc); + + return prc.m_ret; +} + + /** atomicExpr ::= placeholder @@ -720,25 +977,25 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (type) { - // jsonDOC + // jsonDOC case Token::LCURLY: return parse(DOC, prc); - // array + // array case Token::LSQBRACKET: return parse(ARR, prc); - // groupedExpr + // groupedExpr case Token::LPAREN: - { - consume_token(Token::LPAREN); - Expression *res = parse(FULL,prc); - consume_token(Token::RPAREN); - return res; - } + { + consume_token(Token::LPAREN); + Expression *res = parse(FULL, prc); + consume_token(Token::RPAREN); + return res; + } default: break; } @@ -764,28 +1021,28 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (type) { - // placeholder + // placeholder case Token::COLON: consume_token(Token::COLON); safe_prc(prc)->scalar()->param(consume_token(Token::ID)); return stored.release(); - // castOp + // castOp case Token::CAST: parse_cast(prc->scalar()); return stored.release(); - // nullary "*" + // nullary "*" case Token::MUL: - { - consume_token(Token::MUL); - safe_prc(prc)->scalar()->op("*"); - // NOTE: arguments processor is ignored as there are no arguments - return stored.release(); - } + { + consume_token(Token::MUL); + safe_prc(prc)->scalar()->op("*"); + // NOTE: arguments processor is ignored as there are no arguments + return stored.release(); + } default: break; } @@ -799,36 +1056,36 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (type) { - case Token::PLUS: - case Token::MINUS: - { - const Token &t = get_token(); - type = peek_token().get_type(); - if (Token::LNUM == type || Token::LINTEGER == type) { - // treat as numeric literal with possibly negated value - neg = (Token::MINUS == t.get_type()); - break; - } - // otherwise report as unary operator - argsp = sprc->op(operator_name(t.get_text()).c_str()); - break; - } + case Token::PLUS: + case Token::MINUS: + { + const Token &t = get_token(); + type = peek_token().get_type(); + if (Token::LNUM == type || Token::LINTEGER == type) { + // treat as numeric literal with possibly negated value + neg = (Token::MINUS == t.get_type()); + break; + } + // otherwise report as unary operator + argsp = sprc->op(operator_name(t.get_text()).c_str()); + break; + } - case Token::BANG: + case Token::BANG: get_token(); argsp = sprc->op(operator_name("!").c_str()); break; - case Token::NOT: + case Token::NOT: get_token(); argsp = sprc->op(operator_name("not").c_str()); break; - case Token::NEG: + case Token::NEG: get_token(); argsp = sprc->op(operator_name("~").c_str()); break; - default: - break; // will continue with literal parsing + default: + break; // will continue with literal parsing } // Report the single argument of the unary operator @@ -845,20 +1102,20 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (peek_token().get_type()) { - case Token::LSTRING: - if (m_strings_as_blobs) - sprc->val()->value(cdk::TYPE_BYTES, Format_info(), - cdk::bytes(get_token().get_text())); - else - sprc->val()->str(get_token().get_text()); - return stored.release(); + case Token::LSTRING: + if (m_strings_as_blobs) + sprc->val()->value(cdk::TYPE_BYTES, Format_info(), + cdk::bytes(get_token().get_text())); + else + sprc->val()->str(get_token().get_text()); + return stored.release(); - case Token::T_NULL: - sprc->val()->null(); - get_token(); - return stored.release(); + case Token::T_NULL: + sprc->val()->null(); + get_token(); + return stored.release(); - case Token::LNUM: + case Token::LNUM: try { double val = boost::lexical_cast(get_token().get_text()); sprc->val()->num(neg ? -val : val); @@ -866,7 +1123,7 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) } RETHROW_BOOST_LEXICAL; - case Token::LINTEGER: + case Token::LINTEGER: try { if (neg) { @@ -901,13 +1158,13 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) } RETHROW_BOOST_LEXICAL; - case Token::TRUE_: - case Token::FALSE_: - sprc->val()->yesno(get_token().get_type() == Token::TRUE_); - return stored.release(); + case Token::TRUE_: + case Token::FALSE_: + sprc->val()->yesno(get_token().get_type() == Token::TRUE_); + return stored.release(); - default: - // will continue with functionCall | columnIdent | documentField parsing + default: + // will continue with functionCall | columnIdent | documentField parsing break; } @@ -916,113 +1173,116 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) /* functionCall | columnIdent | documentField - In this case the first token can be either ID, QUOTED_ID or DOLLAR: + It is not possible to tell which of these 3 alternatives we have by + looking at the current token. Either functionCall or columnIdent or + documentField can start with something which looks like a schema-qualified + name: "A" or "A.B". + + For that reason we start with a call to parse_schema_indent() which would + parse such a schema-qualified name and store it as table/schema name of + m_col_ref member. + + After this we try to parse a function call and if it fails we try + columnIndent or documentField, depending on the parsing mode. + */ + + Token::TokenType types[2]; + bool schema_ident = false; - functionCall ::= schemaQualifiedIdent ... - columIdent ::= shcemaQualifiedIdent ... - documentField ::= ID .... | DOLLAR ... + m_col_ref.clear(); - schemaQualifiedIdent ::= ident ... - ident ::= ID | QUOTED_ID + /* + Try to parse schema-qualified identifier, storing the types of the tokens + that have been consumed. If parsing fails, we ignore the error because + in this case we will try a document path below. - ID can start either of the three types of atomic expression, DOLLAR - can only start documentField, QUOTED_ID can start either functinCall - or columnIdent. + Note: it is important that parse_schema_ident() stores correct tokens + in m_col_ref even if it fails in the end. */ + try { + parse_schema_ident(&types); + schema_ident = true; + } + catch (const cdk::Error&) + {} - const Token& t = peek_token(); + /* + If parse_schema_ident() succeeded, and we have the result in + m_col_ref.table(), we see if it is not a beginning of a function call. + If parse_function_call() succeeds then we are done. + */ - if (t.get_type() == Token::ID || - t.get_type() == Token::QUOTED_ID || - t.is_reserved_word()) + if (schema_ident) { - /* - Parse schemaQualifiedIdent - the result will be stored - in m_col_ref.table() - */ - - parse_schema_ident(); assert(m_col_ref.table()); - /* - First check if this is a function call. If yes, the call will - be reported to the processor and there is nothing more to do. - */ - if (parse_function_call(*m_col_ref.table(), sprc)) return stored.release(); + } - /* - Otherwise, if we are in TABLE mode, identifier we parsed so far - should be a beginning of columnIdent. We complete parsing it, report - it to the processor and then we are done. - */ + /* + Otherwise we must have either a document path (in DOCUMENT mode) or + a column identifier, possibly followed by a path (in TABLE mode). + */ - if (Parser_mode::TABLE == m_parser_mode) - { - parse_column_ident1(); - sprc->ref(m_col_ref, m_path.is_empty() ? NULL : &m_path); - return stored.release(); - } + cdk::Doc_path_storage path; + if (Parser_mode::TABLE == m_parser_mode) + { /* - Otherwise we are in DOCUMENT mode. In this case the document field - should not start with a quotted identifier (documentField rule only - allows ID, not QUOTED_ID). - */ + If we are in the TABLE mode, and parse_schema_ident() failed above, then + we do not have a valid column identifier which is an error. + */ - if (Token::QUOTED_ID == type) - unexpected_token(get_token(), "atomic expr"); + if (!schema_ident) + unexpected_token(peek_token(), "when looking for a column identifier"); /* - We re-interpret schemaQualifiedIdent parsed above as a beginning of a - document field expression: + Otherwise we complete parsing the column identifier and report it to + the processor. + */ - - if it is of the form A.B, where A is schema name and B is table name, - then A becomes main document field name and B becomes the first - element in the document path; + parse_column_ident1(&path); + sprc->ref(m_col_ref, path.is_empty() ? NULL : &path); + return stored.release(); + } - - if it is a single identifier A (table name) then it becomes the - main field name. + /* + Here we know that we are in DOCUMENT mode and we are expecting a document + path. If parse_schema_ident() called above consumed some tokens, we check + if they were not quotted identifiers. Such identifiers are allowed when + reffering to tables or columns but are invalid in a document path. + */ - The rest of the document path is parsed within parse_document_path() - method. - */ + if (Token::QUOTED_ID == types[0] || Token::QUOTED_ID == types[1]) + throw_error("invalid document path"); - if (m_col_ref.table()->schema()) - parse_document_path(m_col_ref.table()->schema()->name(), - m_col_ref.table()->name()); - else - parse_document_path(m_col_ref.table()->name()); + /* + Now we treat the identifiers "A.B" parsed by parse_schema_ident() and + stored as table/schema name in m_col_ref (if any), as an initail segment + of a document filed reference and complete parsing the whole document + field. + */ - /* - Note: the parsed document path will be reported to the processor below - (after switch() statement). - */ + if (m_col_ref.table() && m_col_ref.table()->schema()) + { + parse_document_field( + m_col_ref.table()->schema()->name(), + m_col_ref.table()->name(), + &path + ); } - else if (type == Token::DOLLAR) + else if (m_col_ref.table()) { - /* - DOLLAR starts documentField, which is valid only in DOCUMENT mode. - */ - - if (Parser_mode::DOCUMENT != m_parser_mode) - unexpected_token(get_token(), "atomic expr"); - - parse_document_field(); + parse_document_field(m_col_ref.table()->name(), &path); } else { - - /* - If we see any other token, then we throw exception, since it is unexpected - */ - unexpected_token(t,"atomic expr"); - + parse_document_field(&path); } - sprc->ref(m_path); + sprc->ref(path); return stored.release(); } @@ -1481,10 +1741,10 @@ void Order_parser::process(Processor& prc) const It last = m_tokenizer.end(); /* - * note: passing m_toks.end() directly as constructor argument results - * in "incompatible iterators" exception when comparing iterators (at - * least on win, vs2010). problem with passing temporary object? - */ + note: passing m_toks.end() directly as constructor argument results + in "incompatible iterators" exception when comparing iterators (at + least on win, vs2010). problem with passing temporary object? + */ Stored_any store_expr; @@ -1530,10 +1790,10 @@ void Projection_parser::process(Projection_processor& prc) const It last = m_tokenizer.end(); /* - * note: passing m_toks.end() directly as constructor argument results - * in "incompatible iterators" exception when comparing iterators (at - * least on win, vs2010). problem with passing temporary object? - */ + note: passing m_toks.end() directly as constructor argument results + in "incompatible iterators" exception when comparing iterators (at + least on win, vs2010). problem with passing temporary object? + */ Expr_parser_base parser(first, last, m_mode); parser.process_if(prc.expr()); @@ -1573,10 +1833,10 @@ void Projection_parser::process(Document_processor& prc) const It last = m_tokenizer.end(); /* - * note: passing m_toks.end() directly as constructor argument results - * in "incompatible iterators" exception when comparing iterators (at - * least on win, vs2010). problem with passing temporary object? - */ + note: passing m_toks.end() directly as constructor argument results + in "incompatible iterators" exception when comparing iterators (at + least on win, vs2010). problem with passing temporary object? + */ Stored_any store_expr; diff --git a/cdk/parser/expr_parser.h b/cdk/parser/expr_parser.h index 6828ccdc3..d5e655912 100644 --- a/cdk/parser/expr_parser.h +++ b/cdk/parser/expr_parser.h @@ -28,9 +28,6 @@ #include #include "parser.h" -PUSH_BOOST_WARNINGS -#include -POP_BOOST_WARNINGS PUSH_SYS_WARNINGS #include #include @@ -54,42 +51,44 @@ using cdk::Expression; paths within the parser. */ -struct Column_ref : public cdk::api::Column_ref +struct Table_ref : public cdk::api::Table_ref { - - struct Table_ref : public cdk::api::Table_ref + struct : public cdk::api::Schema_ref { - struct : public cdk::api::Schema_ref - { - cdk::string m_name; + cdk::string m_name; - virtual const cdk::string name() const { return m_name; } + virtual const cdk::string name() const { return m_name; } - } m_schema_ref; + } m_schema_ref; - cdk::string m_name; + cdk::string m_name; - virtual const cdk::string name() const { return m_name; } + virtual const cdk::string name() const { return m_name; } - virtual const cdk::api::Schema_ref* schema() const - { return m_schema_ref.m_name.empty() ? NULL : &m_schema_ref; } + virtual const cdk::api::Schema_ref* schema() const + { return m_schema_ref.m_name.empty() ? NULL : &m_schema_ref; } - void set(const cdk::string &name) - { m_name = name; } + void set(const cdk::string &name) + { m_name = name; } - void set(const cdk::string &name, const cdk::string &schema) - { - m_name = name; - m_schema_ref.m_name = schema; - } + void set(const cdk::string &name, const cdk::string &schema) + { + m_name = name; + m_schema_ref.m_name = schema; + } - void clear() - { - m_name.clear(); - m_schema_ref.m_name.clear(); - } + void clear() + { + m_name.clear(); + m_schema_ref.m_name.clear(); + } - } m_table_ref; +}; + + +struct Column_ref : public cdk::api::Column_ref +{ + Table_ref m_table_ref; cdk::string m_col_name; @@ -146,119 +145,10 @@ struct Column_ref : public cdk::api::Column_ref }; -struct Doc_path : public cdk::Doc_path -{ - // Doc_path - - struct Doc_path_data - { - Doc_path_data(Type doc_type) - : m_doc_type(doc_type) - {} - - Doc_path_data(Type doc_type, const cdk::string& name) - : m_doc_type(doc_type) - , m_name(name) - {} - - Doc_path_data(Type doc_type, uint32_t index) - : m_doc_type(doc_type) - , m_index(index) - {} - - Type m_doc_type; - cdk::string m_name; - uint32_t m_index; - }; - - std::vector m_doc_path; - - virtual ~Doc_path() {} - - unsigned length() const - { - size_t cnt = m_doc_path.size(); - assert(cnt <= std::numeric_limits::max()); - return (unsigned)cnt; - } - - Type get_type(unsigned pos) const { return m_doc_path[pos].m_doc_type; } - - const uint32_t* get_index(unsigned pos) const - { - switch (m_doc_path[pos].m_doc_type) - { - case ARRAY_INDEX: - return &m_doc_path[pos].m_index; - default: - return NULL; - } - } - - const cdk::string* get_name(unsigned pos) const - { - switch (m_doc_path[pos].m_doc_type) - { - case MEMBER: - case MEMBER_ASTERISK: - return &m_doc_path[pos].m_name; - default: - return NULL; - } - } - - - void add(Type type, const cdk::string &name) - { - m_doc_path.push_back(Doc_path_data(type, name)); - } - - void add(Type type, uint32_t index) - { - m_doc_path.push_back(Doc_path_data(type, index)); - } - - void add(Type type) - { - m_doc_path.push_back(Doc_path_data(type)); - } - - - Doc_path& operator=(const cdk::Doc_path &other) - { - for (unsigned pos=0; pos < other.length(); ++pos) - { - switch (other.get_type(pos)) - { - case MEMBER: - add(MEMBER, *other.get_name(pos)); - break; - case ARRAY_INDEX: - add(ARRAY_INDEX, *other.get_index(pos)); - break; - default: - add(other.get_type(pos)); - break; - } - } - return *this; - } - - void clear() - { - m_doc_path.clear(); - } - - bool is_empty() const - { - return m_doc_path.empty(); - } -}; - - /* Trivial Format_info class that is used to report opaque blob values. */ + struct Format_info : public cdk::Format_info { bool for_type(cdk::Type_info ti) const { return cdk::TYPE_BYTES == ti; } @@ -272,171 +162,6 @@ struct Format_info : public cdk::Format_info // ------------------------------------------------------------------------------ -/* - Class that implements token navigation and usage methods - */ - -class Token_op_base -{ - -protected: - - typedef std::set TokSet; - - It *m_first; - It m_last; - - const std::string& consume_token(Token::TokenType type) - { - if (!cur_token_type_is(type)) - unexpected_token(peek_token(), (boost::format("while looking for token %s") - % Token::get_name(type)).str().c_str()); - return get_token().get_text(); - } - - const Token& peek_token() - { - if (!tokens_available()) - throw Error("unexpected end of string"); - return **m_first; - } - - bool cur_token_type_is(Token::TokenType type) - { - return tokens_available() && peek_token().get_type() == type; - } - - bool is_token_type_within_set(TokSet types) - { - return tokens_available() - && types.find(peek_token().get_type()) != types.end(); - } - - unsigned get_token_pos() const - { - // TODO - return 0; - } - - It& cur_pos() const - { - return *m_first; - } - - const It& end_pos() const - { - return m_last; - } - - bool tokens_available() const - { - return cur_pos() != end_pos(); - } - - const Token& get_token() - { - if (!tokens_available()) - throw Error("unexpected end of string"); - const Token &t = peek_token(); - ++(*m_first); - return t; - } - - std::string operator_name(const std::string &name) - { - return Tokenizer::map.operator_names.at(name); - } - - void unexpected_token(const Token&, const char *ctx); - -public: - Token_op_base(It &first, const It &last) - : m_first(&first), m_last(last) - {} -}; - -/* - Class implementing Document Path parsing methods. - */ - - -class Doc_path_parser_base - : public Token_op_base - -{ -protected: - - void parse_document_path(bool clear = true); - void parse_document_path(const cdk::string&); - void parse_document_path(const cdk::string&, const cdk::string&); - - void parse_docpath_member(); - void parse_docpath_array_loc(); - -public: - - Doc_path_parser_base(It &first, const It &last) - : Token_op_base(first, last) - {} - - Doc_path m_path; - - /* - Used to parse documentPath only strings, not as part of an expression. - */ - void parse_document_field(); - -}; - -/* - This class parses Document path using Doc_path_parser_base methods and - act as a cdk::Doc_path object - - Used to parse documentPath only fields, not expressions. - */ - - -class Doc_field_parser - : public cdk::Doc_path -{ - Tokenizer m_tokenizer; - cdk::scoped_ptr m_parser; - - -public: - - Doc_field_parser(const cdk::string &doc_path) - : m_tokenizer(doc_path) - { - m_tokenizer.get_tokens(); - - It begin = m_tokenizer.begin(); - const It end = m_tokenizer.end(); - m_parser.reset(new Doc_path_parser_base(begin, end)); - - m_parser->parse_document_field(); - } - - unsigned length() const - { - return m_parser->m_path.length(); - } - - Type get_type(unsigned pos) const - { - return m_parser->m_path.get_type(pos); - } - const cdk::string* get_name(unsigned pos) const - { - return m_parser->m_path.get_name(pos); - } - - const uint32_t* get_index(unsigned pos) const - { - return m_parser->m_path.get_index(pos); - } - -}; /* Main parser class containing parsing logic. An instance acts @@ -456,14 +181,14 @@ struct Parser_mode class Expr_parser_base - : Doc_path_parser_base - , public Expr_parser + : public Expr_parser { public: typedef Expression::Processor Processor; typedef Expression::Scalar::Processor Scalar_prc; + typedef cdk::api::Doc_path::Processor Path_prc; static Expression::Processor *get_base_prc(Processor *prc) { return prc; } @@ -485,8 +210,7 @@ class Expr_parser_base Expr_parser_base(It &first, const It &last, Parser_mode::value parser_mode, bool strings_as_blobs = false) - : Doc_path_parser_base(first, last) - , Expr_parser(first, last) + : Expr_parser(first, last) , m_parser_mode(parser_mode) , m_strings_as_blobs(strings_as_blobs) { @@ -497,7 +221,6 @@ class Expr_parser_base bool do_parse(It &first, const It &last, Processor *prc); - enum Start { FULL, ATOMIC, MUL, ADD, SHIFT, BIT, COMP, ILRI, AND, OR, CAST_TYPE, COLID_DOCPATH, DOC, ARR}; @@ -535,12 +258,19 @@ class Expr_parser_base void parse_argslist(Expression::List::Processor*, bool strings_as_blobs = false); - void parse_schema_ident(); - void parse_column_ident(); - void parse_column_ident1(); + void parse_schema_ident(Token::TokenType (*types)[2] = NULL); + void parse_column_ident(Path_prc*); + void parse_column_ident1(Path_prc*); const std::string &get_ident(); - void parse_document_field(bool prefix = false); + void parse_document_field(Path_prc*, bool prefix = false); + void parse_document_field(const cdk::string&, Path_prc*); + void parse_document_field(const cdk::string&, const cdk::string&, Path_prc*); + + bool parse_document_path(Path_prc*, bool require_dot=false); + bool parse_document_path1(Path_prc*); + bool parse_docpath_member(Path_prc::Element_prc*); + void parse_docpath_array_loc(Path_prc::Element_prc*); void parse_cast(Scalar_prc*); cdk::string parse_cast_type(); @@ -552,23 +282,15 @@ class Expr_parser_base void parse_doc(Processor::Doc_prc*); void parse_arr(Processor::List_prc*); - - private: Column_ref m_col_ref; - - // Access to the underlying sequence of tokens. - -// It *m_first; -// It m_last; - - friend class Expression_parser; friend class Order_parser; friend class Projection_parser; friend class Table_field_parser; + friend class Doc_field_parser; }; @@ -706,48 +428,79 @@ class Projection_parser class Table_field_parser : public cdk::api::Column_ref + , public cdk::Doc_path { - Tokenizer m_tokenizer; - cdk::scoped_ptr m_table_field; + parser::Column_ref m_col; + cdk::Doc_path_storage m_path; public: Table_field_parser(const cdk::string &table_field) - : m_tokenizer(table_field) { - m_tokenizer.get_tokens(); - - It begin = m_tokenizer.begin(); - const It end = m_tokenizer.end(); - - m_table_field.reset(new Expr_parser_base(begin, - end, - Parser_mode::TABLE)); + Tokenizer toks(table_field); + toks.get_tokens(); - m_table_field->parse_column_ident(); + It begin = toks.begin(); + const It end = toks.end(); + Expr_parser_base parser(begin, end, Parser_mode::TABLE); + parser.parse_column_ident(&m_path); + m_col = parser.m_col_ref; } const cdk::string name() const { - return m_table_field->m_col_ref.name(); + return m_col.name(); } const cdk::api::Table_ref *table() const { - return m_table_field->m_col_ref.table(); + return m_col.table(); } - const Doc_path *path() const + bool has_path() const { - return m_table_field->m_path.length() == 0 ? - NULL : - &(m_table_field->m_path); + return !m_path.is_empty(); + } + + void process(Processor &prc) const + { + m_path.process(prc); } }; +/* + This class acts as cdk::Doc_path object taking path data from a string + containing document field specification (documentField grammar) +*/ + +class Doc_field_parser + : public cdk::Doc_path +{ + Tokenizer m_tokenizer; + cdk::scoped_ptr m_parser; + It m_it; + +public: + + Doc_field_parser(const cdk::string &doc_path) + : m_tokenizer(doc_path) + { + m_tokenizer.get_tokens(); + + m_it = m_tokenizer.begin(); + const It end = m_tokenizer.end(); + m_parser.reset(new Expr_parser_base(m_it, end, Parser_mode::DOCUMENT)); + } + + void process(Processor &prc) const + { + const_cast(m_parser.get())->parse_document_field(&prc); + } +}; + // ------------------------------------------------------------------------------ /* @@ -907,7 +660,7 @@ struct Stored_scalar // Storage for the values parser::Column_ref m_col_ref; - parser::Doc_path m_doc_path; + cdk::Doc_path_storage m_doc_path; std::string m_op_name; cdk::string m_str; @@ -1075,13 +828,13 @@ struct Stored_scalar m_type = COL_REF; m_col_ref = col; if (path) - m_doc_path = *path; + path->process(m_doc_path); } void ref(const Doc_path &path) { m_type = PATH; - m_doc_path = path; + path.process(m_doc_path); } void param(const string &name) diff --git a/cdk/parser/parser.h b/cdk/parser/parser.h index 297b34825..a84088884 100644 --- a/cdk/parser/parser.h +++ b/cdk/parser/parser.h @@ -28,6 +28,11 @@ #include #include "tokenizer.h" +PUSH_BOOST_WARNINGS +#include +POP_BOOST_WARNINGS + + #ifdef _WIN32 /* @@ -53,6 +58,104 @@ namespace parser { typedef Tokenizer::iterator It; using cdk::throw_error; + +/* + Class that implements token navigation and usage methods +*/ + +class Token_op_base +{ + +protected: + + typedef std::set TokSet; + + It *m_first; + It m_last; + + const std::string& consume_token(Token::TokenType type) + { + if (!cur_token_type_is(type)) + unexpected_token(peek_token(), (boost::format("while looking for token %s") + % Token::get_name(type)).str().c_str()); + return get_token().get_text(); + } + + const Token& peek_token() + { + if (!tokens_available()) + throw Error("unexpected end of string"); + return **m_first; + } + + bool cur_token_type_is(Token::TokenType type) + { + return tokens_available() && peek_token().get_type() == type; + } + + bool is_token_type_within_set(TokSet types) + { + return tokens_available() + && types.find(peek_token().get_type()) != types.end(); + } + + unsigned get_token_pos() const + { + // TODO + return 0; + } + + It& cur_pos() + { + assert(m_first); + return *m_first; + } + + const It& cur_pos() const + { + return const_cast(this)->cur_pos(); + } + + const It& end_pos() const + { + return m_last; + } + + bool tokens_available() const + { + return m_first && cur_pos() != end_pos(); + } + + const Token& get_token() + { + if (!tokens_available()) + throw Error("unexpected end of string"); + const Token &t = peek_token(); + ++(*m_first); + return t; + } + + std::string operator_name(const std::string &name) + { + return Tokenizer::map.operator_names.at(name); + } + + void unexpected_token(const Token&, const char *ctx); + +public: + + Token_op_base() + : m_first(NULL) + {} + + void set_tokens(It &first, const It &last) + { + m_first = &first; + m_last = last; + } +}; + + /* Base class for parsers which parse tokens and present result as an expression over processor PRC. @@ -94,12 +197,15 @@ using cdk::throw_error; template class Expr_parser : public cdk::api::Expr_base + , protected Token_op_base { public: Expr_parser(It &first, const It &last) - : m_first(first), m_last(last), m_consumed(false) - {} + : m_consumed(false) + { + set_tokens(first, last); + } void process(PRC &prc) const { @@ -131,7 +237,7 @@ class Expr_parser if (m_consumed) THROW("Expr_praser: second pass"); - if (!do_parse(m_first, m_last, &prc)) + if (!do_parse(cur_pos(), end_pos(), &prc)) return false; m_consumed = true; return true; @@ -153,7 +259,7 @@ class Expr_parser { if (m_consumed) return; - do_consume(m_first, m_last); + do_consume(cur_pos(), end_pos()); m_consumed = true; } @@ -171,10 +277,6 @@ class Expr_parser return true; } -private: - - It &m_first; - const It m_last; protected: diff --git a/cdk/parser/tests/parser-t.cc b/cdk/parser/tests/parser-t.cc index e3a9cab11..1b3b3d631 100644 --- a/cdk/parser/tests/parser-t.cc +++ b/cdk/parser/tests/parser-t.cc @@ -373,6 +373,62 @@ class Expr_printer }; + struct Path_printer + : public cdk::api::Doc_path::Processor + , cdk::api::Doc_path_processor + { + ostream &m_out; + bool m_first; + + Path_printer(ostream &out) + : m_out(out), m_first(true) + {} + + void list_begin() + { + m_first = true; + } + + Element_prc* list_el() + { + return this; + } + + void member(const string &name) + { + if (!m_first) + m_out << "."; + m_first = false; + m_out << name; + } + + void any_member() + { + if (!m_first) + m_out << "."; + m_first = false; + m_out << "*"; + } + + void index(index_t pos) + { + m_first = false; + m_out << "[" << pos << "]"; + } + + void any_index() + { + m_first = false; + m_out << "[*]"; + } + + void any_path() + { + m_first = false; + m_out << "**"; + } + }; + struct Scalar_printer : public Scalar_prc , public Scalar_prc::Args_prc @@ -383,10 +439,12 @@ class Expr_printer cdk::string m_op_name; Val_printer m_val_printer; + Path_printer m_path_printer; Scalar_printer(Expr_printer &parent) : m_parent(parent), m_pb(parent.m_pb) , m_val_printer(parent.m_pb) + , m_path_printer(parent.m_pb.m_out) {} // Table_ref @@ -444,32 +502,8 @@ class Expr_printer virtual void ref(const cdk::Doc_path &path) { - ostream &out = m_pb.out_ind(); - for (unsigned i=0; i < path.length(); ++i) - { - if (i > 0) - out << "."; - switch(path.get_type(i)) - { - case Doc_path::MEMBER: - out << *path.get_name(i); - break; - case Doc_path::MEMBER_ASTERISK: - out << "*"; - break; - case Doc_path::ARRAY_INDEX: - out << "[" << *path.get_index(i) << "]"; - break; - case Doc_path::ARRAY_INDEX_ASTERISK: - out << "[*]"; - break; - case Doc_path::DOUBLE_ASTERISK: - out << "**"; - break; - } - } - - out << endl; + path.process(m_path_printer); + m_pb.m_out << endl; } virtual void ref(const cdk::api::Column_ref &col, const cdk::Doc_path *path) @@ -486,20 +520,8 @@ class Expr_printer if (path) { - out <<"->$"; - for (unsigned i= 0; - i < path->length(); - ++i) - { - switch (path->get_type(i)) - { - case Doc_path::MEMBER: out <<"." << *path->get_name(i); break; - case Doc_path::MEMBER_ASTERISK: out << ".*"; break; - case Doc_path::ARRAY_INDEX: out << "["<< *path->get_index(i) <<"]"; break; - case Doc_path::ARRAY_INDEX_ASTERISK: out << "[*]"; break; - case Doc_path::DOUBLE_ASTERISK: out << "**"; break; - } - } + out <<"->$."; + path->process(m_path_printer); } out < cast(14.01 as decimal(3,2))"}, { parser::Parser_mode::TABLE , L"CHARSET(CHAR(X'65'))"}, { parser::Parser_mode::TABLE , L"CHARSET(CHAR(0x65))"}, - { parser::Parser_mode::TABLE , L"CHARSET(CHAR(X'65' USING utf8))"}, +// { parser::Parser_mode::TABLE , L"CHARSET(CHAR(X'65' USING utf8))"}, // { parser::Parser_mode::TABLE , L"TRIM(BOTH 'x' FROM 'xxxbarxxx')"}, // { parser::Parser_mode::TABLE , L"TRIM(LEADING 'x' FROM 'xxxbarxxx')"}, // { parser::Parser_mode::TABLE , L"TRIM(TRAILING 'xyz' FROM 'barxxyz')"}, @@ -600,7 +622,6 @@ TEST(Parser, expr) { Expr_printer printer(cout, 0); - for (unsigned i=0; i < sizeof(exprs)/sizeof(Expr_Test); i++) { cout < +#include PUSH_BOOST_WARNINGS #include diff --git a/cdk/protocol/mysqlx/tests/expr.h b/cdk/protocol/mysqlx/tests/expr.h index fc503aa50..c6c610492 100644 --- a/cdk/protocol/mysqlx/tests/expr.h +++ b/cdk/protocol/mysqlx/tests/expr.h @@ -50,17 +50,11 @@ namespace expr { using std::min; - //using namespace ::std; -//using namespace cdk::foundation; using namespace cdk::protocol::mysqlx; namespace api { using namespace cdk::protocol::mysqlx::api; -} // papi - -//typedef cdk::byte byte; -//typedef cdk::string string; -//typedef foundation::Number_codec Number_codec; +} // api class Scalar_base : public api::Scalar @@ -137,6 +131,7 @@ class Expr_class : public B { return new E(*(E*)this); } }; + class Param_String : public Expr_class { std::string m_val; diff --git a/cdk/protocol/mysqlx/tests/test.h b/cdk/protocol/mysqlx/tests/test.h index 9845303cf..fe53a0339 100644 --- a/cdk/protocol/mysqlx/tests/test.h +++ b/cdk/protocol/mysqlx/tests/test.h @@ -71,8 +71,11 @@ using namespace ::std; using namespace cdk::foundation; using namespace cdk::protocol::mysqlx; -typedef cdk::byte byte; -typedef cdk::string string; +// Disambiguate these types + +using cdk::protocol::mysqlx::charset_id_t; +using cdk::protocol::mysqlx::row_count_t; + typedef foundation::Number_codec Number_codec; /* @@ -220,6 +223,13 @@ class Stmt_handler void execute_ok() { cout <<"Statement executed OK" <= 0) @@ -228,6 +238,7 @@ class Stmt_handler cout <<"Rows affected: " < Date: Fri, 4 Nov 2016 09:26:31 +0100 Subject: [PATCH 05/79] Adjustments after CDK refactoring. Mainly changes related to a different document path processor interface. --- devapi/collection_crud.cc | 8 +++----- devapi/table_crud.cc | 8 +++++--- xapi/row.cc | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/devapi/collection_crud.cc b/devapi/collection_crud.cc index 2196de450..e1fa39b46 100644 --- a/devapi/collection_crud.cc +++ b/devapi/collection_crud.cc @@ -34,8 +34,6 @@ #include "impl.h" using namespace mysqlx; -using cdk::string; -using namespace parser; // -------------------------------------------------------------------- @@ -149,7 +147,7 @@ class Op_collection_add return true; } - void process(Expression::Processor &ep) const override; + void process(cdk::Expression::Processor &ep) const override; // JSON::Processor @@ -297,7 +295,7 @@ class Insert_id into account. */ -void Op_collection_add::process(Expression::Processor &ep) const +void Op_collection_add::process(cdk::Expression::Processor &ep) const { assert(m_pos > 0); // this method should be called after calling next() @@ -578,7 +576,7 @@ class Op_collection_modify void process(Update_spec::Processor &prc) const override { - Doc_field_parser doc_field((mysqlx::string)m_update_it->m_field); + parser::Doc_field_parser doc_field((mysqlx::string)m_update_it->m_field); switch (m_update_it->m_op) { diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index 951b04257..bbce15fe6 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -34,8 +34,7 @@ #include "impl.h" using namespace mysqlx; -using cdk::string; -using namespace parser; +using parser::Parser_mode; // -------------------------------------------------------------------- @@ -327,7 +326,10 @@ class Op_table_update prc.column(*this); Value_expr val_prc(m_set_it->second, parser::Parser_mode::TABLE); - val_prc.process_if(prc.set(m_table_field->path())); + + val_prc.process_if( + prc.set(m_table_field->has_path() ? m_table_field.get() : NULL) + ); } diff --git a/xapi/row.cc b/xapi/row.cc index 4790fd5da..95d4f7fdf 100644 --- a/xapi/row.cc +++ b/xapi/row.cc @@ -352,10 +352,11 @@ void Update_spec::process(Processor &prc) const { const Update_item *it = get_cur_item(); parser::Table_field_parser field(it->m_field); + cdk::Doc_path *path = field.has_path() ? &field : NULL; prc.column(field); if (it->is_expr()) { - cdk::Update_processor::Expr_prc *eprc = prc.set(field.path()); + cdk::Update_processor::Expr_prc *eprc = prc.set(path); // Cannot use process_if() method because of specialized process() methods if (eprc) it->process(*eprc); @@ -363,7 +364,7 @@ void Update_spec::process(Processor &prc) const else { cdk::Expr_processor::Value_prc *vprc = - cdk::safe_prc(prc)->set(field.path())->scalar()->val(); + cdk::safe_prc(prc)->set(path)->scalar()->val(); // Cannot use process_if() method because of specialized process() methods if (vprc) it->process_val(*vprc); From 23b54ad459804856fe724ef46d91237fa1f66843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Thu, 27 Oct 2016 09:27:30 +0100 Subject: [PATCH 06/79] Fix Building with CLANG on Linux --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56baa2cc0..7699e1bee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,7 +93,8 @@ SET(CMAKE_CXX_EXTENSIONS no) # if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" - AND NOT DEFINED ENV{MACOSX_DEPLOYMENT_TARGET}) + AND NOT DEFINED ENV{MACOSX_DEPLOYMENT_TARGET} + AND NOT CMAKE_SYSTEM_NAME MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif() From 903f519fddb3a7ce83ee762f7e3967083e6ef8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Mon, 31 Oct 2016 11:13:20 +0000 Subject: [PATCH 07/79] MYCPP-56 CRUD find/select groupBy and having implementation. --- devapi/collection_crud.cc | 4 +- devapi/impl.h | 117 +++++++++++++++++++++++++++++- devapi/table_crud.cc | 4 +- devapi/tests/crud-t.cc | 111 +++++++++++++++++++++++++++- include/devapi/collection_crud.h | 112 +++++++++++++++++++++++++++-- include/devapi/crud.h | 11 ++- include/devapi/table_crud.h | 120 ++++++++++++++++++++++++++++++- 7 files changed, 462 insertions(+), 17 deletions(-) diff --git a/devapi/collection_crud.cc b/devapi/collection_crud.cc index e1fa39b46..16a451976 100644 --- a/devapi/collection_crud.cc +++ b/devapi/collection_crud.cc @@ -439,8 +439,8 @@ class Op_collection_find get_where(), get_doc_proj(), get_order_by(), - nullptr, // group_by - nullptr, // having + get_group_by(), // group_by + get_having(), // having get_limit(), get_params() )); diff --git a/devapi/impl.h b/devapi/impl.h index 9ee217bea..56270993a 100644 --- a/devapi/impl.h +++ b/devapi/impl.h @@ -792,9 +792,120 @@ class Op_sort }; +/* + This template adds handling of having specification on top of + Op_sort. + + It implements the `set_having` method required by implementations of + CRUD operations that support having expression. The Expression is stored + internally and transformed to the form expected by CDK: + method `get_having` return pointer to cdk::Expression (as expected + for table/collection having definition) or NULL if no having specification + is given. + + Template parameters are the implementation interface class being + implemented and parser mode for parsing expressions in order + specifications. +*/ + +template +class Op_having + : public Op_sort + , public cdk::Expression +{ + cdk::string m_having; + + void set_having(const mysqlx::string &having) + { + m_having = having; + } + +protected: + + template + Op_having(T &x) : Op_sort(x) + {} + +public: + + cdk::Expression* get_having() + { + return m_having.empty() ? nullptr : this; + } + +private: + + // cdk::Expression processor + + void process(cdk::Expression:: Processor& prc) const + { + parser::Expression_parser expr_parser(PM, m_having); + expr_parser.process(prc); + } +}; + + +/* + This template adds handling of groupBy specification on top of + Op_having. + + It implements the `add_group_by` method required by implementations of + CRUD operations that support groupBy expressions. The Expressions are stored + internally and transformed to the form expected by CDK: + method `get_group_by` return pointer to cdk::Expr_list (as expected + for table/collection groupBy definition) or NULL if no groupBy specification + is given. + + Template parameters are the implementation interface class being + implemented and parser mode for parsing expressions in order + specifications. +*/ + +template +class Op_group_by + : public Op_having + , public cdk::Expr_list +{ + std::vector m_group_by; + + void add_group_by(const mysqlx::string &group_by) + { + m_group_by.push_back(group_by); + } + +protected: + + template + Op_group_by(T &x) : Op_having(x) + {} + +public: + + cdk::Expr_list* get_group_by() + { + return m_group_by.empty() ? nullptr : this; + } + +private: + + void process(cdk::Expr_list::Processor& prc) const + { + prc.list_begin(); + + for (cdk::string el : m_group_by) + { + parser::Expression_parser expr_parser(PM, el); + expr_parser.process_if(prc.list_el()); + } + + prc.list_end(); + } +}; + + /* This template adds handling of projection specifications on top - of Op_order. + of Op_group_by. It implements the `add_proj` method required by implementations of CRUD operations that support projection. Projection specifications @@ -811,7 +922,7 @@ class Op_sort template class Op_projection - : public Op_sort + : public Op_group_by , public cdk::Projection , public cdk::Expression::Document { @@ -822,7 +933,7 @@ class Op_projection protected: template - Op_projection(X &init) : Op_sort(init) + Op_projection(X &init) : Op_group_by(init) {} public: diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index bbce15fe6..2e6964174 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -216,8 +216,8 @@ class Op_table_select get_where(), get_tbl_proj(), get_order_by(), - nullptr, - nullptr, + get_group_by(), + get_having(), get_limit(), get_params() )); diff --git a/devapi/tests/crud-t.cc b/devapi/tests/crud-t.cc index b6d03e528..f42f01f71 100644 --- a/devapi/tests/crud-t.cc +++ b/devapi/tests/crud-t.cc @@ -25,6 +25,7 @@ #include #include #include +#include using std::cout; using std::endl; @@ -1838,4 +1839,112 @@ TEST_F(Crud, doc_id) EXPECT_THROW(coll.add("{\"_id\": 127 }").execute(), Error); EXPECT_THROW(coll.add("{\"_id\": 12.7 }").execute(), Error); -} \ No newline at end of file +} + +TEST_F(Crud, group_by_having) +{ + + SKIP_IF_NO_XPLUGIN; + + cout << "Preparing table..." << endl; + + XSession sess(this); + + sess.dropCollection("test", "coll"); + + Collection coll = sess.createSchema("test", true) + .createCollection("coll", true); + + Table tbl = sess.createSchema("test", true).getCollectionAsTable("coll", true); + + coll.remove().execute(); + + std::vector names = {"Foo", "Baz", "Bar"}; + + int i=0; + + for (auto name : names) + { + std::stringstream json; + json <<"{ \"_id\":\""<< i << "\", \"user\":\"" << name << "\", \"age\":" << 20+i << "}"; + coll.add(json.str()).execute(); + ++i; + } + + // Function to check order of operation + auto check_order = [&names] (DocResult &coll_res, RowResult &tbl_res) + { + DbDoc coll_row = coll_res.fetchOne(); + Row tbl_row = tbl_res.fetchOne(); + + for (auto name = names.begin(); + coll_row && tbl_row && name != names.end(); + coll_row = coll_res.fetchOne(), + tbl_row = tbl_res.fetchOne(), + ++name) + { + EXPECT_EQ(*name, static_cast(coll_row["user"])); + EXPECT_EQ(*name, static_cast(tbl_row[0])); + } + + EXPECT_TRUE(coll_row.isNull()); + EXPECT_TRUE(tbl_row.isNull()); + }; + + auto coll_res = coll.find().fields("user AS user", "age as age").execute(); + auto tbl_res = tbl.select("doc->$.user as user","doc->$.age as age").execute(); + + check_order(coll_res, tbl_res); + + cout << "Check with groupBy" << endl; + std::sort(names.begin(), names.end()); + + std::vector fields = {"user"}; + coll_res = coll.find() + .fields("user AS user", "age as age") + .groupBy(fields, "age") + .execute(); + + cout << "and on table" << endl; + tbl_res = tbl.select("doc->$.user as user", "doc->$.age as age") + .groupBy(fields,"age") + .execute(); + + + check_order(coll_res, tbl_res); + + + cout << "Having usage will remove last element of previous groupBy." << endl; + names.pop_back(); + + coll_res = coll.find() + .fields("user AS user", "age as age") + .groupBy(fields,"age") + .having(L"age > 20") + .execute(); + + //and on table + tbl_res = tbl.select("doc->$.user as user", "doc->$.age as age") + .groupBy(fields, "age") + .having(L"age > 20") + .execute(); + + check_order(coll_res, tbl_res); + + cout << "Same test but passing std::string to groupBy" << endl; + + coll_res = coll.find() + .fields("user AS user", "age as age") + .groupBy(fields, std::string("age")) + .having(std::string("age > 20")) + .execute(); + + cout << "and on table" << endl; + tbl_res = tbl.select("doc->$.user as user", "doc->$.age as age") + .groupBy(fields, std::string("age")) + .having(std::string("age > 20")) + .execute(); + + check_order(coll_res, tbl_res); + +} diff --git a/include/devapi/collection_crud.h b/include/devapi/collection_crud.h index ce9f85d24..3aba7f1da 100644 --- a/include/devapi/collection_crud.h +++ b/include/devapi/collection_crud.h @@ -501,6 +501,104 @@ namespace internal { } // internal +// ---------------------------------------------------------------------- + +namespace internal { + + /** + Class defining .having() clause. + */ + + class CollectionHaving + : public internal::CollectionSort + { + + typedef internal::Having_impl Impl; + typedef internal::CollectionSort CollectionSort; + + Impl* get_impl() + { + check_if_valid(); + return static_cast(m_impl.get()); + } + + public: + + /** + Specify having filter in the operation. + + Arguments are a string defining filter to be used. + */ + + CollectionSort& having(const string& having_spec) + { + get_impl()->set_having(having_spec); + return *this; + } + }; +} + +// ---------------------------------------------------------------------- + +namespace internal { + + /** + Class defining .groupBy() clause. + */ + + class CollectionGroupBy + : public internal::CollectionHaving + { + + typedef internal::Group_by_impl Impl; + typedef internal::CollectionHaving CollectionHaving; + + Impl* get_impl() + { + check_if_valid(); + return static_cast(m_impl.get()); + } + + + public: + + /** + Specify groupBy fields in the operation. + + Arguments are a one or more strings defining fields to group. + */ + + template ::value>::type* = nullptr + > + CollectionHaving& groupBy(GroupBy group_by_spec) + { + get_impl()->add_group_by(group_by_spec); + return *this; + } + + template ::value>::type* = nullptr + > + CollectionHaving& groupBy(GroupBy group_by_spec) + { + for (auto el : group_by_spec) + { + get_impl()->add_group_by(el); + } + return *this; + } + + template + CollectionHaving& groupBy(GroupBy group_by_spec, + T...rest) + { + groupBy(group_by_spec); + return groupBy(rest...); + } + }; +} + // ---------------------------------------------------------------------- @@ -623,7 +721,7 @@ namespace internal { DLL_WARNINGS_PUSH class PUBLIC_API CollectionFind - : public internal::CollectionSort + : public internal::CollectionGroupBy { DLL_WARNINGS_POP @@ -631,7 +729,7 @@ DLL_WARNINGS_POP protected: typedef internal::Proj_impl Impl; - typedef internal::CollectionSort CollectionSort; + typedef internal::CollectionGroupBy CollectionGroupBy; Impl* get_impl() { @@ -675,7 +773,7 @@ DIAGNOSTIC_POP evaluating the expression an the result will be returned by the operation. */ - CollectionSort& fields(internal::ExprValue proj) + CollectionGroupBy& fields(internal::ExprValue proj) { if (!proj.isExpression()) throw_error("Invalid projection"); @@ -684,13 +782,13 @@ DIAGNOSTIC_POP } - CollectionSort& fields(const string& ord) + CollectionGroupBy& fields(const string& ord) { get_impl()->add_proj(ord); return *this; } - CollectionSort& fields(const char* ord) + CollectionGroupBy& fields(const char* ord) { get_impl()->add_proj(ord); return *this; @@ -709,7 +807,7 @@ DIAGNOSTIC_POP */ template - CollectionSort& fields(const Ord& ord) + CollectionGroupBy& fields(const Ord& ord) { for (auto el : ord) { @@ -739,7 +837,7 @@ DIAGNOSTIC_POP !std::is_same::value >::type > - CollectionSort& fields(const Proj& ord, const Type&...rest) + CollectionGroupBy& fields(const Proj& ord, const Type&...rest) { fields(ord); return fields(rest...); diff --git a/include/devapi/crud.h b/include/devapi/crud.h index 6959bbaf1..c5acbcf6d 100644 --- a/include/devapi/crud.h +++ b/include/devapi/crud.h @@ -242,8 +242,17 @@ struct Sort_impl : public Limit_impl virtual void add_sort(const string&) = 0; }; +struct Having_impl : public Sort_impl +{ + virtual void set_having(const string&) = 0; +}; + +struct Group_by_impl : public Having_impl +{ + virtual void add_group_by(const string&) = 0; +}; -struct Proj_impl : public Sort_impl +struct Proj_impl : public Group_by_impl { virtual void add_proj(const string&) = 0; virtual void set_proj(const string&) = 0; diff --git a/include/devapi/table_crud.h b/include/devapi/table_crud.h index 6809f40b2..4640e303a 100644 --- a/include/devapi/table_crud.h +++ b/include/devapi/table_crud.h @@ -459,6 +459,121 @@ namespace internal { } // internal +// --------------------------------------------------------------------------- + +namespace internal { + + /** + Class defining table CRUD .having() clause. + */ + + class TableHaving + : public TableSort + { + protected: + + typedef internal::Having_impl Impl; + + using TableSort::check_if_valid; + using TableSort::m_impl; + + typedef TableSort TableSort; + + Impl* get_impl() + { + check_if_valid(); + return static_cast(m_impl.get()); + } + + public: + + /** + Specify having filter in the operation. + + Arguments are a string defining filter to be used. + */ + + TableSort& having(const string& having_spec) + { + get_impl()->set_having(having_spec); + return *this; + } + + }; + +} // internal + + +// ---------------------------------------------------------------------- + +namespace internal { + + /** + Class defining .groupBy() clause. + */ + + class TableGroupBy + : public internal::TableHaving + { + + protected: + + typedef internal::Group_by_impl Impl; + + using TableHaving::check_if_valid; + using TableHaving::m_impl; + + typedef internal::TableHaving TableHaving; + + Impl* get_impl() + { + check_if_valid(); + return static_cast(m_impl.get()); + } + + + public: + + /** + Specify groupBy fields in the operation. + + Arguments are a one or more strings defining fields to group. + */ + + template ::value>::type* = nullptr + > + TableHaving& groupBy(GroupBy group_by_spec) + { + get_impl()->add_group_by(group_by_spec); + return *this; + } + + template ::value>::type* = nullptr + > + TableHaving& groupBy(GroupBy group_by_spec) + { + for (auto el : group_by_spec) + { + get_impl()->add_group_by(el); + } + return *this; + } + + template + TableHaving& groupBy(GroupBy group_by_spec, + T...rest) + { + groupBy(group_by_spec); + return groupBy(rest...); + } + + + }; +} + + // --------------------------------------------------------------------------- namespace internal { @@ -497,13 +612,16 @@ namespace internal { DLL_WARNINGS_PUSH class PUBLIC_API TableSelect - : public internal::TableSort + : public internal::TableGroupBy { DLL_WARNINGS_POP typedef internal::TableSelect_impl Impl; + using TableGroupBy::check_if_valid; + using TableGroupBy::m_impl; + Impl* get_impl() { check_if_valid(); From 480edf8dc8fb2162b67063f10078ea35419f75df Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Tue, 15 Nov 2016 23:10:17 +1100 Subject: [PATCH 08/79] Added support for HAVING and GROUP by to XAPI --- include/mysql_xapi.h | 90 ++++++++++++++++++++++++++ xapi/crud.cc | 107 ++++++++++++++++++++++++------ xapi/crud_internal.h | 53 ++++++++------- xapi/mysqlx.cc | 19 ++++++ xapi/tests/xapi_crud-t.cc | 132 +++++++++++++++++++++++++++++++++++++- 5 files changed, 352 insertions(+), 49 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 5ea023377..896464def 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -154,6 +154,7 @@ typedef object_id* MYSQLX_GUID; #define MYSQLX_ERROR_MISSING_KEY_NAME_MSG "Missing key name" #define MYSQLX_ERROR_OUTPUT_BUFFER_NULL "The output buffer cannot be NULL" #define MYSQLX_ERROR_OUTPUT_BUFFER_ZERO "The output buffer cannot have zero length" +#define MYSQLX_ERROR_OP_NOT_SUPPORTED "The operation is not supported by the function" /* Opaque structures*/ @@ -1099,6 +1100,26 @@ PUBLIC_API int mysqlx_set_find_projection(mysqlx_stmt_t *stmt, const char *proj) #define mysqlx_set_find_criteria mysqlx_set_where +/* +A macro defining a function for setting HAVING for FIND operation. + +@see mysqlx_set_having() +@ingroup xapi_tbl +*/ + +#define mysqlx_set_find_having mysqlx_set_having + + +/** +A macro defining a function for setting GROUP BY for FIND operation. + +@see mysqlx_set_group_by() +@ingroup xapi_tbl +*/ + +#define mysqlx_set_find_group_by mysqlx_set_group_by + + /** A macro defining a function for setting LIMIT for DELETE operation. @@ -1555,10 +1576,20 @@ mysqlx_table_select_new(mysqlx_table_t *table); @see mysqlx_set_having() @ingroup xapi_tbl +*/ #define mysqlx_set_select_having mysqlx_set_having + + +/** +A macro defining a function for setting GROUP BY for SELECT operation. + +@see mysqlx_set_group_by() +@ingroup xapi_tbl */ +#define mysqlx_set_select_group_by mysqlx_set_group_by + /** A macro defining a function for setting LIMIT for SELECT operation. @@ -1913,6 +1944,65 @@ PUBLIC_API int mysqlx_set_items(mysqlx_stmt_t *stmt, ...); PUBLIC_API int mysqlx_set_where(mysqlx_stmt_t *stmt, const char *where_expr); +/** + Specify filter conditions for a group of rows/documents or aggregates + such as GROUP BY + + Restrict the statement to rows/documents that satisfy + given selection criteria: + - for select/find operations limit the returned rows/documents, + + Statements supported by this function: SELECT, FIND. + Calling it for UPDATE, MODIFY, DELETE, REMOVE, INSERT or ADD + will result in an error + + @param stmt statement handle + @param having_expr character string containing Boolean expression + like in SQL HAVING clause + + @return `RESULT_OK` - on success; `RESULT_ERR` - on error + + @note this function can be be used directly, but for the convenience + the code can use the specialized macros for a specific operation. + For SELECT operation the user code should use + `mysqlx_set_select_having()` macros that map the + corresponding `mysqlx_set_having()` function. + This way the unsupported operations will not be used. + + @ingroup xapi_stmt +*/ + +PUBLIC_API int mysqlx_set_having(mysqlx_stmt_t *stmt, const char *having_expr); + + +/** + Specify one or more columns/values to group the result in conjunction + with the aggregate functions. + + Statements supported by this function: SELECT, FIND. + Calling it for UPDATE, MODIFY, DELETE, REMOVE, INSERT or ADD + will result in an error + + @param stmt statement handle + @param ... variable parameters list consisting of character strings + containing expressions specifying grouping: + expr_1, ..., expr_n, PARAM_END + (PARAM_END marks the end of projection's item list) + + @return `RESULT_OK` - on success; `RESULT_ERR` - on error + + @note this function can be be used directly, but for the convenience + the code can use the specialized macros for a specific operation. + For SELECT operation the user code should use + `mysqlx_set_select_group_by()` macros that map the + corresponding `mysqlx_set_group_by()` function. + This way the unsupported operations will not be used. + + @ingroup xapi_stmt +*/ + +PUBLIC_API int mysqlx_set_group_by(mysqlx_stmt_t *stmt, ...); + /** Specify ordering for a statement. diff --git a/xapi/crud.cc b/xapi/crud.cc index 7d0f14d82..ea78a66ef 100644 --- a/xapi/crud.cc +++ b/xapi/crud.cc @@ -60,6 +60,7 @@ void mysqlx_stmt_t::init_data_model() m_parser_mode = parser::Parser_mode::TABLE; break; } + m_group_by_list.set_parser_mode(m_parser_mode); } void mysqlx_stmt_t::init_crud() @@ -477,8 +478,8 @@ mysqlx_result_t *mysqlx_stmt_t::exec() m_where.get(), m_proj_list.get(), m_order_by.get(), - NULL, // Group by - NULL, // Having + m_group_by_list.get_list(), + m_having.get(), m_limit.get(), m_param_source.count() ? &m_param_source : NULL); break; @@ -517,8 +518,8 @@ mysqlx_result_t *mysqlx_stmt_t::exec() m_where.get(), m_proj_list.get(), m_order_by.get(), - NULL, // Group by - NULL, // Having + m_group_by_list.get_list(), + m_having.get(), m_limit.get(), m_param_source.count() ? &m_param_source : NULL); break; @@ -582,30 +583,22 @@ mysqlx_result_t *mysqlx_stmt_t::exec() } /* - Set WHERE for CRUD operation - PARAMETERS: - where_expr - character string containing WHERE clause, - which will be parsed as required - - RETURN: - RESULT_OK - on success - RESULT_ERROR - on error - - NOTE: each call to this function replaces previously set WHERE + Set member to a CDK expression which results from parsing given string val */ -int mysqlx_stmt_t::set_where(const char *where_expr) +int mysqlx_stmt_t::set_expression(cdk::scoped_ptr &member, + const char *val) { - if (!where_expr || !where_expr[0]) + if (!val || !val[0]) return RESULT_OK; int res = RESULT_OK; try { - m_where.reset(new Expression_parser(m_parser_mode, where_expr)); - if (!m_where.get()) + member.reset(new Expression_parser(m_parser_mode, val)); + if (!member.get()) res = RESULT_ERROR; } - catch(...) + catch (...) { res = RESULT_ERROR; // TODO: Get exception details @@ -613,6 +606,45 @@ int mysqlx_stmt_t::set_where(const char *where_expr) return res; } + +/* + Set WHERE for statement operation + PARAMETERS: + where_expr - character string containing WHERE clause, + which will be parsed as required + + RETURN: + RESULT_OK - on success + RESULT_ERROR - on error + + NOTE: each call to this function replaces previously set WHERE +*/ +int mysqlx_stmt_t::set_where(const char *where_expr) +{ + if (m_op_type == OP_ADD || m_op_type == OP_INSERT) + throw Mysqlx_exception(MYSQLX_ERROR_OP_NOT_SUPPORTED); + return set_expression(m_where, where_expr); +} + +/* + Set HAVING for statement operation + PARAMETERS: + having_expr - character string containing HAVING clause, + which will be parsed as required + + RETURN: + RESULT_OK - on success + RESULT_ERROR - on error + + NOTE: each call to this function replaces previously set HAVING +*/ +int mysqlx_stmt_t::set_having(const char *having_expr) +{ + if (m_op_type != OP_SELECT && m_op_type != OP_FIND) + throw Mysqlx_exception(MYSQLX_ERROR_OP_NOT_SUPPORTED); + return set_expression(m_having, having_expr); +} + /* Set LIMIT for CRUD operation PARAMETERS: @@ -627,6 +659,9 @@ int mysqlx_stmt_t::set_where(const char *where_expr) */ int mysqlx_stmt_t::set_limit(row_count_t row_count, row_count_t offset) { + if (m_op_type == OP_ADD || m_op_type == OP_INSERT) + throw Mysqlx_exception(MYSQLX_ERROR_OP_NOT_SUPPORTED); + int res = RESULT_OK; try { @@ -728,7 +763,7 @@ int mysqlx_stmt_t::add_document(const char *json_doc) int res = RESULT_OK; if (m_op_type != OP_ADD) { - m_error.set("Wrong operation type. Only ADD is supported.", 0); + set_diagnostic("Wrong operation type. Only ADD is supported.", 0); return RESULT_ERROR; } @@ -763,4 +798,34 @@ int mysqlx_stmt_t::add_multiple_documents(va_list args) rc = add_document(json_doc); } return rc; -} \ No newline at end of file +} + +int mysqlx_stmt_t::add_group_by(va_list args) +{ + m_group_by_list.clear(); + if (m_op_type != OP_SELECT && m_op_type != OP_FIND) + { + set_diagnostic(MYSQLX_ERROR_OP_NOT_SUPPORTED, 0); + return RESULT_ERROR; + } + + const char *group_by; + while ((group_by = va_arg(args, char*)) != NULL) + { + m_group_by_list.add_group_by(group_by); + } + return RESULT_OK; +} + +void Group_by_list::process(cdk::Expr_list::Processor& prc) const +{ + prc.list_begin(); + + for (group_by_list_type::const_iterator it = m_group_by_list.begin(); + it != m_group_by_list.end(); ++it) + { + parser::Expression_parser expr_parser(m_parser_mode, *it); + expr_parser.process_if(prc.list_el()); + } + prc.list_end(); +} diff --git a/xapi/crud_internal.h b/xapi/crud_internal.h index 8c9f842a4..524436c53 100644 --- a/xapi/crud_internal.h +++ b/xapi/crud_internal.h @@ -34,17 +34,35 @@ class Order_by; class Param_list; class Row_source; +class Group_by_list : public cdk::Expr_list +{ + typedef std::vector group_by_list_type; + group_by_list_type m_group_by_list; + parser::Parser_mode::value m_parser_mode; + +public: + + Group_by_list() {} + + void set_parser_mode(parser::Parser_mode::value mode) { m_parser_mode = mode; } + void add_group_by(const char *expr) { m_group_by_list.push_back(cdk::string(expr)); } + void clear() { m_group_by_list.clear(); } + void process(cdk::Expr_list::Processor& prc) const; + cdk::Expr_list *get_list() { return m_group_by_list.size() ? this : NULL; } +}; + typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag { private: mysqlx_session_t &m_session; - cdk::scoped_ptr m_result; // TODO: multiple results + cdk::scoped_ptr m_result; Db_obj_ref m_db_obj_ref; cdk::protocol::mysqlx::Data_model m_data_model; parser::Parser_mode::value m_parser_mode; mysqlx_op_t m_op_type; cdk::Reply m_reply; cdk::scoped_ptr m_where; + cdk::scoped_ptr m_having; cdk::scoped_ptr m_limit; cdk::scoped_ptr m_order_by; cdk::scoped_ptr m_proj_list; @@ -56,6 +74,9 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag Update_spec m_update_spec; Modify_spec m_modify_spec; cdk::string m_query; + Group_by_list m_group_by_list; + + int set_expression(cdk::scoped_ptr &member, const char *val); public: mysqlx_stmt_struct(mysqlx_session_t *session, const char *query, uint32_t length) : @@ -132,33 +153,9 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag mysqlx_op_t op_type() { return m_op_type; } mysqlx_session_t &get_session() { return m_session; } - /* - Set WHERE for CRUD operation - PARAMETERS: - where_expr - character string containing WHERE clause, - which will be parsed as required - - RETURN: - RESULT_OK - on success - RESULT_ERR - on error - - NOTE: each call to this function replaces previously set WHERE - */ int set_where(const char *where_expr); - - /* - Set LIMIT for CRUD operation - PARAMETERS: - row_count - the number of result rows to return - offset - the number of rows to skip before starting counting - - RETURN: - RESULT_OK - on success - RESULT_ERR - on error - - NOTE: each call to this function replaces previously set LIMIT - */ int set_limit(row_count_t row_count, row_count_t offset); + int set_having(const char *having_expr); int add_order_by(va_list args); int add_row(bool get_columns, va_list args); @@ -168,6 +165,7 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag int add_projections(va_list args); int add_table_update_values(va_list args); int add_coll_modify_values(va_list args, mysqlx_modify_op op); + int add_group_by(va_list args); // Clear the list of ORDER BY items void clear_order_by(); @@ -175,4 +173,5 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag // Return the session validity state bool session_valid(); -} mysqlx_stmt_t; + friend Group_by_list; +} mysqlx_stmt_t; \ No newline at end of file diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index c037a84cb..acb0497f0 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -395,6 +395,25 @@ int STDCALL mysqlx_set_where(mysqlx_stmt_t *stmt, const char *where_expr) SAFE_EXCEPTION_END(stmt, RESULT_ERROR) } +int STDCALL mysqlx_set_having(mysqlx_stmt_t *stmt, const char *having_expr) +{ + SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR) + return stmt->set_having(having_expr); + SAFE_EXCEPTION_END(stmt, RESULT_ERROR) +} + +int STDCALL mysqlx_set_group_by(mysqlx_stmt_t *stmt, ...) +{ + SAFE_EXCEPTION_BEGIN(stmt, RESULT_ERROR) + va_list args; + int res = RESULT_OK; + va_start(args, stmt); + res = stmt->add_group_by(args); + va_end(args); + return res; + SAFE_EXCEPTION_END(stmt, RESULT_ERROR) +} + int STDCALL mysqlx_set_limit_and_offset(mysqlx_stmt_t *stmt, uint64_t row_count, uint64_t offset) diff --git a/xapi/tests/xapi_crud-t.cc b/xapi/tests/xapi_crud-t.cc index 1311875cd..6618ec56e 100644 --- a/xapi/tests/xapi_crud-t.cc +++ b/xapi/tests/xapi_crud-t.cc @@ -43,6 +43,136 @@ }; +TEST_F(xapi, test_having_group_by) +{ + SKIP_IF_NO_XPLUGIN + + mysqlx_result_t *res; + mysqlx_schema_t *schema; + mysqlx_table_t *table; + mysqlx_stmt_t *stmt; + mysqlx_row_t *row; + mysqlx_collection_t *collection; + const char *errmsg = NULL; + int row_num = 1; + const char *json_string = NULL; + size_t json_len = 0; + + AUTHENTICATE(); + + mysqlx_schema_drop(get_session(), "cc_crud_test"); + EXPECT_EQ(RESULT_OK, mysqlx_schema_create(get_session(), "cc_crud_test")); + + res = mysqlx_sql(get_session(), "CREATE TABLE cc_crud_test.group_test" \ + "(id int primary key," \ + "user_name varchar(32))", + MYSQLX_NULL_TERMINATED); + EXPECT_TRUE(res != NULL); + EXPECT_TRUE((schema = mysqlx_get_schema(get_session(), "cc_crud_test", 1)) != NULL); + EXPECT_TRUE((table = mysqlx_get_table(schema, "group_test", 1)) != NULL); + + stmt = mysqlx_table_insert_new(table); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_columns(stmt, "id", "user_name", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(1), PARAM_STRING("John"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(2), PARAM_STRING("Mary"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(3), PARAM_STRING("Alan"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(4), PARAM_STRING("Anna"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(5), PARAM_STRING("Peter"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(6), PARAM_STRING("Anna"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(7), PARAM_STRING("Peter"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_UINT(8), PARAM_STRING("Anna"), PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + stmt = mysqlx_table_select_new(table); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_items(stmt, "COUNT(*) AS cnt", "user_name", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_group_by(stmt, "user_name", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_having(stmt, "COUNT(*) > 1")); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_order_by(stmt, "user_name", SORT_ORDER_ASC, PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + /* + This is the expected result + +-----+-----------+ + | cnt | user_name | + +-----+-----------+ + | 3 | Anna | + | 2 | Peter | + +-----+-----------+ + */ + + while ((row = mysqlx_row_fetch_one(res)) != NULL) + { + int64_t cnt = 0; + char buf[256]; + size_t buflen = sizeof(buf); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 0, &cnt)); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, buf, &buflen)); + + printf("\n Row # %d: ", row_num); + printf("[ %d ] [ %s ]", (int)cnt, buf); + + switch (row_num) + { + case 1: + EXPECT_EQ(cnt, 3); + EXPECT_EQ(buflen, 5); + EXPECT_STREQ(buf, "Anna"); + break; + case 2: + EXPECT_EQ(cnt, 2); + EXPECT_EQ(buflen, 6); + EXPECT_STREQ(buf, "Peter"); + break; + default: + FAIL(); + } + ++row_num; + } + + EXPECT_EQ(RESULT_OK, mysqlx_collection_create(schema, "coll_group")); + EXPECT_TRUE((collection = mysqlx_get_collection(schema, "coll_group", 1)) != NULL); + stmt = mysqlx_collection_add_new(collection); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 1, \"user_name\" : \"John\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 2, \"user_name\" : \"Mary\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 3, \"user_name\" : \"Alan\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 4, \"user_name\" : \"Anna\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 5, \"user_name\" : \"Peter\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 6, \"user_name\" : \"Anna\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 7, \"user_name\" : \"Peter\"}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_add_document(stmt, "{\"num\": 8, \"user_name\" : \"Anna\"}")); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + stmt = mysqlx_collection_find_new(collection); + EXPECT_EQ(RESULT_OK, mysqlx_set_find_projection(stmt, "{cnt: COUNT(*), user_name: user_name}")); + EXPECT_EQ(RESULT_OK, mysqlx_set_find_group_by(stmt, "user_name", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_find_having(stmt, "cnt > 1")); + EXPECT_EQ(RESULT_OK, mysqlx_set_find_order_by(stmt, "user_name", SORT_ORDER_ASC, PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + row_num = 1; + /* + This is the expected result: + {"cnt": 3, "user_name": "Anna"} + {"cnt": 2, "user_name": "Peter"} + */ + while ((json_string = mysqlx_json_fetch_one(res, &json_len)) != NULL) + { + if (json_string) + printf("\n[json: %s]", json_string); + switch (row_num) + { + case 1: + EXPECT_STREQ("{\"cnt\": 3, \"user_name\": \"Anna\"}", json_string); + break; + case 2: + EXPECT_STREQ("{\"cnt\": 2, \"user_name\": \"Peter\"}", json_string); + break; + default:FAIL(); + } + ++row_num; + } +} + TEST_F(xapi, schema) { SKIP_IF_NO_XPLUGIN @@ -2251,7 +2381,7 @@ TEST_F(xapi_bugs, myc_352_stored_proc_err) { SKIP_IF_NO_XPLUGIN - mysqlx_result_t *res; + mysqlx_result_t *res; const char *schema_name = "cc_crud_test"; const char *errmsg = NULL; From a94c1ecda1d1ad8c88aa7aff2a9fc1c6203da0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 15 Nov 2016 16:28:09 +0000 Subject: [PATCH 09/79] Remove test not needed, since the behaviour is the expected. --- devapi/tests/ddl-t.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/devapi/tests/ddl-t.cc b/devapi/tests/ddl-t.cc index 7f48e256d..d1909a77b 100644 --- a/devapi/tests/ddl-t.cc +++ b/devapi/tests/ddl-t.cc @@ -109,10 +109,6 @@ TEST_F(Ddl, create_drop) EXPECT_THROW(schema.getTable("tb1", true), mysqlx::Error); EXPECT_THROW(schema.getTable("tb2", true), mysqlx::Error); - // xplugin is not reporting view because view uses deleted table. - // checking this with xplugin team - EXPECT_THROW(schema.getTable("view1", true), mysqlx::Error); - } //Collection tests From c154341a41864a348209a0310a5b1e0cf09d1649 Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Wed, 16 Nov 2016 22:05:48 +1100 Subject: [PATCH 10/79] Added new return flag RESULT_MORE_DATA --- include/mysql_xapi.h | 12 +++++++++++- xapi/mysqlx.cc | 6 +++++- xapi/tests/xapi_crud-t.cc | 30 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 896464def..36d652597 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -103,6 +103,14 @@ typedef object_id* MYSQLX_GUID; #define RESULT_OK 0 +/** + Return value flag indicating that the last reading operation + did not finish reading to the end and there is still more data + to be fetched by functions suchs as mysqlx_get_bytes() +*/ + +#define RESULT_MORE_DATA 8 + /** Return value flag indicating end of data items (documents or rows) in a query result. This is used by functions which iterate @@ -2253,7 +2261,9 @@ mysqlx_get_auto_increment_value(mysqlx_result_t *res); buffer [OUT] @return `RESULT_OK` - on success; `RESULT_NULL` when the value in the - requested column is NULL; `RESULT_ERR` - on error + requested column is NULL; `RESULT_MORE_DATA` if not all data was + fetched after the last call to the function; + `RESULT_ERR` - on error @ingroup xapi_res */ diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index acb0497f0..2090d2ada 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -828,6 +828,7 @@ int STDCALL mysqlx_get_bytes(mysqlx_row_t* row, uint32_t col, uint64_t offset, CHECK_COLUMN_RANGE(col, row) cdk::bytes b = row->get_col_data(col); + int rc = RESULT_OK; if (b.size() == 0) return RESULT_NULL; @@ -841,8 +842,11 @@ int STDCALL mysqlx_get_bytes(mysqlx_row_t* row, uint32_t col, uint64_t offset, if (b.size() - offset < *buf_len) *buf_len = b.size() - (size_t)offset; + else + rc = RESULT_MORE_DATA; + memcpy(buf, b.begin() + offset, *buf_len); - return RESULT_OK; + return rc; SAFE_EXCEPTION_END(row, RESULT_ERROR) } diff --git a/xapi/tests/xapi_crud-t.cc b/xapi/tests/xapi_crud-t.cc index 6618ec56e..e98d67bda 100644 --- a/xapi/tests/xapi_crud-t.cc +++ b/xapi/tests/xapi_crud-t.cc @@ -2410,3 +2410,33 @@ TEST_F(xapi_bugs, myc_352_stored_proc_err) EXPECT_TRUE((errmsg = mysqlx_error_message(res)) != NULL); printf("\nExpected error: %s\n", errmsg); } + + +TEST_F(xapi, more_data_test) +{ + SKIP_IF_NO_XPLUGIN + + mysqlx_result_t *res; + mysqlx_row_t *row; + char data_buf[1200]; + size_t buf_len = 1200; + + // A piece of data 3K + const char *query = "SELECT BINARY REPEAT('z', 3000) as longdata"; + + AUTHENTICATE(); + + res = mysqlx_sql(get_session(), query, strlen(query)); + + while ((row = mysqlx_row_fetch_one(res)) != NULL) + { + EXPECT_EQ(RESULT_MORE_DATA, mysqlx_get_bytes(row, 0, 0, data_buf, &buf_len)); + EXPECT_EQ(1200, buf_len); + + EXPECT_EQ(RESULT_MORE_DATA, mysqlx_get_bytes(row, 0, 1200, data_buf, &buf_len)); + EXPECT_EQ(1200, buf_len); + + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 2400, data_buf, &buf_len)); + EXPECT_EQ(601, buf_len); + } +} From a4a57f1d971213a2ff8c642d5f9ae4d1a94ec6e8 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 9 Nov 2016 11:33:52 +0100 Subject: [PATCH 11/79] cmake: gcov support. --- CMakeLists.txt | 10 ++++- cdk/CMakeLists.txt | 5 +++ cdk/cmake/gcov.cmake | 66 ++++++++++++++++++++++++++++++ cdk/cmake/testing.cmake | 15 +------ cdk/core/CMakeLists.txt | 2 + cdk/foundation/CMakeLists.txt | 2 +- cdk/mysqlx/CMakeLists.txt | 3 +- cdk/parser/CMakeLists.txt | 2 + cdk/protocol/mysqlx/CMakeLists.txt | 1 + devapi/CMakeLists.txt | 2 + xapi/CMakeLists.txt | 2 +- 11 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 cdk/cmake/gcov.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7699e1bee..5f9f0d537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,8 @@ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) -CMAKE_POLICY(VERSION 2.8.11) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) +CMAKE_POLICY(VERSION 2.8.12) cmake_policy(SET CMP0022 NEW) # @@ -150,6 +150,12 @@ if(WIN32 AND NOT UNREACHABLE_CODE_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4297") endif() +# +# Gcov support (Linux only) +# + +include(gcov) +#message("WITH_COVERAGE: ${WITH_COVERAGE}") #message("flags: ${CMAKE_C_FLAGS}") #message("c++ flags: ${CMAKE_CXX_FLAGS}") diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index f6a77d91e..bae6930f5 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -83,6 +83,11 @@ if(WITH_PIC) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() +# +# Gcov support (Linux only). +# + +include(gcov) # # Disable 64-bit warnings until we have dealt with them diff --git a/cdk/cmake/gcov.cmake b/cdk/cmake/gcov.cmake new file mode 100644 index 000000000..ed11a2281 --- /dev/null +++ b/cdk/cmake/gcov.cmake @@ -0,0 +1,66 @@ +# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. +# +# This code is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FLOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 2 of the License. +# +# This program 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 General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +if (NOT DEFINED WITH_COVERAGE) + # use ENABLE_GCOV here to make it compatible with server conventions + option(WITH_COVERAGE "Enable gcov (debug, Linux builds only)" ${ENABLE_GCOV}) +endif() + +if (WITH_COVERAGE AND NOT BUILD_STATIC) + message(WARNING "To get good coverage results use static build of the" + " connector (BUILD_STATIC)") +endif() + + +macro(ADD_COVERAGE target) + + if(CMAKE_COMPILER_IS_GNUCXX AND WITH_COVERAGE) + + message(STATUS "Enabling gcc coverage support for target: ${target}") + + # Note: we use set_property(... APPEND ...) to not override other sttings + # for the target. + + set_property(TARGET ${target} APPEND + PROPERTY COMPILE_DEFINITIONS_DEBUG WITH_COVERAGE + ) + + # Note: COMPILE_OPTIONS property does not have per build configuration + # variant. Generator expression is used instead. + + set_property(TARGET ${target} APPEND + PROPERTY COMPILE_OPTIONS + $<$:-O0;-fprofile-arcs;-ftest-coverage> + ) + + set_property(TARGET ${target} APPEND + PROPERTY LINK_FLAGS_DEBUG -fprofile-arcs -ftest-coverage + ) + + set_property(TARGET ${target} APPEND + PROPERTY INTERFACE_LINK_LIBRARIES gcov + ) + + endif() + +endmacro(ADD_COVERAGE) diff --git a/cdk/cmake/testing.cmake b/cdk/cmake/testing.cmake index 1dc7f47ad..70b2150ea 100644 --- a/cdk/cmake/testing.cmake +++ b/cdk/cmake/testing.cmake @@ -54,6 +54,7 @@ IF(NOT DEFINED WITH_COVERAGE) OPTION(WITH_COVERAGE "Enable coverage support for gcc" OFF) ENDIF() + # # Note: On Windows the runtime type must match the one used by gtest. # @@ -72,19 +73,6 @@ IF(WITH_TESTS) ENDIF() -MACRO(ADD_GCOV target) -IF (WITH_TESTS) - IF(WITH_COVERAGE) - MESSAGE(STATUS "Enabling coverage support for gcc") - - SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage ") - SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "-fprofile-arcs -ftest-coverage") - - ENDIF(WITH_COVERAGE) -ENDIF (WITH_TESTS) - -ENDMACRO(ADD_GCOV) - MACRO(SETUP_TESTING) IF(WITH_TESTS) INCLUDE(CTest) @@ -273,7 +261,6 @@ IF(WITH_TESTS) ) TARGET_LINK_LIBRARIES(${target_run_unit_tests} gtest) - ADD_GCOV(${target_run_unit_tests}) #ADD_BOOST(${target_run_unit_tests}) # diff --git a/cdk/core/CMakeLists.txt b/cdk/core/CMakeLists.txt index 27f3d80eb..6286b1cac 100644 --- a/cdk/core/CMakeLists.txt +++ b/cdk/core/CMakeLists.txt @@ -48,6 +48,8 @@ add_library_ex(cdk STATIC session.cc codec.cc ${cdk_libs} ) +add_coverage(cdk) + #MESSAGE("cdk depends on: ${target_mysqlx} ${target_parser}") EXPORT(TARGETS cdk diff --git a/cdk/foundation/CMakeLists.txt b/cdk/foundation/CMakeLists.txt index 9af01e325..e53d3ae91 100644 --- a/cdk/foundation/CMakeLists.txt +++ b/cdk/foundation/CMakeLists.txt @@ -64,7 +64,7 @@ SET(target_foundation ${cdk_target_prefix}foundation CACHE INTERNAL "CDK foundation target") ADD_LIBRARY(${target_foundation} OBJECT ${sources}) -#ADD_BOOST(${target_foundation}) +ADD_COVERAGE(${target_foundation}) IF(WITH_SSL STREQUAL "bundled") lib_interface_link_libraries(${target_foundation} yassl) diff --git a/cdk/mysqlx/CMakeLists.txt b/cdk/mysqlx/CMakeLists.txt index 1647143e9..b05dcbe68 100644 --- a/cdk/mysqlx/CMakeLists.txt +++ b/cdk/mysqlx/CMakeLists.txt @@ -21,8 +21,6 @@ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -cmake_minimum_required(VERSION 2.8) - SET(target_mysqlx ${cdk_target_prefix}mysqlx CACHE INTERNAL "CDK mysqlx target") # @@ -36,6 +34,7 @@ if(WIN32) endif() ADD_LIBRARY(${target_mysqlx} OBJECT session.cc result.cc auth_mysql41.cc) +ADD_COVERAGE(${target_mysqlx}) #TARGET_LINK_LIBRARIES(${target_mysqlx} ${target_proto_mysqlx}) diff --git a/cdk/parser/CMakeLists.txt b/cdk/parser/CMakeLists.txt index 902122345..1bcf1ce8d 100644 --- a/cdk/parser/CMakeLists.txt +++ b/cdk/parser/CMakeLists.txt @@ -32,3 +32,5 @@ add_library(${target_parser} OBJECT json_parser.cc expr_parser.cc uri_parser.cc) + +add_coverage(${target_parser}) diff --git a/cdk/protocol/mysqlx/CMakeLists.txt b/cdk/protocol/mysqlx/CMakeLists.txt index bdbf8cb09..4125f2140 100644 --- a/cdk/protocol/mysqlx/CMakeLists.txt +++ b/cdk/protocol/mysqlx/CMakeLists.txt @@ -96,6 +96,7 @@ SET(target_proto_mysqlx ${cdk_target_prefix}proto_mysqlx ADD_LIBRARY(${target_proto_mysqlx} OBJECT protocol.cc session.cc rset.cc stmt.cc crud.cc ${PB_SRCS}) +ADD_COVERAGE(${target_proto_mysqlx}) source_group(protobuf FILES ${PB_SRCS}) diff --git a/devapi/CMakeLists.txt b/devapi/CMakeLists.txt index 9740d7d4c..d8e295ea5 100644 --- a/devapi/CMakeLists.txt +++ b/devapi/CMakeLists.txt @@ -45,6 +45,8 @@ ADD_LIBRARY(devapi OBJECT table_crud.cc ) +ADD_COVERAGE(devapi) + lib_interface_link_libraries(devapi cdk) if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/xapi/CMakeLists.txt b/xapi/CMakeLists.txt index 855307a7c..9c1f21660 100644 --- a/xapi/CMakeLists.txt +++ b/xapi/CMakeLists.txt @@ -48,7 +48,7 @@ SET(_libmysqlx_cc_src ) ADD_LIBRARY(xapi OBJECT ${_libmysqlx_cc_src}) - +ADD_COVERAGE(xapi) ADD_SUBDIRECTORY(tests) From 5feeddba6508318b8f26cffd7e256587e87a6fcf Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 17 Nov 2016 19:40:02 +0100 Subject: [PATCH 12/79] Avoid C++11 warning in XAPI code. --- xapi/crud_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi/crud_internal.h b/xapi/crud_internal.h index 524436c53..171e66890 100644 --- a/xapi/crud_internal.h +++ b/xapi/crud_internal.h @@ -173,5 +173,5 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag // Return the session validity state bool session_valid(); - friend Group_by_list; + friend class Group_by_list; } mysqlx_stmt_t; \ No newline at end of file From 490c4409ca720ca48a2f26489b106ed9ac0d3522 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 17 Nov 2016 19:40:57 +0100 Subject: [PATCH 13/79] Disabled warnings in PB code triggered by deprecations in OSX 10.12 --- cdk/include/mysql/cdk/foundation/common.h | 5 +++-- cdk/protobuf/CMakeLists.txt | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cdk/include/mysql/cdk/foundation/common.h b/cdk/include/mysql/cdk/foundation/common.h index d7d6441d9..5bbf006ae 100644 --- a/cdk/include/mysql/cdk/foundation/common.h +++ b/cdk/include/mysql/cdk/foundation/common.h @@ -155,8 +155,9 @@ #else #define PUSH_PB_WARNINGS DIAGNOSTIC_PUSH \ - DISABLE_WARNING(-Wshadow) \ - DISABLE_WARNING(-Wunused-parameter) + DISABLE_WARNING(-Wshadow) \ + DISABLE_WARNING(-Wunused-parameter) \ + DISABLE_WARNING(-Wdeprecated-declarations) \ #endif diff --git a/cdk/protobuf/CMakeLists.txt b/cdk/protobuf/CMakeLists.txt index d4cdb7aa3..c17592ae6 100644 --- a/cdk/protobuf/CMakeLists.txt +++ b/cdk/protobuf/CMakeLists.txt @@ -100,6 +100,16 @@ IF(UNIX) list(APPEND warnings_list "-Wno-return-type") list(APPEND warnings_list "-Wno-unused-function") + if(APPLE) + + # Our version of protobuf uses many constructs (mainly atomic ops) + # which were depracated in OSX 10.12. + # TODO: Upgrade bundled protobuf + + list(APPEND warnings_list -Wdeprecated-declarations) + + endif() + IF(CMAKE_COMPILER_IS_GNUCXX) list(APPEND warnings_list "-Wno-unused-local-typedefs") list(APPEND warnings_list "-Wno-maybe-uninitialized") From 61737d2d5815488837362ffa0e30ea218e07f14b Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 17 Nov 2016 20:02:32 +0100 Subject: [PATCH 14/79] Fix CDK cmake files after coverge support refactoring. --- cdk/CMakeLists.txt | 2 +- cdk/parser/tests/CMakeLists.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index bae6930f5..82230e5d3 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -365,6 +365,6 @@ ENDIF() IF(cdk_stand_alone) ADD_EXECUTABLE(try try.cc) TARGET_LINK_LIBRARIES(try cdk) - ADD_GCOV(try) + #ADD_COVERAGE(try) ENDIF() diff --git a/cdk/parser/tests/CMakeLists.txt b/cdk/parser/tests/CMakeLists.txt index 6732d6b37..96d57ee89 100644 --- a/cdk/parser/tests/CMakeLists.txt +++ b/cdk/parser/tests/CMakeLists.txt @@ -48,8 +48,6 @@ if(MSVC) target_compile_options(expr_test PRIVATE /W3) endif() -ADD_GCOV(expr_test) - # # Add unit test that runs expr_test using runtests.py script # From 499c29f23fd338b2408e0684e55aee29653f11b5 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 9 Nov 2016 11:33:52 +0100 Subject: [PATCH 15/79] cmake: gcov support. --- CMakeLists.txt | 10 ++++- cdk/CMakeLists.txt | 5 +++ cdk/cmake/gcov.cmake | 66 ++++++++++++++++++++++++++++++ cdk/cmake/testing.cmake | 15 +------ cdk/core/CMakeLists.txt | 2 + cdk/foundation/CMakeLists.txt | 2 +- cdk/mysqlx/CMakeLists.txt | 3 +- cdk/parser/CMakeLists.txt | 2 + cdk/protocol/mysqlx/CMakeLists.txt | 1 + devapi/CMakeLists.txt | 2 + xapi/CMakeLists.txt | 2 +- 11 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 cdk/cmake/gcov.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7699e1bee..5f9f0d537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,8 @@ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) -CMAKE_POLICY(VERSION 2.8.11) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) +CMAKE_POLICY(VERSION 2.8.12) cmake_policy(SET CMP0022 NEW) # @@ -150,6 +150,12 @@ if(WIN32 AND NOT UNREACHABLE_CODE_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4297") endif() +# +# Gcov support (Linux only) +# + +include(gcov) +#message("WITH_COVERAGE: ${WITH_COVERAGE}") #message("flags: ${CMAKE_C_FLAGS}") #message("c++ flags: ${CMAKE_CXX_FLAGS}") diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index f6a77d91e..bae6930f5 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -83,6 +83,11 @@ if(WITH_PIC) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() +# +# Gcov support (Linux only). +# + +include(gcov) # # Disable 64-bit warnings until we have dealt with them diff --git a/cdk/cmake/gcov.cmake b/cdk/cmake/gcov.cmake new file mode 100644 index 000000000..ed11a2281 --- /dev/null +++ b/cdk/cmake/gcov.cmake @@ -0,0 +1,66 @@ +# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. +# +# This code is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FLOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 2 of the License. +# +# This program 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 General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +if (NOT DEFINED WITH_COVERAGE) + # use ENABLE_GCOV here to make it compatible with server conventions + option(WITH_COVERAGE "Enable gcov (debug, Linux builds only)" ${ENABLE_GCOV}) +endif() + +if (WITH_COVERAGE AND NOT BUILD_STATIC) + message(WARNING "To get good coverage results use static build of the" + " connector (BUILD_STATIC)") +endif() + + +macro(ADD_COVERAGE target) + + if(CMAKE_COMPILER_IS_GNUCXX AND WITH_COVERAGE) + + message(STATUS "Enabling gcc coverage support for target: ${target}") + + # Note: we use set_property(... APPEND ...) to not override other sttings + # for the target. + + set_property(TARGET ${target} APPEND + PROPERTY COMPILE_DEFINITIONS_DEBUG WITH_COVERAGE + ) + + # Note: COMPILE_OPTIONS property does not have per build configuration + # variant. Generator expression is used instead. + + set_property(TARGET ${target} APPEND + PROPERTY COMPILE_OPTIONS + $<$:-O0;-fprofile-arcs;-ftest-coverage> + ) + + set_property(TARGET ${target} APPEND + PROPERTY LINK_FLAGS_DEBUG -fprofile-arcs -ftest-coverage + ) + + set_property(TARGET ${target} APPEND + PROPERTY INTERFACE_LINK_LIBRARIES gcov + ) + + endif() + +endmacro(ADD_COVERAGE) diff --git a/cdk/cmake/testing.cmake b/cdk/cmake/testing.cmake index 1dc7f47ad..70b2150ea 100644 --- a/cdk/cmake/testing.cmake +++ b/cdk/cmake/testing.cmake @@ -54,6 +54,7 @@ IF(NOT DEFINED WITH_COVERAGE) OPTION(WITH_COVERAGE "Enable coverage support for gcc" OFF) ENDIF() + # # Note: On Windows the runtime type must match the one used by gtest. # @@ -72,19 +73,6 @@ IF(WITH_TESTS) ENDIF() -MACRO(ADD_GCOV target) -IF (WITH_TESTS) - IF(WITH_COVERAGE) - MESSAGE(STATUS "Enabling coverage support for gcc") - - SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage ") - SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "-fprofile-arcs -ftest-coverage") - - ENDIF(WITH_COVERAGE) -ENDIF (WITH_TESTS) - -ENDMACRO(ADD_GCOV) - MACRO(SETUP_TESTING) IF(WITH_TESTS) INCLUDE(CTest) @@ -273,7 +261,6 @@ IF(WITH_TESTS) ) TARGET_LINK_LIBRARIES(${target_run_unit_tests} gtest) - ADD_GCOV(${target_run_unit_tests}) #ADD_BOOST(${target_run_unit_tests}) # diff --git a/cdk/core/CMakeLists.txt b/cdk/core/CMakeLists.txt index 27f3d80eb..6286b1cac 100644 --- a/cdk/core/CMakeLists.txt +++ b/cdk/core/CMakeLists.txt @@ -48,6 +48,8 @@ add_library_ex(cdk STATIC session.cc codec.cc ${cdk_libs} ) +add_coverage(cdk) + #MESSAGE("cdk depends on: ${target_mysqlx} ${target_parser}") EXPORT(TARGETS cdk diff --git a/cdk/foundation/CMakeLists.txt b/cdk/foundation/CMakeLists.txt index 9af01e325..e53d3ae91 100644 --- a/cdk/foundation/CMakeLists.txt +++ b/cdk/foundation/CMakeLists.txt @@ -64,7 +64,7 @@ SET(target_foundation ${cdk_target_prefix}foundation CACHE INTERNAL "CDK foundation target") ADD_LIBRARY(${target_foundation} OBJECT ${sources}) -#ADD_BOOST(${target_foundation}) +ADD_COVERAGE(${target_foundation}) IF(WITH_SSL STREQUAL "bundled") lib_interface_link_libraries(${target_foundation} yassl) diff --git a/cdk/mysqlx/CMakeLists.txt b/cdk/mysqlx/CMakeLists.txt index 1647143e9..b05dcbe68 100644 --- a/cdk/mysqlx/CMakeLists.txt +++ b/cdk/mysqlx/CMakeLists.txt @@ -21,8 +21,6 @@ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -cmake_minimum_required(VERSION 2.8) - SET(target_mysqlx ${cdk_target_prefix}mysqlx CACHE INTERNAL "CDK mysqlx target") # @@ -36,6 +34,7 @@ if(WIN32) endif() ADD_LIBRARY(${target_mysqlx} OBJECT session.cc result.cc auth_mysql41.cc) +ADD_COVERAGE(${target_mysqlx}) #TARGET_LINK_LIBRARIES(${target_mysqlx} ${target_proto_mysqlx}) diff --git a/cdk/parser/CMakeLists.txt b/cdk/parser/CMakeLists.txt index 902122345..1bcf1ce8d 100644 --- a/cdk/parser/CMakeLists.txt +++ b/cdk/parser/CMakeLists.txt @@ -32,3 +32,5 @@ add_library(${target_parser} OBJECT json_parser.cc expr_parser.cc uri_parser.cc) + +add_coverage(${target_parser}) diff --git a/cdk/protocol/mysqlx/CMakeLists.txt b/cdk/protocol/mysqlx/CMakeLists.txt index bdbf8cb09..4125f2140 100644 --- a/cdk/protocol/mysqlx/CMakeLists.txt +++ b/cdk/protocol/mysqlx/CMakeLists.txt @@ -96,6 +96,7 @@ SET(target_proto_mysqlx ${cdk_target_prefix}proto_mysqlx ADD_LIBRARY(${target_proto_mysqlx} OBJECT protocol.cc session.cc rset.cc stmt.cc crud.cc ${PB_SRCS}) +ADD_COVERAGE(${target_proto_mysqlx}) source_group(protobuf FILES ${PB_SRCS}) diff --git a/devapi/CMakeLists.txt b/devapi/CMakeLists.txt index 9740d7d4c..d8e295ea5 100644 --- a/devapi/CMakeLists.txt +++ b/devapi/CMakeLists.txt @@ -45,6 +45,8 @@ ADD_LIBRARY(devapi OBJECT table_crud.cc ) +ADD_COVERAGE(devapi) + lib_interface_link_libraries(devapi cdk) if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/xapi/CMakeLists.txt b/xapi/CMakeLists.txt index 855307a7c..9c1f21660 100644 --- a/xapi/CMakeLists.txt +++ b/xapi/CMakeLists.txt @@ -48,7 +48,7 @@ SET(_libmysqlx_cc_src ) ADD_LIBRARY(xapi OBJECT ${_libmysqlx_cc_src}) - +ADD_COVERAGE(xapi) ADD_SUBDIRECTORY(tests) From 5a8174b3b527dcce1270731ac5feeeefef04c58c Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 17 Nov 2016 19:40:02 +0100 Subject: [PATCH 16/79] Avoid C++11 warning in XAPI code. --- xapi/crud_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi/crud_internal.h b/xapi/crud_internal.h index 524436c53..171e66890 100644 --- a/xapi/crud_internal.h +++ b/xapi/crud_internal.h @@ -173,5 +173,5 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag // Return the session validity state bool session_valid(); - friend Group_by_list; + friend class Group_by_list; } mysqlx_stmt_t; \ No newline at end of file From 20414df38c491093b0124008d94fd6a43e8bd765 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 17 Nov 2016 19:40:57 +0100 Subject: [PATCH 17/79] Disabled warnings in PB code triggered by deprecations in OSX 10.12 --- cdk/include/mysql/cdk/foundation/common.h | 5 +++-- cdk/protobuf/CMakeLists.txt | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cdk/include/mysql/cdk/foundation/common.h b/cdk/include/mysql/cdk/foundation/common.h index d7d6441d9..5bbf006ae 100644 --- a/cdk/include/mysql/cdk/foundation/common.h +++ b/cdk/include/mysql/cdk/foundation/common.h @@ -155,8 +155,9 @@ #else #define PUSH_PB_WARNINGS DIAGNOSTIC_PUSH \ - DISABLE_WARNING(-Wshadow) \ - DISABLE_WARNING(-Wunused-parameter) + DISABLE_WARNING(-Wshadow) \ + DISABLE_WARNING(-Wunused-parameter) \ + DISABLE_WARNING(-Wdeprecated-declarations) \ #endif diff --git a/cdk/protobuf/CMakeLists.txt b/cdk/protobuf/CMakeLists.txt index d4cdb7aa3..d59ab5b20 100644 --- a/cdk/protobuf/CMakeLists.txt +++ b/cdk/protobuf/CMakeLists.txt @@ -100,6 +100,16 @@ IF(UNIX) list(APPEND warnings_list "-Wno-return-type") list(APPEND warnings_list "-Wno-unused-function") + if(APPLE) + + # Our version of protobuf uses many constructs (mainly atomic ops) + # which were depracated in OSX 10.12. + # TODO: Upgrade bundled protobuf + + list(APPEND warnings_list -Wno-deprecated-declarations) + + endif() + IF(CMAKE_COMPILER_IS_GNUCXX) list(APPEND warnings_list "-Wno-unused-local-typedefs") list(APPEND warnings_list "-Wno-maybe-uninitialized") From 1a7f8fedd17f22432a93423671e33835d2de2a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Mon, 31 Oct 2016 11:13:20 +0000 Subject: [PATCH 18/79] MYCPP-56 CRUD find/select groupBy and having implementation. --- devapi/tests/crud-t.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/devapi/tests/crud-t.cc b/devapi/tests/crud-t.cc index f42f01f71..35b00c62e 100644 --- a/devapi/tests/crud-t.cc +++ b/devapi/tests/crud-t.cc @@ -1948,3 +1948,4 @@ TEST_F(Crud, group_by_having) check_order(coll_res, tbl_res); } + From 496ab75493c07faedf4b1c339ef9a5c4cec3d84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Mon, 7 Nov 2016 15:08:29 +0000 Subject: [PATCH 19/79] MYCPP-80: Session over SSL implementation --- CMakeLists.txt | 2 +- cdk/CMakeLists.txt | 1 + devapi/session.cc | 103 +++++++--- devapi/tests/session-t.cc | 80 ++++++++ include/devapi/document.h | 3 + include/mysql_devapi.h | 414 ++++++++++++++++++++++---------------- 6 files changed, 398 insertions(+), 205 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f9f0d537..092b2688c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,7 @@ SETUP_BOOST() SET(WITH_CDK_DOC 0) OPTION(WITH_CDK_TESTS "cdk tests" OFF) -set(WITH_SSL OFF) +#set(WITH_SSL OFF) set(WITH_PIC ${CMAKE_POSITION_INDEPENDENT_CODE}) ADD_SUBDIRECTORY(cdk) INCLUDE_DIRECTORIES(${CDK_INCLUDE_DIR}) diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index bae6930f5..d516f1a71 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -176,6 +176,7 @@ INCLUDE(protobuf) if(NOT DEFINED WITH_SSL) SET(WITH_SSL "bundled" CACHE STRING "") endif() + message("WITH_SSL: ${WITH_SSL}") IF(WITH_SSL) diff --git a/devapi/session.cc b/devapi/session.cc index 8aa312660..466423589 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -118,7 +118,7 @@ class internal::XSession_base::Impl struct URI_parser : public internal::XSession_base::Access::Options - , public endpoint::TCPIP + , private endpoint::TCPIP , public parser::URI_processor { URI_parser(const std::string &uri) @@ -132,68 +132,105 @@ struct URI_parser return *this; } - void user(const std::string &usr) + void user(const std::string &usr) override { m_usr = usr; } - void password(const std::string &pwd) + void password(const std::string &pwd) override { m_pwd = pwd; m_has_pwd = true; } - void host(const std::string &host) + void host(const std::string &host) override { m_host = host; } - void port(unsigned short port) + void port(unsigned short port) override { m_port = port; } - virtual void path(const std::string &db) + virtual void path(const std::string &db) override { set_database(db); } -}; + void key_val(const std::string &key) override + { + if (key == "ssl-enable") + m_use_tls = true; + } -internal::XSession_base::XSession_base(const std::string &url) -{ - URI_parser parser(url); +}; - try { - m_impl = new Impl( - static_cast(parser.get_endpoint()), - static_cast(parser) - ); - } - CATCH_AND_WRAP -} -internal::XSession_base::XSession_base( - const std::string &host, unsigned port, - const string &user, const char *pwd, - const string &db) +internal::XSession_base::XSession_base(SessionSettings settings) { try { - std::string pwd_str; - if (pwd) - pwd_str = pwd; + if (settings.has_option(SessionSettings::URI)) + { + URI_parser parser( + settings[SessionSettings::URI].get() + ); + + m_impl = new Impl( + static_cast(parser.get_endpoint()), + static_cast(parser)); + } + else + { + std::string host = "localhost"; + if (settings.has_option(SessionSettings::HOST)) + host = settings[SessionSettings::HOST].get(); + + unsigned port = DEFAULT_MYSQLX_PORT; + + if (settings.has_option(SessionSettings::PORT)) + port = settings[SessionSettings::PORT]; - if (port > 65535U) - throw_error("Port value out of range"); + if (port > 65535U) + throw_error("Port value out of range"); - endpoint::TCPIP ep(host, (uint16_t)port); - Options opt(user, pwd ? &pwd_str : NULL); - if (!db.empty()) - opt.set_database(db); + std::string pwd_str; + bool has_pwd = false; - m_impl = new Impl(ep, opt); + if (settings.has_option(SessionSettings::PWD) && + settings[SessionSettings::PWD].isNull() == false) + { + has_pwd = true; + pwd_str = settings[SessionSettings::PWD].get(); + } + + endpoint::TCPIP ep( host, (uint16_t)port); + + string user; + + if (settings.has_option(SessionSettings::USER)) + { + user = settings[SessionSettings::USER]; + } + else + { + throw Error("User not defined!"); + } + + Options opt(user, has_pwd ? &pwd_str : NULL); + + if (settings.has_option(SessionSettings::DB)) + opt.set_database( + settings[SessionSettings::DB].get() + ); + + if (settings.has_option(SessionSettings::SSL_ENABLE)) + opt.set_tls(settings[SessionSettings::SSL_ENABLE].get()); + + m_impl = new Impl(ep, opt); + } } CATCH_AND_WRAP } @@ -311,7 +348,7 @@ void internal::XSession_base::close() NodeSession XSession::bindToDefaultShard() { - return this; + return static_cast(this); } // --------------------------------------------------------------------- diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 6a9018bcf..740df4dbb 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -350,3 +350,83 @@ TEST_F(Sess, bind_node_session) cout << "Done!" << endl; } + +TEST_F(Sess, ssl_session) +{ + + SKIP_IF_NO_XPLUGIN; + + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, true); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } + + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER, get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + } + + //Using URI + + std::stringstream uri; + + uri << "mysqlx://" << get_user(); + + if (get_password()) + uri << ":"<< *get_password(); + + uri << "@" << "localhost:" << get_port(); + + //URI without ssl_enable + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + } + + + //Enable SSL + uri << "/?ssl-enable"; + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } + +} diff --git a/include/devapi/document.h b/include/devapi/document.h index 7155a476b..05960b77b 100644 --- a/include/devapi/document.h +++ b/include/devapi/document.h @@ -398,6 +398,9 @@ class PUBLIC_API Value : public internal::Printable operator const bytes&() const; operator DbDoc() const; + template + T get() { return static_cast(*this); } + //@} diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index c5824af83..7c0dc656f 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -494,6 +494,240 @@ class PUBLIC_API Table }; +/** + Represents session options to be passed at XSession/NodeSession object + creation. + + SessionSettings can be constructed using uri, common connect options (host, + port, user, password, database) or using pairs of SessionSettings::Options - + Value objects. + + @ingroup devapi +*/ + +class SessionSettings +{ +public: + enum Options + { + URI, + HOST, + PORT, + USER, + PWD, + DB, + SSL_ENABLE + }; + + + + SessionSettings(){} + + SessionSettings(SessionSettings &settings) + : m_options(settings.m_options) + {} + + SessionSettings(SessionSettings &&settings) + : m_options(std::move(settings.m_options)) + {} + + + SessionSettings(const string &uri) + { + add(URI, uri); + } + + + /** + Create session explicitly specifying session parameters. + */ + + SessionSettings(const std::string &host, unsigned port, + const string &user, + const char *pwd = NULL, + const string &db = string()) + { + add(HOST, host, + PORT, port, + USER, user, + DB, db); + + if (pwd) + add(PWD, pwd); + + //SSL enabled by default + add(SSL_ENABLE, true); + } + + SessionSettings(const std::string &host, unsigned port, + const string &user, + const std::string &pwd, + const string &db = string()) + : SessionSettings(host, port, user, pwd.c_str(), db) + {} + + /** + Create session using the default port + */ + + SessionSettings(const std::string &host, + const string &user, + const char *pwd = NULL, + const string &db = string()) + : SessionSettings(host, DEFAULT_MYSQLX_PORT, user, pwd, db) + {} + + SessionSettings(const std::string &host, + const string &user, + const std::string &pwd, + const string &db = string()) + : SessionSettings(host, DEFAULT_MYSQLX_PORT, user, pwd, db) + {} + + /** + Create session on localhost. + */ + + SessionSettings(unsigned port, + const string &user, + const char *pwd = NULL, + const string &db = string()) + : SessionSettings("localhost", port, user, pwd, db) + {} + + SessionSettings(unsigned port, + const string &user, + const std::string &pwd, + const string &db = string()) + : SessionSettings("localhost", port, user, pwd.c_str(), db) + {} + + /* + Templates below are here to take care of the optional password + parameter of type const char* (which can be either 3-rd or 4-th in + the parameter list). Without these templates passing + NULL as password does not work, because NULL is defined as 0 + which has type int. + */ + + template < + typename HOST, + typename PORT, + typename USER, + typename... T, + typename std::enable_if< + std::is_constructible::value + >::type* = nullptr + > + SessionSettings(HOST h, PORT p, USER u ,long pwd, T... args) + : SessionSettings(h, p, u, (const char*)pwd, args...) + {} + + template < + typename HOST, + typename PORT, + typename USER, + typename... T, + typename std::enable_if< + std::is_constructible::value + >::type* = nullptr + > + SessionSettings(HOST h, PORT p, USER u ,void* pwd, T... args) + : SessionSettings(h, p, u, (const char*)pwd, args...) + {} + + + template < + typename PORT, + typename USER, + typename... T, + typename std::enable_if< + std::is_constructible::value + >::type* = nullptr + > + SessionSettings(PORT p, USER u ,long pwd, T... args) + : SessionSettings(p, u, (const char*)pwd, args...) + {} + + + template < + typename PORT, + typename USER, + typename... T, + typename std::enable_if< + std::is_constructible::value + >::type* = nullptr + > + SessionSettings(PORT p, USER u ,void* pwd, T... args) + : SessionSettings(p, u, (const char*)pwd, args...) + {} + + + /** + Passing option - value pairs + */ + + template + SessionSettings(Options opt, V val, R&...rest) + { + add(opt, val, rest...); + } + + /** + SessionSetting operator and methods + */ + + Value& operator[](Options opt) + { + return m_options[opt]; + } + + void clear() + { + m_options.clear(); + } + + void erase(Options opt) + { + m_options.erase(opt); + } + + bool has_option(Options opt) + { + return m_options.find(opt) != m_options.end(); + } + + +private: + + std::map m_options; + + template::value, + V>::type* = nullptr> + void add(Options opt, V v) + { + m_options[opt] = v; + } + + template::value, + V>::type* = nullptr> + void add(Options opt, V v) + { + m_options[opt] = string(v); + } + + template + void add(Options opt, V v, R...rest) + { + add(opt,v); + add(rest...); + } + +}; + + namespace internal { DLL_WARNINGS_PUSH @@ -519,8 +753,6 @@ namespace internal { struct Options; - //XSession_base(const Options&); - /* This constructor constructs a child session of a parent session. */ @@ -541,68 +773,13 @@ namespace internal { parsing). */ - XSession_base(const std::string &url); - - XSession_base(const char *url) - : XSession_base(std::string(url)) - {} - - XSession_base(const string &url) - : XSession_base(std::string(url)) - {} - - - /** - Create session explicitly specifying session parameters. - */ - - XSession_base(const std::string &host, unsigned port, - const string &user, - const char *pwd = NULL, - const string &db = string()); + XSession_base(SessionSettings settings); - XSession_base(const std::string &host, unsigned port, - const string &user, - const std::string &pwd, - const string &db = string()) - : XSession_base(host, port, user, pwd.c_str(), db) + template + XSession_base(T...options) + : XSession_base(SessionSettings(options...)) {} - /** - Create session using the default port - */ - - XSession_base(const std::string &host, - const string &user, - const char *pwd = NULL, - const string &db = string()) - : XSession_base(host, DEFAULT_MYSQLX_PORT, user, pwd, db) - {} - - XSession_base(const std::string &host, - const string &user, - const std::string &pwd, - const string &db = string()) - : XSession_base(host, DEFAULT_MYSQLX_PORT, user, pwd, db) - {} - - /** - Create session on localhost. - */ - - XSession_base(unsigned port, - const string &user, - const char *pwd = NULL, - const string &db = string()) - : XSession_base("localhost", port, user, pwd, db) - {} - - XSession_base(unsigned port, - const string &user, - const std::string &pwd, - const string &db = string()) - : XSession_base("localhost", port, user, pwd.c_str(), db) - {} virtual ~XSession_base(); @@ -732,79 +909,11 @@ class PUBLIC_API XSession : public internal::XSession_base { -protected: - - //XSession(const Options &opt) - // : XSession_base(opt) - //{} - public: - XSession(const std::string &url) - : XSession_base(url) - {} - - XSession(const char *url) - : XSession_base(std::string(url)) - {} - - XSession(const string &url) - : XSession_base(std::string(url)) - {} - - - /** - Create session explicitly specifying session parameters. - */ - - XSession(const std::string &host, unsigned port, - const string &user, - const char *pwd = NULL, - const string &db = string()) - : XSession_base(host, port, user, pwd, db) - {} - - XSession(const std::string &host, unsigned port, - const string &user, - const std::string &pwd, - const string &db = string()) - : XSession_base(host, port, user, pwd.c_str(), db) - {} - - /** - Create session using the default port - */ - - XSession(const std::string &host, - const string &user, - const char *pwd = NULL, - const string &db = string()) - : XSession_base(host, DEFAULT_MYSQLX_PORT, user, pwd, db) - {} - - XSession(const std::string &host, - const string &user, - const std::string &pwd, - const string &db = string()) - : XSession_base(host, DEFAULT_MYSQLX_PORT, user, pwd, db) - {} - - /** - Create session on localhost. - */ - - XSession(unsigned port, - const string &user, - const char *pwd = NULL, - const string &db = string()) - : XSession_base("localhost", port, user, pwd, db) - {} - - XSession(unsigned port, - const string &user, - const std::string &pwd, - const string &db = string()) - : XSession_base("localhost", port, user, pwd.c_str(), db) + template + XSession(S...settings) + : XSession_base(settings...) {} @@ -832,7 +941,7 @@ class PUBLIC_API NodeSession NodeSession(NodeSession &&other) - : XSession_base(&other) + : XSession_base(static_cast(&other)) {} /** @@ -840,48 +949,11 @@ class PUBLIC_API NodeSession as XSession constructors. */ - template < - typename... T, - typename = typename std::enable_if< - std::is_constructible::value - >::type - > + template NodeSession(T... args) : XSession_base(args...) {} - /* - Templates below are here to take care of the optional password - parameter of type const char* (which can be either 2-nd or 3-rd in - the parameter list). Without these templates passing - NULL as password does not work, because NULL is defined as 0 - which has type int. - */ - - template < - typename A, - typename B, - typename... T, - typename = typename std::enable_if< - std::is_constructible::value - >::type - > - NodeSession(A a, B b, void* p, T... args) - : XSession_base(a, b, (const char*)p, args...) - {} - - template < - typename A, - typename B, - typename C, - typename... T, - typename = typename std::enable_if< - std::is_constructible::value - >::type - > - NodeSession(A a, B b, C c, void* p, T... args) - : XSession_base(a, b, c, (const char*)p, args...) - {} /** From b92d15e7cb375f2b95cb5176f00d30792ec482d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Wed, 30 Nov 2016 13:05:12 +0000 Subject: [PATCH 20/79] Fix UT because of empty password --- devapi/tests/session-t.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 740df4dbb..76af4abac 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -394,8 +394,8 @@ TEST_F(Sess, ssl_session) uri << "mysqlx://" << get_user(); - if (get_password()) - uri << ":"<< *get_password(); + if (get_password() && *get_password()) + uri << ":"<< get_password(); uri << "@" << "localhost:" << get_port(); From 8575e075a356999e3fa33032a7e4ca305f024cfb Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 22 Nov 2016 15:19:57 +0100 Subject: [PATCH 21/79] CDK: Separate charset and collation information for character data. --- cdk/extra/exprtest/r/expr_basic.result | 3 + cdk/include/mysql/cdk/charsets.h | 80 ++++ cdk/include/mysql/cdk/codec.h | 52 ++- cdk/include/mysql/cdk/common.h | 17 +- cdk/include/mysql/cdk/mysqlx/common.h | 2 +- cdk/include/mysql/cdk/mysqlx/session.h | 50 ++- cdk/include/mysql/cdk/protocol/mysqlx.h | 6 +- .../mysql/cdk/protocol/mysqlx/collations.h | 348 ++++++++++++++++++ cdk/include/mysql/cdk/protocol/mysqlx/expr.h | 8 +- .../mysql/cdk/protocol/mysqlx/traits.h | 2 +- cdk/mysqlx/session.cc | 2 +- cdk/protobuf/CMakeLists.txt | 2 +- cdk/protocol/mysqlx/builders.h | 4 +- cdk/protocol/mysqlx/rset.cc | 2 +- cdk/protocol/mysqlx/tests/expr.h | 8 +- .../mysqlx/tests/proto_mysqlx_crud-t.cc | 2 +- .../mysqlx/tests/proto_mysqlx_msg-t.cc | 2 +- cdk/protocol/mysqlx/tests/test.h | 4 +- 18 files changed, 548 insertions(+), 46 deletions(-) create mode 100644 cdk/include/mysql/cdk/charsets.h create mode 100644 cdk/include/mysql/cdk/protocol/mysqlx/collations.h diff --git a/cdk/extra/exprtest/r/expr_basic.result b/cdk/extra/exprtest/r/expr_basic.result index ba49aedd2..172a7fbd5 100644 --- a/cdk/extra/exprtest/r/expr_basic.result +++ b/cdk/extra/exprtest/r/expr_basic.result @@ -71,6 +71,7 @@ operator { type: V_OCTETS v_octets { value: "a" + content_type: 0 } } } @@ -80,6 +81,7 @@ operator { type: V_OCTETS v_octets { value: "b" + content_type: 0 } } } @@ -89,6 +91,7 @@ operator { type: V_OCTETS v_octets { value: "c" + content_type: 0 } } } diff --git a/cdk/include/mysql/cdk/charsets.h b/cdk/include/mysql/cdk/charsets.h new file mode 100644 index 000000000..477a938bd --- /dev/null +++ b/cdk/include/mysql/cdk/charsets.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + Lists of character sets known to CDK string codec (see codec.h). + This is generally kept in sync with character sets known to the MySQL Server. + See: http://dev.mysql.com/doc/refman/5.7/en/charset-charsets.html + + Note: currently the codec can only convert utf8 strings. +*/ + + +#ifndef MYSQL_CDK_CHARSETS_H +#define MYSQL_CDK_CHARSETS_H + +#define CDK_CS_LIST(X) \ + X(big5) \ + X(dec8) \ + X(cp850) \ + X(hp8) \ + X(koi8r) \ + X(latin1) \ + X(latin2) \ + X(swe7) \ + X(ascii) \ + X(ujis) \ + X(sjis) \ + X(hebrew) \ + X(tis620) \ + X(euckr) \ + X(koi8u) \ + X(gb2312) \ + X(greek) \ + X(cp1250) \ + X(gbk) \ + X(latin5) \ + X(armscii8) \ + X(utf8) \ + X(ucs2) \ + X(cp866) \ + X(keybcs2) \ + X(macce) \ + X(macroman) \ + X(cp852) \ + X(latin7) \ + X(utf8mb4) \ + X(cp1251) \ + X(utf16) \ + X(utf16le) \ + X(cp1256) \ + X(cp1257) \ + X(utf32) \ + X(binary) \ + X(geostd8) \ + X(cp932) \ + X(eucjpms) \ + X(gb18030) \ + +#endif diff --git a/cdk/include/mysql/cdk/codec.h b/cdk/include/mysql/cdk/codec.h index 47997ed79..2d8a6e3cd 100644 --- a/cdk/include/mysql/cdk/codec.h +++ b/cdk/include/mysql/cdk/codec.h @@ -26,7 +26,7 @@ #define CDK_CODEC_H #include "common.h" - +#include "charsets.h" namespace cdk { @@ -141,28 +141,53 @@ class Format : public Format_base }; +/* + String encoding formats (charsets) + ---------------------------------- +*/ + +/* + Constants for the known character set encodings. There is constant + Charset::CS for each charset CS listed in CDK_CD_LIST() macro (see + charsets.h). +*/ + +struct Charset +{ + +#undef CS_ENUM +#undef CS +#define CS_ENUM(CS) CS, + + enum value + { + CDK_CS_LIST(CS_ENUM) + }; +}; + + template<> -class Format : public Format_base +class Format : public Format_base { public: Format(const Format_info &fi) : Format_base(TYPE_STRING, fi) - , m_cs(0), m_width(0), m_kind(STRING) + , m_cs(Charset::value(0)), m_width(0), m_kind(STRING) { fi.get_info(*this); } - charset_id_t charset() const { return m_cs; } + Charset::value charset() const { return m_cs; } uint64_t pad_width() const { return m_width; } bool is_enum() const { return m_kind == ENUM; } bool is_set() const { return m_kind == SET; } protected: - // MySQL collation id that determines character encoding. + // Character set encoding. - charset_id_t m_cs; + Charset::value m_cs; /** If not zero and actual string is shorter than m_width @@ -251,7 +276,20 @@ class Codec { public: - Codec(const Format_info &fi) : Codec_base(fi) {} + Codec(const Format_info &fi) : Codec_base(fi) + { + /* + FIXME: Currently we ignore character set information and try to + decode string data as if it was utf8. But this fails miserably if + string data is in another multibyte encoding or if non-ascii characters + are used. However, we do not throw error yet as this would break all + our unit tests (and render CDK almost unusable, given that MySQL default + charset is latin1). + + if (Charset::utf8 != m_fmt.charset()) + throw_error("Non utf-8 character encodings are not supported yet"); + */ + } /** Return number of bytes required to encode given string (including diff --git a/cdk/include/mysql/cdk/common.h b/cdk/include/mysql/cdk/common.h index 6d440eaa4..55e1cc73d 100644 --- a/cdk/include/mysql/cdk/common.h +++ b/cdk/include/mysql/cdk/common.h @@ -138,6 +138,14 @@ class Format_info ========== */ +/* + Note: These types are compatible with the X protocol. +*/ + +typedef uint64_t row_count_t; +typedef uint32_t col_count_t; +typedef uint64_t collation_id_t; + class Column_info : public api::Column_ref @@ -148,16 +156,9 @@ class Column_info virtual length_t length() const =0; virtual length_t decimals() const =0; + virtual collation_id_t collation() const = 0; }; -/* - Note: These types are compatible with the X protocol. -*/ - -typedef uint64_t row_count_t; -typedef uint32_t col_count_t; -typedef uint64_t charset_id_t; - struct Traits { diff --git a/cdk/include/mysql/cdk/mysqlx/common.h b/cdk/include/mysql/cdk/mysqlx/common.h index a3d8b7baa..ffd4d8e3a 100644 --- a/cdk/include/mysql/cdk/mysqlx/common.h +++ b/cdk/include/mysql/cdk/mysqlx/common.h @@ -66,7 +66,7 @@ using protocol::mysqlx::Protocol; using protocol::mysqlx::sql_state_t; using protocol::mysqlx::row_count_t; using protocol::mysqlx::col_count_t; -using protocol::mysqlx::charset_id_t; +using protocol::mysqlx::collation_id_t; using protocol::mysqlx::insert_id_t; typedef api::Async_op Async_op; diff --git a/cdk/include/mysql/cdk/mysqlx/session.h b/cdk/include/mysql/cdk/mysqlx/session.h index 373d24c3c..cabd5031b 100644 --- a/cdk/include/mysql/cdk/mysqlx/session.h +++ b/cdk/include/mysql/cdk/mysqlx/session.h @@ -27,6 +27,8 @@ #include #include +#include + #include "common.h" PUSH_SYS_WARNINGS @@ -66,7 +68,7 @@ struct cdk::Format::Access { typedef cdk::Format Format; static void set_width(Format &o, uint64_t width) { o.m_width= width; } - static void set_cs(Format &o, cdk::charset_id_t cs) { o.m_cs= cs; } + static void set_cs(Format &o, Charset::value cs) { o.m_cs= cs; } static void set_kind_set(Format &o) { o.m_kind= Format::SET; } static void set_kind_enum(Format &o) { o.m_kind= Format::ENUM; } }; @@ -120,6 +122,27 @@ class Obj_ref : public Base }; +/* + Determine charset from collation id reported by the protocol. The mapping + is given by COLLATIONS_XXX() lists in collations.h. +*/ + +inline +cdk::Charset::value get_collation_cs(collation_id_t id) +{ + +#undef CS +#define COLL_TO_CS(CS) COLLATIONS_##CS(COLL_TO_CS_CASE) return cdk::Charset::CS; +#define COLL_TO_CS_CASE(CS,ID,COLL,CC) case ID: + + switch (id) + { + CDK_CS_LIST(COLL_TO_CS) + default: + THROW("Unkonwn collation id"); + } +} + class Col_metadata : public Obj_ref @@ -131,7 +154,7 @@ class Col_metadata int m_content_type; length_t m_length; unsigned int m_decimals; - charset_id_t m_cs; + collation_id_t m_cs; uint32_t m_flags; class : public Obj_ref @@ -160,7 +183,10 @@ class Col_metadata return m_has_table ? &m_table : NULL; } - // Encoding format information + /* + Format_info interface + --------------------- + */ bool for_type(Type_info type) const { @@ -194,6 +220,11 @@ class Col_metadata } } + /* + Methods get_info() update a Type_info object to describe the + encoding format used by this column data. + */ + void get_info(Format& fmt) const { switch (m_type) @@ -226,14 +257,14 @@ class Col_metadata void get_info(Format& fmt) const { + Format::Access::set_cs(fmt, get_collation_cs(m_cs)); + /* - Note: Types ENUM and SET are generally treated as - strings, but we set a 'kind' flag in the format description - to be able to distinguish them from plain strings. + Note: Types ENUM and SET are generally treated as + strings, but we set a 'kind' flag in the format description + to be able to distinguish them from plain strings. */ - Format::Access::set_cs(fmt, m_cs); - switch (m_type) { case protocol::mysqlx::col_type::BYTES: @@ -305,6 +336,7 @@ class Col_metadata length_t length() const { return m_length; } length_t decimals() const { return m_decimals; } + collation_id_t collation() const { return m_cs; } friend class Session; friend class Cursor; @@ -569,7 +601,7 @@ class Session const string &table, const string &original); void col_schema(col_count_t pos, const string &schema, const string &catalog); - void col_charset(col_count_t pos, charset_id_t cs); + void col_collation(col_count_t pos, collation_id_t cs); void col_length(col_count_t pos, uint32_t length); void col_decimals(col_count_t pos, unsigned short decimals); void col_flags(col_count_t, uint32_t); diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index 435a68371..fb2163292 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -841,8 +841,8 @@ class Mdata_processor : public Error_processor { public: - typedef protocol::mysqlx::col_count_t col_count_t; - typedef protocol::mysqlx::charset_id_t charset_id_t; + typedef protocol::mysqlx::col_count_t col_count_t; + typedef protocol::mysqlx::collation_id_t collation_id_t; virtual void col_count(col_count_t) {} virtual void col_type(col_count_t /*pos*/, unsigned short /*type*/) {} @@ -852,7 +852,7 @@ class Mdata_processor : public Error_processor const string &/*table*/, const string &/*original*/) {} virtual void col_schema(col_count_t /*pos*/, const string &/*schema*/, const string &/*catalog*/) {} - virtual void col_charset(col_count_t /*pos*/, charset_id_t /*cs*/) {} + virtual void col_collation(col_count_t /*pos*/, collation_id_t /*cs*/) {} virtual void col_length(col_count_t /*pos*/, uint32_t /*length*/) {} virtual void col_decimals(col_count_t /*pos*/, unsigned short /*decimals*/) {} virtual void col_content_type(col_count_t /*pos*/, unsigned short /*type*/) {} diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/collations.h b/cdk/include/mysql/cdk/protocol/mysqlx/collations.h new file mode 100644 index 000000000..e9d2adac6 --- /dev/null +++ b/cdk/include/mysql/cdk/protocol/mysqlx/collations.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + Lists of collations used by MySQL Server and its protocols. + + Note: it is assumed that each collation's charset is known to CDK and + is listed in CDK_CS_LIST(). +*/ + +#ifndef MYSQL_CDK_PROTOCOL_MYSQLX_COLLATIONS_H +#define MYSQL_CDK_PROTOCOL_MYSQLX_COLLATIONS_H + +/* + Each line X(CS, ID, COLL, CASE) in the expansion of + a COLLATION_XXX() macro declares collation with name COLL for character set + CS. ID is the MySQL id number for the collation. CASE is one of ci, cs or bin + and indicates whether it is case insensitive, sensitive or binary collation, + respectively. +*/ + +#define COLLATIONS_big5(X) \ + X(big5,1,chinese,ci) \ + X(big5,84,bin,bin) \ + +#define COLLATIONS_dec8(X) \ + X(dec8,3,swedish,ci) \ + X(dec8,69,bin,bin) \ + +#define COLLATIONS_cp850(X) \ + X(cp850,4,general,ci) \ + X(cp850,80,bin,bin) \ + +#define COLLATIONS_hp8(X) \ + X(hp8,6,english,ci) \ + X(hp8,72,bin,bin) \ + +#define COLLATIONS_koi8r(X) \ + X(koi8r,7,general,ci) \ + X(koi8r,74,bin,bin) \ + +#define COLLATIONS_latin1(X) \ + X(latin1,5,german1,ci) \ + X(latin1,8,swedish,ci) \ + X(latin1,15,danish,ci) \ + X(latin1,31,german2,ci) \ + X(latin1,47,bin,bin) \ + X(latin1,48,general,ci) \ + X(latin1,49,general,cs) \ + X(latin1,94,spanish,ci) \ + +#define COLLATIONS_latin2(X) \ + X(latin2,2,czech,cs) \ + X(latin2,9,general,ci) \ + X(latin2,21,hungarian,ci) \ + X(latin2,27,croatian,ci) \ + X(latin2,77,bin,bin) \ + +#define COLLATIONS_swe7(X) \ + X(swe7,10,swedish,ci) \ + X(swe7,82,bin,bin) \ + +#define COLLATIONS_ascii(X) \ + X(ascii,11,general,ci) \ + X(ascii,65,bin,bin) \ + +#define COLLATIONS_ujis(X) \ + X(ujis,12,japanese,ci) \ + X(ujis,91,bin,bin) \ + +#define COLLATIONS_sjis(X) \ + X(sjis,13,japanese,ci) \ + X(sjis,88,bin,bin) \ + +#define COLLATIONS_hebrew(X) \ + X(hebrew,16,general,ci) \ + X(hebrew,71,bin,bin) \ + +#define COLLATIONS_tis620(X) \ + X(tis620,18,thai,ci) \ + X(tis620,89,bin,bin) \ + +#define COLLATIONS_euckr(X) \ + X(euckr,19,korean,ci) \ + X(euckr,85,bin,bin) \ + +#define COLLATIONS_koi8u(X) \ + X(koi8u,22,general,ci) \ + X(koi8u,75,bin,bin) \ + +#define COLLATIONS_gb2312(X) \ + X(gb2312,24,chinese,ci) \ + X(gb2312,86,bin,bin) \ + +#define COLLATIONS_greek(X) \ + X(greek,25,general,ci) \ + X(greek,70,bin,bin) \ + +#define COLLATIONS_cp1250(X) \ + X(cp1250,26,general,ci) \ + X(cp1250,34,czech,cs) \ + X(cp1250,44,croatian,ci) \ + X(cp1250,66,bin,bin) \ + X(cp1250,99,polish,ci) \ + +#define COLLATIONS_gbk(X) \ + X(gbk,28,chinese,ci) \ + X(gbk,87,bin,bin) \ + +#define COLLATIONS_latin5(X) \ + X(latin5,30,turkish,ci) \ + X(latin5,78,bin,bin) \ + +#define COLLATIONS_armscii8(X) \ + X(armscii8,32,general,ci) \ + X(armscii8,64,bin,bin) \ + +#define COLLATIONS_utf8(X) \ + X(utf8,33,general,ci) \ + X(utf8,83,bin,bin) \ + X(utf8,192,unicode,ci) \ + X(utf8,193,icelandic,ci) \ + X(utf8,194,latvian,ci) \ + X(utf8,195,romanian,ci) \ + X(utf8,196,slovenian,ci) \ + X(utf8,197,polish,ci) \ + X(utf8,198,estonian,ci) \ + X(utf8,199,spanish,ci) \ + X(utf8,200,swedish,ci) \ + X(utf8,201,turkish,ci) \ + X(utf8,202,czech,ci) \ + X(utf8,203,danish,ci) \ + X(utf8,204,lithuanian,ci) \ + X(utf8,205,slovak,ci) \ + X(utf8,206,spanish2,ci) \ + X(utf8,207,roman,ci) \ + X(utf8,208,persian,ci) \ + X(utf8,209,esperanto,ci) \ + X(utf8,210,hungarian,ci) \ + X(utf8,211,sinhala,ci) \ + X(utf8,212,german2,ci) \ + X(utf8,213,croatian,ci) \ + X(utf8,214,unicode_520,ci) \ + X(utf8,215,vietnamese,ci) \ + X(utf8,223,general_mysql500,ci) \ + +#define COLLATIONS_ucs2(X) \ + X(ucs2,35,general,ci) \ + X(ucs2,90,bin,bin) \ + X(ucs2,128,unicode,ci) \ + X(ucs2,129,icelandic,ci) \ + X(ucs2,130,latvian,ci) \ + X(ucs2,131,romanian,ci) \ + X(ucs2,132,slovenian,ci) \ + X(ucs2,133,polish,ci) \ + X(ucs2,134,estonian,ci) \ + X(ucs2,135,spanish,ci) \ + X(ucs2,136,swedish,ci) \ + X(ucs2,137,turkish,ci) \ + X(ucs2,138,czech,ci) \ + X(ucs2,139,danish,ci) \ + X(ucs2,140,lithuanian,ci) \ + X(ucs2,141,slovak,ci) \ + X(ucs2,142,spanish2,ci) \ + X(ucs2,143,roman,ci) \ + X(ucs2,144,persian,ci) \ + X(ucs2,145,esperanto,ci) \ + X(ucs2,146,hungarian,ci) \ + X(ucs2,147,sinhala,ci) \ + X(ucs2,148,german2,ci) \ + X(ucs2,149,croatian,ci) \ + X(ucs2,150,unicode_520,ci) \ + X(ucs2,151,vietnamese,ci) \ + X(ucs2,159,general_mysql500,ci) \ + +#define COLLATIONS_cp866(X) \ + X(cp866,36,general,ci) \ + X(cp866,68,bin,bin) \ + +#define COLLATIONS_keybcs2(X) \ + X(keybcs2,37,general,ci) \ + X(keybcs2,73,bin,bin) \ + +#define COLLATIONS_macce(X) \ + X(macce,38,general,ci) \ + X(macce,43,bin,bin) \ + +#define COLLATIONS_macroman(X) \ + X(macroman,39,general,ci) \ + X(macroman,53,bin,bin) \ + +#define COLLATIONS_cp852(X) \ + X(cp852,40,general,ci) \ + X(cp852,81,bin,bin) \ + +#define COLLATIONS_latin7(X) \ + X(latin7,20,estonian,cs) \ + X(latin7,41,general,ci) \ + X(latin7,42,general,cs) \ + X(latin7,79,bin,bin) \ + +#define COLLATIONS_utf8mb4(X) \ + X(utf8mb4,45,general,ci) \ + X(utf8mb4,46,bin,bin) \ + X(utf8mb4,224,unicode,ci) \ + X(utf8mb4,225,icelandic,ci) \ + X(utf8mb4,226,latvian,ci) \ + X(utf8mb4,227,romanian,ci) \ + X(utf8mb4,228,slovenian,ci) \ + X(utf8mb4,229,polish,ci) \ + X(utf8mb4,230,estonian,ci) \ + X(utf8mb4,231,spanish,ci) \ + X(utf8mb4,232,swedish,ci) \ + X(utf8mb4,233,turkish,ci) \ + X(utf8mb4,234,czech,ci) \ + X(utf8mb4,235,danish,ci) \ + X(utf8mb4,236,lithuanian,ci) \ + X(utf8mb4,237,slovak,ci) \ + X(utf8mb4,238,spanish2,ci) \ + X(utf8mb4,239,roman,ci) \ + X(utf8mb4,240,persian,ci) \ + X(utf8mb4,241,esperanto,ci) \ + X(utf8mb4,242,hungarian,ci) \ + X(utf8mb4,243,sinhala,ci) \ + X(utf8mb4,244,german2,ci) \ + X(utf8mb4,245,croatian,ci) \ + X(utf8mb4,246,unicode_520,ci) \ + X(utf8mb4,247,vietnamese,ci) \ + +#define COLLATIONS_cp1251(X) \ + X(cp1251,14,bulgarian,ci) \ + X(cp1251,23,ukrainian,ci) \ + X(cp1251,50,bin,bin) \ + X(cp1251,51,general,ci) \ + X(cp1251,52,general,cs) \ + +#define COLLATIONS_utf16(X) \ + X(utf16,54,general,ci) \ + X(utf16,55,bin,bin) \ + X(utf16,101,unicode,ci) \ + X(utf16,102,icelandic,ci) \ + X(utf16,103,latvian,ci) \ + X(utf16,104,romanian,ci) \ + X(utf16,105,slovenian,ci) \ + X(utf16,106,polish,ci) \ + X(utf16,107,estonian,ci) \ + X(utf16,108,spanish,ci) \ + X(utf16,109,swedish,ci) \ + X(utf16,110,turkish,ci) \ + X(utf16,111,czech,ci) \ + X(utf16,112,danish,ci) \ + X(utf16,113,lithuanian,ci) \ + X(utf16,114,slovak,ci) \ + X(utf16,115,spanish2,ci) \ + X(utf16,116,roman,ci) \ + X(utf16,117,persian,ci) \ + X(utf16,118,esperanto,ci) \ + X(utf16,119,hungarian,ci) \ + X(utf16,120,sinhala,ci) \ + X(utf16,121,german2,ci) \ + X(utf16,122,croatian,ci) \ + X(utf16,123,unicode_520,ci) \ + X(utf16,124,vietnamese,ci) \ + +#define COLLATIONS_utf16le(X) \ + X(utf16le,56,general,ci) \ + X(utf16le,62,bin,bin) \ + +#define COLLATIONS_cp1256(X) \ + X(cp1256,57,general,ci) \ + X(cp1256,67,bin,bin) \ + +#define COLLATIONS_cp1257(X) \ + X(cp1257,29,lithuanian,ci) \ + X(cp1257,58,bin,bin) \ + X(cp1257,59,general,ci) \ + +#define COLLATIONS_utf32(X) \ + X(utf32,60,general,ci) \ + X(utf32,61,bin,bin) \ + X(utf32,160,unicode,ci) \ + X(utf32,161,icelandic,ci) \ + X(utf32,162,latvian,ci) \ + X(utf32,163,romanian,ci) \ + X(utf32,164,slovenian,ci) \ + X(utf32,165,polish,ci) \ + X(utf32,166,estonian,ci) \ + X(utf32,167,spanish,ci) \ + X(utf32,168,swedish,ci) \ + X(utf32,169,turkish,ci) \ + X(utf32,170,czech,ci) \ + X(utf32,171,danish,ci) \ + X(utf32,172,lithuanian,ci) \ + X(utf32,173,slovak,ci) \ + X(utf32,174,spanish2,ci) \ + X(utf32,175,roman,ci) \ + X(utf32,176,persian,ci) \ + X(utf32,177,esperanto,ci) \ + X(utf32,178,hungarian,ci) \ + X(utf32,179,sinhala,ci) \ + X(utf32,180,german2,ci) \ + X(utf32,181,croatian,ci) \ + X(utf32,182,unicode_520,ci) \ + X(utf32,183,vietnamese,ci) \ + +#define COLLATIONS_binary(X) \ + X(binary,63,bin,bin) \ + +#define COLLATIONS_geostd8(X) \ + X(geostd8,92,general,ci) \ + X(geostd8,93,bin,bin) \ + +#define COLLATIONS_cp932(X) \ + X(cp932,95,japanese,ci) \ + X(cp932,96,bin,bin) \ + +#define COLLATIONS_eucjpms(X) \ + X(eucjpms,97,japanese,ci) \ + X(eucjpms,98,bin,bin) \ + +#define COLLATIONS_gb18030(X) \ + X(gb18030,248,chinese,ci) \ + X(gb18030,249,bin,bin) \ + X(gb18030,250,unicode_520,ci) \ + + +#endif diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/expr.h b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h index 207ca1daf..b162f7170 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx/expr.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h @@ -108,12 +108,12 @@ class Scalar_processor { public: - typedef protocol::mysqlx::charset_id_t charset_id_t; + typedef protocol::mysqlx::collation_id_t collation_id_t; virtual void null() =0; virtual void str(bytes) =0; - virtual void str(charset_id_t, bytes) =0; + virtual void str(collation_id_t, bytes) =0; virtual void num(int64_t) =0; virtual void num(uint64_t) =0; virtual void num(float) =0; @@ -262,7 +262,7 @@ struct Safe_prc typedef Safe_prc_base Base; using Base::Processor; - typedef Processor::charset_id_t charset_id_t; + typedef Processor::collation_id_t collation_id_t; Safe_prc(Processor *prc) : Base(prc) {} @@ -279,7 +279,7 @@ struct Safe_prc void str(bytes val) { return m_prc ? m_prc->str(val) : (void)NULL; } - void str(charset_id_t cs, bytes val) + void str(collation_id_t cs, bytes val) { return m_prc ? m_prc->str(cs, val) : (void)NULL; } void num(int64_t val) diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/traits.h b/cdk/include/mysql/cdk/protocol/mysqlx/traits.h index ded9571bb..49c25733d 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx/traits.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx/traits.h @@ -14,7 +14,7 @@ typedef uint32_t cursor_id_t; typedef uint64_t row_count_t; typedef uint32_t col_count_t; // Note: protocol uses 64bit numbers for collation ids -typedef uint64_t charset_id_t; +typedef uint64_t collation_id_t; typedef uint64_t insert_id_t; typedef int64_t sint64_t; diff --git a/cdk/mysqlx/session.cc b/cdk/mysqlx/session.cc index 7817e7903..c0ecb7c26 100644 --- a/cdk/mysqlx/session.cc +++ b/cdk/mysqlx/session.cc @@ -627,7 +627,7 @@ void Session::col_schema(col_count_t pos, } -void Session::col_charset(col_count_t pos, charset_id_t cs) +void Session::col_collation(col_count_t pos, collation_id_t cs) { if (m_discard) return; diff --git a/cdk/protobuf/CMakeLists.txt b/cdk/protobuf/CMakeLists.txt index c17592ae6..d59ab5b20 100644 --- a/cdk/protobuf/CMakeLists.txt +++ b/cdk/protobuf/CMakeLists.txt @@ -106,7 +106,7 @@ IF(UNIX) # which were depracated in OSX 10.12. # TODO: Upgrade bundled protobuf - list(APPEND warnings_list -Wdeprecated-declarations) + list(APPEND warnings_list -Wno-deprecated-declarations) endif() diff --git a/cdk/protocol/mysqlx/builders.h b/cdk/protocol/mysqlx/builders.h index 1a7ac6895..5e9295a68 100644 --- a/cdk/protocol/mysqlx/builders.h +++ b/cdk/protocol/mysqlx/builders.h @@ -567,7 +567,7 @@ class Scalar_builder_base void null(); void str(bytes val); - void str(charset_id_t cs, bytes val); + void str(collation_id_t cs, bytes val); void num(int64_t val); void num(uint64_t val); void num(float val); @@ -724,7 +724,7 @@ void Scalar_builder_base::str(bytes val) template inline -void Scalar_builder_base::str(charset_id_t cs, bytes val) +void Scalar_builder_base::str(collation_id_t cs, bytes val) { String &str= get_string(); str.set_collation(cs); diff --git a/cdk/protocol/mysqlx/rset.cc b/cdk/protocol/mysqlx/rset.cc index 2349c2cb2..373843939 100644 --- a/cdk/protocol/mysqlx/rset.cc +++ b/cdk/protocol/mysqlx/rset.cc @@ -601,7 +601,7 @@ void Rcv_result_base::process_msg_with(Mysqlx::Resultset::ColumnMetaData &col_md col_mdata.has_catalog() ? col_mdata.catalog() : ""); if (col_mdata.has_collation()) - mdata_proc.col_charset(ccount, col_mdata.collation()); + mdata_proc.col_collation(ccount, col_mdata.collation()); if (col_mdata.has_length()) mdata_proc.col_length(ccount, col_mdata.length()); diff --git a/cdk/protocol/mysqlx/tests/expr.h b/cdk/protocol/mysqlx/tests/expr.h index c6c610492..94c8b8d9c 100644 --- a/cdk/protocol/mysqlx/tests/expr.h +++ b/cdk/protocol/mysqlx/tests/expr.h @@ -135,12 +135,12 @@ class Expr_class : public B class Param_String : public Expr_class { std::string m_val; - charset_id_t m_cs; + collation_id_t m_cs; bool m_has_cs; public: - Param_String(charset_id_t cs, const std::string &val) + Param_String(collation_id_t cs, const std::string &val) : m_val(val), m_cs(cs), m_has_cs(true) {} @@ -267,12 +267,12 @@ List::List(const List &rhs) class String : public Expr_class { std::string m_val; - charset_id_t m_cs; + collation_id_t m_cs; bool m_has_cs; public: - String(charset_id_t cs, const std::string &val) + String(collation_id_t cs, const std::string &val) : m_val(val), m_cs(cs), m_has_cs(true) {} diff --git a/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc b/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc index 6ccc9f887..5d2e62df8 100644 --- a/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc +++ b/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc @@ -348,7 +348,7 @@ class Expr_printer out_ind() <<"\"" < Number_codec; @@ -301,7 +301,7 @@ class Mdata_handler < Date: Wed, 30 Nov 2016 14:44:34 +0100 Subject: [PATCH 22/79] CDK: ASCII decoder for non-utf8 strings. --- cdk/CMakeLists.txt | 33 +++- cdk/core/codec.cc | 43 +++-- cdk/core/tests/CMakeLists.txt | 2 +- cdk/core/tests/result-t.cc | 227 +++++++++++++++++++++++ cdk/foundation/string.cc | 109 +++++++---- cdk/include/mysql/cdk/codec.h | 15 +- cdk/include/mysql/cdk/foundation/codec.h | 138 ++++++++++++-- 7 files changed, 491 insertions(+), 76 deletions(-) create mode 100644 cdk/core/tests/result-t.cc diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index 82230e5d3..832dd014b 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -113,12 +113,6 @@ if(DISABLE_WARNINGS) endif() -#message("flags: ${CMAKE_C_FLAGS}") -#message("c++ flags: ${CMAKE_CXX_FLAGS}") -#foreach(TYPE DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) -# message("${TYPE} flags: ${CMAKE_C_FLAGS_${TYPE}}") -# message("c++ ${TYPE} flags: ${CMAKE_CXX_FLAGS_${TYPE}}") -#endforeach() # # Infrastructure for defining code configuration settings @@ -242,6 +236,26 @@ if(WITH_TESTS) endif() +# +# Deal with broken optimization in gcc 4.8. +# +# We observed very strange behaviour of exceptions when compiling +# fully optimized code wtih gcc 4.8. Downgrade optimization to -O1 +# in this case. To get trully optimized code use gcc 4.9+ or clang. +# + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9") + foreach(LANG C CXX) + foreach(TYPE RELEASE RELWITHDEBINFO) + string(REPLACE "-O3" "-O1" CMAKE_${LANG}_FLAGS_${TYPE} "${CMAKE_${LANG}_FLAGS_${TYPE}}") + string(REPLACE "-O2" "-O1" CMAKE_${LANG}_FLAGS_${TYPE} "${CMAKE_${LANG}_FLAGS_${TYPE}}") + endforeach(TYPE) + endforeach(LANG) +endif() +endif() + + # # Set higher warning level on Windows to catch non-portable # code. @@ -307,6 +321,13 @@ ENDIF() endforeach(LANG) +#message("flags: ${CMAKE_C_FLAGS}") +#message("c++ flags: ${CMAKE_CXX_FLAGS}") +#foreach(TYPE DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) +# message("${TYPE} flags: ${CMAKE_C_FLAGS_${TYPE}}") +# message("c++ ${TYPE} flags: ${CMAKE_CXX_FLAGS_${TYPE}}") +#endforeach() + # # Parser library diff --git a/cdk/core/codec.cc b/cdk/core/codec.cc index 142336118..a136f87e8 100644 --- a/cdk/core/codec.cc +++ b/cdk/core/codec.cc @@ -60,36 +60,49 @@ size_t cdk::Codec::to_bytes(const std::string &str, bytes raw) return len; } -size_t Codec::measure(const string &) +size_t Codec::measure(const string &str) { - //TODO: CS - return 0; + // add 1 for the trailing 0x00 byte + return 1 + get_codec().measure(str); } size_t Codec::from_bytes(bytes raw, string &str) { - //TODO: CS - //TODO: detect utf8 encoding //TODO: padding - foundation::Codec utf8; // using string object, no need to have NULL char terminator // remove NULL char terminator if present - return utf8.from_bytes(bytes(raw.begin(), - ( raw.size() > 0 && *(raw.end()-1) == '\0') ? - raw.end()-1 : - raw.end()), - str); + return get_codec().from_bytes(bytes(raw.begin(), + ( raw.size() > 0 && *(raw.end()-1) == '\0') ? + raw.end()-1 : + raw.end()), + str); } size_t Codec::to_bytes(const string& str,bytes raw) { - //TODO: CS - //TODO: detect utf8 encoding - foundation::Codec utf8; - return utf8.to_bytes(str, raw); + // FIXME: should we add the trailing 0x00 byte here, or is it done by + // foundation codecs? + return get_codec().to_bytes(str, raw); +} + + +foundation::api::String_codec* Format::codec() const +{ + /* + TODO: This implementation uses ASCII codec for all non utf8 strings, + which works only for simple strings. Correctly handle all MySQL + character encodings. + */ + + static foundation::String_codec utf8; + static foundation::String_codec ascii; + + return Charset::utf8 == charset() ? + (foundation::api::String_codec*)&utf8 + : (foundation::api::String_codec*)&ascii; } diff --git a/cdk/core/tests/CMakeLists.txt b/cdk/core/tests/CMakeLists.txt index e2aecaf69..a3e48add3 100644 --- a/cdk/core/tests/CMakeLists.txt +++ b/cdk/core/tests/CMakeLists.txt @@ -24,6 +24,6 @@ IF (WITH_TESTS) ADD_DEFINITIONS(-DDEFAULT_PORT=33060) -ADD_NG_TEST(cdk-t session-t.cc session_crud-t.cc) +ADD_NG_TEST(cdk-t session-t.cc session_crud-t.cc result-t.cc) ENDIF() diff --git a/cdk/core/tests/result-t.cc b/cdk/core/tests/result-t.cc new file mode 100644 index 000000000..26c7ff98e --- /dev/null +++ b/cdk/core/tests/result-t.cc @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "test.h" +#include "session_test.h" + +#include +#include + + +using ::std::cout; +using ::std::endl; +using namespace ::cdk; + +class Result + : public cdk::test::Core_test + , public cdk::test::Row_processor +{ +public: + + scoped_ptr m_sess; + + virtual void SetUp() + { + Core_test::SetUp(); + + if (!has_xplugin()) + return; + + m_sess.reset(new Session(this)); + if (!m_sess->is_valid()) + FAIL() << "could not create session"; + } + + Session& get_sess() + { + return *m_sess; + } + + void do_sql(const string &query) + { + Reply r; + r = m_sess->sql(query); + r.wait(); + if (0 < r.entry_count()) + r.get_error().rethrow (); + } +}; + + +using ::std::cout; +using ::std::endl; +using namespace ::cdk; +using namespace ::cdk::test; + + +class Result_cs : public Result +{ +public: + + Table_ref t; + + Result_cs() + : t("t1", "test") + {} + + string expected_string; + + void process_field_val(col_count_t pos, bytes data, + const cdk::string &val) + { + std::cout << val; + if (!expected_string.empty()) + EXPECT_EQ(expected_string, val); + } + + /* + Check that we correctly retreive non-ascii strings if stored using + utf8 encoding. + */ + + void check1(const char *cs, const string &val) + { + cout << "Testing " << cs << " string stored as utf8" << endl; + create_table("utf8"); + insert_string(val); + Reply select(get_sess().table_select(t)); + Cursor c(select); + set_meta_data(c); + expected_string = val; + c.get_rows(*this); + c.wait(); + } + + /* + Check that non-utf8 strings which use non-ascii characters trigger + string conversion errors (as, at the moment, we do not support encodings + other than utf8) + */ + + void check2(const char *cs, const string &val) + { + cout << "Testing " << cs << " string (expected conversion error)" << endl; + create_table(cs); + insert_string(val); + Reply select(get_sess().table_select(t)); + Cursor c(select); + set_meta_data(c); + EXPECT_THROW({ c.get_rows(*this); c.wait(); }, cdk::Error); + cout << endl; + } + + /* + Check that non-utf8 strings which consist only of ascii characters are + handled correctly. + */ + + void check3(const char *cs) + { + cout << "Testing ascii string stored as " << cs << endl; + expected_string = "I can eat glass{}, [].!"; + create_table(cs); + insert_string(expected_string); + Reply select(get_sess().table_select(t)); + Cursor c(select); + set_meta_data(c); + c.get_rows(*this); + c.wait(); + } + + void create_table(const char *cs) + { + create_table(t, cs); + } + + void create_table(const Table_ref &t, const char *cs) + { + do_sql( + string(L"drop table if exists ") + + L"`" + t.schema()->name() + L"`.`" + t.name() + L"`"); + do_sql( + string(L"create table ") + + L"`" + t.schema()->name() + L"`.`" + t.name() + L"`" + + L"(c text character set " + string(cs) + L")" + ); + } + + void insert_string(const string &val) + { + insert_string(t, val); + } + + void insert_string(const Table_ref &t, const string &val) + { + do_sql( + string(L"insert into ") + + L"`" + t.schema()->name() + L"`.`" + t.name() + L"`" + + L" values ('" + val + L"')" + ); + } + +}; + + +// Note: samples taken from foundation codec_t test. + +#define SAMPLES(X) \ + X (polish, "latin2", L"Mog\u0119 je\u015B\u0107 szk\u0142o", \ + "\x4D\x6F\x67\xC4\x99\x20\x6A\x65\xC5\x9B\xC4\x87\x20\x73\x7A\x6B\xC5\x82\x6F") \ + X (japaneese, "ujis", L"\u79C1\u306F\u30AC\u30E9\u30B9\u3092\u98DF\u3079\u3089\u308C\u307E\u3059\u3002\u305D\u308C\u306F\u79C1\u3092\u50B7\u3064\u3051\u307E\u305B\u3093\u3002", \ + "\xE7\xA7\x81\xE3\x81\xAF\xE3\x82\xAC\xE3\x83\xA9\xE3\x82\xB9\xE3\x82\x92\xE9\xA3\x9F\xE3\x81\xB9\xE3\x82\x89\xE3\x82\x8C\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82\xE3\x81\x9D\xE3\x82\x8C\xE3\x81\xAF\xE7\xA7\x81\xE3\x82\x92\xE5\x82\xB7\xE3\x81\xA4\xE3\x81\x91\xE3\x81\xBE\xE3\x81\x9B\xE3\x82\x93\xE3\x80\x82") \ + X (ukrainian, "koi8u", L"\u042F \u043C\u043E\u0436\u0443 \u0457\u0441\u0442\u0438 \u0441\u043A\u043B\u043E, \u0456 \u0432\u043E\u043D\u043E \u043C\u0435\u043D\u0456 \u043D\u0435 \u0437\u0430\u0448\u043A\u043E\u0434\u0438\u0442\u044C", \ + "\xD0\xAF\x20\xD0\xBC\xD0\xBE\xD0\xB6\xD1\x83\x20\xD1\x97\xD1\x81\xD1\x82\xD0\xB8\x20\xD1\x81\xD0\xBA\xD0\xBB\xD0\xBE\x2C\x20\xD1\x96\x20\xD0\xB2\xD0\xBE\xD0\xBD\xD0\xBE\x20\xD0\xBC\xD0\xB5\xD0\xBD\xD1\x96\x20\xD0\xBD\xD0\xB5\x20\xD0\xB7\xD0\xB0\xD1\x88\xD0\xBA\xD0\xBE\xD0\xB4\xD0\xB8\xD1\x82\xD1\x8C") \ + X (portuguese, "latin1", L"Posso comer vidro, n\u00E3o me faz mal", \ + "\x50\x6F\x73\x73\x6F\x20\x63\x6F\x6D\x65\x72\x20\x76\x69\x64\x72\x6F\x2C\x20\x6E\xC3\xA3\x6F\x20\x6D\x65\x20\x66\x61\x7A\x20\x6D\x61\x6C") + + +TEST_F(Result_cs, strings) +{ + SKIP_IF_NO_XPLUGIN; + + try + { + cout << "== CHECK 1 ==" << endl; + +#define CHECK1(NAME,CS,WIDE,UTF) check1(CS,WIDE); + + SAMPLES(CHECK1) + + cout <::to_bytes(const string &in, bytes out) -{ - codecvt_utf8::state_type state; - const char_t *in_next; - char *out_next; - - std::codecvt_base::result res= - m_codec.out(state, &in[0], &in[in.length()], in_next, - (char*)out.begin(), (char*)out.end(), out_next); - - if (std::codecvt_base::ok != res) - THROW("conversion error"); // TODO: report errors - - assert((byte*)out_next >= out.begin()); - return static_cast((byte*)out_next - out.begin()); -} - - -size_t Codec::from_bytes(bytes in, string &out) -{ - codecvt_utf8::state_type state; - const char *in_next; - char_t *out_next; - - out.resize(in.size()+1); - std::codecvt_base::result res= - m_codec.in(state, (char*)in.begin(), (char*)in.end(), in_next, - &out[0], &out[in.size()], out_next); - - if (std::codecvt_base::ok != res) - THROW("conversion error"); // TODO: report errors - - assert(out_next >= &out[0]); - out.resize(static_cast(out_next - &out[0])); - - assert((byte*)in_next >= in.begin()); - return static_cast((byte*)in_next - in.begin()); -} - - string& string::set_utf8(const std::string &str) { Codec codec; @@ -182,3 +142,72 @@ codecvt_utf8::do_in(state_type& state, #endif +namespace cdk { +namespace foundation { + +codecvt_ascii::result +codecvt_ascii::do_out(state_type& state, + const intern_type* from, + const intern_type* from_end, + const intern_type*& from_next, + extern_type* to, + extern_type* to_end, + extern_type*& to_next ) const +{ + from_next = from; + to_next = to; + + while (from_next < from_end) + { + int c = m_ctype.narrow(*from_next, -1); + + if (-1 == c) + return error; + + *to_next = (extern_type)c; + to_next++; + from_next++; + } + + return ok; +} + + +codecvt_ascii::result +codecvt_ascii::do_in(state_type& state, + const extern_type* from, + const extern_type* from_end, + const extern_type*& from_next, + intern_type* to, + intern_type* to_end, + intern_type*& to_next ) const +{ + from_next = from; + to_next = to; + + while (from_next < from_end) + { + unsigned char c = (unsigned char)*from_next; + + /* + Note: In absence of character encoding information, only ASCII + characters can be reliably converted to wide chars by + ctype::widen() method. + */ + if (c > 128) + return error; + + intern_type wc = m_ctype.widen(*from_next); + + if (-1 == wc) + return error; + + *to_next = wc; + to_next++; + from_next++; + } + + return ok; +} + +}} // cdk::foundation diff --git a/cdk/include/mysql/cdk/codec.h b/cdk/include/mysql/cdk/codec.h index 2d8a6e3cd..bdd0f5ee2 100644 --- a/cdk/include/mysql/cdk/codec.h +++ b/cdk/include/mysql/cdk/codec.h @@ -183,6 +183,8 @@ class Format : public Format_base bool is_enum() const { return m_kind == ENUM; } bool is_set() const { return m_kind == SET; } + foundation::api::String_codec *codec() const; + protected: // Character set encoding. @@ -274,9 +276,20 @@ class Codec : public foundation::api::String_codec , Codec_base { +// foundation::api::String_codec *m_codec; + + foundation::api::String_codec& get_codec() + { + foundation::api::String_codec *codec = m_fmt.codec(); + if (!codec) + throw_error("undefined string conversion"); + return *codec; + } + public: - Codec(const Format_info &fi) : Codec_base(fi) + Codec(const Format_info &fi) + : Codec_base(fi) { /* FIXME: Currently we ignore character set information and try to diff --git a/cdk/include/mysql/cdk/foundation/codec.h b/cdk/include/mysql/cdk/foundation/codec.h index af1281a0c..182c41a6a 100644 --- a/cdk/include/mysql/cdk/foundation/codec.h +++ b/cdk/include/mysql/cdk/foundation/codec.h @@ -48,16 +48,28 @@ POP_BOOST_WARNINGS namespace cdk { namespace foundation { -#ifdef HAVE_CODECVT_UTF8 -typedef std::codecvt_utf8 codecvt_utf8; -#else - /* Note: the third codecvt template parameter (conversion state type) - probably has to be std::mbstate_t if this codec should work with + probably has to be std::mbstate_t if derived codecs should work with C++ I/O streams (via imbue() method). */ + +#ifdef HAVE_CODECVT_UTF8 + +class codecvt_utf8 : public std::codecvt_utf8 +{ +public: + + size_t measure(const string& str) const + { + THROW("codecvt_utf8: measure() not yet implemented"); + } + +}; + +#else + class codecvt_utf8 : public std::codecvt { result do_out( state_type& state, @@ -75,10 +87,59 @@ class codecvt_utf8 : public std::codecvt intern_type* to, intern_type* to_end, intern_type*& to_next ) const; + +public: + + size_t measure(const string& str) const + { + THROW("codecvt_utf8: measure() not yet implemented"); + } + }; #endif + +class codecvt_ascii : public std::codecvt +{ + result do_out( state_type& state, + const intern_type* from, + const intern_type* from_end, + const intern_type*& from_next, + extern_type* to, + extern_type* to_end, + extern_type*& to_next ) const; + + result do_in( state_type& state, + const extern_type* from, + const extern_type* from_end, + const extern_type*& from_next, + intern_type* to, + intern_type* to_end, + intern_type*& to_next ) const; + + /* + Note: At least in VS, dtor of std::ctype<> is protected and for + that reason we can not have direct instance of std::ctype<>. + */ + + struct : public std::ctype< wchar_t > + {} + m_ctype; + +public: + + codecvt_ascii() + {} + + size_t measure(const string& str) const + { + return str.length(); + } + +}; + + }} // cdk::foundation @@ -111,6 +172,7 @@ class String_codec virtual ~String_codec() {} + virtual size_t measure(const string&) =0; virtual size_t from_bytes(bytes, string&) =0; virtual size_t to_bytes(const string&, bytes) =0; }; @@ -118,23 +180,73 @@ class String_codec } // api namespace - -// String utf8 codec - -template<> -class Codec : public api::String_codec +template +class String_codec : public api::String_codec { - codecvt_utf8 m_codec; + VT m_codec; public: + String_codec() + {} + typedef cdk::foundation::char_t char_t; - size_t from_bytes(bytes, string &); - size_t to_bytes(const string&, bytes); + size_t measure(const string &in) + { + return m_codec.measure(in); + } + + size_t from_bytes(bytes in, string &out) + { + typename VT::state_type state; + const char *in_next; + char_t *out_next; + + out.resize(in.size()+1); + std::codecvt_base::result res= + m_codec.in(state, (char*)in.begin(), (char*)in.end(), in_next, + &out[0], &out[in.size()], out_next); + + if (std::codecvt_base::ok != res) + throw_error("string conversion error"); // TODO: report errors + + assert(out_next >= &out[0]); + out.resize(static_cast(out_next - &out[0])); + + assert((byte*)in_next >= in.begin()); + return static_cast((byte*)in_next - in.begin()); + } + + + size_t to_bytes(const string &in, bytes out) + { + typename VT::state_type state; + const char_t *in_next; + char *out_next; + + std::codecvt_base::result res= + m_codec.out(state, &in[0], &in[in.length()], in_next, + (char*)out.begin(), (char*)out.end(), out_next); + + if (std::codecvt_base::ok != res) + throw_error("string conversion error"); // TODO: report errors + + assert((byte*)out_next >= out.begin()); + return static_cast((byte*)out_next - out.begin()); + } + }; +// String utf8 codec + +template<> +class Codec : public String_codec +{}; + + + #undef BIG_ENDIAN #if BOOST_ENDIAN_BIG_BYTE From 3e1a89218b68989864b80df0709d6708a2269b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Wed, 30 Nov 2016 17:24:37 +0000 Subject: [PATCH 23/79] Fix windows Build. --- include/mysql_devapi.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 7c0dc656f..bb684cba0 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -505,7 +505,7 @@ class PUBLIC_API Table @ingroup devapi */ -class SessionSettings +class PUBLIC_API SessionSettings { public: enum Options @@ -911,9 +911,14 @@ class PUBLIC_API XSession public: - template - XSession(S...settings) - : XSession_base(settings...) + XSession(SessionSettings settings) + : XSession_base(settings) + {} + + + template + XSession(T...options) + : XSession_base(SessionSettings(options...)) {} @@ -949,9 +954,14 @@ class PUBLIC_API NodeSession as XSession constructors. */ + NodeSession(SessionSettings settings) + : XSession_base(settings) + {} + + template - NodeSession(T... args) - : XSession_base(args...) + NodeSession(T...options) + : XSession_base(SessionSettings(options...)) {} From 5f741051ad9bc593730e682e48906aa9bda92188 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 1 Dec 2016 12:08:17 +0100 Subject: [PATCH 24/79] CDK: Fix compile warning. --- cdk/include/mysql/cdk/foundation/codec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdk/include/mysql/cdk/foundation/codec.h b/cdk/include/mysql/cdk/foundation/codec.h index 182c41a6a..381ce7c5d 100644 --- a/cdk/include/mysql/cdk/foundation/codec.h +++ b/cdk/include/mysql/cdk/foundation/codec.h @@ -90,7 +90,7 @@ class codecvt_utf8 : public std::codecvt public: - size_t measure(const string& str) const + size_t measure(const string&) const { THROW("codecvt_utf8: measure() not yet implemented"); } From b8399f1a6eb8f15fe19f14ac22d587a7dc6dc6a2 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 2 Dec 2016 08:11:41 +0100 Subject: [PATCH 25/79] CDK: Fixes for string handling. --- cdk/core/codec.cc | 15 ++++++++------- cdk/include/mysql/cdk/codec.h | 20 ++------------------ cdk/include/mysql/cdk/mysqlx/session.h | 7 +++++++ 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/cdk/core/codec.cc b/cdk/core/codec.cc index a136f87e8..088f4802b 100644 --- a/cdk/core/codec.cc +++ b/cdk/core/codec.cc @@ -62,8 +62,7 @@ size_t cdk::Codec::to_bytes(const std::string &str, bytes raw) size_t Codec::measure(const string &str) { - // add 1 for the trailing 0x00 byte - return 1 + get_codec().measure(str); + return get_codec().measure(str); } @@ -71,8 +70,12 @@ size_t Codec::from_bytes(bytes raw, string &str) { //TODO: padding - // using string object, no need to have NULL char terminator - // remove NULL char terminator if present + /* + Note: xprotocol adds 0x00 byte at the end of bytes encoding + a string to distinguisht the empty string from the null value. + When decoding, we strip the extra 0x00 byte at the end, if present. + */ + return get_codec().from_bytes(bytes(raw.begin(), ( raw.size() > 0 && *(raw.end()-1) == '\0') ? raw.end()-1 : @@ -81,10 +84,8 @@ size_t Codec::from_bytes(bytes raw, string &str) } -size_t Codec::to_bytes(const string& str,bytes raw) +size_t Codec::to_bytes(const string& str, bytes raw) { - // FIXME: should we add the trailing 0x00 byte here, or is it done by - // foundation codecs? return get_codec().to_bytes(str, raw); } diff --git a/cdk/include/mysql/cdk/codec.h b/cdk/include/mysql/cdk/codec.h index bdd0f5ee2..b70c60155 100644 --- a/cdk/include/mysql/cdk/codec.h +++ b/cdk/include/mysql/cdk/codec.h @@ -276,7 +276,6 @@ class Codec : public foundation::api::String_codec , Codec_base { -// foundation::api::String_codec *m_codec; foundation::api::String_codec& get_codec() { @@ -290,24 +289,9 @@ class Codec Codec(const Format_info &fi) : Codec_base(fi) - { - /* - FIXME: Currently we ignore character set information and try to - decode string data as if it was utf8. But this fails miserably if - string data is in another multibyte encoding or if non-ascii characters - are used. However, we do not throw error yet as this would break all - our unit tests (and render CDK almost unusable, given that MySQL default - charset is latin1). - - if (Charset::utf8 != m_fmt.charset()) - throw_error("Non utf-8 character encodings are not supported yet"); - */ - } + {} - /** - Return number of bytes required to encode given string (including - the trailing 0x00 - */ + /// Return number of bytes required to encode given string. size_t measure(const string&); size_t from_bytes(bytes raw, string& str); diff --git a/cdk/include/mysql/cdk/mysqlx/session.h b/cdk/include/mysql/cdk/mysqlx/session.h index cabd5031b..6f7579d53 100644 --- a/cdk/include/mysql/cdk/mysqlx/session.h +++ b/cdk/include/mysql/cdk/mysqlx/session.h @@ -130,6 +130,13 @@ class Obj_ref : public Base inline cdk::Charset::value get_collation_cs(collation_id_t id) { + /* + If collation id is 0, that is, there is no collation info in server + reply, we assume utf8. + */ + + if (0 == id) + return cdk::Charset::utf8; #undef CS #define COLL_TO_CS(CS) COLLATIONS_##CS(COLL_TO_CS_CASE) return cdk::Charset::CS; From daacba681221fca6fc8b26e9e25ddc156edd0821 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 2 Dec 2016 08:13:45 +0100 Subject: [PATCH 26/79] MYCPP-287: MySQL character sets support. This patch integrates changes from CDK. After these changes CDK string codec is looking at the character set used to encode a string and throws errors for charsets that it can not handle. Currently this is all non-utf8 charsets unless the string consists of ascii chars only. --- devapi/result.cc | 128 ++++++---- devapi/tests/crud-t.cc | 17 ++ devapi/tests/types-t.cc | 34 ++- include/devapi/CMakeLists.txt | 2 +- include/devapi/collations.h | 389 +----------------------------- include/devapi/mysql_charsets.h | 78 ++++++ include/devapi/mysql_collations.h | 348 ++++++++++++++++++++++++++ 7 files changed, 554 insertions(+), 442 deletions(-) create mode 100644 include/devapi/mysql_charsets.h create mode 100644 include/devapi/mysql_collations.h diff --git a/devapi/result.cc b/devapi/result.cc index d11ecf3c7..8a4f5e881 100644 --- a/devapi/result.cc +++ b/devapi/result.cc @@ -386,6 +386,7 @@ class Column::Impl : public Format_info unsigned long m_length; unsigned short m_decimals; + cdk::collation_id_t m_collation; template Impl(const T &init) : Format_info(init) @@ -405,6 +406,7 @@ class Column::Impl : public Format_info m_schema_name = ci.table()->schema()->name(); } + m_collation = ci.collation(); m_length = ci.length(); assert(ci.decimals() < std::numeric_limits::max()); m_decimals = static_cast(ci.decimals()); @@ -604,11 +606,11 @@ bool Column::isPadded() const #define COLL_SWITCH(CS,ID,COLL,CASE) \ case ID: return Collation::COLL_CONST_NAME(COLL,CASE); -const CollationInfo& collation_from_charset_id(cdk::charset_id_t id) +const CollationInfo& collation_from_id(cdk::collation_id_t id) { switch (id) { - CS_LIST(CS_SWITCH) + CDK_CS_LIST(CS_SWITCH) default: THROW("Unknown collation id"); } @@ -630,8 +632,7 @@ const CollationInfo& Column::getCollation() const case cdk::TYPE_STRING: { - const Format_descr &fd = m_impl->get(); - return collation_from_charset_id(fd.m_format.charset()); + return collation_from_id(m_impl->m_collation); } case cdk::TYPE_INTEGER: @@ -646,6 +647,8 @@ const CollationInfo& Column::getCollation() const CharacterSet Column::getCharacterSet() const { + // TODO: Better use cdk encoding format information + //const Format_descr &fd = m_impl->get(); return getCollation().getCharacterSet(); } @@ -687,7 +690,7 @@ Collation::COLL_CONST_NAME(COLL,CASE) = \ #define COLL_NAME_ci(CS,COLL) #CS "_" #COLL "_ci" #define COLL_NAME_cs(CS,COLL) #CS "_" #COLL "_cs" -CS_LIST(COLL_DEFS) +CDK_CS_LIST(COLL_DEFS) /* @@ -785,15 +788,25 @@ const Row::Impl& Row::get_impl() const col_count_t Row::colCount() const { - const Impl &impl = get_impl(); - col_count_t cnt = (impl.m_mdata ? impl.m_mdata->col_count() : 0); - return impl.m_col_count > cnt ? impl.m_col_count : cnt; + try { + const Impl &impl = get_impl(); + col_count_t cnt = (impl.m_mdata ? impl.m_mdata->col_count() : 0); + return impl.m_col_count > cnt ? impl.m_col_count : cnt; + } + CATCH_AND_WRAP } bytes Row::getBytes(col_count_t pos) const { - return get_impl().get_bytes(pos); + try { + return get_impl().get_bytes(pos); + } + catch (const std::out_of_range&) + { + throw; + } + CATCH_AND_WRAP } @@ -828,68 +841,77 @@ Value& Row::get(mysqlx::col_count_t pos) */ try { - // will throw out_of_range exception if column at `pos` is NULL - bytes data = getBytes(pos); - switch (impl.m_mdata->get_type(pos)) - { - case cdk::TYPE_STRING: return impl.get(pos); - case cdk::TYPE_INTEGER: return impl.get(pos); - case cdk::TYPE_FLOAT: return impl.get(pos); - case cdk::TYPE_DOCUMENT: return impl.get(pos); + try { + // will throw out_of_range exception if column at `pos` is NULL + bytes data = getBytes(pos); - /* - TODO: Other "natural" conversions - TODO: User-defined conversions (also to user-defined types) - */ + switch (impl.m_mdata->get_type(pos)) + { + case cdk::TYPE_STRING: return impl.get(pos); + case cdk::TYPE_INTEGER: return impl.get(pos); + case cdk::TYPE_FLOAT: return impl.get(pos); + case cdk::TYPE_DOCUMENT: return impl.get(pos); - case cdk::TYPE_BYTES: + /* + TODO: Other "natural" conversions + TODO: User-defined conversions (also to user-defined types) + */ - /* - Note: in case of raw bytes, we trim the extra 0x00 byte added - at the end by the protocol (to handle NULL values). - */ + case cdk::TYPE_BYTES: - return set(pos, bytes(data.begin(), data.end() - 1)); + /* + Note: in case of raw bytes, we trim the extra 0x00 byte added + at the end by the protocol (to handle NULL values). + */ - default: + return set(pos, bytes(data.begin(), data.end() - 1)); - /* - For all types for which we do not have a natural conversion - to C++ type, we return raw bytes representing the value as - returned by protocol. - */ + default: - return set(pos, data); + /* + For all types for which we do not have a natural conversion + to C++ type, we return raw bytes representing the value as + returned by protocol. + */ + + return set(pos, data); + } } + catch (std::out_of_range&) + { + // set to NULL + return set(pos, Value()); + } + } - catch (std::out_of_range&) - { - // set to NULL - return set(pos, Value()); - } + CATCH_AND_WRAP } Value& Row::set(col_count_t pos, const Value &val) { - if (!m_impl) - m_impl = std::make_shared(); + try { + if (!m_impl) + m_impl = std::make_shared(); - Impl &impl = get_impl(); + Impl &impl = get_impl(); - impl.m_vals.emplace(pos, val); + impl.m_vals.emplace(pos, val); - if (pos + 1 > impl.m_col_count) - impl.m_col_count = pos + 1; + if (pos + 1 > impl.m_col_count) + impl.m_col_count = pos + 1; - return impl.m_vals.at(pos); + return impl.m_vals.at(pos); + } + CATCH_AND_WRAP } void Row::clear() { - m_impl.reset(); + try { m_impl.reset(); } + CATCH_AND_WRAP } @@ -906,14 +928,22 @@ template<> const Value Row::Impl::convert(cdk::bytes data, Format_descr &fd) const { + /* + String encoding has artificial 0x00 byte appended at the end to + distinguish the empty string from the null value. We skip + the trailing 0x00 byte to get just the raw bytes that encode the string. + */ + + cdk::bytes raw(data.begin(), data.end() - 1); + // If this string value is in fact a SET, then return it as raw bytes. if (fd.m_format.is_set()) - return Value(bytes(data.begin(), data.end())); + return Value(bytes(raw.begin(), raw.end())); auto &codec = fd.m_codec; cdk::string str; - codec.from_bytes(data, str); + codec.from_bytes(raw, str); return Value(std::move(str)); } diff --git a/devapi/tests/crud-t.cc b/devapi/tests/crud-t.cc index f42f01f71..892f4af6e 100644 --- a/devapi/tests/crud-t.cc +++ b/devapi/tests/crud-t.cc @@ -34,6 +34,23 @@ using namespace mysqlx; class Crud : public mysqlx::test::Xplugin { public: + + void SetUp() + { + Xplugin::SetUp(); + + /* + Clear sql_mode to work around problems with how + xplugin handles group_by queries (the "only_full_group_by" + mode which is enabled by default). + */ + try { + get_sess().sql("set sql_mode=''").execute(); + } + catch (...) + {} + } + void add_data(Collection &coll); }; diff --git a/devapi/tests/types-t.cc b/devapi/tests/types-t.cc index a16c1e0a3..e93bc1431 100644 --- a/devapi/tests/types-t.cc +++ b/devapi/tests/types-t.cc @@ -398,27 +398,17 @@ TEST_F(Types, string) sql( "CREATE TABLE test.types(" " c0 VARCHAR(10) COLLATE latin2_general_ci," - " c1 VARCHAR(32) COLLATE utf8_swedish_ci" + " c1 VARCHAR(32) COLLATE utf8_swedish_ci," + " c2 VARCHAR(32) CHARACTER SET latin2" ")" ); Table types = getSchema("test").getTable("types"); - /* - FIXME: For table columns using non utf8 encoding, any non-ascii - characters are returned by xplugin using the column encoding. This - causes errors when reading data because we asssume xplugin - sends strings using utf8 encoding. Check X protocol specs. - - When this is fixed, the first string should use some non-ascii - characters that can be represented in latin2 (str0 can be made - the same as str1). - */ - string str0(L"Foobar"); string str1(L"Mog\u0119 je\u015B\u0107 szk\u0142o"); - types.insert().values(str0, str1).execute(); + types.insert().values(str0, str1, str1).execute(); cout << "Table prepared, querying it..." << endl; @@ -449,10 +439,28 @@ TEST_F(Types, string) EXPECT_EQ(CharacterSet::utf8, c1.getCharacterSet()); EXPECT_EQ(Collation::swedish_ci, c1.getCollation()); + Column c2 = res.getColumn(2); + EXPECT_EQ(Type::STRING, c2.getType()); + cout << "column #2 length: " << c2.getLength() << endl; + cout << "column #2 charset: " << c2.getCharacterSetName() << endl; + cout << "column #2 collation: " << c2.getCollationName() << endl; + + EXPECT_EQ(CharacterSet::latin2, c2.getCharacterSet()); + Row row = res.fetchOne(); EXPECT_EQ(str0, (string)row[0]); EXPECT_EQ(str1, (string)row[1]); + + /* + FIXME: the third colum contains non-utf8 string which uses non-ascii + characters. Currently we do not handle such strings and an error is + thrown on an attempt of converting it to a C++ string. + + Replace with EXPECT_EQ() once we handle all MySQL charsets. + */ + + EXPECT_THROW((string)row[2], Error); } diff --git a/include/devapi/CMakeLists.txt b/include/devapi/CMakeLists.txt index 0df859ee9..253f083cf 100644 --- a/include/devapi/CMakeLists.txt +++ b/include/devapi/CMakeLists.txt @@ -22,7 +22,7 @@ SET(headers common.h result.h statement.h document.h crud.h collection_crud.h table_crud.h - collations.h) + collations.h mysql_charsets.h mysql_collations.h) ADD_HEADERS(${headers}) ADD_HEADER_CHECKS() diff --git a/include/devapi/collations.h b/include/devapi/collations.h index 8969013d5..a20d21b8e 100644 --- a/include/devapi/collations.h +++ b/include/devapi/collations.h @@ -28,84 +28,28 @@ #include "common.h" /* - List of built-in character sets and collations supported by version 5.7 - of MySQL Server. The lists are taken from: - - http://dev.mysql.com/doc/refman/5.7/en/charset-charsets.html + Import Lists of built-in character sets and collations supported by MySQL + Server. */ -namespace mysqlx { - -/** - This macro defines a list of known MySQL character set names. For each - character set name CS listed here, there is `CharacterSet::CS` constant - in the CharacterSet enumeration. For example constant `CharacterSet::latin1` - is the id of the "latin1" character set. - - @ingroup devapi_res -*/ +#include "mysql_charsets.h" +#include "mysql_collations.h" -#define CS_LIST(X) \ - X(big5) \ - X(dec8) \ - X(cp850) \ - X(hp8) \ - X(koi8r) \ - X(latin1) \ - X(latin2) \ - X(swe7) \ - X(ascii) \ - X(ujis) \ - X(sjis) \ - X(hebrew) \ - X(tis620) \ - X(euckr) \ - X(koi8u) \ - X(gb2312) \ - X(greek) \ - X(cp1250) \ - X(gbk) \ - X(latin5) \ - X(armscii8) \ - X(utf8) \ - X(ucs2) \ - X(cp866) \ - X(keybcs2) \ - X(macce) \ - X(macroman) \ - X(cp852) \ - X(latin7) \ - X(utf8mb4) \ - X(cp1251) \ - X(utf16) \ - X(utf16le) \ - X(cp1256) \ - X(cp1257) \ - X(utf32) \ - X(binary) \ - X(geostd8) \ - X(cp932) \ - X(eucjpms) \ - X(gb18030) \ - - -// Fix for Solaris build -#ifdef CS -# undef CS -#endif +namespace mysqlx { /* Enumeration of known character sets. For each character set CS listed - in CS_LIST() macro, there is CharacterSet::CS constant in this + in CDK_CS_LIST() macro, there is CharacterSet::CS constant in this enumeration. */ enum class CharacterSet : unsigned short { + #undef CS #define CS_ENUM(CS) CS, - CS_LIST(CS_ENUM) + CDK_CS_LIST(CS_ENUM) }; @@ -122,7 +66,7 @@ const char* characterSetName(CharacterSet id) { switch (id) { - CS_LIST(CS_NAME_SWITCH) + CDK_CS_LIST(CS_NAME_SWITCH) default: THROW("Unknown character set id"); } @@ -205,319 +149,6 @@ template struct Collation; respectively. */ -/** - @macro - Macro defining known collations for a given character set. - @{ -*/ - -#define COLLATIONS_big5(X) \ - X(big5,1,chinese,ci) \ - X(big5,84,bin,bin) \ - -#define COLLATIONS_dec8(X) \ - X(dec8,3,swedish,ci) \ - X(dec8,69,bin,bin) \ - -#define COLLATIONS_cp850(X) \ - X(cp850,4,general,ci) \ - X(cp850,80,bin,bin) \ - -#define COLLATIONS_hp8(X) \ - X(hp8,6,english,ci) \ - X(hp8,72,bin,bin) \ - -#define COLLATIONS_koi8r(X) \ - X(koi8r,7,general,ci) \ - X(koi8r,74,bin,bin) \ - -#define COLLATIONS_latin1(X) \ - X(latin1,5,german1,ci) \ - X(latin1,8,swedish,ci) \ - X(latin1,15,danish,ci) \ - X(latin1,31,german2,ci) \ - X(latin1,47,bin,bin) \ - X(latin1,48,general,ci) \ - X(latin1,49,general,cs) \ - X(latin1,94,spanish,ci) \ - -#define COLLATIONS_latin2(X) \ - X(latin2,2,czech,cs) \ - X(latin2,9,general,ci) \ - X(latin2,21,hungarian,ci) \ - X(latin2,27,croatian,ci) \ - X(latin2,77,bin,bin) \ - -#define COLLATIONS_swe7(X) \ - X(swe7,10,swedish,ci) \ - X(swe7,82,bin,bin) \ - -#define COLLATIONS_ascii(X) \ - X(ascii,11,general,ci) \ - X(ascii,65,bin,bin) \ - -#define COLLATIONS_ujis(X) \ - X(ujis,12,japanese,ci) \ - X(ujis,91,bin,bin) \ - -#define COLLATIONS_sjis(X) \ - X(sjis,13,japanese,ci) \ - X(sjis,88,bin,bin) \ - -#define COLLATIONS_hebrew(X) \ - X(hebrew,16,general,ci) \ - X(hebrew,71,bin,bin) \ - -#define COLLATIONS_tis620(X) \ - X(tis620,18,thai,ci) \ - X(tis620,89,bin,bin) \ - -#define COLLATIONS_euckr(X) \ - X(euckr,19,korean,ci) \ - X(euckr,85,bin,bin) \ - -#define COLLATIONS_koi8u(X) \ - X(koi8u,22,general,ci) \ - X(koi8u,75,bin,bin) \ - -#define COLLATIONS_gb2312(X) \ - X(gb2312,24,chinese,ci) \ - X(gb2312,86,bin,bin) \ - -#define COLLATIONS_greek(X) \ - X(greek,25,general,ci) \ - X(greek,70,bin,bin) \ - -#define COLLATIONS_cp1250(X) \ - X(cp1250,26,general,ci) \ - X(cp1250,34,czech,cs) \ - X(cp1250,44,croatian,ci) \ - X(cp1250,66,bin,bin) \ - X(cp1250,99,polish,ci) \ - -#define COLLATIONS_gbk(X) \ - X(gbk,28,chinese,ci) \ - X(gbk,87,bin,bin) \ - -#define COLLATIONS_latin5(X) \ - X(latin5,30,turkish,ci) \ - X(latin5,78,bin,bin) \ - -#define COLLATIONS_armscii8(X) \ - X(armscii8,32,general,ci) \ - X(armscii8,64,bin,bin) \ - -#define COLLATIONS_utf8(X) \ - X(utf8,33,general,ci) \ - X(utf8,83,bin,bin) \ - X(utf8,192,unicode,ci) \ - X(utf8,193,icelandic,ci) \ - X(utf8,194,latvian,ci) \ - X(utf8,195,romanian,ci) \ - X(utf8,196,slovenian,ci) \ - X(utf8,197,polish,ci) \ - X(utf8,198,estonian,ci) \ - X(utf8,199,spanish,ci) \ - X(utf8,200,swedish,ci) \ - X(utf8,201,turkish,ci) \ - X(utf8,202,czech,ci) \ - X(utf8,203,danish,ci) \ - X(utf8,204,lithuanian,ci) \ - X(utf8,205,slovak,ci) \ - X(utf8,206,spanish2,ci) \ - X(utf8,207,roman,ci) \ - X(utf8,208,persian,ci) \ - X(utf8,209,esperanto,ci) \ - X(utf8,210,hungarian,ci) \ - X(utf8,211,sinhala,ci) \ - X(utf8,212,german2,ci) \ - X(utf8,213,croatian,ci) \ - X(utf8,214,unicode_520,ci) \ - X(utf8,215,vietnamese,ci) \ - X(utf8,223,general_mysql500,ci) \ - -#define COLLATIONS_ucs2(X) \ - X(ucs2,35,general,ci) \ - X(ucs2,90,bin,bin) \ - X(ucs2,128,unicode,ci) \ - X(ucs2,129,icelandic,ci) \ - X(ucs2,130,latvian,ci) \ - X(ucs2,131,romanian,ci) \ - X(ucs2,132,slovenian,ci) \ - X(ucs2,133,polish,ci) \ - X(ucs2,134,estonian,ci) \ - X(ucs2,135,spanish,ci) \ - X(ucs2,136,swedish,ci) \ - X(ucs2,137,turkish,ci) \ - X(ucs2,138,czech,ci) \ - X(ucs2,139,danish,ci) \ - X(ucs2,140,lithuanian,ci) \ - X(ucs2,141,slovak,ci) \ - X(ucs2,142,spanish2,ci) \ - X(ucs2,143,roman,ci) \ - X(ucs2,144,persian,ci) \ - X(ucs2,145,esperanto,ci) \ - X(ucs2,146,hungarian,ci) \ - X(ucs2,147,sinhala,ci) \ - X(ucs2,148,german2,ci) \ - X(ucs2,149,croatian,ci) \ - X(ucs2,150,unicode_520,ci) \ - X(ucs2,151,vietnamese,ci) \ - X(ucs2,159,general_mysql500,ci) \ - -#define COLLATIONS_cp866(X) \ - X(cp866,36,general,ci) \ - X(cp866,68,bin,bin) \ - -#define COLLATIONS_keybcs2(X) \ - X(keybcs2,37,general,ci) \ - X(keybcs2,73,bin,bin) \ - -#define COLLATIONS_macce(X) \ - X(macce,38,general,ci) \ - X(macce,43,bin,bin) \ - -#define COLLATIONS_macroman(X) \ - X(macroman,39,general,ci) \ - X(macroman,53,bin,bin) \ - -#define COLLATIONS_cp852(X) \ - X(cp852,40,general,ci) \ - X(cp852,81,bin,bin) \ - -#define COLLATIONS_latin7(X) \ - X(latin7,20,estonian,cs) \ - X(latin7,41,general,ci) \ - X(latin7,42,general,cs) \ - X(latin7,79,bin,bin) \ - -#define COLLATIONS_utf8mb4(X) \ - X(utf8mb4,45,general,ci) \ - X(utf8mb4,46,bin,bin) \ - X(utf8mb4,224,unicode,ci) \ - X(utf8mb4,225,icelandic,ci) \ - X(utf8mb4,226,latvian,ci) \ - X(utf8mb4,227,romanian,ci) \ - X(utf8mb4,228,slovenian,ci) \ - X(utf8mb4,229,polish,ci) \ - X(utf8mb4,230,estonian,ci) \ - X(utf8mb4,231,spanish,ci) \ - X(utf8mb4,232,swedish,ci) \ - X(utf8mb4,233,turkish,ci) \ - X(utf8mb4,234,czech,ci) \ - X(utf8mb4,235,danish,ci) \ - X(utf8mb4,236,lithuanian,ci) \ - X(utf8mb4,237,slovak,ci) \ - X(utf8mb4,238,spanish2,ci) \ - X(utf8mb4,239,roman,ci) \ - X(utf8mb4,240,persian,ci) \ - X(utf8mb4,241,esperanto,ci) \ - X(utf8mb4,242,hungarian,ci) \ - X(utf8mb4,243,sinhala,ci) \ - X(utf8mb4,244,german2,ci) \ - X(utf8mb4,245,croatian,ci) \ - X(utf8mb4,246,unicode_520,ci) \ - X(utf8mb4,247,vietnamese,ci) \ - -#define COLLATIONS_cp1251(X) \ - X(cp1251,14,bulgarian,ci) \ - X(cp1251,23,ukrainian,ci) \ - X(cp1251,50,bin,bin) \ - X(cp1251,51,general,ci) \ - X(cp1251,52,general,cs) \ - -#define COLLATIONS_utf16(X) \ - X(utf16,54,general,ci) \ - X(utf16,55,bin,bin) \ - X(utf16,101,unicode,ci) \ - X(utf16,102,icelandic,ci) \ - X(utf16,103,latvian,ci) \ - X(utf16,104,romanian,ci) \ - X(utf16,105,slovenian,ci) \ - X(utf16,106,polish,ci) \ - X(utf16,107,estonian,ci) \ - X(utf16,108,spanish,ci) \ - X(utf16,109,swedish,ci) \ - X(utf16,110,turkish,ci) \ - X(utf16,111,czech,ci) \ - X(utf16,112,danish,ci) \ - X(utf16,113,lithuanian,ci) \ - X(utf16,114,slovak,ci) \ - X(utf16,115,spanish2,ci) \ - X(utf16,116,roman,ci) \ - X(utf16,117,persian,ci) \ - X(utf16,118,esperanto,ci) \ - X(utf16,119,hungarian,ci) \ - X(utf16,120,sinhala,ci) \ - X(utf16,121,german2,ci) \ - X(utf16,122,croatian,ci) \ - X(utf16,123,unicode_520,ci) \ - X(utf16,124,vietnamese,ci) \ - -#define COLLATIONS_utf16le(X) \ - X(utf16le,56,general,ci) \ - X(utf16le,62,bin,bin) \ - -#define COLLATIONS_cp1256(X) \ - X(cp1256,57,general,ci) \ - X(cp1256,67,bin,bin) \ - -#define COLLATIONS_cp1257(X) \ - X(cp1257,29,lithuanian,ci) \ - X(cp1257,58,bin,bin) \ - X(cp1257,59,general,ci) \ - -#define COLLATIONS_utf32(X) \ - X(utf32,60,general,ci) \ - X(utf32,61,bin,bin) \ - X(utf32,160,unicode,ci) \ - X(utf32,161,icelandic,ci) \ - X(utf32,162,latvian,ci) \ - X(utf32,163,romanian,ci) \ - X(utf32,164,slovenian,ci) \ - X(utf32,165,polish,ci) \ - X(utf32,166,estonian,ci) \ - X(utf32,167,spanish,ci) \ - X(utf32,168,swedish,ci) \ - X(utf32,169,turkish,ci) \ - X(utf32,170,czech,ci) \ - X(utf32,171,danish,ci) \ - X(utf32,172,lithuanian,ci) \ - X(utf32,173,slovak,ci) \ - X(utf32,174,spanish2,ci) \ - X(utf32,175,roman,ci) \ - X(utf32,176,persian,ci) \ - X(utf32,177,esperanto,ci) \ - X(utf32,178,hungarian,ci) \ - X(utf32,179,sinhala,ci) \ - X(utf32,180,german2,ci) \ - X(utf32,181,croatian,ci) \ - X(utf32,182,unicode_520,ci) \ - X(utf32,183,vietnamese,ci) \ - -#define COLLATIONS_binary(X) \ - X(binary,63,bin,bin) \ - -#define COLLATIONS_geostd8(X) \ - X(geostd8,92,general,ci) \ - X(geostd8,93,bin,bin) \ - -#define COLLATIONS_cp932(X) \ - X(cp932,95,japanese,ci) \ - X(cp932,96,bin,bin) \ - -#define COLLATIONS_eucjpms(X) \ - X(eucjpms,97,japanese,ci) \ - X(eucjpms,98,bin,bin) \ - -#define COLLATIONS_gb18030(X) \ - X(gb18030,248,chinese,ci) \ - X(gb18030,249,bin,bin) \ - X(gb18030,250,unicode_520,ci) \ - -/**@}*/ - - /* Generate declarations of Collation::COLL constants using COLLATINS_XXX() macros. The list CS_LIST() is processed using @@ -548,7 +179,7 @@ static PUBLIC_API const CollationInfo COLL_CONST_NAME(COLL,CASE); #define COLL_CONST_NAME_ci(COLL) COLL##_ci #define COLL_CONST_NAME_cs(COLL) COLL##_cs -CS_LIST(COLL_DECL) +CDK_CS_LIST(COLL_DECL) } // mysqlx diff --git a/include/devapi/mysql_charsets.h b/include/devapi/mysql_charsets.h new file mode 100644 index 000000000..d052281d1 --- /dev/null +++ b/include/devapi/mysql_charsets.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + Lists of character sets known to CDK string codec (see codec.h). + + Note: Keep this file in sync with +*/ + + +#ifndef MYSQLX_MYSQL_CHARSETS_H +#define MYSQLX_MYSQL_CHARSETS_H + +#define CDK_CS_LIST(X) \ + X(big5) \ + X(dec8) \ + X(cp850) \ + X(hp8) \ + X(koi8r) \ + X(latin1) \ + X(latin2) \ + X(swe7) \ + X(ascii) \ + X(ujis) \ + X(sjis) \ + X(hebrew) \ + X(tis620) \ + X(euckr) \ + X(koi8u) \ + X(gb2312) \ + X(greek) \ + X(cp1250) \ + X(gbk) \ + X(latin5) \ + X(armscii8) \ + X(utf8) \ + X(ucs2) \ + X(cp866) \ + X(keybcs2) \ + X(macce) \ + X(macroman) \ + X(cp852) \ + X(latin7) \ + X(utf8mb4) \ + X(cp1251) \ + X(utf16) \ + X(utf16le) \ + X(cp1256) \ + X(cp1257) \ + X(utf32) \ + X(binary) \ + X(geostd8) \ + X(cp932) \ + X(eucjpms) \ + X(gb18030) \ + +#endif diff --git a/include/devapi/mysql_collations.h b/include/devapi/mysql_collations.h new file mode 100644 index 000000000..12891c951 --- /dev/null +++ b/include/devapi/mysql_collations.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + Lists of collations used by MySQL Server and its protocols. These lists + define mapping from MySQL collation ID to charset ID. + + Note: Keep this file in sync with +*/ + +#ifndef MYSQLX_MYSQL_COLLATIONS_H +#define MYSQLX_MYSQL_COLLATIONS_H + +/* + Each line X(CS, ID, COLL, CASE) in the expansion of + a COLLATION_XXX() macro declares collation with name COLL for character set + CS. ID is the MySQL id number for the collation. CASE is one of ci, cs or bin + and indicates whether it is case insensitive, sensitive or binary collation, + respectively. +*/ + +#define COLLATIONS_big5(X) \ + X(big5,1,chinese,ci) \ + X(big5,84,bin,bin) \ + +#define COLLATIONS_dec8(X) \ + X(dec8,3,swedish,ci) \ + X(dec8,69,bin,bin) \ + +#define COLLATIONS_cp850(X) \ + X(cp850,4,general,ci) \ + X(cp850,80,bin,bin) \ + +#define COLLATIONS_hp8(X) \ + X(hp8,6,english,ci) \ + X(hp8,72,bin,bin) \ + +#define COLLATIONS_koi8r(X) \ + X(koi8r,7,general,ci) \ + X(koi8r,74,bin,bin) \ + +#define COLLATIONS_latin1(X) \ + X(latin1,5,german1,ci) \ + X(latin1,8,swedish,ci) \ + X(latin1,15,danish,ci) \ + X(latin1,31,german2,ci) \ + X(latin1,47,bin,bin) \ + X(latin1,48,general,ci) \ + X(latin1,49,general,cs) \ + X(latin1,94,spanish,ci) \ + +#define COLLATIONS_latin2(X) \ + X(latin2,2,czech,cs) \ + X(latin2,9,general,ci) \ + X(latin2,21,hungarian,ci) \ + X(latin2,27,croatian,ci) \ + X(latin2,77,bin,bin) \ + +#define COLLATIONS_swe7(X) \ + X(swe7,10,swedish,ci) \ + X(swe7,82,bin,bin) \ + +#define COLLATIONS_ascii(X) \ + X(ascii,11,general,ci) \ + X(ascii,65,bin,bin) \ + +#define COLLATIONS_ujis(X) \ + X(ujis,12,japanese,ci) \ + X(ujis,91,bin,bin) \ + +#define COLLATIONS_sjis(X) \ + X(sjis,13,japanese,ci) \ + X(sjis,88,bin,bin) \ + +#define COLLATIONS_hebrew(X) \ + X(hebrew,16,general,ci) \ + X(hebrew,71,bin,bin) \ + +#define COLLATIONS_tis620(X) \ + X(tis620,18,thai,ci) \ + X(tis620,89,bin,bin) \ + +#define COLLATIONS_euckr(X) \ + X(euckr,19,korean,ci) \ + X(euckr,85,bin,bin) \ + +#define COLLATIONS_koi8u(X) \ + X(koi8u,22,general,ci) \ + X(koi8u,75,bin,bin) \ + +#define COLLATIONS_gb2312(X) \ + X(gb2312,24,chinese,ci) \ + X(gb2312,86,bin,bin) \ + +#define COLLATIONS_greek(X) \ + X(greek,25,general,ci) \ + X(greek,70,bin,bin) \ + +#define COLLATIONS_cp1250(X) \ + X(cp1250,26,general,ci) \ + X(cp1250,34,czech,cs) \ + X(cp1250,44,croatian,ci) \ + X(cp1250,66,bin,bin) \ + X(cp1250,99,polish,ci) \ + +#define COLLATIONS_gbk(X) \ + X(gbk,28,chinese,ci) \ + X(gbk,87,bin,bin) \ + +#define COLLATIONS_latin5(X) \ + X(latin5,30,turkish,ci) \ + X(latin5,78,bin,bin) \ + +#define COLLATIONS_armscii8(X) \ + X(armscii8,32,general,ci) \ + X(armscii8,64,bin,bin) \ + +#define COLLATIONS_utf8(X) \ + X(utf8,33,general,ci) \ + X(utf8,83,bin,bin) \ + X(utf8,192,unicode,ci) \ + X(utf8,193,icelandic,ci) \ + X(utf8,194,latvian,ci) \ + X(utf8,195,romanian,ci) \ + X(utf8,196,slovenian,ci) \ + X(utf8,197,polish,ci) \ + X(utf8,198,estonian,ci) \ + X(utf8,199,spanish,ci) \ + X(utf8,200,swedish,ci) \ + X(utf8,201,turkish,ci) \ + X(utf8,202,czech,ci) \ + X(utf8,203,danish,ci) \ + X(utf8,204,lithuanian,ci) \ + X(utf8,205,slovak,ci) \ + X(utf8,206,spanish2,ci) \ + X(utf8,207,roman,ci) \ + X(utf8,208,persian,ci) \ + X(utf8,209,esperanto,ci) \ + X(utf8,210,hungarian,ci) \ + X(utf8,211,sinhala,ci) \ + X(utf8,212,german2,ci) \ + X(utf8,213,croatian,ci) \ + X(utf8,214,unicode_520,ci) \ + X(utf8,215,vietnamese,ci) \ + X(utf8,223,general_mysql500,ci) \ + +#define COLLATIONS_ucs2(X) \ + X(ucs2,35,general,ci) \ + X(ucs2,90,bin,bin) \ + X(ucs2,128,unicode,ci) \ + X(ucs2,129,icelandic,ci) \ + X(ucs2,130,latvian,ci) \ + X(ucs2,131,romanian,ci) \ + X(ucs2,132,slovenian,ci) \ + X(ucs2,133,polish,ci) \ + X(ucs2,134,estonian,ci) \ + X(ucs2,135,spanish,ci) \ + X(ucs2,136,swedish,ci) \ + X(ucs2,137,turkish,ci) \ + X(ucs2,138,czech,ci) \ + X(ucs2,139,danish,ci) \ + X(ucs2,140,lithuanian,ci) \ + X(ucs2,141,slovak,ci) \ + X(ucs2,142,spanish2,ci) \ + X(ucs2,143,roman,ci) \ + X(ucs2,144,persian,ci) \ + X(ucs2,145,esperanto,ci) \ + X(ucs2,146,hungarian,ci) \ + X(ucs2,147,sinhala,ci) \ + X(ucs2,148,german2,ci) \ + X(ucs2,149,croatian,ci) \ + X(ucs2,150,unicode_520,ci) \ + X(ucs2,151,vietnamese,ci) \ + X(ucs2,159,general_mysql500,ci) \ + +#define COLLATIONS_cp866(X) \ + X(cp866,36,general,ci) \ + X(cp866,68,bin,bin) \ + +#define COLLATIONS_keybcs2(X) \ + X(keybcs2,37,general,ci) \ + X(keybcs2,73,bin,bin) \ + +#define COLLATIONS_macce(X) \ + X(macce,38,general,ci) \ + X(macce,43,bin,bin) \ + +#define COLLATIONS_macroman(X) \ + X(macroman,39,general,ci) \ + X(macroman,53,bin,bin) \ + +#define COLLATIONS_cp852(X) \ + X(cp852,40,general,ci) \ + X(cp852,81,bin,bin) \ + +#define COLLATIONS_latin7(X) \ + X(latin7,20,estonian,cs) \ + X(latin7,41,general,ci) \ + X(latin7,42,general,cs) \ + X(latin7,79,bin,bin) \ + +#define COLLATIONS_utf8mb4(X) \ + X(utf8mb4,45,general,ci) \ + X(utf8mb4,46,bin,bin) \ + X(utf8mb4,224,unicode,ci) \ + X(utf8mb4,225,icelandic,ci) \ + X(utf8mb4,226,latvian,ci) \ + X(utf8mb4,227,romanian,ci) \ + X(utf8mb4,228,slovenian,ci) \ + X(utf8mb4,229,polish,ci) \ + X(utf8mb4,230,estonian,ci) \ + X(utf8mb4,231,spanish,ci) \ + X(utf8mb4,232,swedish,ci) \ + X(utf8mb4,233,turkish,ci) \ + X(utf8mb4,234,czech,ci) \ + X(utf8mb4,235,danish,ci) \ + X(utf8mb4,236,lithuanian,ci) \ + X(utf8mb4,237,slovak,ci) \ + X(utf8mb4,238,spanish2,ci) \ + X(utf8mb4,239,roman,ci) \ + X(utf8mb4,240,persian,ci) \ + X(utf8mb4,241,esperanto,ci) \ + X(utf8mb4,242,hungarian,ci) \ + X(utf8mb4,243,sinhala,ci) \ + X(utf8mb4,244,german2,ci) \ + X(utf8mb4,245,croatian,ci) \ + X(utf8mb4,246,unicode_520,ci) \ + X(utf8mb4,247,vietnamese,ci) \ + +#define COLLATIONS_cp1251(X) \ + X(cp1251,14,bulgarian,ci) \ + X(cp1251,23,ukrainian,ci) \ + X(cp1251,50,bin,bin) \ + X(cp1251,51,general,ci) \ + X(cp1251,52,general,cs) \ + +#define COLLATIONS_utf16(X) \ + X(utf16,54,general,ci) \ + X(utf16,55,bin,bin) \ + X(utf16,101,unicode,ci) \ + X(utf16,102,icelandic,ci) \ + X(utf16,103,latvian,ci) \ + X(utf16,104,romanian,ci) \ + X(utf16,105,slovenian,ci) \ + X(utf16,106,polish,ci) \ + X(utf16,107,estonian,ci) \ + X(utf16,108,spanish,ci) \ + X(utf16,109,swedish,ci) \ + X(utf16,110,turkish,ci) \ + X(utf16,111,czech,ci) \ + X(utf16,112,danish,ci) \ + X(utf16,113,lithuanian,ci) \ + X(utf16,114,slovak,ci) \ + X(utf16,115,spanish2,ci) \ + X(utf16,116,roman,ci) \ + X(utf16,117,persian,ci) \ + X(utf16,118,esperanto,ci) \ + X(utf16,119,hungarian,ci) \ + X(utf16,120,sinhala,ci) \ + X(utf16,121,german2,ci) \ + X(utf16,122,croatian,ci) \ + X(utf16,123,unicode_520,ci) \ + X(utf16,124,vietnamese,ci) \ + +#define COLLATIONS_utf16le(X) \ + X(utf16le,56,general,ci) \ + X(utf16le,62,bin,bin) \ + +#define COLLATIONS_cp1256(X) \ + X(cp1256,57,general,ci) \ + X(cp1256,67,bin,bin) \ + +#define COLLATIONS_cp1257(X) \ + X(cp1257,29,lithuanian,ci) \ + X(cp1257,58,bin,bin) \ + X(cp1257,59,general,ci) \ + +#define COLLATIONS_utf32(X) \ + X(utf32,60,general,ci) \ + X(utf32,61,bin,bin) \ + X(utf32,160,unicode,ci) \ + X(utf32,161,icelandic,ci) \ + X(utf32,162,latvian,ci) \ + X(utf32,163,romanian,ci) \ + X(utf32,164,slovenian,ci) \ + X(utf32,165,polish,ci) \ + X(utf32,166,estonian,ci) \ + X(utf32,167,spanish,ci) \ + X(utf32,168,swedish,ci) \ + X(utf32,169,turkish,ci) \ + X(utf32,170,czech,ci) \ + X(utf32,171,danish,ci) \ + X(utf32,172,lithuanian,ci) \ + X(utf32,173,slovak,ci) \ + X(utf32,174,spanish2,ci) \ + X(utf32,175,roman,ci) \ + X(utf32,176,persian,ci) \ + X(utf32,177,esperanto,ci) \ + X(utf32,178,hungarian,ci) \ + X(utf32,179,sinhala,ci) \ + X(utf32,180,german2,ci) \ + X(utf32,181,croatian,ci) \ + X(utf32,182,unicode_520,ci) \ + X(utf32,183,vietnamese,ci) \ + +#define COLLATIONS_binary(X) \ + X(binary,63,bin,bin) \ + +#define COLLATIONS_geostd8(X) \ + X(geostd8,92,general,ci) \ + X(geostd8,93,bin,bin) \ + +#define COLLATIONS_cp932(X) \ + X(cp932,95,japanese,ci) \ + X(cp932,96,bin,bin) \ + +#define COLLATIONS_eucjpms(X) \ + X(eucjpms,97,japanese,ci) \ + X(eucjpms,98,bin,bin) \ + +#define COLLATIONS_gb18030(X) \ + X(gb18030,248,chinese,ci) \ + X(gb18030,249,bin,bin) \ + X(gb18030,250,unicode_520,ci) \ + + +#endif From e8192c63636671164cc846bab9e08e181509d0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 29 Nov 2016 12:31:31 +0000 Subject: [PATCH 27/79] MYC-375: CDK TLS Options implementation --- CMakeLists.txt | 16 ++- cdk/core/session.cc | 15 ++- cdk/core/tests/session-t.cc | 110 +++++++++++++++++- cdk/core/tests/test.h | 4 +- cdk/extra/yassl/src/ssl.cpp | 30 ++--- cdk/foundation/connection_yassl.cc | 53 +++++++-- cdk/include/mysql/cdk/data_source.h | 44 +++++-- cdk/include/mysql/cdk/foundation.h | 2 + .../mysql/cdk/foundation/connection_yassl.h | 36 +++++- cdk/include/mysql/cdk/session.h | 3 +- devapi/session.cc | 10 +- xapi/mysqlx_cc_internal.h | 8 +- 12 files changed, 279 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 092b2688c..69145605f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,8 +248,22 @@ SETUP_BOOST() SET(WITH_CDK_DOC 0) OPTION(WITH_CDK_TESTS "cdk tests" OFF) -#set(WITH_SSL OFF) set(WITH_PIC ${CMAKE_POSITION_INDEPENDENT_CODE}) + + +if(NOT DEFINED WITH_SSL) +SET(WITH_SSL "bundled" CACHE STRING "") +endif() + +IF(WITH_SSL) + IF(WITH_SSL STREQUAL "bundled") + ADD_DEFINITIONS(-DWITH_SSL_YASSL) + ENDIF() + ADD_DEFINITIONS(-DWITH_SSL) +ENDIF() + + + ADD_SUBDIRECTORY(cdk) INCLUDE_DIRECTORIES(${CDK_INCLUDE_DIR}) INCLUDE_DIRECTORIES(cdk/parser) diff --git a/cdk/core/session.cc b/cdk/core/session.cc index 4280098d9..ed0594044 100644 --- a/cdk/core/session.cc +++ b/cdk/core/session.cc @@ -30,7 +30,7 @@ namespace cdk { -Session::Session(ds::TCPIP &ds, const ds::Options &options) +Session::Session(ds::TCPIP &ds, const ds::TCPIP::Options &options) : m_session(NULL) , m_connection(NULL) , m_trans(false) @@ -49,11 +49,12 @@ Session::Session(ds::TCPIP &ds, const ds::Options &options) rethrow_error(); } + + if (options.get_tls().use_tls()) + { #ifdef WITH_SSL using foundation::connection::TLS; - if (options.use_tls()) - { // Negotiate TLS capabilities. cdk::protocol::mysqlx::Protocol proto(*connection); @@ -79,16 +80,18 @@ Session::Session(ds::TCPIP &ds, const ds::Options &options) } prc; proto.rcv_Reply(prc).wait(); - + // - TLS* tls = new TLS(connection); + TLS* tls = new TLS(connection, options.get_tls()); tls->connect(); m_connection = tls; m_session = new mysqlx::Session(*tls, options); +#else // WITH_SSL + throw Error("Connector doesn't support SSL connections"); +#endif } else -#endif // WITH_SSL { m_connection = connection; m_session = new mysqlx::Session(*connection, options); diff --git a/cdk/core/tests/session-t.cc b/cdk/core/tests/session-t.cc index 484b4e559..e69075c23 100644 --- a/cdk/core/tests/session-t.cc +++ b/cdk/core/tests/session-t.cc @@ -73,7 +73,7 @@ TEST_F(Session_core, basic) { ds::TCPIP ds("localhost", m_port); - ds::Options options("root"); + ds::TCPIP::Options options("root"); cdk::Session s1(ds, options); @@ -108,7 +108,7 @@ TEST_F(Session_core, default_schema) { ds::TCPIP ds("localhost", m_port); - ds::Options options("root"); + ds::TCPIP::Options options("root"); options.set_database("test"); cdk::Session s(ds, options); @@ -946,3 +946,109 @@ TEST_F(Session_core, docs) #endif + +TEST_F(Session_core, tls_options) +{ + SKIP_IF_NO_XPLUGIN; + + struct row_processor_variable + : cdk::Row_processor + { + row_processor_variable(std::string &variable) + : m_variable(variable) + {} + + virtual bool row_begin(row_count_t pos) + { + return true; + } + + virtual void row_end(row_count_t pos) {} + + virtual size_t field_begin(col_count_t pos, size_t data_len) + { + return data_len; + } + + virtual void field_end(col_count_t pos) {} + + virtual void field_null(col_count_t pos) {} + + virtual size_t field_data(col_count_t pos, bytes data) + { + if (pos == 1) + m_variable.assign(data.begin(), data.end()-1); + + return data.size(); + } + + virtual void end_of_data() {} + + std::string& m_variable; + + }; + + try + { + + ds::TCPIP ds("localhost", m_port); + ds::TCPIP::Options options("root"); + connection::TLS::Options tls_options; + + std::string ssl_ca; + std::string datadir; + + { + + options.set_tls(true); + cdk::Session s_tmp(ds, options); + + Reply ssl_var(s_tmp.sql("show global variables like 'ssl_ca';")); + + if (ssl_var.has_results()) + { + Cursor cur(ssl_var); + + row_processor_variable m_row_ca(ssl_ca); + + cur.get_row(m_row_ca); + } + + // CA path is same as data dir + Reply ssl_var_path(s_tmp.sql("show global variables like 'datadir';")); + if (ssl_var_path.has_results()) + { + Cursor cur(ssl_var_path); + + row_processor_variable m_row_ca_path(datadir); + + cur.get_row(m_row_ca_path); + + } + } + + tls_options.set_ca(datadir+ssl_ca); + + options.set_tls(tls_options); + + cdk::Session s1(ds, options); + + + if (!s1.is_valid()) + FAIL() << "Invalid Session created"; + + ssl_ca.erase(ssl_ca.size()-1); + + tls_options.set_ca(ssl_ca); + + options.set_tls(tls_options); + + EXPECT_THROW(cdk::Session s1(ds, options), Error); + + } + catch (Error &e) + { + FAIL() << "Connection error: " << e << endl; + } + +} diff --git a/cdk/core/tests/test.h b/cdk/core/tests/test.h index bfded80c0..d7b7d0a79 100644 --- a/cdk/core/tests/test.h +++ b/cdk/core/tests/test.h @@ -46,10 +46,10 @@ class Core_test return *m_ds; } - ds::Options& get_opts() + ds::TCPIP::Options& get_opts() { // TODO: make it configurable through env. variables - static ds::Options opts("root", NULL); + static ds::TCPIP::Options opts("root", NULL); opts.set_database("test"); return opts; } diff --git a/cdk/extra/yassl/src/ssl.cpp b/cdk/extra/yassl/src/ssl.cpp index acefe8b65..56b6c31fd 100644 --- a/cdk/extra/yassl/src/ssl.cpp +++ b/cdk/extra/yassl/src/ssl.cpp @@ -112,7 +112,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) ctx->GetUserData()); byte key[AES_256_KEY_SZ]; // max sizes byte iv[AES_IV_SZ]; - + // use file's salt for key derivation, but not real iv TaoCrypt::Source source(info.iv, info.ivSz); TaoCrypt::HexDecoder dec(source); @@ -137,7 +137,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) return SSL_BAD_FILE; } cipher->set_decryptKey(key, info.iv); - mySTL::auto_ptr newx(NEW_YS x509(x->get_length())); + mySTL::auto_ptr newx(NEW_YS x509(x->get_length())); cipher->decrypt(newx->use_buffer(), x->get_buffer(), x->get_length()); ysDelete(x); @@ -278,7 +278,7 @@ int SSL_connect(SSL* ssl) ssl->SetError(no_error); if (ssl->GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { - + ssl->SetError(no_error); ssl->SendWriteBuffered(); if (!ssl->GetError()) @@ -301,7 +301,7 @@ int SSL_connect(SSL* ssl) while (ssl->getStates().getClient() < neededState) { if (ssl->GetError()) break; processReply(*ssl); - // if resumption failed, reset needed state + // if resumption failed, reset needed state if (neededState == serverFinishedComplete) if (!ssl->getSecurity().get_resuming()) neededState = serverHelloDoneComplete; @@ -342,7 +342,7 @@ int SSL_connect(SSL* ssl) if (ssl->GetError()) { GetErrors().Add(ssl->GetError()); return SSL_FATAL_ERROR; - } + } return SSL_SUCCESS; default : @@ -370,7 +370,7 @@ int SSL_accept(SSL* ssl) ssl->SetError(no_error); if (ssl->GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { - + ssl->SetError(no_error); ssl->SendWriteBuffered(); if (!ssl->GetError()) @@ -400,7 +400,7 @@ int SSL_accept(SSL* ssl) sendServerHelloDone(*ssl); ssl->flushBuffer(); } - + if (!ssl->GetError()) ssl->useStates().UseAccept() = SERVER_HELLO_DONE; @@ -555,8 +555,8 @@ void SSL_flush_sessions(SSL_CTX *ctx, long /* tm */) const char* SSL_get_cipher_name(SSL* ssl) -{ - return SSL_get_cipher(ssl); +{ + return SSL_get_cipher(ssl); } @@ -750,7 +750,7 @@ X509_NAME* X509_get_subject_name(X509* x) } -void SSL_load_error_strings() // compatibility only +void SSL_load_error_strings() // compatibility only {} @@ -875,7 +875,7 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, closedir(dir); return SSL_BAD_STAT; } - + if (S_ISREG(buf.st_mode)) ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } @@ -1055,7 +1055,7 @@ void DH_free(DH* dh) } -// convert positive big-endian num of length sz into retVal, which may need to +// convert positive big-endian num of length sz into retVal, which may need to // be created BIGNUM* BN_bin2bn(const unsigned char* num, int sz, BIGNUM* retVal) { @@ -1527,7 +1527,7 @@ int SSL_pending(SSL* ssl) // Just in case there's pending data that hasn't been processed yet... char c; SSL_peek(ssl, &c, 1); - + return ssl->bufferedData(); } @@ -1566,7 +1566,7 @@ unsigned long err_helper(bool peek = false) return CERTFICATE_ERROR; break; default : - return 0; + return ysError; } return 0; // shut up compiler @@ -1785,7 +1785,7 @@ unsigned long ERR_get_error() #else snprintf(buf, len, "%s %2d %02d:%02d:%02d %d GMT", #endif - month_names[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, + month_names[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900); return buf; } diff --git a/cdk/foundation/connection_yassl.cc b/cdk/foundation/connection_yassl.cc index e845b2bd4..3d619ae04 100644 --- a/cdk/foundation/connection_yassl.cc +++ b/cdk/foundation/connection_yassl.cc @@ -34,14 +34,19 @@ POP_SYS_WARNINGS #include "connection_tcpip_base.h" +static void throw_yassl_error_msg(const char* msg) +{ + throw cdk::foundation::Error(cdk::foundation::cdkerrc::tls_error, + std::string("yaSSL: ") + msg); +} + static void throw_yassl_error() { char buffer[512]; yaSSL::ERR_error_string_n(yaSSL::ERR_get_error(), buffer, sizeof(buffer)); - throw cdk::foundation::Error(cdk::foundation::cdkerrc::tls_error, - std::string("yaSSL: ") + buffer); + throw_yassl_error_msg(buffer); } @@ -54,10 +59,12 @@ class connection_TLS_impl : public ::cdk::foundation::connection::TCPIP_base::Impl { public: - connection_TLS_impl(cdk::foundation::connection::TCPIP_base* tcpip) + connection_TLS_impl(cdk::foundation::connection::TCPIP_base* tcpip, + cdk::foundation::connection::TLS::Options options) : m_tcpip(tcpip) , m_tls(NULL) , m_tls_ctx(NULL) + , m_options(options) {} ~connection_TLS_impl() @@ -79,6 +86,7 @@ class connection_TLS_impl cdk::foundation::connection::TCPIP_base* m_tcpip; yaSSL::SSL* m_tls; yaSSL::SSL_CTX* m_tls_ctx; + cdk::foundation::connection::TLS::Options m_options; }; @@ -96,6 +104,7 @@ void connection_TLS_impl::do_connect() try { yaSSL::SSL_METHOD* method = yaSSL::TLSv1_client_method(); + if (!method) throw_yassl_error(); @@ -103,8 +112,34 @@ void connection_TLS_impl::do_connect() if (!m_tls_ctx) throw_yassl_error(); - // TODO: Server certificate verification. - SSL_CTX_set_verify(m_tls_ctx, yaSSL::SSL_VERIFY_NONE, 0); + if (!m_options.get_ca().empty() || + !m_options.get_ca_path().empty()) + { + SSL_CTX_set_verify(m_tls_ctx, yaSSL::SSL_VERIFY_PEER , NULL); + + int errNr = SSL_CTX_load_verify_locations( + m_tls_ctx, + m_options.get_ca().c_str(), + m_options.get_ca_path().empty() + ? NULL : m_options.get_ca_path().c_str()); + + switch(errNr) + { + case yaSSL::SSL_BAD_FILE: + throw_yassl_error_msg("error opening ca file"); + case yaSSL::SSL_BAD_PATH: + throw_yassl_error_msg("bad ca_path"); + case yaSSL::SSL_BAD_STAT: + throw_yassl_error_msg("bad file permissions inside ca_path"); + default: + break; + } + + } + else + { + SSL_CTX_set_verify(m_tls_ctx, yaSSL::SSL_VERIFY_NONE, 0); + } m_tls = yaSSL::SSL_new(m_tls_ctx); if (!m_tls) @@ -116,8 +151,9 @@ void connection_TLS_impl::do_connect() yaSSL::SSL_set_fd(m_tls, static_cast(fd)); - if (yaSSL::SSL_connect(m_tls) != yaSSL::SSL_SUCCESS) + if(yaSSL::SSL_connect(m_tls) != yaSSL::SSL_SUCCESS) throw_yassl_error(); + } catch (...) { @@ -148,8 +184,9 @@ namespace foundation { namespace connection { -TLS::TLS(TCPIP_base* tcpip) - : opaque_impl(NULL, tcpip) +TLS::TLS(TCPIP_base* tcpip, + const TLS::Options &options) + : opaque_impl(NULL, tcpip, options) {} diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index 70fb39a1c..2a0d06542 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -37,28 +37,29 @@ namespace ds { * Generic session options which are valid for any data source. */ + class Options { public: Options() - : m_usr(L"root"), m_has_pwd(false), m_has_db(false), m_use_tls(false) + : m_usr(L"root"), m_has_pwd(false), m_has_db(false) { } Options(const Options &other) : m_usr(other.m_usr) , m_has_pwd(other.m_has_pwd), m_pwd(other.m_pwd) - , m_has_db(false), m_use_tls(other.m_use_tls) + , m_has_db(false) { } Options(const string &usr, const std::string *pwd =NULL) - : m_usr(usr), m_has_pwd(false), m_has_db(false), m_use_tls(false) + : m_usr(usr), m_has_pwd(false), m_has_db(false) { if (pwd) { - m_has_pwd= true; + m_has_pwd = true; m_pwd= *pwd; } } @@ -69,8 +70,6 @@ class Options virtual const std::string* password() const { return m_has_pwd ? &m_pwd : NULL; } - virtual bool use_tls() const { return m_use_tls; } - void set_tls(bool use_tls) { m_use_tls = use_tls; } virtual const string* database() const { @@ -90,8 +89,8 @@ class Options std::string m_pwd; bool m_has_db; - bool m_use_tls; string m_db; + }; @@ -110,7 +109,8 @@ class TCPIP public: - typedef ds::Options Options; + class Options; + TCPIP(const std::string &_host="localhost", unsigned short _port =33060) : m_port(_port), m_host(_host) @@ -125,6 +125,34 @@ class TCPIP virtual const std::string& host() const { return m_host; } }; + +class TCPIP::Options : public ds::Options +{ +public: + + Options() + {} + + Options(const string &usr, const std::string *pwd =NULL) + : ds::Options(usr, pwd) + , m_tls_options(true) + {} + + + void set_tls(const cdk::connection::TLS::Options& options) + { + m_tls_options = options; + } + + const cdk::connection::TLS::Options& get_tls() const + { + return m_tls_options; + } + +private: + cdk::connection::TLS::Options m_tls_options; +}; + } // mysqlx namespace mysql { diff --git a/cdk/include/mysql/cdk/foundation.h b/cdk/include/mysql/cdk/foundation.h index 98dfef401..309d5beb8 100644 --- a/cdk/include/mysql/cdk/foundation.h +++ b/cdk/include/mysql/cdk/foundation.h @@ -74,9 +74,11 @@ namespace cdk { namespace connection { using foundation::connection::TCPIP; + using foundation::connection::TLS; using foundation::connection::Error_eos; using foundation::connection::Error_no_connection; using foundation::connection::Error_timeout; + } } // cdk diff --git a/cdk/include/mysql/cdk/foundation/connection_yassl.h b/cdk/include/mysql/cdk/foundation/connection_yassl.h index aacda6737..e1945568c 100644 --- a/cdk/include/mysql/cdk/foundation/connection_yassl.h +++ b/cdk/include/mysql/cdk/foundation/connection_yassl.h @@ -26,6 +26,7 @@ #define CDK_FOUNDATION_CONNECTION_YASSL_H #include "connection_tcpip.h" +#include "stream.h" #include "error.h" @@ -39,7 +40,12 @@ class TLS , opaque_impl { public: - TLS(TCPIP_base* tcpip); + + class Options; + + TLS(TCPIP_base* tcpip, + const Options& Opts); + class Read_op; class Read_some_op; @@ -51,6 +57,34 @@ class TLS }; +class TLS::Options +{ +public: + + Options(bool use_tls = true) + : m_use_tls(use_tls) + {} + + bool use_tls() const { return m_use_tls; } + + void set_key(const string &key) { m_key = key; } + const std::string &get_key() const { return m_key; } + + void set_ca(const string &ca) { m_ca = ca; } + void set_ca_path(const string &ca_path) { m_ca_path = ca_path; } + + const std::string &get_ca() const { return m_ca; } + const std::string &get_ca_path() const { return m_ca_path; } + +protected: + + bool m_use_tls; + std::string m_key; + std::string m_ca; + std::string m_ca_path; +}; + + class TLS::Read_op : public TCPIP_base::IO_op { public: diff --git a/cdk/include/mysql/cdk/session.h b/cdk/include/mysql/cdk/session.h index 17ce53950..aeea6726c 100644 --- a/cdk/include/mysql/cdk/session.h +++ b/cdk/include/mysql/cdk/session.h @@ -58,7 +58,8 @@ class Session /// Create session to a data store represented by `ds` object. - Session(ds::TCPIP &ds, const ds::Options &options = ds::Options()); + Session(ds::TCPIP &ds, + const ds::TCPIP::Options &options = ds::TCPIP::Options()); ~Session(); diff --git a/devapi/session.cc b/devapi/session.cc index 466423589..353704d2b 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -44,11 +44,11 @@ struct Endpoint struct internal::XSession_base::Options - : public cdk::ds::Options + : public cdk::ds::TCPIP::Options { Options(const string &usr, const std::string *pwd, string schema = string()) - : cdk::ds::Options(usr, pwd) + : cdk::ds::TCPIP::Options(usr, pwd) { if (!schema.empty()) set_database(schema); @@ -107,7 +107,7 @@ class internal::XSession_base::Impl , m_sess(m_ds, opt) { if (opt.database()) - m_default_db = *opt.database(); + m_default_db = *opt.database(); if (!m_sess.is_valid()) m_sess.get_error().rethrow(); } @@ -123,6 +123,8 @@ struct URI_parser { URI_parser(const std::string &uri) { + // TLS OFF by default on URI + set_tls(false); parser::parse_conn_str(uri, *this); } @@ -161,7 +163,7 @@ struct URI_parser void key_val(const std::string &key) override { if (key == "ssl-enable") - m_use_tls = true; + set_tls(true); } }; diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index c0e7f68bc..50b1ce1d5 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -297,7 +297,7 @@ class Order_by : public cdk::Order_by Order_by_item(const char *expr, Sort_direction::value sort_direction, parser::Parser_mode::value mode) : - m_mode(mode), m_expr(expr), + m_mode(mode), m_expr(expr), m_sort_direction(sort_direction) {} @@ -358,7 +358,7 @@ class Order_by : public cdk::Order_by typedef struct mysqlx_session_options_struct : public Mysqlx_diag, public parser::URI_processor, - public cdk::ds::Options + public cdk::ds::TCPIP::Options { private: std::string m_host; @@ -374,9 +374,9 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, mysqlx_session_options_struct(const std::string host, unsigned short port, const std::string usr, const std::string *pwd, const std::string *db, bool ssl_enable = true) : - cdk::ds::Options(usr, pwd), + cdk::ds::TCPIP::Options(usr, pwd), m_host(host), m_port(port ? port : DEFAULT_MYSQLX_PORT), - m_tcp(NULL) + m_tcp(NULL) { if (db) set_database(*db); From 40c3d1a92fd83ff1f0f2029a717823b02d51ab37 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 7 Dec 2016 09:37:20 +0100 Subject: [PATCH 28/79] Fixing compile warnings. --- include/mysql_devapi.h | 8 ++++---- xapi/tests/xapi_crud-t.cc | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index bb684cba0..bfb66afd3 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -619,8 +619,8 @@ class PUBLIC_API SessionSettings std::is_constructible::value >::type* = nullptr > - SessionSettings(HOST h, PORT p, USER u ,long pwd, T... args) - : SessionSettings(h, p, u, (const char*)pwd, args...) + SessionSettings(HOST h, PORT p, USER u ,long , T... args) + : SessionSettings(h, p, u, nullptr, args...) {} template < @@ -645,8 +645,8 @@ class PUBLIC_API SessionSettings std::is_constructible::value >::type* = nullptr > - SessionSettings(PORT p, USER u ,long pwd, T... args) - : SessionSettings(p, u, (const char*)pwd, args...) + SessionSettings(PORT p, USER u ,long , T... args) + : SessionSettings(p, u, nullptr, args...) {} diff --git a/xapi/tests/xapi_crud-t.cc b/xapi/tests/xapi_crud-t.cc index e98d67bda..809bde5e6 100644 --- a/xapi/tests/xapi_crud-t.cc +++ b/xapi/tests/xapi_crud-t.cc @@ -53,7 +53,6 @@ TEST_F(xapi, test_having_group_by) mysqlx_stmt_t *stmt; mysqlx_row_t *row; mysqlx_collection_t *collection; - const char *errmsg = NULL; int row_num = 1; const char *json_string = NULL; size_t json_len = 0; From 3789ece2d5a5aa0503c2a722cf3116186c53763d Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 9 Dec 2016 11:44:55 +0100 Subject: [PATCH 29/79] Merge CDK changes to SSL handling code: - Fix code to build when WITH_SSL is not defined, - Adapt to CDK session not using SSL by default. --- cdk/CMakeLists.txt | 7 ++++- cdk/core/session.cc | 7 ++--- cdk/core/tests/session-t.cc | 15 ++++++++-- cdk/include/mysql/cdk/data_source.h | 8 ++++- .../mysql/cdk/foundation/connection_yassl.h | 2 +- devapi/session.cc | 26 +++++++++++++++- xapi/mysqlx.cc | 7 +++++ xapi/mysqlx_cc_internal.h | 30 ++++++++++++++++--- 8 files changed, 87 insertions(+), 15 deletions(-) diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index b025d5942..12ec9ed6d 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -168,7 +168,7 @@ INCLUDE(protobuf) # if(NOT DEFINED WITH_SSL) -SET(WITH_SSL "bundled" CACHE STRING "") +SET(WITH_SSL "bundled" CACHE STRING "TODO: Document me!") endif() message("WITH_SSL: ${WITH_SSL}") @@ -177,6 +177,11 @@ IF(WITH_SSL) IF(WITH_SSL STREQUAL "bundled") ADD_DEFINITIONS(-DWITH_SSL_YASSL) ADD_SUBDIRECTORY(extra/yassl) + ELSE() + MESSAGE(WARNING "WITH_SSL option set to unrecognized value '${WITH_SSL}'" + " - will be ignored. Currently the only value allowed is" + " 'bundled', which uses the bundled YaSSL library to implement" + " TLS connections.") ENDIF() ADD_DEFINITIONS(-DWITH_SSL) ENDIF() diff --git a/cdk/core/session.cc b/cdk/core/session.cc index ed0594044..97ecc75eb 100644 --- a/cdk/core/session.cc +++ b/cdk/core/session.cc @@ -50,9 +50,9 @@ Session::Session(ds::TCPIP &ds, const ds::TCPIP::Options &options) } +#ifdef WITH_SSL if (options.get_tls().use_tls()) { -#ifdef WITH_SSL using foundation::connection::TLS; // Negotiate TLS capabilities. @@ -81,17 +81,14 @@ Session::Session(ds::TCPIP &ds, const ds::TCPIP::Options &options) proto.rcv_Reply(prc).wait(); - // TLS* tls = new TLS(connection, options.get_tls()); tls->connect(); m_connection = tls; m_session = new mysqlx::Session(*tls, options); -#else // WITH_SSL - throw Error("Connector doesn't support SSL connections"); -#endif } else +#endif { m_connection = connection; m_session = new mysqlx::Session(*connection, options); diff --git a/cdk/core/tests/session-t.cc b/cdk/core/tests/session-t.cc index e69075c23..0592cd278 100644 --- a/cdk/core/tests/session-t.cc +++ b/cdk/core/tests/session-t.cc @@ -947,6 +947,8 @@ TEST_F(Session_core, docs) #endif +#ifdef WITH_SSL + TEST_F(Session_core, tls_options) { SKIP_IF_NO_XPLUGIN; @@ -993,7 +995,7 @@ TEST_F(Session_core, tls_options) ds::TCPIP ds("localhost", m_port); ds::TCPIP::Options options("root"); - connection::TLS::Options tls_options; + connection::TLS::Options tls_options(true); std::string ssl_ca; std::string datadir; @@ -1012,6 +1014,8 @@ TEST_F(Session_core, tls_options) row_processor_variable m_row_ca(ssl_ca); cur.get_row(m_row_ca); + + cout << "Server CA: " << ssl_ca << endl; } // CA path is same as data dir @@ -1024,10 +1028,13 @@ TEST_F(Session_core, tls_options) cur.get_row(m_row_ca_path); + cout << "Server data dir: " << datadir << endl; } } - tls_options.set_ca(datadir+ssl_ca); + cout << "Setting CA to: " << ssl_ca << endl; + + tls_options.set_ca(ssl_ca); options.set_tls(tls_options); @@ -1039,6 +1046,8 @@ TEST_F(Session_core, tls_options) ssl_ca.erase(ssl_ca.size()-1); + cout << "Setting CA to: " << ssl_ca << endl; + tls_options.set_ca(ssl_ca); options.set_tls(tls_options); @@ -1052,3 +1061,5 @@ TEST_F(Session_core, tls_options) } } + +#endif diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index 2a0d06542..eb40963e0 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -135,9 +135,9 @@ class TCPIP::Options : public ds::Options Options(const string &usr, const std::string *pwd =NULL) : ds::Options(usr, pwd) - , m_tls_options(true) {} +#ifdef WITH_SSL void set_tls(const cdk::connection::TLS::Options& options) { @@ -149,8 +149,14 @@ class TCPIP::Options : public ds::Options return m_tls_options; } +#endif + private: + +#ifdef WITH_SSL cdk::connection::TLS::Options m_tls_options; +#endif + }; } // mysqlx diff --git a/cdk/include/mysql/cdk/foundation/connection_yassl.h b/cdk/include/mysql/cdk/foundation/connection_yassl.h index e1945568c..566acf736 100644 --- a/cdk/include/mysql/cdk/foundation/connection_yassl.h +++ b/cdk/include/mysql/cdk/foundation/connection_yassl.h @@ -61,7 +61,7 @@ class TLS::Options { public: - Options(bool use_tls = true) + Options(bool use_tls = false) : m_use_tls(use_tls) {} diff --git a/devapi/session.cc b/devapi/session.cc index 353704d2b..1de33dbe6 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -52,9 +52,17 @@ struct internal::XSession_base::Options { if (!schema.empty()) set_database(schema); +#ifdef WITH_SSL + set_tls(true); +#endif } - Options() = default; + Options() + { +#ifdef WITH_SSL + set_tls(true); +#endif + } }; @@ -123,8 +131,10 @@ struct URI_parser { URI_parser(const std::string &uri) { +#ifdef WITH_SSL // TLS OFF by default on URI set_tls(false); +#endif parser::parse_conn_str(uri, *this); } @@ -163,7 +173,14 @@ struct URI_parser void key_val(const std::string &key) override { if (key == "ssl-enable") +#ifdef WITH_SSL set_tls(true); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif } }; @@ -229,7 +246,14 @@ internal::XSession_base::XSession_base(SessionSettings settings) ); if (settings.has_option(SessionSettings::SSL_ENABLE)) +#ifdef WITH_SSL opt.set_tls(settings[SessionSettings::SSL_ENABLE].get()); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif m_impl = new Impl(ep, opt); } diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index 2090d2ada..329f12b32 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -1708,8 +1708,15 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, opt->set_database(char_data); break; case MYSQLX_OPT_SSL_ENABLE: +#ifdef WITH_SSL uint_data = va_arg(args, unsigned int); opt->set_tls(uint_data > 0); +#else + opt->set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); +#endif break; default: opt->set_diagnostic("Invalid option value", 0); diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 50b1ce1d5..19b194e56 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -373,15 +373,30 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, mysqlx_session_options_struct(const std::string host, unsigned short port, const std::string usr, const std::string *pwd, - const std::string *db, bool ssl_enable = true) : - cdk::ds::TCPIP::Options(usr, pwd), - m_host(host), m_port(port ? port : DEFAULT_MYSQLX_PORT), - m_tcp(NULL) + const std::string *db, + bool ssl_enable = +#ifdef WITH_SSL + true +#else + false +#endif + ) : + cdk::ds::TCPIP::Options(usr, pwd), + m_host(host), m_port(port ? port : DEFAULT_MYSQLX_PORT), + m_tcp(NULL) { if (db) set_database(*db); +#ifdef WITH_SSL set_tls(ssl_enable); +#else + if (ssl_enable) + set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); +#endif } mysqlx_session_options_struct(const std::string &conn_str) : m_tcp(NULL) @@ -427,7 +442,14 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, { if (key.compare("ssl-enable") == 0) { +#ifdef WITH_SSL set_tls(true); +#else + set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); +#endif } } From 7114668506d664f191cea931f85693eb1927041b Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 4 Jan 2017 16:32:51 +0100 Subject: [PATCH 30/79] Merge CDK changes to SSL handling code (part 2) --- cdk/core/tests/session-t.cc | 2 +- cdk/include/mysql/cdk/data_source.h | 2 ++ cdk/include/mysql/cdk/foundation/connection_yassl.h | 12 +++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cdk/core/tests/session-t.cc b/cdk/core/tests/session-t.cc index 0592cd278..21b26e617 100644 --- a/cdk/core/tests/session-t.cc +++ b/cdk/core/tests/session-t.cc @@ -995,7 +995,7 @@ TEST_F(Session_core, tls_options) ds::TCPIP ds("localhost", m_port); ds::TCPIP::Options options("root"); - connection::TLS::Options tls_options(true); + connection::TLS::Options tls_options; std::string ssl_ca; std::string datadir; diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index eb40963e0..b6d843d5a 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -131,10 +131,12 @@ class TCPIP::Options : public ds::Options public: Options() + : m_tls_options(false) {} Options(const string &usr, const std::string *pwd =NULL) : ds::Options(usr, pwd) + , m_tls_options(false) {} #ifdef WITH_SSL diff --git a/cdk/include/mysql/cdk/foundation/connection_yassl.h b/cdk/include/mysql/cdk/foundation/connection_yassl.h index 566acf736..84c84dd78 100644 --- a/cdk/include/mysql/cdk/foundation/connection_yassl.h +++ b/cdk/include/mysql/cdk/foundation/connection_yassl.h @@ -61,7 +61,17 @@ class TLS::Options { public: - Options(bool use_tls = false) + /* + Note: Normally m_use_tls should be always true: using TLS options object + implies an intent to have TLS connection. A TLS::Options object with + m_use_tls set to false is only used to disable TLS connection inside + TCPIP::Options object. The TCPIP::Options object holds an instance + of TLS::Options. Calling TCPIP::Options::set_tls(false) will alter this + internal TLS::Options instance so that m_use_tls is false and then the + TCPIP::Options object knows that TLS should not be used for the connection. + */ + + Options(bool use_tls = true) : m_use_tls(use_tls) {} From d93a966a43e2864ce632864a48cbedb8ceb593b4 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 4 Jan 2017 16:33:42 +0100 Subject: [PATCH 31/79] Merge from CDK: Handling big-endian platforms. --- cdk/CMakeLists.txt | 34 +++++++++++++++++------ cdk/cmake/config.cmake | 35 ++++++++++++++++-------- cdk/include/mysql/cdk/foundation/codec.h | 33 +++++----------------- cdk/protocol/mysqlx/protocol.h | 4 +-- 4 files changed, 59 insertions(+), 47 deletions(-) diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index 12ec9ed6d..0f424cc44 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -53,6 +53,28 @@ LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) include(libutils) +# +# Infrastructure for defining code configuration settings +# (the ADD_CONFIG() macro for declaring contents of config.h). +# + +INCLUDE(config) + + +# +# Detect endianess +# + +if(NOT DEFINED CDK_BIG_ENDIAN) + + INCLUDE(TestBigEndian) + TEST_BIG_ENDIAN(CDK_BIG_ENDIAN) + +endif() + +message(STATUS "BIG_ENDIAN: ${BIG_ENDIAN}") +add_config(CDK_BIG_ENDIAN ${CDK_BIG_ENDIAN}) + # # Configure static runtime library on Windows if requested # @@ -74,7 +96,7 @@ endforeach(LANG) ENDIF() # -# Postion independent code support. +# Position independent code support. # option(WITH_PIC "Generate position independet code (PIC)" OFF) @@ -114,13 +136,6 @@ if(DISABLE_WARNINGS) endif() -# -# Infrastructure for defining code configuration settings -# (the ADD_CONFIG() macro for declaring contents of config.h). -# - -INCLUDE(config) - # # We want CDK code to compile both under C++ and C++11 compiler. # In case of C++11 build we can use certain generic C++11 features @@ -176,6 +191,9 @@ message("WITH_SSL: ${WITH_SSL}") IF(WITH_SSL) IF(WITH_SSL STREQUAL "bundled") ADD_DEFINITIONS(-DWITH_SSL_YASSL) + if(CDK_BIG_ENDIAN) + ADD_DEFINITIONS(-DWORDS_BIGENDIAN) + endif() ADD_SUBDIRECTORY(extra/yassl) ELSE() MESSAGE(WARNING "WITH_SSL option set to unrecognized value '${WITH_SSL}'" diff --git a/cdk/cmake/config.cmake b/cdk/cmake/config.cmake index 9bcf74853..055e7c364 100644 --- a/cdk/cmake/config.cmake +++ b/cdk/cmake/config.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. # # The MySQL Connector/C++ is licensed under the terms of the GPLv2 # , like most @@ -36,21 +36,27 @@ # set(CONFIG_VARS "" CACHE INTERNAL "configuration settings" FORCE) +set(CONFIG_VARS_VAL "" CACHE INTERNAL "configuration settings" FORCE) -macro(ADD_CONFIG var) - #message("- adding configuration setting: ${var}") - list(APPEND CONFIG_VARS ${var}) - list(REMOVE_DUPLICATES CONFIG_VARS) - set(CONFIG_VARS ${CONFIG_VARS} CACHE INERNAL "configuration settings" FORCE) +function(ADD_CONFIG var) + #message("- adding configuration setting: ${var} (${ARGN})") - # set variable to the value if given + if(DEFINED ARGV1) + + set(${var} ${ARGV1}) + list(APPEND CONFIG_VARS_VAL ${var}) + list(REMOVE_DUPLICATES CONFIG_VARS_VAL) + set(CONFIG_VARS_VAL ${CONFIG_VARS_VAL} CACHE INERNAL "configuration settings" FORCE) + + else() + + list(APPEND CONFIG_VARS ${var}) + list(REMOVE_DUPLICATES CONFIG_VARS) + set(CONFIG_VARS ${CONFIG_VARS} CACHE INERNAL "configuration settings" FORCE) - if(ARGN) - set(${var} ${ARGN}) - list(GET ${var} 0 ${var}) endif() -endmacro(ADD_CONFIG) +endfunction(ADD_CONFIG) # # Call this macro to write a configuration header containing defines @@ -71,6 +77,13 @@ macro(WRITE_CONFIG_HEADER path) else() set(DEFINE "/* #undef ${var} */") endif() + #message("writing to config.h: ${DEFINE}") + set(GENERATED_CONFIG_DEFS "${GENERATED_CONFIG_DEFS}\n${DEFINE}") + endforeach() + + foreach(var ${CONFIG_VARS_VAL}) + set(DEFINE "#define ${var} ${${var}}") + #message("writing to config.h: ${DEFINE}") set(GENERATED_CONFIG_DEFS "${GENERATED_CONFIG_DEFS}\n${DEFINE}") endforeach() diff --git a/cdk/include/mysql/cdk/foundation/codec.h b/cdk/include/mysql/cdk/foundation/codec.h index 381ce7c5d..38f503bd7 100644 --- a/cdk/include/mysql/cdk/foundation/codec.h +++ b/cdk/include/mysql/cdk/foundation/codec.h @@ -35,15 +35,6 @@ #include // for std::numeric_limits -/* - TODO: This is probably the only dependency of CDK public headers - on Boost. Remove it... - NOTE: is used in types.h -*/ -PUSH_BOOST_WARNINGS -#include // to detect endianess -POP_BOOST_WARNINGS - namespace cdk { namespace foundation { @@ -247,33 +238,23 @@ class Codec : public String_codec -#undef BIG_ENDIAN - -#if BOOST_ENDIAN_BIG_BYTE -#define BIG_ENDIAN 1 -#endif - -#if BOOST_ENDIAN_LITTLE_BYTE -#define BIG_ENDIAN 0 -#endif - -#ifndef BIG_ENDIAN -#error Endianess could not be determined! -#endif - - /* Number codecs ============= */ +#ifndef CDK_BIG_ENDIAN +#error Unknown endianess! +#endif + + struct Endianess { enum value { BIG, LITTLE, NATIVE = -#if BIG_ENDIAN +#if CDK_BIG_ENDIAN BIG #else LITTLE @@ -448,7 +429,7 @@ static size_t convert(bytes buf, T &val) template<> class Number_codec< -#if BIG_ENDIAN +#if CDK_BIG_ENDIAN Endianess::LITTLE #else Endianess::BIG diff --git a/cdk/protocol/mysqlx/protocol.h b/cdk/protocol/mysqlx/protocol.h index 829088f08..853909049 100644 --- a/cdk/protocol/mysqlx/protocol.h +++ b/cdk/protocol/mysqlx/protocol.h @@ -69,11 +69,11 @@ typedef unsigned short int msg_type_t; #elif defined(HAVE_BYTEORDER_H) #include #define bswap32(X) BSWAP_32(X) -#elif BIG_ENDIAN +#elif CDK_BIG_ENDIAN #error No byte-swap function available on big-endian platform. #endif -#if BIG_ENDIAN +#if CDK_BIG_ENDIAN #define NTOHSIZE(S) do { (S) = bswap32(S); } while(0) #define HTONSIZE(S) do { (S) = bswap32(S); } while(0) #else From ca83285e4d0ab24758128174e9ef491543db049f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Wed, 30 Nov 2016 19:26:41 +0000 Subject: [PATCH 32/79] Fix for URI with IPv6 address. Add UT with IPv6 --- cdk/parser/tests/parser-t.cc | 32 +++++++++++++++- cdk/parser/uri_parser.cc | 71 ++++++++++++++++++++++++++---------- devapi/tests/session-t.cc | 54 +++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 21 deletions(-) diff --git a/cdk/parser/tests/parser-t.cc b/cdk/parser/tests/parser-t.cc index 1b3b3d631..99dff1933 100644 --- a/cdk/parser/tests/parser-t.cc +++ b/cdk/parser/tests/parser-t.cc @@ -1113,10 +1113,18 @@ TEST(Parser, uri) "host", URI_parts(none, none, "host", 0, none, false) }, + { + "[::1]", + URI_parts(none, none, "::1", 0, none, false) + }, { "host:123", URI_parts(none, none, "host", 123, none, false) }, + { + "[::1]:123", + URI_parts(none, none, "::1", 123, none, false) + }, { "host:0", URI_parts(none,none, "host", 0, none , false) @@ -1125,6 +1133,10 @@ TEST(Parser, uri) "host/path", URI_parts(none , none, "host", 0, "path", false) }, + { + "[::1]/path", + URI_parts(none , none, "::1", 0, "path", false) + }, { "host/", URI_parts(none , none, "host", 0, "", false) @@ -1133,6 +1145,10 @@ TEST(Parser, uri) "user@host/path", URI_parts("user" , none, "host", 0, "path", false) }, + { + "user@[::1]/path", + URI_parts("user" , none, "::1", 0, "path", false) + }, { "user%40host%2Fpath", URI_parts(none , none, "user@host/path", 0, none, false) @@ -1145,10 +1161,18 @@ TEST(Parser, uri) "user:pwd@host", URI_parts("user" , "pwd", "host", 0, none, false) }, + { + "user:pwd@[::1]", + URI_parts("user" , "pwd", "::1", 0, none, false) + }, { "user:pwd@host:123", URI_parts("user" , "pwd", "host", 123, none, false) }, + { + "user:pwd@[::1]:123", + URI_parts("user" , "pwd", "::1", 123, none, false) + }, { "user:pwd@host:123/", URI_parts("user" , "pwd", "host", 123, "", false) @@ -1157,6 +1181,10 @@ TEST(Parser, uri) "user:pwd@host:123/foo?key=val", URI_parts("user" , "pwd", "host", 123, "foo", true) }, + { + "user:pwd@[::1]:123/foo?key=val", + URI_parts("user" , "pwd", "::1", 123, "foo", true) + }, { "user:pwd@host:123?key=val", URI_parts("user" , "pwd", "host", 123, none, true) @@ -1277,7 +1305,9 @@ TEST(Parser, uri) "host/db?query#foo", "host/db?a=[a,b,c&b", "host/db?a=[a,b,c]foo=bar", - "host/db?a=[a,b=foo" + "host/db?a=[a,b=foo", + "[::1]:port:123", + "[::1" //"host/db?l=[a,b&c]" TODO: should this fail? // TODO: allowed chars in host/path component }; diff --git a/cdk/parser/uri_parser.cc b/cdk/parser/uri_parser.cc index e20243581..448f32a5e 100644 --- a/cdk/parser/uri_parser.cc +++ b/cdk/parser/uri_parser.cc @@ -263,6 +263,13 @@ struct URI_parser::TokSet m_bits.set(tt2); } + TokSet(token_type tt1, token_type tt2, token_type tt3) + { + m_bits.set(tt1); + m_bits.set(tt2); + m_bits.set(tt3); + } + bool has_token(token_type tt) const { return m_bits.test(tt); @@ -294,11 +301,20 @@ void URI_parser::process(Processor &prc) const bool rescan = false; bool has_port = false; - self->consume_until(host, TokSet(T_AT, T_COLON)); - - if (self->consume_token(T_COLON)) + if (self->next_token_is(T_SQOPEN)) { /* + IPv6 adress found! Will be parsed on rescan + */ + rescan = true; + } + else + { + self->consume_until(host, TokSet(T_AT, T_COLON )); + + if (self->consume_token(T_COLON)) + { + /* We have seen ":" and it still can be user followed by a password or host followed by a port. @@ -306,9 +322,9 @@ void URI_parser::process(Processor &prc) const part, whichever comes first. */ - self->consume_until(port, T_AT); + self->consume_until(port, T_AT); - /* + /* If we see @ now, then it means we were looking at user credentials so far (and they are stored in host and port, respectively). We report them and request re-scanning host/port @@ -319,25 +335,26 @@ void URI_parser::process(Processor &prc) const the corresponding variables. */ - if (self->consume_token(T_AT)) - { - // :@... - prc.user(host); - prc.password(port); - rescan = true; + if (self->consume_token(T_AT)) + { + // :@... + prc.user(host); + prc.password(port); + rescan = true; + } + else + has_port = true; } - else - has_port = true; - } - else if (self->consume_token(T_AT)) - { - /* + else if (self->consume_token(T_AT)) + { + /* No ':' seen but we see '@'. It means user without password and user is stored in host variable. We report it an request re-scanning of host/port info. */ - prc.user(host); - rescan = true; + prc.user(host); + rescan = true; + } } /* @@ -350,7 +367,21 @@ void URI_parser::process(Processor &prc) const { host.clear(); port.clear(); - self->consume_until(host, T_COLON); + + if (self->consume_token(T_SQOPEN)) + { + /* + IPv6 address + */ + host.clear(); + self->consume_until(host, T_SQCLOSE); + if (!self->consume_token(T_SQCLOSE)) + throw Error(this, L"Missing ']' while parsing IPv6 address"); + } + else + { + self->consume_until(host, T_COLON ); + } if (self->consume_token(T_COLON)) { diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 76af4abac..c1490da59 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -430,3 +430,57 @@ TEST_F(Sess, ssl_session) } } + +TEST_F(Sess, ipv6) +{ + + SKIP_IF_NO_XPLUGIN; + + { + mysqlx::XSession sess(SessionSettings::HOST, "::1", + SessionSettings::PORT, get_port(), + SessionSettings::USER, get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false); + } + + //Using URI + + std::stringstream uri; + + uri << "mysqlx://" << get_user(); + + if (get_password() && *get_password()) + uri << ":"<< get_password(); + + uri << "@" << "[::1]:" << get_port(); + + //URI without ssl_enable + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + } + + //Enable SSL + uri << "/?ssl-enable"; + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } +} From cf8f0449735a616e59fc71c5ca53ab25b3d53350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Mon, 9 Jan 2017 19:38:20 +0000 Subject: [PATCH 33/79] Add missing getDefaultSchemaName() to XSession. --- devapi/session.cc | 5 +++++ devapi/tests/session-t.cc | 2 ++ include/mysql_devapi.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/devapi/session.cc b/devapi/session.cc index 1de33dbe6..e9a580967 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -813,6 +813,11 @@ Schema internal::XSession_base::getDefaultSchema() return Schema(*this, m_impl->m_default_db); } +string internal::XSession_base::getDefaultSchemaName() +{ + return m_impl->m_default_db; +} + Schema internal::XSession_base::getSchema(const string &name, bool check) { diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 76af4abac..41e44eb78 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -161,6 +161,7 @@ TEST_F(Sess, default_schema) mysqlx::NodeSession s(m_port, m_user, m_password, "test"); EXPECT_EQ(string("test"), s.getDefaultSchema().getName()); + EXPECT_EQ(string("test"), s.getDefaultSchemaName()); SqlResult res = s.sql(L"SELECT DATABASE()").execute(); string db = res.fetchOne()[0]; EXPECT_EQ(string("test"), db); @@ -176,6 +177,7 @@ TEST_F(Sess, default_schema) mysqlx::NodeSession s(url); EXPECT_EQ(string("test"), s.getDefaultSchema().getName()); + EXPECT_EQ(string("test"), s.getDefaultSchemaName()); SqlResult res = s.sql(L"SELECT DATABASE()").execute(); string db = res.fetchOne()[0]; EXPECT_EQ(string("test"), db); diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index bfb66afd3..3464200dc 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -804,6 +804,8 @@ namespace internal { Schema getDefaultSchema(); + string getDefaultSchemaName(); + /** Get list of schema objects in a given session. */ From de56bcaaf6706735746b8df4c6697fecb22c8991 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Mon, 9 Jan 2017 20:49:17 +0100 Subject: [PATCH 34/79] cmake: Add /bigobj compile flag on Win We hit the limits of win object files (probably due to heavy use of templates and inlines). --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69145605f..7725349f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,12 @@ if(WIN32 AND NOT UNREACHABLE_CODE_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4297") endif() + +if(WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif() + + # # Gcov support (Linux only) # From b0834d05e5b351c5d63cfb6086e585c991010676 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Mon, 9 Jan 2017 20:35:13 +0100 Subject: [PATCH 35/79] Merge from CDK: MYC-378 Support for view DDL commands. --- cdk/core/tests/session_crud-t.cc | 219 ++++++- cdk/foundation/connection_yassl.cc | 1 - cdk/include/mysql/cdk/api/query.h | 115 +++- cdk/include/mysql/cdk/common.h | 7 + cdk/include/mysql/cdk/converters.h | 14 + cdk/include/mysql/cdk/mysqlx/session.h | 17 +- cdk/include/mysql/cdk/protocol/mysqlx.h | 213 +++++-- cdk/include/mysql/cdk/session.h | 16 +- cdk/mysqlx/delayed_op.h | 553 ++++++++++++------ cdk/mysqlx/result.cc | 6 +- cdk/mysqlx/session.cc | 88 +-- cdk/protocol/mysqlx/crud.cc | 286 ++++++--- cdk/protocol/mysqlx/pb/mysqlx.proto | 6 +- .../mysqlx/pb/mysqlx_connection.proto | 2 +- cdk/protocol/mysqlx/pb/mysqlx_crud.proto | 84 ++- cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto | 16 +- cdk/protocol/mysqlx/pb/mysqlx_expect.proto | 2 +- cdk/protocol/mysqlx/pb/mysqlx_expr.proto | 2 +- cdk/protocol/mysqlx/pb/mysqlx_notice.proto | 3 +- cdk/protocol/mysqlx/pb/mysqlx_resultset.proto | 13 +- cdk/protocol/mysqlx/pb/mysqlx_session.proto | 2 +- cdk/protocol/mysqlx/pb/mysqlx_sql.proto | 2 +- cdk/protocol/mysqlx/protocol.cc | 2 +- cdk/protocol/mysqlx/protocol.h | 1 - cdk/protocol/mysqlx/rset.cc | 27 +- cdk/protocol/mysqlx/stmt.cc | 2 +- .../mysqlx/tests/proto_mysqlx_crud-t.cc | 139 +++-- devapi/collection_crud.cc | 5 +- devapi/table_crud.cc | 1 + xapi/crud.cc | 2 + 30 files changed, 1444 insertions(+), 402 deletions(-) diff --git a/cdk/core/tests/session_crud-t.cc b/cdk/core/tests/session_crud-t.cc index 8270ead58..1e71bca98 100644 --- a/cdk/core/tests/session_crud-t.cc +++ b/cdk/core/tests/session_crud-t.cc @@ -846,7 +846,7 @@ CRUD_TEST_BEGIN(find) Expr criteria(criteria_str); - Reply find(sess.coll_find(coll, &criteria, NULL)); + Reply find(sess.coll_find(coll, NULL, &criteria, NULL)); Cursor c(find); set_meta_data(c); @@ -869,7 +869,7 @@ CRUD_TEST_BEGIN(find) Expr criteria(criteria_str); - Reply find(sess.coll_find(coll, &criteria, NULL)); + Reply find(sess.coll_find(coll, NULL, &criteria, NULL)); Cursor c(find); set_meta_data(c); @@ -1054,7 +1054,7 @@ CRUD_TEST_BEGIN(update) // Show data after update. - Reply find(sess.coll_find(coll, &which)); + Reply find(sess.coll_find(coll, NULL, &which)); Cursor c(find); set_meta_data(c); c.get_rows(*this); @@ -1088,7 +1088,7 @@ CRUD_TEST_BEGIN(update) // Show data after update. - Reply find(sess.coll_find(coll, &which)); + Reply find(sess.coll_find(coll, NULL, &which)); Cursor c(find); set_meta_data(c); c.get_rows(*this); @@ -1173,7 +1173,7 @@ CRUD_TEST_BEGIN(parameters) param_values; { - Reply find(sess.coll_find(coll, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); + Reply find(sess.coll_find(coll, NULL, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); Cursor c(find); set_meta_data(c); @@ -1205,7 +1205,7 @@ CRUD_TEST_BEGIN(parameters) } { - Reply find(sess.coll_find(coll, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); + Reply find(sess.coll_find(coll, NULL, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); Cursor c(find); set_meta_data(c); @@ -1226,7 +1226,7 @@ CRUD_TEST_BEGIN(parameters) } { - Reply find(sess.coll_find(coll, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); + Reply find(sess.coll_find(coll, NULL, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); Cursor c(find); set_meta_data(c); @@ -1287,6 +1287,7 @@ CRUD_TEST_BEGIN(projections) Reply find( sess.coll_find(coll, + NULL, // view spec NULL, // where &projection, NULL, // sort @@ -1360,7 +1361,7 @@ CRUD_TEST_BEGIN(projections) } projection; - Reply find(sess.table_select(coll, &criteria, &projection)); + Reply find(sess.table_select(coll, NULL, &criteria, &projection)); Cursor c(find); set_meta_data(c); @@ -1447,7 +1448,7 @@ CRUD_TEST_BEGIN(insert) { TExpr cond("id IS NULL AND extra IS NULL"); - Reply check(sess.table_select(tbl, &cond)); + Reply check(sess.table_select(tbl, NULL, &cond)); Cursor c(check); set_meta_data(c); c.get_rows(*this); @@ -1540,6 +1541,7 @@ CRUD_TEST_BEGIN(group_by) Reply find( sess.coll_find(coll, + NULL, // view spec NULL, // where &projection, NULL, // sort @@ -1604,6 +1606,7 @@ CRUD_TEST_BEGIN(group_by) Reply find( sess.table_select(tbl, + NULL, // view spec NULL, // where &projection, NULL, // sort @@ -1626,3 +1629,201 @@ CRUD_TEST_BEGIN(group_by) cout <<"Done!" <process_if(prc.columns()); + if (opts) + opts->process_if(prc.options()); + } + } + view; + + cout << "Creating collection view..." << endl; + + // Drop the view first, if it already exists. + + { + Reply drop(sess.view_drop(view.v)); + drop.wait(); + if (0 < drop.entry_count()) + drop.get_error().rethrow(); + } + + { + struct : public View_spec::Options + { + void process(Processor &prc) const + { + prc.security(View_security::DEFINER); + prc.check(View_check::LOCAL); + } + } + view_opts; + + view.opts = &view_opts; + + struct : public Expression::Document + { + void process(Processor &prc) const + { + Path name_path("name"); + Path age_path("age"); + Expr double_age("2*age"); + Safe_prc sprc(prc); + + prc.doc_begin(); + + sprc->key_val("name_proj")->scalar()->ref(name_path); + double_age.process_if(sprc->key_val("age_proj")); + sprc->key_val("extra.orig_age")->scalar()->ref(age_path); + sprc->key_val("extra.val")->scalar()->val()->str("bar"); + + prc.doc_end(); + } + } + projection; + + Expr cond("name LIKE 'ba%'"); + + Reply create(sess.coll_find(coll, &view, &cond, &projection)); + create.wait(); + if (0 < create.entry_count()) + create.get_error().rethrow(); + } + + cout << "View created, querying it..." << endl; + + { + Reply select(sess.coll_find(view.v)); + select.wait(); + + cout << "Got reply..." << endl; + + Cursor c(select); + + set_meta_data(c); + c.get_rows(*this); + c.wait(); + } + + + cout << "Creating table view..." << endl; + + // Drop the view first. + + { + Reply drop(sess.view_drop(view.v, false)); + drop.wait(); + if (0 < drop.entry_count()) + drop.get_error().rethrow(); + } + + { + struct : public View_spec::Options + { + void process(Processor &prc) const + { + prc.security(View_security::INVOKER); + prc.algorithm(View_algorithm::UNDEFINED); + } + } + view_opts; + + view.opts = &view_opts; + + struct : public Projection + { + void process(Processor &prc) const + { + Processor::Element_prc *ep; + + prc.list_begin(); + + if ((ep = prc.list_el())) + { + TExpr proj(L"name"); + proj.process_if(ep->expr()); + // no alias + } + + if ((ep = prc.list_el())) + { + TExpr proj(L"2 * age"); + proj.process_if(ep->expr()); + ep->alias(L"double age"); + } + + prc.list_end(); + } + } + projection; + + struct : public cdk::String_list + { + void process(Processor &prc) const + { + prc.list_begin(); + safe_prc(prc)->list_el()->val("view_name"); + safe_prc(prc)->list_el()->val("view_age"); + prc.list_end(); + } + } + columns; + + view.columns = &columns; + + TExpr cond("name LIKE 'ba%'"); + + Reply create(sess.table_select(tbl, &view, &cond, &projection)); + create.wait(); + if (0 < create.entry_count()) + create.get_error().rethrow(); + } + + cout << "View created, querying it..." << endl; + + { + Reply select(sess.table_select(view.v)); + select.wait(); + + cout << "Got reply..." << endl; + + Cursor c(select); + + EXPECT_EQ(L"view_name", c.col_info(0).name()); + EXPECT_EQ(L"view_age", c.col_info(1).name()); + + set_meta_data(c); + c.get_rows(*this); + c.wait(); + } + + + cout <<"Done!" < #include #include #include diff --git a/cdk/include/mysql/cdk/api/query.h b/cdk/include/mysql/cdk/api/query.h index b7c878de9..375abf113 100644 --- a/cdk/include/mysql/cdk/api/query.h +++ b/cdk/include/mysql/cdk/api/query.h @@ -27,6 +27,7 @@ #ifndef CDK_API_QUERY_H #define CDK_API_QUERY_H +#include "obj_ref.h" #include "expression.h" #include "document.h" #include "../foundation/types.h" @@ -36,6 +37,15 @@ namespace api { using foundation::string; +class String_processor +{ +public: + virtual void val(const string&) = 0; +}; + +typedef Expr_list< Expr_base > String_list; + + /* Classes for representing different parts of a query such as LIMIT, ORDER BY etc. @@ -96,7 +106,7 @@ class Order_by /* Projection specification is a list of items. Each item is an expression over - Projection_processor which reports an expression and optional alias. + Projection_processor which reports a projection expression and optional alias. */ template @@ -120,6 +130,85 @@ class Projection {}; +/* + View specifications. + + A view specification can be passed to a session method, such as table_find(), + which sends CRUD query. When view specification is given for a query, then + this query is saved as a new view, or it replaces the query of an existing + view. +*/ + +template +class View_processor +{ +public: + + typedef OPTS Options; + typedef String_list::Processor List_processor; + + virtual void name(const Table_ref&, bool update = false) = 0; + virtual typename Options::Processor* options() = 0; + virtual List_processor* columns() + { return NULL; } +}; + + +template +class View_spec : public Expr_base< View_processor > +{ +public: + + typedef OPTS Options; +}; + + +/* + Standard view options: these are aligned with view options defined by + DevAPI. +*/ + +struct View_security +{ + enum value { + DEFINER, INVOKER + }; +}; + +struct View_algorithm +{ + enum value { + UNDEFINED, + MERGE, + TEMPTABLE + }; +}; + +struct View_check +{ + enum value { + LOCAL, + CASCADED + }; +}; + + +class View_opt_prc +{ +public: + + typedef View_security::value View_security_t; + typedef View_algorithm::value View_algorithm_t; + typedef View_check::value View_check_t; + + virtual void security(View_security_t) = 0; + virtual void algorithm(View_algorithm_t) = 0; + virtual void check(View_check_t) = 0; +}; + +typedef Expr_base View_options; + + /* Columns specification specifies table columns into which table insert operation should insert values. It is a list @@ -155,6 +244,30 @@ typedef Expr_list< Expr_base > Columns; namespace cdk { +using api::String_list; + +template<> +struct Safe_prc + : Safe_prc_base +{ + typedef Safe_prc_base Base; + using Base::Processor; + + Safe_prc(Processor *prc) : Base(prc) + {} + + Safe_prc(Processor &prc) : Base(&prc) + {} + + using Base::m_prc; + + void val(const string &val) + { + return m_prc ? m_prc->val(val) : (void)NULL; + } +}; + + template<> struct Safe_prc : Safe_prc_base diff --git a/cdk/include/mysql/cdk/common.h b/cdk/include/mysql/cdk/common.h index 55e1cc73d..1fdfaf5c0 100644 --- a/cdk/include/mysql/cdk/common.h +++ b/cdk/include/mysql/cdk/common.h @@ -523,6 +523,13 @@ typedef cdk::api::Sort_direction Sort_direction; typedef cdk::api::Doc_base Param_source; +using cdk::api::View_security; +using cdk::api::View_algorithm; +using cdk::api::View_check; + +typedef cdk::api::View_options View_options; +typedef cdk::api::View_spec View_spec; + /* Classes for describing update operations ======================================== diff --git a/cdk/include/mysql/cdk/converters.h b/cdk/include/mysql/cdk/converters.h index 50cfe644a..f8c756271 100644 --- a/cdk/include/mysql/cdk/converters.h +++ b/cdk/include/mysql/cdk/converters.h @@ -163,11 +163,25 @@ class Expr_conv_base : m_expr(&expr) {} + Expr_conv_base(const Expr_from *expr) + : m_expr(expr) + {} + void reset(const Expr_from &expr) { m_expr = &expr; } + bool is_valid() const + { + return NULL != m_expr; + } + + const TO* get() const + { + return m_expr ? this : NULL; + } + void process(Prc_to &proc) const { if (!m_expr) diff --git a/cdk/include/mysql/cdk/mysqlx/session.h b/cdk/include/mysql/cdk/mysqlx/session.h index 6f7579d53..b18c1d580 100644 --- a/cdk/include/mysql/cdk/mysqlx/session.h +++ b/cdk/include/mysql/cdk/mysqlx/session.h @@ -102,6 +102,8 @@ class Cursor; template class Obj_ref : public Base { +protected: + string m_name; string m_name_original; bool m_has_name_original; @@ -112,6 +114,12 @@ class Obj_ref : public Base : m_has_name_original(false) {} + Obj_ref(const cdk::api::Ref_base &ref) + : m_name(ref.name()) + , m_name_original(ref.orig_name()) + , m_has_name_original(true) + {} + const string name() const { return m_name; } const string orig_name() const { @@ -365,6 +373,7 @@ using cdk::Limit; using cdk::Order_by; using cdk::Sort_direction; using cdk::Param_source; +using cdk::View_spec; typedef Session Reply_init; @@ -377,7 +386,6 @@ class Session : public api::Diagnostics , public Async_op , private protocol::mysqlx::Auth_processor - , private protocol::mysqlx::Reply_processor , private protocol::mysqlx::Mdata_processor , private protocol::mysqlx::Stmt_processor , private protocol::mysqlx::SessionState_processor @@ -509,6 +517,7 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL); Reply_init &coll_find(const Table_ref&, + const View_spec *view = NULL, const Expression *expr = NULL, const Expression::Document *proj = NULL, const Order_by *order_by = NULL, @@ -529,6 +538,7 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL); Reply_init &table_select(const Table_ref&, + const View_spec *view = NULL, const Expression *expr = NULL, const Projection *proj = NULL, const Order_by *order_by = NULL, @@ -547,6 +557,8 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL); + Reply_init &view_drop(const api::Table_ref&, bool check_existence = false); + /* Async (cdk::api::Async_op) @@ -599,6 +611,7 @@ class Session Mdata_processor (cdk::protocol::mysqlx::Mdata_processor) */ + void ok(string); void col_count(col_count_t nr_cols); void col_type(col_count_t pos, unsigned short type); void col_content_type(col_count_t pos, unsigned short type); @@ -637,7 +650,7 @@ class Session */ void send_cmd(); - void start_reading_row_set(); + void start_reading_result(); Proto_op* start_reading_row_data(protocol::mysqlx::Row_processor &prc); void start_reading_stmt_reply(); void start_authentication(const char* mechanism,bytes data,bytes response); diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index fb2163292..03a36651d 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -76,7 +76,10 @@ enum ClientMessages_Type { ClientMessages_Type_CRUD_UPDATE = 19, ClientMessages_Type_CRUD_DELETE = 20, ClientMessages_Type_EXPECT_OPEN = 24, - ClientMessages_Type_EXPECT_CLOSE = 25 + ClientMessages_Type_EXPECT_CLOSE = 25, + ClientMessages_Type_CRUD_CREATE_VIEW = 30, + ClientMessages_Type_CRUD_MODIFY_VIEW = 31, + ClientMessages_Type_CRUD_DROP_VIEW = 32 }; enum ServerMessages_Type { @@ -147,6 +150,9 @@ enum ServerMessages_Type { ExpectOpen, EXPECT_OPEN) \ MSG_CLIENT(X, Mysqlx::Crud::Delete, \ ExpectClose, EXPECT_CLOSE) \ + MSG_CLIENT(X, Mysqlx::Crud::CreateView, CreateView, CRUD_CREATE_VIEW) \ + MSG_CLIENT(X, Mysqlx::Crud::ModifyView, ModifyView, CRUD_MODIFY_VIEW) \ + MSG_CLIENT(X, Mysqlx::Crud::DropView, DropView, CRUD_DROP_VIEW) \ \ MSG_SERVER(X, Mysqlx::Ok, \ Ok, OK) \ @@ -408,9 +414,46 @@ typedef cdk::api::Sort_direction Sort_direction; typedef cdk::api::Projection Projection; typedef cdk::api::Columns Columns; +typedef cdk::api::View_options View_options; + } // api namespace +/* + Interfaces which specify parameters for Find and other CRUD operations, + such as Delete or Update, which can work on limited set of rwos/documents. + + Interface Select_spec specifies parameter common to all CRUD operations + which limit set of rows/documents. Interface Find_spec specifies additional + parameters of the Find operation. +*/ + +struct Select_spec +{ +public: + + typedef api::Db_obj Db_obj; + typedef api::Expression Expression; + typedef api::Order_by Order_by; + typedef api::Limit Limit; + + virtual const Db_obj& obj() const = 0; + virtual const Expression* select() const = 0; + virtual const Order_by* order() const = 0; + virtual const Limit* limit() const = 0; +}; + +struct Find_spec : public Select_spec +{ +public: + + typedef api::Projection Projection; + typedef api::Expr_list Expr_list; + + virtual const Projection* project() const = 0; + virtual const Expr_list* group_by() const = 0; + virtual const Expression* having() const = 0; +}; /* @@ -437,43 +480,122 @@ class Protocol Op& snd_AuthenticateContinue(bytes data); Op& snd_Close(); - Op& snd_StmtExecute(const char *ns, const string &stmt, api::Any_list *args); - -// Op& snd_PrepareStmt(stmt_id_t id, const string &stmt); -// Op& snd_PreparedStmtExecute(stmt_id_t id, cursor_id_t cid); -// Op& snd_CursorClose(cursor_id_t cid); -// Op& snd_PreparedStmtClose(stmt_id_t id); - -// Op& snd_CursorFetchRows(cursor_id_t cid, row_count_t limit); -// Op& snd_CursorFetchRows(cursor_id_t cid); - -// Op& snd_CursorFetchMetadata(cursor_id_t cid); - - Op& snd_Find(Data_model, - api::Db_obj&, - api::Expression* = NULL, // select - api::Projection* = NULL, // project - api::Order_by* = NULL, // order - api::Expr_list* = NULL, // group_by - api::Expression* = NULL, // having - api::Limit* = NULL, // limit - api::Args_map * = NULL); - - Op& snd_Insert(Data_model, api::Db_obj&, - const api::Columns*, - Row_source&, - api::Args_map *args = NULL); - Op& snd_Update(Data_model, api::Db_obj&, - api::Expression*, - Update_spec &, - api::Order_by* = NULL, - api::Limit* = NULL, - api::Args_map * = NULL); - Op& snd_Delete(Data_model, api::Db_obj&, - api::Expression* = NULL, - api::Order_by* = NULL, - api::Limit* = NULL, - api::Args_map * = NULL); + + /** + Send protocol command which executes a statement. + + Which statements are understood by the server are defined by the + X Protocol. Currently we use "sql" namespace to execute plain SQL + statements and commands in "admin" namespace for other operations + and queries. + + @param ns namespace used to interpret the statement + @param stmt the statement to be eecuted + @param args optional parameters of the statement + */ + + Op& snd_StmtExecute(const char *ns, const string &stmt, + const api::Any_list *args); + + + /** + Send CRUD Find command. + + This command returns rows from a table or documents from a collection. + Selected data can be transformed using a projection before sending to + the client. + + @param dm determines whether this command fetches rows or documents + + @param spec specifies source of the data, criteria selecting + rows/documents to be returned, optional projection and other parameters + of the commnad (@see Find_spec) + + @param args if expressions used in the specification use named parameters, + this argument map provides values of these parameters + */ + + Op& snd_Find(Data_model dm, const Find_spec &spec, + const api::Args_map *args = NULL); + + /** + Send CRUD Insert command. + + This command inserts rows into a table or documents into a collection + + @param dm determines whether this command inserts rows or documents + + @param obj target table or collection + + @param columns optional specification determining which columns of the + target table should be updated with provided data. + + @param data Object defining rows/documents to be inserted. It is a + sequence of tuples of expressions; each tuple in the sequence defines + values of fields in a single row to be inserted (when inserting documents, + there should be just one filed with the document). + + @param args defines values of named parameters, if any are used in the + expressions of the row source object + */ + + Op& snd_Insert(Data_model dm, api::Db_obj &obj, + const api::Columns *columns, + Row_source &data, + const api::Args_map *args = NULL); + + /** + Send CRUD Update command. + + This command updates existing rows in a table or documents in a collection. + In can work on a subset of rows or document defined by a select criteria. + + @param dm determines whether this command updates rows or documents + + @param select defines target table or collection whose data should be + modified and a subset of rows/documents that is affected by the command + + @param update a specification of what modifications should be applied to + each row/document + + @param args defines values of named parameters, if any are used in the + selection criteria or update specification. + */ + + Op& snd_Update(Data_model dm, + const Select_spec &select, + Update_spec &update, + const api::Args_map *args = NULL); + + /** + Send CRUD Delete command. + + This command removes all or selected rows/documents from a table or + collection. + + @param dm determines whether this command removes rows or documents + + @param select defines target table or collection whose data should be + modified and a subset of rows/documents to be deleted + + @param args defines values of named parameters, if any are used in the + selection criteria + */ + + Op& snd_Delete(Data_model dm, const Select_spec &select, + const api::Args_map *args = NULL); + + + Op& snd_CreateView(Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *columns, + api::View_options* = NULL, + const api::Args_map *args = NULL); + Op& snd_ModifyView(Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *columns, + api::View_options* = NULL, + const api::Args_map *args = NULL); + Op& snd_DropView(const api::Db_obj &obj, bool if_exists); + Op& rcv_AuthenticateReply(Auth_processor &); Op& rcv_Reply(Reply_processor &); @@ -837,7 +959,7 @@ class Row_processor : public Error_processor virtual void done(bool /*eod*/, bool /*more*/) {} }; -class Mdata_processor : public Error_processor +class Mdata_processor : public Reply_processor { public: @@ -998,6 +1120,16 @@ class Db_obj : public api::Db_obj Db_obj(string name, string schema) : m_name(name), m_schema(schema), m_schema_set(true) {} + Db_obj(const api::Db_obj &other) + : m_name(other.get_name()) + , m_schema_set(false) + { + if (!other.get_schema()) + return; + m_schema = *other.get_schema(); + m_schema_set = true; + } + virtual ~Db_obj() {} virtual const string& get_name() const { return m_name; }; @@ -1053,6 +1185,9 @@ class Limit : public api::Limit bool m_offset_set; public: + Limit() : m_row_count(0), m_offset(0), m_offset_set(false) + {} + Limit(row_count_t row_count) : m_row_count(row_count), m_offset(0), m_offset_set(false) {} Limit(row_count_t row_count, row_count_t offset) : m_row_count(row_count), m_offset(offset), diff --git a/cdk/include/mysql/cdk/session.h b/cdk/include/mysql/cdk/session.h index aeea6726c..cb95519fc 100644 --- a/cdk/include/mysql/cdk/session.h +++ b/cdk/include/mysql/cdk/session.h @@ -265,6 +265,7 @@ class Session */ Reply_init coll_find(const api::Object_ref &coll, + const View_spec *view = NULL, const Expression *expr = NULL, const Expression::Document *proj = NULL, const Order_by *order_by = NULL, @@ -273,7 +274,7 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL) { - return m_session->coll_find(coll, expr, proj, order_by, + return m_session->coll_find(coll, view, expr, proj, order_by, group_by, having, lim, param); } @@ -316,6 +317,7 @@ class Session */ Reply_init table_select(const api::Table_ref &tab, + const View_spec *view = NULL, const Expression *expr = NULL, const Projection *proj = NULL, const Order_by *order_by = NULL, @@ -324,7 +326,7 @@ class Session const Limit* lim = NULL, const Param_source *param = NULL) { - return m_session->table_select(tab, expr, proj, order_by, + return m_session->table_select(tab, view, expr, proj, order_by, group_by, having, lim, param); } @@ -383,6 +385,16 @@ class Session return m_session->table_update(tab, expr, us, order_by, lim, param); } + + // Views + // ----- + + Reply_init view_drop(const api::Table_ref &view, bool check_existence = false) + { + return m_session->view_drop(view, check_existence); + } + + // Async_op interface public: diff --git a/cdk/mysqlx/delayed_op.h b/cdk/mysqlx/delayed_op.h index 7f34e9cd3..39b0be010 100644 --- a/cdk/mysqlx/delayed_op.h +++ b/cdk/mysqlx/delayed_op.h @@ -30,6 +30,8 @@ #include #include "converters.h" +#include + namespace cdk { namespace mysqlx { @@ -110,6 +112,42 @@ class Proto_delayed_op }; +class Crud_op_base + : public Proto_delayed_op + , public protocol::mysqlx::api::Db_obj +{ +protected: + + string m_name; + string m_schema; + bool m_has_schema; + + Crud_op_base(Protocol &proto) + : Proto_delayed_op(proto) + , m_has_schema(false) + {} + + Crud_op_base(Protocol &proto, const api::Object_ref &obj) + : Proto_delayed_op(proto) + { + set(obj); + } + + void set(const api::Object_ref &obj) + { + m_name = obj.name(); + m_has_schema = (NULL != obj.schema()); + if (m_has_schema) + m_schema = obj.schema()->name(); + } + + // Db_obj + + const string& get_name() const { return m_name; } + const string* get_schema() const { return m_has_schema ? &m_schema : NULL; } + +}; + // ------------------------------------------------------------------------- @@ -144,14 +182,11 @@ class SndStmt class SndInsertDocs - : public Proto_delayed_op + : public Crud_op_base , public protocol::mysqlx::Row_source - , public protocol::mysqlx::api::Db_obj { protected: - const string m_schema; - const string m_table; cdk::Doc_source &m_docs; const Param_source *m_param; @@ -171,12 +206,10 @@ class SndInsertDocs public: - SndInsertDocs(Protocol& protocol, - const string &schema, const string &table, + SndInsertDocs(Protocol& protocol, const api::Table_ref &coll, cdk::Doc_source &docs, const Param_source *param) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) + : Crud_op_base(protocol, coll) , m_docs(docs) , m_param(param) {} @@ -202,10 +235,6 @@ class SndInsertDocs return m_docs.next(); } - // Db_obj - - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; @@ -213,14 +242,11 @@ class SndInsertDocs class SndInsertRows - : public Proto_delayed_op + : public Crud_op_base , public protocol::mysqlx::Row_source - , public protocol::mysqlx::api::Db_obj { protected: - const string m_schema; - const string m_table; Expr_converter m_conv; cdk::Row_source &m_rows; const api::Columns *m_cols; @@ -245,12 +271,11 @@ class SndInsertRows // TODO: Life-time of rows instance... SndInsertRows(Protocol& protocol, - const string &schema, const string &table, + const api::Table_ref &coll, cdk::Row_source &rows, const api::Columns *cols, const Param_source *param) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) + : Crud_op_base(protocol, coll) , m_rows(rows), m_cols(cols), m_param(param) {} @@ -270,10 +295,6 @@ class SndInsertRows return m_rows.next(); } - // Db_obj - - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; @@ -322,74 +343,98 @@ typedef Expr_conv_base< // ------------------------------------------------------------------------- +/* + Helper base class which implements protocol's Select_spec + (or Find_spec) interface. This is used by CRUD operations + which involve selecting a subset of rows/documents in the + table/colleciton. + + A CRUD operation class which derives from this Select_op_base + can be used as selection criteria specification as required + by protocol object methods. + + Note: This class uses converters to convert selection + parameters from generic cdk types to types required by + the protocol layer. +*/ -class SndDelete - : public Proto_delayed_op - , public Expression - , public protocol::mysqlx::api::Db_obj +template +class Select_op_base + : public Crud_op_base + , public IF { protected: - const string m_schema; - const string m_table; - const Expression *m_expr; - const Limit *m_limit; - const cdk::mysqlx::Order_by *m_order_by; - const Param_source *m_param; + Expr_converter m_expr_conv; + Param_converter m_param_conv; + Order_by_converter m_ord_conv; + const Limit *m_limit; + + + Select_op_base( + Protocol &protocol, + const api::Object_ref &obj, + const cdk::Expression *expr, + const cdk::Order_by *order_by, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL + ) + : Crud_op_base(protocol, obj) + , m_expr_conv(expr), m_param_conv(param), m_ord_conv(order_by) + , m_limit(lim) + {} - const cdk::protocol::mysqlx::Data_model m_data_model; - Proto_op* start() - { - Expr_converter conv; - Param_converter param_conv; - Order_by_converter ord_conv; + virtual ~Select_op_base() + {} - if (m_order_by) - ord_conv.reset(*m_order_by); - if (m_expr) - conv.reset(*m_expr); + // Select_spec - if (m_param) - param_conv.reset(*m_param); + const protocol::mysqlx::api::Db_obj& obj() const { return *this; } - return &m_protocol.snd_Delete(m_data_model, - *this, - (m_expr ? &conv : NULL), - (m_order_by ? &ord_conv : NULL), - (cdk::protocol::mysqlx::api::Limit*)m_limit, - (m_param ? ¶m_conv : NULL)); + const protocol::mysqlx::api::Expression* select() const + { + return m_expr_conv.get(); } -public: + const protocol::mysqlx::api::Order_by* order() const + { + return m_ord_conv.get(); + } - SndDelete(Protocol& protocol, cdk::protocol::mysqlx::Data_model data_model, - const string &schema, const string &table, - const Expression *expr, - const Order_by *order_by, - const Limit *lim = NULL, - const Param_source *param = NULL) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) - , m_expr(expr), m_limit(lim) - , m_order_by(order_by), m_param(param) - , m_data_model(data_model) - {} + const protocol::mysqlx::api::Limit* limit() const + { + return m_limit; + } -private: +}; - // Expression - void process(Expression::Processor &ep) const +// ------------------------------------------------------------------------- + + +template +class SndDelete + : public Select_op_base<> +{ +protected: + + Proto_op* start() { - m_expr->process(ep); + return &m_protocol.snd_Delete(DM, *this, m_param_conv.get()); } - // Db_obj +public: + + SndDelete(Protocol& protocol, const api::Object_ref &obj, + const cdk::Expression *expr, + const cdk::Order_by *order_by, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL) + : Select_op_base(protocol, obj, expr, order_by, lim, param) + {} - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; @@ -507,92 +552,290 @@ struct Find_traits }; +template class SndViewCrud; + + template class SndFind - : public Proto_delayed_op - , public protocol::mysqlx::api::Db_obj + : public Select_op_base { protected: typedef typename Find_traits::Projection Projection; typedef typename Find_traits::Projection_converter Projection_converter; - const string m_schema; - const string m_table; - const Expression *m_expr; - const Limit *m_limit; - const cdk::mysqlx::Order_by *m_order_by; - const Expr_list *m_group_by; - const Expression *m_having; - const Param_source *m_param; - const Projection *m_proj; + Projection_converter m_proj_conv; + Expr_list_converter m_group_by_conv; + Expr_converter m_having_conv; Proto_op* start() { - Expr_converter expr_conv; - Param_converter param_conv; - Order_by_converter ord_conv; - Projection_converter proj_conv; - Expr_converter having_conv; - Expr_list_converter group_by_conv; + return &m_protocol.snd_Find(DM, *this, m_param_conv.get()); + } + +public: - if (m_expr) - expr_conv.reset(*m_expr); + SndFind( + Protocol& protocol, const api::Table_ref &coll, + const cdk::Expression *expr = NULL, + const Projection *proj = NULL, + const cdk::Order_by *order_by = NULL, + const cdk::Expr_list *group_by = NULL, + const cdk::Expression *having = NULL, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL + ) + : Select_op_base(protocol, coll, expr, order_by, lim, param) + , m_proj_conv(proj) + , m_group_by_conv(group_by), m_having_conv(having) + {} - if (m_param) - param_conv.reset(*m_param); +private: + + const protocol::mysqlx::api::Projection* project() const + { + return m_proj_conv.get(); + } + + const protocol::mysqlx::api::Expr_list* group_by() const + { + return m_group_by_conv.get(); + } + + const protocol::mysqlx::api::Expression* having() const + { + return m_having_conv.get(); + } + + friend class SndViewCrud; +}; + + +// ------------------------------------------------------------------------- + +/* + Conversion from string processor used to process a list of view column names + to callbacks expected by protocol's column info processor. + Basically, each string in a list is reported as column name. Other column + specification parameters, such as alias, are not reported. +*/ + +struct String_to_col_prc_converter + : public Converter< + String_to_col_prc_converter, + cdk::api::String_processor, + cdk::protocol::mysqlx::api::Columns::Processor::Element_prc + > +{ + void val(const string &col) + { + m_proc->name(col); + } + + virtual ~String_to_col_prc_converter() + {} +}; + +typedef List_prc_converter Columns_prc_converter; - if (m_order_by) - ord_conv.reset(*m_order_by); - if (m_group_by) - group_by_conv.reset(*m_group_by); +/* + Delayed operation which sends view create or update request. These request + can include a find message. Whether update or create request should be sent + is determined by the view specification passed when creating this delayed + operation. +*/ + +template +class SndViewCrud + : public Crud_op_base + , public View_spec::Processor + , public cdk::protocol::mysqlx::api::Columns + , public protocol::mysqlx::api::View_options +{ + const View_spec *m_view; + SndFind *m_find; + bool m_update; + bool m_has_cols; + bool m_has_opts; - if (m_having) - having_conv.reset(*m_having); + // Columns - if (m_proj) - proj_conv.reset(*m_proj); + void process(cdk::protocol::mysqlx::api::Columns::Processor &prc) const + { + assert(m_view); + + /* + Column names are reported to the protocol layer as column specification + (as used by snd_Insert() for example). We use processor converter to convert + string list processor callbacks to these of Columns specification + processor. + */ + + Columns_prc_converter conv; + conv.reset(prc); + + /* + Process view specification extracting columns information and passing + it to the converter. + */ + + struct : public cdk::View_spec::Processor + { + String_list::Processor *m_prc; - return &m_protocol.snd_Find(DM, *this, - (m_expr ? &expr_conv : NULL), - (m_proj ? &proj_conv : NULL), - (m_order_by ? &ord_conv : NULL), - (m_group_by ? &group_by_conv : NULL), - (m_having ? &having_conv : NULL), - (cdk::protocol::mysqlx::api::Limit*)m_limit, - (m_param ? ¶m_conv : NULL)); + void name(const Table_ref&, bool) {} + + Options::Processor* options() + { + return NULL; + } + + List_processor* columns() + { + return m_prc; + } + + } + vprc; + + vprc.m_prc = &conv; + m_view->process(vprc); + } + + protocol::mysqlx::api::Columns* + get_cols() + { + return m_has_cols ? this : NULL; + } + + // View_options + + void process(protocol::mysqlx::api::View_options::Processor &prc) const + { + assert(m_view); + + /* + Process view specification extracting options information and passing + it to the processor. + */ + + struct Opts : public cdk::View_spec::Processor + { + Options::Processor *m_prc; + + void name(const Table_ref&, bool) {} + + Options::Processor* options() + { + return m_prc; + } + + List_processor* columns() + { + return NULL; + } + } + vprc; + + vprc.m_prc = &prc; + m_view->process(vprc); + } + + protocol::mysqlx::api::View_options* + get_opts() + { + return m_has_opts ? this : NULL; + } + + + Proto_op* start() + { + if (m_update) + return &m_protocol.snd_ModifyView(DM, *this, *m_find, + get_cols(), get_opts()); + else + return &m_protocol.snd_CreateView(DM, *this, *m_find, + get_cols(), get_opts()); } public: - SndFind(Protocol& protocol, - const string &schema, const string &table, - const Expression *expr = NULL, - const Projection *proj = NULL, - const cdk::mysqlx::Order_by *order_by = NULL, - const Expr_list *group_by = NULL, - const Expression *having = NULL, - const Limit *lim = NULL, - const Param_source *param = NULL) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) - , m_expr(expr), m_limit(lim), m_order_by(order_by) - , m_group_by(group_by), m_having(having) - , m_param(param), m_proj(proj) - {} + SndViewCrud(const View_spec &view, SndFind *find = NULL) + : Crud_op_base(find->m_protocol) + , m_view(&view), m_find(find), m_update(false) + , m_has_cols(false), m_has_opts(false) + { + /* + Process view specification to extract view name and information which + type of view operation should be sent (m_update member). This also + determines whether columns and options information is present in the + specification. + */ + view.process(*this); + } + + ~SndViewCrud() + { + delete m_find; + } private: - // Db_obj + // View_spec::Processor + + void name(const Table_ref &view, bool update = false) + { + Crud_op_base::set(view); + m_update = update; + } + + List_processor* columns() + { + m_has_cols = true; + /* + Note: we do not process columns here, it is done above when this + object acts as protocol Columns specification. + */ + return NULL; + } + + Options::Processor* options() + { + m_has_opts = true; + return NULL; + } + +}; + + +class SndDropView + : public Crud_op_base +{ + bool m_check_exists; + + Proto_op* start() + { + return &m_protocol.snd_DropView(*this, m_check_exists); + } + +public: + + SndDropView( + Protocol &protocol, + const api::Object_ref &view, + bool check_exists + ) + : Crud_op_base(protocol, view) + , m_check_exists(check_exists) + {} - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; // ------------------------------------------------------------------------- + /* Update_converter */ @@ -773,66 +1016,30 @@ class Update_converter template class SndUpdate - : public Proto_delayed_op - , public protocol::mysqlx::api::Db_obj + : public Select_op_base<> { protected: - const string m_schema; - const string m_table; - const Expression *m_expr; - const Update_spec &m_us; - const cdk::mysqlx::Order_by *m_order_by; - const Limit *m_limit; - const Param_source *m_param; + Update_converter m_upd_conv; Proto_op* start() { - Expr_converter conv; - Param_converter param_conv; - Order_by_converter ord_conv; - - if (m_expr) - conv.reset(*m_expr); - - if (m_param) - param_conv.reset(*m_param); - - if (m_order_by) - ord_conv.reset(*m_order_by); - - Update_converter u_conv(DM, m_us); - - return &m_protocol.snd_Update(DM, - *this, - (m_expr ? &conv : NULL), - u_conv, - (m_order_by ? &ord_conv : NULL), - const_cast(m_limit), - (m_param ? ¶m_conv : NULL)); + return &m_protocol.snd_Update(DM, *this, m_upd_conv, m_param_conv.get()); } public: SndUpdate(Protocol& protocol, - const string &schema, const string &table, - const Expression *expr, - const Update_spec &us, - const Order_by *order_by, - const Limit *lim = NULL, - const Param_source *param = NULL) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) - , m_expr(expr), m_us(us), m_order_by(order_by), m_limit(lim), m_param(param) + const api::Table_ref &table, + const cdk::Expression *expr, + const cdk::Update_spec &us, + const cdk::Order_by *order_by, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL) + : Select_op_base(protocol, table, expr, order_by, lim, param) + , m_upd_conv(DM, us) {} -private: - - - // Db_obj - - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; diff --git a/cdk/mysqlx/result.cc b/cdk/mysqlx/result.cc index 7520aa000..3fec640a4 100644 --- a/cdk/mysqlx/result.cc +++ b/cdk/mysqlx/result.cc @@ -63,7 +63,7 @@ void Reply::init(Reply_init &init) init.register_reply(this); m_session->send_cmd(); - m_session->start_reading_row_set(); + m_session->start_reading_result(); } @@ -563,7 +563,9 @@ void Cursor::done(bool eod, bool more) if (more) { - m_session.start_reading_row_set(); + // TODO: Normally start_reading_result() accepts OK message from + // server, but here it should not. + m_session.start_reading_result(); } else if (eod) { diff --git a/cdk/mysqlx/session.cc b/cdk/mysqlx/session.cc index c0ecb7c26..395edd069 100644 --- a/cdk/mysqlx/session.cc +++ b/cdk/mysqlx/session.cc @@ -334,10 +334,12 @@ void Session::rollback() } -Reply_init& Session::coll_add(const Table_ref &coll, Doc_source &docs, const Param_source *param) +Reply_init& Session::coll_add(const Table_ref &coll, + Doc_source &docs, + const Param_source *param) { return set_command( - new SndInsertDocs(m_protocol, coll.schema()->name(), coll.name(), docs, param) + new SndInsertDocs(m_protocol, coll, docs, param) ); } @@ -348,12 +350,14 @@ Reply_init& Session::coll_remove(const Table_ref &coll, const Param_source *param) { return set_command( - new SndDelete(m_protocol, protocol::mysqlx::DOCUMENT, - coll.schema()->name(), coll.name(), expr,order_by, lim, param) + new SndDelete( + m_protocol, coll, expr,order_by, lim, param + ) ); } Reply_init& Session::coll_find(const Table_ref &coll, + const View_spec *view, const Expression *expr, const Expression::Document *proj, const Order_by *order_by, @@ -362,11 +366,16 @@ Reply_init& Session::coll_find(const Table_ref &coll, const Limit *lim, const Param_source *param) { - return set_command( - new SndFind(m_protocol, - coll.schema()->name(), coll.name(), expr, - proj, order_by, group_by, having, lim, param) - ); + SndFind *find + = new SndFind( + m_protocol, coll, expr, proj, order_by, + group_by, having, lim, param + ); + + if (view) + return set_command(new SndViewCrud(*view, find)); + + return set_command(find); } Reply_init& Session::coll_update(const api::Table_ref &coll, @@ -377,14 +386,9 @@ Reply_init& Session::coll_update(const api::Table_ref &coll, const Param_source *param) { return set_command( - new SndUpdate(m_protocol, - coll.schema()->name(), - coll.name(), - expr, - us, - order_by, - lim, - param) + new SndUpdate( + m_protocol, coll, expr, us, order_by, lim, param + ) ); } @@ -392,7 +396,7 @@ Reply_init& Session::table_insert(const Table_ref &coll, Row_source &rows, const api::Columns *cols, const Param_source *param) { return set_command( - new SndInsertRows(m_protocol, coll.schema()->name(), coll.name(), rows, cols, param) + new SndInsertRows(m_protocol, coll, rows, cols, param) ); } @@ -403,13 +407,14 @@ Reply_init& Session::table_delete(const Table_ref &coll, const Param_source *param) { return set_command( - new SndDelete(m_protocol, protocol::mysqlx::TABLE, - coll.schema()->name(), coll.name(), - expr, order_by, lim, param) + new SndDelete( + m_protocol, coll, expr, order_by, lim, param + ) ); } Reply_init& Session::table_select(const Table_ref &coll, + const View_spec *view, const Expression *expr, const Projection *proj, const Order_by *order_by, @@ -418,11 +423,16 @@ Reply_init& Session::table_select(const Table_ref &coll, const Limit *lim, const Param_source *param) { - return set_command( - new SndFind(m_protocol, - coll.schema()->name(), coll.name(), expr, proj, - order_by, group_by, having, lim, param) - ); + SndFind *find + = new SndFind( + m_protocol, coll, expr, proj, order_by, + group_by, having, lim, param + ); + + if (view) + return set_command(new SndViewCrud(*view, find)); + + return set_command(find); } Reply_init& Session::table_update(const api::Table_ref &coll, @@ -433,18 +443,22 @@ Reply_init& Session::table_update(const api::Table_ref &coll, const Param_source *param) { return set_command( - new SndUpdate(m_protocol, - coll.schema()->name(), - coll.name(), - expr, - us, - order_by, - lim, - param) + new SndUpdate( + m_protocol, coll, expr, us, order_by, lim, param + ) ); } +Reply_init& Session::view_drop(const api::Table_ref &view, bool check_existence) +{ + return set_command( + new SndDropView(m_protocol, view, check_existence) + ); +} + + + Reply_init &Session::set_command(Proto_op *cmd) { if (!is_valid()) @@ -551,6 +565,10 @@ void Session::add_diagnostics(Severity::value level, unsigned code, } +void Session::ok(string) +{} + + void Session::col_count(col_count_t nr_cols) { //When all columns metadata arrived... @@ -714,7 +732,7 @@ void Session::send_cmd() } -void Session::start_reading_row_set() +void Session::start_reading_result() { m_col_metadata.reset(new Mdata_storage()); m_executed = false; diff --git a/cdk/protocol/mysqlx/crud.cc b/cdk/protocol/mysqlx/crud.cc index 61e936535..b639e1456 100644 --- a/cdk/protocol/mysqlx/crud.cc +++ b/cdk/protocol/mysqlx/crud.cc @@ -55,7 +55,7 @@ namespace mysqlx { Helper function template to set a db object for a given message of MSG class */ -template void set_db_obj(api::Db_obj &db_obj, MSG &msg) +template void set_db_obj(const api::Db_obj &db_obj, MSG &msg) { Mysqlx::Crud::Collection *proto_collect = msg.mutable_collection(); @@ -82,7 +82,7 @@ template void set_data_model(Data_model dm, MSG &msg) Helper function template to set `limit` field inside message of type MSG. */ -template void set_limit(api::Limit &lim, MSG &msg) +template void set_limit(const api::Limit &lim, MSG &msg) { Mysqlx::Crud::Limit *proto_lim = msg.mutable_limit(); @@ -100,8 +100,8 @@ template void set_limit(api::Limit &lim, MSG &msg) MSG. */ -template void set_criteria(api::Expression &api_expr, MSG &msg, - Args_conv &conv /*= NULL*/) +template void set_criteria(const api::Expression &api_expr, + MSG &msg, Args_conv &conv) { Mysqlx::Expr::Expr *pb_expr = msg.mutable_criteria(); @@ -110,6 +110,26 @@ template void set_criteria(api::Expression &api_expr, MSG &msg, } +/* + Helper function template to set selection parameters given by a + `Select_spec` object. +*/ + +template +void set_select(const Select_spec &sel, MSG &msg, Args_conv &conv) +{ + set_db_obj(sel.obj(), msg); + + if (sel.select()) + set_criteria(*sel.select(), msg, conv); + + if (sel.order()) + set_order_by(*sel.order(), msg, conv); + + if (sel.limit()) + set_limit(*sel.limit(), msg); +} + // ------------------------------------------------------------------------- /* @@ -219,7 +239,7 @@ struct Ord_msg_traits is stored in a repeated `order` field within the message. */ -template void set_order_by(api::Order_by &order_by, +template void set_order_by(const api::Order_by &order_by, MSG &msg, Args_conv &conv) { @@ -390,7 +410,7 @@ void set_doc_path(Mysqlx::Expr::ColumnIdentifier *p_col_id, /* - Storing Group_by information inside Find protocol command. + Storing Group_by information inside Find protocol command. This command has a repeated `grouping` field of type Mysqlx::Expr::Expr. Below we fill it using a builder created from Array_builer<> template. Such builder process list of @@ -412,59 +432,49 @@ struct Group_by_traits }; -Protocol::Op& -Protocol::snd_Find( - Data_model dm, - api::Db_obj &db_obj, - api::Expression *api_expr, - api::Projection *proj, - api::Order_by *order, - api::Expr_list *group_by, - api::Expression *having, - api::Limit *lim, - api::Args_map *args) +void set_find(Mysqlx::Crud::Find &msg, + Data_model dm, const Find_spec &fs, const api::Args_map *args) { - Mysqlx::Crud::Find find; - Placeholder_conv_imp conv; - set_db_obj(db_obj, find); - set_data_model(dm, find); + set_data_model(dm, msg); if (args) - set_args(*args, find, conv); - - if (api_expr) - set_criteria(*api_expr, find, conv); + set_args(*args, msg, conv); - if (lim) - set_limit(*lim, find); + set_select(fs, msg, conv); - if (order) - set_order_by(*order, find, conv); - - if (proj) + if (fs.project()) { - Array_builder + Array_builder proj_builder; - proj_builder.reset(find, &conv); - proj->process(proj_builder); + proj_builder.reset(msg, &conv); + fs.project()->process(proj_builder); } - if (group_by) + if (fs.group_by()) { Array_builder group_by_builder; - group_by_builder.reset(find, &conv); - group_by->process(group_by_builder); + group_by_builder.reset(msg, &conv); + fs.group_by()->process(group_by_builder); } - if (having) + if (fs.having()) { Expr_builder expr_builder; - expr_builder.reset(*find.mutable_grouping_criteria()); - having->process(expr_builder); + expr_builder.reset(*msg.mutable_grouping_criteria()); + fs.having()->process(expr_builder); } +} + + +Protocol::Op& +Protocol::snd_Find(Data_model dm, const Find_spec &fs, const api::Args_map *args) +{ + Mysqlx::Crud::Find find; + + set_find(find, dm, fs, args); return get_impl().snd_start(find, msg_type::cli_CrudFind); } @@ -531,7 +541,7 @@ Protocol::snd_Insert( api::Db_obj &db_obj, const api::Columns *columns, Row_source &rs, - api::Args_map *args) + const api::Args_map *args) { Mysqlx::Crud::Insert insert; @@ -637,30 +647,19 @@ class Update_builder Protocol::Op& Protocol::snd_Update( Data_model dm, - api::Db_obj &db_obj, - api::Expression *api_expr, + const Select_spec &sel, Update_spec &us, - api::Order_by *order, - api::Limit *lim, - api::Args_map *args) + const api::Args_map *args) { Mysqlx::Crud::Update update; Placeholder_conv_imp conv; - set_db_obj(db_obj, update); set_data_model(dm, update); if (args) set_args(*args, update, conv); - if (api_expr) - set_criteria(*api_expr, update, conv); - - if (order) - set_order_by(*order, update, conv); - - if (lim) - set_limit(*lim, update); + set_select(sel, update, conv); while (us.next()) { @@ -676,34 +675,181 @@ Protocol::Op& Protocol::snd_Update( Protocol::Op& -Protocol::snd_Delete( - Data_model dm, - api::Db_obj &db_obj, - api::Expression *api_expr, - api::Order_by *order_by, - api::Limit *lim, - api::Args_map *args) +Protocol::snd_Delete(Data_model dm, const Select_spec &sel, const api::Args_map *args) { Mysqlx::Crud::Delete del; Placeholder_conv_imp conv; - set_db_obj(db_obj, del); set_data_model(dm, del); if (args) set_args(*args, del, conv); - if (api_expr) - set_criteria(*api_expr, del, conv); + set_select(sel, del, conv); - if (lim) - set_limit(*lim, del); + return get_impl().snd_start(del, msg_type::cli_CrudDelete); +} - if (order_by) - set_order_by(*order_by, del, conv); - return get_impl().snd_start(del, msg_type::cli_CrudDelete); +// ------------------------------------------------------------------------- + + +template +void set_view_columns(MSG &msg, const api::Columns &cols) +{ + struct + : public api::Columns::Processor + , api::Columns::Processor::Element_prc + { + MSG *m_msg; + + // List processor + + void list_begin() {} + void list_end() {} + + Element_prc* list_el() + { + return this; + } + + // Column_processor + + void name(const string &col) + { + m_msg->add_column(col); + } + + virtual void alias(const string&) + { + THROW( + "Unexpected column alias specification when processing view columns" + ); + } + + virtual Path_prc* path() + { + THROW( + "Unexpected path specification when processing view columns" + ); + } + } + prc; + + prc.m_msg = &msg; + cols.process(prc); +} + + +template +void set_view_options(MSG &msg, api::View_options &opts) +{ + struct : public api::View_options::Processor + { + MSG *m_msg; + + void security(View_security_t security) + { + switch (security) + { + case cdk::api::View_security::DEFINER: + m_msg->set_security(Mysqlx::Crud::DEFINER); + break; + case cdk::api::View_security::INVOKER: + m_msg->set_security(Mysqlx::Crud::INVOKER); + break; + } + } + + void algorithm(View_algorithm_t alg) + { + switch (alg) + { + case cdk::api::View_algorithm::UNDEFINED: + m_msg->set_algorithm(Mysqlx::Crud::UNDEFINED); + break; + case cdk::api::View_algorithm::MERGE: + m_msg->set_algorithm(Mysqlx::Crud::MERGE); + break; + case cdk::api::View_algorithm::TEMPTABLE: + m_msg->set_algorithm(Mysqlx::Crud::TEMPTABLE); + break; + } + } + + void check(View_check_t check) + { + switch (check) + { + case cdk::api::View_check::LOCAL: + m_msg->set_check(Mysqlx::Crud::LOCAL); + break; + case cdk::api::View_check::CASCADED: + m_msg->set_check(Mysqlx::Crud::CASCADED); + break; + } + } + } + prc; + + prc.m_msg = &msg; + opts.process(prc); } +Protocol::Op& +Protocol::snd_CreateView( + Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *cols, + api::View_options *opts, + const api::Args_map *args +) +{ + Mysqlx::Crud::CreateView view; + + set_db_obj(obj, view); + + if (cols) + set_view_columns(view, *cols); + + if (opts) + set_view_options(view, *opts); + + set_find(*view.mutable_stmt(), dm, query, args); + return get_impl().snd_start(view, msg_type::cli_CreateView); +} + + +Protocol::Op& +Protocol::snd_ModifyView( + Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *cols, + api::View_options *opts, + const api::Args_map *args +) +{ + Mysqlx::Crud::ModifyView modify; + + set_db_obj(obj, modify); + + if (cols) + set_view_columns(modify, *cols); + + if (opts) + set_view_options(modify, *opts); + + set_find(*modify.mutable_stmt(), dm, query, args); + + return get_impl().snd_start(modify, msg_type::cli_ModifyView); +} + + +Protocol::Op& Protocol::snd_DropView(const api::Db_obj &obj, bool check_exists) +{ + Mysqlx::Crud::DropView drop; + set_db_obj(obj, drop); + drop.set_if_exists(!check_exists); + return get_impl().snd_start(drop, msg_type::cli_DropView); +} + }}} // cdk::protocol::mysqlx diff --git a/cdk/protocol/mysqlx/pb/mysqlx.proto b/cdk/protocol/mysqlx/pb/mysqlx.proto index acf581d29..a0e9a237d 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -73,6 +73,10 @@ message ClientMessages { EXPECT_OPEN = 24; EXPECT_CLOSE = 25; + + CRUD_CREATE_VIEW = 30; + CRUD_MODIFY_VIEW = 31; + CRUD_DROP_VIEW = 32; } } diff --git a/cdk/protocol/mysqlx/pb/mysqlx_connection.proto b/cdk/protocol/mysqlx/pb/mysqlx_connection.proto index ddb4f3864..91484786b 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_connection.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_connection.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_crud.proto b/cdk/protocol/mysqlx/pb/mysqlx_crud.proto index 31d5f65ce..e046f2c62 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_crud.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_crud.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -192,3 +192,85 @@ message Delete { repeated Order order = 5; }; + +// ViewAlgorithm defines how MySQL Server processes the view +enum ViewAlgorithm { + UNDEFINED =1; // MySQL chooses which algorithm to use + MERGE = 2; // the text of a statement that refers to the view and the view definition are merged + TEMPTABLE = 3; // the view are retrieved into a temporary table +} + +// ViewSqlSecurity defines the security context in which the view is going to be +// executed, this means that VIEW can be executed with current user permissions or +// with permissions of the uses who defined the VIEW +enum ViewSqlSecurity { + INVOKER = 1; + DEFINER = 2; +} + + +// ViewCheckOption limits the write operations done on a `VIEW` +// (`INSERT`, `UPDATE`, `DELETE`) to rows in which the `WHERE` clause is `TRUE` +enum ViewCheckOption { + LOCAL = 1; // the view WHERE clause is checked, but no underlying views are checked + CASCADED = 2; // the view WHERE clause is checked, then checking recurses to underlying views +} + + +// CreateView create view based on indicated Mysqlx.Crud.Find message +// +// param collection: name of the VIEW object, which should be created +// param definer: user name of the definer, if the value isn't set then the definer is current user +// param algorithm: defines how MySQL Server processes the view +// param security: defines the security context in which the view is going be executed +// param check: limits the write operations done on a VIEW +// param column: defines the list of aliases for column names specified in `stmt` +// param stmt: Mysqlx.Crud.Find message from which the SELECT statement is going to be build +// param replace_existing: if true then suppress error when created view already exists; just replace it + +message CreateView { + required Collection collection = 1; + + optional string definer = 2; + optional ViewAlgorithm algorithm = 3 [default = UNDEFINED]; + optional ViewSqlSecurity security = 4 [default = DEFINER]; + optional ViewCheckOption check = 5; + + repeated string column = 6; + required Find stmt = 7; + optional bool replace_existing = 8 [default = false]; +} + + +// ModifyView modify existing view based on indicated Mysqlx.Crud.Find message +// +// param collection: name of the VIEW object, which should be modified +// param definer: user name of the definer, if the value isn't set then the definer is current user +// param algorithm: defined how MySQL Server processes the view +// param security: defines the security context in which the view is going be executed +// param check: limits the write operations done on a VIEW +// param column: defines the list of aliases for column names specified in `stmt` +// param stmt: Mysqlx.Crud.Find message from which the SELECT statement is going to be build + +message ModifyView { + required Collection collection = 1; + + optional string definer = 2; + optional ViewAlgorithm algorithm = 3; + optional ViewSqlSecurity security = 4; + optional ViewCheckOption check = 5; + + repeated string column = 6; + optional Find stmt = 7; +} + + +// DropView removing existing view +// +// param collection: name of the VIEW object, which should be deleted +// param if_exists: if true then suppress error when deleted view does not exists + +message DropView { + required Collection collection = 1; + optional bool if_exists = 2 [ default = false ]; +} diff --git a/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto b/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto index 04a948c89..f4f5ba1f8 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto @@ -31,14 +31,14 @@ message Scalar { required bytes value = 1; optional uint64 collation = 2; }; - -// an opaque octet sequence, with an optional content_type -// See ``Mysqlx.Resultset.ColumnMetadata`` for list of known values. -message Octets { - required bytes value = 1; - optional uint32 content_type = 2; -}; - + + // an opaque octet sequence, with an optional content_type + // See ``Mysqlx.Resultset.ColumnMetadata`` for list of known values. + message Octets { + required bytes value = 1; + optional uint32 content_type = 2; + }; + enum Type { V_SINT = 1; V_UINT = 2; diff --git a/cdk/protocol/mysqlx/pb/mysqlx_expect.proto b/cdk/protocol/mysqlx/pb/mysqlx_expect.proto index b7988191a..cd8611384 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_expect.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_expect.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_expr.proto b/cdk/protocol/mysqlx/pb/mysqlx_expr.proto index 5a1aa6afd..fb5057878 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_expr.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_expr.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_notice.proto b/cdk/protocol/mysqlx/pb/mysqlx_notice.proto index af52ec5c2..bd9104ca2 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_notice.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_notice.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -29,6 +29,7 @@ syntax = "proto2"; // * is sent from the server to the client // * may be global or relate to the current message sequence package Mysqlx.Notice; +option java_package = "com.mysql.cj.mysqlx.protobuf"; import "mysqlx_datatypes.proto"; diff --git a/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto b/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto index 9ecbf889b..bee493760 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto @@ -424,6 +424,16 @@ message FetchDone { // BYTES 0x0001 rightpad // ======= ====== =========== // +// ====== ================ +// value description +// ====== ================ +// 0x0010 NOT_NULL +// 0x0020 PRIMARY_KEY +// 0x0040 UNIQUE_KEY +// 0x0080 MULTIPLE_KEY +// 0x0100 AUTO_INCREMENT +// ====== ================ +// // default: 0 // :param content_type: // a hint about the higher-level encoding of a BYTES field @@ -487,7 +497,8 @@ message ColumnMetaData { // Row in a Resultset // // a row is represented as a list of fields encoded as byte blobs. -// Value of each field is encoded as sequence of bytes using encoding appropriate for the +// Blob of size 0 represents the NULL value. Otherwise, if it contains at least +// one byte, it encodes a non-null value of the field using encoding appropriate for the // type of the value given by ``ColumnMetadata``, as specified // in the :protobuf:msg:`Mysqlx.Resultset::ColumnMetaData` description. // diff --git a/cdk/protocol/mysqlx/pb/mysqlx_session.proto b/cdk/protocol/mysqlx/pb/mysqlx_session.proto index 818a4c788..5a6842433 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_session.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_session.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_sql.proto b/cdk/protocol/mysqlx/pb/mysqlx_sql.proto index 05e4d843b..f955757ff 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_sql.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_sql.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/protocol.cc b/cdk/protocol/mysqlx/protocol.cc index a70187fcc..70a0e1876 100644 --- a/cdk/protocol/mysqlx/protocol.cc +++ b/cdk/protocol/mysqlx/protocol.cc @@ -191,7 +191,7 @@ Protocol::Op& Protocol_impl::snd_start(Message &msg, msg_type_t msg_type) using std::endl; cerr << endl; - cerr << ">>>> Seding message >>>>" << endl; + cerr << ">>>> Sending message >>>>" << endl; cerr << "of type " << msg_type << ": " << msg_type_name(CLIENT, msg_type) << endl; cerr << msg.DebugString(); diff --git a/cdk/protocol/mysqlx/protocol.h b/cdk/protocol/mysqlx/protocol.h index 853909049..a4695b33f 100644 --- a/cdk/protocol/mysqlx/protocol.h +++ b/cdk/protocol/mysqlx/protocol.h @@ -528,7 +528,6 @@ class Op_rcv : public Op_base { switch (type) { - // TODO: Notice case msg_type::Error: return EXPECTED; case msg_type::Notice: return EXPECTED; default: return do_next_msg(type); diff --git a/cdk/protocol/mysqlx/rset.cc b/cdk/protocol/mysqlx/rset.cc index 373843939..b49947d9a 100644 --- a/cdk/protocol/mysqlx/rset.cc +++ b/cdk/protocol/mysqlx/rset.cc @@ -110,7 +110,7 @@ class Rcv_result_base : public Op_rcv } */ - enum { MDATA, ROWS, CLOSE, DONE } m_result_state, m_next_state; + enum { START, MDATA, ROWS, CLOSE, DONE } m_result_state, m_next_state; row_count_t m_rcount; col_count_t m_ccount; @@ -164,7 +164,7 @@ class Rcv_result : public Message_dispatcher Rcv_result_base::Rcv_result_base(Protocol_impl &proto) : Op_rcv(proto) - , m_result_state(MDATA) + , m_result_state(START) , m_rcount(0) , m_ccount(0) { @@ -181,7 +181,7 @@ Rcv_result_base::Rcv_result_base(Protocol_impl &proto) void Rcv_result_base::resume(Mdata_processor &prc) { - if (MDATA != m_result_state) + if (START != m_result_state && MDATA != m_result_state) throw_error("Rcv_result: incorrect resume: attempt to read meta-data"); //TODO: Improve error report m_ccount = 0; m_completed = false; @@ -295,6 +295,18 @@ Op_rcv::Next_msg Rcv_result_base::do_next_msg(msg_type_t type) switch (m_result_state) { + case START: + + if (msg_type::Ok == type) + { + m_next_state = DONE; + m_completed = true; + return EXPECTED; + } + + m_next_state = MDATA; + // fall through to MDATA case + case MDATA: /* @@ -318,6 +330,7 @@ Op_rcv::Next_msg Rcv_result_base::do_next_msg(msg_type_t type) switch (type) { + case msg_type::ColumnMetaData: return EXPECTED; /* @@ -625,6 +638,13 @@ void Rcv_result_base::process_msg_with(Mysqlx::Resultset::ColumnMetaData &col_md mdata_proc.col_flags(ccount, col_mdata.flags()); } +template<> +void Rcv_result_base::process_msg_with(Mysqlx::Ok &ok, + Mdata_processor &prc) +{ + prc.ok(ok.msg()); +} + template<> void Rcv_result_base::process_msg_with(Mysqlx::Sql::StmtExecuteOk &ok, @@ -656,6 +676,7 @@ void Rcv_result::do_process_msg(msg_type_t type, Message &msg) switch (m_result_state) { + case START: case MDATA: Dispatcher::process_msg_with(type, msg, *static_cast(m_prc)); break; diff --git a/cdk/protocol/mysqlx/stmt.cc b/cdk/protocol/mysqlx/stmt.cc index 7398e11f1..1cfa95ccf 100644 --- a/cdk/protocol/mysqlx/stmt.cc +++ b/cdk/protocol/mysqlx/stmt.cc @@ -72,7 +72,7 @@ struct Arr_msg_traits Protocol::Op& Protocol::snd_StmtExecute(const char *ns, const string &stmt, - api::Any_list *args) + const api::Any_list *args) { Mysqlx::Sql::StmtExecute stmt_exec; diff --git a/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc b/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc index 5d2e62df8..2abb88a88 100644 --- a/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc +++ b/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc @@ -174,6 +174,78 @@ class Update }; +/* + Class implementing protocol Find_spec interface, as required by + Protocol methods which send CRUD commands. +*/ + +class Find + : public protocol::mysqlx::Find_spec +{ + protocol::mysqlx::Db_obj m_obj; + const Expression *m_expr; + const Projection *m_proj; + cdk::test::proto::Limit m_lim; + bool m_has_lim; + +public: + + Find(const Db_obj &obj, + const Expression *criteria, row_count_t limit, row_count_t skip = 0) + : m_obj(obj) + , m_expr(criteria), m_proj(NULL) + , m_lim(limit, skip), m_has_lim(true) + {} + + Find(const Db_obj &obj, + const Expression *criteria = NULL, + const Projection *proj = NULL) + : m_obj(obj) + , m_expr(criteria) + , m_proj(proj) + , m_has_lim(false) + {} + +private: + + const Db_obj& obj() const + { + return m_obj; + } + + const Expression* select() const + { + return m_expr; + } + + const Order_by* order() const + { + return NULL; + } + + const Limit* limit() const + { + return m_has_lim ? &m_lim : NULL; + } + + const Projection* project() const + { + return m_proj; + } + + const Expr_list* group_by() const + { + return NULL; + } + + const Expression* having() const + { + return NULL; + } + +}; + + TEST_F(Protocol_mysqlx_xplugin, crud_basic) { SKIP_IF_NO_XPLUGIN; @@ -189,15 +261,10 @@ TEST_F(Protocol_mysqlx_xplugin, crud_basic) Protocol &proto= get_proto(); Db_obj db_obj("crud_basic", "crud_test_db"); - Limit lim1(1, 1); + Find find1(db_obj, NULL, 1, 1); + cout <<"Find" < Date: Fri, 23 Dec 2016 23:21:27 +1100 Subject: [PATCH 36/79] Improved UUID generator --- cdk/extra/uuid/doc/uuid.txt | 131 +++---- cdk/extra/uuid/include/uuid_gen.h | 23 +- cdk/extra/uuid/src/uuid_gen.cc | 524 +++++++-------------------- cdk/extra/uuid/testing/tests_uuid.cc | 24 +- devapi/collection_crud.cc | 26 +- include/mysql_xapi.h | 3 +- xapi/mysqlx.cc | 6 + xapi/row.cc | 29 +- 8 files changed, 240 insertions(+), 526 deletions(-) diff --git a/cdk/extra/uuid/doc/uuid.txt b/cdk/extra/uuid/doc/uuid.txt index f064d475c..4fdd2c04d 100644 --- a/cdk/extra/uuid/doc/uuid.txt +++ b/cdk/extra/uuid/doc/uuid.txt @@ -1,25 +1,3 @@ -# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. -# -# The MySQL Connector/C++ is licensed under the terms of the GPLv2 -# , like most -# MySQL Connectors. There are special exceptions to the terms and -# conditions of the GPLv2 as it is applied to this software, see the -# FLOSS License Exception -# . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; version 2 of the License. -# -# This program 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 General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - .. uuid_doc documentation master file, created by sphinx-quickstart on Fri Feb 6 18:39:23 2015. You can adapt this file completely to your liking, but it should at least @@ -44,37 +22,36 @@ UUID has the following structure: .. uml:: - object TIME_LOW - object TIME_MID + object NODE + object CLOCK_SEQ object TIME_HI_VER - object PROCESS_ID - object HW_MAC_ADDR + object TIME_MID + object TIME_LOW - TIME_LOW : 32-bit - TIME_MID : 16-bit + NODE : 48-bit + CLOCK_SEQ : 16-bit TIME_HI_VER : 16-bit - PROCESS_ID : 16-bit - HW_MAC_ADDR : 48-bit + TIME_MID : 16-bit + TIME_LOW : 32-bit - TIME_LOW -down-> TIME_MID - TIME_MID -down-> TIME_HI_VER - TIME_HI_VER -down-> PROCESS_ID - PROCESS_ID -down-> HW_MAC_ADDR + NODE -down-> CLOCK_SEQ + CLOCK_SEQ -down-> TIME_HI_VER + TIME_HI_VER -down-> TIME_MID + TIME_MID -down-> TIME_LOW - note right of TIME_LOW - represents the lower 32 bits of system timestamp - in order not to generate the same value the lower bits - can be "borrowed" from the future when two UUIDs generate - within the clock granularity - - this protects against generating similar values within - the same process + note right of NODE + 6 bytes randomly generated using a user-provided seed. + The same node values are used within a process. + Changing the random generator seed causes generating of + new node. end note - note right of TIME_MID - represents the medium 16 bits of system timestamp - this component changes when TIME_LOW reaches its maximum + note right of CLOCK_SEQ + randomly generated 16-bit value also containing the + UUID variant. This value changes on setting a new seed + for the generator or if two time values within the same + process have same time values. end note note right of TIME_HI_VER @@ -85,23 +62,19 @@ UUID has the following structure: timestamp >> 48 | UUID_VERSION end note - note right of PROCESS_ID - represents the lower 16 bits of the current Process ID - to make sure the duplicate values would not be generated if - two independent processes running on the same host - getting UUID at the same time + note right of TIME_MID + represents the medium 16 bits of system timestamp + this component changes when TIME_LOW reaches its maximum end note - note right of HW_MAC_ADDR - 6 bytes from Hardware MAC address of the network adapter - this component eliminates the possibility of duplication on - two or more UUIDs generated on separate hosts at the same - moment of time + note right of TIME_LOW + represents the lower 32 bits of system timestamp + in order not to generate the same value the lower bits + can be "borrowed" from the future when two UUIDs generate + within the clock granularity - If MAC address could not be obtained this value is generated - randomly depending on time, the number of bytes sent, - Query ID (number), query performance frequency and - query performance offset + this protects against generating similar values within + the same process end note How to use UUID generator @@ -114,6 +87,8 @@ To start using the ``UUID`` generator the client code has to use the header: #include +The classes and declarations for the ``UUID`` generator are inside ``uuid`` name space. + The header file contains the definitions for ``uuid_type`` as: .. code-block:: c @@ -122,47 +97,45 @@ The header file contains the definitions for ``uuid_type`` as: typedef unsigned char uuid_type[UUID_LENGTH_BIN]; -UUID functions --------------- +UUID structures +--------------- .. |vspace| raw:: latex \vspace{5mm} -* ``init_uuid(unsigned long seed)`` - initialization function, which should - be called only once before using the generator. The parameter `unsigned long seed` is - used to generate the 6-byte `Hardware MAC address` if it could not be obtained. - The seed can be a random value, system time, the query number, number of sent bytes, etc. +* ``Uuid`` - a static structure with automatically called constructor and destructor + initializing/freeing mutexes etc. The user code is not supposed to create instances of + this structure. |vspace| + +* ``Uuid::set_seed(uint16_t seed)`` - Setting the seed for the UUID generator. + The seed has to be set before generator can be used. Otherwise it throws + an exception. -* ``generate_uuid(uuid_type& uuid)`` - generator returning the result into `uuid` parameter. +* ``Uuid::set_seed_from_time_pid()`` - Converience function for setting the seed + for the UUID generator using the current machine time and the process id. + +* ``Uuid::generate_uuid(uuid_type& uuid)`` - generator returning the result into `uuid` parameter. Could be called many times, sequentially or concurrently from different threads. - Requires `init_uuid()` function to be called before the first use of `generate_uuid`. -|vspace| - -* ``end_uuid()`` - should be called when the application exists or when UUID generator is - not needed. Destroys the mutexes used for synchronizing in concurrent threads. Usage example ------------- .. code-block:: c - /* Initialize the UUID generator and create mutexes */ - unsigned long seed = ; - init_uuid(seed); +#include "uuid_gen.h" ... + uuid::uuid_type uuid; /* Use the generator. The result formatted and converted to text could look as: - bf17975b-4e44-d011-4c6b00268312fb20 + 4c6b00268312fb20-4e44-d011-bf17975b */ - generate_uuid(uuid); - ... - /* Destroy mutexes */ - end_uuid(); + uuid::set_seed(set_seed((uint16_t)(time(0) ^ process_id)); + uuid::generate_uuid(uuid); Contents: diff --git a/cdk/extra/uuid/include/uuid_gen.h b/cdk/extra/uuid/include/uuid_gen.h index 96a585db4..b67db67b6 100644 --- a/cdk/extra/uuid/include/uuid_gen.h +++ b/cdk/extra/uuid/include/uuid_gen.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,14 +15,27 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef UUID_GEN_INCLUDED -#define UUID_GEN_INCLUDED +#ifndef _UUID_GEN_H_ +#define _UUID_GEN_H_ + +#include #define UUID_LENGTH_BIN 16 + +namespace uuid { + typedef unsigned char uuid_type[UUID_LENGTH_BIN]; -void init_uuid(unsigned long); -void end_uuid(); +/* The seed must be set before using the generator. */ +void set_seed(uint16_t seed); + +/* Convenience function, which sets the seed using the time and + process id */ +void set_seed_from_time_pid(); + +/* UUID generator */ void generate_uuid(uuid_type &uuid); +} // namespace uuid + #endif \ No newline at end of file diff --git a/cdk/extra/uuid/src/uuid_gen.cc b/cdk/extra/uuid/src/uuid_gen.cc index ec336529f..0f03c5db8 100644 --- a/cdk/extra/uuid/src/uuid_gen.cc +++ b/cdk/extra/uuid/src/uuid_gen.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,31 +15,25 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "uuid_gen.h" #ifdef _WIN32 -#include -#include #include -#include -#endif - -#include -#include +#include +#else #include -#include +#endif +#include +#include -/* -Begin of MySQL defs and structs -*/ #ifdef _WIN32 typedef CRITICAL_SECTION pthread_mutex_t; typedef DWORD pthread_t; typedef struct thread_attr { - DWORD dwStackSize ; - DWORD dwCreatingFlag ; -} pthread_attr_t ; + DWORD dwStackSize; + DWORD dwCreatingFlag; +} pthread_attr_t; #define pthread_getspecific(A) (TlsGetValue(A)) #define pthread_self() (GetCurrentThreadId()) @@ -52,7 +46,6 @@ typedef struct thread_attr { #else #include -#include #include #include @@ -76,288 +69,50 @@ typedef struct thread_attr { #define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) -typedef unsigned int uint32; -typedef unsigned short uint16; -typedef char my_bool; /* Small bool */ +static pthread_mutex_t LOCK_uuid_generator; -#define UUID_LENGTH_TEXT (8+1+4+1+4+1+4+1+12) - -struct rand_struct { - unsigned long seed1,seed2,max_value; - double max_value_dbl; -}; +/* The seed and the random value are stored in uuid_seed */ +static uint16_t uuid_seed = 0; -static pthread_mutex_t LOCK_uuid_generator, LOCK_sql_rand; +/* Needed for the time counting */ +static unsigned int nanoseq = 0; - -/* -End MySQL defs and structs -*/ - -/* - These values are obtained during the live session, but - here we set them just to non-zero -*/ -static unsigned long uuid_seed= 0; +/* The last used time value is stored here */ +static unsigned long long uuid_time2 = 0; #if defined(_WIN32) -static unsigned long long query_performance_frequency= 0; -static unsigned long long query_performance_offset= 0; +static unsigned long long query_performance_frequency = 0; +static unsigned long long query_performance_offset = 0; #endif +static uint16_t time_seq_global = 0; -static unsigned int nanoseq= 0; -static unsigned long long uuid_time2=0; +/* + The randomly generated node part is stored here. + It is generated only when the seed is changed. + All other times it is just re-used. +*/ +unsigned char node_global[6]; /** number of 100-nanosecond intervals between 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00. */ #define UUID_TIME_OFFSET ((unsigned long long) 141427 * 24 * 60 * 60 * \ - 1000 * 1000 * 10) + 1000 * 1000 * 10) #define UUID_MS 10000000 #define UUID_VERSION 0x1000 #define UUID_VARIANT 0x8000 -struct rand_struct sql_rand; -struct rand_struct uuid_rand; - -/** - Getting MAC address -*/ - -#ifdef __FreeBSD__ - -#include -#include -#include // for struct sockaddr -#include -#include -#include - -/* - my_gethwaddr - FreeBSD version - - @brief Retrieve MAC address from network hardware - - @param[out] to MAC address exactly six bytes - - @return Operation status - @retval 0 OK - @retval <>0 FAILED -*/ -my_bool my_gethwaddr(unsigned char *to) -{ - size_t len; - char *buf, *next, *end; - struct if_msghdr *ifm; - struct sockaddr_dl *sdl; - int res=1, mib[6]={CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0}; - char zero_array[ETHER_ADDR_LEN] = {0}; - - if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) - goto err; - if (!(buf = (char*)alloca(len))) - goto err; - if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) - goto err; - - end = buf + len; - - for (next = buf ; res && next < end ; next += ifm->ifm_msglen) - { - ifm = (struct if_msghdr *)next; - if (ifm->ifm_type == RTM_IFINFO) - { - sdl= (struct sockaddr_dl *)(ifm + 1); - std::memcpy(to, LLADDR(sdl), ETHER_ADDR_LEN); - res= std::memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1; - } - } - -err: - return res; -} - -#elif __linux__ - -#include -#include -#include - -#define MAX_IFS 64 -/* - my_gethwaddr - Linux version - - @brief Retrieve MAC address from network hardware - - @param[out] to MAC address exactly six bytes - - @return Operation status - @retval 0 OK - @retval <>0 FAILED -*/ -my_bool my_gethwaddr(unsigned char *to) +/* Generate pseudo-random values using Fibonaccy sequence */ +uint16_t rand_fibonacci() { - int fd= -1; - int res= 1; - struct ifreq ifr; - struct ifreq ifs[MAX_IFS]; - struct ifreq *ifri= NULL; - struct ifreq *ifend= NULL; - - char zero_array[ETHER_ADDR_LEN] = {0}; - struct ifconf ifc; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) - return 1; - - /* Retrieve interfaces */ - ifc.ifc_len= sizeof(ifs); - ifc.ifc_req= ifs; - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) - { - close(fd); - return 1; - } - - /* Initialize out parameter */ - std::memcpy(to, zero_array, ETHER_ADDR_LEN); - - /* Calculate first address after array */ - ifend= ifs + (ifc.ifc_len / sizeof(struct ifreq)); - - /* Loop over all interfaces */ - for (ifri= ifc.ifc_req; ifri < ifend; ifri++) - { - if (ifri->ifr_addr.sa_family == AF_INET) - { - /* Reset struct, copy interface name */ - std::memset(&ifr, 0, sizeof(ifr)); - std::strncpy(ifr.ifr_name, ifri->ifr_name, sizeof(ifr.ifr_name)); - - /* Get HW address, break if not 0 */ - if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) - { - std::memcpy(to, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); - if (std::memcmp(to, zero_array, ETHER_ADDR_LEN)) - { - res= 0; - break; - } - } - } - } - close(fd); - return res; -} - -#elif defined(_WIN32) - -/* - The following typedef is for dynamically loading iphlpapi.dll / - GetAdaptersAddresses. Dynamic loading is used because - GetAdaptersAddresses is not available on Windows 2000 which MySQL - still supports. Static linking would cause an unresolved export. -*/ -typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family, - IN DWORD Flags,IN PVOID Reserved, - OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses, - IN OUT PULONG pOutBufLen); - -/* - my_gethwaddr - Windows version - - @brief Retrieve MAC address from network hardware - - @param[out] to MAC address exactly six bytes - - @return Operation status - @retval 0 OK - @retval <>0 FAILED -*/ -my_bool my_gethwaddr(unsigned char *to) -{ - PIP_ADAPTER_ADDRESSES pAdapterAddresses; - PIP_ADAPTER_ADDRESSES pCurrAddresses; - IP_ADAPTER_ADDRESSES adapterAddresses; - ULONG address_len; - my_bool return_val= 1; - pfnGetAdaptersAddresses fnGetAdaptersAddresses= - (pfnGetAdaptersAddresses)-1; - - if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1) - { - /* Get the function from the DLL */ - fnGetAdaptersAddresses= (pfnGetAdaptersAddresses) - GetProcAddress(LoadLibrary("iphlpapi.dll"), - "GetAdaptersAddresses"); - } - if (!fnGetAdaptersAddresses) - return 1; /* failed to get function */ - address_len= sizeof (IP_ADAPTER_ADDRESSES); - - /* Get the required size for the address data. */ - if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len) - == ERROR_BUFFER_OVERFLOW) - { - pAdapterAddresses= (PIP_ADAPTER_ADDRESSES)malloc(address_len); - if (!pAdapterAddresses) - return 1; /* error, alloc failed */ - } - else - pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */ - - /* Get the hardware info. */ - if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len) - == NO_ERROR) - { - pCurrAddresses= pAdapterAddresses; - - while (pCurrAddresses) - { - /* Look for ethernet cards. */ - if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD) - { - /* check for a good address */ - if (pCurrAddresses->PhysicalAddressLength < 6) - continue; /* bad address */ - - /* save 6 bytes of the address in the 'to' parameter */ - memcpy(to, pCurrAddresses->PhysicalAddress, 6); - - /* Network card found, we're done. */ - return_val= 0; - break; - } - pCurrAddresses= pCurrAddresses->Next; - } - } - - /* Clean up memory allocation. */ - if (pAdapterAddresses != &adapterAddresses) - free(pAdapterAddresses); - - return return_val; -} - -#else /* __FreeBSD__ || __linux__ || _WIN32 */ -/* just fail */ -my_bool my_gethwaddr(unsigned char *to __attribute__((unused))) -{ - return 1; -} -#endif - - -double my_rnd(rand_struct *rand_st) -{ - rand_st->seed1= (rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; - rand_st->seed2= (rand_st->seed1+rand_st->seed2+33) % rand_st->max_value; - return (((double) rand_st->seed1) / rand_st->max_value_dbl); + uint16_t bit = ((uuid_seed >> 0) ^ (uuid_seed >> 2) ^ + (uuid_seed >> 3) ^ (uuid_seed >> 5)) & 1; + uuid_seed = (uuid_seed >> 1) | (bit << 15); + return uuid_seed; } @@ -366,7 +121,7 @@ unsigned long long my_getsystime() #ifdef HAVE_CLOCK_GETTIME struct timespec tp; clock_gettime(CLOCK_REALTIME, &tp); - return (unsigned long long)tp.tv_sec*10000000+(unsigned long long)tp.tv_nsec/100; + return (unsigned long long)tp.tv_sec * 10000000 + (unsigned long long)tp.tv_nsec / 100; #elif defined(_WIN32) LARGE_INTEGER t_cnt; if (query_performance_frequency) @@ -374,138 +129,102 @@ unsigned long long my_getsystime() QueryPerformanceCounter(&t_cnt); return ((t_cnt.QuadPart / query_performance_frequency * 10000000) + ((t_cnt.QuadPart % query_performance_frequency) * 10000000 / - query_performance_frequency) + query_performance_offset); + query_performance_frequency) + query_performance_offset); } return 0; #else /* TODO: check for other possibilities for hi-res timestamping */ struct timeval tv; - gettimeofday(&tv,NULL); - return (unsigned long long)tv.tv_sec*10000000+(unsigned long long)tv.tv_usec*10; + gettimeofday(&tv, NULL); + return (unsigned long long)tv.tv_sec * 10000000 + (unsigned long long)tv.tv_usec * 10; #endif } - -unsigned long sql_rnd_with_mutex() +/* Get process id */ +static uint32_t get_proc_id() { - pthread_mutex_lock(&LOCK_sql_rand); - unsigned long tmp=(unsigned long) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */ - pthread_mutex_unlock(&LOCK_sql_rand); - return tmp; -} - - -void randominit(struct rand_struct *rand_st, unsigned long seed1, unsigned long seed2) -{ /* For mysql 3.21.# */ -#ifdef HAVE_purify - memset(rand_st, 0, sizeof(*rand_st)); /* Avoid UMC varnings */ -#endif - rand_st->max_value= 0x3FFFFFFFL; - rand_st->max_value_dbl=(double) rand_st->max_value; - rand_st->seed1=seed1%rand_st->max_value ; - rand_st->seed2=seed2%rand_st->max_value; -} - - -static uint16 get_proc_id() -{ - uint16 proc_id= 0; #ifdef _WIN32 - proc_id= (uint16)(GetCurrentProcessId() & 0x0000FFFF); + return (uint32_t)GetCurrentProcessId(); #else - proc_id= (uint16)(getpid() & 0x0000FFFF); + return (uint32_t)getpid(); #endif - return proc_id; } - -void init_uuid(unsigned long seed) +/* Do initialization for UUID generator */ +void init_uuid() { pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&LOCK_sql_rand, MY_MUTEX_INIT_FAST); - uuid_seed= seed; + uuid_seed = 0; #if defined(_WIN32) FILETIME ft; LARGE_INTEGER li, t_cnt; if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0) - query_performance_frequency= 0; + query_performance_frequency = 0; else { GetSystemTimeAsFileTime(&ft); - li.LowPart= ft.dwLowDateTime; - li.HighPart= ft.dwHighDateTime; - query_performance_offset= li.QuadPart-UUID_TIME_OFFSET; + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + query_performance_offset = li.QuadPart - UUID_TIME_OFFSET; QueryPerformanceCounter(&t_cnt); - query_performance_offset-= (t_cnt.QuadPart / - query_performance_frequency * UUID_MS + - t_cnt.QuadPart % - query_performance_frequency * UUID_MS / - query_performance_frequency); + query_performance_offset -= (t_cnt.QuadPart / + query_performance_frequency * UUID_MS + + t_cnt.QuadPart % + query_performance_frequency * UUID_MS / + query_performance_frequency); } #endif -} - -void end_uuid() -{ - pthread_mutex_destroy(&LOCK_uuid_generator); - pthread_mutex_destroy(&LOCK_sql_rand); } -void generate_uuid(uuid_type &uuid) +/* + Structure of UUID produced by the generator. + It already has its components reversed, but we will + consider the order of components as direct. +*/ +struct uuid_internal_st { + unsigned char node[6]; + uint16_t clock_seq; + uint16_t time_hi_and_version; + uint16_t time_mid; + uint32_t time_low; +}; - struct uuid_internal_st - { - uint32 time_low; - uint16 time_mid; - uint16 time_hi_and_version; - uint16 process_id; - unsigned char hw_mac[6]; - }; - - static uuid_internal_st uuid_internal; +/* Random generation of the node part in UUID */ +void generate_node() +{ + uint16_t i = 0; + uint16_t rand_buf[3]; - pthread_mutex_lock(&LOCK_uuid_generator); + /* Run a few steps through the sequence */ + i = rand_fibonacci() & 7; + while (i && rand_fibonacci()) --i; - /* The thread key address will be used for random number generation */ -#ifdef _WIN32 - static DWORD key; -#else - static pthread_t key; -#endif + for (i = 0; i < 3; i++) + { + rand_buf[i] = rand_fibonacci(); + } - key= pthread_self(); + memcpy(node_global, rand_buf, sizeof(node_global)); + time_seq_global = rand_fibonacci(); +} - size_t i; +namespace uuid +{ - if (!uuid_time2) /* first UUID() call. initializing data */ - { - unsigned long client_start_time= time(0); - randominit(&sql_rand,(unsigned long) client_start_time,(unsigned long) client_start_time/2); - unsigned long tmp=sql_rnd_with_mutex(); - if (my_gethwaddr(uuid_internal.hw_mac)) - { +void generate_uuid(uuid_type &uuid) +{ + if (!uuid_seed) + throw std::logic_error("The seed must be set for random numbers generator"); - /* purecov: begin inspected */ - /* - generating random "hardware addr" - and because specs explicitly specify that it should NOT correlate - with a clock_seq value (initialized random below), we use a separate - randominit() here - */ - randominit(&uuid_rand, tmp + (unsigned long) key, tmp + (unsigned long)uuid_seed); - for (i=0; i < (int)sizeof(uuid_internal.hw_mac); i++) - uuid_internal.hw_mac[i]=(unsigned char)(my_rnd(&uuid_rand)*255); - /* purecov: end */ - } + uuid_internal_st uuid_internal; - uuid_internal.process_id= get_proc_id(); - } + pthread_mutex_lock(&LOCK_uuid_generator); - unsigned long long tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq; + unsigned long long tv = my_getsystime() + UUID_TIME_OFFSET + nanoseq; if (likely(tv > uuid_time2)) { @@ -519,9 +238,9 @@ void generate_uuid(uuid_type &uuid) /* -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time) */ - unsigned long delta= std::min(nanoseq, (unsigned long) (tv - uuid_time2 -1)); - tv-= delta; - nanoseq-= delta; + unsigned long delta = std::min(nanoseq, (unsigned long)(tv - uuid_time2 - 1)); + tv -= delta; + nanoseq -= delta; } } else @@ -555,28 +274,55 @@ void generate_uuid(uuid_type &uuid) In either case, we throw away any nanoseq borrowing since it's irrelevant in the new numberspace. */ - uuid_internal.process_id= get_proc_id(); - tv= my_getsystime() + UUID_TIME_OFFSET; - nanoseq= 0; + tv = my_getsystime() + UUID_TIME_OFFSET; + time_seq_global = rand_fibonacci() | UUID_VARIANT; + + nanoseq = 0; } } - uuid_time2=tv; - pthread_mutex_unlock(&LOCK_uuid_generator); + uuid_time2 = tv; - uuid_internal.time_low= (uint32) (tv & 0xFFFFFFFF); - uuid_internal.time_mid= (uint16) ((tv >> 32) & 0xFFFF); - uuid_internal.time_hi_and_version= (uint16) ((tv >> 48) | UUID_VERSION); + uuid_internal.time_low = (uint32_t)(tv & 0xFFFFFFFF); + uuid_internal.time_mid = (uint16_t)((tv >> 32) & 0xFFFF); + uuid_internal.time_hi_and_version = (uint16_t)((tv >> 48) | UUID_VERSION); + uuid_internal.clock_seq = time_seq_global; + memcpy(uuid_internal.node, node_global, sizeof(node_global)); memcpy(uuid, &uuid_internal, sizeof(uuid_internal)); + pthread_mutex_unlock(&LOCK_uuid_generator); +} - union thread_to_char - { - pthread_t thr; - unsigned char c[sizeof(pthread_t)]; - }t_val; +void set_seed(uint16_t seed) +{ + pthread_mutex_lock(&LOCK_uuid_generator); + uuid_seed ^= seed; + generate_node(); + pthread_mutex_unlock(&LOCK_uuid_generator); +} - t_val.thr = key; - for (i = 0; i < sizeof(key); ++i) - uuid[sizeof(uuid) - i - 1] ^= t_val.c[i]; +void set_seed_from_time_pid() +{ + if (!uuid_seed) + set_seed((uint16_t)(time(0) ^ get_proc_id())); } + +/* + The struct automaticaly initializes and disposes of mutexes etc. +*/ +static struct Uuid_initializer +{ + Uuid_initializer() + { + init_uuid(); + } + + ~Uuid_initializer() + { + pthread_mutex_destroy(&LOCK_uuid_generator); + } + +}Uuid_initializer_inst; + + +} \ No newline at end of file diff --git a/cdk/extra/uuid/testing/tests_uuid.cc b/cdk/extra/uuid/testing/tests_uuid.cc index 571c48bab..fe9232445 100644 --- a/cdk/extra/uuid/testing/tests_uuid.cc +++ b/cdk/extra/uuid/testing/tests_uuid.cc @@ -32,6 +32,7 @@ */ using namespace std; +using namespace uuid; std::ostream& operator<<(std::ostream &out, unsigned char u) { @@ -44,11 +45,11 @@ std::ostream& operator<<(std::ostream &out, unsigned char u) std::ostream& operator<<(std::ostream &out, const unsigned char id[16]) { - out << id[0] << id[1] << id[2] << id[3]; - out <<"-" << id[4] << id[5]; + out << id[0] << id[1] << id[2] << id[3] << id[4] << id[5]; out <<"-" << id[6] << id[7]; out <<"-" << id[8] << id[9]; - out << id[10] << id[11] << id[12] << id[13] << id[14] << id[15]; + out <<"-" << id[10] << id[11]; + out << id[12] << id[13] << id[14] << id[15]; return out; } @@ -56,24 +57,16 @@ std::ostream& operator<<(std::ostream &out, const unsigned char id[16]) int main(int argc, char **argv) { - init_uuid(365873); + std::cout << "UUID Generator:" << std::endl; - std::cout << "UUID Generator:" << std::endl << "----------------------" << std::endl; - - int iter_number= 100; - - if (argc > 1) - iter_number = std::atoi(argv[1]); - else - std::cout << "Optional number of iterations can be specified in the command line" << std::endl; - - std::cout << "Number of iterations: " << iter_number << std::endl << std::endl; + int iter_number= 20; int i = 0; uuid_type uuid; while(i < iter_number) { + set_seed_from_time_pid(); generate_uuid(uuid); std::cout << "UUID_" << std::setw(4) << std::setfill('0') << ++i << " " << uuid << std::endl; #ifdef _WIN32 @@ -83,7 +76,4 @@ int main(int argc, char **argv) #endif } std::cout << "DONE!" << std::endl; - - end_uuid(); - return 0; } diff --git a/devapi/collection_crud.cc b/devapi/collection_crud.cc index 16a451976..ba978b713 100644 --- a/devapi/collection_crud.cc +++ b/devapi/collection_crud.cc @@ -34,33 +34,25 @@ #include "impl.h" using namespace mysqlx; - +using namespace uuid; // -------------------------------------------------------------------- - -static struct UUID_initializer { - - UUID_initializer() - { - init_uuid((unsigned long)time(NULL)); - } - - ~UUID_initializer() +static struct Uuid_seed_initializer +{ + Uuid_seed_initializer() { - end_uuid(); + uuid::set_seed_from_time_pid(); } - -} uuid_initializer; - +} uuid_seed_initializer; void mysqlx::GUID::generate() { - uuid_type uuid; - generate_uuid(uuid); + uuid::uuid_type uuid; + uuid::generate_uuid(uuid); boost::format fmt("%02X"); - for (unsigned i = 0; i < sizeof(uuid) && 2*i < sizeof(m_data); ++i) + for (unsigned i = 0; i < sizeof(uuid) && 2 * i < sizeof(m_data); ++i) { memcpy(m_data + 2 * i, (fmt % (unsigned)uuid[i]).str().data(), 2); } diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 36d652597..94f94bf09 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -85,7 +85,7 @@ extern "C" { #ifdef _WIN32 #pragma comment(lib, "ws2_32") - #endif +#endif // FIXME #define STDCALL @@ -2762,7 +2762,6 @@ PUBLIC_API unsigned int mysqlx_result_warning_count(mysqlx_result_t *res); PUBLIC_API mysqlx_error_t * mysqlx_result_next_warning(mysqlx_result_t *res); - #ifdef __cplusplus } #endif diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index 329f12b32..57c162166 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -27,6 +27,7 @@ #include #include #include +#include #define SAFE_EXCEPTION_BEGIN(HANDLE, ERR) try { \ if (HANDLE == NULL) return ERR; @@ -42,6 +43,11 @@ HANDLE->set_diagnostic(mysqlx_ex); \ return ERR; \ } \ + catch (const std::logic_error &logicerr) \ + { \ + HANDLE->set_diagnostic(logicerr.what(), 0); \ + return ERR; \ + } \ catch(...) \ { \ HANDLE->set_diagnostic("Unknown error!", MYSQLX_ERR_UNKNOWN); \ diff --git a/xapi/row.cc b/xapi/row.cc index 95d4f7fdf..ead38ad18 100644 --- a/xapi/row.cc +++ b/xapi/row.cc @@ -28,19 +28,14 @@ #include "../cdk/extra/uuid/include/uuid_gen.h" #include "mysqlx_cc_internal.h" -static struct UUID_initializer { - - UUID_initializer() - { - init_uuid((unsigned long)time(NULL)); - } - - ~UUID_initializer() +/* This is done only once per library */ +static struct Uuid_seed_initializer +{ + Uuid_seed_initializer() { - end_uuid(); + uuid::set_seed_from_time_pid(); } - -} uuid_initializer; +} uuid_seed_initializer; /* @@ -186,7 +181,7 @@ void Row_item::process(cdk::Value_processor &prc) const void Row_item::generate_uuid() { - uuid_type uuid; + uuid::uuid_type uuid; /* Create a local copy of a document structure just to get _id @@ -200,7 +195,7 @@ void Row_item::generate_uuid() throw Mysqlx_exception("Document id must be a string"); std::string str_id = doc.get_string("_id"); - if (str_id.length() > sizeof(uuid_type)* 2) + if (str_id.length() > sizeof(uuid::uuid_type)* 2) throw Mysqlx_exception("Specified UUID is too long"); m_uuid = str_id; } @@ -209,8 +204,8 @@ void Row_item::generate_uuid() if (!doc.count()) m_empty_doc = true; // do not add "," before _id - ::generate_uuid(uuid); - char buf[sizeof(uuid_type)* 2 + 1]; + uuid::generate_uuid(uuid); + char buf[sizeof(uuid::uuid_type)* 2 + 1]; const char digits[17] = { "0123456789ABCDEF" }; for (size_t i = 0; i < sizeof(uuid); ++i) @@ -218,7 +213,7 @@ void Row_item::generate_uuid() buf[i * 2] = digits[((unsigned char)uuid[i]) & 0x0F]; buf[i * 2 + 1] = digits[((unsigned char)uuid[i] >> 4)]; } - buf[sizeof(uuid_type)* 2] = 0; // put a string termination + buf[sizeof(uuid::uuid_type)* 2] = 0; // put a string termination m_uuid = buf; } } @@ -435,4 +430,4 @@ void Modify_spec::process(Processor &prc) const prc.remove(&field); break; } -} \ No newline at end of file +} From ca20717d1877c3cf9f33110ea52e88778e4945e7 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 3 Jan 2017 18:16:52 +0100 Subject: [PATCH 37/79] Different way of initializing the UUID generator. --- cdk/extra/uuid/src/uuid_gen.cc | 73 +++++++++++++++++++++++----------- devapi/collection_crud.cc | 10 +---- devapi/impl.h | 2 + global.h | 60 ++++++++++++++++++++++++++++ xapi/mysqlx_cc_internal.h | 2 + xapi/row.cc | 12 +----- 6 files changed, 116 insertions(+), 43 deletions(-) create mode 100644 global.h diff --git a/cdk/extra/uuid/src/uuid_gen.cc b/cdk/extra/uuid/src/uuid_gen.cc index 0f03c5db8..beed28a9f 100644 --- a/cdk/extra/uuid/src/uuid_gen.cc +++ b/cdk/extra/uuid/src/uuid_gen.cc @@ -179,6 +179,50 @@ void init_uuid() } + +void deinit_uuid() +{ + pthread_mutex_destroy(&LOCK_uuid_generator); +} + + +/* + Instance of this class holds the global UUID generator mutex until + it gets destroyed. An exception-safe way of executing a block of code while + holding the mutex is like follows: + + { + Uuid_guard guard; + // code executed under the guard of the global mutex + } +*/ + +struct Uuid_guard +{ + struct Initializer + { + Initializer() { init_uuid(); } + ~Initializer() { deinit_uuid(); } + }; + + Uuid_guard() + { + /* + This static initializer instance gets constructed only once. + It ensures that uuid module is properly initialized before + using the mutex. + */ + static Initializer init; + pthread_mutex_lock(&LOCK_uuid_generator); + } + + ~Uuid_guard() + { + pthread_mutex_unlock(&LOCK_uuid_generator); + } +}; + + /* Structure of UUID produced by the generator. It already has its components reversed, but we will @@ -212,6 +256,7 @@ void generate_node() time_seq_global = rand_fibonacci(); } + namespace uuid { @@ -222,7 +267,7 @@ void generate_uuid(uuid_type &uuid) uuid_internal_st uuid_internal; - pthread_mutex_lock(&LOCK_uuid_generator); + Uuid_guard guard; unsigned long long tv = my_getsystime() + UUID_TIME_OFFSET + nanoseq; @@ -290,39 +335,21 @@ void generate_uuid(uuid_type &uuid) memcpy(uuid_internal.node, node_global, sizeof(node_global)); memcpy(uuid, &uuid_internal, sizeof(uuid_internal)); - pthread_mutex_unlock(&LOCK_uuid_generator); } + void set_seed(uint16_t seed) { - pthread_mutex_lock(&LOCK_uuid_generator); + Uuid_guard guard; uuid_seed ^= seed; generate_node(); - pthread_mutex_unlock(&LOCK_uuid_generator); } + void set_seed_from_time_pid() { - if (!uuid_seed) - set_seed((uint16_t)(time(0) ^ get_proc_id())); + set_seed((uint16_t)(time(0) ^ get_proc_id())); } -/* - The struct automaticaly initializes and disposes of mutexes etc. -*/ -static struct Uuid_initializer -{ - Uuid_initializer() - { - init_uuid(); - } - - ~Uuid_initializer() - { - pthread_mutex_destroy(&LOCK_uuid_generator); - } - -}Uuid_initializer_inst; - } \ No newline at end of file diff --git a/devapi/collection_crud.cc b/devapi/collection_crud.cc index ba978b713..9b5a3c903 100644 --- a/devapi/collection_crud.cc +++ b/devapi/collection_crud.cc @@ -38,18 +38,10 @@ using namespace uuid; // -------------------------------------------------------------------- -static struct Uuid_seed_initializer -{ - Uuid_seed_initializer() - { - uuid::set_seed_from_time_pid(); - } -} uuid_seed_initializer; - void mysqlx::GUID::generate() { uuid::uuid_type uuid; - uuid::generate_uuid(uuid); + mysqlx::generate_uuid(uuid); boost::format fmt("%02X"); for (unsigned i = 0; i < sizeof(uuid) && 2 * i < sizeof(m_data); ++i) diff --git a/devapi/impl.h b/devapi/impl.h index 56270993a..9fa084e81 100644 --- a/devapi/impl.h +++ b/devapi/impl.h @@ -38,6 +38,8 @@ #include #include +#include "../global.h" + namespace mysqlx { diff --git a/global.h b/global.h new file mode 100644 index 000000000..164e7a99e --- /dev/null +++ b/global.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * + * The MySQL Connector/C++ is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef MYSQLX_GLOBAL_H +#define MYSQLX_GLOBAL_H + +#include "cdk/extra/uuid/include/uuid_gen.h" + +namespace mysqlx { + +/* + Wrapper around uuid generator which ensures that it is properly + initialized using process id (so that concurrent processes use + different UUIDs). +*/ + +inline +void generate_uuid(uuid::uuid_type &buf) +{ + /* + Note: This static initializer instance will be constructed + only once. + */ + static struct Initializer + { + Initializer() + { + uuid::set_seed_from_time_pid(); + } + } + uuid_init; + + uuid::generate_uuid(buf); +} + +} + +#endif diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 19b194e56..3179ca42a 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -33,12 +33,14 @@ #include #include #include +#include "../global.h" #include "def_internal.h" #include "ref_internal.h" #include "error_internal.h" #include "row_internal.h" #include "crud_internal.h" + #define SKIP_ERROR_COLL_EXISTS 1051 #define FILTER_TABLE 1 diff --git a/xapi/row.cc b/xapi/row.cc index ead38ad18..74cc8299f 100644 --- a/xapi/row.cc +++ b/xapi/row.cc @@ -25,18 +25,8 @@ #include #include #include -#include "../cdk/extra/uuid/include/uuid_gen.h" #include "mysqlx_cc_internal.h" -/* This is done only once per library */ -static struct Uuid_seed_initializer -{ - Uuid_seed_initializer() - { - uuid::set_seed_from_time_pid(); - } -} uuid_seed_initializer; - /* Helper class for allocating the result buffer dynamically and keeping @@ -204,7 +194,7 @@ void Row_item::generate_uuid() if (!doc.count()) m_empty_doc = true; // do not add "," before _id - uuid::generate_uuid(uuid); + mysqlx::generate_uuid(uuid); char buf[sizeof(uuid::uuid_type)* 2 + 1]; const char digits[17] = { "0123456789ABCDEF" }; From 842db5359dfc2f26c95d1b271af529c42e76f5f7 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Mon, 9 Jan 2017 20:49:17 +0100 Subject: [PATCH 38/79] cmake: Add /bigobj compile flag on Win We hit the limits of win object files (probably due to heavy use of templates and inlines). --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69145605f..7725349f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,12 @@ if(WIN32 AND NOT UNREACHABLE_CODE_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4297") endif() + +if(WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif() + + # # Gcov support (Linux only) # From 5d9c1a2507dd974c7efa0adb4cc8dfffe59cca18 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 11 Jan 2017 12:29:59 +0100 Subject: [PATCH 39/79] Fixes for session shutdown logic: 1. Ignore errors that might be thrown during session shutdown. 2. Make sure that cdk::Session::close() also closes underlying connection. --- cdk/include/mysql/cdk/session.h | 3 ++- xapi/mysqlx.cc | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cdk/include/mysql/cdk/session.h b/cdk/include/mysql/cdk/session.h index aeea6726c..334b46be3 100644 --- a/cdk/include/mysql/cdk/session.h +++ b/cdk/include/mysql/cdk/session.h @@ -71,7 +71,8 @@ class Session void close() { if (m_trans) rollback(); - return m_session->close(); + m_session->close(); + m_connection->close(); } /* diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index 329f12b32..0ac7c4370 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -101,7 +101,7 @@ _get_session(const char *host, int port, const char *user, { std::string pwd(password ? password : ""); std::string db(database ? database : ""); - + // TODO: the default user has to be determined in a more flexible way sess = new mysqlx_session_t(host ? host : "localhost", port, user ? user : "root", password ? &pwd : NULL, @@ -413,7 +413,7 @@ int STDCALL mysqlx_set_group_by(mysqlx_stmt_t *stmt, ...) return res; SAFE_EXCEPTION_END(stmt, RESULT_ERROR) } - + int STDCALL mysqlx_set_limit_and_offset(mysqlx_stmt_t *stmt, uint64_t row_count, uint64_t offset) @@ -1146,7 +1146,16 @@ void STDCALL mysqlx_result_free(mysqlx_result_t *res) */ void STDCALL mysqlx_session_close(mysqlx_session_t *sess) { - if (sess) delete sess; + if (sess) + { + try { + delete sess; + } + catch (...) + { + // Ignore errors that might happen during session destruction. + } + } } int STDCALL @@ -1573,7 +1582,7 @@ mysqlx_get_schemas(mysqlx_session_t *sess, const char *schema_pattern) if ((stmt = sess->sql_query("SHOW SCHEMAS LIKE ?", MYSQLX_NULL_TERMINATED, true)) == NULL) return NULL; - + if (mysqlx_stmt_bind(stmt, PARAM_STRING(schema_pattern ? schema_pattern : "%"), PARAM_END) == RESULT_ERROR) SET_ERROR_FROM_STMT(sess, stmt, NULL); From 485019a17e6a56cd94c1091ebed2b1a2cef36e7f Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 20 Jan 2017 14:36:50 +0100 Subject: [PATCH 40/79] Fix xapi_test to use the same 'test' database as devapi_test. --- testapp/xapi_test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testapp/xapi_test.c b/testapp/xapi_test.c index aa1836d2c..9da4460de 100644 --- a/testapp/xapi_test.c +++ b/testapp/xapi_test.c @@ -91,14 +91,14 @@ int main(int argc, const char* argv[]) /* Drop test table if exists */ res = mysqlx_sql(sess, - "DROP TABLE IF EXISTS cc_crud_test.crud_placeholder_test", + "DROP TABLE IF EXISTS test.crud_placeholder_test", MYSQLX_NULL_TERMINATED); RESULT_CHECK(res, sess); /* Create a test table */ res = mysqlx_sql(sess, - "CREATE TABLE cc_crud_test.crud_placeholder_test " \ + "CREATE TABLE test.crud_placeholder_test " \ "(sint BIGINT, uint BIGINT UNSIGNED, flv FLOAT," \ "dbv DOUBLE, strv VARCHAR(255))", MYSQLX_NULL_TERMINATED); @@ -108,7 +108,7 @@ int main(int argc, const char* argv[]) /* Do insert as a plain SQL with parameters */ crud = mysqlx_sql_new(sess, - "INSERT INTO cc_crud_test.crud_placeholder_test " \ + "INSERT INTO test.crud_placeholder_test " \ "(sint, uint, flv, dbv, strv) VALUES (?,?,?,?,?)", MYSQLX_NULL_TERMINATED); CRUD_CHECK(crud, sess); @@ -132,7 +132,7 @@ int main(int argc, const char* argv[]) Query table using CRUD operations. */ - db = mysqlx_get_schema(sess, "cc_crud_test", 1); + db = mysqlx_get_schema(sess, "test", 1); RESULT_CHECK(db, sess); table = mysqlx_get_table(db, "crud_placeholder_test", 1); From 44607978cbbd0c34c2f6d78f21c8e6270eea44e7 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 25 Jan 2017 09:40:38 +0100 Subject: [PATCH 41/79] Merge from CDK: MYC-378: Add view definer option. --- cdk/include/mysql/cdk/api/query.h | 1 + cdk/protocol/mysqlx/crud.cc | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/cdk/include/mysql/cdk/api/query.h b/cdk/include/mysql/cdk/api/query.h index 375abf113..8cbc7b4df 100644 --- a/cdk/include/mysql/cdk/api/query.h +++ b/cdk/include/mysql/cdk/api/query.h @@ -201,6 +201,7 @@ class View_opt_prc typedef View_algorithm::value View_algorithm_t; typedef View_check::value View_check_t; + virtual void definer(const string&) = 0; virtual void security(View_security_t) = 0; virtual void algorithm(View_algorithm_t) = 0; virtual void check(View_check_t) = 0; diff --git a/cdk/protocol/mysqlx/crud.cc b/cdk/protocol/mysqlx/crud.cc index b639e1456..c67f85f7f 100644 --- a/cdk/protocol/mysqlx/crud.cc +++ b/cdk/protocol/mysqlx/crud.cc @@ -748,6 +748,11 @@ void set_view_options(MSG &msg, api::View_options &opts) { MSG *m_msg; + void definer(const string &user) + { + m_msg->set_definer(user); + } + void security(View_security_t security) { switch (security) From cc9715031bd8ff7fdbe808f82477da9e9760e178 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 27 Jan 2017 12:51:03 +0100 Subject: [PATCH 42/79] Merge from CDK: Add replace flavor to view DDL operations. --- cdk/core/tests/session_crud-t.cc | 2 +- cdk/include/mysql/cdk/api/document.h | 1 - cdk/include/mysql/cdk/api/expression.h | 1 + cdk/include/mysql/cdk/api/query.h | 4 +++- cdk/include/mysql/cdk/data_source.h | 4 ++++ cdk/include/mysql/cdk/protocol/mysqlx.h | 1 + cdk/mysqlx/delayed_op.h | 30 ++++++++++++++++--------- cdk/protocol/mysqlx/crud.cc | 2 ++ 8 files changed, 32 insertions(+), 13 deletions(-) diff --git a/cdk/core/tests/session_crud-t.cc b/cdk/core/tests/session_crud-t.cc index 1e71bca98..69f679ab1 100644 --- a/cdk/core/tests/session_crud-t.cc +++ b/cdk/core/tests/session_crud-t.cc @@ -1654,7 +1654,7 @@ CRUD_TEST_BEGIN(views) void process(Processor &prc) const { - prc.name(v, false); + prc.name(v); if (columns) columns->process_if(prc.columns()); if (opts) diff --git a/cdk/include/mysql/cdk/api/document.h b/cdk/include/mysql/cdk/api/document.h index cef3ed983..d6bf5ffbe 100644 --- a/cdk/include/mysql/cdk/api/document.h +++ b/cdk/include/mysql/cdk/api/document.h @@ -25,7 +25,6 @@ #ifndef CDK_API_DOCUMENT_H #define CDK_API_DOCUMENT_H -#include "../foundation.h" #include "expression.h" namespace cdk { diff --git a/cdk/include/mysql/cdk/api/expression.h b/cdk/include/mysql/cdk/api/expression.h index 3824c885d..258acbc16 100644 --- a/cdk/include/mysql/cdk/api/expression.h +++ b/cdk/include/mysql/cdk/api/expression.h @@ -25,6 +25,7 @@ #ifndef CDK_API_EXPRESSION_H #define CDK_API_EXPRESSION_H +#include "../foundation.h" #include // for NULL #include diff --git a/cdk/include/mysql/cdk/api/query.h b/cdk/include/mysql/cdk/api/query.h index 8cbc7b4df..438d259fa 100644 --- a/cdk/include/mysql/cdk/api/query.h +++ b/cdk/include/mysql/cdk/api/query.h @@ -146,8 +146,9 @@ class View_processor typedef OPTS Options; typedef String_list::Processor List_processor; + enum op_type { CREATE, UPDATE, REPLACE }; - virtual void name(const Table_ref&, bool update = false) = 0; + virtual void name(const Table_ref&, op_type type = CREATE) = 0; virtual typename Options::Processor* options() = 0; virtual List_processor* columns() { return NULL; } @@ -160,6 +161,7 @@ class View_spec : public Expr_base< View_processor > public: typedef OPTS Options; + typedef typename View_processor::op_type op_type; }; diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index b6d843d5a..5231b10cb 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -131,12 +131,16 @@ class TCPIP::Options : public ds::Options public: Options() +#ifdef WITH_SSL : m_tls_options(false) +#endif {} Options(const string &usr, const std::string *pwd =NULL) : ds::Options(usr, pwd) +#ifdef WITH_SSL , m_tls_options(false) +#endif {} #ifdef WITH_SSL diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index 03a36651d..9a78f6160 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -588,6 +588,7 @@ class Protocol Op& snd_CreateView(Data_model dm, const api::Db_obj &obj, const Find_spec &query, const api::Columns *columns, + bool replace = false, api::View_options* = NULL, const api::Args_map *args = NULL); Op& snd_ModifyView(Data_model dm, const api::Db_obj &obj, diff --git a/cdk/mysqlx/delayed_op.h b/cdk/mysqlx/delayed_op.h index 39b0be010..1cbe4f856 100644 --- a/cdk/mysqlx/delayed_op.h +++ b/cdk/mysqlx/delayed_op.h @@ -655,7 +655,7 @@ class SndViewCrud { const View_spec *m_view; SndFind *m_find; - bool m_update; + View_spec::op_type m_type; bool m_has_cols; bool m_has_opts; @@ -684,7 +684,7 @@ class SndViewCrud { String_list::Processor *m_prc; - void name(const Table_ref&, bool) {} + void name(const Table_ref&, op_type) {} Options::Processor* options() { @@ -724,7 +724,8 @@ class SndViewCrud { Options::Processor *m_prc; - void name(const Table_ref&, bool) {} + void name(const Table_ref&, op_type) + {} Options::Processor* options() { @@ -751,19 +752,28 @@ class SndViewCrud Proto_op* start() { - if (m_update) - return &m_protocol.snd_ModifyView(DM, *this, *m_find, - get_cols(), get_opts()); - else + switch (m_type) + { + case CREATE: + case REPLACE: return &m_protocol.snd_CreateView(DM, *this, *m_find, + get_cols(), REPLACE == m_type, + get_opts()); + + case UPDATE: + return &m_protocol.snd_ModifyView(DM, *this, *m_find, get_cols(), get_opts()); + default: + assert(false); + return NULL; // quiet compile warnings + } } public: SndViewCrud(const View_spec &view, SndFind *find = NULL) : Crud_op_base(find->m_protocol) - , m_view(&view), m_find(find), m_update(false) + , m_view(&view), m_find(find), m_type(CREATE) , m_has_cols(false), m_has_opts(false) { /* @@ -784,10 +794,10 @@ class SndViewCrud // View_spec::Processor - void name(const Table_ref &view, bool update = false) + void name(const Table_ref &view, View_spec::op_type type) { Crud_op_base::set(view); - m_update = update; + m_type = type; } List_processor* columns() diff --git a/cdk/protocol/mysqlx/crud.cc b/cdk/protocol/mysqlx/crud.cc index c67f85f7f..5d769dc79 100644 --- a/cdk/protocol/mysqlx/crud.cc +++ b/cdk/protocol/mysqlx/crud.cc @@ -806,6 +806,7 @@ Protocol::Op& Protocol::snd_CreateView( Data_model dm, const api::Db_obj &obj, const Find_spec &query, const api::Columns *cols, + bool replace, api::View_options *opts, const api::Args_map *args ) @@ -813,6 +814,7 @@ Protocol::snd_CreateView( Mysqlx::Crud::CreateView view; set_db_obj(obj, view); + view.set_replace_existing(replace); if (cols) set_view_columns(view, *cols); From 374a694a50bc3173cb396a0bc3f834163cad78fe Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Mon, 30 Jan 2017 21:50:10 +1100 Subject: [PATCH 43/79] Added ssl-enable, ssl-ca and ssl-ca-path options into XAPI --- include/mysql_xapi.h | 4 +- xapi/mysqlx.cc | 51 +++++++++++++++--- xapi/mysqlx_cc_internal.h | 83 ++++++++++++++++++++++++---- xapi/tests/xapi-t.cc | 110 ++++++++++++++++++++++++++++++++------ 4 files changed, 212 insertions(+), 36 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 36d652597..9747459af 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -334,7 +334,9 @@ typedef enum mysqlx_opt_type_enum MYSQLX_OPT_USER = 3, MYSQLX_OPT_PWD = 4, MYSQLX_OPT_DB = 5, - MYSQLX_OPT_SSL_ENABLE = 6 + MYSQLX_OPT_SSL_ENABLE = 6, + MYSQLX_OPT_SSL_CA = 7, + MYSQLX_OPT_SSL_CA_PATH = 8 } mysqlx_opt_type_t; diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index 329f12b32..d8ad3ff39 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -1707,17 +1707,29 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, char_data = ""; opt->set_database(char_data); break; - case MYSQLX_OPT_SSL_ENABLE: #ifdef WITH_SSL + case MYSQLX_OPT_SSL_ENABLE: uint_data = va_arg(args, unsigned int); opt->set_tls(uint_data > 0); + break; + case MYSQLX_OPT_SSL_CA: + char_data = va_arg(args, char*); + opt->set_ssl_ca(char_data); + break; + case MYSQLX_OPT_SSL_CA_PATH: + char_data = va_arg(args, char*); + opt->set_ssl_ca_path(char_data); + break; #else + case MYSQLX_OPT_SSL_ENABLE: + case MYSQLX_OPT_SSL_CA: + case MYSQLX_OPT_SSL_CA_PATH: opt->set_diagnostic( "Can not create TLS session - this connector is built" " without TLS support.", 0 ); + break; #endif - break; default: opt->set_diagnostic("Invalid option value", 0); rc = RESULT_ERROR; @@ -1728,7 +1740,7 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, SAFE_EXCEPTION_END(opt, RESULT_ERROR) } -#define CHAR_OUTPUT_BUF(V) V = va_arg(args, char*); \ +#define CHECK_OUTPUT_BUF(V, T) V = va_arg(args, T); \ if (V == NULL) \ { \ opt->set_diagnostic(MYSQLX_ERROR_OUTPUT_BUFFER_NULL, 0); \ @@ -1750,25 +1762,48 @@ mysqlx_session_option_get(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, switch(type) { case MYSQLX_OPT_HOST: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_host().data()); break; case MYSQLX_OPT_PORT: - uint_data = va_arg(args, unsigned int*); + CHECK_OUTPUT_BUF(uint_data, unsigned int*) *uint_data = opt->get_port(); break; case MYSQLX_OPT_USER: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_user().data()); break; case MYSQLX_OPT_PWD: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_password().data()); break; case MYSQLX_OPT_DB: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_db().data()); break; +#ifdef WITH_SSL + case MYSQLX_OPT_SSL_ENABLE: + CHECK_OUTPUT_BUF(uint_data, unsigned int*) + *uint_data = opt->get_tls().use_tls() ? 1 : 0; + break; + case MYSQLX_OPT_SSL_CA: + CHECK_OUTPUT_BUF(char_data, char*) + strcpy(char_data, opt->get_tls().get_ca().data()); + break; + case MYSQLX_OPT_SSL_CA_PATH: + CHECK_OUTPUT_BUF(char_data, char*) + strcpy(char_data, opt->get_tls().get_ca_path().data()); + break; +#else + case MYSQLX_OPT_SSL_ENABLE: + case MYSQLX_OPT_SSL_CA: + case MYSQLX_OPT_SSL_CA_PATH: + opt->set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); + break; +#endif default: opt->set_diagnostic("Invalid option value", 0); rc = RESULT_ERROR; diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 19b194e56..12c1741b4 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -366,6 +366,7 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, /* The pointer is used because TCPIP options can only be set in the constructor */ cdk::ds::TCPIP *m_tcp; + cdk::connection::TLS::Options m_tls_options; public: mysqlx_session_options_struct() : m_tcp(NULL) @@ -388,9 +389,10 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, if (db) set_database(*db); -#ifdef WITH_SSL + // This call must be made at all times because SSL is enabled by default set_tls(ssl_enable); -#else + +#ifndef WITH_SSL if (ssl_enable) set_diagnostic( "Can not create TLS session - this connector is built" @@ -401,6 +403,7 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, mysqlx_session_options_struct(const std::string &conn_str) : m_tcp(NULL) { + set_tls(false); parser::parse_conn_str(conn_str, *this); } @@ -434,30 +437,88 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, m_port = port; } + std::string get_host() { return m_host; } + unsigned int get_port() { return m_port; } + std::string get_user() { return m_usr; } + std::string get_password() { return m_pwd; } + std::string get_db() { return m_db; } + + void set_use_tls(bool tls) + { + if (tls) + set_tls(m_tls_options); + else + set_tls(false); + } + + void set_ssl_ca(const string &ca) + { + m_tls_options.set_ca(ca); + set_tls(m_tls_options); + } + + void set_ssl_ca_path(const string &ca_path) + { + m_tls_options.set_ca_path(ca_path); + set_tls(m_tls_options); + } + + void set_ssl_key(const string &key) + { + m_tls_options.set_key(key); + set_tls(m_tls_options); + } + // Implementing URI_Processor interface void path(const std::string &path) - { set_database(path); } + { + set_database(path); + } void key_val(const std::string& key) { - if (key.compare("ssl-enable") == 0) + if (key.find("ssl-", 0) == 0) { #ifdef WITH_SSL - set_tls(true); + if (key.compare("ssl-enable") == 0) + { + set_tls(true); + } #else set_diagnostic( "Can not create TLS session - this connector is built" " without TLS support.", 0 - ); + ); #endif } } - std::string get_host() { return m_host; } - unsigned int get_port() { return m_port; } - std::string get_user() { return m_usr; } - std::string get_password() { return m_pwd; } - std::string get_db() { return m_db; } + void key_val(const std::string& key, const std::string& val) + { + if (key.find("ssl-", 0) == 0) + { + #ifdef WITH_SSL + if (key.compare("ssl-ca") == 0) + { + set_ssl_ca(val); + } + else if (key.compare("ssl-ca-path") == 0) + { + set_ssl_ca_path(val); + } + else if (key.compare("ssl-key") == 0) + { + set_ssl_key(val); + } +#else + set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); + #endif + } + } + ~mysqlx_session_options_struct() { diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 846e3a3ad..65f50d3bc 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -27,7 +27,6 @@ #include #include "test.h" - TEST_F(xapi, store_result_select) { SKIP_IF_NO_XPLUGIN @@ -317,7 +316,7 @@ TEST_F(xapi, conn_string_test) unsigned short port = 0; char conn_error[MYSQLX_MAX_ERROR_LEN] = { 0 }; - char conn_str[1024]; + char conn_str[4096]; int conn_err_code = 0; bool ssl_enable = false; const char *xplugin_port = getenv("XPLUGIN_PORT"); @@ -326,8 +325,8 @@ TEST_F(xapi, conn_string_test) const char *xplugin_host = getenv("XPLUGIN_HOST"); mysqlx_session_t *local_sess; - mysqlx_stmt_t *stmt; mysqlx_result_t *res; + mysqlx_stmt_t *stmt; mysqlx_row_t *row; if (xplugin_port) @@ -354,16 +353,19 @@ TEST_F(xapi, conn_string_test) } cout << "Connected to xplugin..." << endl; - RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SELECT 'foo'", MYSQLX_NULL_TERMINATED)); + RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SHOW STATUS LIKE 'mysqlx_ssl_cipher'", MYSQLX_NULL_TERMINATED)); CRUD_CHECK(res = mysqlx_execute(stmt), stmt); - while ((row = mysqlx_row_fetch_one(res)) != NULL) + if ((row = mysqlx_row_fetch_one(res)) != NULL) { - char data[32]; + char data[128] = { 0 }; size_t data_len = sizeof(data); - EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, data, &data_len)); - EXPECT_STREQ("foo", data); - cout << "ROW DATA: " << data << " " << endl; + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, data, &data_len)); + if (ssl_enable) + { + cout << "SSL Cipher: " << data << endl; + EXPECT_TRUE(data_len > 1); + } } mysqlx_session_close(local_sess); @@ -372,6 +374,33 @@ TEST_F(xapi, conn_string_test) { ssl_enable = true; strcat(conn_str, "/?ssl-enable"); + authenticate(); + + res = mysqlx_sql(get_session(), "select @@ssl_ca, @@ssl_capath, @@datadir", MYSQLX_NULL_TERMINATED); + if ((row = mysqlx_row_fetch_one(res)) != NULL) + { + char ca_buf[1024] = { 0 }, capath_buf[1024] = { 0 }; + size_t ca_len = sizeof(ca_buf), capath_len = sizeof(capath_buf); + int rc = mysqlx_get_bytes(row, 0, 0, ca_buf, &ca_len); + if (rc != RESULT_OK && ca_len < 2) + return; + + strcat(conn_str, "&ssl-ca="); + rc = mysqlx_get_bytes(row, 1, 0, capath_buf, &capath_len); + if (rc != RESULT_OK || capath_len < 2) + { + capath_len = sizeof(capath_buf); + rc = mysqlx_get_bytes(row, 2, 0, capath_buf, &capath_len); + if (rc != RESULT_OK && capath_len < 2) + return; // Could not collect enough data about certificates + + strcat(conn_str, capath_buf); + } + strcat(conn_str, ca_buf); + strcat(conn_str, "&ssl-ca-path="); + strcat(conn_str, capath_buf); + } + goto DO_CONNECT; } } @@ -390,6 +419,7 @@ TEST_F(xapi, conn_options_test) const char *xplugin_usr = getenv("XPLUGIN_USER"); const char *xplugin_pwd = getenv("XPLUGIN_PASSWORD"); const char *xplugin_host = getenv("XPLUGIN_HOST"); + bool ssl_ca_detected = false; char buf[1024]; @@ -436,23 +466,71 @@ TEST_F(xapi, conn_options_test) } cout << "Connected to xplugin..." << endl; - RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SELECT 'foo'", MYSQLX_NULL_TERMINATED)); + RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SHOW STATUS LIKE 'mysqlx_ssl_cipher'", MYSQLX_NULL_TERMINATED)); CRUD_CHECK(res = mysqlx_execute(stmt), stmt); - while ((row = mysqlx_row_fetch_one(res)) != NULL) + if ((row = mysqlx_row_fetch_one(res)) != NULL) { - char data[32]; + char data[128] = { 0 }; size_t data_len = sizeof(data); - EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, data, &data_len)); - EXPECT_STREQ("foo", data); - cout << "ROW DATA: " << data << " " << endl; + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, data, &data_len)); + if (ssl_ca_detected) + { + cout << "SSL Cipher: " << data << endl; + EXPECT_TRUE(data_len > 0); + } } mysqlx_session_close(local_sess); + if (!ssl_enable) { - ssl_enable = 1; + ssl_enable = true; + authenticate(); EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_ENABLE, ssl_enable)); + + res = mysqlx_sql(get_session(), "select @@ssl_ca, @@ssl_capath, @@datadir", MYSQLX_NULL_TERMINATED); + if ((row = mysqlx_row_fetch_one(res)) != NULL) + { + char ca_buf[1024] = { 0 }, capath_buf[1024] = { 0 }, combined_buf[1024] = { 0 }; + char buf_check[1024] = { 0 }; + size_t ca_len = sizeof(ca_buf), capath_len = sizeof(capath_buf); + int rc = mysqlx_get_bytes(row, 0, 0, ca_buf, &ca_len); + if (rc != RESULT_OK && ca_len < 2) + { + mysqlx_free_options(opt); + return; + } + + rc = mysqlx_get_bytes(row, 1, 0, capath_buf, &capath_len); + if (rc != RESULT_OK || capath_len < 2) + { + capath_len = sizeof(capath_buf); + rc = mysqlx_get_bytes(row, 2, 0, capath_buf, &capath_len); + if (rc != RESULT_OK && capath_len < 2) + { + mysqlx_free_options(opt); + return; + } + + strcat(combined_buf, capath_buf); + strcat(combined_buf, ca_buf); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA, combined_buf)); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA, buf_check)); + EXPECT_STREQ(combined_buf, buf_check); + } + else + { + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA, ca_buf)); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA, buf_check)); + EXPECT_STREQ(ca_buf, buf_check); + } + + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA_PATH, capath_buf)); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA_PATH, buf_check)); + EXPECT_STREQ(capath_buf, buf_check); + } + goto DO_CONNECT; } From 59e3ee0a0b1686582dbec1fc970837dbb6f3f876 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Mon, 30 Jan 2017 16:25:58 +0100 Subject: [PATCH 44/79] Merge from CDK: Restrict allowed TLS ciphers. --- cdk/foundation/connection_yassl.cc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/cdk/foundation/connection_yassl.cc b/cdk/foundation/connection_yassl.cc index 3d619ae04..fef7d6a44 100644 --- a/cdk/foundation/connection_yassl.cc +++ b/cdk/foundation/connection_yassl.cc @@ -34,6 +34,15 @@ POP_SYS_WARNINGS #include "connection_tcpip_base.h" +static const char* tls_ciphers_list="DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" + "AES128-RMD:DES-CBC3-RMD:DHE-RSA-AES256-RMD:" + "DHE-RSA-AES128-RMD:DHE-RSA-DES-CBC3-RMD:" + "AES256-SHA:RC4-SHA:RC4-MD5:DES-CBC3-SHA:" + "DES-CBC-SHA:EDH-RSA-DES-CBC3-SHA:" + "EDH-RSA-DES-CBC-SHA:AES128-SHA:AES256-RMD:"; +static const char* tls_cipher_blocked= "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:!SSLv3:"; + + static void throw_yassl_error_msg(const char* msg) { throw cdk::foundation::Error(cdk::foundation::cdkerrc::tls_error, @@ -103,7 +112,7 @@ void connection_TLS_impl::do_connect() try { - yaSSL::SSL_METHOD* method = yaSSL::TLSv1_client_method(); + yaSSL::SSL_METHOD* method = yaSSL::TLSv1_1_client_method(); if (!method) throw_yassl_error(); @@ -112,6 +121,13 @@ void connection_TLS_impl::do_connect() if (!m_tls_ctx) throw_yassl_error(); + + std::string cipher_list; + cipher_list.append(tls_cipher_blocked); + cipher_list.append(tls_ciphers_list); + + SSL_CTX_set_cipher_list(m_tls_ctx, cipher_list.c_str()); + if (!m_options.get_ca().empty() || !m_options.get_ca_path().empty()) { From 426f394c28d279a30420a465146807c0ec48219a Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Wed, 1 Feb 2017 20:01:19 +1100 Subject: [PATCH 45/79] Added View DDL functions into XAPI --- include/mysql_xapi.h | 95 ++++++++- xapi/CMakeLists.txt | 1 + xapi/crud.cc | 118 ++++++++++- xapi/crud_internal.h | 31 ++- xapi/def_internal.h | 7 +- xapi/mysqlx.cc | 152 ++++++++++++++ xapi/mysqlx_cc_internal.h | 12 +- xapi/row.cc | 11 + xapi/row_internal.h | 3 +- xapi/schema.cc | 5 +- xapi/session.cc | 11 +- xapi/tests/xapi-t.cc | 426 +++++++++++++++++++++++++++++++++++++- xapi/view.cc | 141 +++++++++++++ xapi/view_internal.h | 72 +++++++ 14 files changed, 1069 insertions(+), 16 deletions(-) create mode 100644 xapi/view.cc create mode 100644 xapi/view_internal.h diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 36d652597..5be7917d6 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -157,9 +157,12 @@ typedef object_id* MYSQLX_GUID; #define MYSQLX_ERROR_INDEX_OUT_OF_RANGE_MSG "Index is out of range" #define MYSQLX_ERROR_MISSING_SCHEMA_NAME_MSG "Missing schema name" #define MYSQLX_ERROR_MISSING_TABLE_NAME_MSG "Missing table name" -#define MYSQLX_ERROR_MISSING_COLLECTION_NAME_MSG "Missing collection name" #define MYSQLX_ERROR_MISSING_VIEW_NAME_MSG "Missing view name" +#define MYSQLX_ERROR_MISSING_COLLECTION_NAME_MSG "Missing collection name" #define MYSQLX_ERROR_MISSING_KEY_NAME_MSG "Missing key name" +#define MYSQLX_ERROR_HANDLE_NULL_MSG "Handle cannot be NULL" +#define MYSQLX_ERROR_VIEW_INVALID_STMT_TYPE "Invalid statement type for View. Only SELECT type is supported" +#define MYSQLX_ERROR_VIEW_TYPE_MSG "Statement must be of VIEW type" #define MYSQLX_ERROR_OUTPUT_BUFFER_NULL "The output buffer cannot be NULL" #define MYSQLX_ERROR_OUTPUT_BUFFER_ZERO "The output buffer cannot have zero length" #define MYSQLX_ERROR_OP_NOT_SUPPORTED "The operation is not supported by the function" @@ -308,7 +311,6 @@ typedef enum mysqlx_data_type_enum #define PARAM_END (void*)0 - /** Sort directions in sorting operations such as ORDER BY. */ @@ -320,6 +322,9 @@ typedef enum mysqlx_sort_direction_enum } mysqlx_sort_direction_t; +#define PARAM_SORT_ASC(A) A, SORT_ORDER_ASC +#define PARAM_SORT_DESC(A) A, SORT_ORDER_DESC + /** Session options for use with `mysqlx_session_option_get()` and `mysqlx_session_option_set()` functions. @@ -339,6 +344,42 @@ typedef enum mysqlx_opt_type_enum mysqlx_opt_type_t; +/** + Constants for defining the View algorithm using + mysqlx_set_view_algorithm() function. +*/ + +typedef enum mysqlx_view_algorithm_enum +{ + VIEW_ALGORITHM_UNDEFINED = 0, + VIEW_ALGORITHM_MERGE = 1, + VIEW_ALGORITHM_TEMPTABLE = 2 +}mysqlx_view_algorithm_t; + + +/** + Constants for defining the View security using + mysqlx_set_view_security() function. +*/ + +typedef enum mysqlx_view_security_enum +{ + VIEW_SECURITY_DEFINER = 1, + VIEW_SECURITY_INVOKER = 2 +}mysqlx_view_security_t; + + +/** + Constants for defining the View check options + mysqlx_set_view_security() function. +*/ + +typedef enum mysqlx_view_check_option_enum +{ + VIEW_CHECK_OPTION_CASCADED = 1, + VIEW_CHECK_OPTION_LOCAL = 2 +}mysqlx_view_check_option_t; + /* ==================================================================== Session operations @@ -2762,6 +2803,56 @@ PUBLIC_API unsigned int mysqlx_result_warning_count(mysqlx_result_t *res); PUBLIC_API mysqlx_error_t * mysqlx_result_next_warning(mysqlx_result_t *res); +#define VIEW_OPTION_ALGORITHM 100 +#define VIEW_OPTION_SECURITY 101 +#define VIEW_OPTION_CHECK_OPTION 102 +#define VIEW_OPTION_DEFINER 103 +#define VIEW_OPTION_COLUMNS 104 + +#define VIEW_ALGORITHM(A) (void*)VIEW_OPTION_ALGORITHM, A +#define VIEW_SECURITY(S) (void*)VIEW_OPTION_SECURITY, S +#define VIEW_CHECK_OPTION(C) (void*)VIEW_OPTION_CHECK_OPTION, C +#define VIEW_DEFINER(D) (void*)VIEW_OPTION_DEFINER, D +#define VIEW_COLUMNS(...) (void*)VIEW_OPTION_COLUMNS, __VA_ARGS__ + +PUBLIC_API mysqlx_stmt_t * +mysqlx_view_create_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt); + +PUBLIC_API mysqlx_result_t * +mysqlx_view_create(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, ...); + +PUBLIC_API mysqlx_stmt_t * +mysqlx_view_modify_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt); + +PUBLIC_API mysqlx_result_t * +mysqlx_view_modify(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, ...); + +PUBLIC_API mysqlx_stmt_t * +mysqlx_view_replace_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt); + +PUBLIC_API mysqlx_result_t * +mysqlx_view_replace(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, ...); + +PUBLIC_API int +mysqlx_set_view_algorithm(mysqlx_stmt_t *view_stmt, int algorithm); + +PUBLIC_API int +mysqlx_set_view_security(mysqlx_stmt_t *view_stmt, int security); + +PUBLIC_API int +mysqlx_set_view_check_option(mysqlx_stmt_t *view_stmt, int option); + +PUBLIC_API int +mysqlx_set_view_definer(mysqlx_stmt_t *view_stmt, const char *user); + +PUBLIC_API int +mysqlx_set_view_columns(mysqlx_stmt_t *view_stmt, ...); #ifdef __cplusplus } diff --git a/xapi/CMakeLists.txt b/xapi/CMakeLists.txt index 9c1f21660..54886a456 100644 --- a/xapi/CMakeLists.txt +++ b/xapi/CMakeLists.txt @@ -45,6 +45,7 @@ SET(_libmysqlx_cc_src schema.cc collection.cc table.cc + view.cc ) ADD_LIBRARY(xapi OBJECT ${_libmysqlx_cc_src}) diff --git a/xapi/crud.cc b/xapi/crud.cc index 96494e964..f0c51e01c 100644 --- a/xapi/crud.cc +++ b/xapi/crud.cc @@ -58,11 +58,32 @@ void mysqlx_stmt_t::init_data_model() default: m_data_model = cdk::protocol::mysqlx::DEFAULT; m_parser_mode = parser::Parser_mode::TABLE; - break; + break; } m_group_by_list.set_parser_mode(m_parser_mode); } +void mysqlx_stmt_t::copy_parent_data(mysqlx_stmt_struct *parent) +{ + if (parent->m_where.get()) + m_where.reset(new Expression_parser(*static_cast(parent->m_where.get()))); + + if (parent->m_having.get()) + m_having.reset(new Expression_parser(*static_cast(parent->m_having.get()))); + + if (parent->m_limit.get()) + m_limit.reset(new Limit(*parent->m_limit.get())); + + if (parent->m_order_by.get()) + m_order_by.reset(new Order_by(*parent->m_order_by.get())); + + if (parent->m_proj_list.get()) + m_proj_list.reset(new Projection_list(*parent->m_proj_list.get())); + + m_param_source = parent->m_param_source; + m_group_by_list = parent->m_group_by_list; +} + void mysqlx_stmt_t::init_crud() { m_session.reset_diagnostic(); @@ -484,6 +505,19 @@ mysqlx_result_t *mysqlx_stmt_t::exec() m_limit.get(), m_param_source.count() ? &m_param_source : NULL); break; + case OP_VIEW_CREATE: + case OP_VIEW_UPDATE: + case OP_VIEW_REPLACE: + m_reply = sess.table_select(m_db_obj_ref, + &m_view_spec, + m_where.get(), + m_proj_list.get(), + m_order_by.get(), + m_group_by_list.get_list(), + m_having.get(), + m_limit.get(), + m_param_source.count() ? &m_param_source : NULL); + break; case OP_INSERT: { if (!m_row_source.row_count()) @@ -750,6 +784,88 @@ void mysqlx_stmt_t::clear_order_by() if(m_order_by.get()) m_order_by->clear(); } +bool mysqlx_stmt_t::is_view_op() +{ + return (m_op_type == OP_VIEW_CREATE || m_op_type == OP_VIEW_UPDATE || + m_op_type == OP_VIEW_REPLACE); +} + +void mysqlx_stmt_t::set_view_algorithm(int algorithm) +{ + if (!is_view_op()) + throw Mysqlx_exception(MYSQLX_ERROR_VIEW_TYPE_MSG); + + m_view_spec.set_algorithm(algorithm); +} + +void mysqlx_stmt_t::set_view_security(int security) +{ + if (!is_view_op()) + throw Mysqlx_exception(MYSQLX_ERROR_VIEW_TYPE_MSG); + + m_view_spec.set_security(security); +} + +void mysqlx_stmt_t::set_view_check_option(int option) +{ + if (!is_view_op()) + throw Mysqlx_exception(MYSQLX_ERROR_VIEW_TYPE_MSG); + + m_view_spec.set_check(option); +} + +void mysqlx_stmt_t::set_view_definer(const char* user) +{ + if (!is_view_op()) + throw Mysqlx_exception(MYSQLX_ERROR_VIEW_TYPE_MSG); + + m_view_spec.set_definer(user); +} + +void mysqlx_stmt_t::set_view_columns(va_list args) +{ + if (!is_view_op()) + throw Mysqlx_exception(MYSQLX_ERROR_VIEW_TYPE_MSG); + + m_view_spec.set_columns(args); +} + +void mysqlx_stmt_t::set_view_properties(va_list args) +{ + int64_t view_option = 0; + if (!is_view_op()) + throw Mysqlx_exception(MYSQLX_ERROR_VIEW_TYPE_MSG); + + /* + The list of arguments is ending after the list of columns, + so the function must stop getting more arguments + */ + while (view_option != VIEW_OPTION_COLUMNS && + (view_option = (int64_t)va_arg(args, void*)) != 0) + { + switch (view_option) + { + case VIEW_OPTION_ALGORITHM: + set_view_algorithm(va_arg(args, int)); + break; + case VIEW_OPTION_SECURITY: + set_view_security(va_arg(args, int)); + break; + case VIEW_OPTION_CHECK_OPTION: + set_view_check_option(va_arg(args, int)); + break; + case VIEW_OPTION_DEFINER: + set_view_definer(va_arg(args, const char*)); + break; + case VIEW_OPTION_COLUMNS: + set_view_columns(args); + break; + default: + throw Mysqlx_exception("Wrong VIEW property"); + } + } +} + mysqlx_stmt_t::~mysqlx_stmt_struct() { try diff --git a/xapi/crud_internal.h b/xapi/crud_internal.h index 171e66890..7d18a2d00 100644 --- a/xapi/crud_internal.h +++ b/xapi/crud_internal.h @@ -51,7 +51,7 @@ class Group_by_list : public cdk::Expr_list cdk::Expr_list *get_list() { return m_group_by_list.size() ? this : NULL; } }; -typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag +typedef struct mysqlx_stmt_struct : public Mysqlx_diag { private: mysqlx_session_t &m_session; @@ -75,6 +75,7 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag Modify_spec m_modify_spec; cdk::string m_query; Group_by_list m_group_by_list; + View_spec m_view_spec; int set_expression(cdk::scoped_ptr &member, const char *val); @@ -88,13 +89,24 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag } mysqlx_stmt_struct(mysqlx_session_t *session, const cdk::string &schema, const cdk::string &name, - mysqlx_op_t op_type) : m_session(*session), - m_db_obj_ref(schema, name), - m_op_type(op_type) + mysqlx_op_t op_type) : m_session(*session), + m_db_obj_ref(schema, name), + m_op_type(op_type) { init_data_model(); } + mysqlx_stmt_struct(mysqlx_session_t *session, const cdk::string &schema, const cdk::string &name, + mysqlx_op_t op_type, mysqlx_stmt_struct *parent) : m_session(*session), + m_db_obj_ref(parent->get_ref()), + m_op_type(op_type), + m_view_spec(schema, name, op_type) + { + init_data_model(); + if (parent) + copy_parent_data(parent); + } + /* Un-registering result. The parameter is not used. @@ -107,6 +119,8 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag return m_result.get() != NULL; } + void copy_parent_data(mysqlx_stmt_struct *parent); + mysqlx_result_t *get_result() { return m_result.get(); } /* @@ -152,6 +166,7 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag */ mysqlx_op_t op_type() { return m_op_type; } mysqlx_session_t &get_session() { return m_session; } + const Db_obj_ref &get_ref() { return m_db_obj_ref; } int set_where(const char *where_expr); int set_limit(row_count_t row_count, row_count_t offset); @@ -172,6 +187,14 @@ typedef struct mysqlx_stmt_struct : public cdk::foundation::nocopy, Mysqlx_diag // Return the session validity state bool session_valid(); + bool is_view_op(); + + void set_view_algorithm(int algorithm); + void set_view_security(int security); + void set_view_check_option(int option); + void set_view_definer(const char* user); + void set_view_columns(va_list args); + void set_view_properties(va_list args); friend class Group_by_list; } mysqlx_stmt_t; \ No newline at end of file diff --git a/xapi/def_internal.h b/xapi/def_internal.h index eb303e087..e9ab74267 100644 --- a/xapi/def_internal.h +++ b/xapi/def_internal.h @@ -41,7 +41,12 @@ typedef enum mysqlx_op_enum */ OP_SQL = 9, - OP_ADMIN_LIST = 10 +/* + View operation codes +*/ + OP_VIEW_CREATE = 10, OP_VIEW_UPDATE = 11, OP_VIEW_REPLACE = 12, + + OP_ADMIN_LIST = 13 } mysqlx_op_t; typedef enum mysqlx_modify_op_enum diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index 329f12b32..d14543100 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -81,6 +81,12 @@ return ERR; \ } +#define PARAM_NULL_CHECK(PARAM, HANDLE, ERR_MSG, ERR) if (!PARAM) \ + { \ + HANDLE->set_diagnostic(ERR_MSG, 0); \ + return ERR; \ + } + #define OUT_BUF_CHECK(PARAM, HANDLE, ERR_MSG, ERR) if (!PARAM) \ { \ HANDLE->set_diagnostic(ERR_MSG, 0); \ @@ -1837,6 +1843,152 @@ unsigned int STDCALL mysqlx_error_num(void *obj) return 0; } +#define STMT_SELECT_FIND_CHECK(SCHEMA, STMT, RET) if (STMT->op_type() != OP_SELECT) { \ + SCHEMA->set_diagnostic(MYSQLX_ERROR_VIEW_INVALID_STMT_TYPE, 0); \ + return RET; \ + } + +mysqlx_stmt_t * +_mysqlx_view_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, mysqlx_op_t op_type) +{ + SAFE_EXCEPTION_BEGIN(schema, NULL) + PARAM_NULL_EMPTY_CHECK(name, schema, MYSQLX_ERROR_MISSING_VIEW_NAME_MSG, NULL) + PARAM_NULL_CHECK(select_stmt, schema, MYSQLX_ERROR_HANDLE_NULL_MSG, NULL) + STMT_SELECT_FIND_CHECK(schema, select_stmt, NULL) + mysqlx_stmt_t *stmt = schema->stmt_op(name, op_type, select_stmt); + return stmt; + SAFE_EXCEPTION_END(schema, NULL) +} + + +mysqlx_stmt_t * +mysqlx_view_create_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt) +{ + return _mysqlx_view_new(schema, name, select_stmt, OP_VIEW_CREATE); +} + + +mysqlx_stmt_t * +mysqlx_view_modify_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt) +{ + return _mysqlx_view_new(schema, name, select_stmt, OP_VIEW_UPDATE); +} + + +mysqlx_stmt_t * +mysqlx_view_replace_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt) +{ + return _mysqlx_view_new(schema, name, select_stmt, OP_VIEW_REPLACE); +} + + +PUBLIC_API mysqlx_result_t * +_mysqlx_view(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, + mysqlx_op_t op_type, va_list args) +{ + SAFE_EXCEPTION_BEGIN(schema, NULL) + mysqlx_stmt_t *stmt; + + if ((stmt =_mysqlx_view_new(schema, name, select_stmt, + op_type)) == NULL) + return NULL; + + stmt->set_view_properties(args); + + mysqlx_result_t *res = mysqlx_execute(stmt); + if (res == NULL) + SET_ERROR_FROM_STMT(schema, stmt, NULL); + + return res; + SAFE_EXCEPTION_END(schema, NULL) +} + +PUBLIC_API mysqlx_result_t * +mysqlx_view_create(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, ...) +{ + va_list args; + va_start(args, select_stmt); + mysqlx_result_t *res = _mysqlx_view(schema, name, select_stmt, + OP_VIEW_CREATE, args); + va_end(args); + return res; +} + +PUBLIC_API mysqlx_result_t * +mysqlx_view_replace(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, ...) +{ + va_list args; + va_start(args, select_stmt); + mysqlx_result_t *res = _mysqlx_view(schema, name, select_stmt, + OP_VIEW_REPLACE, args); + va_end(args); + return res; +} + +PUBLIC_API mysqlx_result_t * +mysqlx_view_modify(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt, ...) +{ + va_list args; + va_start(args, select_stmt); + mysqlx_result_t *res = _mysqlx_view(schema, name, select_stmt, + OP_VIEW_UPDATE, args); + va_end(args); + return res; +} + +int mysqlx_set_view_algorithm(mysqlx_stmt_t *view_stmt, int algorithm) +{ + SAFE_EXCEPTION_BEGIN(view_stmt, RESULT_ERROR) + view_stmt->set_view_algorithm(algorithm); + return RESULT_OK; + SAFE_EXCEPTION_END(view_stmt, RESULT_ERROR) +} + +int mysqlx_set_view_security(mysqlx_stmt_t *view_stmt, int security) +{ + SAFE_EXCEPTION_BEGIN(view_stmt, RESULT_ERROR) + view_stmt->set_view_security(security); + return RESULT_OK; + SAFE_EXCEPTION_END(view_stmt, RESULT_ERROR) +} + +int mysqlx_set_view_check_option(mysqlx_stmt_t *view_stmt, int option) +{ + SAFE_EXCEPTION_BEGIN(view_stmt, RESULT_ERROR) + view_stmt->set_view_check_option(option); + return RESULT_OK; + SAFE_EXCEPTION_END(view_stmt, RESULT_ERROR) +} + +int mysqlx_set_view_definer(mysqlx_stmt_t *view_stmt, const char* user) +{ + SAFE_EXCEPTION_BEGIN(view_stmt, RESULT_ERROR) + view_stmt->set_view_definer(user); + return RESULT_OK; + SAFE_EXCEPTION_END(view_stmt, RESULT_ERROR) +} + +int mysqlx_set_view_columns(mysqlx_stmt_t *view_stmt, ...) +{ + SAFE_EXCEPTION_BEGIN(view_stmt, RESULT_ERROR) + va_list args; + va_start(args, view_stmt); + view_stmt->set_view_columns(args); + va_end(args); + return RESULT_OK; + SAFE_EXCEPTION_END(view_stmt, RESULT_ERROR) +} + + + #ifdef _WIN32 BOOL WINAPI DllMain( _In_ HINSTANCE, diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 19b194e56..06095cd56 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -37,6 +37,7 @@ #include "ref_internal.h" #include "error_internal.h" #include "row_internal.h" +#include "view_internal.h" #include "crud_internal.h" #define SKIP_ERROR_COLL_EXISTS 1051 @@ -489,7 +490,8 @@ typedef struct mysqlx_schema_struct : public Mysqlx_diag mysqlx_session_t &get_session() { return m_session; } mysqlx_collection_t & get_collection(const char *name, bool check); mysqlx_table_t & get_table(const char *name, bool check); - mysqlx_stmt_t *stmt_op(const cdk::string obj_name, mysqlx_op_t op_type); + mysqlx_stmt_t *stmt_op(const cdk::string obj_name, mysqlx_op_t op_type, + mysqlx_stmt_t *parent = NULL); ~mysqlx_schema_struct(); } mysqlx_schema_t; @@ -579,13 +581,19 @@ typedef struct mysqlx_session_struct : public Mysqlx_diag obj_name - table/collection name for the operation op_type - operation type. The allowed values are: OP_SELECT, OP_INSERT, OP_UPDATE, OP_DELETE + delete_crud - flag indicates if created statement is on session level + or above. Determining ownership of the object + (either caller or the session) is a side aspect of this. + parent - parent statement. Some statement types such as VIEW need to get + the context of parent SELECT or FIND statements. RETURN: CRUD handler containing the results and/or error TODO: error must be set if op_type goes out of the allowed range */ mysqlx_stmt_t *stmt_op(const cdk::string schema, const cdk::string obj_name, - mysqlx_op_t op_type, bool delete_crud = true); + mysqlx_op_t op_type, bool delete_crud = true, + mysqlx_stmt_t *parent = NULL); /* Delete the CRUD object and reset the pointer diff --git a/xapi/row.cc b/xapi/row.cc index 95d4f7fdf..ca1616277 100644 --- a/xapi/row.cc +++ b/xapi/row.cc @@ -328,6 +328,17 @@ void Column_source::process(cdk::api::Columns::Processor& prc) const prc.list_end(); } +void Column_source::process(cdk::String_list::Processor& prc) const +{ + prc.list_begin(); + for (Column_list::const_iterator it = m_columns.begin(); + it != m_columns.end(); ++it) + { + cdk::safe_prc(prc)->list_el()->val(*it); + } + prc.list_end(); +} + cdk::string Update_item::get_expr() const { diff --git a/xapi/row_internal.h b/xapi/row_internal.h index 5be6e8c22..e0c285434 100644 --- a/xapi/row_internal.h +++ b/xapi/row_internal.h @@ -559,7 +559,7 @@ class Doc_source : public Source_base, public cdk::Doc_source } }; -class Column_source : public cdk::api::Columns +class Column_source : public cdk::api::Columns, public cdk::String_list { typedef std::vector Column_list; Column_list m_columns; @@ -572,6 +572,7 @@ class Column_source : public cdk::api::Columns size_t count() { return m_columns.size(); } void process(cdk::api::Columns::Processor& prc) const; + void process(cdk::String_list::Processor& prc) const; }; class Modify_spec; diff --git a/xapi/schema.cc b/xapi/schema.cc index 092fb2282..0b5ab3860 100644 --- a/xapi/schema.cc +++ b/xapi/schema.cc @@ -78,12 +78,13 @@ mysqlx_schema_struct::~mysqlx_schema_struct() delete m_stmt; } -mysqlx_stmt_t *mysqlx_schema_struct::stmt_op(const cdk::string obj_name, mysqlx_op_t op_type) +mysqlx_stmt_t *mysqlx_schema_struct::stmt_op(const cdk::string obj_name, mysqlx_op_t op_type, + mysqlx_stmt_t *parent) { if (m_stmt) delete m_stmt; - m_stmt = m_session.stmt_op(m_name, obj_name, op_type, false); + m_stmt = m_session.stmt_op(m_name, obj_name, op_type, false, parent); if (!m_stmt) throw Mysqlx_exception("Error creating schema operation"); return m_stmt; diff --git a/xapi/session.cc b/xapi/session.cc index 67665ef4e..332885d2d 100644 --- a/xapi/session.cc +++ b/xapi/session.cc @@ -67,7 +67,8 @@ mysqlx_stmt_t * mysqlx_session_t::sql_query(const char *query, uint32_t length, collection or a table */ mysqlx_stmt_t * mysqlx_session_t::stmt_op(const cdk::string schema, const cdk::string obj_name, - mysqlx_op_t op_type, bool session_crud) + mysqlx_op_t op_type, bool session_crud, + mysqlx_stmt_t *parent) { mysqlx_stmt_t *stmt; @@ -82,7 +83,13 @@ mysqlx_stmt_t * mysqlx_session_t::stmt_op(const cdk::string schema, const cdk::s throw Mysqlx_exception("The default schema is not specified"); } - stmt = new mysqlx_stmt_t(this, schema.length() ? schema : *m_sess_opt.database(), obj_name, op_type); + if (parent) + stmt = new mysqlx_stmt_t(this, schema.length() ? schema : *m_sess_opt.database(), + obj_name, op_type, parent); + else + stmt = new mysqlx_stmt_t(this, schema.length() ? schema : *m_sess_opt.database(), + obj_name, op_type); + if (session_crud) m_stmt = stmt; return stmt; diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 846e3a3ad..2ddf2ba36 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -28,6 +28,429 @@ #include "test.h" +TEST_F(xapi, view_ddl_test) +{ + SKIP_IF_NO_XPLUGIN + + mysqlx_result_t *res; + mysqlx_row_t *row; + mysqlx_schema_t *schema; + mysqlx_table_t *table, *view, *view2; + mysqlx_stmt_t *stmt, *vstmt; + bool view2_read = false; + + uint32_t col_num = 0, row_num = 0, i = 0; + + authenticate(); + mysqlx_schema_drop(get_session(), "view_ddl"); + mysqlx_schema_create(get_session(), "view_ddl"); + + schema = mysqlx_get_schema(get_session(), "view_ddl", 1); + exec_sql("CREATE TABLE view_ddl.tab1(a INT, b VARCHAR(32))"); + EXPECT_TRUE((table = mysqlx_get_table(schema, "tab1", 1)) != NULL); + + RESULT_CHECK(stmt = mysqlx_table_insert_new(table)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_columns(stmt, "a", "b", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_SINT(100), PARAM_STRING("mysql"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_SINT(200), PARAM_STRING("test"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_SINT(300), PARAM_STRING("view"), PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + RESULT_CHECK(stmt = mysqlx_table_select_new(table)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_items(stmt, "a", "a*5 AS a5", "800 as a800", "CONCAT(b, ' tab') as conview", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_where(stmt, "a > 100")); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_order_by(stmt, PARAM_SORT_DESC("a"), PARAM_END)); + + // We do not have to execute the SELECT statement + RESULT_CHECK(vstmt = mysqlx_view_create_new(schema, "view1", stmt)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_algorithm(vstmt, VIEW_ALGORITHM_MERGE)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_security(vstmt, VIEW_SECURITY_INVOKER)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_check_option(vstmt, VIEW_CHECK_OPTION_CASCADED)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_definer(vstmt, "root")); + + // Change parent SELECT STMT, it is not supposed to affect the VIEW STMT in any way + EXPECT_EQ(RESULT_OK, mysqlx_set_select_items(stmt, "b", PARAM_END)); + + EXPECT_EQ(RESULT_OK, mysqlx_set_view_columns(vstmt, "viewcol1", "viewcol2", "viewcol3", "viewcol4", PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(vstmt), vstmt); + + EXPECT_TRUE((view = mysqlx_get_table(schema, "view1", 0)) != NULL); + RESULT_CHECK(res = mysqlx_table_select(view, NULL)); + + col_num = mysqlx_column_get_count(res); + EXPECT_EQ(col_num, 4); + + for (i = 0; i < col_num; ++i) + { + char name_val[32] = { 0 }; + const char *cname = mysqlx_column_get_name(res, i); + sprintf(name_val, "viewcol%d", i+1); + EXPECT_STREQ(name_val, cname); + } + + while ((row = mysqlx_row_fetch_one(res)) != NULL) + { + int64_t a, a5, a800; + char buf[128] = { 0 }; + + size_t buflen = sizeof(buf); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 0, &a)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 1, &a5)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 2, &a800)); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 3, 0, buf, &buflen)); + + cout << "Row #" << row_num << ": [" << a << " " << a5 << " " << a800 + << " '" << buf << "']" << endl; + + switch (row_num) + { + case 0: + EXPECT_EQ(300, a); + EXPECT_EQ(1500, a5); + EXPECT_EQ(800, a800); + EXPECT_STREQ(buf, "view tab"); + break; + case 1: + EXPECT_EQ(200, a); + EXPECT_EQ(1000, a5); + EXPECT_EQ(800, a800); + EXPECT_STREQ(buf, "test tab"); + break; + default: + FAIL() << "Wrong number of rows is fetched"; + } + + ++row_num; + } + + RESULT_CHECK(res = mysqlx_sql(get_session(), "SHOW CREATE VIEW `view_ddl`.`view1`", + MYSQLX_NULL_TERMINATED)); + EXPECT_TRUE((row = mysqlx_row_fetch_one(res)) != NULL); + { + char vbuf[4096] = { 0 }; + size_t vbuflen = sizeof(vbuf); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, vbuf, &vbuflen)); + EXPECT_TRUE(strstr(vbuf, "ALGORITHM=MERGE") != NULL ); + EXPECT_TRUE(strstr(vbuf, "SQL SECURITY INVOKER") != NULL); + EXPECT_TRUE(strstr(vbuf, "WITH CASCADED CHECK OPTION") != NULL); + EXPECT_TRUE(strstr(vbuf, "`root`@") != NULL); + } + + /* Check how CREATE VIEW works on existing view, error expected */ + RESULT_CHECK(vstmt = mysqlx_view_create_new(schema, "view1", stmt)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_columns(vstmt, "rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4", PARAM_END)); + EXPECT_TRUE(mysqlx_execute(vstmt) == NULL); + printf("Expected error: %s\n", mysqlx_error_message(vstmt)); + + RESULT_CHECK(stmt = mysqlx_table_select_new(table)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_items(stmt, "a", "a*10 AS a10", "8000 as a8000", "CONCAT(b, ' mod') as conview", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_where(stmt, "a > 200")); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_order_by(stmt, PARAM_SORT_DESC("a"), PARAM_END)); + + /* Check how REPLACE VIEW works on existing view */ + RESULT_CHECK(vstmt = mysqlx_view_replace_new(schema, "view1", stmt)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_algorithm(vstmt, VIEW_ALGORITHM_TEMPTABLE)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_security(vstmt, VIEW_SECURITY_DEFINER)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_columns(vstmt, "rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4", PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(vstmt), vstmt); + + /* Check how REPLACE VIEW works on non-existing view */ + RESULT_CHECK(vstmt = mysqlx_view_replace_new(schema, "view2", stmt)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_algorithm(vstmt, VIEW_ALGORITHM_TEMPTABLE)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_security(vstmt, VIEW_SECURITY_DEFINER)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_columns(vstmt, "rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4", PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(vstmt), vstmt); + + RESULT_CHECK(res = mysqlx_table_select(view, NULL)); + +REPEAT_VIEW_CHECK: + row_num = 0; + col_num = mysqlx_column_get_count(res); + EXPECT_EQ(col_num, 4); + + for (i = 0; i < col_num; ++i) + { + char name_val[32] = { 0 }; + const char *cname = mysqlx_column_get_name(res, i); + sprintf(name_val, "rviewcol%d", i + 1); + EXPECT_STREQ(name_val, cname); + } + + while ((row = mysqlx_row_fetch_one(res)) != NULL) + { + int64_t a, a10, a8000; + char buf[128] = { 0 }; + + size_t buflen = sizeof(buf); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 0, &a)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 1, &a10)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 2, &a8000)); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 3, 0, buf, &buflen)); + + cout << endl << "Row #" << row_num << ": [" << a << " " << a10 << " " << a8000 + << " '" << buf << "']"; + + switch (row_num) + { + case 0: + EXPECT_EQ(300, a); + EXPECT_EQ(3000, a10); + EXPECT_EQ(8000, a8000); + EXPECT_STREQ(buf, "view mod"); + break; + default: + FAIL() << "Wrong number of rows is fetched"; + } + ++row_num; + } + + if (!view2_read) + { + view2_read = true; + EXPECT_TRUE((view2 = mysqlx_get_table(schema, "view2", 0)) != NULL); + RESULT_CHECK(res = mysqlx_table_select(view2, NULL)); + goto REPEAT_VIEW_CHECK; // Same results for a new view + } + + /* Check how MODIFY VIEW works on non-existing view, error expected */ + RESULT_CHECK(vstmt = mysqlx_view_modify_new(schema, "view3", stmt)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_algorithm(vstmt, VIEW_ALGORITHM_TEMPTABLE)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_security(vstmt, VIEW_SECURITY_DEFINER)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_columns(vstmt, "rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4", PARAM_END)); + EXPECT_TRUE(mysqlx_execute(vstmt) == NULL); + printf("\nExpected error: %s\n", mysqlx_error_message(vstmt)); + + /* Check how MODIFY VIEW works on existing view */ + RESULT_CHECK(vstmt = mysqlx_view_modify_new(schema, "view2", stmt)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_algorithm(vstmt, VIEW_ALGORITHM_TEMPTABLE)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_security(vstmt, VIEW_SECURITY_DEFINER)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_columns(vstmt, "modcol1", "modcol2", "modcol3", "modcol4", PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(vstmt), vstmt); + + RESULT_CHECK(res = mysqlx_table_select(view2, NULL)); + col_num = mysqlx_column_get_count(res); + EXPECT_EQ(col_num, 4); + + for (i = 0; i < col_num; ++i) + { + char name_val[32] = { 0 }; + const char *cname = mysqlx_column_get_name(res, i); + sprintf(name_val, "modcol%d", i + 1); + EXPECT_STREQ(name_val, cname); + } + +} + +TEST_F(xapi, view_ddl_one_call_test) +{ + SKIP_IF_NO_XPLUGIN + + mysqlx_result_t *res; + mysqlx_row_t *row; + mysqlx_schema_t *schema; + mysqlx_table_t *table, *view, *view2; + mysqlx_stmt_t *stmt; + bool view2_read = false; + + uint32_t col_num = 0, row_num = 0, i = 0; + + authenticate(); + mysqlx_schema_drop(get_session(), "view_ddl"); + mysqlx_schema_create(get_session(), "view_ddl"); + + schema = mysqlx_get_schema(get_session(), "view_ddl", 1); + exec_sql("CREATE TABLE view_ddl.tab1(a INT, b VARCHAR(32))"); + EXPECT_TRUE((table = mysqlx_get_table(schema, "tab1", 1)) != NULL); + + RESULT_CHECK(stmt = mysqlx_table_insert_new(table)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_columns(stmt, "a", "b", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_SINT(100), PARAM_STRING("mysql"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_SINT(200), PARAM_STRING("test"), PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_insert_row(stmt, PARAM_SINT(300), PARAM_STRING("view"), PARAM_END)); + CRUD_CHECK(res = mysqlx_execute(stmt), stmt); + + RESULT_CHECK(stmt = mysqlx_table_select_new(table)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_items(stmt, "a", "a*5 AS a5", "800 as a800", "CONCAT(b, ' tab') as conview", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_where(stmt, "a > 100")); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_order_by(stmt, PARAM_SORT_DESC("a"), PARAM_END)); + + // We do not have to execute the SELECT statement + CRUD_CHECK(res = mysqlx_view_create(schema, "view1", stmt, + VIEW_ALGORITHM(VIEW_ALGORITHM_MERGE), + VIEW_SECURITY(VIEW_SECURITY_INVOKER), + VIEW_CHECK_OPTION(VIEW_CHECK_OPTION_CASCADED), + VIEW_DEFINER("root"), + VIEW_COLUMNS("viewcol1", "viewcol2", "viewcol3", "viewcol4"), + PARAM_END), schema); + + EXPECT_TRUE((view = mysqlx_get_table(schema, "view1", 0)) != NULL); + RESULT_CHECK(res = mysqlx_table_select(view, NULL)); + + col_num = mysqlx_column_get_count(res); + EXPECT_EQ(col_num, 4); + + for (i = 0; i < col_num; ++i) + { + char name_val[32] = { 0 }; + const char *cname = mysqlx_column_get_name(res, i); + sprintf(name_val, "viewcol%d", i + 1); + EXPECT_STREQ(name_val, cname); + } + + while ((row = mysqlx_row_fetch_one(res)) != NULL) + { + int64_t a, a5, a800; + char buf[128] = { 0 }; + + size_t buflen = sizeof(buf); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 0, &a)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 1, &a5)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 2, &a800)); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 3, 0, buf, &buflen)); + + cout << "Row #" << row_num << ": [" << a << " " << a5 << " " << a800 + << " '" << buf << "']" << endl; + + switch (row_num) + { + case 0: + EXPECT_EQ(300, a); + EXPECT_EQ(1500, a5); + EXPECT_EQ(800, a800); + EXPECT_STREQ(buf, "view tab"); + break; + case 1: + EXPECT_EQ(200, a); + EXPECT_EQ(1000, a5); + EXPECT_EQ(800, a800); + EXPECT_STREQ(buf, "test tab"); + break; + default: + FAIL() << "Wrong number of rows is fetched"; + } + + ++row_num; + } + + RESULT_CHECK(res = mysqlx_sql(get_session(), "SHOW CREATE VIEW `view_ddl`.`view1`", + MYSQLX_NULL_TERMINATED)); + EXPECT_TRUE((row = mysqlx_row_fetch_one(res)) != NULL); + { + char vbuf[4096] = { 0 }; + size_t vbuflen = sizeof(vbuf); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, vbuf, &vbuflen)); + EXPECT_TRUE(strstr(vbuf, "ALGORITHM=MERGE") != NULL); + EXPECT_TRUE(strstr(vbuf, "SQL SECURITY INVOKER") != NULL); + EXPECT_TRUE(strstr(vbuf, "WITH CASCADED CHECK OPTION") != NULL); + EXPECT_TRUE(strstr(vbuf, "`root`@") != NULL); + } + + /* Check how CREATE VIEW works on existing view, error expected */ + EXPECT_TRUE(mysqlx_view_create(schema, "view1", stmt, + VIEW_COLUMNS("viewcol1", "viewcol2", "viewcol3", "viewcol4"), + PARAM_END) == NULL); + printf("Expected error: %s\n", mysqlx_error_message(schema)); + + RESULT_CHECK(stmt = mysqlx_table_select_new(table)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_items(stmt, "a", "a*10 AS a10", "8000 as a8000", "CONCAT(b, ' mod') as conview", PARAM_END)); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_where(stmt, "a > 200")); + EXPECT_EQ(RESULT_OK, mysqlx_set_select_order_by(stmt, PARAM_SORT_DESC("a"), PARAM_END)); + + /* Check how REPLACE VIEW works on existing view */ + CRUD_CHECK(res = mysqlx_view_replace(schema, "view1", stmt, + VIEW_ALGORITHM(VIEW_ALGORITHM_TEMPTABLE), + VIEW_SECURITY(VIEW_SECURITY_DEFINER), + VIEW_COLUMNS("rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4"), + PARAM_END), schema); + + /* Check how REPLACE VIEW works on non-existing view */ + CRUD_CHECK(res = mysqlx_view_replace(schema, "view2", stmt, + VIEW_ALGORITHM(VIEW_ALGORITHM_TEMPTABLE), + VIEW_SECURITY(VIEW_SECURITY_DEFINER), + VIEW_COLUMNS("rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4"), + PARAM_END), schema); + + RESULT_CHECK(res = mysqlx_table_select(view, NULL)); + +REPEAT_VIEW_CHECK: + row_num = 0; + col_num = mysqlx_column_get_count(res); + EXPECT_EQ(col_num, 4); + + for (i = 0; i < col_num; ++i) + { + char name_val[32] = { 0 }; + const char *cname = mysqlx_column_get_name(res, i); + sprintf(name_val, "rviewcol%d", i + 1); + EXPECT_STREQ(name_val, cname); + } + + while ((row = mysqlx_row_fetch_one(res)) != NULL) + { + int64_t a, a10, a8000; + char buf[128] = { 0 }; + + size_t buflen = sizeof(buf); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 0, &a)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 1, &a10)); + EXPECT_EQ(RESULT_OK, mysqlx_get_sint(row, 2, &a8000)); + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 3, 0, buf, &buflen)); + + cout << endl << "Row #" << row_num << ": [" << a << " " << a10 << " " << a8000 + << " '" << buf << "']"; + + switch (row_num) + { + case 0: + EXPECT_EQ(300, a); + EXPECT_EQ(3000, a10); + EXPECT_EQ(8000, a8000); + EXPECT_STREQ(buf, "view mod"); + break; + default: + FAIL() << "Wrong number of rows is fetched"; + } + ++row_num; + } + + if (!view2_read) + { + view2_read = true; + EXPECT_TRUE((view2 = mysqlx_get_table(schema, "view2", 0)) != NULL); + RESULT_CHECK(res = mysqlx_table_select(view2, NULL)); + goto REPEAT_VIEW_CHECK; // Same results for a new view + } + + /* Check how MODIFY VIEW works on non-existing view, error expected */ + EXPECT_TRUE((res = mysqlx_view_modify(schema, "view3", stmt, + VIEW_ALGORITHM(VIEW_ALGORITHM_TEMPTABLE), + VIEW_SECURITY(VIEW_SECURITY_DEFINER), + VIEW_COLUMNS("rviewcol1", "rviewcol2", "rviewcol3", "rviewcol4"), + PARAM_END)) == NULL); + printf("\nExpected error: %s\n", mysqlx_error_message(schema)); + + /* Check how MODIFY VIEW works on existing view */ + CRUD_CHECK(res = mysqlx_view_modify(schema, "view2", stmt, + VIEW_ALGORITHM(VIEW_ALGORITHM_TEMPTABLE), + VIEW_SECURITY(VIEW_SECURITY_DEFINER), + VIEW_COLUMNS("modcol1", "modcol2", "modcol3", "modcol4"), + PARAM_END), schema); + + RESULT_CHECK(res = mysqlx_table_select(view2, NULL)); + col_num = mysqlx_column_get_count(res); + EXPECT_EQ(col_num, 4); + + for (i = 0; i < col_num; ++i) + { + char name_val[32] = { 0 }; + const char *cname = mysqlx_column_get_name(res, i); + sprintf(name_val, "modcol%d", i + 1); + EXPECT_STREQ(name_val, cname); + } + +} + + TEST_F(xapi, store_result_select) { SKIP_IF_NO_XPLUGIN @@ -676,4 +1099,5 @@ TEST_F(xapi, myc_344_sql_error_test) } EXPECT_TRUE((err_msg = mysqlx_error_message(res)) != NULL); printf("\nExpected error: %s\n", err_msg); -} \ No newline at end of file +} + diff --git a/xapi/view.cc b/xapi/view.cc new file mode 100644 index 000000000..85e3dbb63 --- /dev/null +++ b/xapi/view.cc @@ -0,0 +1,141 @@ +/* +* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. +* +* The MySQL Connector/C is licensed under the terms of the GPLv2 +* , like most +* MySQL Connectors. There are special exceptions to the terms and +* conditions of the GPLv2 as it is applied to this software, see the +* FLOSS License Exception +* . +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation; version 2 of the License. +* +* This program 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 General Public License +* for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "mysqlx_cc_internal.h" + + +View_spec::View_spec(const cdk::string &schema, const cdk::string &name, + mysqlx_op_t type) : m_ref(schema, name) +{ + switch (type) + { + case OP_VIEW_CREATE: + m_view_op_type = cdk::api::View_processor::CREATE; + break; + case OP_VIEW_UPDATE: + m_view_op_type = cdk::api::View_processor::UPDATE; + break; + case OP_VIEW_REPLACE: + m_view_op_type = cdk::api::View_processor::REPLACE; + break; + default: + throw Mysqlx_exception("Wrong VIEW operation"); + } +} + + +void View_spec::set_algorithm(int val) +{ + switch (val) + { + case VIEW_ALGORITHM_UNDEFINED: + m_opts.m_algorithm = cdk::View_algorithm::UNDEFINED; + break; + case VIEW_ALGORITHM_MERGE: + m_opts.m_algorithm = cdk::View_algorithm::MERGE; + break; + case VIEW_ALGORITHM_TEMPTABLE: + m_opts.m_algorithm = cdk::View_algorithm::TEMPTABLE; + break; + default: + throw Mysqlx_exception("Wrong value for VIEW algorithm"); + } + m_opts.m_algorithm_set = true; +} + +void View_spec::set_security(int val) +{ + switch (val) + { + case VIEW_SECURITY_DEFINER: + m_opts.m_security = cdk::View_security::DEFINER; + break; + case VIEW_SECURITY_INVOKER: + m_opts.m_security = cdk::View_security::INVOKER; + break; + default: + throw Mysqlx_exception("Wrong value for VIEW security"); + } + m_opts.m_security_set = true; +} + +void View_spec::set_check(int val) +{ + switch (val) + { + case VIEW_CHECK_OPTION_CASCADED: + m_opts.m_check = cdk::View_check::CASCADED; + break; + case VIEW_CHECK_OPTION_LOCAL: + m_opts.m_check = cdk::View_check::LOCAL; + break; + default: + throw Mysqlx_exception("Wrong value for VIEW check option"); + } + m_opts.m_check_set = true; +} + +void View_spec::set_definer(const char* val) +{ + m_opts.m_definer_set = true; + m_opts.m_definer = val; +} + +void View_spec::set_columns(va_list args) +{ + m_columns.clear(); + const char *col_name = va_arg(args, char*); + while (col_name) + { + m_columns.add_column(col_name); + col_name = va_arg(args, char*); + } +} + + +void View_spec::process(Processor &prc) const +{ + prc.name(m_ref, m_view_op_type); + m_opts.process_if(prc.options()); + + cdk::String_list::Processor *sprc = prc.columns(); + if (sprc) + m_columns.process(*sprc); +} + +void View_spec::View_opts::process(Processor &prc) const +{ + if (m_algorithm_set) + prc.algorithm(m_algorithm); + + if (m_security_set) + prc.security(m_security); + + if (m_check_set) + prc.check(m_check); + + if (m_definer_set) + prc.definer(m_definer); +} \ No newline at end of file diff --git a/xapi/view_internal.h b/xapi/view_internal.h new file mode 100644 index 000000000..29e4731e5 --- /dev/null +++ b/xapi/view_internal.h @@ -0,0 +1,72 @@ +/* +* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. +* +* The MySQL Connector/C is licensed under the terms of the GPLv2 +* , like most +* MySQL Connectors. There are special exceptions to the terms and +* conditions of the GPLv2 as it is applied to this software, see the +* FLOSS License Exception +* . +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation; version 2 of the License. +* +* This program 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 General Public License +* for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +class View_spec : public cdk::View_spec +{ + + struct View_opts : cdk::View_spec::Options + { + cdk::View_algorithm::value m_algorithm; + cdk::View_security::value m_security; + cdk::View_check::value m_check; + std::string m_definer; + + /* + Set flags must be introduced in order not to overwrite + previously set values by the default ones + */ + bool m_algorithm_set, m_security_set, m_check_set, m_definer_set; + + View_opts() : m_algorithm_set(false), m_security_set(false), + m_check_set(false), m_definer_set(false) + {} + + void process(Processor &prc) const; + }; + + View_opts m_opts; + Db_obj_ref m_ref; + cdk::string m_schema; + op_type m_view_op_type; + Column_source m_columns; + +public: + + View_spec() + {}; + + View_spec(const cdk::string &schema, const cdk::string &name, + mysqlx_op_t op_type); + + void set_algorithm(int val); + void set_security(int val); + void set_check(int val); + void set_definer(const char *val); + void set_columns(va_list arg); + + void process(Processor &prc) const; + +}; \ No newline at end of file From 1e26f31b8ada6420b40f37744f0bcb944828149c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Wed, 18 Jan 2017 16:11:42 +0000 Subject: [PATCH 46/79] MYCPP-72: DevAPI methods to define and manage views. --- devapi/collection_crud.cc | 23 ++- devapi/impl.h | 60 +++++- devapi/session.cc | 10 +- devapi/table_crud.cc | 289 +++++++++++++++++++++++++++- devapi/tests/crud-t.cc | 81 ++++++++ devapi/tests/session-t.cc | 172 +++++++++++++++++ include/devapi/collection_crud.h | 2 +- include/devapi/statement.h | 17 +- include/devapi/table_crud.h | 6 +- include/mysql_devapi.h | 311 +++++++++++++++++++++++++++++++ 10 files changed, 948 insertions(+), 23 deletions(-) diff --git a/devapi/collection_crud.cc b/devapi/collection_crud.cc index 4d6a0f511..4c747ef9a 100644 --- a/devapi/collection_crud.cc +++ b/devapi/collection_crud.cc @@ -110,6 +110,11 @@ class Op_collection_add , m_pos(0) {} + Executable_impl* clone() const override + { + return new Op_collection_add(*this); + } + void add_json(const mysqlx::string &json) override { @@ -365,8 +370,13 @@ class Op_collection_remove add_where(expr); } + Executable_impl* clone() const override + { + return new Op_collection_remove(*this); + } + - cdk::Reply* send_command() + cdk::Reply* send_command() override { return new cdk::Reply(get_cdk_session().coll_remove( @@ -430,8 +440,12 @@ class Op_collection_find add_where(expr); } + Executable_impl* clone() const override + { + return new Op_collection_find(*this); + } - cdk::Reply* send_command() + cdk::Reply* send_command() override { return new cdk::Reply(get_cdk_session().coll_find( @@ -530,6 +544,11 @@ class Op_collection_modify add_where(expr); } + Executable_impl* clone() const override + { + return new Op_collection_modify(*this); + } + cdk::Reply* send_command() override { // Do nothing if no update specifications were added diff --git a/devapi/impl.h b/devapi/impl.h index 56270993a..a0ae53fcc 100644 --- a/devapi/impl.h +++ b/devapi/impl.h @@ -536,7 +536,6 @@ class Op_base : public Impl , public cdk::Limit , public cdk::Param_source - , internal::nocopy { protected: @@ -566,6 +565,14 @@ class Op_base Op_base(Table &tbl) : m_sess(&tbl.getSession()) {} + Op_base(const Op_base& other) + : m_sess (other.m_sess ) + , m_limit (other.m_limit ) + , m_has_limit (other.m_has_limit ) + , m_offset (other.m_offset ) + , m_has_offset (other.m_has_offset) + , m_map (other.m_map ) + {} virtual ~Op_base() {} @@ -760,10 +767,15 @@ class Op_sort protected: - template - Op_sort(T &x) : Op_base(x) + template ::value + >::type* = nullptr + > + Op_sort(X &x) : Op_base(x) {} + public: cdk::Order_by* get_order_by() @@ -822,8 +834,12 @@ class Op_having protected: - template - Op_having(T &x) : Op_sort(x) + template ::value + >::type* = nullptr + > + Op_having(X &x) : Op_sort(x) {} public: @@ -875,8 +891,12 @@ class Op_group_by protected: - template - Op_group_by(T &x) : Op_having(x) + template ::value + >::type* = nullptr + > + Op_group_by(X &x) : Op_having(x) {} public: @@ -932,7 +952,12 @@ class Op_projection protected: - template + + template ::value + >::type* = nullptr + > Op_projection(X &init) : Op_group_by(init) {} @@ -1052,17 +1077,32 @@ class Op_select : public Base { protected: + mysqlx::string m_where_expr; std::unique_ptr m_expr; - template + template ::value + >::type* = nullptr + > Op_select(X &init) : Base(init) {} + Op_select(const Op_select &other) + : Base(other) + , m_where_expr(other.m_where_expr) + { + if (!m_where_expr.empty()) + m_expr.reset(new parser::Expression_parser(PM, m_where_expr)); + } + public: void add_where(const mysqlx::string &expr) { - m_expr.reset(new parser::Expression_parser(PM, expr)); + m_where_expr = expr; + if (!m_where_expr.empty()) + m_expr.reset(new parser::Expression_parser(PM, m_where_expr)); } cdk::Expression* get_where() const diff --git a/devapi/session.cc b/devapi/session.cc index 1de33dbe6..8f8b08745 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -1151,12 +1151,18 @@ struct Op_sql : public Op_base } m_params; - void add_param(Value val) + void add_param(Value val) override { m_params.m_values.emplace_back(std::move(val)); } - cdk::Reply* send_command() + Executable_impl* clone() const override + { + return new Op_sql(*this); + } + + + cdk::Reply* send_command() override { return new cdk::Reply( get_cdk_session().sql( diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index 7df49ee5a..10e878a36 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -83,6 +83,17 @@ class Op_table_insert , m_table(tbl) {} + Op_table_insert(const Op_table_insert &other) + : Op_sort(other) + , m_table(other.m_table) + , m_rows(other.m_rows) + , m_cols(other.m_cols) + {} + + Executable_impl* clone() const override + { + return new Op_table_insert(*this); + } void add_column(const mysqlx::string &column) override { @@ -207,13 +218,14 @@ class Op_table_select //typedef cdk::string string; Table_ref m_table; + const cdk::View_spec *m_view = nullptr; cdk::Reply* send_command() override { return new cdk::Reply(get_cdk_session().table_select( m_table, - NULL, // view spec + m_view, // view spec get_where(), get_tbl_proj(), get_order_by(), @@ -224,6 +236,16 @@ class Op_table_select )); } + void set_view(const cdk::View_spec *view) + { + m_view = view; + } + + + Executable_impl* clone() const override + { + return new Op_table_select(*this); + } public: @@ -232,7 +254,10 @@ class Op_table_select , m_table(table) {} + + friend mysqlx::TableSelect; + friend mysqlx::internal::Op_ViewCreateAlter; }; @@ -280,6 +305,11 @@ class Op_table_update SetValues m_set_values; SetValues::const_iterator m_set_it; + Executable_impl* clone() const override + { + return new Op_table_update(*this); + } + void add_set(const mysqlx::string &field, internal::ExprValue &&val) override { m_set_values[field] = std::move(val); @@ -346,6 +376,7 @@ class Op_table_update return m_table_field->table(); } + public: Op_table_update(Table &table) @@ -353,6 +384,12 @@ class Op_table_update , m_table(table) {} + Op_table_update(const Op_table_update &other) + : Op_select(other) + , m_table(other.m_table) + , m_set_values(other.m_set_values) + {} + friend mysqlx::TableUpdate; }; @@ -392,6 +429,12 @@ class Op_table_remove Table_ref m_table; + Executable_impl* clone() const override + { + return new Op_table_remove(*this); + } + + cdk::Reply* send_command() override { return @@ -412,6 +455,7 @@ class Op_table_remove {} + friend mysqlx::TableRemove; }; @@ -420,3 +464,246 @@ void TableRemove::prepare(Table &table) { m_impl.reset(new Op_table_remove(table)); } + + +// -------------------------------------------------------------------- + +/* + ViewCreateAlter + =============== +*/ + +namespace mysqlx{ +namespace internal { + +class Op_ViewCreateAlter + : public Op_base + , cdk::View_spec + , Table_ref +{ +public: + typedef cdk::View_spec::op_type op_type; + +private: + + op_type m_op_type; + CheckOption m_check_option; + std::unique_ptr m_table_select; + SQLSecurity m_security; + Algorithm m_algorythm; + std::vector m_columns; + mysqlx::string m_user; + + Executable_impl* clone() const override + { + return new Op_ViewCreateAlter(*this); + } + + Op_ViewCreateAlter(const Op_ViewCreateAlter& other) + : Op_base(other) + , Table_ref(other) + , m_op_type (other.m_op_type ) + , m_check_option (other.m_check_option) + , m_security (other.m_security ) + , m_algorythm (other.m_algorythm ) + , m_columns (other.m_columns ) + , m_user (other.m_user ) + { + if (other.m_table_select.get() != NULL) + { + m_table_select.reset(new TableSelect(*other.m_table_select.get())); + static_cast(m_table_select->get_impl())->set_view(this); + } + } + +public: + + Op_ViewCreateAlter(Schema &sch, const mysqlx::string &name, op_type replace) + : Op_base< mysqlx::internal::View_impl >(sch.getSession()) + , Table_ref(sch.getName(), name) + , m_op_type(replace) + {} + + void with_check_option(CheckOption option) override + { + m_check_option = option; + } + + void defined_as(TableSelect &&select) override + { + m_table_select.reset(new TableSelect(std::move(select))); + static_cast(m_table_select->get_impl())->set_view(this); + } + + void definer(const mysqlx::string &user) override + { + m_user = user; + } + + void security(SQLSecurity security) override + { + m_security = security; + } + + void algorithm(Algorithm algorythm) override + { + m_algorythm = algorythm; + } + + void add_columns(const mysqlx::string &name) override + { + m_columns.push_back(name); + } + + cdk::Reply* send_command() override + { + if (m_table_select.get() == NULL) + throw_error("Unexpected empty TableSelect"); + + cdk::Reply *ret = + static_cast(m_table_select->get_impl())->send_command(); + + return ret; + + } + + /* + cdk::View_spec Processor + */ + + void process( cdk::View_spec::Processor &prc) const override + { + prc.name(*this, m_op_type); + + if (m_columns.size() != 0) + { + auto list_columns = prc.columns(); + if (list_columns) + { + list_columns->list_begin(); + for (auto column : m_columns) + { + list_columns->list_el()->val(column); + } + list_columns->list_end(); + } + } + + auto options = prc.options(); + + if (options) + { + + switch (m_algorythm) + { + case Algorithm::MERGE: + options->algorithm(cdk::api::View_algorithm::MERGE); + break; + case Algorithm::TEMPTABLE: + options->algorithm(cdk::api::View_algorithm::TEMPTABLE); + break; + case Algorithm::UNDEFINED: + options->algorithm(cdk::api::View_algorithm::UNDEFINED); + break; + } + + switch(m_check_option) + { + case CheckOption::CASCADED: + options->check(cdk::api::View_check::CASCADED); + case CheckOption::LOCAL: + options->check(cdk::api::View_check::LOCAL); + } + + switch(m_security) + { + case SQLSecurity::DEFINER: + options->security(cdk::api::View_security::DEFINER); + break; + case SQLSecurity::INVOKER: + options->security(cdk::api::View_security::INVOKER); + } + } + + } +}; + +}} // namespace mysqlx::internal + +namespace mysqlx { + +ViewCreate::ViewCreate(Schema &sch, const string &name, bool replace) +{ + m_impl.reset( + new internal::Op_ViewCreateAlter(sch, + name, + replace ? + internal::Op_ViewCreateAlter::op_type::REPLACE : + internal::Op_ViewCreateAlter::op_type::CREATE ) + ); +} + + + +ViewAlter::ViewAlter(Schema &sch, const string &name) +{ + m_impl.reset( + new internal::Op_ViewCreateAlter(sch, + name, + internal::Op_ViewCreateAlter::op_type::UPDATE) + ); +} + +} // namespace mysqlx + + + +/* + ViewDrop + ======== +*/ + +namespace mysqlx { +namespace internal{ + +class Op_ViewDrop + : public Op_base + , public Table_ref +{ + bool m_checkExistence = true; + +public: + + Op_ViewDrop(Schema &sch, const string &name) + : Op_base(sch.getSession()) + , Table_ref(sch.getName(), name) + {} + + void if_exists() override + { + m_checkExistence = false; + } + + Executable_impl* clone() const override + { + return new Op_ViewDrop(*this); + } + + cdk::Reply* send_command() override + { + return new cdk::Reply(get_cdk_session().view_drop(*this,m_checkExistence)); + } +}; + +} // namespace internal + +ViewDrop::ViewDrop(Schema &sch, const string &name) +{ + m_impl.reset(new internal::Op_ViewDrop(sch, name)); +} + +} // namespace mysqlx + + + +// --------------------------------------------------------------------- diff --git a/devapi/tests/crud-t.cc b/devapi/tests/crud-t.cc index a78e5dcde..706261f0a 100644 --- a/devapi/tests/crud-t.cc +++ b/devapi/tests/crud-t.cc @@ -1966,3 +1966,84 @@ TEST_F(Crud, group_by_having) } +TEST_F(Crud, copy_semantics) +{ + SKIP_IF_NO_XPLUGIN; + + cout << "Creating session..." << endl; + + XSession sess(this); + + cout << "Session accepted, creating collection..." << endl; + + Schema sch = sess.getSchema("test"); + Collection coll = sch.createCollection("c1", true); + + add_data(coll); + + + cout << "Fetching documents..." << endl; + + CollectionFind find = coll.find("name like :name and age < :age"); + find.bind("name", "ba%"); + find.bind("age", 3); + + CollectionFind find2 = find; + + DocResult docs = find2.execute(); + + DbDoc doc = docs.fetchOne(); + + unsigned i = 0; + for (; doc; ++i, doc = docs.fetchOne()) + { + cout << "doc#" << i << ": " << doc << endl; + + for (Field fld : doc) + { + cout << " field `" << fld << "`: " << doc[fld] << endl; + } + + string name = doc["name"]; + cout << " name: " << name << endl; + + EXPECT_EQ(string("bar"), (string)doc["name"]); + + cout << " age: " << doc["age"] << endl; + + EXPECT_EQ(2, (int)doc["age"]); + + cout << endl; + } + + EXPECT_EQ(1, i); + + std::map args; + + args["name"] = "ba%"; + args["age"] = 3; + + CollectionRemove remove(coll, "name like :name and age < :age"); + + remove.bind(args); + + CollectionRemove remove2 = remove; + + remove2.execute(); + + { + CollectionFind f(coll, "name like :name and age < :age"); + + CollectionFind find2 = f; + + find2.bind(args); + + docs = find2.execute(); + + doc = docs.fetchOne(); + EXPECT_FALSE((bool)doc); + } + + + cout << "Done!" << endl; +} diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 76af4abac..7b97e9764 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -430,3 +430,175 @@ TEST_F(Sess, ssl_session) } } + +TEST_F(Sess, view) +{ + SKIP_IF_NO_XPLUGIN; + + XSession s(this); + + const string schema_name = "schemaView"; + const string tbl_name = "tblView"; + const string view_name = "view1"; + const string view_name2 = "view2"; + + Schema sch = s.createSchema(schema_name,true); + + s.dropTable(schema_name, tbl_name); + + sch.dropView(view_name).ifExists().execute(); + + std::stringstream qry; + + qry << "CREATE TABLE `"<< schema_name << + "`.`" << tbl_name <<"` (name VARCHAR(20) ,age INT);"; + + get_sess().sql(qry.str()).execute(); + + Table tbl = sch.getTable(tbl_name, true); + + tbl.insert("name", "age") + .values("Foo", 20) + .values("Bar", 30) + .values("Baz", 40) + .execute(); + + std::cout << "Create View" << std::endl; + + sch.createView(view_name, false) + .security(mysqlx::SQLSecurity::DEFINER) + .definer("root") + .definedAs(tbl.select("name as view_name", "2016-age as view_birth")) + .withCheckOption(mysqlx::CheckOption::LOCAL) + .execute(); + + std::cout << "Check View" << std::endl; + + { + Table view = sch.getTable(view_name); + + RowResult res = view.select().execute(); + + EXPECT_EQ(string("view_name"), res.getColumn(0).getColumnName()); + EXPECT_EQ(string("view_birth"), res.getColumn(1).getColumnName()); + + for(auto row : res) + { + if (row.get(0).get() == string("Foo")) + EXPECT_EQ(1996, row.get(1).get()); + else if (row.get(0).get() == string("Bar")) + EXPECT_EQ(1986, row.get(1).get()); + else if (row.get(0).get() == string("Baz")) + EXPECT_EQ(1976, row.get(1).get()); + } + } + + std::cout << "Expects error, since view is already created" << std::endl; + + EXPECT_THROW( + sch.createView(view_name, false) + .security(mysqlx::SQLSecurity::DEFINER) + .definedAs(tbl.select("name as view_name", "2016-age as view_birth")) + .withCheckOption(mysqlx::CheckOption::LOCAL) + .execute() + , mysqlx::Error + ); + + TableSelect tbl_select= + tbl.select("name", "2*age", "1 as one", "2 as two"); + + std::vector columns_list = {"view_name", "view_double_age"}; + + std::cout << "Different number of columns... Error expected" << std::endl; + + EXPECT_THROW( + sch.alterView(view_name) + .columns(columns_list, "one") + .security(mysqlx::SQLSecurity::DEFINER) + .definer("root") + .definedAs(tbl_select) + .withCheckOption(mysqlx::CheckOption::LOCAL) + .execute() + , mysqlx::Error); + + auto view_exec = sch.alterView(view_name) + .columns(columns_list, "one", string("two")) + .security(mysqlx::SQLSecurity::DEFINER) + .definer("root") + .definedAs(tbl_select) + .withCheckOption(mysqlx::CheckOption::LOCAL); + + TableSelect tbl_select_2 = tbl_select; + + std::cout << "Shouldn't update the alterView" << std::endl; + + tbl_select.limit(1); + + tbl_select_2.limit(2); + + //Execute copy of ViewAlter obj + auto view_exec2 = view_exec; + + view_exec2.execute(); + + std::cout << "Execute previously create TableSelect" << std::endl; + + EXPECT_EQ(1, tbl_select.execute().count()); + + std::cout << "Execute previously create TableSelect" << std::endl; + + EXPECT_EQ(2, tbl_select_2.execute().count()); + + std::cout << "Cannot alter View that is not created" << std::endl; + + EXPECT_THROW( sch.alterView(view_name2) + .columns("view_name", "fake") + .security(mysqlx::SQLSecurity::DEFINER) + .definer("root") + .definedAs(tbl_select) + .withCheckOption(mysqlx::CheckOption::LOCAL) + .execute() + , mysqlx::Error); + + std::cout << "Check View after alterView" << std::endl; + + { + Table view = sch.getTable(view_name); + + RowResult res = view.select().execute(); + + std::vector columns_metadata = res.getColumns(); + + EXPECT_EQ(string("view_name"), res.getColumn(0).getColumnName()); + EXPECT_EQ(string("view_double_age"), res.getColumn(1).getColumnName()); + EXPECT_EQ(string("one"), res.getColumn(2).getColumnName()); + EXPECT_EQ(string("two"), res.getColumn(3).getColumnName()); + + //EXPECT 3 rows, since the changed tableSelect shouldn't affect the view + EXPECT_EQ(3, res.count()); + + for(auto row : res) + { + if (row.get(0).get() == string("Foo")) + EXPECT_EQ(40, row.get(1).get()); + if (row.get(0).get() == string("Bar")) + EXPECT_EQ(60, row.get(1).get()); + if (row.get(0).get() == string("Baz")) + EXPECT_EQ(80, row.get(1).get()); + } + + } + + std::cout << "Drop view" << std::endl; + + sch.dropView(view_name).execute(); + + std::cout << "Drop view doesn't throw error because using ifExists" << std::endl; + + sch.dropView(view_name).ifExists().execute(); + + std::cout << "Without ifExists, will throw Error if no such View." << std::endl; + + EXPECT_THROW(sch.dropView(view_name).execute(), mysqlx::Error); + +} diff --git a/include/devapi/collection_crud.h b/include/devapi/collection_crud.h index 3aba7f1da..7f216d215 100644 --- a/include/devapi/collection_crud.h +++ b/include/devapi/collection_crud.h @@ -367,7 +367,7 @@ DLL_WARNINGS_POP CollectionAdd(Collection &coll); CollectionAdd(CollectionAdd &other) : Executable(other) {} - CollectionAdd(CollectionAdd &&other) : CollectionAdd(other) {} + CollectionAdd(CollectionAdd &&other) : Executable(std::move(other)) {} private: diff --git a/include/devapi/statement.h b/include/devapi/statement.h index b7853b7d8..9cb28cfd3 100644 --- a/include/devapi/statement.h +++ b/include/devapi/statement.h @@ -55,11 +55,16 @@ class XSession_base; struct Executable_impl { virtual BaseResult execute() = 0; + + virtual Executable_impl *clone() const = 0; + virtual ~Executable_impl() {} }; } // internal + + /** Represents an operation that can be executed. @@ -78,7 +83,7 @@ class Executable typedef internal::Executable_impl Impl; - std::unique_ptr m_impl; + std::shared_ptr m_impl; Executable() = default; Executable(Impl *impl) @@ -94,13 +99,15 @@ class Executable public: - Executable(Executable &other) : Executable(std::move(other)) + Executable(const Executable &other) + : m_impl(other.m_impl->clone()) {} Executable(Executable &&other) - : m_impl(std::move(other.m_impl)) + : m_impl(other.m_impl) {} + /// Execute given operation and wait for its result. virtual Res execute() @@ -172,10 +179,10 @@ class Statement public: Statement(Statement &other) - : Executable(std::move(other)) + : Executable(other) {} - Statement(Statement &&other) : Statement(other) {} + Statement(Statement &&other) : Executable(std::move(other)) {} /// Bind parameter with given name to the given value. diff --git a/include/devapi/table_crud.h b/include/devapi/table_crud.h index 4640e303a..e5b446ec1 100644 --- a/include/devapi/table_crud.h +++ b/include/devapi/table_crud.h @@ -579,6 +579,7 @@ namespace internal { namespace internal { class TableSelectBase; + class Op_ViewCreateAlter; /* Interface to be implemented by internal implementations @@ -679,8 +680,8 @@ DIAGNOSTIC_PUSH add_proj(proj...); } - TableSelect(TableSelect &other) : Executable(other) {} - TableSelect(TableSelect &&other) : TableSelect(other) {} + TableSelect(const TableSelect &other) : Executable(other) {} + TableSelect(TableSelect &&other) : Executable(std::move(other)) {} DIAGNOSTIC_POP @@ -698,6 +699,7 @@ DIAGNOSTIC_POP ///@cond IGNORED friend internal::TableSelectBase; + friend internal::Op_ViewCreateAlter; ///@endcond }; diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index bfb66afd3..8af28cb13 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -161,6 +161,292 @@ class PUBLIC_API DatabaseObject }; +/** + View creation and alter classes + */ + +enum class CheckOption +{ + CASCADED, + LOCAL +}; + +enum class Algorithm +{ + UNDEFINED, + MERGE, + TEMPTABLE +}; + +enum class SQLSecurity +{ + DEFINER, + INVOKER +}; + + +class ViewCreate; +class ViewAlter; + +namespace internal { + +/* + Create/Alter View classes +*/ + +struct View_impl + : public Executable_impl +{ + virtual void add_columns(const string&) = 0; + virtual void algorithm(Algorithm) = 0; + virtual void security(SQLSecurity) = 0; + virtual void definer(const string&) = 0; + virtual void defined_as(TableSelect&&) = 0; + virtual void with_check_option(CheckOption) = 0; +}; + +class PUBLIC_API View_check_opt +: public Executable +{ +protected: + + View_impl* get_impl() + { + check_if_valid(); + return static_cast(m_impl.get()); + } + +public: + + /** + Set constraints on the View. + */ + Executable withCheckOption(CheckOption option) + { + get_impl()->with_check_option(option); + return std::move(*this); + } +}; + +class PUBLIC_API View_defined_as +: protected View_check_opt +{ + +public: + + /** + Define the table select statement to generate the View. + */ + + View_check_opt definedAs(TableSelect&& table) + { + get_impl()->defined_as(std::move(table)); + return std::move(*this); + } + + View_check_opt definedAs(const TableSelect& table) + { + TableSelect table_tmp(table); + get_impl()->defined_as(std::move(table_tmp)); + return std::move(*this); + } +}; + +class PUBLIC_API View_definer +: public View_defined_as +{ + +public: + + /** + Define the View’s definer. + */ + View_defined_as definer(const string &user) + { + get_impl()->definer(user); + return std::move(*this); + } +}; + +class PUBLIC_API View_security + : public View_definer +{ + +public: + + /** + Define the View’s security scheme. + */ + View_definer security(SQLSecurity sec) + { + get_impl()->security(sec); + return std::move(*this); + } +}; + +class PUBLIC_API View_algorithm + : public View_security +{ + +public: + + /** + define the View’s algorithm. + */ + + View_security algorithm(Algorithm alg) + { + get_impl()->algorithm(alg); + return std::move(*this); + } + +}; + + +/* + Base blass for Create/Alter View +*/ +class PUBLIC_API View_base + : public View_algorithm +{ + + void add_columns(const char *name) + { + get_impl()->add_columns(name); + } + + void add_columns(const string &name) + { + get_impl()->add_columns(name); + } + + template + void add_columns(const C& col) + { + for (auto el : col) + { + get_impl()->add_columns(el); + } + } + + template + void add_columns(const C &name,const R&...rest) + { + add_columns(name); + add_columns(rest...); + } + +public: + + /** + Define the column names of the created/altered View. + */ + + template + View_algorithm columns(const T&...names) + { + add_columns(names...); + return std::move(*this); + } + + /// @cond IGNORED + friend class Schema; + friend ViewCreate; + friend ViewAlter; + /// @endcond + +}; + + + + +} // namespace internal + +/** + The ViewCreate class represents the creation of a view +*/ + +class PUBLIC_API ViewCreate + : public internal::View_base +{ + + ViewCreate(Schema &sch, const string& name, bool replace); + + /// @cond IGNORED + friend class Schema; + /// @endcond + +}; + + +/** + The ViewCreate class represents the creation of a view +*/ + +class PUBLIC_API ViewAlter + : public internal::View_base +{ + + ViewAlter(Schema &sch, const string& name); + + /// @cond IGNORED + friend class Schema; + /// @endcond + +}; + + +namespace internal { + +/* + View drop classes +*/ + +struct ViewDrop_impl + : public Executable_impl +{ + + virtual void if_exists() = 0; +}; + +class ViewDropIfExists + : public Executable +{ + + ViewDrop_impl* get_impl() + { + check_if_valid(); + return static_cast(m_impl.get()); + } + +public: + + Executable ifExists() + { + get_impl()->if_exists(); + return std::move(*this); + } +}; + +} // namespace internal + +/** + The ViewDrop class represents the drop of a view +*/ + +class PUBLIC_API ViewDrop + : public internal::ViewDropIfExists +{ + + ViewDrop(Schema &sch, const string& name); + + /// @cond IGNORED + friend class Schema; + /// @endcond + +}; + + /** Represents a database schema. @@ -297,6 +583,31 @@ class PUBLIC_API Schema */ Table getCollectionAsTable(const string&, bool check_exists = true); + /** + Create new View in the schema. + + If replace is true, the view should exist, otherwise Error is thrown. + */ + ViewCreate createView(const mysqlx::string& view_name, bool replace = false) + { + return ViewCreate(*this, view_name, replace); + } + + /** + Change created View in the schema. + */ + ViewAlter alterView(const mysqlx::string& view_name) + { + return ViewAlter(*this, view_name); + } + + + ViewDrop dropView(const mysqlx::string& view_name) + { + return ViewDrop(*this, view_name); + } + + friend Collection; }; From 5b2bd602de691bdb79dd8cf17ba540eec20acd7e Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 9 Feb 2017 10:35:29 +0100 Subject: [PATCH 47/79] Merge from CDK: Upgrade YaSSL to 2.4.2. --- cdk/extra/yassl/CMakeLists.txt | 13 +- cdk/extra/yassl/README | 102 ++++++-- cdk/extra/yassl/certs/dsa-cert.pem | 38 +-- cdk/extra/yassl/include/crypto_wrapper.hpp | 9 +- .../include/openssl/generate_prefix_files.pl | 0 cdk/extra/yassl/include/openssl/ssl.h | 11 +- cdk/extra/yassl/include/yassl_error.hpp | 3 +- cdk/extra/yassl/include/yassl_int.hpp | 12 +- cdk/extra/yassl/src/buffer.cpp | 2 +- cdk/extra/yassl/src/cert_wrapper.cpp | 45 ++-- cdk/extra/yassl/src/crypto_wrapper.cpp | 57 +++-- cdk/extra/yassl/src/handshake.cpp | 70 ++--- cdk/extra/yassl/src/lock.cpp | 18 +- cdk/extra/yassl/src/log.cpp | 7 +- cdk/extra/yassl/src/socket_wrapper.cpp | 12 +- cdk/extra/yassl/src/ssl.cpp | 130 +++++++--- cdk/extra/yassl/src/timer.cpp | 6 +- cdk/extra/yassl/src/yassl_error.cpp | 50 ++-- cdk/extra/yassl/src/yassl_imp.cpp | 162 ++++++------ cdk/extra/yassl/src/yassl_int.cpp | 58 +++-- cdk/extra/yassl/taocrypt/include/aes.hpp | 58 +++++ cdk/extra/yassl/taocrypt/include/asn.hpp | 15 +- cdk/extra/yassl/taocrypt/include/block.hpp | 2 +- cdk/extra/yassl/taocrypt/include/des.hpp | 6 +- cdk/extra/yassl/taocrypt/include/dh.hpp | 4 +- cdk/extra/yassl/taocrypt/include/dsa.hpp | 6 +- cdk/extra/yassl/taocrypt/include/error.hpp | 2 +- cdk/extra/yassl/taocrypt/include/file.hpp | 10 +- cdk/extra/yassl/taocrypt/include/hash.hpp | 4 +- cdk/extra/yassl/taocrypt/include/hmac.hpp | 8 +- cdk/extra/yassl/taocrypt/include/integer.hpp | 40 +-- cdk/extra/yassl/taocrypt/include/md5.hpp | 2 +- cdk/extra/yassl/taocrypt/include/misc.hpp | 44 ++-- cdk/extra/yassl/taocrypt/include/modarith.hpp | 4 +- cdk/extra/yassl/taocrypt/include/modes.hpp | 8 +- cdk/extra/yassl/taocrypt/include/rsa.hpp | 12 +- cdk/extra/yassl/taocrypt/include/runtime.hpp | 3 + cdk/extra/yassl/taocrypt/include/types.hpp | 9 +- cdk/extra/yassl/taocrypt/src/aes.cpp | 240 ++++++++++-------- cdk/extra/yassl/taocrypt/src/aestables.cpp | 2 +- cdk/extra/yassl/taocrypt/src/algebra.cpp | 6 +- cdk/extra/yassl/taocrypt/src/arc4.cpp | 16 +- cdk/extra/yassl/taocrypt/src/asn.cpp | 127 ++++----- cdk/extra/yassl/taocrypt/src/coding.cpp | 14 +- cdk/extra/yassl/taocrypt/src/des.cpp | 22 +- cdk/extra/yassl/taocrypt/src/dsa.cpp | 20 +- cdk/extra/yassl/taocrypt/src/file.cpp | 2 +- cdk/extra/yassl/taocrypt/src/hash.cpp | 8 +- cdk/extra/yassl/taocrypt/src/hc128.cpp | 122 ++++----- cdk/extra/yassl/taocrypt/src/integer.cpp | 28 +- cdk/extra/yassl/taocrypt/src/md2.cpp | 2 +- cdk/extra/yassl/taocrypt/src/md4.cpp | 10 +- cdk/extra/yassl/taocrypt/src/md5.cpp | 28 +- cdk/extra/yassl/taocrypt/src/misc.cpp | 2 +- cdk/extra/yassl/taocrypt/src/rabbit.cpp | 12 +- cdk/extra/yassl/taocrypt/src/random.cpp | 2 +- cdk/extra/yassl/taocrypt/src/ripemd.cpp | 32 +-- cdk/extra/yassl/taocrypt/src/rsa.cpp | 8 +- cdk/extra/yassl/taocrypt/src/sha.cpp | 160 ++++++------ cdk/extra/yassl/taocrypt/test/test.cpp | 3 + cdk/extra/yassl/testsuite/test.hpp | 21 +- 61 files changed, 1134 insertions(+), 795 deletions(-) mode change 100644 => 100755 cdk/extra/yassl/include/openssl/generate_prefix_files.pl diff --git a/cdk/extra/yassl/CMakeLists.txt b/cdk/extra/yassl/CMakeLists.txt index 0dcbed914..d09eedbe6 100644 --- a/cdk/extra/yassl/CMakeLists.txt +++ b/cdk/extra/yassl/CMakeLists.txt @@ -17,10 +17,9 @@ INCLUDE(install_macros) INCLUDE(msvc) INCLUDE_DIRECTORIES( - ${CMAKE_BINARY_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/include - ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/mySTL) + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/include + ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/mySTL) ADD_DEFINITIONS(${SSL_DEFINES}) @@ -49,8 +48,8 @@ CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) ADD_DEFINITIONS(-DSIZEOF_LONG=${SIZEOF_LONG} -DSIZEOF_LONG_LONG=${SIZEOF_LONG_LONG}) SET(YASSL_SOURCES src/buffer.cpp src/cert_wrapper.cpp src/crypto_wrapper.cpp src/handshake.cpp src/lock.cpp - src/log.cpp src/socket_wrapper.cpp src/ssl.cpp src/timer.cpp src/yassl_error.cpp - src/yassl_imp.cpp src/yassl_int.cpp) + src/log.cpp src/socket_wrapper.cpp src/ssl.cpp src/timer.cpp src/yassl_error.cpp + src/yassl_imp.cpp src/yassl_int.cpp) ADD_LIBRARY(yassl STATIC ${YASSL_SOURCES}) #RESTRICT_SYMBOL_EXPORTS(yassl) @@ -68,4 +67,4 @@ ENDIF() # if(NOT WINDOWS_RUNTIME_MD) # CHANGE_MD_2_MT() # endif() -#endif() \ No newline at end of file +#endif() diff --git a/cdk/extra/yassl/README b/cdk/extra/yassl/README index d245d20ce..32a505438 100644 --- a/cdk/extra/yassl/README +++ b/cdk/extra/yassl/README @@ -2,7 +2,7 @@ yaSSL takes a different approach to certificate verification than OpenSSL does. The default policy for the client is to verify the server, this means that if -you don't load CAs to verify the server you'll get a connect error, unable to +you don't load CAs to verify the server you'll get a connect error, unable to verify. It you want to mimic OpenSSL behavior of not verifying the server and reducing security you can do this by calling: @@ -12,6 +12,66 @@ before calling SSL_new(); *** end Note *** +yaSSL Release notes, version 2.4.2 (9/22/2016) + This release of yaSSL fixes a medium security vulnerability. A fix for + potential AES side channel leaks is included that a local user monitoring + the same CPU core cache could exploit. VM users, hyper-threading users, + and users where potential attackers have access to the CPU cache will need + to update if they utilize AES. + + DSA padding fixes for unusual sizes is included as well. Users with DSA + certficiates should update. + +yaSSL Release notes, version 2.4.0 (5/20/2016) + This release of yaSSL fixes the OpenSSL compatibility function + SSL_CTX_load_verify_locations() when using the path directory to allow + unlimited path sizes. Minor Windows build fixes are included. + No high level security fixes in this version but we always recommend + updating. + + +yaSSL Release notes, version 2.3.9b (2/03/2016) + This release of yaSSL fixes the OpenSSL compatibility function + X509_NAME_get_index_by_NID() to use the actual index of the common name + instead of searching on the format prefix. Thanks for the report from + yashwant.sahu@oracle.com . Anyone using this function should update. + +yaSSL Release notes, version 2.3.9 (12/01/2015) + This release of yaSSL fixes two client side Diffie-Hellman problems. + yaSSL was only handling the cases of zero or one leading zeros for the key + agreement instead of potentially any number. This caused about 1 in 50,000 + connections to fail when using DHE cipher suites. The second problem was + the case where a server would send a public value shorter than the prime + value, causing about 1 in 128 client connections to fail, and also + caused the yaSSL client to read off the end of memory. All client side + DHE cipher suite users should update. + Thanks to Adam Langely (agl@imperialviolet.org) for the detailed report! + +yaSSL Release notes, version 2.3.8 (9/17/2015) + This release of yaSSL fixes a high security vulnerability. All users + SHOULD update. If using yaSSL for TLS on the server side with private + RSA keys allowing ephemeral key exchange you MUST update and regenerate + the RSA private keys. This report is detailed in: + https://people.redhat.com/~fweimer/rsa-crt-leaks.pdf + yaSSL now detects RSA signature faults and returns an error. + +yaSSL Patch notes, version 2.3.7e (6/26/2015) + This release of yaSSL includes a fix for Date less than comparison. + Previously yaSSL would return true on less than comparisons if the Dates + were equal. Reported by Oracle. No security problem, but if a cert was + generated right now, a server started using it in the same second, and a + client tried to verify it in the same second it would report not yet valid. + +yaSSL Patch notes, version 2.3.7d (6/22/2015) + This release of yaSSL includes a fix for input_buffer set_current with + index 0. SSL_peek() at front of waiting data could trigger. Robert + Golebiowski of Oracle identified and suggested a fix, thanks! + +yaSSL Patch notes, version 2.3.7c (6/12/2015) + This release of yaSSL does certificate DATE comparisons to the second + instead of to the minute, helpful when using freshly generated certs. + Though keep in mind that time sync differences could still show up. + yaSSL Patch notes, version 2.3.7b (3/18/2015) This release of yaSSL fixes a potential crash with corrupted private keys. Also detects bad keys earlier for user. @@ -24,7 +84,7 @@ yaSSL Release notes, version 2.3.6 (11/25/2014) This release of yaSSL fixes some valgrind warnings/errors including uninitialized reads and off by one index errors induced from fuzzing - the handshake. These were reported by Oracle. + the handshake. These were reported by Oracle. yaSSL Release notes, version 2.3.5 (9/29/2014) @@ -113,7 +173,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. This release of yaSSL contains bug fixes, the removal of assert() s and a security patch for a buffer overflow possibility in certificate name - processing. + processing. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -141,7 +201,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.9.2 (9/24/08) This release of yaSSL contains bug fixes and improved certificate verify - callback support. + callback support. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -149,7 +209,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.8.8 (5/7/08) - This release of yaSSL contains bug fixes, and better socket handling. + This release of yaSSL contains bug fixes, and better socket handling. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -159,7 +219,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. This release of yaSSL contains bug fixes, and fixes security problems associated with using SSL 2.0 client hellos and improper input handling. - Please upgrade to this version if you are using a previous one. + Please upgrade to this version if you are using a previous one. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -168,7 +228,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.7.5 (10/15/07) This release of yaSSL contains bug fixes, adds MSVC 2005 project support, - GCC 4.2 support, IPV6 support and test, and new test certificates. + GCC 4.2 support, IPV6 support and test, and new test certificates. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -177,7 +237,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.7.2 (8/20/07) This release of yaSSL contains bug fixes and adds initial OpenVPN support. - Just configure at this point and beginning of build. + Just configure at this point and beginning of build. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -208,8 +268,8 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. Since yaSSL now supports zlib, as does libcurl, the libcurl build test can - fail if yaSSL is built with zlib support since the zlib library isn't - passed. You can do two things to fix this: + fail if yaSSL is built with zlib support since the zlib library isn't + passed. You can do two things to fix this: 1) build yaSSL w/o zlib --without-zlib 2) or add flags to curl configure LDFLAGS="-lm -lz" @@ -223,7 +283,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. SSL_METHOD *TLSv1_1_server_method(void); SSL_METHOD *TLSv1_1_client_method(void); - + or the SSLv23 versions (even though yaSSL doesn't support SSL 2.0 the v23 means to pick the highest of SSL 3.0, TLS 1.0, or TLS 1.1). @@ -260,7 +320,7 @@ See libcurl build instructions below under 1.3.0. 2) follow the instructions in zlib from projects/visualc6/README.txt for how to add the zlib project into the yaSSL workspace noting that you'll need to add configuration support for "Win32 Debug" and - "Win32 Release" in note 3 under "To use:". + "Win32 Release" in note 3 under "To use:". 3) define HAVE_LIBZ when building yaSSL @@ -272,7 +332,7 @@ See libcurl build instructions below under 1.3.0. This release of yaSSL contains bug fixes, portability enhancements, - nonblocking connect and accept, better OpenSSL error mapping, and + nonblocking connect and accept, better OpenSSL error mapping, and certificate caching for session resumption. See normal build instructions below under 1.0.6. @@ -283,7 +343,7 @@ See libcurl build instructions below under 1.3.0. This release of yaSSL contains bug fixes, portability enhancements, - and libcurl 7.15.4 support (any newer versions may not build). + and libcurl 7.15.4 support (any newer versions may not build). See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0. @@ -325,12 +385,12 @@ See normal build instructions below under 1.0.6. --To build for libcurl on Win32: - Simply add the yaSSL project as a dependency to libcurl, add + Simply add the yaSSL project as a dependency to libcurl, add yaSSL-Home\include and yaSSL-Home\include\openssl to the include list, and define USE_SSLEAY and USE_OPENSSL please email todd@yassl.com if you have any questions. - + *******************yaSSL Release notes, version 1.2.2 (03/27/06) @@ -523,8 +583,8 @@ Please see build instructions in release notes 0.3.0. ******************yaSSL Release notes, version 0.4.0 This release of yaSSL contains minor bug fixes, an optional memory tracker, -an echo client and server with input/output redirection for load testing, -and initial session caching support. +an echo client and server with input/output redirection for load testing, +and initial session caching support. Please see build instructions in release notes 0.3.0. @@ -572,7 +632,7 @@ See the notes at the bottom of this page for build instructions. *******************yaSSL Release notes, version 0.2.0 This release of yaSSL contains minor bug fixes and initial alternate crypto -functionality. +functionality. *** Complete Build *** @@ -588,7 +648,7 @@ gzip -cd yassl-update-0.2.0.tar.gz | tar xvf - to update the previous release. -Then issue the make command on linux or rebuild the yaSSL project on Windows. +Then issue the make command on linux or rebuild the yaSSL project on Windows. *******************yaSSL Release notes, version 0.1.0 @@ -648,7 +708,7 @@ Building yassl on linux: use the ./buildall script to build everything. -buildall will configure and build CML, CryptoPP, and yassl. Testing was +buildall will configure and build CML, CryptoPP, and yassl. Testing was preformed with gcc version 3.3.2 on kernel 2.4.22. diff --git a/cdk/extra/yassl/certs/dsa-cert.pem b/cdk/extra/yassl/certs/dsa-cert.pem index 10d533edc..10794cbee 100644 --- a/cdk/extra/yassl/certs/dsa-cert.pem +++ b/cdk/extra/yassl/certs/dsa-cert.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDqzCCA2ugAwIBAgIJAMGqrgDU6DyhMAkGByqGSM44BAMwgY4xCzAJBgNVBAYT +MIIDrzCCA2+gAwIBAgIJAK1zRM7YFcNjMAkGByqGSM44BAMwgZAxCzAJBgNVBAYT AlVTMQ8wDQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQK -DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wu -Y29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTEzMDQyMjIw -MDk0NFoXDTE2MDExNzIwMDk0NFowgY4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZP -cmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQKDAd3b2xmU1NMMRAwDgYD -VQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wuY29tMR8wHQYJKoZIhvcN -AQkBFhBpbmZvQHdvbGZzc2wuY29tMIIBuDCCASwGByqGSM44BAEwggEfAoGBAL1R -7koy4IrH6sbh6nDEUUPPKgfhxxLCWCVexF2+qzANEr+hC9M002haJXFOfeS9DyoO -WFbL0qMZOuqv+22CaHnoUWl7q3PjJOAI3JH0P54ZyUPuU1909RzgTdIDp5+ikbr7 -KYjnltL73FQVMbjTZQKthIpPn3MjYcF+4jp2W2zFAhUAkcntYND6MGf+eYzIJDN2 -L7SonHUCgYEAklpxErfqznIZjVvqqHFaq+mgAL5J8QrKVmdhYZh/Y8z4jCjoCA8o -TDoFKxf7s2ZzgaPKvglaEKiYqLqic9qY78DYJswzQMLFvjsF4sFZ+pYCBdWPQI4N -PgxCiznK6Ce+JH9ikSBvMvG+tevjr2UpawDIHX3+AWYaZBZwKADAaboDgYUAAoGB -AJ3LY89yHyvQ/TsQ6zlYbovjbk/ogndsMqPdNUvL4RuPTgJP/caaDDa0XJ7ak6A7 -TJ+QheLNwOXoZPYJC4EGFSDAXpYniGhbWIrVTCGe6lmZDfnx40WXS0kk3m/DHaC0 -3ElLAiybxVGxyqoUfbT3Zv1JwftWMuiqHH5uADhdXuXVo1AwTjAdBgNVHQ4EFgQU -IJjk416o4v8qpH9LBtXlR9v8gccwHwYDVR0jBBgwFoAUIJjk416o4v8qpH9LBtXl -R9v8gccwDAYDVR0TBAUwAwEB/zAJBgcqhkjOOAQDAy8AMCwCFCjGKIdOSV12LcTu -k08owGM6YkO1AhQe+K173VuaO/OsDNsxZlKpyH8+1g== +DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz +bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMTYwOTIy +MjEyMzA0WhcNMjIwMzE1MjEyMzA0WjCBkDELMAkGA1UEBhMCVVMxDzANBgNVBAgM +Bk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxEDAOBgNVBAoMB3dvbGZTU0wxEDAO +BgNVBAsMB3Rlc3RpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG +SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCAbgwggEsBgcqhkjOOAQBMIIBHwKB +gQC9Ue5KMuCKx+rG4epwxFFDzyoH4ccSwlglXsRdvqswDRK/oQvTNNNoWiVxTn3k +vQ8qDlhWy9KjGTrqr/ttgmh56FFpe6tz4yTgCNyR9D+eGclD7lNfdPUc4E3SA6ef +opG6+ymI55bS+9xUFTG402UCrYSKT59zI2HBfuI6dltsxQIVAJHJ7WDQ+jBn/nmM +yCQzdi+0qJx1AoGBAJJacRK36s5yGY1b6qhxWqvpoAC+SfEKylZnYWGYf2PM+Iwo +6AgPKEw6BSsX+7Nmc4Gjyr4JWhComKi6onPamO/A2CbMM0DCxb47BeLBWfqWAgXV +j0CODT4MQos5yugnviR/YpEgbzLxvrXr469lKWsAyB19/gFmGmQWcCgAwGm6A4GF +AAKBgQCdy2PPch8r0P07EOs5WG6L425P6IJ3bDKj3TVLy+Ebj04CT/3Gmgw2tFye +2pOgO0yfkIXizcDl6GT2CQuBBhUgwF6WJ4hoW1iK1UwhnupZmQ358eNFl0tJJN5v +wx2gtNxJSwIsm8VRscqqFH2092b9ScH7VjLoqhx+bgA4XV7l1aNQME4wHQYDVR0O +BBYEFCCY5ONeqOL/KqR/SwbV5Ufb/IHHMB8GA1UdIwQYMBaAFCCY5ONeqOL/KqR/ +SwbV5Ufb/IHHMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwMvADAsAhQRYSCVN/Ge +agV3mffU3qNZ92fI0QIUPH7Jp+iASI7U1ocaYDc10qXGaGY= -----END CERTIFICATE----- diff --git a/cdk/extra/yassl/include/crypto_wrapper.hpp b/cdk/extra/yassl/include/crypto_wrapper.hpp index db9136c53..84419e342 100644 --- a/cdk/extra/yassl/include/crypto_wrapper.hpp +++ b/cdk/extra/yassl/include/crypto_wrapper.hpp @@ -17,7 +17,7 @@ */ -/* The crypto wrapper header is used to define policies for the cipher +/* The crypto wrapper header is used to define policies for the cipher * components used by SSL. There are 3 policies to consider: * * 1) MAC, the Message Authentication Code used for each Message @@ -174,7 +174,7 @@ class HMAC_RMD : public Digest { }; -// BulkCipher policy should implement encrypt, decrypt, get block size, +// BulkCipher policy should implement encrypt, decrypt, get block size, // and set keys for encrypt and decrypt struct BulkCipher : public virtual_base { virtual void encrypt(byte*, const byte*, unsigned int) = 0; @@ -318,7 +318,7 @@ struct Auth : public virtual_base { // For use with NULL Authentication schemes struct NO_Auth : public Auth { void sign(byte*, const byte*, unsigned int, const RandomPool&) {} - bool verify(const byte*, unsigned int, const byte*, unsigned int) + bool verify(const byte*, unsigned int, const byte*, unsigned int) { return true; } }; @@ -372,11 +372,12 @@ class DiffieHellman { DiffieHellman(const Integer&, const Integer&, const RandomPool&); ~DiffieHellman(); - DiffieHellman(const DiffieHellman&); + DiffieHellman(const DiffieHellman&); DiffieHellman& operator=(const DiffieHellman&); uint get_agreedKeyLength() const; const byte* get_agreedKey() const; + uint get_publicKeyLength() const; const byte* get_publicKey() const; void makeAgreement(const byte*, unsigned int); diff --git a/cdk/extra/yassl/include/openssl/generate_prefix_files.pl b/cdk/extra/yassl/include/openssl/generate_prefix_files.pl old mode 100644 new mode 100755 diff --git a/cdk/extra/yassl/include/openssl/ssl.h b/cdk/extra/yassl/include/openssl/ssl.h index becf7aacd..37654ab71 100644 --- a/cdk/extra/yassl/include/openssl/ssl.h +++ b/cdk/extra/yassl/include/openssl/ssl.h @@ -34,7 +34,7 @@ #include "rsa.h" -#define YASSL_VERSION "2.3.7b" +#define YASSL_VERSION "2.4.2" #if defined(__cplusplus) @@ -335,9 +335,6 @@ enum { /* ssl Constants */ SSL_OP_ALL = 61, SSL_OP_SINGLE_DH_USE = 62, SSL_OP_EPHEMERAL_RSA = 63, - SSL_OP_NO_SSLv2 = 64, - SSL_OP_NO_SSLv3 = 65, - SSL_OP_NO_TLSv1 = 66, SSL_OP_PKCS1_CHECK_1 = 67, SSL_OP_PKCS1_CHECK_2 = 68, SSL_OP_NETSCAPE_CA_DN_BUG = 69, @@ -358,8 +355,12 @@ enum { /* ssl Constants */ SSL_RECEIVED_SHUTDOWN = 94, SSL_CB_ALERT = 95, SSL_CB_READ = 96, - SSL_CB_HANDSHAKE_DONE = 97 + SSL_CB_HANDSHAKE_DONE = 97, + SSL_OP_NO_SSLv2 = 128, + SSL_OP_NO_SSLv3 = 256, + SSL_OP_NO_TLSv1 = 512, + SSL_OP_NO_TLSv1_1 = 1024, }; diff --git a/cdk/extra/yassl/include/yassl_error.hpp b/cdk/extra/yassl/include/yassl_error.hpp index beba7b0b5..d63244dca 100644 --- a/cdk/extra/yassl/include/yassl_error.hpp +++ b/cdk/extra/yassl/include/yassl_error.hpp @@ -53,7 +53,8 @@ enum YasslError { compress_error = 118, decompress_error = 119, pms_version_error = 120, - sanityCipher_error = 121 + sanityCipher_error = 121, + rsaSignFault_error = 122 // !!!! add error message to .cpp !!!! diff --git a/cdk/extra/yassl/include/yassl_int.hpp b/cdk/extra/yassl/include/yassl_int.hpp index 85cbbc966..b360b7775 100644 --- a/cdk/extra/yassl/include/yassl_int.hpp +++ b/cdk/extra/yassl/include/yassl_int.hpp @@ -53,7 +53,6 @@ char* yassl_get_tty_password(const char*); #define get_tty_password yassl_get_tty_password - namespace STL = STL_NAMESPACE; @@ -201,14 +200,19 @@ class sslFactory { class X509_NAME { char* name_; size_t sz_; + int cnPosition_; // start of common name, -1 is none + int cnLen_; // length of above ASN1_STRING entry_; public: - X509_NAME(const char*, size_t sz); + X509_NAME(const char*, size_t sz, int pos, int len); ~X509_NAME(); const char* GetName() const; ASN1_STRING* GetEntry(int i); size_t GetLength() const; + int GetCnPosition() const { return cnPosition_; } + int GetCnLength() const { return cnLen_; } + private: X509_NAME(const X509_NAME&); // hide copy X509_NAME& operator=(const X509_NAME&); // and assign @@ -236,7 +240,7 @@ class X509 { StringHolder afterDate_; // not valid after public: X509(const char* i, size_t, const char* s, size_t, - ASN1_STRING *b, ASN1_STRING *a); + ASN1_STRING *b, ASN1_STRING *a, int, int, int, int); ~X509() {} X509_NAME* GetIssuer(); @@ -488,7 +492,7 @@ class SSL_CTX { void SetUserData(void*); void SetSessionCacheOff(); void SetSessionCacheFlushOff(); - + void SetMethod(SSL_METHOD* meth); void IncrementStats(StatsField); void AddCA(x509* ca); const CertList& GetCA_List() const; diff --git a/cdk/extra/yassl/src/buffer.cpp b/cdk/extra/yassl/src/buffer.cpp index 07325c0e2..e5a996b7f 100644 --- a/cdk/extra/yassl/src/buffer.cpp +++ b/cdk/extra/yassl/src/buffer.cpp @@ -162,7 +162,7 @@ void input_buffer::set_error() void input_buffer::set_current(uint i) { - if (error_ == 0 && i && check(i - 1, size_) == 0) + if (error_ == 0 && check(i ? i - 1 : 0, size_) == 0) current_ = i; else error_ = -1; diff --git a/cdk/extra/yassl/src/cert_wrapper.cpp b/cdk/extra/yassl/src/cert_wrapper.cpp index af94f5bc2..96c8e94fa 100644 --- a/cdk/extra/yassl/src/cert_wrapper.cpp +++ b/cdk/extra/yassl/src/cert_wrapper.cpp @@ -37,14 +37,14 @@ namespace yaSSL { -x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) +x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) { } -x509::~x509() -{ - ysArrayDelete(buffer_); +x509::~x509() +{ + ysArrayDelete(buffer_); } @@ -71,20 +71,20 @@ x509& x509::operator=(const x509& that) uint x509::get_length() const -{ - return length_; +{ + return length_; } const opaque* x509::get_buffer() const -{ - return buffer_; +{ + return buffer_; } opaque* x509::use_buffer() -{ - return buffer_; +{ + return buffer_; } @@ -173,7 +173,7 @@ void CertManager::setVerifyCallback(VerifyCallback vc) void CertManager::AddPeerCert(x509* x) -{ +{ peerList_.push_back(x); // take ownership } @@ -203,13 +203,13 @@ int CertManager::CopyCaCert(const x509* x) const x509* CertManager::get_cert() const -{ +{ return list_.front(); } const opaque* CertManager::get_peerKey() const -{ +{ return peerPublicKey_.get_buffer(); } @@ -239,19 +239,19 @@ SignatureAlgorithm CertManager::get_keyType() const uint CertManager::get_peerKeyLength() const -{ +{ return peerPublicKey_.get_size(); } const opaque* CertManager::get_privateKey() const -{ +{ return privateKey_.get_buffer(); } uint CertManager::get_privateKeyLength() const -{ +{ return privateKey_.get_size(); } @@ -304,7 +304,10 @@ int CertManager::Validate() afterDate.type= cert.GetAfterDateType(); afterDate.length= strlen((char *) afterDate.data) + 1; peerX509_ = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength() + ); if (err == TaoCrypt::SIG_OTHER_E && verifyCallback_) { X509_STORE_CTX store; @@ -350,7 +353,9 @@ int CertManager::SetPrivateKey(const x509& key) afterDate.type= cd.GetAfterDateType(); afterDate.length= strlen((char *) afterDate.data) + 1; selfX509_ = NEW_YS X509(cd.GetIssuer(), iSz, cd.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cd.GetIssuerCnStart(), cd.GetIssuerCnLength(), + cd.GetSubjectCnStart(), cd.GetSubjectCnLength()); } return 0; } @@ -367,7 +372,9 @@ void CertManager::setPeerX509(X509* x) ASN1_STRING* after = x->GetAfter(); peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), - subject->GetName(), subject->GetLength(), before, after); + subject->GetName(), subject->GetLength(), before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); } diff --git a/cdk/extra/yassl/src/crypto_wrapper.cpp b/cdk/extra/yassl/src/crypto_wrapper.cpp index 529943645..e9b4586da 100644 --- a/cdk/extra/yassl/src/crypto_wrapper.cpp +++ b/cdk/extra/yassl/src/crypto_wrapper.cpp @@ -58,7 +58,7 @@ MD5::MD5() : pimpl_(NEW_YS MD5Impl) {} MD5::~MD5() { ysDelete(pimpl_); } -MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS +MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS MD5Impl(that.pimpl_->md5_)) {} @@ -223,8 +223,8 @@ struct HMAC_MD5::HMAC_MD5Impl { }; -HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_MD5Impl) +HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_MD5Impl) { pimpl_->mac_.SetKey(secret, len); } @@ -273,8 +273,8 @@ struct HMAC_SHA::HMAC_SHAImpl { }; -HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_SHAImpl) +HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_SHAImpl) { pimpl_->mac_.SetKey(secret, len); } @@ -324,8 +324,8 @@ struct HMAC_RMD::HMAC_RMDImpl { }; -HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_RMDImpl) +HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_RMDImpl) { pimpl_->mac_.SetKey(secret, len); } @@ -536,7 +536,7 @@ RandomPool::~RandomPool() { ysDelete(pimpl_); } int RandomPool::GetError() const { - return pimpl_->RNG_.GetError(); + return pimpl_->RNG_.GetError(); } void RandomPool::Fill(opaque* dst, uint sz) const @@ -573,10 +573,10 @@ void DSS::DSSImpl::SetPrivate(const byte* key, unsigned int sz) // Set public or private key -DSS::DSS(const byte* key, unsigned int sz, bool publicKey) +DSS::DSS(const byte* key, unsigned int sz, bool publicKey) : pimpl_(NEW_YS DSSImpl) { - if (publicKey) + if (publicKey) pimpl_->SetPublic(key, sz); else pimpl_->SetPrivate(key, sz); @@ -644,10 +644,10 @@ void RSA::RSAImpl::SetPrivate(const byte* key, unsigned int sz) // Set public or private key -RSA::RSA(const byte* key, unsigned int sz, bool publicKey) +RSA::RSA(const byte* key, unsigned int sz, bool publicKey) : pimpl_(NEW_YS RSAImpl) { - if (publicKey) + if (publicKey) pimpl_->SetPublic(key, sz); else pimpl_->SetPrivate(key, sz); @@ -695,7 +695,7 @@ bool RSA::verify(const byte* message, unsigned int sz, const byte* sig, void RSA::encrypt(byte* cipher, const byte* plain, unsigned int sz, const RandomPool& random) { - + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); enc.Encrypt(plain, sz, cipher, random.pimpl_->RNG_); } @@ -723,7 +723,7 @@ Integer::~Integer() { ysDelete(pimpl_); } -Integer::Integer(const Integer& other) : pimpl_(NEW_YS +Integer::Integer(const Integer& other) : pimpl_(NEW_YS IntegerImpl(other.pimpl_->int_)) {} @@ -748,18 +748,19 @@ struct DiffieHellman::DHImpl { byte* publicKey_; byte* privateKey_; byte* agreedKey_; + uint pubKeyLength_; DHImpl(TaoCrypt::RandomNumberGenerator& r) : ranPool_(r), publicKey_(0), - privateKey_(0), agreedKey_(0) {} - ~DHImpl() - { - ysArrayDelete(agreedKey_); - ysArrayDelete(privateKey_); + privateKey_(0), agreedKey_(0), pubKeyLength_(0) {} + ~DHImpl() + { + ysArrayDelete(agreedKey_); + ysArrayDelete(privateKey_); ysArrayDelete(publicKey_); } DHImpl(const DHImpl& that) : dh_(that.dh_), ranPool_(that.ranPool_), - publicKey_(0), privateKey_(0), agreedKey_(0) + publicKey_(0), privateKey_(0), agreedKey_(0), pubKeyLength_(0) { uint length = dh_.GetByteLength(); AllocKeys(length, length, length); @@ -807,7 +808,7 @@ DiffieHellman::DiffieHellman(const byte* p, unsigned int pSz, const byte* g, using TaoCrypt::Integer; pimpl_->dh_.Initialize(Integer(p, pSz).Ref(), Integer(g, gSz).Ref()); - pimpl_->publicKey_ = NEW_YS opaque[pubSz]; + pimpl_->publicKey_ = NEW_YS opaque[pimpl_->pubKeyLength_ = pubSz]; memcpy(pimpl_->publicKey_, pub, pubSz); } @@ -832,9 +833,9 @@ DiffieHellman::~DiffieHellman() { ysDelete(pimpl_); } // Client side and view, use server that for p and g -DiffieHellman::DiffieHellman(const DiffieHellman& that) +DiffieHellman::DiffieHellman(const DiffieHellman& that) : pimpl_(NEW_YS DHImpl(*that.pimpl_)) -{ +{ pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, pimpl_->publicKey_); } @@ -851,7 +852,7 @@ DiffieHellman& DiffieHellman::operator=(const DiffieHellman& that) void DiffieHellman::makeAgreement(const byte* other, unsigned int otherSz) { - pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); + pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); } @@ -866,6 +867,10 @@ const byte* DiffieHellman::get_agreedKey() const return pimpl_->agreedKey_; } +uint DiffieHellman::get_publicKeyLength() const +{ + return pimpl_->pubKeyLength_; +} const byte* DiffieHellman::get_publicKey() const { @@ -954,7 +959,7 @@ x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) if (fgets(line,sizeof(line), file)) // get blank line begin = ftell(file); } - + } while(fgets(line, sizeof(line), file)) @@ -973,7 +978,7 @@ x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) size_t bytes = fread(tmp.get_buffer(), end - begin, 1, file); if (bytes != 1) return 0; - + Source der(tmp.get_buffer(), end - begin); Base64Decoder b64Dec(der); diff --git a/cdk/extra/yassl/src/handshake.cpp b/cdk/extra/yassl/src/handshake.cpp index e63d69e9e..212163e6b 100644 --- a/cdk/extra/yassl/src/handshake.cpp +++ b/cdk/extra/yassl/src/handshake.cpp @@ -44,7 +44,7 @@ void buildClientHello(SSL& ssl, ClientHello& hello) memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), ID_LEN); } - else + else hello.id_len_ = 0; hello.suite_len_ = ssl.getSecurity().get_parms().suites_size_; memcpy(hello.cipher_suites_, ssl.getSecurity().get_parms().suites_, @@ -87,7 +87,7 @@ void buildServerHello(SSL& ssl, ServerHello& hello) // add handshake from buffer into md5 and sha hashes, use handshake header void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) { - const opaque* buffer = input.get_buffer() + input.get_current() - + const opaque* buffer = input.get_buffer() + input.get_current() - HANDSHAKE_HEADER; sz += HANDSHAKE_HEADER; ssl.useHashes().use_MD5().update(buffer, sz); @@ -99,7 +99,7 @@ void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) namespace { // Write a plaintext record to buffer -void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, const Message& msg) { buffer.allocate(RECORD_HEADER + rlHdr.length_); @@ -108,7 +108,7 @@ void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, // Write a plaintext record to buffer -void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, const HandShakeHeader& hsHdr, const HandShakeBase& shake) { buffer.allocate(RECORD_HEADER + rlHdr.length_); @@ -170,7 +170,7 @@ void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) opaque md5_inner[SIZEOF_SENDER + SECRET_LEN + PAD_MD5]; opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make md5 inner @@ -194,12 +194,12 @@ void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) // calculate SHA hash for finished void buildSHA(SSL& ssl, Finished& fin, const opaque* sender) { - + opaque sha_result[SHA_LEN]; opaque sha_inner[SIZEOF_SENDER + SECRET_LEN + PAD_SHA]; opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make sha inner @@ -309,7 +309,7 @@ void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) uint ivSz = iv.get_size(); output.allocate(sz); output << rlHeader << iv << hsHeader << fin; - + hashHandShake(ssl, output, ssl.isTLSv1_1() ? true : false); opaque digest[SHA_LEN]; // max size if (ssl.isTLS()) @@ -335,7 +335,7 @@ void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) { uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); - uint sz = RECORD_HEADER + msg.get_length() + digestSz; + uint sz = RECORD_HEADER + msg.get_length() + digestSz; uint pad = 0; uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); @@ -358,11 +358,11 @@ void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) ssl.getCrypto().get_random().Fill(iv.get_buffer(), blockSz); iv.add_size(blockSz); } - + uint ivSz = iv.get_size(); output.allocate(sz); output << rlHeader << iv << msg; - + opaque digest[SHA_LEN]; // max size if (ssl.isTLS()) TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER + ivSz, @@ -397,7 +397,7 @@ void buildAlert(SSL& ssl, output_buffer& output, const Alert& alert) // build TLS finished message -void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) +void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) { opaque handshake_hash[FINISHED_SZ]; @@ -410,9 +410,9 @@ void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) else side = tls_server; - PRF(fin.set_md5(), TLS_FINISHED_SZ, - ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, - side, FINISHED_LABEL_SZ, + PRF(fin.set_md5(), TLS_FINISHED_SZ, + ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, + side, FINISHED_LABEL_SZ, handshake_hash, FINISHED_SZ); fin.set_length(TLS_FINISHED_SZ); // shorter length for TLS @@ -441,7 +441,7 @@ void p_hash(output_buffer& result, const output_buffer& secret, uint lastTime = times - 1; for (uint i = 0; i < times; i++) { - hmac->update(previous, len); + hmac->update(previous, len); hmac->get_digest(current, seed.get_buffer(), seed.get_size()); if (lastLen && (i == lastTime)) @@ -459,7 +459,7 @@ void p_hash(output_buffer& result, const output_buffer& secret, void get_xor(byte *digest, uint digLen, output_buffer& md5, output_buffer& sha) { - for (uint i = 0; i < digLen; i++) + for (uint i = 0; i < digLen; i++) digest[i] = md5[AUTO] ^ sha[AUTO]; } @@ -471,7 +471,7 @@ void buildMD5_CertVerify(SSL& ssl, byte* digest) opaque md5_inner[SECRET_LEN + PAD_MD5]; opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make md5 inner @@ -497,7 +497,7 @@ void buildSHA_CertVerify(SSL& ssl, byte* digest) opaque sha_inner[SECRET_LEN + PAD_SHA]; opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make sha inner @@ -572,7 +572,7 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) } int j = 0; - for (uint16 i = 0; i < ch.suite_len_; i += 3) { + for (uint16 i = 0; i < ch.suite_len_; i += 3) { byte first = input[AUTO]; if (first) // sslv2 type input.read(len, SUITE_LEN); // skip @@ -589,13 +589,13 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) if (randomLen < RAN_LEN) memset(ch.random_, 0, RAN_LEN - randomLen); input.read(&ch.random_[RAN_LEN - randomLen], randomLen); - + ch.Process(input, ssl); } // Build a finished message, see 7.6.9 -void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) +void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) { // store current states, building requires get_digest which resets state MD5 md5(ssl.getHashes().get_MD5()); @@ -623,7 +623,7 @@ void hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, { Digest& mac = ssl.useCrypto().use_digest(); opaque inner[SHA_LEN + PAD_MD5 + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ]; - opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; + opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; opaque result[SHA_LEN]; // max possible sizes uint digestSz = mac.get_digestSize(); // actual sizes uint padSz = mac.get_padSize(); @@ -676,11 +676,11 @@ void TLS_hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, hmac.reset(NEW_YS HMAC_RMD(ssl.get_macSecret(verify), RMD_LEN)); else hmac.reset(NEW_YS HMAC_MD5(ssl.get_macSecret(verify), MD5_LEN)); - + hmac->update(seq, SEQ_SZ); // seq_num inner[0] = content; // type - inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; - inner[SIZEOF_ENUM + SIZEOF_ENUM] = + inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; + inner[SIZEOF_ENUM + SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.minor_; // version memcpy(&inner[SIZEOF_ENUM + VERSION_SZ], length, LENGTH_SZ); // length hmac->update(inner, sizeof(inner)); @@ -760,14 +760,16 @@ int DoProcessReply(SSL& ssl) if (read == static_cast(-1)) { ssl.SetError(receive_error); return 0; - } + } else if (read == 0) + return 1; + buffer.add_size(read); uint offset = 0; const MessageFactory& mf = ssl.getFactory().getMessage(); // old style sslv2 client hello? if (ssl.getSecurity().get_parms().entity_ == server_end && - ssl.getStates().getServer() == clientNull) + ssl.getStates().getServer() == clientNull) if (buffer.peek() != handshake) { ProcessOldClientHello(buffer, ssl); if (ssl.GetError()) @@ -814,7 +816,7 @@ int DoProcessReply(SSL& ssl) if (ssl.GetError()) return 0; } - + mySTL::auto_ptr msg(mf.CreateObject(hdr.type_)); if (!msg.get()) { ssl.SetError(factory_error); @@ -835,7 +837,7 @@ int DoProcessReply(SSL& ssl) void processReply(SSL& ssl) { if (ssl.GetError()) return; - + if (DoProcessReply(ssl)) { // didn't complete process if (!ssl.getSocket().IsNonBlocking()) { @@ -934,7 +936,7 @@ void sendChangeCipher(SSL& ssl, BufferOutput buffer) buildHeader(ssl, rlHeader, ccs); mySTL::auto_ptr out(NEW_YS output_buffer); buildOutput(*out.get(), rlHeader, ccs); - + if (buffer == buffered) ssl.addBuffer(out.release()); else @@ -961,7 +963,7 @@ void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer) GetSessions().add(ssl); // store session if (side == client_end) buildFinished(ssl, ssl.useHashes().use_verify(), server); // server - } + } ssl.useSecurity().use_connection().CleanMaster(); if (buffer == buffered) @@ -1063,7 +1065,7 @@ int receiveData(SSL& ssl, Data& data, bool peek) ssl.SetError(YasslError(SSL_ERROR_WANT_READ)); return SSL_WOULD_BLOCK; } - return data.get_length(); + return data.get_length(); } @@ -1168,6 +1170,8 @@ void sendCertificateVerify(SSL& ssl, BufferOutput buffer) CertificateVerify verify; verify.Build(ssl); + if (ssl.GetError()) return; + RecordLayerHeader rlHeader; HandShakeHeader hsHeader; mySTL::auto_ptr out(NEW_YS output_buffer); diff --git a/cdk/extra/yassl/src/lock.cpp b/cdk/extra/yassl/src/lock.cpp index c74ea1c6b..1ba2450e0 100644 --- a/cdk/extra/yassl/src/lock.cpp +++ b/cdk/extra/yassl/src/lock.cpp @@ -28,7 +28,7 @@ namespace yaSSL { #ifdef MULTI_THREADED #ifdef _WIN32 - + Mutex::Mutex() { InitializeCriticalSection(&cs_); @@ -40,20 +40,20 @@ namespace yaSSL { DeleteCriticalSection(&cs_); } - + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) { - EnterCriticalSection(&mutex_.cs_); + EnterCriticalSection(&mutex_.cs_); } Mutex::Lock::~Lock() { - LeaveCriticalSection(&mutex_.cs_); + LeaveCriticalSection(&mutex_.cs_); } - + #else // _WIN32 - + Mutex::Mutex() { pthread_mutex_init(&mutex_, 0); @@ -68,15 +68,15 @@ namespace yaSSL { Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) { - pthread_mutex_lock(&mutex_.mutex_); + pthread_mutex_lock(&mutex_.mutex_); } Mutex::Lock::~Lock() { - pthread_mutex_unlock(&mutex_.mutex_); + pthread_mutex_unlock(&mutex_.mutex_); } - + #endif // _WIN32 #endif // MULTI_THREADED diff --git a/cdk/extra/yassl/src/log.cpp b/cdk/extra/yassl/src/log.cpp index c6cb8e6e4..5f034f96c 100644 --- a/cdk/extra/yassl/src/log.cpp +++ b/cdk/extra/yassl/src/log.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -60,6 +60,7 @@ namespace yaSSL { time_t clicks = time(0); char timeStr[32]; + memset(timeStr, 0, sizeof(timeStr)); // get rid of newline strncpy(timeStr, ctime(&clicks), sizeof(timeStr)); unsigned int len = strlen(timeStr); @@ -93,7 +94,7 @@ namespace yaSSL { const char* p = reinterpret_cast(&peeraddr.sin_addr); char msg[MAX_MSG]; char number[16]; - + if (ended) strncpy(msg, "yaSSL conn DONE w/ peer ", 26); else @@ -120,7 +121,7 @@ namespace yaSSL { char number[16]; if (sent) - strncpy(msg, "Sent ", 10); + strncpy(msg, "Sent ", 10); else strncpy(msg, "Received ", 10); sprintf(number, "%u", bytes); diff --git a/cdk/extra/yassl/src/socket_wrapper.cpp b/cdk/extra/yassl/src/socket_wrapper.cpp index a23c1c12e..19e2479c0 100644 --- a/cdk/extra/yassl/src/socket_wrapper.cpp +++ b/cdk/extra/yassl/src/socket_wrapper.cpp @@ -17,8 +17,8 @@ */ -/* The socket wrapper source implements a Socket class that hides the - * differences between Berkely style sockets and Windows sockets, allowing +/* The socket wrapper source implements a Socket class that hides the + * differences between Berkely style sockets and Windows sockets, allowing * transparent TCP access. */ @@ -75,7 +75,7 @@ extern "C" long system_send(void *ptr, const void *buf, size_t count) namespace yaSSL { -Socket::Socket(socket_t s) +Socket::Socket(socket_t s) : socket_(s), wouldBlock_(false), nonBlocking_(false), ptr_(&socket_), send_func_(system_send), recv_func_(system_recv) {} @@ -159,10 +159,10 @@ uint Socket::send(const byte* buf, unsigned int sz, unsigned int& written) while (pos != end) { int sent = send_func_(ptr_, pos, static_cast(end - pos)); if (sent == -1) { - if (get_lastError() == SOCKET_EWOULDBLOCK || + if (get_lastError() == SOCKET_EWOULDBLOCK || get_lastError() == SOCKET_EAGAIN) { wouldBlock_ = true; // would have blocked this time only - nonBlocking_ = true; // nonblocking, win32 only way to tell + nonBlocking_ = true; // nonblocking, win32 only way to tell return 0; } return static_cast(-1); @@ -183,7 +183,7 @@ uint Socket::receive(byte* buf, unsigned int sz) // idea to seperate error from would block by arnetheduck@gmail.com if (recvd == -1) { - if (get_lastError() == SOCKET_EWOULDBLOCK || + if (get_lastError() == SOCKET_EWOULDBLOCK || get_lastError() == SOCKET_EAGAIN) { wouldBlock_ = true; // would have blocked this time only nonBlocking_ = true; // socket nonblocking, win32 only way to tell diff --git a/cdk/extra/yassl/src/ssl.cpp b/cdk/extra/yassl/src/ssl.cpp index 56b6c31fd..fef2d3cdd 100644 --- a/cdk/extra/yassl/src/ssl.cpp +++ b/cdk/extra/yassl/src/ssl.cpp @@ -161,7 +161,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) TaoCrypt::DSA_PrivateKey dsaKey; dsaKey.Initialize(dsaSource); - if (rsaSource.GetError().What()) { + if (dsaSource.GetError().What()) { // neither worked ret = SSL_FAILURE; } @@ -598,8 +598,14 @@ const char* SSL_get_version(SSL* ssl) { static const char* version3 = "SSLv3"; static const char* version31 = "TLSv1"; + static const char* version32 = "TLSv1.1"; - return ssl->isTLS() ? version31 : version3; + if (ssl->isTLSv1_1()) + return version32; + else if(ssl->isTLS()) + return version31; + else + return version3; } const char* SSLeay_version(int) @@ -639,7 +645,9 @@ X509* X509_Copy(X509 *x) X509 *newX509 = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), - before, after); + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); return newX509; } @@ -707,7 +715,10 @@ X509* PEM_read_X509(FILE *fp, X509 *x, afterDate.length = strlen((char *) afterDate.data) + 1; X509 *thisX509 = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength()); + ysDelete(ptr); return thisX509; @@ -827,7 +838,6 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, const char* path) { int ret = SSL_FAILURE; - const int HALF_PATH = 128; if (file) ret = read_file(ctx, file, SSL_FILETYPE_PEM, CA); @@ -838,40 +848,67 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, WIN32_FIND_DATA FindFileData; HANDLE hFind; - char name[MAX_PATH + 1]; // directory specification - strncpy(name, path, MAX_PATH - 3); - strncat(name, "\\*", 3); + const int DELIMITER_SZ = 2; + const int DELIMITER_STAR_SZ = 3; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_STAR_SZ + 1; // plus 1 for terminator + char* name = NEW_YS char[nameSz]; // directory specification + memset(name, 0, nameSz); + strncpy(name, path, nameSz - DELIMITER_STAR_SZ - 1); + strncat(name, "\\*", DELIMITER_STAR_SZ); hFind = FindFirstFile(name, &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) return SSL_BAD_PATH; + if (hFind == INVALID_HANDLE_VALUE) { + ysArrayDelete(name); + return SSL_BAD_PATH; + } do { - if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) { - strncpy(name, path, MAX_PATH - 2 - HALF_PATH); - strncat(name, "\\", 2); - strncat(name, FindFileData.cFileName, HALF_PATH); + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + int curSz = (int)strlen(FindFileData.cFileName); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + // plus 1 for terminator + nameSz = pathSz + curSz + DELIMITER_SZ + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - DELIMITER_SZ - 1); + strncat(name, "\\", DELIMITER_SZ); + strncat(name, FindFileData.cFileName, + nameSz - pathSz - DELIMITER_SZ - 1); ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } } while (ret == SSL_SUCCESS && FindNextFile(hFind, &FindFileData)); + ysArrayDelete(name); FindClose(hFind); #else // _WIN32 - - const int MAX_PATH = 260; - DIR* dir = opendir(path); if (!dir) return SSL_BAD_PATH; struct dirent* entry; struct stat buf; - char name[MAX_PATH + 1]; + const int DELIMITER_SZ = 1; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_SZ + 1; //plus 1 for null terminator + char* name = NEW_YS char[nameSz]; // directory specification while (ret == SSL_SUCCESS && (entry = readdir(dir))) { - strncpy(name, path, MAX_PATH - 1 - HALF_PATH); - strncat(name, "/", 1); - strncat(name, entry->d_name, HALF_PATH); + int curSz = (int)strlen(entry->d_name); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + nameSz = pathSz + DELIMITER_SZ + curSz + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - 1); + strncat(name, "/", DELIMITER_SZ); + strncat(name, entry->d_name, nameSz - pathSz - DELIMITER_SZ - 1); + if (stat(name, &buf) < 0) { + ysArrayDelete(name); closedir(dir); return SSL_BAD_STAT; } @@ -880,6 +917,7 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } + ysArrayDelete(name); closedir(dir); #endif @@ -1015,9 +1053,43 @@ int SSL_get_verify_depth(SSL* ssl) } -long SSL_CTX_set_options(SSL_CTX*, long) +long SSL_CTX_set_options(SSL_CTX* ctx, long options) { - // TDOD: + ProtocolVersion pv= ctx->getMethod()->getVersion(); + bool multi_proto= ctx->getMethod()->multipleProtocol(); + unsigned long ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1; + + do + { + if (options == 0) + break; + // only TLSv1.1 + if ((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= false; + break; + } + // only TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 1; + multi_proto= false; + break; + } + // TLSv1.1 and TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= true; + break; + } + }while(0); + + SSL_METHOD *meth= NEW_YS SSL_METHOD(ctx->getMethod()->getSide(), ProtocolVersion(3,pv.minor_), multi_proto); + ctx->SetMethod(meth); return SSL_SUCCESS; } @@ -1404,16 +1476,14 @@ int ASN1_STRING_type(ASN1_STRING *x) int X509_NAME_get_index_by_NID(X509_NAME* name,int nid, int lastpos) { int idx = -1; // not found - const char* start = &name->GetName()[lastpos + 1]; + int cnPos = -1; switch (nid) { case NID_commonName: - const char* found = strstr(start, "/CN="); - if (found) { - found += 4; // advance to str - idx = found - start + lastpos + 1; - } - break; + cnPos = name->GetCnPosition(); + if (lastpos < cnPos) + idx = cnPos; + break; } return idx; @@ -1566,7 +1636,7 @@ unsigned long err_helper(bool peek = false) return CERTFICATE_ERROR; break; default : - return ysError; + return 0; } return 0; // shut up compiler diff --git a/cdk/extra/yassl/src/timer.cpp b/cdk/extra/yassl/src/timer.cpp index a1b9063e1..a8e1a4fa2 100644 --- a/cdk/extra/yassl/src/timer.cpp +++ b/cdk/extra/yassl/src/timer.cpp @@ -37,7 +37,7 @@ namespace yaSSL { { static bool init(false); static LARGE_INTEGER freq; - + if (!init) { QueryPerformanceFrequency(&freq); init = true; @@ -62,7 +62,7 @@ namespace yaSSL { struct timeval tv; gettimeofday(&tv, 0); - return static_cast(tv.tv_sec) + return static_cast(tv.tv_sec) + static_cast(tv.tv_usec) / 1000000; } @@ -72,7 +72,7 @@ namespace yaSSL { struct timeval tv; gettimeofday(&tv, 0); - return tv.tv_sec; + return tv.tv_sec; } diff --git a/cdk/extra/yassl/src/yassl_error.cpp b/cdk/extra/yassl/src/yassl_error.cpp index e5d693673..0b3f9362a 100644 --- a/cdk/extra/yassl/src/yassl_error.cpp +++ b/cdk/extra/yassl/src/yassl_error.cpp @@ -35,8 +35,8 @@ namespace yaSSL { /* may bring back in future -Error::Error(const char* s, YasslError e, Library l) - : mySTL::runtime_error(s), error_(e), lib_(l) +Error::Error(const char* s, YasslError e, Library l) + : mySTL::runtime_error(s), error_(e), lib_(l) { } @@ -59,66 +59,66 @@ void SetErrorString(YasslError error, char* buffer) { using namespace TaoCrypt; const int max = MAX_ERROR_SZ; // shorthand - int localError = error; // errors from a few enums + int localError = error; // errors from a few enums switch (localError) { // yaSSL proper errors case range_error : strncpy(buffer, "buffer index error, out of range", max); - break; + break; case realloc_error : strncpy(buffer, "trying to realloc a fixed buffer", max); - break; + break; - case factory_error : + case factory_error : strncpy(buffer, "unknown factory create request", max); - break; + break; case unknown_cipher : strncpy(buffer, "trying to use an unknown cipher", max); - break; + break; - case prefix_error : + case prefix_error : strncpy(buffer, "bad master secret derivation, prefix too big", max); - break; + break; - case record_layer : + case record_layer : strncpy(buffer, "record layer not ready yet", max); - break; - + break; + case handshake_layer : strncpy(buffer, "handshake layer not ready yet", max); - break; + break; case out_of_order : strncpy(buffer, "handshake message received in wrong order", max); - break; + break; - case bad_input : + case bad_input : strncpy(buffer, "bad cipher suite input", max); - break; + break; case match_error : strncpy(buffer, "unable to match a supported cipher suite", max); - break; + break; - case no_key_file : + case no_key_file : strncpy(buffer, "the server needs a private key file", max); - break; + break; case verify_error : strncpy(buffer, "unable to verify peer checksum", max); - break; + break; case send_error : strncpy(buffer, "socket layer send error", max); - break; + break; case receive_error : strncpy(buffer, "socket layer receive error", max); - break; + break; case certificate_error : strncpy(buffer, "unable to proccess cerificate", max); @@ -148,6 +148,10 @@ void SetErrorString(YasslError error, char* buffer) strncpy(buffer, "sanity check on cipher text size error", max); break; + case rsaSignFault_error: + strncpy(buffer, "rsa signature fault error", max); + break; + // openssl errors case SSL_ERROR_WANT_READ : strncpy(buffer, "the read operation would block", max); diff --git a/cdk/extra/yassl/src/yassl_imp.cpp b/cdk/extra/yassl/src/yassl_imp.cpp index 867811dbb..2802c52cb 100644 --- a/cdk/extra/yassl/src/yassl_imp.cpp +++ b/cdk/extra/yassl/src/yassl_imp.cpp @@ -47,8 +47,8 @@ bool isTLS(ProtocolVersion pv) void hashHandShake(SSL&, const input_buffer&, uint); -ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) - : major_(maj), minor_(min) +ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) + : major_(maj), minor_(min) {} @@ -109,15 +109,12 @@ void ClientDiffieHellmanPublic::build(SSL& ssl) uint keyLength = dhClient.get_agreedKeyLength(); // pub and agree same alloc(keyLength, true); - dhClient.makeAgreement(dhServer.get_publicKey(), keyLength); + dhClient.makeAgreement(dhServer.get_publicKey(), + dhServer.get_publicKeyLength()); c16toa(keyLength, Yc_); memcpy(Yc_ + KEY_OFFSET, dhClient.get_publicKey(), keyLength); - // because of encoding first byte might be zero, don't use it for preMaster - if (*dhClient.get_agreedKey() == 0) - ssl.set_preMaster(dhClient.get_agreedKey() + 1, keyLength - 1); - else - ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); + ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); } @@ -134,7 +131,7 @@ void DH_Server::build(SSL& ssl) short sigSz = 0; mySTL::auto_ptr auth; const CertManager& cert = ssl.getCrypto().get_certManager(); - + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { if (cert.get_keyType() != rsa_sa_algo) { ssl.SetError(privateKey_error); @@ -152,7 +149,7 @@ void DH_Server::build(SSL& ssl) cert.get_privateKeyLength(), false)); sigSz += DSS_ENCODED_EXTRA; } - + sigSz += auth->get_signatureLength(); if (!sigSz) { ssl.SetError(privateKey_error); @@ -196,9 +193,16 @@ void DH_Server::build(SSL& ssl) sha.update(tmp.get_buffer(), tmp.get_size()); sha.get_digest(&hash[MD5_LEN]); - if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { auth->sign(signature_, hash, sizeof(hash), ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!auth->verify(hash, sizeof(hash), signature_, + auth->get_signatureLength())) { + ssl.SetError(rsaSignFault_error); + return; + } + } else { auth->sign(signature_, &hash[MD5_LEN], SHA_LEN, ssl.getCrypto().get_random()); @@ -243,7 +247,7 @@ void EncryptedPreMasterSecret::read(SSL& ssl, input_buffer& input) opaque preMasterSecret[SECRET_LEN]; memset(preMasterSecret, 0, sizeof(preMasterSecret)); - rsa.decrypt(preMasterSecret, secret_, length_, + rsa.decrypt(preMasterSecret, secret_, length_, ssl.getCrypto().get_random()); ProtocolVersion pv = ssl.getSecurity().get_connection().chVersion_; @@ -312,13 +316,9 @@ void ClientDiffieHellmanPublic::read(SSL& ssl, input_buffer& input) ssl.SetError(bad_input); return; } - dh.makeAgreement(Yc_, keyLength); + dh.makeAgreement(Yc_, keyLength); - // because of encoding, first byte might be 0, don't use for preMaster - if (*dh.get_agreedKey() == 0) - ssl.set_preMaster(dh.get_agreedKey() + 1, dh.get_agreedKeyLength() - 1); - else - ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); + ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); ssl.makeMasterSecret(); } @@ -346,9 +346,9 @@ opaque* ClientDiffieHellmanPublic::get_clientKey() const } -void ClientDiffieHellmanPublic::alloc(int sz, bool offset) +void ClientDiffieHellmanPublic::alloc(int sz, bool offset) { - length_ = sz + (offset ? KEY_OFFSET : 0); + length_ = sz + (offset ? KEY_OFFSET : 0); Yc_ = NEW_YS opaque[length_]; } @@ -444,7 +444,7 @@ void DH_Server::read(SSL& ssl, input_buffer& input) sha.get_digest(&hash[MD5_LEN]); const CertManager& cert = ssl.getCrypto().get_certManager(); - + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); if (!rsa.verify(hash, sizeof(hash), signature_, length)) @@ -453,7 +453,7 @@ void DH_Server::read(SSL& ssl, input_buffer& input) else { byte decodedSig[DSS_SIG_SZ]; length = TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, length); - + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); if (!dss.verify(&hash[MD5_LEN], SHA_LEN, decodedSig, length)) ssl.SetError(verify_error); @@ -492,7 +492,7 @@ opaque* DH_Server::get_serverKey() const // set available suites -Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, +Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, ProtocolVersion pv, bool haveDH) : entity_(ce) { pending_ = true; // suite not set yet @@ -505,7 +505,7 @@ Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, memcpy(suites_, ciphers.suites_, ciphers.suiteSz_); SetCipherNames(); } - else + else SetSuites(pv, ce == server_end && removeDH_); // defaults } @@ -576,7 +576,7 @@ void Parameters::SetSuites(ProtocolVersion pv, bool removeDH, bool removeRSA, if (!removeRSA) { suites_[i++] = 0x00; - suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; + suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; suites_[i++] = 0x00; suites_[i++] = SSL_RSA_WITH_RC4_128_MD5; @@ -647,7 +647,7 @@ output_buffer& operator<<(output_buffer& output, const RecordLayerHeader& hdr) output[AUTO] = hdr.type_; output[AUTO] = hdr.version_.major_; output[AUTO] = hdr.version_.minor_; - + // length byte tmp[2]; c16toa(hdr.length_, tmp); @@ -679,7 +679,7 @@ input_buffer& operator>>(input_buffer& input, HandShakeHeader& hs) hs.length_[0] = input[AUTO]; hs.length_[1] = input[AUTO]; hs.length_[2] = input[AUTO]; - + return input; } @@ -789,14 +789,14 @@ input_buffer& HandShakeBase::set(input_buffer& in) return in; } - + output_buffer& HandShakeBase::get(output_buffer& out) const { return out; } -void HandShakeBase::Process(input_buffer&, SSL&) +void HandShakeBase::Process(input_buffer&, SSL&) {} @@ -826,7 +826,7 @@ HandShakeType HelloRequest::get_type() const input_buffer& operator>>(input_buffer& input, ChangeCipherSpec& cs) { cs.type_ = CipherChoice(input[AUTO]); - return input; + return input; } // output operator for CipherSpec @@ -837,7 +837,7 @@ output_buffer& operator<<(output_buffer& output, const ChangeCipherSpec& cs) } -ChangeCipherSpec::ChangeCipherSpec() +ChangeCipherSpec::ChangeCipherSpec() : type_(change_cipher_spec_choice) {} @@ -924,7 +924,7 @@ input_buffer& operator>>(input_buffer& input, Alert& a) { a.level_ = AlertLevel(input[AUTO]); a.description_ = AlertDescription(input[AUTO]); - + return input; } @@ -969,7 +969,7 @@ void Alert::Process(input_buffer& input, SSL& ssl) ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - aSz - digestSz; - for (int i = 0; i < padSz; i++) + for (int i = 0; i < padSz; i++) fill = input[AUTO]; } @@ -1052,7 +1052,7 @@ output_buffer& operator<<(output_buffer& output, const Data& data) } -// check all bytes for equality +// check all bytes for equality static int constant_compare(const byte* a, const byte* b, int len) { int good = 0; @@ -1095,7 +1095,7 @@ static int pad_check(const byte* input, byte pad, int len) // get number of compression rounds static inline int get_rounds(int pLen, int padLen, int t) { - int roundL1 = 1; // round ups + int roundL1 = 1; // round ups int roundL2 = 1; int L1 = COMPRESS_CONSTANT + pLen - t; @@ -1126,7 +1126,7 @@ static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) Digest* digest = NULL; MACAlgorithm ma = ssl.getSecurity().get_parms().mac_algorithm_; - if (ma == sha) + if (ma == sha) digest = NEW_YS SHA; else if (ma == md5) digest = NEW_YS MD5; @@ -1138,7 +1138,7 @@ static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) for (int i = 0; i < rounds; i++) digest->update(dummy, COMPRESS_LOWER); - ysDelete(digest); + ysDelete(digest); } } @@ -1217,16 +1217,16 @@ void Data::Process(input_buffer& input, SSL& ssl) } } else { // SSLv3, some don't do this padding right - int sz3 = msgSz - digestSz - pad - 1; + int sz3 = msgSz - digestSz - pad - 1; hmac(ssl, verify, rawData, sz3, application_data, true); if (constant_compare(verify, rawData + sz3, digestSz) != 0) { ssl.SetError(verify_error); return; } - } + } } else { // stream - int streamSz = msgSz - digestSz; + int streamSz = msgSz - digestSz; if (ssl.isTLS()) TLS_hmac(ssl, verify, rawData, streamSz, application_data, true); else @@ -1286,7 +1286,7 @@ output_buffer& operator<<(output_buffer& output, const HandShakeBase& hs) } -Certificate::Certificate(const x509* cert) : cert_(cert) +Certificate::Certificate(const x509* cert) : cert_(cert) { if (cert) set_length(cert_->get_length() + 2 * CERT_HEADER); // list and cert size @@ -1339,7 +1339,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) } CertManager& cm = ssl.useCrypto().use_certManager(); - + uint32 list_sz; byte tmp[3]; @@ -1356,7 +1356,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) ssl.SetError(YasslError(bad_input)); return; } - + while (list_sz) { // cert size uint32 cert_sz; @@ -1369,7 +1369,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) tmp[1] = input[AUTO]; tmp[2] = input[AUTO]; c24to32(tmp, cert_sz); - + if (cert_sz > (uint)MAX_RECORD_SIZE || input.get_remaining() < cert_sz){ ssl.SetError(YasslError(bad_input)); return; @@ -1496,27 +1496,27 @@ opaque* ServerKeyBase::get_serverKey() const // input operator for ServerHello input_buffer& operator>>(input_buffer& input, ServerHello& hello) -{ +{ // Protocol hello.server_version_.major_ = input[AUTO]; hello.server_version_.minor_ = input[AUTO]; - + // Random input.read(hello.random_, RAN_LEN); - + // Session hello.id_len_ = input[AUTO]; if (hello.id_len_ > ID_LEN) { - input.set_error(); + input.set_error(); return input; } if (hello.id_len_) input.read(hello.session_id_, hello.id_len_); - + // Suites hello.cipher_suite_[0] = input[AUTO]; hello.cipher_suite_[1] = input[AUTO]; - + // Compression hello.compression_method_ = CompressionMethod(input[AUTO]); @@ -1711,7 +1711,7 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // Session hello.id_len_ = input[AUTO]; if (hello.id_len_) input.read(hello.session_id_, ID_LEN); - + // Suites byte tmp[2]; uint16 len; @@ -1746,7 +1746,7 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // output operaotr for Client Hello output_buffer& operator<<(output_buffer& output, const ClientHello& hello) -{ +{ // Protocol output[AUTO] = hello.client_version_.major_; output[AUTO] = hello.client_version_.minor_; @@ -1764,7 +1764,7 @@ output_buffer& operator<<(output_buffer& output, const ClientHello& hello) output[AUTO] = tmp[0]; output[AUTO] = tmp[1]; output.write(hello.cipher_suites_, hello.suite_len_); - + // Compression output[AUTO] = hello.comp_len_; output[AUTO] = hello.compression_methods_; @@ -1792,18 +1792,18 @@ void ClientHello::Process(input_buffer& input, SSL& ssl) if (ssl.isTLS() && client_version_.minor_ < 1) { // downgrade to SSLv3 ssl.useSecurity().use_connection().TurnOffTLS(); - + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; bool removeDH = ssl.getSecurity().get_parms().removeDH_; bool removeRSA = false; bool removeDSA = false; - + const CertManager& cm = ssl.getCrypto().get_certManager(); if (cm.get_keyType() == rsa_sa_algo) removeDSA = true; else removeRSA = true; - + // reset w/ SSL suites ssl.useSecurity().use_parms().SetSuites(pv, removeDH, removeRSA, removeDSA); @@ -1945,9 +1945,9 @@ ServerKeyExchange::~ServerKeyExchange() } -void ServerKeyExchange::build(SSL& ssl) -{ - server_key_->build(ssl); +void ServerKeyExchange::build(SSL& ssl) +{ + server_key_->build(ssl); set_length(server_key_->get_length()); } @@ -1982,7 +1982,7 @@ HandShakeType ServerKeyExchange::get_type() const } -// CertificateRequest +// CertificateRequest CertificateRequest::CertificateRequest() : typeTotal_(0) { @@ -2008,7 +2008,7 @@ void CertificateRequest::Build() uint16 authCount = 0; uint16 authSz = 0; - + for (int j = 0; j < authCount; j++) { int sz = REQUEST_HEADER + MIN_DIS_SIZE; DistinguishedName dn; @@ -2017,7 +2017,7 @@ void CertificateRequest::Build() opaque tmp[REQUEST_HEADER]; c16toa(MIN_DIS_SIZE, tmp); memcpy(dn, tmp, sizeof(tmp)); - + // fill w/ junk for now memcpy(dn, tmp, MIN_DIS_SIZE); authSz += sz; @@ -2063,7 +2063,7 @@ input_buffer& operator>>(input_buffer& input, CertificateRequest& request) tmp[0] = input[AUTO]; tmp[1] = input[AUTO]; ato16(tmp, dnSz); - + input.set_current(input.get_current() + dnSz); sz -= dnSz + REQUEST_HEADER; @@ -2128,7 +2128,7 @@ HandShakeType CertificateRequest::get_type() const } -// CertificateVerify +// CertificateVerify CertificateVerify::CertificateVerify() : signature_(0) {} @@ -2159,6 +2159,12 @@ void CertificateVerify::Build(SSL& ssl) memcpy(sig.get(), len, VERIFY_HEADER); rsa.sign(sig.get() + VERIFY_HEADER, hashes_.md5_, sizeof(Hashes), ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!rsa.verify(hashes_.md5_, sizeof(Hashes), sig.get() + VERIFY_HEADER, + rsa.get_cipherLength())) { + ssl.SetError(rsaSignFault_error); + return; + } } else { // DSA DSS dss(cert.get_privateKey(), cert.get_privateKeyLength(), false); @@ -2246,7 +2252,7 @@ void CertificateVerify::Process(input_buffer& input, SSL& ssl) else { // DSA byte decodedSig[DSS_SIG_SZ]; TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, get_length()); - + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); if (!dss.verify(hashVerify.sha_, SHA_LEN, decodedSig, get_length())) ssl.SetError(verify_error); @@ -2307,9 +2313,9 @@ ClientKeyExchange::~ClientKeyExchange() } -void ClientKeyExchange::build(SSL& ssl) -{ - client_key_->build(ssl); +void ClientKeyExchange::build(SSL& ssl) +{ + client_key_->build(ssl); set_length(client_key_->get_length()); } @@ -2348,7 +2354,7 @@ input_buffer& operator>>(input_buffer& input, Finished&) { /* do in process */ - return input; + return input; } // output operator for Finished @@ -2375,7 +2381,7 @@ void Finished::Process(input_buffer& input, SSL& ssl) // verify hashes const Finished& verify = ssl.getHashes().get_verify(); uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; - + input.read(hashes_.md5_, finishedSz); if (input.get_error()) { ssl.SetError(bad_input); @@ -2415,7 +2421,7 @@ void Finished::Process(input_buffer& input, SSL& ssl) opaque fill; int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - HANDSHAKE_HEADER - finishedSz - digestSz; - for (int i = 0; i < padSz; i++) + for (int i = 0; i < padSz; i++) fill = input[AUTO]; if (input.get_error()) { ssl.SetError(bad_input); @@ -2499,14 +2505,14 @@ Connection::Connection(ProtocolVersion v, RandomPool& ran) } -Connection::~Connection() -{ +Connection::~Connection() +{ CleanMaster(); CleanPreMaster(); ysArrayDelete(pre_master_secret_); } -void Connection::AllocPreSecret(uint sz) -{ +void Connection::AllocPreSecret(uint sz) +{ pre_master_secret_ = NEW_YS opaque[pre_secret_len_ = sz]; } @@ -2561,7 +2567,7 @@ HandShakeBase* CreateClientHello() { return NEW_YS ClientHello; } HandShakeBase* CreateServerHello() { return NEW_YS ServerHello; } HandShakeBase* CreateCertificate() { return NEW_YS Certificate; } HandShakeBase* CreateServerKeyExchange() { return NEW_YS ServerKeyExchange;} -HandShakeBase* CreateCertificateRequest() { return NEW_YS +HandShakeBase* CreateCertificateRequest() { return NEW_YS CertificateRequest; } HandShakeBase* CreateServerHelloDone() { return NEW_YS ServerHelloDone; } HandShakeBase* CreateCertificateVerify() { return NEW_YS CertificateVerify;} @@ -2574,9 +2580,9 @@ ServerKeyBase* CreateDHServerKEA() { return NEW_YS DH_Server; } ServerKeyBase* CreateFortezzaServerKEA() { return NEW_YS Fortezza_Server; } // Create functions for client key exchange factory -ClientKeyBase* CreateRSAClient() { return NEW_YS +ClientKeyBase* CreateRSAClient() { return NEW_YS EncryptedPreMasterSecret; } -ClientKeyBase* CreateDHClient() { return NEW_YS +ClientKeyBase* CreateDHClient() { return NEW_YS ClientDiffieHellmanPublic; } ClientKeyBase* CreateFortezzaClient() { return NEW_YS FortezzaKeys; } diff --git a/cdk/extra/yassl/src/yassl_int.cpp b/cdk/extra/yassl/src/yassl_int.cpp index ea321ead9..62334d1be 100644 --- a/cdk/extra/yassl/src/yassl_int.cpp +++ b/cdk/extra/yassl/src/yassl_int.cpp @@ -857,6 +857,19 @@ void SSL::set_random(const opaque* random, ConnectionEnd sender) // store client pre master secret void SSL::set_preMaster(const opaque* pre, uint sz) { + uint i(0); // trim leading zeros + uint fullSz(sz); + + while (i++ < fullSz && *pre == 0) { + sz--; + pre++; + } + + if (sz == 0) { + SetError(bad_input); + return; + } + secure_.use_connection().AllocPreSecret(sz); memcpy(secure_.use_connection().pre_master_secret_, pre, sz); } @@ -974,6 +987,8 @@ void SSL::order_error() // Create and store the master secret see page 32, 6.1 void SSL::makeMasterSecret() { + if (GetError()) return; + if (isTLS()) makeTLSMasterSecret(); else { @@ -1590,7 +1605,9 @@ void SSL_SESSION::CopyX509(X509* x) peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), - before, after); + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); } @@ -2123,6 +2140,14 @@ void SSL_CTX::SetSessionCacheOff() } +void SSL_CTX::SetMethod(SSL_METHOD* meth) +{ + if(method_) + ysDelete(method_); + method_= meth; +} + + void SSL_CTX::SetSessionCacheFlushOff() { sessionCacheFlushOff_ = true; @@ -2219,7 +2244,7 @@ void SSL_CTX::IncrementStats(StatsField fd) switch (fd) { - case Accept: + case Accept: ++stats_.accept_; break; @@ -2568,8 +2593,8 @@ void Security::set_resuming(bool b) } -X509_NAME::X509_NAME(const char* n, size_t sz) - : name_(0), sz_(sz) +X509_NAME::X509_NAME(const char* n, size_t sz, int pos, int len) + : name_(0), sz_(sz), cnPosition_(pos), cnLen_(len) { if (sz) { name_ = NEW_YS char[sz]; @@ -2599,8 +2624,10 @@ size_t X509_NAME::GetLength() const X509::X509(const char* i, size_t iSz, const char* s, size_t sSz, - ASN1_STRING *b, ASN1_STRING *a) - : issuer_(i, iSz), subject_(s, sSz), + ASN1_STRING *b, ASN1_STRING *a, + int issPos, int issLen, + int subPos, int subLen) + : issuer_(i, iSz, issPos, issLen), subject_(s, sSz, subPos, subLen), beforeDate_((char *) b->data, b->length, b->type), afterDate_((char *) a->data, a->length, a->type) {} @@ -2635,19 +2662,20 @@ ASN1_STRING* X509_NAME::GetEntry(int i) if (i < 0 || i >= int(sz_)) return 0; + if (i != cnPosition_ || cnLen_ <= 0) // only entry currently supported + return 0; + + if (cnLen_ > int(sz_-i)) // make sure there's room in read buffer + return 0; + if (entry_.data) ysArrayDelete(entry_.data); - entry_.data = NEW_YS byte[sz_]; // max size; + entry_.data = NEW_YS byte[cnLen_+1]; // max size; - memcpy(entry_.data, &name_[i], sz_ - i); - if (entry_.data[sz_ -i - 1]) { - entry_.data[sz_ - i] = 0; - entry_.length = int(sz_) - i; - } - else - entry_.length = int(sz_) - i - 1; + memcpy(entry_.data, &name_[i], cnLen_); + entry_.data[cnLen_] = 0; + entry_.length = cnLen_; entry_.type = 0; - return &entry_; } diff --git a/cdk/extra/yassl/taocrypt/include/aes.hpp b/cdk/extra/yassl/taocrypt/include/aes.hpp index 017630331..bccf6e73f 100644 --- a/cdk/extra/yassl/taocrypt/include/aes.hpp +++ b/cdk/extra/yassl/taocrypt/include/aes.hpp @@ -60,6 +60,7 @@ class AES : public Mode_BASE { static const word32 Te[5][256]; static const word32 Td[5][256]; + static const byte CTd4[256]; static const word32* Te0; static const word32* Te1; @@ -80,11 +81,68 @@ class AES : public Mode_BASE { void ProcessAndXorBlock(const byte*, const byte*, byte*) const; + word32 PreFetchTe() const; + word32 PreFetchTd() const; + word32 PreFetchCTd4() const; + AES(const AES&); // hide copy AES& operator=(const AES&); // and assign }; +#if defined(__x86_64__) || defined(_M_X64) || \ + (defined(__ILP32__) && (__ILP32__ >= 1)) + #define TC_CACHE_LINE_SZ 64 +#else + /* default cache line size */ + #define TC_CACHE_LINE_SZ 32 +#endif + +inline word32 AES::PreFetchTe() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Te[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchTd() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Td[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchCTd4() const +{ + word32 x = 0; + int i; + + for (i = 0; i < 256; i += TC_CACHE_LINE_SZ) { + x &= CTd4[i]; + } + + return x; +} + + typedef BlockCipher AES_ECB_Encryption; typedef BlockCipher AES_ECB_Decryption; diff --git a/cdk/extra/yassl/taocrypt/include/asn.hpp b/cdk/extra/yassl/taocrypt/include/asn.hpp index bc3eebe6b..e029001ba 100644 --- a/cdk/extra/yassl/taocrypt/include/asn.hpp +++ b/cdk/extra/yassl/taocrypt/include/asn.hpp @@ -16,7 +16,7 @@ MA 02110-1301 USA. */ -/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding +/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding */ @@ -109,7 +109,7 @@ enum Constants MIN_DATE_SZ = 13, MAX_DATE_SZ = 16, MAX_ALGO_SZ = 16, - MAX_LENGTH_SZ = 5, + MAX_LENGTH_SZ = 5, MAX_SEQ_SZ = 5, // enum(seq|con) + length(4) MAX_ALGO_SIZE = 9, MAX_DIGEST_SZ = 69, // SHA512 + enum(Bit or Octet) + length(4) @@ -269,7 +269,7 @@ enum KeyType { DSAk = 515, RSAk = 645 }; // sums of algo OID // an x509v Certificate BER Decoder class CertDecoder : public BER_Decoder { public: - enum DateType { BEFORE, AFTER }; + enum DateType { BEFORE, AFTER }; enum NameType { ISSUER, SUBJECT }; enum CertType { CA, USER }; @@ -286,7 +286,10 @@ class CertDecoder : public BER_Decoder { byte GetBeforeDateType() const { return beforeDateType_; } const char* GetAfterDate() const { return afterDate_; } byte GetAfterDateType() const { return afterDateType_; } - + int GetSubjectCnStart() const { return subCnPos_; } + int GetIssuerCnStart() const { return issCnPos_; } + int GetSubjectCnLength() const { return subCnLen_; } + int GetIssuerCnLength() const { return issCnLen_; } void DecodeToKey(); private: PublicKey key_; @@ -295,6 +298,10 @@ class CertDecoder : public BER_Decoder { word32 sigLength_; // length of signature word32 signatureOID_; // sum of algorithm object id word32 keyOID_; // sum of key algo object id + int subCnPos_; // subject common name start, -1 is none + int subCnLen_; // length of above + int issCnPos_; // issuer common name start, -1 is none + int issCnLen_; // length of above byte subjectHash_[SHA_SIZE]; // hash of all Names byte issuerHash_[SHA_SIZE]; // hash of all Names byte* signature_; diff --git a/cdk/extra/yassl/taocrypt/include/block.hpp b/cdk/extra/yassl/taocrypt/include/block.hpp index 4f58c82ff..8242891b0 100644 --- a/cdk/extra/yassl/taocrypt/include/block.hpp +++ b/cdk/extra/yassl/taocrypt/include/block.hpp @@ -125,7 +125,7 @@ class AllocatorWithCleanup : public AllocatorBase template > class Block { public: - explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) + explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) { CleanNew(sz_); } Block(const T* buff, word32 s) : sz_(s), buffer_(allocator_.allocate(sz_)) diff --git a/cdk/extra/yassl/taocrypt/include/des.hpp b/cdk/extra/yassl/taocrypt/include/des.hpp index d88e9ef2f..04d1439dd 100644 --- a/cdk/extra/yassl/taocrypt/include/des.hpp +++ b/cdk/extra/yassl/taocrypt/include/des.hpp @@ -48,10 +48,10 @@ class BasicDES { }; -// DES +// DES class DES : public Mode_BASE, public BasicDES { public: - DES(CipherDir DIR, Mode MODE) + DES(CipherDir DIR, Mode MODE) : Mode_BASE(DES_BLOCK_SIZE, DIR, MODE) {} private: @@ -65,7 +65,7 @@ class DES : public Mode_BASE, public BasicDES { // DES_EDE2 class DES_EDE2 : public Mode_BASE { public: - DES_EDE2(CipherDir DIR, Mode MODE) + DES_EDE2(CipherDir DIR, Mode MODE) : Mode_BASE(DES_BLOCK_SIZE, DIR, MODE) {} void SetKey(const byte*, word32, CipherDir dir); diff --git a/cdk/extra/yassl/taocrypt/include/dh.hpp b/cdk/extra/yassl/taocrypt/include/dh.hpp index bdb90ddae..93783f156 100644 --- a/cdk/extra/yassl/taocrypt/include/dh.hpp +++ b/cdk/extra/yassl/taocrypt/include/dh.hpp @@ -40,7 +40,7 @@ class DH { explicit DH(Source&); DH(const DH& that) : p_(that.p_), g_(that.g_) {} - DH& operator=(const DH& that) + DH& operator=(const DH& that) { DH tmp(that); Swap(tmp); @@ -77,7 +77,7 @@ class DH { Integer g_; void GeneratePrivate(RandomNumberGenerator&, byte*); - void GeneratePublic(const byte*, byte*); + void GeneratePublic(const byte*, byte*); }; diff --git a/cdk/extra/yassl/taocrypt/include/dsa.hpp b/cdk/extra/yassl/taocrypt/include/dsa.hpp index d7f81c274..05ae56843 100644 --- a/cdk/extra/yassl/taocrypt/include/dsa.hpp +++ b/cdk/extra/yassl/taocrypt/include/dsa.hpp @@ -43,7 +43,7 @@ class DSA_PublicKey { void Initialize(Source&); void Initialize(const Integer& p, const Integer& q, const Integer& g, const Integer& y); - + const Integer& GetModulus() const; const Integer& GetSubGroupOrder() const; const Integer& GetSubGroupGenerator() const; @@ -55,7 +55,7 @@ class DSA_PublicKey { void SetPublicPart(const Integer&); word32 SignatureLength() const; - + DSA_PublicKey(const DSA_PublicKey&); DSA_PublicKey& operator=(const DSA_PublicKey&); @@ -73,7 +73,7 @@ class DSA_PrivateKey : public DSA_PublicKey { void Initialize(Source&); void Initialize(const Integer& p, const Integer& q, const Integer& g, const Integer& y, const Integer& x); - + const Integer& GetPrivatePart() const; void SetPrivatePart(const Integer&); diff --git a/cdk/extra/yassl/taocrypt/include/error.hpp b/cdk/extra/yassl/taocrypt/include/error.hpp index cb2130d48..a6ab7c72e 100644 --- a/cdk/extra/yassl/taocrypt/include/error.hpp +++ b/cdk/extra/yassl/taocrypt/include/error.hpp @@ -68,7 +68,7 @@ SIG_OTHER_E = 1039, // "bad other signature confirmation" CONTENT_E = 1040, // "bad content processing" PEM_E = 1041 // "bad pem format error" - // add error string to yassl/src/yassl_error.cpp !!! + // add error string to yassl/src/yassl_error.cpp !!! }; diff --git a/cdk/extra/yassl/taocrypt/include/file.hpp b/cdk/extra/yassl/taocrypt/include/file.hpp index 9851a001a..a8d0375e8 100644 --- a/cdk/extra/yassl/taocrypt/include/file.hpp +++ b/cdk/extra/yassl/taocrypt/include/file.hpp @@ -40,13 +40,13 @@ class Source { Source(const byte* b, word32 sz) : buffer_(b, sz), current_(0) {} word32 remaining() { if (GetError().What()) return 0; - else return buffer_.size() - current_; } + else return buffer_.size() - current_; } word32 size() const { return buffer_.size(); } void grow(word32 sz) { buffer_.CleanGrow(sz); } bool IsLeft(word32 sz) { if (remaining() >= sz) return true; else { SetError(CONTENT_E); return false; } } - + const byte* get_buffer() const { return buffer_.get_buffer(); } const byte* get_current() const { return &buffer_[current_]; } word32 get_index() const { return current_; } @@ -82,7 +82,7 @@ class Source { return *this; } - void Swap(Source& other) + void Swap(Source& other) { buffer_.Swap(other.buffer_); STL::swap(current_, other.current_); @@ -97,11 +97,11 @@ class FileSource { public: FileSource(const char* fname, Source& source); ~FileSource(); - + word32 size(bool use_current = false); private: word32 get(Source&); - word32 size_left(); + word32 size_left(); FileSource(const FileSource&); // hide FileSource& operator=(const FileSource&); // hide diff --git a/cdk/extra/yassl/taocrypt/include/hash.hpp b/cdk/extra/yassl/taocrypt/include/hash.hpp index 4d2f7dd35..e1d57ed57 100644 --- a/cdk/extra/yassl/taocrypt/include/hash.hpp +++ b/cdk/extra/yassl/taocrypt/include/hash.hpp @@ -56,7 +56,7 @@ class HASHwithTransform : public HASH { word32 GetBitCountLo() const { return loLen_ << 3; } word32 GetBitCountHi() const { return (loLen_ >> (8*sizeof(loLen_) - 3)) + - (hiLen_ << 3); } + (hiLen_ << 3); } enum { MaxDigestSz = 8, MaxBufferSz = 64 }; protected: typedef word32 HashLengthType; @@ -87,7 +87,7 @@ class HASH64withTransform : public HASH { word32 GetBitCountLo() const { return loLen_ << 3; } word32 GetBitCountHi() const { return (loLen_ >> (8*sizeof(loLen_) - 3)) + - (hiLen_ << 3); } + (hiLen_ << 3); } enum { MaxDigestSz = 8, MaxBufferSz = 128 }; protected: typedef word32 HashLengthType; diff --git a/cdk/extra/yassl/taocrypt/include/hmac.hpp b/cdk/extra/yassl/taocrypt/include/hmac.hpp index 4df081b84..836710db3 100644 --- a/cdk/extra/yassl/taocrypt/include/hmac.hpp +++ b/cdk/extra/yassl/taocrypt/include/hmac.hpp @@ -34,11 +34,11 @@ class HMAC { public: enum { IPAD = 0x36, OPAD = 0x5C }; - HMAC() : ipad_(reinterpret_cast(&ip_)), + HMAC() : ipad_(reinterpret_cast(&ip_)), opad_(reinterpret_cast(&op_)), - innerHash_(reinterpret_cast(&innerH_)) - { - Init(); + innerHash_(reinterpret_cast(&innerH_)) + { + Init(); } void Update(const byte*, word32); void Final(byte*); diff --git a/cdk/extra/yassl/taocrypt/include/integer.hpp b/cdk/extra/yassl/taocrypt/include/integer.hpp index d21219ea1..dab238726 100644 --- a/cdk/extra/yassl/taocrypt/include/integer.hpp +++ b/cdk/extra/yassl/taocrypt/include/integer.hpp @@ -47,7 +47,7 @@ #ifdef TAOCRYPT_X86ASM_AVAILABLE #if defined(__GNUC__) && (__GNUC__ >= 4) - // GCC 4 or greater optimizes too much inline on recursive for bigint, + // GCC 4 or greater optimizes too much inline on recursive for bigint, // -O3 just as fast without asm here anyway #undef TAOCRYPT_X86ASM_AVAILABLE #endif @@ -118,6 +118,10 @@ namespace TaoCrypt { #endif + +#ifdef _WIN32 + #undef max // avoid name clash +#endif // general MAX template inline const T& max(const T& a, const T& b) @@ -147,7 +151,7 @@ class Integer { Signedness s = UNSIGNED); ~Integer() {} - + static const Integer& Zero(); static const Integer& One(); @@ -190,7 +194,7 @@ class Integer { Integer& operator+=(const Integer& t); Integer& operator-=(const Integer& t); Integer& operator*=(const Integer& t) { return *this = Times(t); } - Integer& operator/=(const Integer& t) + Integer& operator/=(const Integer& t) { return *this = DividedBy(t);} Integer& operator%=(const Integer& t) { return *this = Modulo(t); } Integer& operator/=(word t) { return *this = DividedBy(t); } @@ -198,7 +202,7 @@ class Integer { Integer& operator<<=(unsigned int); Integer& operator>>=(unsigned int); - + void Randomize(RandomNumberGenerator &rng, unsigned int bitcount); void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); @@ -206,7 +210,7 @@ class Integer { void SetBit(unsigned int n, bool value = 1); void SetByte(unsigned int n, byte value); - void Negate(); + void Negate(); void SetPositive() { sign_ = POSITIVE; } void SetNegative() { if (!!(*this)) sign_ = NEGATIVE; } void Swap(Integer& a); @@ -216,9 +220,9 @@ class Integer { Integer operator-() const; Integer& operator++(); Integer& operator--(); - Integer operator++(int) + Integer operator++(int) { Integer temp = *this; ++*this; return temp; } - Integer operator--(int) + Integer operator--(int) { Integer temp = *this; --*this; return temp; } int Compare(const Integer& a) const; @@ -277,28 +281,28 @@ class Integer { Sign sign_; }; -inline bool operator==(const Integer& a, const Integer& b) +inline bool operator==(const Integer& a, const Integer& b) {return a.Compare(b)==0;} -inline bool operator!=(const Integer& a, const Integer& b) +inline bool operator!=(const Integer& a, const Integer& b) {return a.Compare(b)!=0;} -inline bool operator> (const Integer& a, const Integer& b) +inline bool operator> (const Integer& a, const Integer& b) {return a.Compare(b)> 0;} -inline bool operator>=(const Integer& a, const Integer& b) +inline bool operator>=(const Integer& a, const Integer& b) {return a.Compare(b)>=0;} -inline bool operator< (const Integer& a, const Integer& b) +inline bool operator< (const Integer& a, const Integer& b) {return a.Compare(b)< 0;} -inline bool operator<=(const Integer& a, const Integer& b) +inline bool operator<=(const Integer& a, const Integer& b) {return a.Compare(b)<=0;} -inline Integer operator+(const Integer &a, const Integer &b) +inline Integer operator+(const Integer &a, const Integer &b) {return a.Plus(b);} -inline Integer operator-(const Integer &a, const Integer &b) +inline Integer operator-(const Integer &a, const Integer &b) {return a.Minus(b);} -inline Integer operator*(const Integer &a, const Integer &b) +inline Integer operator*(const Integer &a, const Integer &b) {return a.Times(b);} -inline Integer operator/(const Integer &a, const Integer &b) +inline Integer operator/(const Integer &a, const Integer &b) {return a.DividedBy(b);} -inline Integer operator%(const Integer &a, const Integer &b) +inline Integer operator%(const Integer &a, const Integer &b) {return a.Modulo(b);} inline Integer operator/(const Integer &a, word b) {return a.DividedBy(b);} inline word operator%(const Integer &a, word b) {return a.Modulo(b);} diff --git a/cdk/extra/yassl/taocrypt/include/md5.hpp b/cdk/extra/yassl/taocrypt/include/md5.hpp index fce37bd55..2529d4d57 100644 --- a/cdk/extra/yassl/taocrypt/include/md5.hpp +++ b/cdk/extra/yassl/taocrypt/include/md5.hpp @@ -37,7 +37,7 @@ class MD5 : public HASHwithTransform { public: enum { BLOCK_SIZE = 64, DIGEST_SIZE = 16, PAD_SIZE = 56, TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes - MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) + MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) { Init(); } ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); } word32 getBlockSize() const { return BLOCK_SIZE; } diff --git a/cdk/extra/yassl/taocrypt/include/misc.hpp b/cdk/extra/yassl/taocrypt/include/misc.hpp index 18f13e783..6f82ce117 100644 --- a/cdk/extra/yassl/taocrypt/include/misc.hpp +++ b/cdk/extra/yassl/taocrypt/include/misc.hpp @@ -105,21 +105,21 @@ void CleanUp(); #define NEW_TC new class virtual_base {}; - - + + #endif // YASSL_PURE_C #if defined(_MSC_VER) || defined(__BCPLUSPLUS__) - #define INTEL_INTRINSICS - #define FAST_ROTATE + #define INTEL_INTRINSICS + #define FAST_ROTATE #elif defined(__MWERKS__) && TARGET_CPU_PPC - #define PPC_INTRINSICS - #define FAST_ROTATE + #define PPC_INTRINSICS + #define FAST_ROTATE #elif defined(__GNUC__) && defined(__i386__) // GCC does peephole optimizations which should result in using rotate // instructions - #define FAST_ROTATE + #define FAST_ROTATE #endif @@ -163,7 +163,7 @@ void CleanUp(); // Turn on ia32 ASM for Ciphers and Message Digests // Seperate define since these are more complex, use member offsets -// and user may want to turn off while leaving Big Integer optos on +// and user may want to turn off while leaving Big Integer optos on #if defined(TAOCRYPT_X86ASM_AVAILABLE) && !defined(DISABLE_TAO_ASM) #define TAO_ASM #endif @@ -271,7 +271,7 @@ void CleanUp(); template struct CompileAssert { - static char dummy[2*b-1]; + static char dummy[2*b-1]; }; #define TAOCRYPT_COMPILE_ASSERT(assertion) \ @@ -440,7 +440,7 @@ template<> inline word32 rotrFixed(word32 x, word32 y) #ifdef min #undef min -#endif +#endif template @@ -472,14 +472,14 @@ inline word32 ByteReverse(word32 value) inline word64 ByteReverse(word64 value) { #ifdef TAOCRYPT_SLOW_WORD64 - return (word64(ByteReverse(word32(value))) << 32) | + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); #else - value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); - value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); - return rotlFixed(value, 32U); + return rotlFixed(value, 32U); #endif } @@ -512,7 +512,7 @@ inline T ByteReverseIf(T value, ByteOrder order) template inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) { - if (!HostByteOrderIs(order)) + if (!HostByteOrderIs(order)) ByteReverse(out, in, bc); else if (out != in) memcpy(out, in, bc); @@ -520,7 +520,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) -// do Asm Reverse is host is Little and x86asm +// do Asm Reverse is host is Little and x86asm #ifdef LITTLE_ENDIAN_ORDER #ifdef TAOCRYPT_X86ASM_AVAILABLE #define LittleReverse AsmReverse @@ -532,7 +532,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) #endif -// do Asm Reverse is host is Big and x86asm +// do Asm Reverse is host is Big and x86asm #ifdef BIG_ENDIAN_ORDER #ifdef TAOCRYPT_X86ASM_AVAILABLE #define BigReverse AsmReverse @@ -551,14 +551,14 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) inline word32 AsmReverse(word32 wd) { #ifdef __GNUC__ - __asm__ + __asm__ ( "bswap %1" : "=r"(wd) : "0"(wd) ); #else - __asm + __asm { mov eax, wd bswap eax @@ -568,7 +568,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) return wd; } -#endif +#endif template @@ -699,7 +699,7 @@ inline void PutWord(bool assumeAligned, ByteOrder order, byte* block, T value, if (assumeAligned) { if (xorBlock) - *reinterpret_cast(block) = ByteReverseIf(value, order) + *reinterpret_cast(block) = ByteReverseIf(value, order) ^ *reinterpret_cast(xorBlock); else *reinterpret_cast(block) = ByteReverseIf(value, order); @@ -759,7 +759,7 @@ struct BlockGetAndPut { // function needed because of C++ grammatical ambiguity between // expression-statements and declarations - static inline GetBlock Get(const void *block) + static inline GetBlock Get(const void *block) {return GetBlock(block);} typedef PutBlock Put; }; diff --git a/cdk/extra/yassl/taocrypt/include/modarith.hpp b/cdk/extra/yassl/taocrypt/include/modarith.hpp index 5ac3f67ab..f84436d6d 100644 --- a/cdk/extra/yassl/taocrypt/include/modarith.hpp +++ b/cdk/extra/yassl/taocrypt/include/modarith.hpp @@ -45,8 +45,8 @@ class ModularArithmetic : public AbstractRing modulus(ma.modulus), result((word)0, modulus.reg_.size()) {} const Integer& GetModulus() const {return modulus;} - void SetModulus(const Integer &newModulus) - { + void SetModulus(const Integer &newModulus) + { modulus = newModulus; result.reg_.resize(modulus.reg_.size()); } diff --git a/cdk/extra/yassl/taocrypt/include/modes.hpp b/cdk/extra/yassl/taocrypt/include/modes.hpp index bfe8c6ec5..b9c4f0ec4 100644 --- a/cdk/extra/yassl/taocrypt/include/modes.hpp +++ b/cdk/extra/yassl/taocrypt/include/modes.hpp @@ -38,11 +38,11 @@ class BlockCipher { public: BlockCipher() : cipher_(DIR, MODE) {} - void Process(byte* c, const byte* p, word32 sz) + void Process(byte* c, const byte* p, word32 sz) { cipher_.Process(c, p, sz); } - void SetKey(const byte* k, word32 sz) + void SetKey(const byte* k, word32 sz) { cipher_.SetKey(k, sz, DIR); } - void SetKey(const byte* k, word32 sz, const byte* iv) + void SetKey(const byte* k, word32 sz, const byte* iv) { cipher_.SetKey(k, sz, DIR); cipher_.SetIV(iv); } private: T cipher_; @@ -57,7 +57,7 @@ class Mode_BASE : public virtual_base { public: enum { MaxBlockSz = 16 }; - explicit Mode_BASE(int sz, CipherDir dir, Mode mode) + explicit Mode_BASE(int sz, CipherDir dir, Mode mode) : blockSz_(sz), reg_(reinterpret_cast(r_)), tmp_(reinterpret_cast(t_)), dir_(dir), mode_(mode) {} diff --git a/cdk/extra/yassl/taocrypt/include/rsa.hpp b/cdk/extra/yassl/taocrypt/include/rsa.hpp index ee3e378a6..030970325 100644 --- a/cdk/extra/yassl/taocrypt/include/rsa.hpp +++ b/cdk/extra/yassl/taocrypt/include/rsa.hpp @@ -38,11 +38,11 @@ class PK_Lengths { explicit PK_Lengths(const Integer& i) : image_(i) {} word32 PaddedBlockBitLength() const {return image_.BitCount() - 1;} - word32 PaddedBlockByteLength() const + word32 PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} word32 FixedCiphertextLength() const {return image_.ByteCount();} - word32 FixedMaxPlaintextLength() const + word32 FixedMaxPlaintextLength() const {return SaturatingSubtract(PaddedBlockBitLength() / 8, 10U); } }; @@ -101,7 +101,7 @@ class RSA_PrivateKey : public RSA_PublicKey { explicit RSA_PrivateKey(Source&); void Initialize(const Integer& n, const Integer& e, const Integer& d, - const Integer& p, const Integer& q, const Integer& dp, + const Integer& p, const Integer& q, const Integer& dp, const Integer& dq, const Integer& u) {n_ = n; e_ = e; d_ = d; p_ = p; q_ = q; dp_ = dp; dq_ = dq; u_ = u;} void Initialize(Source&); @@ -113,7 +113,7 @@ class RSA_PrivateKey : public RSA_PublicKey { const Integer& GetPrivateExponent() const {return d_;} const Integer& GetModPrime1PrivateExponent() const {return dp_;} const Integer& GetModPrime2PrivateExponent() const {return dq_;} - const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return u_;} void SetPrime1(const Integer& p) {p_ = p;} @@ -140,7 +140,7 @@ class RSA_BlockType2 { // block type 1 padding class RSA_BlockType1 { public: - void Pad(const byte*, word32, byte*, word32, + void Pad(const byte*, word32, byte*, word32, RandomNumberGenerator&) const; word32 UnPad(const byte*, word32, byte*) const; }; @@ -199,7 +199,7 @@ word32 RSA_Decryptor::Decrypt(const byte* cipher, word32 sz, byte* plain, if (sz != lengths.FixedCiphertextLength()) return 0; - + ByteBlock paddedBlock(lengths.PaddedBlockByteLength()); Integer x = key_.CalculateInverse(rng, Integer(cipher, lengths.FixedCiphertextLength()).Ref()); diff --git a/cdk/extra/yassl/taocrypt/include/runtime.hpp b/cdk/extra/yassl/taocrypt/include/runtime.hpp index b41f20c6d..accd86a37 100644 --- a/cdk/extra/yassl/taocrypt/include/runtime.hpp +++ b/cdk/extra/yassl/taocrypt/include/runtime.hpp @@ -25,6 +25,9 @@ #ifndef yaSSL_NEW_HPP #define yaSSL_NEW_HPP +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #ifdef YASSL_PURE_C diff --git a/cdk/extra/yassl/taocrypt/include/types.hpp b/cdk/extra/yassl/taocrypt/include/types.hpp index ce6ea0809..67ea2609a 100644 --- a/cdk/extra/yassl/taocrypt/include/types.hpp +++ b/cdk/extra/yassl/taocrypt/include/types.hpp @@ -22,6 +22,9 @@ #ifndef TAO_CRYPT_TYPES_HPP #define TAO_CRYPT_TYPES_HPP +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif namespace TaoCrypt { @@ -48,7 +51,7 @@ typedef unsigned int word32; #define WORD64_AVAILABLE typedef unsigned long word64; #define W64LIT(x) x##LL -#elif SIZEOF_LONG_LONG == 8 +#elif SIZEOF_LONG_LONG == 8 #define WORD64_AVAILABLE #define WORD64_IS_DISTINCT_TYPE typedef unsigned long long word64; @@ -63,10 +66,10 @@ typedef unsigned int word32; #endif #endif - + #if defined(HAVE_64_MULTIPLY) && (defined(__ia64__) \ || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__) \ - || defined(_M_X64) || defined(_M_IA64)) + || defined(_M_X64) || defined(_M_IA64)) // These platforms have 64-bit CPU registers. Unfortunately most C++ compilers // don't allow any way to access the 64-bit by 64-bit multiply instruction // without using assembly, so in order to use word64 as word, the assembly diff --git a/cdk/extra/yassl/taocrypt/src/aes.cpp b/cdk/extra/yassl/taocrypt/src/aes.cpp index ee4c7a6e8..87c8c074b 100644 --- a/cdk/extra/yassl/taocrypt/src/aes.cpp +++ b/cdk/extra/yassl/taocrypt/src/aes.cpp @@ -47,7 +47,7 @@ void AES::Process(byte* out, const byte* in, word32 sz) if (dir_ == ENCRYPTION) AsmEncrypt(in, out, (void*)Te0); else - AsmDecrypt(in, out, (void*)Td0); + AsmDecrypt(in, out, (void*)Td0); out += BLOCK_SIZE; in += BLOCK_SIZE; } @@ -69,7 +69,7 @@ void AES::Process(byte* out, const byte* in, word32 sz) else { while (blocks--) { AsmDecrypt(in, out, (void*)Td0); - + *(word32*)out ^= r_[0]; *(word32*)(out + 4) ^= r_[1]; *(word32*)(out + 8) ^= r_[2]; @@ -94,7 +94,7 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) keylen = 32; else if (keylen != 24) keylen = 24; - + rounds_ = keylen/4 + 6; word32 temp, *rk = key_; @@ -109,10 +109,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[3]; rk[4] = rk[0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; @@ -128,10 +128,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; @@ -149,10 +149,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; @@ -161,10 +161,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) break; temp = rk[11]; rk[12] = rk[ 4] ^ - (Te4[GETBYTE(temp, 3)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 0)] & 0x000000ff); + (Te2[GETBYTE(temp, 3)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 0)] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; @@ -191,25 +191,25 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) for (i = 1; i < rounds_; i++) { rk += 4; rk[0] = - Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[0], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[0], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[0], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[0], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[0], 0)] & 0xff]; rk[1] = - Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[1], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[1], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[1], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[1], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[1], 0)] & 0xff]; rk[2] = - Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[2], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[2], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[2], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[2], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[2], 0)] & 0xff]; rk[3] = - Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[3], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[3], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[3], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[3], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[3], 0)] & 0xff]; } } } @@ -226,7 +226,7 @@ void AES::ProcessAndXorBlock(const byte* in, const byte* xOr, byte* out) const typedef BlockGetAndPut gpBlock; - + void AES::encrypt(const byte* inBlock, const byte* xorBlock, byte* outBlock) const { @@ -243,7 +243,8 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; - + + s0 |= PreFetchTe(); /* * Nr - 1 full rounds: */ @@ -279,7 +280,7 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, if (--r == 0) { break; } - + s0 = Te0[GETBYTE(t0, 3)] ^ Te1[GETBYTE(t1, 2)] ^ @@ -312,28 +313,28 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, */ s0 = - (Te4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t0, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t3, 0)] & 0x000000ff) ^ rk[0]; s1 = - (Te4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t1, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t0, 0)] & 0x000000ff) ^ rk[1]; s2 = - (Te4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t2, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t1, 0)] & 0x000000ff) ^ rk[2]; s3 = - (Te4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t3, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t2, 0)] & 0x000000ff) ^ rk[3]; @@ -358,6 +359,8 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, s2 ^= rk[2]; s3 ^= rk[3]; + s0 |= PreFetchTd(); + /* * Nr - 1 full rounds: */ @@ -423,29 +426,32 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, * apply last round and * map cipher state to byte array block: */ + + t0 |= PreFetchCTd4(); + s0 = - (Td4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t1, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t0, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t3, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t2, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t1, 0)]) ^ rk[0]; s1 = - (Td4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t2, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t1, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t0, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t3, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t2, 0)]) ^ rk[1]; s2 = - (Td4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t3, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t2, 3)] << 24 ) ^ + ((word32)CTd4[GETBYTE(t1, 2)] << 16 ) ^ + ((word32)CTd4[GETBYTE(t0, 1)] << 8 ) ^ + ((word32)CTd4[GETBYTE(t3, 0)]) ^ rk[2]; s3 = - (Td4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t0, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t3, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t2, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t1, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t0, 0)]) ^ rk[3]; gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); @@ -466,13 +472,13 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, "movd mm7, ebp;" \ "movd mm4, eax;" \ "mov ebp, edx;" \ - "sub esp, 4;" + "sub esp, 4;" #define EPILOG() \ "add esp, 4;" \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "S" (inBlock), "d" (boxes), "a" (outBlock) \ : "%edi", "memory", "cc" \ @@ -502,13 +508,13 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 12 ) - - + + #endif #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -528,7 +534,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS1( dec edx ) AS2( movd mm6, edi ) // save rk AS2( movd mm5, edx ) // save rounds - + AS2( mov eax, DWORD PTR [esi] ) AS2( mov ebx, DWORD PTR [esi + 4] ) AS2( mov ecx, DWORD PTR [esi + 8] ) @@ -549,17 +555,17 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const #else AS1(1: ) // loop1 #endif - /* Put0 (mm0) = + /* Put0 (mm0) = Te0[get0,rs 24] ^ Te1[get1,rs 16] ^ Te2[get2,rs 8] ^ Te3[get3,rs 0] */ - + AS2( mov esi, eax ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ebx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -573,7 +579,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm0, esi ) - /* Put1 (mm1) = + /* Put1 (mm1) = Te0[get1,rs 24] ^ Te1[get2,rs 16] ^ Te2[get3,rs 8] ^ @@ -598,11 +604,11 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm1, esi ) - /* Put2 (mm2) = + /* Put2 (mm2) = Te0[get2,rs 24] ^ Te1[get3,rs 16] ^ Te2[get0,rs 8] ^ - Te3[get1,rs 0] + Te3[get1,rs 0] */ AS2( mov esi, ecx ) @@ -622,11 +628,11 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm2, esi ) - /* Put3 (edx) = + /* Put3 (edx) = Te0[get3,rs 24] ^ Te1[get0,rs 16] ^ Te2[get1,rs 8] ^ - Te3[get2,rs 0] + Te3[get2,rs 0] */ AS2( mov esi, edx ) @@ -792,7 +798,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( and esi, 255 ) AS2( xor edx, esi ) - + // xOr AS2( movd eax, mm0 ) AS2( movd esi, mm6 ) // rk @@ -833,7 +839,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -844,12 +850,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const #ifdef OLD_GCC_OFFSET AS2( mov edx, DWORD PTR [ecx + 60] ) // rounds - AS2( lea edi, [ecx + 64] ) // rk + AS2( lea edi, [ecx + 64] ) // rk #else AS2( mov edx, DWORD PTR [ecx + 56] ) // rounds - AS2( lea edi, [ecx + 60] ) // rk + AS2( lea edi, [ecx + 60] ) // rk #endif - + AS1( dec edx ) AS2( movd mm6, edi ) // save rk AS2( movd mm5, edx ) // save rounds @@ -879,12 +885,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get0, rs24)] ^ Td1[GETBYTE(get3, rs16)] ^ Td2[GETBYTE(get2, rs 8)] ^ - Td3[GETBYTE(tet1, )] + Td3[GETBYTE(tet1, )] */ AS2( mov esi, eax ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, edx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -902,12 +908,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get1, rs24)] ^ Td1[GETBYTE(get0, rs16)] ^ Td2[GETBYTE(get3, rs 8)] ^ - Td3[GETBYTE(tet2, )] + Td3[GETBYTE(tet2, )] */ AS2( mov esi, ebx ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, eax ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -925,12 +931,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get2, rs24)] ^ Td1[GETBYTE(get1, rs16)] ^ Td2[GETBYTE(get0, rs 8)] ^ - Td3[GETBYTE(tet3, )] + Td3[GETBYTE(tet3, )] */ AS2( mov esi, ecx ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ebx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -948,12 +954,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get3, rs24)] ^ Td1[GETBYTE(get2, rs16)] ^ Td2[GETBYTE(get1, rs 8)] ^ - Td3[GETBYTE(tet0, )] + Td3[GETBYTE(tet0, )] */ AS2( mov esi, edx ) AS2( shr esi, 24 ) AS2( mov edx, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ecx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -1826,18 +1832,52 @@ const word32 AES::Td[5][256] = { } }; +const byte AES::CTd4[256] = +{ + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; + const word32* AES::Te0 = AES::Te[0]; const word32* AES::Te1 = AES::Te[1]; const word32* AES::Te2 = AES::Te[2]; const word32* AES::Te3 = AES::Te[3]; -const word32* AES::Te4 = AES::Te[4]; const word32* AES::Td0 = AES::Td[0]; const word32* AES::Td1 = AES::Td[1]; const word32* AES::Td2 = AES::Td[2]; const word32* AES::Td3 = AES::Td[3]; -const word32* AES::Td4 = AES::Td[4]; diff --git a/cdk/extra/yassl/taocrypt/src/aestables.cpp b/cdk/extra/yassl/taocrypt/src/aestables.cpp index 60795a549..82e0a9aea 100644 --- a/cdk/extra/yassl/taocrypt/src/aestables.cpp +++ b/cdk/extra/yassl/taocrypt/src/aestables.cpp @@ -28,7 +28,7 @@ namespace TaoCrypt { const word32 AES::rcon_[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; diff --git a/cdk/extra/yassl/taocrypt/src/algebra.cpp b/cdk/extra/yassl/taocrypt/src/algebra.cpp index ace17047a..0f5b76687 100644 --- a/cdk/extra/yassl/taocrypt/src/algebra.cpp +++ b/cdk/extra/yassl/taocrypt/src/algebra.cpp @@ -193,8 +193,8 @@ struct WindowSlider if (windowSize == 0) { unsigned int expLen = exp.BitCount(); - windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : - (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : + windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : + (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7))))); } windowModulus <<= windowSize; @@ -259,7 +259,7 @@ void AbstractGroup::SimultaneousMultiply(Integer *results, const Integer &base, notDone = false; for (i=0; i(tm& a, tm& b) { if (a.tm_year > b.tm_year) @@ -95,7 +95,7 @@ bool operator>(tm& a, tm& b) if (a.tm_year == b.tm_year && a.tm_mon > b.tm_mon) return true; - + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && a.tm_mday >b.tm_mday) return true; @@ -108,13 +108,18 @@ bool operator>(tm& a, tm& b) a.tm_min > b.tm_min) return true; + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && + a.tm_mday == b.tm_mday && a.tm_hour == b.tm_hour && + a.tm_min == b.tm_min && a.tm_sec > b.tm_sec) + return true; + return false; } bool operator<(tm& a, tm&b) { - return !(a>b); + return (b>a); } @@ -153,7 +158,7 @@ word32 GetLength(Source& source) word32 length = 0; byte b = source.next(); - if (b >= LONG_LENGTH) { + if (b >= LONG_LENGTH) { word32 bytes = b & 0x7F; if (source.IsLeft(bytes) == false) return 0; @@ -180,7 +185,7 @@ word32 SetLength(word32 length, byte* output) output[i++] = length; else { output[i++] = BytePrecision(length) | 0x80; - + for (int j = BytePrecision(length); j; --j) { output[i] = length >> (j - 1) * 8; i++; @@ -244,8 +249,8 @@ Signer::~Signer() Error BER_Decoder::GetError() -{ - return source_.GetError(); +{ + return source_.GetError(); } @@ -256,7 +261,7 @@ Integer& BER_Decoder::GetInteger(Integer& integer) return integer; } - + // Read a Sequence, return length word32 BER_Decoder::GetSequence() { @@ -319,9 +324,9 @@ word32 BER_Decoder::GetExplicitVersion() source_.next(); return GetVersion(); } - else + else source_.prev(); // put back - + return 0; } @@ -364,7 +369,7 @@ void DSA_Private_Decoder::Decode(DSA_PrivateKey& key) // key key.SetPublicPart(GetInteger(Integer().Ref())); - key.SetPrivatePart(GetInteger(Integer().Ref())); + key.SetPrivatePart(GetInteger(Integer().Ref())); } @@ -408,27 +413,27 @@ void RSA_Public_Decoder::ReadHeaderOpenSSL() source_.advance(len); b = source_.next(); - if (b == TAG_NULL) { // could have NULL tag and 0 terminator, may not + if (b == TAG_NULL) { // could have NULL tag and 0 terminator, may not b = source_.next(); if (b != 0) { source_.SetError(EXPECT_0_E); - return; + return; } } else source_.prev(); // put back b = source_.next(); - if (b != BIT_STRING) { + if (b != BIT_STRING) { source_.SetError(BIT_STR_E); - return; + return; } - len = GetLength(source_); + len = GetLength(source_); b = source_.next(); if (b != 0) // could have 0 source_.prev(); // put back - + GetSequence(); } } @@ -482,8 +487,9 @@ void DH_Decoder::Decode(DH& key) CertDecoder::CertDecoder(Source& s, bool decode, SignerList* signers, bool noVerify, CertType ct) - : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), - signature_(0), verify_(!noVerify) + : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), subCnPos_(-1), + subCnLen_(0), issCnPos_(-1), issCnLen_(0), signature_(0), + verify_(!noVerify) { issuer_[0] = 0; subject_[0] = 0; @@ -534,7 +540,7 @@ void CertDecoder::Decode(SignerList* signers, CertType ct) source_.SetError(SIG_OID_E); return; } - + if (ct != CA && verify_ && !ValidateSignature(signers)) source_.SetError(SIG_OTHER_E); } @@ -544,9 +550,9 @@ void CertDecoder::DecodeToKey() { ReadHeader(); signatureOID_ = GetAlgoId(); - GetName(ISSUER); + GetName(ISSUER); GetValidity(); - GetName(SUBJECT); + GetName(SUBJECT); GetKey(); } @@ -556,7 +562,7 @@ void CertDecoder::GetKey() { if (source_.GetError().What()) return; - GetSequence(); + GetSequence(); keyOID_ = GetAlgoId(); if (keyOID_ == RSAk) { @@ -566,7 +572,7 @@ void CertDecoder::GetKey() return; } b = source_.next(); // length, future - b = source_.next(); + b = source_.next(); while(b != 0) b = source_.next(); } @@ -615,7 +621,7 @@ void CertDecoder::AddDSA() return; } b = source_.next(); // length, future - b = source_.next(); + b = source_.next(); while(b != 0) b = source_.next(); @@ -631,7 +637,7 @@ void CertDecoder::AddDSA() if (source_.IsLeft(length) == false) return; - key_.AddToEnd(source_.get_buffer() + idx, length); + key_.AddToEnd(source_.get_buffer() + idx, length); } @@ -642,7 +648,7 @@ word32 CertDecoder::GetAlgoId() word32 length = GetSequence(); if (source_.GetError().What()) return 0; - + byte b = source_.next(); if (b != OBJECT_IDENTIFIER) { source_.SetError(OBJECT_ID_E); @@ -689,7 +695,7 @@ word32 CertDecoder::GetSignature() source_.SetError(CONTENT_E); return 0; } - + b = source_.next(); if (b != 0) { source_.SetError(EXPECT_0_E); @@ -757,7 +763,7 @@ void CertDecoder::GetName(NameType nt) return; if (source_.IsLeft(length) == false) return; length += source_.get_index(); - + char* ptr; char* buf_end; @@ -773,7 +779,7 @@ void CertDecoder::GetName(NameType nt) while (source_.get_index() < length) { GetSet(); if (source_.GetError().What() == SET_E) { - source_.SetError(NO_ERROR_E); // extensions may only have sequence + source_.SetError(NO_ERROR_E); // extensions may only have sequence source_.prev(); } GetSequence(); @@ -794,7 +800,7 @@ void CertDecoder::GetName(NameType nt) // v1 name types if (joint[0] == 0x55 && joint[1] == 0x04) { source_.advance(2); - byte id = source_.next(); + byte id = source_.next(); b = source_.next(); // strType word32 strLen = GetLength(source_); @@ -804,6 +810,13 @@ void CertDecoder::GetName(NameType nt) case COMMON_NAME: if (!(ptr = AddTag(ptr, buf_end, "/CN=", 4, strLen))) return; + if (nt == ISSUER) { + issCnPos_ = (int)(ptr - strLen - issuer_); + issCnLen_ = (int)strLen; + } else { + subCnPos_ = (int)(ptr - strLen - subject_); + subCnLen_ = (int)strLen; + } break; case SUR_NAME: if (!(ptr = AddTag(ptr, buf_end, "/SN=", 4, strLen))) @@ -834,7 +847,7 @@ void CertDecoder::GetName(NameType nt) sha.Update(source_.get_current(), strLen); source_.advance(strLen); } - else { + else { bool email = false; if (joint[0] == 0x2a && joint[1] == 0x86) // email id hdr email = true; @@ -845,7 +858,7 @@ void CertDecoder::GetName(NameType nt) if (email) { if (!(ptr = AddTag(ptr, buf_end, "/emailAddress=", 14, length))) - return; + return; } source_.advance(length); @@ -901,7 +914,7 @@ void CertDecoder::GetDate(DateType dt) memcpy(afterDate_, date, length); afterDate_[length] = 0; afterDateType_= b; - } + } } @@ -955,11 +968,11 @@ bool CertDecoder::ValidateSignature(SignerList* signers) while (first != last) { if ( memcmp(issuerHash_, (*first)->GetHash(), SHA::DIGEST_SIZE) == 0) { - + const PublicKey& iKey = (*first)->GetPublicKey(); Source pub(iKey.GetKey(), iKey.size()); return ConfirmSignature(pub); - } + } ++first; } return false; @@ -1067,7 +1080,7 @@ word32 Signature_Encoder::SetDigest(const byte* d, word32 dSz, byte* output) output[0] = OCTET_STRING; output[1] = dSz; memcpy(&output[2], d, dSz); - + return dSz + 2; } @@ -1145,7 +1158,7 @@ word32 DER_Encoder::SetAlgoID(HashType aOID, byte* output) word32 SetSequence(word32 len, byte* output) { - + output[0] = SEQUENCE | CONSTRUCTED; return SetLength(len, output + 1) + 1; } @@ -1177,7 +1190,7 @@ word32 EncodeDSA_Signature(const Integer& r, const Integer& s, byte* output) byte seqArray[MAX_SEQ_SZ]; word32 seqSz = SetSequence(rLenSz + rSz + sLenSz + sSz, seqArray); - + // seq memcpy(output, seqArray, seqSz); // r @@ -1210,17 +1223,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 rLen = GetLength(source); if (rLen != 20) { - if (rLen == 21) { // zero at front, eat + while (rLen > 20 && source.remaining() > 0) { // zero's at front, eat source.next(); --rLen; } - else if (rLen == 19) { // add zero to front so 20 bytes + if (rLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = rLen; + while (tmpLen < 20) { decoded[0] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded, source.get_buffer() + source.get_index(), rLen); @@ -1233,17 +1246,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 sLen = GetLength(source); if (sLen != 20) { - if (sLen == 21) { - source.next(); // zero at front, eat + while (sLen > 20 && source.remaining() > 0) { + source.next(); // zero's at front, eat --sLen; } - else if (sLen == 19) { - decoded[rLen] = 0; // add zero to front so 20 bytes + if (sLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = sLen; + while (tmpLen < 20) { + decoded[rLen] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded + rLen, source.get_buffer() + source.get_index(), sLen); @@ -1265,7 +1278,7 @@ int GetCert(Source& source) if (!begin || !end || begin >= end) return -1; - end += strlen(footer); + end += strlen(footer); if (*end == '\r') end++; Source tmp((byte*)begin, end - begin + 1); @@ -1285,7 +1298,7 @@ void PKCS12_Decoder::Decode() // Get AuthSafe GetSequence(); - + // get object id byte obj_id = source_.next(); if (obj_id != OBJECT_IDENTIFIER) { @@ -1299,8 +1312,8 @@ void PKCS12_Decoder::Decode() while (length--) algo_sum += source_.next(); - - + + @@ -1308,7 +1321,7 @@ void PKCS12_Decoder::Decode() // mac digestInfo like certdecoder::getdigest? // macsalt octet string // iter integer - + } diff --git a/cdk/extra/yassl/taocrypt/src/coding.cpp b/cdk/extra/yassl/taocrypt/src/coding.cpp index bc4727cc5..c90d2c85f 100644 --- a/cdk/extra/yassl/taocrypt/src/coding.cpp +++ b/cdk/extra/yassl/taocrypt/src/coding.cpp @@ -37,7 +37,7 @@ const byte hexEncode[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, bad, bad, bad, bad, bad, bad, bad, - 10, 11, 12, 13, 14, 15 + 10, 11, 12, 13, 14, 15 }; // A starts at 0x41 not 0x3A @@ -135,7 +135,7 @@ void Base64Encoder::Encode() word32 i = 0; word32 j = 0; - + while (bytes > 2) { byte b1 = plain_.next(); byte b2 = plain_.next(); @@ -174,10 +174,10 @@ void Base64Encoder::Encode() encoded_[i++] = base64Encode[e2]; encoded_[i++] = (twoBytes) ? base64Encode[e3] : pad; encoded_[i++] = pad; - } + } encoded_[i++] = '\n'; - + if (i == outSz) plain_.reset(encoded_); } @@ -187,7 +187,7 @@ void Base64Encoder::Encode() void Base64Decoder::Decode() { word32 bytes = coded_.size(); - word32 plainSz = bytes - ((bytes + (pemLineSz - 1)) / pemLineSz); + word32 plainSz = bytes - ((bytes + (pemLineSz - 1)) / pemLineSz); const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1; plainSz = ((plainSz * 3) / 4) + 3; decoded_.New(plainSz); @@ -237,7 +237,7 @@ void Base64Decoder::Decode() decoded_[i++] = b3; else break; - + bytes -= 4; if ((++j % 16) == 0) { byte endLine = coded_.next(); @@ -251,7 +251,7 @@ void Base64Decoder::Decode() bytes--; } if (endLine != '\n') { - coded_.SetError(PEM_E); + coded_.SetError(PEM_E); return; } } diff --git a/cdk/extra/yassl/taocrypt/src/des.cpp b/cdk/extra/yassl/taocrypt/src/des.cpp index 53777f082..c1961684c 100644 --- a/cdk/extra/yassl/taocrypt/src/des.cpp +++ b/cdk/extra/yassl/taocrypt/src/des.cpp @@ -257,14 +257,14 @@ void BasicDES::SetKey(const byte* key, word32 /*length*/, CipherDir dir) | ((word32)ks[5] << 8) | ((word32)ks[7]); } - + // reverse key schedule order if (dir == DECRYPTION) for (i = 0; i < 16; i += 2) { STL::swap(k_[i], k_[32 - 2 - i]); STL::swap(k_[i+1], k_[32 - 1 - i]); } - + } static inline void IPERM(word32& left, word32& right) @@ -411,14 +411,14 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) word32 blocks = sz / DES_BLOCK_SIZE; - if (mode_ == CBC) + if (mode_ == CBC) if (dir_ == ENCRYPTION) while (blocks--) { r_[0] ^= *(word32*)in; r_[1] ^= *(word32*)(in + 4); AsmProcess((byte*)r_, (byte*)r_, (void*)Spbox); - + memcpy(out, r_, DES_BLOCK_SIZE); in += DES_BLOCK_SIZE; @@ -427,7 +427,7 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) else while (blocks--) { AsmProcess(in, out, (void*)Spbox); - + *(word32*)out ^= r_[0]; *(word32*)(out + 4) ^= r_[1]; @@ -439,7 +439,7 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) else while (blocks--) { AsmProcess(in, out, (void*)Spbox); - + out += DES_BLOCK_SIZE; in += DES_BLOCK_SIZE; } @@ -641,7 +641,7 @@ void DES_EDE3::ProcessAndXorBlock(const byte* in, const byte* xOr, #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -663,8 +663,8 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "d" (this), "S" (in), "a" (box), "c" (out) \ : "%edi", "memory", "cc" \ @@ -724,7 +724,7 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const DesRound() // 7 DesRound() // 8 - // swap left and right + // swap left and right AS2( xchg eax, ebx ) DesRound() // 1 @@ -765,7 +765,7 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const AS2( mov DWORD PTR [esi], ebx ) // right first AS2( mov DWORD PTR [esi + 4], eax ) - + EPILOG() } diff --git a/cdk/extra/yassl/taocrypt/src/dsa.cpp b/cdk/extra/yassl/taocrypt/src/dsa.cpp index bf116d3e4..a139195a7 100644 --- a/cdk/extra/yassl/taocrypt/src/dsa.cpp +++ b/cdk/extra/yassl/taocrypt/src/dsa.cpp @@ -70,7 +70,7 @@ void DSA_PublicKey::Initialize(const Integer& p, const Integer& q, g_ = g; y_ = y; } - + const Integer& DSA_PublicKey::GetModulus() const { @@ -172,6 +172,7 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, const Integer& q = key_.GetSubGroupOrder(); const Integer& g = key_.GetSubGroupGenerator(); const Integer& x = key_.GetPrivatePart(); + byte* tmpPtr = sig; // initial signature output Integer k(rng, 1, q - 1); @@ -187,22 +188,23 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, return -1; int rSz = r_.ByteCount(); + int tmpSz = rSz; - if (rSz == 19) { - sig[0] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - + r_.Encode(sig, rSz); + sig = tmpPtr + SHA::DIGEST_SIZE; // advance sig output to s int sSz = s_.ByteCount(); + tmpSz = sSz; - if (sSz == 19) { - sig[rSz] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - s_.Encode(sig + rSz, sSz); + s_.Encode(sig, sSz); return 40; } diff --git a/cdk/extra/yassl/taocrypt/src/file.cpp b/cdk/extra/yassl/taocrypt/src/file.cpp index 7c2044bf3..929501f36 100644 --- a/cdk/extra/yassl/taocrypt/src/file.cpp +++ b/cdk/extra/yassl/taocrypt/src/file.cpp @@ -107,7 +107,7 @@ void FileSink::put(Source& source) // swap with other and reset to beginning void Source::reset(ByteBlock& otherBlock) { - buffer_.Swap(otherBlock); + buffer_.Swap(otherBlock); current_ = 0; } diff --git a/cdk/extra/yassl/taocrypt/src/hash.cpp b/cdk/extra/yassl/taocrypt/src/hash.cpp index c176e6a68..c479b7007 100644 --- a/cdk/extra/yassl/taocrypt/src/hash.cpp +++ b/cdk/extra/yassl/taocrypt/src/hash.cpp @@ -92,9 +92,9 @@ void HASHwithTransform::Final(byte* hash) buffLen_ = 0; } memset(&local[buffLen_], 0, padSz - buffLen_); - + ByteReverseIf(local, local, blockSz, order); - + memcpy(&local[padSz], order ? &preHiLen : &preLoLen, sizeof(preLoLen)); memcpy(&local[padSz+4], order ? &preLoLen : &preHiLen, sizeof(preLoLen)); @@ -172,9 +172,9 @@ void HASH64withTransform::Final(byte* hash) buffLen_ = 0; } memset(&local[buffLen_], 0, padSz - buffLen_); - + ByteReverseIf(buffer_, buffer_, padSz, order); - + buffer_[blockSz / sizeof(word64) - 2] = order ? preHiLen : preLoLen; buffer_[blockSz / sizeof(word64) - 1] = order ? preLoLen : preHiLen; diff --git a/cdk/extra/yassl/taocrypt/src/hc128.cpp b/cdk/extra/yassl/taocrypt/src/hc128.cpp index 1d329c87e..df2c3619e 100644 --- a/cdk/extra/yassl/taocrypt/src/hc128.cpp +++ b/cdk/extra/yassl/taocrypt/src/hc128.cpp @@ -60,7 +60,7 @@ namespace TaoCrypt { (T_[(u)]) += tem2+(tem0 ^ tem1); \ (X_[(a)]) = (T_[(u)]); \ (n) = tem3 ^ (T_[(u)]) ; \ -} +} /*one step of HC-128, update Q and generate 32 bits keystream*/ #define step_Q(u,v,a,b,c,d,n){ \ @@ -72,18 +72,18 @@ namespace TaoCrypt { (T_[(u)]) += tem2 + (tem0 ^ tem1); \ (Y_[(a)]) = (T_[(u)]); \ (n) = tem3 ^ (T_[(u)]) ; \ -} +} /*16 steps of HC-128, generate 512 bits keystream*/ -void HC128::GenerateKeystream(word32* keystream) +void HC128::GenerateKeystream(word32* keystream) { word32 cc,dd; cc = counter1024_ & 0x1ff; dd = (cc+16)&0x1ff; - if (counter1024_ < 512) - { + if (counter1024_ < 512) + { counter1024_ = (counter1024_ + 16) & 0x3ff; step_P(cc+0, cc+1, 0, 6, 13,4, keystream[0]); step_P(cc+1, cc+2, 1, 7, 14,5, keystream[1]); @@ -102,9 +102,9 @@ void HC128::GenerateKeystream(word32* keystream) step_P(cc+14,cc+15,14,4, 11,2, keystream[14]); step_P(cc+15,dd+0, 15,5, 12,3, keystream[15]); } - else + else { - counter1024_ = (counter1024_ + 16) & 0x3ff; + counter1024_ = (counter1024_ + 16) & 0x3ff; step_Q(512+cc+0, 512+cc+1, 0, 6, 13,4, keystream[0]); step_Q(512+cc+1, 512+cc+2, 1, 7, 14,5, keystream[1]); step_Q(512+cc+2, 512+cc+3, 2, 8, 15,6, keystream[2]); @@ -138,7 +138,7 @@ void HC128::GenerateKeystream(word32* keystream) h1((X_[(d)]),tem3); \ (T_[(u)]) = ((T_[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ (X_[(a)]) = (T_[(u)]); \ -} +} /*update table Q*/ #define update_Q(u,v,a,b,c,d){ \ @@ -149,7 +149,7 @@ void HC128::GenerateKeystream(word32* keystream) h2((Y_[(d)]),tem3); \ (T_[(u)]) = ((T_[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ (Y_[(a)]) = (T_[(u)]); \ -} +} /*16 steps of HC-128, without generating keystream, */ /*but use the outputs to update P and Q*/ @@ -159,8 +159,8 @@ void HC128::SetupUpdate() /*each time 16 steps*/ cc = counter1024_ & 0x1ff; dd = (cc+16)&0x1ff; - if (counter1024_ < 512) - { + if (counter1024_ < 512) + { counter1024_ = (counter1024_ + 16) & 0x3ff; update_P(cc+0, cc+1, 0, 6, 13, 4); update_P(cc+1, cc+2, 1, 7, 14, 5); @@ -177,9 +177,9 @@ void HC128::SetupUpdate() /*each time 16 steps*/ update_P(cc+12,cc+13,12,2, 9, 0); update_P(cc+13,cc+14,13,3, 10, 1); update_P(cc+14,cc+15,14,4, 11, 2); - update_P(cc+15,dd+0, 15,5, 12, 3); + update_P(cc+15,dd+0, 15,5, 12, 3); } - else + else { counter1024_ = (counter1024_ + 16) & 0x3ff; update_Q(512+cc+0, 512+cc+1, 0, 6, 13, 4); @@ -197,8 +197,8 @@ void HC128::SetupUpdate() /*each time 16 steps*/ update_Q(512+cc+12,512+cc+13,12,2, 9, 0); update_Q(512+cc+13,512+cc+14,13,3, 10, 1); update_Q(512+cc+14,512+cc+15,14,4, 11, 2); - update_Q(512+cc+15,512+dd+0, 15,5, 12, 3); - } + update_Q(512+cc+15,512+dd+0, 15,5, 12, 3); + } } @@ -220,46 +220,46 @@ void HC128::SetupUpdate() /*each time 16 steps*/ void HC128::SetIV(const byte* iv) -{ +{ word32 i; - - for (i = 0; i < (128 >> 5); i++) + + for (i = 0; i < (128 >> 5); i++) iv_[i] = LITTLE32(((word32*)iv)[i]); - + for (; i < 8; i++) iv_[i] = iv_[i-4]; - - /* expand the key and IV into the table T */ - /* (expand the key and IV into the table P and Q) */ - - for (i = 0; i < 8; i++) T_[i] = key_[i]; - for (i = 8; i < 16; i++) T_[i] = iv_[i-8]; - - for (i = 16; i < (256+16); i++) - T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+i; - - for (i = 0; i < 16; i++) T_[i] = T_[256+i]; - - for (i = 16; i < 1024; i++) - T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+256+i; - + + /* expand the key and IV into the table T */ + /* (expand the key and IV into the table P and Q) */ + + for (i = 0; i < 8; i++) T_[i] = key_[i]; + for (i = 8; i < 16; i++) T_[i] = iv_[i-8]; + + for (i = 16; i < (256+16); i++) + T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+i; + + for (i = 0; i < 16; i++) T_[i] = T_[256+i]; + + for (i = 16; i < 1024; i++) + T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+256+i; + /* initialize counter1024, X and Y */ - counter1024_ = 0; - for (i = 0; i < 16; i++) X_[i] = T_[512-16+i]; + counter1024_ = 0; + for (i = 0; i < 16; i++) X_[i] = T_[512-16+i]; for (i = 0; i < 16; i++) Y_[i] = T_[512+512-16+i]; - + /* run the cipher 1024 steps before generating the output */ - for (i = 0; i < 64; i++) SetupUpdate(); + for (i = 0; i < 64; i++) SetupUpdate(); } void HC128::SetKey(const byte* key, const byte* iv) -{ - word32 i; +{ + word32 i; - /* Key size in bits 128 */ + /* Key size in bits 128 */ for (i = 0; i < (128 >> 5); i++) key_[i] = LITTLE32(((word32*)key)[i]); - + for ( ; i < 8 ; i++) key_[i] = key_[i-4]; SetIV(iv); @@ -273,25 +273,25 @@ void HC128::Process(byte* output, const byte* input, word32 msglen) for ( ; msglen >= 64; msglen -= 64, input += 64, output += 64) { - GenerateKeystream(keystream); + GenerateKeystream(keystream); /* unroll loop */ - ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); - ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); - ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); - ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); - ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); - ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); - ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); - ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); - ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); - ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); - ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); - ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); - ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); - ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); - ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); - ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); + ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); + ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); + ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); + ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); + ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); + ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); + ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); + ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); + ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); + ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); + ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); + ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); + ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); + ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); + ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); + ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); } if (msglen > 0) @@ -302,13 +302,13 @@ void HC128::Process(byte* output, const byte* input, word32 msglen) { word32 wordsLeft = msglen / sizeof(word32); if (msglen % sizeof(word32)) wordsLeft++; - + ByteReverse(keystream, keystream, wordsLeft * sizeof(word32)); } #endif for (i = 0; i < msglen; i++) - output[i] = input[i] ^ ((byte*)keystream)[i]; + output[i] = input[i] ^ ((byte*)keystream)[i]; } } diff --git a/cdk/extra/yassl/taocrypt/src/integer.cpp b/cdk/extra/yassl/taocrypt/src/integer.cpp index 478a13cd8..d97376fe4 100644 --- a/cdk/extra/yassl/taocrypt/src/integer.cpp +++ b/cdk/extra/yassl/taocrypt/src/integer.cpp @@ -27,7 +27,7 @@ #endif #if defined(_M_X64) || defined(_M_IA64) - #include + #include #pragma intrinsic(_umul128) #endif @@ -359,7 +359,7 @@ S DivideThreeWordsByTwo(S* A, S B0, S B1, D* dummy_VC6_WorkAround = 0) D p = D::Multiply(B0, Q); D u = (D) A[0] - p.GetLowHalf(); A[0] = u.GetLowHalf(); - u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - + u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - D::Multiply(B1, Q); A[1] = u.GetLowHalf(); A[2] += u.GetHighHalf(); @@ -389,7 +389,7 @@ inline D DivideFourWordsByTwo(S *T, const D &Al, const D &Ah, const D &B) { S Q[2]; T[0] = Al.GetLowHalf(); - T[1] = Al.GetHighHalf(); + T[1] = Al.GetHighHalf(); T[2] = Ah.GetLowHalf(); T[3] = Ah.GetHighHalf(); Q[1] = DivideThreeWordsByTwo(T+1, B.GetLowHalf(), @@ -1083,7 +1083,7 @@ static PMul s_pMul4, s_pMul8, s_pMul8B; static void SetPentiumFunctionPointers() { if (!IsPentium()) - { + { s_pAdd = &Portable::Add; s_pSub = &Portable::Subtract; } @@ -1099,7 +1099,7 @@ static void SetPentiumFunctionPointers() } #ifdef SSE2_INTRINSICS_AVAILABLE - if (!IsPentium()) + if (!IsPentium()) { s_pMul4 = &Portable::Multiply4; s_pMul8 = &Portable::Multiply8; @@ -1406,7 +1406,7 @@ TAOCRYPT_NAKED word P4Optimized::Subtract(word *C, const word *A, #define MulStartup \ AS2(xor ebp, ebp) \ AS2(xor edi, edi) \ - AS2(xor ebx, ebx) + AS2(xor ebx, ebx) #define MulShiftCarry \ AS2(mov ebp, edx) \ @@ -2160,7 +2160,7 @@ void RecursiveMultiply(word *R, word *T, const word *A, const word *B, } -void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) +void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) { if (LowLevel::SquareRecursionLimit() >= 4 && N==4) LowLevel::Square4(R, A); @@ -2581,7 +2581,7 @@ void Integer::Decode(Source& source) source.prev(); if (source.IsLeft(length) == false) return; - + unsigned int words = (length + WORD_SIZE - 1) / WORD_SIZE; words = RoundupSize(words); if (words > reg_.size()) reg_.CleanNew(words); @@ -2596,7 +2596,7 @@ void Integer::Decode(Source& source) void Integer::Decode(const byte* input, unsigned int inputLen, Signedness s) { unsigned int idx(0); - byte b = 0; + byte b = 0; if (inputLen>0) b = input[idx]; // peek sign_ = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE; @@ -3174,7 +3174,7 @@ static inline void AtomicDivide(word *Q, const word *A, const word *B) #ifndef NDEBUG if (B[0] || B[1]) { - // multiply quotient and divisor and add remainder, make sure it + // multiply quotient and divisor and add remainder, make sure it // equals dividend word P[4]; Portable::Multiply2(P, Q, B); @@ -3558,7 +3558,7 @@ const Integer& ModularArithmetic::Half(const Integer &a) const const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Add(result.reg_.begin(), a.reg_.begin(), b.reg_.begin(), @@ -3582,7 +3582,7 @@ const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Add(a.reg_.get_buffer(), a.reg_.get_buffer(), @@ -3607,7 +3607,7 @@ Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const const Integer& ModularArithmetic::Subtract(const Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Subtract(result.reg_.begin(), a.reg_.begin(), @@ -3627,7 +3627,7 @@ const Integer& ModularArithmetic::Subtract(const Integer &a, Integer& ModularArithmetic::Reduce(Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Subtract(a.reg_.get_buffer(), a.reg_.get_buffer(), diff --git a/cdk/extra/yassl/taocrypt/src/md2.cpp b/cdk/extra/yassl/taocrypt/src/md2.cpp index 3dfc0d6e7..a2fe0a107 100644 --- a/cdk/extra/yassl/taocrypt/src/md2.cpp +++ b/cdk/extra/yassl/taocrypt/src/md2.cpp @@ -44,7 +44,7 @@ void MD2::Init() void MD2::Update(const byte* data, word32 len) { - static const byte S[256] = + static const byte S[256] = { 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, diff --git a/cdk/extra/yassl/taocrypt/src/md4.cpp b/cdk/extra/yassl/taocrypt/src/md4.cpp index 9364a1c23..9fb789781 100644 --- a/cdk/extra/yassl/taocrypt/src/md4.cpp +++ b/cdk/extra/yassl/taocrypt/src/md4.cpp @@ -29,7 +29,7 @@ namespace STL = STL_NAMESPACE; - + namespace TaoCrypt { @@ -47,8 +47,8 @@ void MD4::Init() MD4::MD4(const MD4& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -108,7 +108,7 @@ void MD4::Transform() function(C,D,A,B,14,11); function(B,C,D,A,15,19); -#undef function +#undef function #define function(a,b,c,d,k,s) a=rotlFixed(a+G(b,c,d)+buffer_[k]+0x5a827999,s); function(A,B,C,D, 0, 3); function(D,A,B,C, 4, 5); @@ -127,7 +127,7 @@ void MD4::Transform() function(C,D,A,B,11, 9); function(B,C,D,A,15,13); -#undef function +#undef function #define function(a,b,c,d,k,s) a=rotlFixed(a+H(b,c,d)+buffer_[k]+0x6ed9eba1,s); function(A,B,C,D, 0, 3); function(D,A,B,C, 8, 9); diff --git a/cdk/extra/yassl/taocrypt/src/md5.cpp b/cdk/extra/yassl/taocrypt/src/md5.cpp index 45cfa8a33..bdc17c063 100644 --- a/cdk/extra/yassl/taocrypt/src/md5.cpp +++ b/cdk/extra/yassl/taocrypt/src/md5.cpp @@ -48,8 +48,8 @@ void MD5::Init() MD5::MD5(const MD5& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -91,7 +91,7 @@ void MD5::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -174,7 +174,7 @@ void MD5::Update(const byte* data, word32 len) // esi already set up, after using set for next round // ebp already set up, set up using next round index - + #define MD5STEP1(w, x, y, z, index, data, s) \ AS2( xor esi, z ) \ AS2( and esi, x ) \ @@ -223,7 +223,7 @@ void MD5::Update(const byte* data, word32 len) #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -242,8 +242,8 @@ void MD5::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "a" (times) \ : "%esi", "%edx", "memory", "cc" \ @@ -272,7 +272,7 @@ void MD5::AsmTransform(const byte* data, word32 times) AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 8 ) - + #endif @@ -288,16 +288,16 @@ void MD5::AsmTransform(const byte* data, word32 times) AS2( movd mm2, eax ) // store times_ AS2( movd mm1, esi ) // store digest_ - + AS2( mov eax, [esi] ) // a AS2( mov ebx, [esi + 4] ) // b AS2( mov ecx, [esi + 8] ) // c AS2( mov edx, [esi + 12] ) // d - + #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif // set up @@ -375,7 +375,7 @@ void MD5::AsmTransform(const byte* data, word32 times) MD5STEP4( edx, eax, ebx, ecx, 2, 0xbd3af235, 10) MD5STEP4( ecx, edx, eax, ebx, 9, 0x2ad7d2bb, 15) MD5STEP4( ebx, ecx, edx, eax, 9, 0xeb86d391, 21) - + AS2( movd esi, mm1 ) // digest_ AS2( add [esi], eax ) // write out @@ -417,7 +417,7 @@ void MD5::Transform() #define MD5STEP(f, w, x, y, z, data, s) \ w = rotlFixed(w + f(x, y, z) + data, s) + x - // Copy context->state[] to working vars + // Copy context->state[] to working vars word32 a = digest_[0]; word32 b = digest_[1]; word32 c = digest_[2]; @@ -490,7 +490,7 @@ void MD5::Transform() MD5STEP(F4, d, a, b, c, buffer_[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, buffer_[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, buffer_[9] + 0xeb86d391, 21); - + // Add the working vars back into digest state[] digest_[0] += a; digest_[1] += b; diff --git a/cdk/extra/yassl/taocrypt/src/misc.cpp b/cdk/extra/yassl/taocrypt/src/misc.cpp index b576d3d59..26c494d74 100644 --- a/cdk/extra/yassl/taocrypt/src/misc.cpp +++ b/cdk/extra/yassl/taocrypt/src/misc.cpp @@ -185,7 +185,7 @@ bool HaveCpuId() { mov eax, 0 cpuid - } + } } __except (1) { diff --git a/cdk/extra/yassl/taocrypt/src/rabbit.cpp b/cdk/extra/yassl/taocrypt/src/rabbit.cpp index 5e32f3834..614e0b425 100644 --- a/cdk/extra/yassl/taocrypt/src/rabbit.cpp +++ b/cdk/extra/yassl/taocrypt/src/rabbit.cpp @@ -89,7 +89,7 @@ void Rabbit::NextState(RabbitCtx which) ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5])); ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6])); ctx->carry = (ctx->c[7] < c_old[7]); - + /* Calculate the g-values */ for (i=0;i<8;i++) g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i])); @@ -111,7 +111,7 @@ void Rabbit::SetIV(const byte* iv) { /* Temporary variables */ word32 i0, i1, i2, i3, i; - + /* Generate four subvectors */ i0 = LITTLE32(*(word32*)(iv+0)); i2 = LITTLE32(*(word32*)(iv+4)); @@ -189,7 +189,7 @@ void Rabbit::SetKey(const byte* key, const byte* iv) } workCtx_.carry = masterCtx_.carry; - if (iv) SetIV(iv); + if (iv) SetIV(iv); } @@ -238,11 +238,11 @@ void Rabbit::Process(byte* output, const byte* input, word32 msglen) /* Generate 16 bytes of pseudo-random data */ tmp[0] = LITTLE32(workCtx_.x[0] ^ (workCtx_.x[5]>>16) ^ U32V(workCtx_.x[3]<<16)); - tmp[1] = LITTLE32(workCtx_.x[2] ^ + tmp[1] = LITTLE32(workCtx_.x[2] ^ (workCtx_.x[7]>>16) ^ U32V(workCtx_.x[5]<<16)); - tmp[2] = LITTLE32(workCtx_.x[4] ^ + tmp[2] = LITTLE32(workCtx_.x[4] ^ (workCtx_.x[1]>>16) ^ U32V(workCtx_.x[7]<<16)); - tmp[3] = LITTLE32(workCtx_.x[6] ^ + tmp[3] = LITTLE32(workCtx_.x[6] ^ (workCtx_.x[3]>>16) ^ U32V(workCtx_.x[1]<<16)); /* Encrypt/decrypt the data */ diff --git a/cdk/extra/yassl/taocrypt/src/random.cpp b/cdk/extra/yassl/taocrypt/src/random.cpp index 26dae7d19..45df3bdba 100644 --- a/cdk/extra/yassl/taocrypt/src/random.cpp +++ b/cdk/extra/yassl/taocrypt/src/random.cpp @@ -107,7 +107,7 @@ OS_Seed::OS_Seed() } -OS_Seed::~OS_Seed() +OS_Seed::~OS_Seed() { close(fd_); } diff --git a/cdk/extra/yassl/taocrypt/src/ripemd.cpp b/cdk/extra/yassl/taocrypt/src/ripemd.cpp index 5d03dc61c..1c5c6f5d7 100644 --- a/cdk/extra/yassl/taocrypt/src/ripemd.cpp +++ b/cdk/extra/yassl/taocrypt/src/ripemd.cpp @@ -49,8 +49,8 @@ void RIPEMD160::Init() RIPEMD160::RIPEMD160(const RIPEMD160& that) - : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) -{ + : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -93,7 +93,7 @@ void RIPEMD160::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -131,7 +131,7 @@ void RIPEMD160::Update(const byte* data, word32 len) // for all -#define F(x, y, z) (x ^ y ^ z) +#define F(x, y, z) (x ^ y ^ z) #define G(x, y, z) (z ^ (x & (y^z))) #define H(x, y, z) (z ^ (x | ~y)) #define I(x, y, z) (y ^ (z & (x^y))) @@ -266,7 +266,7 @@ void RIPEMD160::Transform() Subround(J, b2, c2, d2, e2, a2, buffer_[ 3], 12, k5); Subround(J, a2, b2, c2, d2, e2, buffer_[12], 6, k5); - Subround(I, e2, a2, b2, c2, d2, buffer_[ 6], 9, k6); + Subround(I, e2, a2, b2, c2, d2, buffer_[ 6], 9, k6); Subround(I, d2, e2, a2, b2, c2, buffer_[11], 13, k6); Subround(I, c2, d2, e2, a2, b2, buffer_[ 3], 15, k6); Subround(I, b2, c2, d2, e2, a2, buffer_[ 7], 7, k6); @@ -362,7 +362,7 @@ void RIPEMD160::Transform() AS2( and esi, x ) \ AS2( xor esi, z ) - + // H(z ^ (x | ~y)) // place in esi #define ASMH(x, y, z) \ @@ -391,7 +391,7 @@ void RIPEMD160::Transform() // for 160 and 320 -// #define ASMSubround(f, a, b, c, d, e, i, s, k) +// #define ASMSubround(f, a, b, c, d, e, i, s, k) // a += f(b, c, d) + data[i] + k; // a = rotlFixed((word32)a, s) + e; // c = rotlFixed((word32)c, 10U) @@ -506,7 +506,7 @@ void RIPEMD160::Transform() #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -525,8 +525,8 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "d" (times) \ : "%esi", "%eax", "memory", "cc" \ @@ -555,7 +555,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 8 ) - + #endif PROLOG() @@ -568,11 +568,11 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS2( sub esp, 24 ) // make room for tmp a1 - e1 AS2( movd mm1, esi ) // store digest_ - + #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif AS2( movd mm2, edx ) // store times_ @@ -583,7 +583,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS2( mov edx, [esi + 12] ) // d1 AS2( mov ebp, [esi + 16] ) // e1 - // setup + // setup AS2( mov esi, ecx ) ASMSubroundF( eax, ebx, ecx, edx, ebp, 0, 11) @@ -713,7 +713,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) // setup AS2( mov esi, ebx ) - ASMSubroundI( ebp, eax, ebx, ecx, edx, 6, 9, k6) + ASMSubroundI( ebp, eax, ebx, ecx, edx, 6, 9, k6) ASMSubroundI( edx, ebp, eax, ebx, ecx, 11, 13, k6) ASMSubroundI( ecx, edx, ebp, eax, ebx, 3, 15, k6) ASMSubroundI( ebx, ecx, edx, ebp, eax, 7, 7, k6) @@ -831,7 +831,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS1( jnz 0b ) // loopStart #endif - // inline adjust + // inline adjust AS2( add esp, 24 ) // fix room on stack EPILOG() diff --git a/cdk/extra/yassl/taocrypt/src/rsa.cpp b/cdk/extra/yassl/taocrypt/src/rsa.cpp index 73f678e26..be8ca6fec 100644 --- a/cdk/extra/yassl/taocrypt/src/rsa.cpp +++ b/cdk/extra/yassl/taocrypt/src/rsa.cpp @@ -61,7 +61,7 @@ Integer RSA_PrivateKey::CalculateInverse(RandomNumberGenerator& rng, Integer y = ModularRoot(re, dq_, dp_, q_, p_, u_); y = modn.Divide(y, r); // unblind - + return y; } @@ -97,7 +97,7 @@ void RSA_BlockType2::Pad(const byte *input, word32 inputLen, byte *pkcsBlock, rng.GenerateBlock(&pkcsBlock[1], padLen); for (word32 i = 1; i < padLen; i++) if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01; - + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); } @@ -200,12 +200,12 @@ word32 RSA_BlockType1::UnPad(const byte* pkcsBlock, word32 pkcsBlockLen, word32 SSL_Decrypt(const RSA_PublicKey& key, const byte* sig, byte* plain) { PK_Lengths lengths(key.GetModulus()); - + ByteBlock paddedBlock(BitsToBytes(lengths.PaddedBlockBitLength())); Integer x = key.ApplyFunction(Integer(sig, lengths.FixedCiphertextLength())); if (x.ByteCount() > paddedBlock.size()) - x = Integer::Zero(); + x = Integer::Zero(); x.Encode(paddedBlock.get_buffer(), paddedBlock.size()); return RSA_BlockType1().UnPad(paddedBlock.get_buffer(), lengths.PaddedBlockBitLength(), plain); diff --git a/cdk/extra/yassl/taocrypt/src/sha.cpp b/cdk/extra/yassl/taocrypt/src/sha.cpp index 4206f7f64..0b2f39ee6 100644 --- a/cdk/extra/yassl/taocrypt/src/sha.cpp +++ b/cdk/extra/yassl/taocrypt/src/sha.cpp @@ -142,8 +142,8 @@ void SHA384::Init() SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -154,8 +154,8 @@ SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), SHA256::SHA256(const SHA256& that) : HASHwithTransform(DIGEST_SIZE / - sizeof(word32), BLOCK_SIZE) -{ + sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -166,8 +166,8 @@ SHA256::SHA256(const SHA256& that) : HASHwithTransform(DIGEST_SIZE / SHA224::SHA224(const SHA224& that) : HASHwithTransform(SHA256::DIGEST_SIZE / - sizeof(word32), BLOCK_SIZE) -{ + sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -177,11 +177,11 @@ SHA224::SHA224(const SHA224& that) : HASHwithTransform(SHA256::DIGEST_SIZE / } -#ifdef WORD64_AVAILABLE +#ifdef WORD64_AVAILABLE SHA512::SHA512(const SHA512& that) : HASH64withTransform(DIGEST_SIZE / - sizeof(word64), BLOCK_SIZE) -{ + sizeof(word64), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -192,8 +192,8 @@ SHA512::SHA512(const SHA512& that) : HASH64withTransform(DIGEST_SIZE / SHA384::SHA384(const SHA384& that) : HASH64withTransform(SHA512::DIGEST_SIZE / - sizeof(word64), BLOCK_SIZE) -{ + sizeof(word64), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -326,7 +326,7 @@ void SHA::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -368,14 +368,14 @@ void SHA::Transform() { word32 W[BLOCK_SIZE / sizeof(word32)]; - // Copy context->state[] to working vars + // Copy context->state[] to working vars word32 a = digest_[0]; word32 b = digest_[1]; word32 c = digest_[2]; word32 d = digest_[3]; word32 e = digest_[4]; - // 4 rounds of 20 operations each. Loop unrolled. + // 4 rounds of 20 operations each. Loop unrolled. R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); @@ -429,7 +429,7 @@ void SHA::Transform() #define h(i) T[(7-i)&7] #define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\ - d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) // for SHA256 #define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22)) @@ -439,22 +439,22 @@ void SHA::Transform() static const word32 K256[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; @@ -514,46 +514,46 @@ void SHA224::Transform() #ifdef WORD64_AVAILABLE static const word64 K512[80] = { - W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), - W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), - W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), - W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), - W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), - W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), - W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), - W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), - W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), - W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), - W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), - W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), - W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), - W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), - W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), - W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), - W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), - W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), - W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), - W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), - W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), - W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), - W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), - W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), - W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), - W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), - W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), - W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), - W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), - W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), - W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), - W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), - W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), - W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), - W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), - W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), - W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), - W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), - W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), - W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) }; @@ -582,7 +582,7 @@ static void Transform512(word64* digest_, word64* buffer_) R(12); R(13); R(14); R(15); } - // Add the working vars back into digest + // Add the working vars back into digest digest_[0] += a(0); digest_[1] += b(0); @@ -779,8 +779,8 @@ void SHA::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "a" (times) \ : "%esi", "%edx", "memory", "cc" \ @@ -808,7 +808,7 @@ void SHA::AsmTransform(const byte* data, word32 times) AS2( mov esp, ebp ) \ AS1( pop ebp ) \ AS1( emms ) \ - AS1( ret 8 ) + AS1( ret 8 ) #endif PROLOG() @@ -829,7 +829,7 @@ void SHA::AsmTransform(const byte* data, word32 times) #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif // byte reverse 16 words of input, 4 at a time, put on stack for W[] @@ -1007,12 +1007,12 @@ void SHA::AsmTransform(const byte* data, word32 times) // setup next round AS2( movd ebp, mm2 ) // times - + AS2( mov edi, DWORD PTR [esp + 64] ) // data - + AS2( add edi, 64 ) // next round of data AS2( mov [esp + 64], edi ) // restore - + AS1( dec ebp ) AS2( movd mm2, ebp ) #ifdef _MSC_VER @@ -1021,7 +1021,7 @@ void SHA::AsmTransform(const byte* data, word32 times) AS1( jnz 0b ) // loopStart #endif - // inline adjust + // inline adjust AS2( add esp, 68 ) // fix room on stack EPILOG() diff --git a/cdk/extra/yassl/taocrypt/test/test.cpp b/cdk/extra/yassl/taocrypt/test/test.cpp index a7d5cb3e8..fc1f0e876 100644 --- a/cdk/extra/yassl/taocrypt/test/test.cpp +++ b/cdk/extra/yassl/taocrypt/test/test.cpp @@ -1277,6 +1277,9 @@ int dsa_test() if (!verifier.Verify(digest, decoded)) return -90; + if (!verifier.Verify(digest, signature)) + return -91; + return 0; } diff --git a/cdk/extra/yassl/testsuite/test.hpp b/cdk/extra/yassl/testsuite/test.hpp index 3e15ce814..92d41706c 100644 --- a/cdk/extra/yassl/testsuite/test.hpp +++ b/cdk/extra/yassl/testsuite/test.hpp @@ -22,7 +22,6 @@ #define yaSSL_TEST_HPP #include "runtime.hpp" -#include "openssl/ssl.h" /* openssl compatibility test */ #include "error.hpp" #include #include @@ -56,6 +55,7 @@ #endif #define SOCKET_T int #endif /* _WIN32 */ +#include "openssl/ssl.h" /* openssl compatibility test */ #ifdef _MSC_VER @@ -469,9 +469,24 @@ inline void showPeer(SSL* ssl) if (peer) { char* issuer = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0); char* subject = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0); + X509_NAME_ENTRY* se = NULL; + ASN1_STRING* sd = NULL; + char* subCN = NULL; + X509_NAME* sub = X509_get_subject_name(peer); + int lastpos = -1; + if (sub) + lastpos = X509_NAME_get_index_by_NID(sub, NID_commonName, lastpos); + if (lastpos >= 0) { + se = X509_NAME_get_entry(sub, lastpos); + if (se) + sd = X509_NAME_ENTRY_get_data(se); + if (sd) + subCN = (char*)ASN1_STRING_data(sd); + } + + printf("peer's cert info:\n issuer : %s\n subject: %s\n" + " subject cn: %s\n", issuer, subject, subCN); - printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer, - subject); free(subject); free(issuer); } From d14eecb1d30c6fcb1f35d6263fef4152abb63499 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 9 Feb 2017 10:39:06 +0100 Subject: [PATCH 48/79] MYCPP-284: TLS Options implementation on DevAPI --- cdk/core/tests/session-t.cc | 5 ++ cdk/include/mysql/cdk/data_source.h | 6 +- .../mysql/cdk/foundation/connection_yassl.h | 1 + devapi/session.cc | 62 +++++++++++++---- devapi/tests/session-t.cc | 66 +++++++++++++++++++ include/mysql_devapi.h | 3 +- 6 files changed, 128 insertions(+), 15 deletions(-) diff --git a/cdk/core/tests/session-t.cc b/cdk/core/tests/session-t.cc index 21b26e617..aa4a0ae26 100644 --- a/cdk/core/tests/session-t.cc +++ b/cdk/core/tests/session-t.cc @@ -1032,6 +1032,11 @@ TEST_F(Session_core, tls_options) } } + if (ssl_ca.find('\\') == string::npos && ssl_ca.find('/') == string::npos) + { //not full path + ssl_ca = datadir + ssl_ca; + } + cout << "Setting CA to: " << ssl_ca << endl; tls_options.set_ca(ssl_ca); diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index b6d843d5a..16150130d 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -131,12 +131,16 @@ class TCPIP::Options : public ds::Options public: Options() +#ifdef WITH_SSL : m_tls_options(false) +#endif {} Options(const string &usr, const std::string *pwd =NULL) : ds::Options(usr, pwd) - , m_tls_options(false) + #ifdef WITH_SSL + ,m_tls_options(false) + #endif {} #ifdef WITH_SSL diff --git a/cdk/include/mysql/cdk/foundation/connection_yassl.h b/cdk/include/mysql/cdk/foundation/connection_yassl.h index 84c84dd78..cd7d764d5 100644 --- a/cdk/include/mysql/cdk/foundation/connection_yassl.h +++ b/cdk/include/mysql/cdk/foundation/connection_yassl.h @@ -75,6 +75,7 @@ class TLS::Options : m_use_tls(use_tls) {} + void set_use_tls(bool use_tls) { m_use_tls = use_tls; } bool use_tls() const { return m_use_tls; } void set_key(const string &key) { m_key = key; } diff --git a/devapi/session.cc b/devapi/session.cc index e9a580967..0979554fb 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -129,13 +129,18 @@ struct URI_parser , private endpoint::TCPIP , public parser::URI_processor { + +#ifdef WITH_SSL + // tls off by default on URI connection + cdk::connection::TLS::Options m_tls_opt = false; +#endif + URI_parser(const std::string &uri) { + parser::parse_conn_str(uri, *this); #ifdef WITH_SSL - // TLS OFF by default on URI - set_tls(false); + set_tls(m_tls_opt); #endif - parser::parse_conn_str(uri, *this); } @@ -173,14 +178,36 @@ struct URI_parser void key_val(const std::string &key) override { if (key == "ssl-enable") + { +#ifdef WITH_SSL + m_tls_opt.set_use_tls(true); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif + } + } + + void key_val(const std::string &key, const std::string &val) override + { + if (key == "ssl-ca") + { #ifdef WITH_SSL - set_tls(true); + m_tls_opt.set_ca(val); #else throw_error( - "Can not create TLS session - this connector is built" - " without TLS support." - ); + "Can not create TLS session - this connector is built" + " without TLS support." + ); #endif + } else + { + std::stringstream err; + err << "Unexpected key " << key << "=" << val << " on URI"; + throw_error(err.str().c_str()); + } } }; @@ -197,8 +224,8 @@ internal::XSession_base::XSession_base(SessionSettings settings) ); m_impl = new Impl( - static_cast(parser.get_endpoint()), - static_cast(parser)); + static_cast(parser.get_endpoint()), + static_cast(parser)); } else { @@ -246,16 +273,25 @@ internal::XSession_base::XSession_base(SessionSettings settings) ); if (settings.has_option(SessionSettings::SSL_ENABLE)) + { #ifdef WITH_SSL - opt.set_tls(settings[SessionSettings::SSL_ENABLE].get()); + cdk::connection::TLS::Options opt_ssl(settings[SessionSettings::SSL_ENABLE]); + + + if (settings.has_option(SessionSettings::SSL_CA)) + opt_ssl.set_ca(settings[SessionSettings::SSL_ENABLE].get()); + + opt.set_tls(opt_ssl); #else throw_error( - "Can not create TLS session - this connector is built" - " without TLS support." - ); + "Can not create TLS session - this connector is built" + " without TLS support." + ); #endif + } m_impl = new Impl(ep, opt); + } } CATCH_AND_WRAP diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 41e44eb78..e5df894c1 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -431,4 +431,70 @@ TEST_F(Sess, ssl_session) EXPECT_FALSE(cipher.empty()); } + + //using wrong ssl-ca and ssl-ca-path as SessionSettings + { + EXPECT_THROW( + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, "unknown") + , mysqlx::Error); + + + } + + //using wrong ssl-ca and ssl-ca-path on URI + { + std::stringstream bad_uri; + bad_uri << uri.str() << "&ssl-ca=" << "unknown.file" << "&ssl-ca-path=" << "unknown.path"; + + EXPECT_THROW(mysqlx::XSession sess(bad_uri.str()), mysqlx::Error); + } + + string ssl_ca; + string datadir; + + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard() + .sql("show global variables like 'ssl_ca'") + .execute(); + + ssl_ca = res.fetchOne().get(1); + + res = sess.bindToDefaultShard() + .sql("show global variables like 'datadir'") + .execute(); + + datadir = res.fetchOne().get(1); + + } + + std::cout << "ssl-ca:" << ssl_ca + << " datadir:" << datadir + << std::endl; + + if (ssl_ca.find('\\') == string::npos && ssl_ca.find('/') == string::npos) + { //not full path + ssl_ca = datadir + ssl_ca; + } + + uri << "&ssl-ca=" << ssl_ca; + + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } + } diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 3464200dc..c54c2b28f 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -516,7 +516,8 @@ class PUBLIC_API SessionSettings USER, PWD, DB, - SSL_ENABLE + SSL_ENABLE, + SSL_CA }; From 1c5042285b0c94acf4b3ba336852cd213ae4e110 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 9 Feb 2017 18:20:39 +0100 Subject: [PATCH 49/79] Merge from CDK: Upgrade YaSSL to 2.4.2. --- cdk/extra/yassl/CMakeLists.txt | 13 +- cdk/extra/yassl/README | 102 ++++++-- cdk/extra/yassl/certs/dsa-cert.pem | 38 +-- cdk/extra/yassl/include/crypto_wrapper.hpp | 9 +- .../include/openssl/generate_prefix_files.pl | 0 cdk/extra/yassl/include/openssl/ssl.h | 11 +- cdk/extra/yassl/include/yassl_error.hpp | 3 +- cdk/extra/yassl/include/yassl_int.hpp | 12 +- cdk/extra/yassl/src/buffer.cpp | 2 +- cdk/extra/yassl/src/cert_wrapper.cpp | 45 ++-- cdk/extra/yassl/src/crypto_wrapper.cpp | 57 +++-- cdk/extra/yassl/src/handshake.cpp | 70 ++--- cdk/extra/yassl/src/lock.cpp | 18 +- cdk/extra/yassl/src/log.cpp | 7 +- cdk/extra/yassl/src/socket_wrapper.cpp | 12 +- cdk/extra/yassl/src/ssl.cpp | 130 +++++++--- cdk/extra/yassl/src/timer.cpp | 6 +- cdk/extra/yassl/src/yassl_error.cpp | 50 ++-- cdk/extra/yassl/src/yassl_imp.cpp | 162 ++++++------ cdk/extra/yassl/src/yassl_int.cpp | 58 +++-- cdk/extra/yassl/taocrypt/include/aes.hpp | 58 +++++ cdk/extra/yassl/taocrypt/include/asn.hpp | 15 +- cdk/extra/yassl/taocrypt/include/block.hpp | 2 +- cdk/extra/yassl/taocrypt/include/des.hpp | 6 +- cdk/extra/yassl/taocrypt/include/dh.hpp | 4 +- cdk/extra/yassl/taocrypt/include/dsa.hpp | 6 +- cdk/extra/yassl/taocrypt/include/error.hpp | 2 +- cdk/extra/yassl/taocrypt/include/file.hpp | 10 +- cdk/extra/yassl/taocrypt/include/hash.hpp | 4 +- cdk/extra/yassl/taocrypt/include/hmac.hpp | 8 +- cdk/extra/yassl/taocrypt/include/integer.hpp | 40 +-- cdk/extra/yassl/taocrypt/include/md5.hpp | 2 +- cdk/extra/yassl/taocrypt/include/misc.hpp | 44 ++-- cdk/extra/yassl/taocrypt/include/modarith.hpp | 4 +- cdk/extra/yassl/taocrypt/include/modes.hpp | 8 +- cdk/extra/yassl/taocrypt/include/rsa.hpp | 12 +- cdk/extra/yassl/taocrypt/include/runtime.hpp | 3 + cdk/extra/yassl/taocrypt/include/types.hpp | 9 +- cdk/extra/yassl/taocrypt/src/aes.cpp | 240 ++++++++++-------- cdk/extra/yassl/taocrypt/src/aestables.cpp | 2 +- cdk/extra/yassl/taocrypt/src/algebra.cpp | 6 +- cdk/extra/yassl/taocrypt/src/arc4.cpp | 16 +- cdk/extra/yassl/taocrypt/src/asn.cpp | 127 ++++----- cdk/extra/yassl/taocrypt/src/coding.cpp | 14 +- cdk/extra/yassl/taocrypt/src/des.cpp | 22 +- cdk/extra/yassl/taocrypt/src/dsa.cpp | 20 +- cdk/extra/yassl/taocrypt/src/file.cpp | 2 +- cdk/extra/yassl/taocrypt/src/hash.cpp | 8 +- cdk/extra/yassl/taocrypt/src/hc128.cpp | 122 ++++----- cdk/extra/yassl/taocrypt/src/integer.cpp | 28 +- cdk/extra/yassl/taocrypt/src/md2.cpp | 2 +- cdk/extra/yassl/taocrypt/src/md4.cpp | 10 +- cdk/extra/yassl/taocrypt/src/md5.cpp | 28 +- cdk/extra/yassl/taocrypt/src/misc.cpp | 2 +- cdk/extra/yassl/taocrypt/src/rabbit.cpp | 12 +- cdk/extra/yassl/taocrypt/src/random.cpp | 2 +- cdk/extra/yassl/taocrypt/src/ripemd.cpp | 32 +-- cdk/extra/yassl/taocrypt/src/rsa.cpp | 8 +- cdk/extra/yassl/taocrypt/src/sha.cpp | 160 ++++++------ cdk/extra/yassl/taocrypt/test/test.cpp | 3 + cdk/extra/yassl/testsuite/test.hpp | 21 +- 61 files changed, 1134 insertions(+), 795 deletions(-) mode change 100644 => 100755 cdk/extra/yassl/include/openssl/generate_prefix_files.pl diff --git a/cdk/extra/yassl/CMakeLists.txt b/cdk/extra/yassl/CMakeLists.txt index 0dcbed914..d09eedbe6 100644 --- a/cdk/extra/yassl/CMakeLists.txt +++ b/cdk/extra/yassl/CMakeLists.txt @@ -17,10 +17,9 @@ INCLUDE(install_macros) INCLUDE(msvc) INCLUDE_DIRECTORIES( - ${CMAKE_BINARY_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/include - ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/mySTL) + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/include + ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/mySTL) ADD_DEFINITIONS(${SSL_DEFINES}) @@ -49,8 +48,8 @@ CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) ADD_DEFINITIONS(-DSIZEOF_LONG=${SIZEOF_LONG} -DSIZEOF_LONG_LONG=${SIZEOF_LONG_LONG}) SET(YASSL_SOURCES src/buffer.cpp src/cert_wrapper.cpp src/crypto_wrapper.cpp src/handshake.cpp src/lock.cpp - src/log.cpp src/socket_wrapper.cpp src/ssl.cpp src/timer.cpp src/yassl_error.cpp - src/yassl_imp.cpp src/yassl_int.cpp) + src/log.cpp src/socket_wrapper.cpp src/ssl.cpp src/timer.cpp src/yassl_error.cpp + src/yassl_imp.cpp src/yassl_int.cpp) ADD_LIBRARY(yassl STATIC ${YASSL_SOURCES}) #RESTRICT_SYMBOL_EXPORTS(yassl) @@ -68,4 +67,4 @@ ENDIF() # if(NOT WINDOWS_RUNTIME_MD) # CHANGE_MD_2_MT() # endif() -#endif() \ No newline at end of file +#endif() diff --git a/cdk/extra/yassl/README b/cdk/extra/yassl/README index d245d20ce..32a505438 100644 --- a/cdk/extra/yassl/README +++ b/cdk/extra/yassl/README @@ -2,7 +2,7 @@ yaSSL takes a different approach to certificate verification than OpenSSL does. The default policy for the client is to verify the server, this means that if -you don't load CAs to verify the server you'll get a connect error, unable to +you don't load CAs to verify the server you'll get a connect error, unable to verify. It you want to mimic OpenSSL behavior of not verifying the server and reducing security you can do this by calling: @@ -12,6 +12,66 @@ before calling SSL_new(); *** end Note *** +yaSSL Release notes, version 2.4.2 (9/22/2016) + This release of yaSSL fixes a medium security vulnerability. A fix for + potential AES side channel leaks is included that a local user monitoring + the same CPU core cache could exploit. VM users, hyper-threading users, + and users where potential attackers have access to the CPU cache will need + to update if they utilize AES. + + DSA padding fixes for unusual sizes is included as well. Users with DSA + certficiates should update. + +yaSSL Release notes, version 2.4.0 (5/20/2016) + This release of yaSSL fixes the OpenSSL compatibility function + SSL_CTX_load_verify_locations() when using the path directory to allow + unlimited path sizes. Minor Windows build fixes are included. + No high level security fixes in this version but we always recommend + updating. + + +yaSSL Release notes, version 2.3.9b (2/03/2016) + This release of yaSSL fixes the OpenSSL compatibility function + X509_NAME_get_index_by_NID() to use the actual index of the common name + instead of searching on the format prefix. Thanks for the report from + yashwant.sahu@oracle.com . Anyone using this function should update. + +yaSSL Release notes, version 2.3.9 (12/01/2015) + This release of yaSSL fixes two client side Diffie-Hellman problems. + yaSSL was only handling the cases of zero or one leading zeros for the key + agreement instead of potentially any number. This caused about 1 in 50,000 + connections to fail when using DHE cipher suites. The second problem was + the case where a server would send a public value shorter than the prime + value, causing about 1 in 128 client connections to fail, and also + caused the yaSSL client to read off the end of memory. All client side + DHE cipher suite users should update. + Thanks to Adam Langely (agl@imperialviolet.org) for the detailed report! + +yaSSL Release notes, version 2.3.8 (9/17/2015) + This release of yaSSL fixes a high security vulnerability. All users + SHOULD update. If using yaSSL for TLS on the server side with private + RSA keys allowing ephemeral key exchange you MUST update and regenerate + the RSA private keys. This report is detailed in: + https://people.redhat.com/~fweimer/rsa-crt-leaks.pdf + yaSSL now detects RSA signature faults and returns an error. + +yaSSL Patch notes, version 2.3.7e (6/26/2015) + This release of yaSSL includes a fix for Date less than comparison. + Previously yaSSL would return true on less than comparisons if the Dates + were equal. Reported by Oracle. No security problem, but if a cert was + generated right now, a server started using it in the same second, and a + client tried to verify it in the same second it would report not yet valid. + +yaSSL Patch notes, version 2.3.7d (6/22/2015) + This release of yaSSL includes a fix for input_buffer set_current with + index 0. SSL_peek() at front of waiting data could trigger. Robert + Golebiowski of Oracle identified and suggested a fix, thanks! + +yaSSL Patch notes, version 2.3.7c (6/12/2015) + This release of yaSSL does certificate DATE comparisons to the second + instead of to the minute, helpful when using freshly generated certs. + Though keep in mind that time sync differences could still show up. + yaSSL Patch notes, version 2.3.7b (3/18/2015) This release of yaSSL fixes a potential crash with corrupted private keys. Also detects bad keys earlier for user. @@ -24,7 +84,7 @@ yaSSL Release notes, version 2.3.6 (11/25/2014) This release of yaSSL fixes some valgrind warnings/errors including uninitialized reads and off by one index errors induced from fuzzing - the handshake. These were reported by Oracle. + the handshake. These were reported by Oracle. yaSSL Release notes, version 2.3.5 (9/29/2014) @@ -113,7 +173,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. This release of yaSSL contains bug fixes, the removal of assert() s and a security patch for a buffer overflow possibility in certificate name - processing. + processing. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -141,7 +201,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.9.2 (9/24/08) This release of yaSSL contains bug fixes and improved certificate verify - callback support. + callback support. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -149,7 +209,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.8.8 (5/7/08) - This release of yaSSL contains bug fixes, and better socket handling. + This release of yaSSL contains bug fixes, and better socket handling. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -159,7 +219,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. This release of yaSSL contains bug fixes, and fixes security problems associated with using SSL 2.0 client hellos and improper input handling. - Please upgrade to this version if you are using a previous one. + Please upgrade to this version if you are using a previous one. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -168,7 +228,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.7.5 (10/15/07) This release of yaSSL contains bug fixes, adds MSVC 2005 project support, - GCC 4.2 support, IPV6 support and test, and new test certificates. + GCC 4.2 support, IPV6 support and test, and new test certificates. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -177,7 +237,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.7.2 (8/20/07) This release of yaSSL contains bug fixes and adds initial OpenVPN support. - Just configure at this point and beginning of build. + Just configure at this point and beginning of build. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -208,8 +268,8 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. Since yaSSL now supports zlib, as does libcurl, the libcurl build test can - fail if yaSSL is built with zlib support since the zlib library isn't - passed. You can do two things to fix this: + fail if yaSSL is built with zlib support since the zlib library isn't + passed. You can do two things to fix this: 1) build yaSSL w/o zlib --without-zlib 2) or add flags to curl configure LDFLAGS="-lm -lz" @@ -223,7 +283,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. SSL_METHOD *TLSv1_1_server_method(void); SSL_METHOD *TLSv1_1_client_method(void); - + or the SSLv23 versions (even though yaSSL doesn't support SSL 2.0 the v23 means to pick the highest of SSL 3.0, TLS 1.0, or TLS 1.1). @@ -260,7 +320,7 @@ See libcurl build instructions below under 1.3.0. 2) follow the instructions in zlib from projects/visualc6/README.txt for how to add the zlib project into the yaSSL workspace noting that you'll need to add configuration support for "Win32 Debug" and - "Win32 Release" in note 3 under "To use:". + "Win32 Release" in note 3 under "To use:". 3) define HAVE_LIBZ when building yaSSL @@ -272,7 +332,7 @@ See libcurl build instructions below under 1.3.0. This release of yaSSL contains bug fixes, portability enhancements, - nonblocking connect and accept, better OpenSSL error mapping, and + nonblocking connect and accept, better OpenSSL error mapping, and certificate caching for session resumption. See normal build instructions below under 1.0.6. @@ -283,7 +343,7 @@ See libcurl build instructions below under 1.3.0. This release of yaSSL contains bug fixes, portability enhancements, - and libcurl 7.15.4 support (any newer versions may not build). + and libcurl 7.15.4 support (any newer versions may not build). See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0. @@ -325,12 +385,12 @@ See normal build instructions below under 1.0.6. --To build for libcurl on Win32: - Simply add the yaSSL project as a dependency to libcurl, add + Simply add the yaSSL project as a dependency to libcurl, add yaSSL-Home\include and yaSSL-Home\include\openssl to the include list, and define USE_SSLEAY and USE_OPENSSL please email todd@yassl.com if you have any questions. - + *******************yaSSL Release notes, version 1.2.2 (03/27/06) @@ -523,8 +583,8 @@ Please see build instructions in release notes 0.3.0. ******************yaSSL Release notes, version 0.4.0 This release of yaSSL contains minor bug fixes, an optional memory tracker, -an echo client and server with input/output redirection for load testing, -and initial session caching support. +an echo client and server with input/output redirection for load testing, +and initial session caching support. Please see build instructions in release notes 0.3.0. @@ -572,7 +632,7 @@ See the notes at the bottom of this page for build instructions. *******************yaSSL Release notes, version 0.2.0 This release of yaSSL contains minor bug fixes and initial alternate crypto -functionality. +functionality. *** Complete Build *** @@ -588,7 +648,7 @@ gzip -cd yassl-update-0.2.0.tar.gz | tar xvf - to update the previous release. -Then issue the make command on linux or rebuild the yaSSL project on Windows. +Then issue the make command on linux or rebuild the yaSSL project on Windows. *******************yaSSL Release notes, version 0.1.0 @@ -648,7 +708,7 @@ Building yassl on linux: use the ./buildall script to build everything. -buildall will configure and build CML, CryptoPP, and yassl. Testing was +buildall will configure and build CML, CryptoPP, and yassl. Testing was preformed with gcc version 3.3.2 on kernel 2.4.22. diff --git a/cdk/extra/yassl/certs/dsa-cert.pem b/cdk/extra/yassl/certs/dsa-cert.pem index 10d533edc..10794cbee 100644 --- a/cdk/extra/yassl/certs/dsa-cert.pem +++ b/cdk/extra/yassl/certs/dsa-cert.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDqzCCA2ugAwIBAgIJAMGqrgDU6DyhMAkGByqGSM44BAMwgY4xCzAJBgNVBAYT +MIIDrzCCA2+gAwIBAgIJAK1zRM7YFcNjMAkGByqGSM44BAMwgZAxCzAJBgNVBAYT AlVTMQ8wDQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQK -DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wu -Y29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTEzMDQyMjIw -MDk0NFoXDTE2MDExNzIwMDk0NFowgY4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZP -cmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQKDAd3b2xmU1NMMRAwDgYD -VQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wuY29tMR8wHQYJKoZIhvcN -AQkBFhBpbmZvQHdvbGZzc2wuY29tMIIBuDCCASwGByqGSM44BAEwggEfAoGBAL1R -7koy4IrH6sbh6nDEUUPPKgfhxxLCWCVexF2+qzANEr+hC9M002haJXFOfeS9DyoO -WFbL0qMZOuqv+22CaHnoUWl7q3PjJOAI3JH0P54ZyUPuU1909RzgTdIDp5+ikbr7 -KYjnltL73FQVMbjTZQKthIpPn3MjYcF+4jp2W2zFAhUAkcntYND6MGf+eYzIJDN2 -L7SonHUCgYEAklpxErfqznIZjVvqqHFaq+mgAL5J8QrKVmdhYZh/Y8z4jCjoCA8o -TDoFKxf7s2ZzgaPKvglaEKiYqLqic9qY78DYJswzQMLFvjsF4sFZ+pYCBdWPQI4N -PgxCiznK6Ce+JH9ikSBvMvG+tevjr2UpawDIHX3+AWYaZBZwKADAaboDgYUAAoGB -AJ3LY89yHyvQ/TsQ6zlYbovjbk/ogndsMqPdNUvL4RuPTgJP/caaDDa0XJ7ak6A7 -TJ+QheLNwOXoZPYJC4EGFSDAXpYniGhbWIrVTCGe6lmZDfnx40WXS0kk3m/DHaC0 -3ElLAiybxVGxyqoUfbT3Zv1JwftWMuiqHH5uADhdXuXVo1AwTjAdBgNVHQ4EFgQU -IJjk416o4v8qpH9LBtXlR9v8gccwHwYDVR0jBBgwFoAUIJjk416o4v8qpH9LBtXl -R9v8gccwDAYDVR0TBAUwAwEB/zAJBgcqhkjOOAQDAy8AMCwCFCjGKIdOSV12LcTu -k08owGM6YkO1AhQe+K173VuaO/OsDNsxZlKpyH8+1g== +DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz +bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMTYwOTIy +MjEyMzA0WhcNMjIwMzE1MjEyMzA0WjCBkDELMAkGA1UEBhMCVVMxDzANBgNVBAgM +Bk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxEDAOBgNVBAoMB3dvbGZTU0wxEDAO +BgNVBAsMB3Rlc3RpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG +SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCAbgwggEsBgcqhkjOOAQBMIIBHwKB +gQC9Ue5KMuCKx+rG4epwxFFDzyoH4ccSwlglXsRdvqswDRK/oQvTNNNoWiVxTn3k +vQ8qDlhWy9KjGTrqr/ttgmh56FFpe6tz4yTgCNyR9D+eGclD7lNfdPUc4E3SA6ef +opG6+ymI55bS+9xUFTG402UCrYSKT59zI2HBfuI6dltsxQIVAJHJ7WDQ+jBn/nmM +yCQzdi+0qJx1AoGBAJJacRK36s5yGY1b6qhxWqvpoAC+SfEKylZnYWGYf2PM+Iwo +6AgPKEw6BSsX+7Nmc4Gjyr4JWhComKi6onPamO/A2CbMM0DCxb47BeLBWfqWAgXV +j0CODT4MQos5yugnviR/YpEgbzLxvrXr469lKWsAyB19/gFmGmQWcCgAwGm6A4GF +AAKBgQCdy2PPch8r0P07EOs5WG6L425P6IJ3bDKj3TVLy+Ebj04CT/3Gmgw2tFye +2pOgO0yfkIXizcDl6GT2CQuBBhUgwF6WJ4hoW1iK1UwhnupZmQ358eNFl0tJJN5v +wx2gtNxJSwIsm8VRscqqFH2092b9ScH7VjLoqhx+bgA4XV7l1aNQME4wHQYDVR0O +BBYEFCCY5ONeqOL/KqR/SwbV5Ufb/IHHMB8GA1UdIwQYMBaAFCCY5ONeqOL/KqR/ +SwbV5Ufb/IHHMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwMvADAsAhQRYSCVN/Ge +agV3mffU3qNZ92fI0QIUPH7Jp+iASI7U1ocaYDc10qXGaGY= -----END CERTIFICATE----- diff --git a/cdk/extra/yassl/include/crypto_wrapper.hpp b/cdk/extra/yassl/include/crypto_wrapper.hpp index db9136c53..84419e342 100644 --- a/cdk/extra/yassl/include/crypto_wrapper.hpp +++ b/cdk/extra/yassl/include/crypto_wrapper.hpp @@ -17,7 +17,7 @@ */ -/* The crypto wrapper header is used to define policies for the cipher +/* The crypto wrapper header is used to define policies for the cipher * components used by SSL. There are 3 policies to consider: * * 1) MAC, the Message Authentication Code used for each Message @@ -174,7 +174,7 @@ class HMAC_RMD : public Digest { }; -// BulkCipher policy should implement encrypt, decrypt, get block size, +// BulkCipher policy should implement encrypt, decrypt, get block size, // and set keys for encrypt and decrypt struct BulkCipher : public virtual_base { virtual void encrypt(byte*, const byte*, unsigned int) = 0; @@ -318,7 +318,7 @@ struct Auth : public virtual_base { // For use with NULL Authentication schemes struct NO_Auth : public Auth { void sign(byte*, const byte*, unsigned int, const RandomPool&) {} - bool verify(const byte*, unsigned int, const byte*, unsigned int) + bool verify(const byte*, unsigned int, const byte*, unsigned int) { return true; } }; @@ -372,11 +372,12 @@ class DiffieHellman { DiffieHellman(const Integer&, const Integer&, const RandomPool&); ~DiffieHellman(); - DiffieHellman(const DiffieHellman&); + DiffieHellman(const DiffieHellman&); DiffieHellman& operator=(const DiffieHellman&); uint get_agreedKeyLength() const; const byte* get_agreedKey() const; + uint get_publicKeyLength() const; const byte* get_publicKey() const; void makeAgreement(const byte*, unsigned int); diff --git a/cdk/extra/yassl/include/openssl/generate_prefix_files.pl b/cdk/extra/yassl/include/openssl/generate_prefix_files.pl old mode 100644 new mode 100755 diff --git a/cdk/extra/yassl/include/openssl/ssl.h b/cdk/extra/yassl/include/openssl/ssl.h index becf7aacd..37654ab71 100644 --- a/cdk/extra/yassl/include/openssl/ssl.h +++ b/cdk/extra/yassl/include/openssl/ssl.h @@ -34,7 +34,7 @@ #include "rsa.h" -#define YASSL_VERSION "2.3.7b" +#define YASSL_VERSION "2.4.2" #if defined(__cplusplus) @@ -335,9 +335,6 @@ enum { /* ssl Constants */ SSL_OP_ALL = 61, SSL_OP_SINGLE_DH_USE = 62, SSL_OP_EPHEMERAL_RSA = 63, - SSL_OP_NO_SSLv2 = 64, - SSL_OP_NO_SSLv3 = 65, - SSL_OP_NO_TLSv1 = 66, SSL_OP_PKCS1_CHECK_1 = 67, SSL_OP_PKCS1_CHECK_2 = 68, SSL_OP_NETSCAPE_CA_DN_BUG = 69, @@ -358,8 +355,12 @@ enum { /* ssl Constants */ SSL_RECEIVED_SHUTDOWN = 94, SSL_CB_ALERT = 95, SSL_CB_READ = 96, - SSL_CB_HANDSHAKE_DONE = 97 + SSL_CB_HANDSHAKE_DONE = 97, + SSL_OP_NO_SSLv2 = 128, + SSL_OP_NO_SSLv3 = 256, + SSL_OP_NO_TLSv1 = 512, + SSL_OP_NO_TLSv1_1 = 1024, }; diff --git a/cdk/extra/yassl/include/yassl_error.hpp b/cdk/extra/yassl/include/yassl_error.hpp index beba7b0b5..d63244dca 100644 --- a/cdk/extra/yassl/include/yassl_error.hpp +++ b/cdk/extra/yassl/include/yassl_error.hpp @@ -53,7 +53,8 @@ enum YasslError { compress_error = 118, decompress_error = 119, pms_version_error = 120, - sanityCipher_error = 121 + sanityCipher_error = 121, + rsaSignFault_error = 122 // !!!! add error message to .cpp !!!! diff --git a/cdk/extra/yassl/include/yassl_int.hpp b/cdk/extra/yassl/include/yassl_int.hpp index 85cbbc966..b360b7775 100644 --- a/cdk/extra/yassl/include/yassl_int.hpp +++ b/cdk/extra/yassl/include/yassl_int.hpp @@ -53,7 +53,6 @@ char* yassl_get_tty_password(const char*); #define get_tty_password yassl_get_tty_password - namespace STL = STL_NAMESPACE; @@ -201,14 +200,19 @@ class sslFactory { class X509_NAME { char* name_; size_t sz_; + int cnPosition_; // start of common name, -1 is none + int cnLen_; // length of above ASN1_STRING entry_; public: - X509_NAME(const char*, size_t sz); + X509_NAME(const char*, size_t sz, int pos, int len); ~X509_NAME(); const char* GetName() const; ASN1_STRING* GetEntry(int i); size_t GetLength() const; + int GetCnPosition() const { return cnPosition_; } + int GetCnLength() const { return cnLen_; } + private: X509_NAME(const X509_NAME&); // hide copy X509_NAME& operator=(const X509_NAME&); // and assign @@ -236,7 +240,7 @@ class X509 { StringHolder afterDate_; // not valid after public: X509(const char* i, size_t, const char* s, size_t, - ASN1_STRING *b, ASN1_STRING *a); + ASN1_STRING *b, ASN1_STRING *a, int, int, int, int); ~X509() {} X509_NAME* GetIssuer(); @@ -488,7 +492,7 @@ class SSL_CTX { void SetUserData(void*); void SetSessionCacheOff(); void SetSessionCacheFlushOff(); - + void SetMethod(SSL_METHOD* meth); void IncrementStats(StatsField); void AddCA(x509* ca); const CertList& GetCA_List() const; diff --git a/cdk/extra/yassl/src/buffer.cpp b/cdk/extra/yassl/src/buffer.cpp index 07325c0e2..e5a996b7f 100644 --- a/cdk/extra/yassl/src/buffer.cpp +++ b/cdk/extra/yassl/src/buffer.cpp @@ -162,7 +162,7 @@ void input_buffer::set_error() void input_buffer::set_current(uint i) { - if (error_ == 0 && i && check(i - 1, size_) == 0) + if (error_ == 0 && check(i ? i - 1 : 0, size_) == 0) current_ = i; else error_ = -1; diff --git a/cdk/extra/yassl/src/cert_wrapper.cpp b/cdk/extra/yassl/src/cert_wrapper.cpp index af94f5bc2..96c8e94fa 100644 --- a/cdk/extra/yassl/src/cert_wrapper.cpp +++ b/cdk/extra/yassl/src/cert_wrapper.cpp @@ -37,14 +37,14 @@ namespace yaSSL { -x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) +x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) { } -x509::~x509() -{ - ysArrayDelete(buffer_); +x509::~x509() +{ + ysArrayDelete(buffer_); } @@ -71,20 +71,20 @@ x509& x509::operator=(const x509& that) uint x509::get_length() const -{ - return length_; +{ + return length_; } const opaque* x509::get_buffer() const -{ - return buffer_; +{ + return buffer_; } opaque* x509::use_buffer() -{ - return buffer_; +{ + return buffer_; } @@ -173,7 +173,7 @@ void CertManager::setVerifyCallback(VerifyCallback vc) void CertManager::AddPeerCert(x509* x) -{ +{ peerList_.push_back(x); // take ownership } @@ -203,13 +203,13 @@ int CertManager::CopyCaCert(const x509* x) const x509* CertManager::get_cert() const -{ +{ return list_.front(); } const opaque* CertManager::get_peerKey() const -{ +{ return peerPublicKey_.get_buffer(); } @@ -239,19 +239,19 @@ SignatureAlgorithm CertManager::get_keyType() const uint CertManager::get_peerKeyLength() const -{ +{ return peerPublicKey_.get_size(); } const opaque* CertManager::get_privateKey() const -{ +{ return privateKey_.get_buffer(); } uint CertManager::get_privateKeyLength() const -{ +{ return privateKey_.get_size(); } @@ -304,7 +304,10 @@ int CertManager::Validate() afterDate.type= cert.GetAfterDateType(); afterDate.length= strlen((char *) afterDate.data) + 1; peerX509_ = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength() + ); if (err == TaoCrypt::SIG_OTHER_E && verifyCallback_) { X509_STORE_CTX store; @@ -350,7 +353,9 @@ int CertManager::SetPrivateKey(const x509& key) afterDate.type= cd.GetAfterDateType(); afterDate.length= strlen((char *) afterDate.data) + 1; selfX509_ = NEW_YS X509(cd.GetIssuer(), iSz, cd.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cd.GetIssuerCnStart(), cd.GetIssuerCnLength(), + cd.GetSubjectCnStart(), cd.GetSubjectCnLength()); } return 0; } @@ -367,7 +372,9 @@ void CertManager::setPeerX509(X509* x) ASN1_STRING* after = x->GetAfter(); peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), - subject->GetName(), subject->GetLength(), before, after); + subject->GetName(), subject->GetLength(), before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); } diff --git a/cdk/extra/yassl/src/crypto_wrapper.cpp b/cdk/extra/yassl/src/crypto_wrapper.cpp index 529943645..e9b4586da 100644 --- a/cdk/extra/yassl/src/crypto_wrapper.cpp +++ b/cdk/extra/yassl/src/crypto_wrapper.cpp @@ -58,7 +58,7 @@ MD5::MD5() : pimpl_(NEW_YS MD5Impl) {} MD5::~MD5() { ysDelete(pimpl_); } -MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS +MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS MD5Impl(that.pimpl_->md5_)) {} @@ -223,8 +223,8 @@ struct HMAC_MD5::HMAC_MD5Impl { }; -HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_MD5Impl) +HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_MD5Impl) { pimpl_->mac_.SetKey(secret, len); } @@ -273,8 +273,8 @@ struct HMAC_SHA::HMAC_SHAImpl { }; -HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_SHAImpl) +HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_SHAImpl) { pimpl_->mac_.SetKey(secret, len); } @@ -324,8 +324,8 @@ struct HMAC_RMD::HMAC_RMDImpl { }; -HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_RMDImpl) +HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_RMDImpl) { pimpl_->mac_.SetKey(secret, len); } @@ -536,7 +536,7 @@ RandomPool::~RandomPool() { ysDelete(pimpl_); } int RandomPool::GetError() const { - return pimpl_->RNG_.GetError(); + return pimpl_->RNG_.GetError(); } void RandomPool::Fill(opaque* dst, uint sz) const @@ -573,10 +573,10 @@ void DSS::DSSImpl::SetPrivate(const byte* key, unsigned int sz) // Set public or private key -DSS::DSS(const byte* key, unsigned int sz, bool publicKey) +DSS::DSS(const byte* key, unsigned int sz, bool publicKey) : pimpl_(NEW_YS DSSImpl) { - if (publicKey) + if (publicKey) pimpl_->SetPublic(key, sz); else pimpl_->SetPrivate(key, sz); @@ -644,10 +644,10 @@ void RSA::RSAImpl::SetPrivate(const byte* key, unsigned int sz) // Set public or private key -RSA::RSA(const byte* key, unsigned int sz, bool publicKey) +RSA::RSA(const byte* key, unsigned int sz, bool publicKey) : pimpl_(NEW_YS RSAImpl) { - if (publicKey) + if (publicKey) pimpl_->SetPublic(key, sz); else pimpl_->SetPrivate(key, sz); @@ -695,7 +695,7 @@ bool RSA::verify(const byte* message, unsigned int sz, const byte* sig, void RSA::encrypt(byte* cipher, const byte* plain, unsigned int sz, const RandomPool& random) { - + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); enc.Encrypt(plain, sz, cipher, random.pimpl_->RNG_); } @@ -723,7 +723,7 @@ Integer::~Integer() { ysDelete(pimpl_); } -Integer::Integer(const Integer& other) : pimpl_(NEW_YS +Integer::Integer(const Integer& other) : pimpl_(NEW_YS IntegerImpl(other.pimpl_->int_)) {} @@ -748,18 +748,19 @@ struct DiffieHellman::DHImpl { byte* publicKey_; byte* privateKey_; byte* agreedKey_; + uint pubKeyLength_; DHImpl(TaoCrypt::RandomNumberGenerator& r) : ranPool_(r), publicKey_(0), - privateKey_(0), agreedKey_(0) {} - ~DHImpl() - { - ysArrayDelete(agreedKey_); - ysArrayDelete(privateKey_); + privateKey_(0), agreedKey_(0), pubKeyLength_(0) {} + ~DHImpl() + { + ysArrayDelete(agreedKey_); + ysArrayDelete(privateKey_); ysArrayDelete(publicKey_); } DHImpl(const DHImpl& that) : dh_(that.dh_), ranPool_(that.ranPool_), - publicKey_(0), privateKey_(0), agreedKey_(0) + publicKey_(0), privateKey_(0), agreedKey_(0), pubKeyLength_(0) { uint length = dh_.GetByteLength(); AllocKeys(length, length, length); @@ -807,7 +808,7 @@ DiffieHellman::DiffieHellman(const byte* p, unsigned int pSz, const byte* g, using TaoCrypt::Integer; pimpl_->dh_.Initialize(Integer(p, pSz).Ref(), Integer(g, gSz).Ref()); - pimpl_->publicKey_ = NEW_YS opaque[pubSz]; + pimpl_->publicKey_ = NEW_YS opaque[pimpl_->pubKeyLength_ = pubSz]; memcpy(pimpl_->publicKey_, pub, pubSz); } @@ -832,9 +833,9 @@ DiffieHellman::~DiffieHellman() { ysDelete(pimpl_); } // Client side and view, use server that for p and g -DiffieHellman::DiffieHellman(const DiffieHellman& that) +DiffieHellman::DiffieHellman(const DiffieHellman& that) : pimpl_(NEW_YS DHImpl(*that.pimpl_)) -{ +{ pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, pimpl_->publicKey_); } @@ -851,7 +852,7 @@ DiffieHellman& DiffieHellman::operator=(const DiffieHellman& that) void DiffieHellman::makeAgreement(const byte* other, unsigned int otherSz) { - pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); + pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); } @@ -866,6 +867,10 @@ const byte* DiffieHellman::get_agreedKey() const return pimpl_->agreedKey_; } +uint DiffieHellman::get_publicKeyLength() const +{ + return pimpl_->pubKeyLength_; +} const byte* DiffieHellman::get_publicKey() const { @@ -954,7 +959,7 @@ x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) if (fgets(line,sizeof(line), file)) // get blank line begin = ftell(file); } - + } while(fgets(line, sizeof(line), file)) @@ -973,7 +978,7 @@ x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) size_t bytes = fread(tmp.get_buffer(), end - begin, 1, file); if (bytes != 1) return 0; - + Source der(tmp.get_buffer(), end - begin); Base64Decoder b64Dec(der); diff --git a/cdk/extra/yassl/src/handshake.cpp b/cdk/extra/yassl/src/handshake.cpp index e63d69e9e..212163e6b 100644 --- a/cdk/extra/yassl/src/handshake.cpp +++ b/cdk/extra/yassl/src/handshake.cpp @@ -44,7 +44,7 @@ void buildClientHello(SSL& ssl, ClientHello& hello) memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), ID_LEN); } - else + else hello.id_len_ = 0; hello.suite_len_ = ssl.getSecurity().get_parms().suites_size_; memcpy(hello.cipher_suites_, ssl.getSecurity().get_parms().suites_, @@ -87,7 +87,7 @@ void buildServerHello(SSL& ssl, ServerHello& hello) // add handshake from buffer into md5 and sha hashes, use handshake header void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) { - const opaque* buffer = input.get_buffer() + input.get_current() - + const opaque* buffer = input.get_buffer() + input.get_current() - HANDSHAKE_HEADER; sz += HANDSHAKE_HEADER; ssl.useHashes().use_MD5().update(buffer, sz); @@ -99,7 +99,7 @@ void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) namespace { // Write a plaintext record to buffer -void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, const Message& msg) { buffer.allocate(RECORD_HEADER + rlHdr.length_); @@ -108,7 +108,7 @@ void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, // Write a plaintext record to buffer -void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, const HandShakeHeader& hsHdr, const HandShakeBase& shake) { buffer.allocate(RECORD_HEADER + rlHdr.length_); @@ -170,7 +170,7 @@ void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) opaque md5_inner[SIZEOF_SENDER + SECRET_LEN + PAD_MD5]; opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make md5 inner @@ -194,12 +194,12 @@ void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) // calculate SHA hash for finished void buildSHA(SSL& ssl, Finished& fin, const opaque* sender) { - + opaque sha_result[SHA_LEN]; opaque sha_inner[SIZEOF_SENDER + SECRET_LEN + PAD_SHA]; opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make sha inner @@ -309,7 +309,7 @@ void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) uint ivSz = iv.get_size(); output.allocate(sz); output << rlHeader << iv << hsHeader << fin; - + hashHandShake(ssl, output, ssl.isTLSv1_1() ? true : false); opaque digest[SHA_LEN]; // max size if (ssl.isTLS()) @@ -335,7 +335,7 @@ void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) { uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); - uint sz = RECORD_HEADER + msg.get_length() + digestSz; + uint sz = RECORD_HEADER + msg.get_length() + digestSz; uint pad = 0; uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); @@ -358,11 +358,11 @@ void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) ssl.getCrypto().get_random().Fill(iv.get_buffer(), blockSz); iv.add_size(blockSz); } - + uint ivSz = iv.get_size(); output.allocate(sz); output << rlHeader << iv << msg; - + opaque digest[SHA_LEN]; // max size if (ssl.isTLS()) TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER + ivSz, @@ -397,7 +397,7 @@ void buildAlert(SSL& ssl, output_buffer& output, const Alert& alert) // build TLS finished message -void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) +void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) { opaque handshake_hash[FINISHED_SZ]; @@ -410,9 +410,9 @@ void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) else side = tls_server; - PRF(fin.set_md5(), TLS_FINISHED_SZ, - ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, - side, FINISHED_LABEL_SZ, + PRF(fin.set_md5(), TLS_FINISHED_SZ, + ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, + side, FINISHED_LABEL_SZ, handshake_hash, FINISHED_SZ); fin.set_length(TLS_FINISHED_SZ); // shorter length for TLS @@ -441,7 +441,7 @@ void p_hash(output_buffer& result, const output_buffer& secret, uint lastTime = times - 1; for (uint i = 0; i < times; i++) { - hmac->update(previous, len); + hmac->update(previous, len); hmac->get_digest(current, seed.get_buffer(), seed.get_size()); if (lastLen && (i == lastTime)) @@ -459,7 +459,7 @@ void p_hash(output_buffer& result, const output_buffer& secret, void get_xor(byte *digest, uint digLen, output_buffer& md5, output_buffer& sha) { - for (uint i = 0; i < digLen; i++) + for (uint i = 0; i < digLen; i++) digest[i] = md5[AUTO] ^ sha[AUTO]; } @@ -471,7 +471,7 @@ void buildMD5_CertVerify(SSL& ssl, byte* digest) opaque md5_inner[SECRET_LEN + PAD_MD5]; opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make md5 inner @@ -497,7 +497,7 @@ void buildSHA_CertVerify(SSL& ssl, byte* digest) opaque sha_inner[SECRET_LEN + PAD_SHA]; opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make sha inner @@ -572,7 +572,7 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) } int j = 0; - for (uint16 i = 0; i < ch.suite_len_; i += 3) { + for (uint16 i = 0; i < ch.suite_len_; i += 3) { byte first = input[AUTO]; if (first) // sslv2 type input.read(len, SUITE_LEN); // skip @@ -589,13 +589,13 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) if (randomLen < RAN_LEN) memset(ch.random_, 0, RAN_LEN - randomLen); input.read(&ch.random_[RAN_LEN - randomLen], randomLen); - + ch.Process(input, ssl); } // Build a finished message, see 7.6.9 -void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) +void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) { // store current states, building requires get_digest which resets state MD5 md5(ssl.getHashes().get_MD5()); @@ -623,7 +623,7 @@ void hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, { Digest& mac = ssl.useCrypto().use_digest(); opaque inner[SHA_LEN + PAD_MD5 + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ]; - opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; + opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; opaque result[SHA_LEN]; // max possible sizes uint digestSz = mac.get_digestSize(); // actual sizes uint padSz = mac.get_padSize(); @@ -676,11 +676,11 @@ void TLS_hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, hmac.reset(NEW_YS HMAC_RMD(ssl.get_macSecret(verify), RMD_LEN)); else hmac.reset(NEW_YS HMAC_MD5(ssl.get_macSecret(verify), MD5_LEN)); - + hmac->update(seq, SEQ_SZ); // seq_num inner[0] = content; // type - inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; - inner[SIZEOF_ENUM + SIZEOF_ENUM] = + inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; + inner[SIZEOF_ENUM + SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.minor_; // version memcpy(&inner[SIZEOF_ENUM + VERSION_SZ], length, LENGTH_SZ); // length hmac->update(inner, sizeof(inner)); @@ -760,14 +760,16 @@ int DoProcessReply(SSL& ssl) if (read == static_cast(-1)) { ssl.SetError(receive_error); return 0; - } + } else if (read == 0) + return 1; + buffer.add_size(read); uint offset = 0; const MessageFactory& mf = ssl.getFactory().getMessage(); // old style sslv2 client hello? if (ssl.getSecurity().get_parms().entity_ == server_end && - ssl.getStates().getServer() == clientNull) + ssl.getStates().getServer() == clientNull) if (buffer.peek() != handshake) { ProcessOldClientHello(buffer, ssl); if (ssl.GetError()) @@ -814,7 +816,7 @@ int DoProcessReply(SSL& ssl) if (ssl.GetError()) return 0; } - + mySTL::auto_ptr msg(mf.CreateObject(hdr.type_)); if (!msg.get()) { ssl.SetError(factory_error); @@ -835,7 +837,7 @@ int DoProcessReply(SSL& ssl) void processReply(SSL& ssl) { if (ssl.GetError()) return; - + if (DoProcessReply(ssl)) { // didn't complete process if (!ssl.getSocket().IsNonBlocking()) { @@ -934,7 +936,7 @@ void sendChangeCipher(SSL& ssl, BufferOutput buffer) buildHeader(ssl, rlHeader, ccs); mySTL::auto_ptr out(NEW_YS output_buffer); buildOutput(*out.get(), rlHeader, ccs); - + if (buffer == buffered) ssl.addBuffer(out.release()); else @@ -961,7 +963,7 @@ void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer) GetSessions().add(ssl); // store session if (side == client_end) buildFinished(ssl, ssl.useHashes().use_verify(), server); // server - } + } ssl.useSecurity().use_connection().CleanMaster(); if (buffer == buffered) @@ -1063,7 +1065,7 @@ int receiveData(SSL& ssl, Data& data, bool peek) ssl.SetError(YasslError(SSL_ERROR_WANT_READ)); return SSL_WOULD_BLOCK; } - return data.get_length(); + return data.get_length(); } @@ -1168,6 +1170,8 @@ void sendCertificateVerify(SSL& ssl, BufferOutput buffer) CertificateVerify verify; verify.Build(ssl); + if (ssl.GetError()) return; + RecordLayerHeader rlHeader; HandShakeHeader hsHeader; mySTL::auto_ptr out(NEW_YS output_buffer); diff --git a/cdk/extra/yassl/src/lock.cpp b/cdk/extra/yassl/src/lock.cpp index c74ea1c6b..1ba2450e0 100644 --- a/cdk/extra/yassl/src/lock.cpp +++ b/cdk/extra/yassl/src/lock.cpp @@ -28,7 +28,7 @@ namespace yaSSL { #ifdef MULTI_THREADED #ifdef _WIN32 - + Mutex::Mutex() { InitializeCriticalSection(&cs_); @@ -40,20 +40,20 @@ namespace yaSSL { DeleteCriticalSection(&cs_); } - + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) { - EnterCriticalSection(&mutex_.cs_); + EnterCriticalSection(&mutex_.cs_); } Mutex::Lock::~Lock() { - LeaveCriticalSection(&mutex_.cs_); + LeaveCriticalSection(&mutex_.cs_); } - + #else // _WIN32 - + Mutex::Mutex() { pthread_mutex_init(&mutex_, 0); @@ -68,15 +68,15 @@ namespace yaSSL { Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) { - pthread_mutex_lock(&mutex_.mutex_); + pthread_mutex_lock(&mutex_.mutex_); } Mutex::Lock::~Lock() { - pthread_mutex_unlock(&mutex_.mutex_); + pthread_mutex_unlock(&mutex_.mutex_); } - + #endif // _WIN32 #endif // MULTI_THREADED diff --git a/cdk/extra/yassl/src/log.cpp b/cdk/extra/yassl/src/log.cpp index c6cb8e6e4..5f034f96c 100644 --- a/cdk/extra/yassl/src/log.cpp +++ b/cdk/extra/yassl/src/log.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -60,6 +60,7 @@ namespace yaSSL { time_t clicks = time(0); char timeStr[32]; + memset(timeStr, 0, sizeof(timeStr)); // get rid of newline strncpy(timeStr, ctime(&clicks), sizeof(timeStr)); unsigned int len = strlen(timeStr); @@ -93,7 +94,7 @@ namespace yaSSL { const char* p = reinterpret_cast(&peeraddr.sin_addr); char msg[MAX_MSG]; char number[16]; - + if (ended) strncpy(msg, "yaSSL conn DONE w/ peer ", 26); else @@ -120,7 +121,7 @@ namespace yaSSL { char number[16]; if (sent) - strncpy(msg, "Sent ", 10); + strncpy(msg, "Sent ", 10); else strncpy(msg, "Received ", 10); sprintf(number, "%u", bytes); diff --git a/cdk/extra/yassl/src/socket_wrapper.cpp b/cdk/extra/yassl/src/socket_wrapper.cpp index a23c1c12e..19e2479c0 100644 --- a/cdk/extra/yassl/src/socket_wrapper.cpp +++ b/cdk/extra/yassl/src/socket_wrapper.cpp @@ -17,8 +17,8 @@ */ -/* The socket wrapper source implements a Socket class that hides the - * differences between Berkely style sockets and Windows sockets, allowing +/* The socket wrapper source implements a Socket class that hides the + * differences between Berkely style sockets and Windows sockets, allowing * transparent TCP access. */ @@ -75,7 +75,7 @@ extern "C" long system_send(void *ptr, const void *buf, size_t count) namespace yaSSL { -Socket::Socket(socket_t s) +Socket::Socket(socket_t s) : socket_(s), wouldBlock_(false), nonBlocking_(false), ptr_(&socket_), send_func_(system_send), recv_func_(system_recv) {} @@ -159,10 +159,10 @@ uint Socket::send(const byte* buf, unsigned int sz, unsigned int& written) while (pos != end) { int sent = send_func_(ptr_, pos, static_cast(end - pos)); if (sent == -1) { - if (get_lastError() == SOCKET_EWOULDBLOCK || + if (get_lastError() == SOCKET_EWOULDBLOCK || get_lastError() == SOCKET_EAGAIN) { wouldBlock_ = true; // would have blocked this time only - nonBlocking_ = true; // nonblocking, win32 only way to tell + nonBlocking_ = true; // nonblocking, win32 only way to tell return 0; } return static_cast(-1); @@ -183,7 +183,7 @@ uint Socket::receive(byte* buf, unsigned int sz) // idea to seperate error from would block by arnetheduck@gmail.com if (recvd == -1) { - if (get_lastError() == SOCKET_EWOULDBLOCK || + if (get_lastError() == SOCKET_EWOULDBLOCK || get_lastError() == SOCKET_EAGAIN) { wouldBlock_ = true; // would have blocked this time only nonBlocking_ = true; // socket nonblocking, win32 only way to tell diff --git a/cdk/extra/yassl/src/ssl.cpp b/cdk/extra/yassl/src/ssl.cpp index 56b6c31fd..fef2d3cdd 100644 --- a/cdk/extra/yassl/src/ssl.cpp +++ b/cdk/extra/yassl/src/ssl.cpp @@ -161,7 +161,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) TaoCrypt::DSA_PrivateKey dsaKey; dsaKey.Initialize(dsaSource); - if (rsaSource.GetError().What()) { + if (dsaSource.GetError().What()) { // neither worked ret = SSL_FAILURE; } @@ -598,8 +598,14 @@ const char* SSL_get_version(SSL* ssl) { static const char* version3 = "SSLv3"; static const char* version31 = "TLSv1"; + static const char* version32 = "TLSv1.1"; - return ssl->isTLS() ? version31 : version3; + if (ssl->isTLSv1_1()) + return version32; + else if(ssl->isTLS()) + return version31; + else + return version3; } const char* SSLeay_version(int) @@ -639,7 +645,9 @@ X509* X509_Copy(X509 *x) X509 *newX509 = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), - before, after); + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); return newX509; } @@ -707,7 +715,10 @@ X509* PEM_read_X509(FILE *fp, X509 *x, afterDate.length = strlen((char *) afterDate.data) + 1; X509 *thisX509 = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength()); + ysDelete(ptr); return thisX509; @@ -827,7 +838,6 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, const char* path) { int ret = SSL_FAILURE; - const int HALF_PATH = 128; if (file) ret = read_file(ctx, file, SSL_FILETYPE_PEM, CA); @@ -838,40 +848,67 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, WIN32_FIND_DATA FindFileData; HANDLE hFind; - char name[MAX_PATH + 1]; // directory specification - strncpy(name, path, MAX_PATH - 3); - strncat(name, "\\*", 3); + const int DELIMITER_SZ = 2; + const int DELIMITER_STAR_SZ = 3; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_STAR_SZ + 1; // plus 1 for terminator + char* name = NEW_YS char[nameSz]; // directory specification + memset(name, 0, nameSz); + strncpy(name, path, nameSz - DELIMITER_STAR_SZ - 1); + strncat(name, "\\*", DELIMITER_STAR_SZ); hFind = FindFirstFile(name, &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) return SSL_BAD_PATH; + if (hFind == INVALID_HANDLE_VALUE) { + ysArrayDelete(name); + return SSL_BAD_PATH; + } do { - if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) { - strncpy(name, path, MAX_PATH - 2 - HALF_PATH); - strncat(name, "\\", 2); - strncat(name, FindFileData.cFileName, HALF_PATH); + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + int curSz = (int)strlen(FindFileData.cFileName); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + // plus 1 for terminator + nameSz = pathSz + curSz + DELIMITER_SZ + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - DELIMITER_SZ - 1); + strncat(name, "\\", DELIMITER_SZ); + strncat(name, FindFileData.cFileName, + nameSz - pathSz - DELIMITER_SZ - 1); ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } } while (ret == SSL_SUCCESS && FindNextFile(hFind, &FindFileData)); + ysArrayDelete(name); FindClose(hFind); #else // _WIN32 - - const int MAX_PATH = 260; - DIR* dir = opendir(path); if (!dir) return SSL_BAD_PATH; struct dirent* entry; struct stat buf; - char name[MAX_PATH + 1]; + const int DELIMITER_SZ = 1; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_SZ + 1; //plus 1 for null terminator + char* name = NEW_YS char[nameSz]; // directory specification while (ret == SSL_SUCCESS && (entry = readdir(dir))) { - strncpy(name, path, MAX_PATH - 1 - HALF_PATH); - strncat(name, "/", 1); - strncat(name, entry->d_name, HALF_PATH); + int curSz = (int)strlen(entry->d_name); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + nameSz = pathSz + DELIMITER_SZ + curSz + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - 1); + strncat(name, "/", DELIMITER_SZ); + strncat(name, entry->d_name, nameSz - pathSz - DELIMITER_SZ - 1); + if (stat(name, &buf) < 0) { + ysArrayDelete(name); closedir(dir); return SSL_BAD_STAT; } @@ -880,6 +917,7 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } + ysArrayDelete(name); closedir(dir); #endif @@ -1015,9 +1053,43 @@ int SSL_get_verify_depth(SSL* ssl) } -long SSL_CTX_set_options(SSL_CTX*, long) +long SSL_CTX_set_options(SSL_CTX* ctx, long options) { - // TDOD: + ProtocolVersion pv= ctx->getMethod()->getVersion(); + bool multi_proto= ctx->getMethod()->multipleProtocol(); + unsigned long ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1; + + do + { + if (options == 0) + break; + // only TLSv1.1 + if ((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= false; + break; + } + // only TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 1; + multi_proto= false; + break; + } + // TLSv1.1 and TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= true; + break; + } + }while(0); + + SSL_METHOD *meth= NEW_YS SSL_METHOD(ctx->getMethod()->getSide(), ProtocolVersion(3,pv.minor_), multi_proto); + ctx->SetMethod(meth); return SSL_SUCCESS; } @@ -1404,16 +1476,14 @@ int ASN1_STRING_type(ASN1_STRING *x) int X509_NAME_get_index_by_NID(X509_NAME* name,int nid, int lastpos) { int idx = -1; // not found - const char* start = &name->GetName()[lastpos + 1]; + int cnPos = -1; switch (nid) { case NID_commonName: - const char* found = strstr(start, "/CN="); - if (found) { - found += 4; // advance to str - idx = found - start + lastpos + 1; - } - break; + cnPos = name->GetCnPosition(); + if (lastpos < cnPos) + idx = cnPos; + break; } return idx; @@ -1566,7 +1636,7 @@ unsigned long err_helper(bool peek = false) return CERTFICATE_ERROR; break; default : - return ysError; + return 0; } return 0; // shut up compiler diff --git a/cdk/extra/yassl/src/timer.cpp b/cdk/extra/yassl/src/timer.cpp index a1b9063e1..a8e1a4fa2 100644 --- a/cdk/extra/yassl/src/timer.cpp +++ b/cdk/extra/yassl/src/timer.cpp @@ -37,7 +37,7 @@ namespace yaSSL { { static bool init(false); static LARGE_INTEGER freq; - + if (!init) { QueryPerformanceFrequency(&freq); init = true; @@ -62,7 +62,7 @@ namespace yaSSL { struct timeval tv; gettimeofday(&tv, 0); - return static_cast(tv.tv_sec) + return static_cast(tv.tv_sec) + static_cast(tv.tv_usec) / 1000000; } @@ -72,7 +72,7 @@ namespace yaSSL { struct timeval tv; gettimeofday(&tv, 0); - return tv.tv_sec; + return tv.tv_sec; } diff --git a/cdk/extra/yassl/src/yassl_error.cpp b/cdk/extra/yassl/src/yassl_error.cpp index e5d693673..0b3f9362a 100644 --- a/cdk/extra/yassl/src/yassl_error.cpp +++ b/cdk/extra/yassl/src/yassl_error.cpp @@ -35,8 +35,8 @@ namespace yaSSL { /* may bring back in future -Error::Error(const char* s, YasslError e, Library l) - : mySTL::runtime_error(s), error_(e), lib_(l) +Error::Error(const char* s, YasslError e, Library l) + : mySTL::runtime_error(s), error_(e), lib_(l) { } @@ -59,66 +59,66 @@ void SetErrorString(YasslError error, char* buffer) { using namespace TaoCrypt; const int max = MAX_ERROR_SZ; // shorthand - int localError = error; // errors from a few enums + int localError = error; // errors from a few enums switch (localError) { // yaSSL proper errors case range_error : strncpy(buffer, "buffer index error, out of range", max); - break; + break; case realloc_error : strncpy(buffer, "trying to realloc a fixed buffer", max); - break; + break; - case factory_error : + case factory_error : strncpy(buffer, "unknown factory create request", max); - break; + break; case unknown_cipher : strncpy(buffer, "trying to use an unknown cipher", max); - break; + break; - case prefix_error : + case prefix_error : strncpy(buffer, "bad master secret derivation, prefix too big", max); - break; + break; - case record_layer : + case record_layer : strncpy(buffer, "record layer not ready yet", max); - break; - + break; + case handshake_layer : strncpy(buffer, "handshake layer not ready yet", max); - break; + break; case out_of_order : strncpy(buffer, "handshake message received in wrong order", max); - break; + break; - case bad_input : + case bad_input : strncpy(buffer, "bad cipher suite input", max); - break; + break; case match_error : strncpy(buffer, "unable to match a supported cipher suite", max); - break; + break; - case no_key_file : + case no_key_file : strncpy(buffer, "the server needs a private key file", max); - break; + break; case verify_error : strncpy(buffer, "unable to verify peer checksum", max); - break; + break; case send_error : strncpy(buffer, "socket layer send error", max); - break; + break; case receive_error : strncpy(buffer, "socket layer receive error", max); - break; + break; case certificate_error : strncpy(buffer, "unable to proccess cerificate", max); @@ -148,6 +148,10 @@ void SetErrorString(YasslError error, char* buffer) strncpy(buffer, "sanity check on cipher text size error", max); break; + case rsaSignFault_error: + strncpy(buffer, "rsa signature fault error", max); + break; + // openssl errors case SSL_ERROR_WANT_READ : strncpy(buffer, "the read operation would block", max); diff --git a/cdk/extra/yassl/src/yassl_imp.cpp b/cdk/extra/yassl/src/yassl_imp.cpp index 867811dbb..2802c52cb 100644 --- a/cdk/extra/yassl/src/yassl_imp.cpp +++ b/cdk/extra/yassl/src/yassl_imp.cpp @@ -47,8 +47,8 @@ bool isTLS(ProtocolVersion pv) void hashHandShake(SSL&, const input_buffer&, uint); -ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) - : major_(maj), minor_(min) +ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) + : major_(maj), minor_(min) {} @@ -109,15 +109,12 @@ void ClientDiffieHellmanPublic::build(SSL& ssl) uint keyLength = dhClient.get_agreedKeyLength(); // pub and agree same alloc(keyLength, true); - dhClient.makeAgreement(dhServer.get_publicKey(), keyLength); + dhClient.makeAgreement(dhServer.get_publicKey(), + dhServer.get_publicKeyLength()); c16toa(keyLength, Yc_); memcpy(Yc_ + KEY_OFFSET, dhClient.get_publicKey(), keyLength); - // because of encoding first byte might be zero, don't use it for preMaster - if (*dhClient.get_agreedKey() == 0) - ssl.set_preMaster(dhClient.get_agreedKey() + 1, keyLength - 1); - else - ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); + ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); } @@ -134,7 +131,7 @@ void DH_Server::build(SSL& ssl) short sigSz = 0; mySTL::auto_ptr auth; const CertManager& cert = ssl.getCrypto().get_certManager(); - + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { if (cert.get_keyType() != rsa_sa_algo) { ssl.SetError(privateKey_error); @@ -152,7 +149,7 @@ void DH_Server::build(SSL& ssl) cert.get_privateKeyLength(), false)); sigSz += DSS_ENCODED_EXTRA; } - + sigSz += auth->get_signatureLength(); if (!sigSz) { ssl.SetError(privateKey_error); @@ -196,9 +193,16 @@ void DH_Server::build(SSL& ssl) sha.update(tmp.get_buffer(), tmp.get_size()); sha.get_digest(&hash[MD5_LEN]); - if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { auth->sign(signature_, hash, sizeof(hash), ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!auth->verify(hash, sizeof(hash), signature_, + auth->get_signatureLength())) { + ssl.SetError(rsaSignFault_error); + return; + } + } else { auth->sign(signature_, &hash[MD5_LEN], SHA_LEN, ssl.getCrypto().get_random()); @@ -243,7 +247,7 @@ void EncryptedPreMasterSecret::read(SSL& ssl, input_buffer& input) opaque preMasterSecret[SECRET_LEN]; memset(preMasterSecret, 0, sizeof(preMasterSecret)); - rsa.decrypt(preMasterSecret, secret_, length_, + rsa.decrypt(preMasterSecret, secret_, length_, ssl.getCrypto().get_random()); ProtocolVersion pv = ssl.getSecurity().get_connection().chVersion_; @@ -312,13 +316,9 @@ void ClientDiffieHellmanPublic::read(SSL& ssl, input_buffer& input) ssl.SetError(bad_input); return; } - dh.makeAgreement(Yc_, keyLength); + dh.makeAgreement(Yc_, keyLength); - // because of encoding, first byte might be 0, don't use for preMaster - if (*dh.get_agreedKey() == 0) - ssl.set_preMaster(dh.get_agreedKey() + 1, dh.get_agreedKeyLength() - 1); - else - ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); + ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); ssl.makeMasterSecret(); } @@ -346,9 +346,9 @@ opaque* ClientDiffieHellmanPublic::get_clientKey() const } -void ClientDiffieHellmanPublic::alloc(int sz, bool offset) +void ClientDiffieHellmanPublic::alloc(int sz, bool offset) { - length_ = sz + (offset ? KEY_OFFSET : 0); + length_ = sz + (offset ? KEY_OFFSET : 0); Yc_ = NEW_YS opaque[length_]; } @@ -444,7 +444,7 @@ void DH_Server::read(SSL& ssl, input_buffer& input) sha.get_digest(&hash[MD5_LEN]); const CertManager& cert = ssl.getCrypto().get_certManager(); - + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); if (!rsa.verify(hash, sizeof(hash), signature_, length)) @@ -453,7 +453,7 @@ void DH_Server::read(SSL& ssl, input_buffer& input) else { byte decodedSig[DSS_SIG_SZ]; length = TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, length); - + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); if (!dss.verify(&hash[MD5_LEN], SHA_LEN, decodedSig, length)) ssl.SetError(verify_error); @@ -492,7 +492,7 @@ opaque* DH_Server::get_serverKey() const // set available suites -Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, +Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, ProtocolVersion pv, bool haveDH) : entity_(ce) { pending_ = true; // suite not set yet @@ -505,7 +505,7 @@ Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, memcpy(suites_, ciphers.suites_, ciphers.suiteSz_); SetCipherNames(); } - else + else SetSuites(pv, ce == server_end && removeDH_); // defaults } @@ -576,7 +576,7 @@ void Parameters::SetSuites(ProtocolVersion pv, bool removeDH, bool removeRSA, if (!removeRSA) { suites_[i++] = 0x00; - suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; + suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; suites_[i++] = 0x00; suites_[i++] = SSL_RSA_WITH_RC4_128_MD5; @@ -647,7 +647,7 @@ output_buffer& operator<<(output_buffer& output, const RecordLayerHeader& hdr) output[AUTO] = hdr.type_; output[AUTO] = hdr.version_.major_; output[AUTO] = hdr.version_.minor_; - + // length byte tmp[2]; c16toa(hdr.length_, tmp); @@ -679,7 +679,7 @@ input_buffer& operator>>(input_buffer& input, HandShakeHeader& hs) hs.length_[0] = input[AUTO]; hs.length_[1] = input[AUTO]; hs.length_[2] = input[AUTO]; - + return input; } @@ -789,14 +789,14 @@ input_buffer& HandShakeBase::set(input_buffer& in) return in; } - + output_buffer& HandShakeBase::get(output_buffer& out) const { return out; } -void HandShakeBase::Process(input_buffer&, SSL&) +void HandShakeBase::Process(input_buffer&, SSL&) {} @@ -826,7 +826,7 @@ HandShakeType HelloRequest::get_type() const input_buffer& operator>>(input_buffer& input, ChangeCipherSpec& cs) { cs.type_ = CipherChoice(input[AUTO]); - return input; + return input; } // output operator for CipherSpec @@ -837,7 +837,7 @@ output_buffer& operator<<(output_buffer& output, const ChangeCipherSpec& cs) } -ChangeCipherSpec::ChangeCipherSpec() +ChangeCipherSpec::ChangeCipherSpec() : type_(change_cipher_spec_choice) {} @@ -924,7 +924,7 @@ input_buffer& operator>>(input_buffer& input, Alert& a) { a.level_ = AlertLevel(input[AUTO]); a.description_ = AlertDescription(input[AUTO]); - + return input; } @@ -969,7 +969,7 @@ void Alert::Process(input_buffer& input, SSL& ssl) ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - aSz - digestSz; - for (int i = 0; i < padSz; i++) + for (int i = 0; i < padSz; i++) fill = input[AUTO]; } @@ -1052,7 +1052,7 @@ output_buffer& operator<<(output_buffer& output, const Data& data) } -// check all bytes for equality +// check all bytes for equality static int constant_compare(const byte* a, const byte* b, int len) { int good = 0; @@ -1095,7 +1095,7 @@ static int pad_check(const byte* input, byte pad, int len) // get number of compression rounds static inline int get_rounds(int pLen, int padLen, int t) { - int roundL1 = 1; // round ups + int roundL1 = 1; // round ups int roundL2 = 1; int L1 = COMPRESS_CONSTANT + pLen - t; @@ -1126,7 +1126,7 @@ static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) Digest* digest = NULL; MACAlgorithm ma = ssl.getSecurity().get_parms().mac_algorithm_; - if (ma == sha) + if (ma == sha) digest = NEW_YS SHA; else if (ma == md5) digest = NEW_YS MD5; @@ -1138,7 +1138,7 @@ static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) for (int i = 0; i < rounds; i++) digest->update(dummy, COMPRESS_LOWER); - ysDelete(digest); + ysDelete(digest); } } @@ -1217,16 +1217,16 @@ void Data::Process(input_buffer& input, SSL& ssl) } } else { // SSLv3, some don't do this padding right - int sz3 = msgSz - digestSz - pad - 1; + int sz3 = msgSz - digestSz - pad - 1; hmac(ssl, verify, rawData, sz3, application_data, true); if (constant_compare(verify, rawData + sz3, digestSz) != 0) { ssl.SetError(verify_error); return; } - } + } } else { // stream - int streamSz = msgSz - digestSz; + int streamSz = msgSz - digestSz; if (ssl.isTLS()) TLS_hmac(ssl, verify, rawData, streamSz, application_data, true); else @@ -1286,7 +1286,7 @@ output_buffer& operator<<(output_buffer& output, const HandShakeBase& hs) } -Certificate::Certificate(const x509* cert) : cert_(cert) +Certificate::Certificate(const x509* cert) : cert_(cert) { if (cert) set_length(cert_->get_length() + 2 * CERT_HEADER); // list and cert size @@ -1339,7 +1339,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) } CertManager& cm = ssl.useCrypto().use_certManager(); - + uint32 list_sz; byte tmp[3]; @@ -1356,7 +1356,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) ssl.SetError(YasslError(bad_input)); return; } - + while (list_sz) { // cert size uint32 cert_sz; @@ -1369,7 +1369,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) tmp[1] = input[AUTO]; tmp[2] = input[AUTO]; c24to32(tmp, cert_sz); - + if (cert_sz > (uint)MAX_RECORD_SIZE || input.get_remaining() < cert_sz){ ssl.SetError(YasslError(bad_input)); return; @@ -1496,27 +1496,27 @@ opaque* ServerKeyBase::get_serverKey() const // input operator for ServerHello input_buffer& operator>>(input_buffer& input, ServerHello& hello) -{ +{ // Protocol hello.server_version_.major_ = input[AUTO]; hello.server_version_.minor_ = input[AUTO]; - + // Random input.read(hello.random_, RAN_LEN); - + // Session hello.id_len_ = input[AUTO]; if (hello.id_len_ > ID_LEN) { - input.set_error(); + input.set_error(); return input; } if (hello.id_len_) input.read(hello.session_id_, hello.id_len_); - + // Suites hello.cipher_suite_[0] = input[AUTO]; hello.cipher_suite_[1] = input[AUTO]; - + // Compression hello.compression_method_ = CompressionMethod(input[AUTO]); @@ -1711,7 +1711,7 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // Session hello.id_len_ = input[AUTO]; if (hello.id_len_) input.read(hello.session_id_, ID_LEN); - + // Suites byte tmp[2]; uint16 len; @@ -1746,7 +1746,7 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // output operaotr for Client Hello output_buffer& operator<<(output_buffer& output, const ClientHello& hello) -{ +{ // Protocol output[AUTO] = hello.client_version_.major_; output[AUTO] = hello.client_version_.minor_; @@ -1764,7 +1764,7 @@ output_buffer& operator<<(output_buffer& output, const ClientHello& hello) output[AUTO] = tmp[0]; output[AUTO] = tmp[1]; output.write(hello.cipher_suites_, hello.suite_len_); - + // Compression output[AUTO] = hello.comp_len_; output[AUTO] = hello.compression_methods_; @@ -1792,18 +1792,18 @@ void ClientHello::Process(input_buffer& input, SSL& ssl) if (ssl.isTLS() && client_version_.minor_ < 1) { // downgrade to SSLv3 ssl.useSecurity().use_connection().TurnOffTLS(); - + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; bool removeDH = ssl.getSecurity().get_parms().removeDH_; bool removeRSA = false; bool removeDSA = false; - + const CertManager& cm = ssl.getCrypto().get_certManager(); if (cm.get_keyType() == rsa_sa_algo) removeDSA = true; else removeRSA = true; - + // reset w/ SSL suites ssl.useSecurity().use_parms().SetSuites(pv, removeDH, removeRSA, removeDSA); @@ -1945,9 +1945,9 @@ ServerKeyExchange::~ServerKeyExchange() } -void ServerKeyExchange::build(SSL& ssl) -{ - server_key_->build(ssl); +void ServerKeyExchange::build(SSL& ssl) +{ + server_key_->build(ssl); set_length(server_key_->get_length()); } @@ -1982,7 +1982,7 @@ HandShakeType ServerKeyExchange::get_type() const } -// CertificateRequest +// CertificateRequest CertificateRequest::CertificateRequest() : typeTotal_(0) { @@ -2008,7 +2008,7 @@ void CertificateRequest::Build() uint16 authCount = 0; uint16 authSz = 0; - + for (int j = 0; j < authCount; j++) { int sz = REQUEST_HEADER + MIN_DIS_SIZE; DistinguishedName dn; @@ -2017,7 +2017,7 @@ void CertificateRequest::Build() opaque tmp[REQUEST_HEADER]; c16toa(MIN_DIS_SIZE, tmp); memcpy(dn, tmp, sizeof(tmp)); - + // fill w/ junk for now memcpy(dn, tmp, MIN_DIS_SIZE); authSz += sz; @@ -2063,7 +2063,7 @@ input_buffer& operator>>(input_buffer& input, CertificateRequest& request) tmp[0] = input[AUTO]; tmp[1] = input[AUTO]; ato16(tmp, dnSz); - + input.set_current(input.get_current() + dnSz); sz -= dnSz + REQUEST_HEADER; @@ -2128,7 +2128,7 @@ HandShakeType CertificateRequest::get_type() const } -// CertificateVerify +// CertificateVerify CertificateVerify::CertificateVerify() : signature_(0) {} @@ -2159,6 +2159,12 @@ void CertificateVerify::Build(SSL& ssl) memcpy(sig.get(), len, VERIFY_HEADER); rsa.sign(sig.get() + VERIFY_HEADER, hashes_.md5_, sizeof(Hashes), ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!rsa.verify(hashes_.md5_, sizeof(Hashes), sig.get() + VERIFY_HEADER, + rsa.get_cipherLength())) { + ssl.SetError(rsaSignFault_error); + return; + } } else { // DSA DSS dss(cert.get_privateKey(), cert.get_privateKeyLength(), false); @@ -2246,7 +2252,7 @@ void CertificateVerify::Process(input_buffer& input, SSL& ssl) else { // DSA byte decodedSig[DSS_SIG_SZ]; TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, get_length()); - + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); if (!dss.verify(hashVerify.sha_, SHA_LEN, decodedSig, get_length())) ssl.SetError(verify_error); @@ -2307,9 +2313,9 @@ ClientKeyExchange::~ClientKeyExchange() } -void ClientKeyExchange::build(SSL& ssl) -{ - client_key_->build(ssl); +void ClientKeyExchange::build(SSL& ssl) +{ + client_key_->build(ssl); set_length(client_key_->get_length()); } @@ -2348,7 +2354,7 @@ input_buffer& operator>>(input_buffer& input, Finished&) { /* do in process */ - return input; + return input; } // output operator for Finished @@ -2375,7 +2381,7 @@ void Finished::Process(input_buffer& input, SSL& ssl) // verify hashes const Finished& verify = ssl.getHashes().get_verify(); uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; - + input.read(hashes_.md5_, finishedSz); if (input.get_error()) { ssl.SetError(bad_input); @@ -2415,7 +2421,7 @@ void Finished::Process(input_buffer& input, SSL& ssl) opaque fill; int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - HANDSHAKE_HEADER - finishedSz - digestSz; - for (int i = 0; i < padSz; i++) + for (int i = 0; i < padSz; i++) fill = input[AUTO]; if (input.get_error()) { ssl.SetError(bad_input); @@ -2499,14 +2505,14 @@ Connection::Connection(ProtocolVersion v, RandomPool& ran) } -Connection::~Connection() -{ +Connection::~Connection() +{ CleanMaster(); CleanPreMaster(); ysArrayDelete(pre_master_secret_); } -void Connection::AllocPreSecret(uint sz) -{ +void Connection::AllocPreSecret(uint sz) +{ pre_master_secret_ = NEW_YS opaque[pre_secret_len_ = sz]; } @@ -2561,7 +2567,7 @@ HandShakeBase* CreateClientHello() { return NEW_YS ClientHello; } HandShakeBase* CreateServerHello() { return NEW_YS ServerHello; } HandShakeBase* CreateCertificate() { return NEW_YS Certificate; } HandShakeBase* CreateServerKeyExchange() { return NEW_YS ServerKeyExchange;} -HandShakeBase* CreateCertificateRequest() { return NEW_YS +HandShakeBase* CreateCertificateRequest() { return NEW_YS CertificateRequest; } HandShakeBase* CreateServerHelloDone() { return NEW_YS ServerHelloDone; } HandShakeBase* CreateCertificateVerify() { return NEW_YS CertificateVerify;} @@ -2574,9 +2580,9 @@ ServerKeyBase* CreateDHServerKEA() { return NEW_YS DH_Server; } ServerKeyBase* CreateFortezzaServerKEA() { return NEW_YS Fortezza_Server; } // Create functions for client key exchange factory -ClientKeyBase* CreateRSAClient() { return NEW_YS +ClientKeyBase* CreateRSAClient() { return NEW_YS EncryptedPreMasterSecret; } -ClientKeyBase* CreateDHClient() { return NEW_YS +ClientKeyBase* CreateDHClient() { return NEW_YS ClientDiffieHellmanPublic; } ClientKeyBase* CreateFortezzaClient() { return NEW_YS FortezzaKeys; } diff --git a/cdk/extra/yassl/src/yassl_int.cpp b/cdk/extra/yassl/src/yassl_int.cpp index ea321ead9..62334d1be 100644 --- a/cdk/extra/yassl/src/yassl_int.cpp +++ b/cdk/extra/yassl/src/yassl_int.cpp @@ -857,6 +857,19 @@ void SSL::set_random(const opaque* random, ConnectionEnd sender) // store client pre master secret void SSL::set_preMaster(const opaque* pre, uint sz) { + uint i(0); // trim leading zeros + uint fullSz(sz); + + while (i++ < fullSz && *pre == 0) { + sz--; + pre++; + } + + if (sz == 0) { + SetError(bad_input); + return; + } + secure_.use_connection().AllocPreSecret(sz); memcpy(secure_.use_connection().pre_master_secret_, pre, sz); } @@ -974,6 +987,8 @@ void SSL::order_error() // Create and store the master secret see page 32, 6.1 void SSL::makeMasterSecret() { + if (GetError()) return; + if (isTLS()) makeTLSMasterSecret(); else { @@ -1590,7 +1605,9 @@ void SSL_SESSION::CopyX509(X509* x) peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), - before, after); + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); } @@ -2123,6 +2140,14 @@ void SSL_CTX::SetSessionCacheOff() } +void SSL_CTX::SetMethod(SSL_METHOD* meth) +{ + if(method_) + ysDelete(method_); + method_= meth; +} + + void SSL_CTX::SetSessionCacheFlushOff() { sessionCacheFlushOff_ = true; @@ -2219,7 +2244,7 @@ void SSL_CTX::IncrementStats(StatsField fd) switch (fd) { - case Accept: + case Accept: ++stats_.accept_; break; @@ -2568,8 +2593,8 @@ void Security::set_resuming(bool b) } -X509_NAME::X509_NAME(const char* n, size_t sz) - : name_(0), sz_(sz) +X509_NAME::X509_NAME(const char* n, size_t sz, int pos, int len) + : name_(0), sz_(sz), cnPosition_(pos), cnLen_(len) { if (sz) { name_ = NEW_YS char[sz]; @@ -2599,8 +2624,10 @@ size_t X509_NAME::GetLength() const X509::X509(const char* i, size_t iSz, const char* s, size_t sSz, - ASN1_STRING *b, ASN1_STRING *a) - : issuer_(i, iSz), subject_(s, sSz), + ASN1_STRING *b, ASN1_STRING *a, + int issPos, int issLen, + int subPos, int subLen) + : issuer_(i, iSz, issPos, issLen), subject_(s, sSz, subPos, subLen), beforeDate_((char *) b->data, b->length, b->type), afterDate_((char *) a->data, a->length, a->type) {} @@ -2635,19 +2662,20 @@ ASN1_STRING* X509_NAME::GetEntry(int i) if (i < 0 || i >= int(sz_)) return 0; + if (i != cnPosition_ || cnLen_ <= 0) // only entry currently supported + return 0; + + if (cnLen_ > int(sz_-i)) // make sure there's room in read buffer + return 0; + if (entry_.data) ysArrayDelete(entry_.data); - entry_.data = NEW_YS byte[sz_]; // max size; + entry_.data = NEW_YS byte[cnLen_+1]; // max size; - memcpy(entry_.data, &name_[i], sz_ - i); - if (entry_.data[sz_ -i - 1]) { - entry_.data[sz_ - i] = 0; - entry_.length = int(sz_) - i; - } - else - entry_.length = int(sz_) - i - 1; + memcpy(entry_.data, &name_[i], cnLen_); + entry_.data[cnLen_] = 0; + entry_.length = cnLen_; entry_.type = 0; - return &entry_; } diff --git a/cdk/extra/yassl/taocrypt/include/aes.hpp b/cdk/extra/yassl/taocrypt/include/aes.hpp index 017630331..bccf6e73f 100644 --- a/cdk/extra/yassl/taocrypt/include/aes.hpp +++ b/cdk/extra/yassl/taocrypt/include/aes.hpp @@ -60,6 +60,7 @@ class AES : public Mode_BASE { static const word32 Te[5][256]; static const word32 Td[5][256]; + static const byte CTd4[256]; static const word32* Te0; static const word32* Te1; @@ -80,11 +81,68 @@ class AES : public Mode_BASE { void ProcessAndXorBlock(const byte*, const byte*, byte*) const; + word32 PreFetchTe() const; + word32 PreFetchTd() const; + word32 PreFetchCTd4() const; + AES(const AES&); // hide copy AES& operator=(const AES&); // and assign }; +#if defined(__x86_64__) || defined(_M_X64) || \ + (defined(__ILP32__) && (__ILP32__ >= 1)) + #define TC_CACHE_LINE_SZ 64 +#else + /* default cache line size */ + #define TC_CACHE_LINE_SZ 32 +#endif + +inline word32 AES::PreFetchTe() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Te[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchTd() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Td[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchCTd4() const +{ + word32 x = 0; + int i; + + for (i = 0; i < 256; i += TC_CACHE_LINE_SZ) { + x &= CTd4[i]; + } + + return x; +} + + typedef BlockCipher AES_ECB_Encryption; typedef BlockCipher AES_ECB_Decryption; diff --git a/cdk/extra/yassl/taocrypt/include/asn.hpp b/cdk/extra/yassl/taocrypt/include/asn.hpp index bc3eebe6b..e029001ba 100644 --- a/cdk/extra/yassl/taocrypt/include/asn.hpp +++ b/cdk/extra/yassl/taocrypt/include/asn.hpp @@ -16,7 +16,7 @@ MA 02110-1301 USA. */ -/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding +/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding */ @@ -109,7 +109,7 @@ enum Constants MIN_DATE_SZ = 13, MAX_DATE_SZ = 16, MAX_ALGO_SZ = 16, - MAX_LENGTH_SZ = 5, + MAX_LENGTH_SZ = 5, MAX_SEQ_SZ = 5, // enum(seq|con) + length(4) MAX_ALGO_SIZE = 9, MAX_DIGEST_SZ = 69, // SHA512 + enum(Bit or Octet) + length(4) @@ -269,7 +269,7 @@ enum KeyType { DSAk = 515, RSAk = 645 }; // sums of algo OID // an x509v Certificate BER Decoder class CertDecoder : public BER_Decoder { public: - enum DateType { BEFORE, AFTER }; + enum DateType { BEFORE, AFTER }; enum NameType { ISSUER, SUBJECT }; enum CertType { CA, USER }; @@ -286,7 +286,10 @@ class CertDecoder : public BER_Decoder { byte GetBeforeDateType() const { return beforeDateType_; } const char* GetAfterDate() const { return afterDate_; } byte GetAfterDateType() const { return afterDateType_; } - + int GetSubjectCnStart() const { return subCnPos_; } + int GetIssuerCnStart() const { return issCnPos_; } + int GetSubjectCnLength() const { return subCnLen_; } + int GetIssuerCnLength() const { return issCnLen_; } void DecodeToKey(); private: PublicKey key_; @@ -295,6 +298,10 @@ class CertDecoder : public BER_Decoder { word32 sigLength_; // length of signature word32 signatureOID_; // sum of algorithm object id word32 keyOID_; // sum of key algo object id + int subCnPos_; // subject common name start, -1 is none + int subCnLen_; // length of above + int issCnPos_; // issuer common name start, -1 is none + int issCnLen_; // length of above byte subjectHash_[SHA_SIZE]; // hash of all Names byte issuerHash_[SHA_SIZE]; // hash of all Names byte* signature_; diff --git a/cdk/extra/yassl/taocrypt/include/block.hpp b/cdk/extra/yassl/taocrypt/include/block.hpp index 4f58c82ff..8242891b0 100644 --- a/cdk/extra/yassl/taocrypt/include/block.hpp +++ b/cdk/extra/yassl/taocrypt/include/block.hpp @@ -125,7 +125,7 @@ class AllocatorWithCleanup : public AllocatorBase template > class Block { public: - explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) + explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) { CleanNew(sz_); } Block(const T* buff, word32 s) : sz_(s), buffer_(allocator_.allocate(sz_)) diff --git a/cdk/extra/yassl/taocrypt/include/des.hpp b/cdk/extra/yassl/taocrypt/include/des.hpp index d88e9ef2f..04d1439dd 100644 --- a/cdk/extra/yassl/taocrypt/include/des.hpp +++ b/cdk/extra/yassl/taocrypt/include/des.hpp @@ -48,10 +48,10 @@ class BasicDES { }; -// DES +// DES class DES : public Mode_BASE, public BasicDES { public: - DES(CipherDir DIR, Mode MODE) + DES(CipherDir DIR, Mode MODE) : Mode_BASE(DES_BLOCK_SIZE, DIR, MODE) {} private: @@ -65,7 +65,7 @@ class DES : public Mode_BASE, public BasicDES { // DES_EDE2 class DES_EDE2 : public Mode_BASE { public: - DES_EDE2(CipherDir DIR, Mode MODE) + DES_EDE2(CipherDir DIR, Mode MODE) : Mode_BASE(DES_BLOCK_SIZE, DIR, MODE) {} void SetKey(const byte*, word32, CipherDir dir); diff --git a/cdk/extra/yassl/taocrypt/include/dh.hpp b/cdk/extra/yassl/taocrypt/include/dh.hpp index bdb90ddae..93783f156 100644 --- a/cdk/extra/yassl/taocrypt/include/dh.hpp +++ b/cdk/extra/yassl/taocrypt/include/dh.hpp @@ -40,7 +40,7 @@ class DH { explicit DH(Source&); DH(const DH& that) : p_(that.p_), g_(that.g_) {} - DH& operator=(const DH& that) + DH& operator=(const DH& that) { DH tmp(that); Swap(tmp); @@ -77,7 +77,7 @@ class DH { Integer g_; void GeneratePrivate(RandomNumberGenerator&, byte*); - void GeneratePublic(const byte*, byte*); + void GeneratePublic(const byte*, byte*); }; diff --git a/cdk/extra/yassl/taocrypt/include/dsa.hpp b/cdk/extra/yassl/taocrypt/include/dsa.hpp index d7f81c274..05ae56843 100644 --- a/cdk/extra/yassl/taocrypt/include/dsa.hpp +++ b/cdk/extra/yassl/taocrypt/include/dsa.hpp @@ -43,7 +43,7 @@ class DSA_PublicKey { void Initialize(Source&); void Initialize(const Integer& p, const Integer& q, const Integer& g, const Integer& y); - + const Integer& GetModulus() const; const Integer& GetSubGroupOrder() const; const Integer& GetSubGroupGenerator() const; @@ -55,7 +55,7 @@ class DSA_PublicKey { void SetPublicPart(const Integer&); word32 SignatureLength() const; - + DSA_PublicKey(const DSA_PublicKey&); DSA_PublicKey& operator=(const DSA_PublicKey&); @@ -73,7 +73,7 @@ class DSA_PrivateKey : public DSA_PublicKey { void Initialize(Source&); void Initialize(const Integer& p, const Integer& q, const Integer& g, const Integer& y, const Integer& x); - + const Integer& GetPrivatePart() const; void SetPrivatePart(const Integer&); diff --git a/cdk/extra/yassl/taocrypt/include/error.hpp b/cdk/extra/yassl/taocrypt/include/error.hpp index cb2130d48..a6ab7c72e 100644 --- a/cdk/extra/yassl/taocrypt/include/error.hpp +++ b/cdk/extra/yassl/taocrypt/include/error.hpp @@ -68,7 +68,7 @@ SIG_OTHER_E = 1039, // "bad other signature confirmation" CONTENT_E = 1040, // "bad content processing" PEM_E = 1041 // "bad pem format error" - // add error string to yassl/src/yassl_error.cpp !!! + // add error string to yassl/src/yassl_error.cpp !!! }; diff --git a/cdk/extra/yassl/taocrypt/include/file.hpp b/cdk/extra/yassl/taocrypt/include/file.hpp index 9851a001a..a8d0375e8 100644 --- a/cdk/extra/yassl/taocrypt/include/file.hpp +++ b/cdk/extra/yassl/taocrypt/include/file.hpp @@ -40,13 +40,13 @@ class Source { Source(const byte* b, word32 sz) : buffer_(b, sz), current_(0) {} word32 remaining() { if (GetError().What()) return 0; - else return buffer_.size() - current_; } + else return buffer_.size() - current_; } word32 size() const { return buffer_.size(); } void grow(word32 sz) { buffer_.CleanGrow(sz); } bool IsLeft(word32 sz) { if (remaining() >= sz) return true; else { SetError(CONTENT_E); return false; } } - + const byte* get_buffer() const { return buffer_.get_buffer(); } const byte* get_current() const { return &buffer_[current_]; } word32 get_index() const { return current_; } @@ -82,7 +82,7 @@ class Source { return *this; } - void Swap(Source& other) + void Swap(Source& other) { buffer_.Swap(other.buffer_); STL::swap(current_, other.current_); @@ -97,11 +97,11 @@ class FileSource { public: FileSource(const char* fname, Source& source); ~FileSource(); - + word32 size(bool use_current = false); private: word32 get(Source&); - word32 size_left(); + word32 size_left(); FileSource(const FileSource&); // hide FileSource& operator=(const FileSource&); // hide diff --git a/cdk/extra/yassl/taocrypt/include/hash.hpp b/cdk/extra/yassl/taocrypt/include/hash.hpp index 4d2f7dd35..e1d57ed57 100644 --- a/cdk/extra/yassl/taocrypt/include/hash.hpp +++ b/cdk/extra/yassl/taocrypt/include/hash.hpp @@ -56,7 +56,7 @@ class HASHwithTransform : public HASH { word32 GetBitCountLo() const { return loLen_ << 3; } word32 GetBitCountHi() const { return (loLen_ >> (8*sizeof(loLen_) - 3)) + - (hiLen_ << 3); } + (hiLen_ << 3); } enum { MaxDigestSz = 8, MaxBufferSz = 64 }; protected: typedef word32 HashLengthType; @@ -87,7 +87,7 @@ class HASH64withTransform : public HASH { word32 GetBitCountLo() const { return loLen_ << 3; } word32 GetBitCountHi() const { return (loLen_ >> (8*sizeof(loLen_) - 3)) + - (hiLen_ << 3); } + (hiLen_ << 3); } enum { MaxDigestSz = 8, MaxBufferSz = 128 }; protected: typedef word32 HashLengthType; diff --git a/cdk/extra/yassl/taocrypt/include/hmac.hpp b/cdk/extra/yassl/taocrypt/include/hmac.hpp index 4df081b84..836710db3 100644 --- a/cdk/extra/yassl/taocrypt/include/hmac.hpp +++ b/cdk/extra/yassl/taocrypt/include/hmac.hpp @@ -34,11 +34,11 @@ class HMAC { public: enum { IPAD = 0x36, OPAD = 0x5C }; - HMAC() : ipad_(reinterpret_cast(&ip_)), + HMAC() : ipad_(reinterpret_cast(&ip_)), opad_(reinterpret_cast(&op_)), - innerHash_(reinterpret_cast(&innerH_)) - { - Init(); + innerHash_(reinterpret_cast(&innerH_)) + { + Init(); } void Update(const byte*, word32); void Final(byte*); diff --git a/cdk/extra/yassl/taocrypt/include/integer.hpp b/cdk/extra/yassl/taocrypt/include/integer.hpp index d21219ea1..dab238726 100644 --- a/cdk/extra/yassl/taocrypt/include/integer.hpp +++ b/cdk/extra/yassl/taocrypt/include/integer.hpp @@ -47,7 +47,7 @@ #ifdef TAOCRYPT_X86ASM_AVAILABLE #if defined(__GNUC__) && (__GNUC__ >= 4) - // GCC 4 or greater optimizes too much inline on recursive for bigint, + // GCC 4 or greater optimizes too much inline on recursive for bigint, // -O3 just as fast without asm here anyway #undef TAOCRYPT_X86ASM_AVAILABLE #endif @@ -118,6 +118,10 @@ namespace TaoCrypt { #endif + +#ifdef _WIN32 + #undef max // avoid name clash +#endif // general MAX template inline const T& max(const T& a, const T& b) @@ -147,7 +151,7 @@ class Integer { Signedness s = UNSIGNED); ~Integer() {} - + static const Integer& Zero(); static const Integer& One(); @@ -190,7 +194,7 @@ class Integer { Integer& operator+=(const Integer& t); Integer& operator-=(const Integer& t); Integer& operator*=(const Integer& t) { return *this = Times(t); } - Integer& operator/=(const Integer& t) + Integer& operator/=(const Integer& t) { return *this = DividedBy(t);} Integer& operator%=(const Integer& t) { return *this = Modulo(t); } Integer& operator/=(word t) { return *this = DividedBy(t); } @@ -198,7 +202,7 @@ class Integer { Integer& operator<<=(unsigned int); Integer& operator>>=(unsigned int); - + void Randomize(RandomNumberGenerator &rng, unsigned int bitcount); void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); @@ -206,7 +210,7 @@ class Integer { void SetBit(unsigned int n, bool value = 1); void SetByte(unsigned int n, byte value); - void Negate(); + void Negate(); void SetPositive() { sign_ = POSITIVE; } void SetNegative() { if (!!(*this)) sign_ = NEGATIVE; } void Swap(Integer& a); @@ -216,9 +220,9 @@ class Integer { Integer operator-() const; Integer& operator++(); Integer& operator--(); - Integer operator++(int) + Integer operator++(int) { Integer temp = *this; ++*this; return temp; } - Integer operator--(int) + Integer operator--(int) { Integer temp = *this; --*this; return temp; } int Compare(const Integer& a) const; @@ -277,28 +281,28 @@ class Integer { Sign sign_; }; -inline bool operator==(const Integer& a, const Integer& b) +inline bool operator==(const Integer& a, const Integer& b) {return a.Compare(b)==0;} -inline bool operator!=(const Integer& a, const Integer& b) +inline bool operator!=(const Integer& a, const Integer& b) {return a.Compare(b)!=0;} -inline bool operator> (const Integer& a, const Integer& b) +inline bool operator> (const Integer& a, const Integer& b) {return a.Compare(b)> 0;} -inline bool operator>=(const Integer& a, const Integer& b) +inline bool operator>=(const Integer& a, const Integer& b) {return a.Compare(b)>=0;} -inline bool operator< (const Integer& a, const Integer& b) +inline bool operator< (const Integer& a, const Integer& b) {return a.Compare(b)< 0;} -inline bool operator<=(const Integer& a, const Integer& b) +inline bool operator<=(const Integer& a, const Integer& b) {return a.Compare(b)<=0;} -inline Integer operator+(const Integer &a, const Integer &b) +inline Integer operator+(const Integer &a, const Integer &b) {return a.Plus(b);} -inline Integer operator-(const Integer &a, const Integer &b) +inline Integer operator-(const Integer &a, const Integer &b) {return a.Minus(b);} -inline Integer operator*(const Integer &a, const Integer &b) +inline Integer operator*(const Integer &a, const Integer &b) {return a.Times(b);} -inline Integer operator/(const Integer &a, const Integer &b) +inline Integer operator/(const Integer &a, const Integer &b) {return a.DividedBy(b);} -inline Integer operator%(const Integer &a, const Integer &b) +inline Integer operator%(const Integer &a, const Integer &b) {return a.Modulo(b);} inline Integer operator/(const Integer &a, word b) {return a.DividedBy(b);} inline word operator%(const Integer &a, word b) {return a.Modulo(b);} diff --git a/cdk/extra/yassl/taocrypt/include/md5.hpp b/cdk/extra/yassl/taocrypt/include/md5.hpp index fce37bd55..2529d4d57 100644 --- a/cdk/extra/yassl/taocrypt/include/md5.hpp +++ b/cdk/extra/yassl/taocrypt/include/md5.hpp @@ -37,7 +37,7 @@ class MD5 : public HASHwithTransform { public: enum { BLOCK_SIZE = 64, DIGEST_SIZE = 16, PAD_SIZE = 56, TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes - MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) + MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) { Init(); } ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); } word32 getBlockSize() const { return BLOCK_SIZE; } diff --git a/cdk/extra/yassl/taocrypt/include/misc.hpp b/cdk/extra/yassl/taocrypt/include/misc.hpp index 18f13e783..6f82ce117 100644 --- a/cdk/extra/yassl/taocrypt/include/misc.hpp +++ b/cdk/extra/yassl/taocrypt/include/misc.hpp @@ -105,21 +105,21 @@ void CleanUp(); #define NEW_TC new class virtual_base {}; - - + + #endif // YASSL_PURE_C #if defined(_MSC_VER) || defined(__BCPLUSPLUS__) - #define INTEL_INTRINSICS - #define FAST_ROTATE + #define INTEL_INTRINSICS + #define FAST_ROTATE #elif defined(__MWERKS__) && TARGET_CPU_PPC - #define PPC_INTRINSICS - #define FAST_ROTATE + #define PPC_INTRINSICS + #define FAST_ROTATE #elif defined(__GNUC__) && defined(__i386__) // GCC does peephole optimizations which should result in using rotate // instructions - #define FAST_ROTATE + #define FAST_ROTATE #endif @@ -163,7 +163,7 @@ void CleanUp(); // Turn on ia32 ASM for Ciphers and Message Digests // Seperate define since these are more complex, use member offsets -// and user may want to turn off while leaving Big Integer optos on +// and user may want to turn off while leaving Big Integer optos on #if defined(TAOCRYPT_X86ASM_AVAILABLE) && !defined(DISABLE_TAO_ASM) #define TAO_ASM #endif @@ -271,7 +271,7 @@ void CleanUp(); template struct CompileAssert { - static char dummy[2*b-1]; + static char dummy[2*b-1]; }; #define TAOCRYPT_COMPILE_ASSERT(assertion) \ @@ -440,7 +440,7 @@ template<> inline word32 rotrFixed(word32 x, word32 y) #ifdef min #undef min -#endif +#endif template @@ -472,14 +472,14 @@ inline word32 ByteReverse(word32 value) inline word64 ByteReverse(word64 value) { #ifdef TAOCRYPT_SLOW_WORD64 - return (word64(ByteReverse(word32(value))) << 32) | + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); #else - value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); - value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); - return rotlFixed(value, 32U); + return rotlFixed(value, 32U); #endif } @@ -512,7 +512,7 @@ inline T ByteReverseIf(T value, ByteOrder order) template inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) { - if (!HostByteOrderIs(order)) + if (!HostByteOrderIs(order)) ByteReverse(out, in, bc); else if (out != in) memcpy(out, in, bc); @@ -520,7 +520,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) -// do Asm Reverse is host is Little and x86asm +// do Asm Reverse is host is Little and x86asm #ifdef LITTLE_ENDIAN_ORDER #ifdef TAOCRYPT_X86ASM_AVAILABLE #define LittleReverse AsmReverse @@ -532,7 +532,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) #endif -// do Asm Reverse is host is Big and x86asm +// do Asm Reverse is host is Big and x86asm #ifdef BIG_ENDIAN_ORDER #ifdef TAOCRYPT_X86ASM_AVAILABLE #define BigReverse AsmReverse @@ -551,14 +551,14 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) inline word32 AsmReverse(word32 wd) { #ifdef __GNUC__ - __asm__ + __asm__ ( "bswap %1" : "=r"(wd) : "0"(wd) ); #else - __asm + __asm { mov eax, wd bswap eax @@ -568,7 +568,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) return wd; } -#endif +#endif template @@ -699,7 +699,7 @@ inline void PutWord(bool assumeAligned, ByteOrder order, byte* block, T value, if (assumeAligned) { if (xorBlock) - *reinterpret_cast(block) = ByteReverseIf(value, order) + *reinterpret_cast(block) = ByteReverseIf(value, order) ^ *reinterpret_cast(xorBlock); else *reinterpret_cast(block) = ByteReverseIf(value, order); @@ -759,7 +759,7 @@ struct BlockGetAndPut { // function needed because of C++ grammatical ambiguity between // expression-statements and declarations - static inline GetBlock Get(const void *block) + static inline GetBlock Get(const void *block) {return GetBlock(block);} typedef PutBlock Put; }; diff --git a/cdk/extra/yassl/taocrypt/include/modarith.hpp b/cdk/extra/yassl/taocrypt/include/modarith.hpp index 5ac3f67ab..f84436d6d 100644 --- a/cdk/extra/yassl/taocrypt/include/modarith.hpp +++ b/cdk/extra/yassl/taocrypt/include/modarith.hpp @@ -45,8 +45,8 @@ class ModularArithmetic : public AbstractRing modulus(ma.modulus), result((word)0, modulus.reg_.size()) {} const Integer& GetModulus() const {return modulus;} - void SetModulus(const Integer &newModulus) - { + void SetModulus(const Integer &newModulus) + { modulus = newModulus; result.reg_.resize(modulus.reg_.size()); } diff --git a/cdk/extra/yassl/taocrypt/include/modes.hpp b/cdk/extra/yassl/taocrypt/include/modes.hpp index bfe8c6ec5..b9c4f0ec4 100644 --- a/cdk/extra/yassl/taocrypt/include/modes.hpp +++ b/cdk/extra/yassl/taocrypt/include/modes.hpp @@ -38,11 +38,11 @@ class BlockCipher { public: BlockCipher() : cipher_(DIR, MODE) {} - void Process(byte* c, const byte* p, word32 sz) + void Process(byte* c, const byte* p, word32 sz) { cipher_.Process(c, p, sz); } - void SetKey(const byte* k, word32 sz) + void SetKey(const byte* k, word32 sz) { cipher_.SetKey(k, sz, DIR); } - void SetKey(const byte* k, word32 sz, const byte* iv) + void SetKey(const byte* k, word32 sz, const byte* iv) { cipher_.SetKey(k, sz, DIR); cipher_.SetIV(iv); } private: T cipher_; @@ -57,7 +57,7 @@ class Mode_BASE : public virtual_base { public: enum { MaxBlockSz = 16 }; - explicit Mode_BASE(int sz, CipherDir dir, Mode mode) + explicit Mode_BASE(int sz, CipherDir dir, Mode mode) : blockSz_(sz), reg_(reinterpret_cast(r_)), tmp_(reinterpret_cast(t_)), dir_(dir), mode_(mode) {} diff --git a/cdk/extra/yassl/taocrypt/include/rsa.hpp b/cdk/extra/yassl/taocrypt/include/rsa.hpp index ee3e378a6..030970325 100644 --- a/cdk/extra/yassl/taocrypt/include/rsa.hpp +++ b/cdk/extra/yassl/taocrypt/include/rsa.hpp @@ -38,11 +38,11 @@ class PK_Lengths { explicit PK_Lengths(const Integer& i) : image_(i) {} word32 PaddedBlockBitLength() const {return image_.BitCount() - 1;} - word32 PaddedBlockByteLength() const + word32 PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} word32 FixedCiphertextLength() const {return image_.ByteCount();} - word32 FixedMaxPlaintextLength() const + word32 FixedMaxPlaintextLength() const {return SaturatingSubtract(PaddedBlockBitLength() / 8, 10U); } }; @@ -101,7 +101,7 @@ class RSA_PrivateKey : public RSA_PublicKey { explicit RSA_PrivateKey(Source&); void Initialize(const Integer& n, const Integer& e, const Integer& d, - const Integer& p, const Integer& q, const Integer& dp, + const Integer& p, const Integer& q, const Integer& dp, const Integer& dq, const Integer& u) {n_ = n; e_ = e; d_ = d; p_ = p; q_ = q; dp_ = dp; dq_ = dq; u_ = u;} void Initialize(Source&); @@ -113,7 +113,7 @@ class RSA_PrivateKey : public RSA_PublicKey { const Integer& GetPrivateExponent() const {return d_;} const Integer& GetModPrime1PrivateExponent() const {return dp_;} const Integer& GetModPrime2PrivateExponent() const {return dq_;} - const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return u_;} void SetPrime1(const Integer& p) {p_ = p;} @@ -140,7 +140,7 @@ class RSA_BlockType2 { // block type 1 padding class RSA_BlockType1 { public: - void Pad(const byte*, word32, byte*, word32, + void Pad(const byte*, word32, byte*, word32, RandomNumberGenerator&) const; word32 UnPad(const byte*, word32, byte*) const; }; @@ -199,7 +199,7 @@ word32 RSA_Decryptor::Decrypt(const byte* cipher, word32 sz, byte* plain, if (sz != lengths.FixedCiphertextLength()) return 0; - + ByteBlock paddedBlock(lengths.PaddedBlockByteLength()); Integer x = key_.CalculateInverse(rng, Integer(cipher, lengths.FixedCiphertextLength()).Ref()); diff --git a/cdk/extra/yassl/taocrypt/include/runtime.hpp b/cdk/extra/yassl/taocrypt/include/runtime.hpp index b41f20c6d..accd86a37 100644 --- a/cdk/extra/yassl/taocrypt/include/runtime.hpp +++ b/cdk/extra/yassl/taocrypt/include/runtime.hpp @@ -25,6 +25,9 @@ #ifndef yaSSL_NEW_HPP #define yaSSL_NEW_HPP +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #ifdef YASSL_PURE_C diff --git a/cdk/extra/yassl/taocrypt/include/types.hpp b/cdk/extra/yassl/taocrypt/include/types.hpp index ce6ea0809..67ea2609a 100644 --- a/cdk/extra/yassl/taocrypt/include/types.hpp +++ b/cdk/extra/yassl/taocrypt/include/types.hpp @@ -22,6 +22,9 @@ #ifndef TAO_CRYPT_TYPES_HPP #define TAO_CRYPT_TYPES_HPP +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif namespace TaoCrypt { @@ -48,7 +51,7 @@ typedef unsigned int word32; #define WORD64_AVAILABLE typedef unsigned long word64; #define W64LIT(x) x##LL -#elif SIZEOF_LONG_LONG == 8 +#elif SIZEOF_LONG_LONG == 8 #define WORD64_AVAILABLE #define WORD64_IS_DISTINCT_TYPE typedef unsigned long long word64; @@ -63,10 +66,10 @@ typedef unsigned int word32; #endif #endif - + #if defined(HAVE_64_MULTIPLY) && (defined(__ia64__) \ || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__) \ - || defined(_M_X64) || defined(_M_IA64)) + || defined(_M_X64) || defined(_M_IA64)) // These platforms have 64-bit CPU registers. Unfortunately most C++ compilers // don't allow any way to access the 64-bit by 64-bit multiply instruction // without using assembly, so in order to use word64 as word, the assembly diff --git a/cdk/extra/yassl/taocrypt/src/aes.cpp b/cdk/extra/yassl/taocrypt/src/aes.cpp index ee4c7a6e8..87c8c074b 100644 --- a/cdk/extra/yassl/taocrypt/src/aes.cpp +++ b/cdk/extra/yassl/taocrypt/src/aes.cpp @@ -47,7 +47,7 @@ void AES::Process(byte* out, const byte* in, word32 sz) if (dir_ == ENCRYPTION) AsmEncrypt(in, out, (void*)Te0); else - AsmDecrypt(in, out, (void*)Td0); + AsmDecrypt(in, out, (void*)Td0); out += BLOCK_SIZE; in += BLOCK_SIZE; } @@ -69,7 +69,7 @@ void AES::Process(byte* out, const byte* in, word32 sz) else { while (blocks--) { AsmDecrypt(in, out, (void*)Td0); - + *(word32*)out ^= r_[0]; *(word32*)(out + 4) ^= r_[1]; *(word32*)(out + 8) ^= r_[2]; @@ -94,7 +94,7 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) keylen = 32; else if (keylen != 24) keylen = 24; - + rounds_ = keylen/4 + 6; word32 temp, *rk = key_; @@ -109,10 +109,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[3]; rk[4] = rk[0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; @@ -128,10 +128,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; @@ -149,10 +149,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; @@ -161,10 +161,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) break; temp = rk[11]; rk[12] = rk[ 4] ^ - (Te4[GETBYTE(temp, 3)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 0)] & 0x000000ff); + (Te2[GETBYTE(temp, 3)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 0)] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; @@ -191,25 +191,25 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) for (i = 1; i < rounds_; i++) { rk += 4; rk[0] = - Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[0], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[0], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[0], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[0], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[0], 0)] & 0xff]; rk[1] = - Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[1], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[1], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[1], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[1], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[1], 0)] & 0xff]; rk[2] = - Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[2], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[2], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[2], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[2], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[2], 0)] & 0xff]; rk[3] = - Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[3], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[3], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[3], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[3], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[3], 0)] & 0xff]; } } } @@ -226,7 +226,7 @@ void AES::ProcessAndXorBlock(const byte* in, const byte* xOr, byte* out) const typedef BlockGetAndPut gpBlock; - + void AES::encrypt(const byte* inBlock, const byte* xorBlock, byte* outBlock) const { @@ -243,7 +243,8 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; - + + s0 |= PreFetchTe(); /* * Nr - 1 full rounds: */ @@ -279,7 +280,7 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, if (--r == 0) { break; } - + s0 = Te0[GETBYTE(t0, 3)] ^ Te1[GETBYTE(t1, 2)] ^ @@ -312,28 +313,28 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, */ s0 = - (Te4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t0, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t3, 0)] & 0x000000ff) ^ rk[0]; s1 = - (Te4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t1, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t0, 0)] & 0x000000ff) ^ rk[1]; s2 = - (Te4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t2, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t1, 0)] & 0x000000ff) ^ rk[2]; s3 = - (Te4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t3, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t2, 0)] & 0x000000ff) ^ rk[3]; @@ -358,6 +359,8 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, s2 ^= rk[2]; s3 ^= rk[3]; + s0 |= PreFetchTd(); + /* * Nr - 1 full rounds: */ @@ -423,29 +426,32 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, * apply last round and * map cipher state to byte array block: */ + + t0 |= PreFetchCTd4(); + s0 = - (Td4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t1, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t0, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t3, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t2, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t1, 0)]) ^ rk[0]; s1 = - (Td4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t2, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t1, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t0, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t3, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t2, 0)]) ^ rk[1]; s2 = - (Td4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t3, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t2, 3)] << 24 ) ^ + ((word32)CTd4[GETBYTE(t1, 2)] << 16 ) ^ + ((word32)CTd4[GETBYTE(t0, 1)] << 8 ) ^ + ((word32)CTd4[GETBYTE(t3, 0)]) ^ rk[2]; s3 = - (Td4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t0, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t3, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t2, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t1, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t0, 0)]) ^ rk[3]; gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); @@ -466,13 +472,13 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, "movd mm7, ebp;" \ "movd mm4, eax;" \ "mov ebp, edx;" \ - "sub esp, 4;" + "sub esp, 4;" #define EPILOG() \ "add esp, 4;" \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "S" (inBlock), "d" (boxes), "a" (outBlock) \ : "%edi", "memory", "cc" \ @@ -502,13 +508,13 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 12 ) - - + + #endif #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -528,7 +534,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS1( dec edx ) AS2( movd mm6, edi ) // save rk AS2( movd mm5, edx ) // save rounds - + AS2( mov eax, DWORD PTR [esi] ) AS2( mov ebx, DWORD PTR [esi + 4] ) AS2( mov ecx, DWORD PTR [esi + 8] ) @@ -549,17 +555,17 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const #else AS1(1: ) // loop1 #endif - /* Put0 (mm0) = + /* Put0 (mm0) = Te0[get0,rs 24] ^ Te1[get1,rs 16] ^ Te2[get2,rs 8] ^ Te3[get3,rs 0] */ - + AS2( mov esi, eax ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ebx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -573,7 +579,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm0, esi ) - /* Put1 (mm1) = + /* Put1 (mm1) = Te0[get1,rs 24] ^ Te1[get2,rs 16] ^ Te2[get3,rs 8] ^ @@ -598,11 +604,11 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm1, esi ) - /* Put2 (mm2) = + /* Put2 (mm2) = Te0[get2,rs 24] ^ Te1[get3,rs 16] ^ Te2[get0,rs 8] ^ - Te3[get1,rs 0] + Te3[get1,rs 0] */ AS2( mov esi, ecx ) @@ -622,11 +628,11 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm2, esi ) - /* Put3 (edx) = + /* Put3 (edx) = Te0[get3,rs 24] ^ Te1[get0,rs 16] ^ Te2[get1,rs 8] ^ - Te3[get2,rs 0] + Te3[get2,rs 0] */ AS2( mov esi, edx ) @@ -792,7 +798,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( and esi, 255 ) AS2( xor edx, esi ) - + // xOr AS2( movd eax, mm0 ) AS2( movd esi, mm6 ) // rk @@ -833,7 +839,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -844,12 +850,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const #ifdef OLD_GCC_OFFSET AS2( mov edx, DWORD PTR [ecx + 60] ) // rounds - AS2( lea edi, [ecx + 64] ) // rk + AS2( lea edi, [ecx + 64] ) // rk #else AS2( mov edx, DWORD PTR [ecx + 56] ) // rounds - AS2( lea edi, [ecx + 60] ) // rk + AS2( lea edi, [ecx + 60] ) // rk #endif - + AS1( dec edx ) AS2( movd mm6, edi ) // save rk AS2( movd mm5, edx ) // save rounds @@ -879,12 +885,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get0, rs24)] ^ Td1[GETBYTE(get3, rs16)] ^ Td2[GETBYTE(get2, rs 8)] ^ - Td3[GETBYTE(tet1, )] + Td3[GETBYTE(tet1, )] */ AS2( mov esi, eax ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, edx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -902,12 +908,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get1, rs24)] ^ Td1[GETBYTE(get0, rs16)] ^ Td2[GETBYTE(get3, rs 8)] ^ - Td3[GETBYTE(tet2, )] + Td3[GETBYTE(tet2, )] */ AS2( mov esi, ebx ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, eax ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -925,12 +931,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get2, rs24)] ^ Td1[GETBYTE(get1, rs16)] ^ Td2[GETBYTE(get0, rs 8)] ^ - Td3[GETBYTE(tet3, )] + Td3[GETBYTE(tet3, )] */ AS2( mov esi, ecx ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ebx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -948,12 +954,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get3, rs24)] ^ Td1[GETBYTE(get2, rs16)] ^ Td2[GETBYTE(get1, rs 8)] ^ - Td3[GETBYTE(tet0, )] + Td3[GETBYTE(tet0, )] */ AS2( mov esi, edx ) AS2( shr esi, 24 ) AS2( mov edx, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ecx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -1826,18 +1832,52 @@ const word32 AES::Td[5][256] = { } }; +const byte AES::CTd4[256] = +{ + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; + const word32* AES::Te0 = AES::Te[0]; const word32* AES::Te1 = AES::Te[1]; const word32* AES::Te2 = AES::Te[2]; const word32* AES::Te3 = AES::Te[3]; -const word32* AES::Te4 = AES::Te[4]; const word32* AES::Td0 = AES::Td[0]; const word32* AES::Td1 = AES::Td[1]; const word32* AES::Td2 = AES::Td[2]; const word32* AES::Td3 = AES::Td[3]; -const word32* AES::Td4 = AES::Td[4]; diff --git a/cdk/extra/yassl/taocrypt/src/aestables.cpp b/cdk/extra/yassl/taocrypt/src/aestables.cpp index 60795a549..82e0a9aea 100644 --- a/cdk/extra/yassl/taocrypt/src/aestables.cpp +++ b/cdk/extra/yassl/taocrypt/src/aestables.cpp @@ -28,7 +28,7 @@ namespace TaoCrypt { const word32 AES::rcon_[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; diff --git a/cdk/extra/yassl/taocrypt/src/algebra.cpp b/cdk/extra/yassl/taocrypt/src/algebra.cpp index ace17047a..0f5b76687 100644 --- a/cdk/extra/yassl/taocrypt/src/algebra.cpp +++ b/cdk/extra/yassl/taocrypt/src/algebra.cpp @@ -193,8 +193,8 @@ struct WindowSlider if (windowSize == 0) { unsigned int expLen = exp.BitCount(); - windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : - (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : + windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : + (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7))))); } windowModulus <<= windowSize; @@ -259,7 +259,7 @@ void AbstractGroup::SimultaneousMultiply(Integer *results, const Integer &base, notDone = false; for (i=0; i(tm& a, tm& b) { if (a.tm_year > b.tm_year) @@ -95,7 +95,7 @@ bool operator>(tm& a, tm& b) if (a.tm_year == b.tm_year && a.tm_mon > b.tm_mon) return true; - + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && a.tm_mday >b.tm_mday) return true; @@ -108,13 +108,18 @@ bool operator>(tm& a, tm& b) a.tm_min > b.tm_min) return true; + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && + a.tm_mday == b.tm_mday && a.tm_hour == b.tm_hour && + a.tm_min == b.tm_min && a.tm_sec > b.tm_sec) + return true; + return false; } bool operator<(tm& a, tm&b) { - return !(a>b); + return (b>a); } @@ -153,7 +158,7 @@ word32 GetLength(Source& source) word32 length = 0; byte b = source.next(); - if (b >= LONG_LENGTH) { + if (b >= LONG_LENGTH) { word32 bytes = b & 0x7F; if (source.IsLeft(bytes) == false) return 0; @@ -180,7 +185,7 @@ word32 SetLength(word32 length, byte* output) output[i++] = length; else { output[i++] = BytePrecision(length) | 0x80; - + for (int j = BytePrecision(length); j; --j) { output[i] = length >> (j - 1) * 8; i++; @@ -244,8 +249,8 @@ Signer::~Signer() Error BER_Decoder::GetError() -{ - return source_.GetError(); +{ + return source_.GetError(); } @@ -256,7 +261,7 @@ Integer& BER_Decoder::GetInteger(Integer& integer) return integer; } - + // Read a Sequence, return length word32 BER_Decoder::GetSequence() { @@ -319,9 +324,9 @@ word32 BER_Decoder::GetExplicitVersion() source_.next(); return GetVersion(); } - else + else source_.prev(); // put back - + return 0; } @@ -364,7 +369,7 @@ void DSA_Private_Decoder::Decode(DSA_PrivateKey& key) // key key.SetPublicPart(GetInteger(Integer().Ref())); - key.SetPrivatePart(GetInteger(Integer().Ref())); + key.SetPrivatePart(GetInteger(Integer().Ref())); } @@ -408,27 +413,27 @@ void RSA_Public_Decoder::ReadHeaderOpenSSL() source_.advance(len); b = source_.next(); - if (b == TAG_NULL) { // could have NULL tag and 0 terminator, may not + if (b == TAG_NULL) { // could have NULL tag and 0 terminator, may not b = source_.next(); if (b != 0) { source_.SetError(EXPECT_0_E); - return; + return; } } else source_.prev(); // put back b = source_.next(); - if (b != BIT_STRING) { + if (b != BIT_STRING) { source_.SetError(BIT_STR_E); - return; + return; } - len = GetLength(source_); + len = GetLength(source_); b = source_.next(); if (b != 0) // could have 0 source_.prev(); // put back - + GetSequence(); } } @@ -482,8 +487,9 @@ void DH_Decoder::Decode(DH& key) CertDecoder::CertDecoder(Source& s, bool decode, SignerList* signers, bool noVerify, CertType ct) - : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), - signature_(0), verify_(!noVerify) + : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), subCnPos_(-1), + subCnLen_(0), issCnPos_(-1), issCnLen_(0), signature_(0), + verify_(!noVerify) { issuer_[0] = 0; subject_[0] = 0; @@ -534,7 +540,7 @@ void CertDecoder::Decode(SignerList* signers, CertType ct) source_.SetError(SIG_OID_E); return; } - + if (ct != CA && verify_ && !ValidateSignature(signers)) source_.SetError(SIG_OTHER_E); } @@ -544,9 +550,9 @@ void CertDecoder::DecodeToKey() { ReadHeader(); signatureOID_ = GetAlgoId(); - GetName(ISSUER); + GetName(ISSUER); GetValidity(); - GetName(SUBJECT); + GetName(SUBJECT); GetKey(); } @@ -556,7 +562,7 @@ void CertDecoder::GetKey() { if (source_.GetError().What()) return; - GetSequence(); + GetSequence(); keyOID_ = GetAlgoId(); if (keyOID_ == RSAk) { @@ -566,7 +572,7 @@ void CertDecoder::GetKey() return; } b = source_.next(); // length, future - b = source_.next(); + b = source_.next(); while(b != 0) b = source_.next(); } @@ -615,7 +621,7 @@ void CertDecoder::AddDSA() return; } b = source_.next(); // length, future - b = source_.next(); + b = source_.next(); while(b != 0) b = source_.next(); @@ -631,7 +637,7 @@ void CertDecoder::AddDSA() if (source_.IsLeft(length) == false) return; - key_.AddToEnd(source_.get_buffer() + idx, length); + key_.AddToEnd(source_.get_buffer() + idx, length); } @@ -642,7 +648,7 @@ word32 CertDecoder::GetAlgoId() word32 length = GetSequence(); if (source_.GetError().What()) return 0; - + byte b = source_.next(); if (b != OBJECT_IDENTIFIER) { source_.SetError(OBJECT_ID_E); @@ -689,7 +695,7 @@ word32 CertDecoder::GetSignature() source_.SetError(CONTENT_E); return 0; } - + b = source_.next(); if (b != 0) { source_.SetError(EXPECT_0_E); @@ -757,7 +763,7 @@ void CertDecoder::GetName(NameType nt) return; if (source_.IsLeft(length) == false) return; length += source_.get_index(); - + char* ptr; char* buf_end; @@ -773,7 +779,7 @@ void CertDecoder::GetName(NameType nt) while (source_.get_index() < length) { GetSet(); if (source_.GetError().What() == SET_E) { - source_.SetError(NO_ERROR_E); // extensions may only have sequence + source_.SetError(NO_ERROR_E); // extensions may only have sequence source_.prev(); } GetSequence(); @@ -794,7 +800,7 @@ void CertDecoder::GetName(NameType nt) // v1 name types if (joint[0] == 0x55 && joint[1] == 0x04) { source_.advance(2); - byte id = source_.next(); + byte id = source_.next(); b = source_.next(); // strType word32 strLen = GetLength(source_); @@ -804,6 +810,13 @@ void CertDecoder::GetName(NameType nt) case COMMON_NAME: if (!(ptr = AddTag(ptr, buf_end, "/CN=", 4, strLen))) return; + if (nt == ISSUER) { + issCnPos_ = (int)(ptr - strLen - issuer_); + issCnLen_ = (int)strLen; + } else { + subCnPos_ = (int)(ptr - strLen - subject_); + subCnLen_ = (int)strLen; + } break; case SUR_NAME: if (!(ptr = AddTag(ptr, buf_end, "/SN=", 4, strLen))) @@ -834,7 +847,7 @@ void CertDecoder::GetName(NameType nt) sha.Update(source_.get_current(), strLen); source_.advance(strLen); } - else { + else { bool email = false; if (joint[0] == 0x2a && joint[1] == 0x86) // email id hdr email = true; @@ -845,7 +858,7 @@ void CertDecoder::GetName(NameType nt) if (email) { if (!(ptr = AddTag(ptr, buf_end, "/emailAddress=", 14, length))) - return; + return; } source_.advance(length); @@ -901,7 +914,7 @@ void CertDecoder::GetDate(DateType dt) memcpy(afterDate_, date, length); afterDate_[length] = 0; afterDateType_= b; - } + } } @@ -955,11 +968,11 @@ bool CertDecoder::ValidateSignature(SignerList* signers) while (first != last) { if ( memcmp(issuerHash_, (*first)->GetHash(), SHA::DIGEST_SIZE) == 0) { - + const PublicKey& iKey = (*first)->GetPublicKey(); Source pub(iKey.GetKey(), iKey.size()); return ConfirmSignature(pub); - } + } ++first; } return false; @@ -1067,7 +1080,7 @@ word32 Signature_Encoder::SetDigest(const byte* d, word32 dSz, byte* output) output[0] = OCTET_STRING; output[1] = dSz; memcpy(&output[2], d, dSz); - + return dSz + 2; } @@ -1145,7 +1158,7 @@ word32 DER_Encoder::SetAlgoID(HashType aOID, byte* output) word32 SetSequence(word32 len, byte* output) { - + output[0] = SEQUENCE | CONSTRUCTED; return SetLength(len, output + 1) + 1; } @@ -1177,7 +1190,7 @@ word32 EncodeDSA_Signature(const Integer& r, const Integer& s, byte* output) byte seqArray[MAX_SEQ_SZ]; word32 seqSz = SetSequence(rLenSz + rSz + sLenSz + sSz, seqArray); - + // seq memcpy(output, seqArray, seqSz); // r @@ -1210,17 +1223,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 rLen = GetLength(source); if (rLen != 20) { - if (rLen == 21) { // zero at front, eat + while (rLen > 20 && source.remaining() > 0) { // zero's at front, eat source.next(); --rLen; } - else if (rLen == 19) { // add zero to front so 20 bytes + if (rLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = rLen; + while (tmpLen < 20) { decoded[0] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded, source.get_buffer() + source.get_index(), rLen); @@ -1233,17 +1246,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 sLen = GetLength(source); if (sLen != 20) { - if (sLen == 21) { - source.next(); // zero at front, eat + while (sLen > 20 && source.remaining() > 0) { + source.next(); // zero's at front, eat --sLen; } - else if (sLen == 19) { - decoded[rLen] = 0; // add zero to front so 20 bytes + if (sLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = sLen; + while (tmpLen < 20) { + decoded[rLen] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded + rLen, source.get_buffer() + source.get_index(), sLen); @@ -1265,7 +1278,7 @@ int GetCert(Source& source) if (!begin || !end || begin >= end) return -1; - end += strlen(footer); + end += strlen(footer); if (*end == '\r') end++; Source tmp((byte*)begin, end - begin + 1); @@ -1285,7 +1298,7 @@ void PKCS12_Decoder::Decode() // Get AuthSafe GetSequence(); - + // get object id byte obj_id = source_.next(); if (obj_id != OBJECT_IDENTIFIER) { @@ -1299,8 +1312,8 @@ void PKCS12_Decoder::Decode() while (length--) algo_sum += source_.next(); - - + + @@ -1308,7 +1321,7 @@ void PKCS12_Decoder::Decode() // mac digestInfo like certdecoder::getdigest? // macsalt octet string // iter integer - + } diff --git a/cdk/extra/yassl/taocrypt/src/coding.cpp b/cdk/extra/yassl/taocrypt/src/coding.cpp index bc4727cc5..c90d2c85f 100644 --- a/cdk/extra/yassl/taocrypt/src/coding.cpp +++ b/cdk/extra/yassl/taocrypt/src/coding.cpp @@ -37,7 +37,7 @@ const byte hexEncode[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, bad, bad, bad, bad, bad, bad, bad, - 10, 11, 12, 13, 14, 15 + 10, 11, 12, 13, 14, 15 }; // A starts at 0x41 not 0x3A @@ -135,7 +135,7 @@ void Base64Encoder::Encode() word32 i = 0; word32 j = 0; - + while (bytes > 2) { byte b1 = plain_.next(); byte b2 = plain_.next(); @@ -174,10 +174,10 @@ void Base64Encoder::Encode() encoded_[i++] = base64Encode[e2]; encoded_[i++] = (twoBytes) ? base64Encode[e3] : pad; encoded_[i++] = pad; - } + } encoded_[i++] = '\n'; - + if (i == outSz) plain_.reset(encoded_); } @@ -187,7 +187,7 @@ void Base64Encoder::Encode() void Base64Decoder::Decode() { word32 bytes = coded_.size(); - word32 plainSz = bytes - ((bytes + (pemLineSz - 1)) / pemLineSz); + word32 plainSz = bytes - ((bytes + (pemLineSz - 1)) / pemLineSz); const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1; plainSz = ((plainSz * 3) / 4) + 3; decoded_.New(plainSz); @@ -237,7 +237,7 @@ void Base64Decoder::Decode() decoded_[i++] = b3; else break; - + bytes -= 4; if ((++j % 16) == 0) { byte endLine = coded_.next(); @@ -251,7 +251,7 @@ void Base64Decoder::Decode() bytes--; } if (endLine != '\n') { - coded_.SetError(PEM_E); + coded_.SetError(PEM_E); return; } } diff --git a/cdk/extra/yassl/taocrypt/src/des.cpp b/cdk/extra/yassl/taocrypt/src/des.cpp index 53777f082..c1961684c 100644 --- a/cdk/extra/yassl/taocrypt/src/des.cpp +++ b/cdk/extra/yassl/taocrypt/src/des.cpp @@ -257,14 +257,14 @@ void BasicDES::SetKey(const byte* key, word32 /*length*/, CipherDir dir) | ((word32)ks[5] << 8) | ((word32)ks[7]); } - + // reverse key schedule order if (dir == DECRYPTION) for (i = 0; i < 16; i += 2) { STL::swap(k_[i], k_[32 - 2 - i]); STL::swap(k_[i+1], k_[32 - 1 - i]); } - + } static inline void IPERM(word32& left, word32& right) @@ -411,14 +411,14 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) word32 blocks = sz / DES_BLOCK_SIZE; - if (mode_ == CBC) + if (mode_ == CBC) if (dir_ == ENCRYPTION) while (blocks--) { r_[0] ^= *(word32*)in; r_[1] ^= *(word32*)(in + 4); AsmProcess((byte*)r_, (byte*)r_, (void*)Spbox); - + memcpy(out, r_, DES_BLOCK_SIZE); in += DES_BLOCK_SIZE; @@ -427,7 +427,7 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) else while (blocks--) { AsmProcess(in, out, (void*)Spbox); - + *(word32*)out ^= r_[0]; *(word32*)(out + 4) ^= r_[1]; @@ -439,7 +439,7 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) else while (blocks--) { AsmProcess(in, out, (void*)Spbox); - + out += DES_BLOCK_SIZE; in += DES_BLOCK_SIZE; } @@ -641,7 +641,7 @@ void DES_EDE3::ProcessAndXorBlock(const byte* in, const byte* xOr, #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -663,8 +663,8 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "d" (this), "S" (in), "a" (box), "c" (out) \ : "%edi", "memory", "cc" \ @@ -724,7 +724,7 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const DesRound() // 7 DesRound() // 8 - // swap left and right + // swap left and right AS2( xchg eax, ebx ) DesRound() // 1 @@ -765,7 +765,7 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const AS2( mov DWORD PTR [esi], ebx ) // right first AS2( mov DWORD PTR [esi + 4], eax ) - + EPILOG() } diff --git a/cdk/extra/yassl/taocrypt/src/dsa.cpp b/cdk/extra/yassl/taocrypt/src/dsa.cpp index bf116d3e4..a139195a7 100644 --- a/cdk/extra/yassl/taocrypt/src/dsa.cpp +++ b/cdk/extra/yassl/taocrypt/src/dsa.cpp @@ -70,7 +70,7 @@ void DSA_PublicKey::Initialize(const Integer& p, const Integer& q, g_ = g; y_ = y; } - + const Integer& DSA_PublicKey::GetModulus() const { @@ -172,6 +172,7 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, const Integer& q = key_.GetSubGroupOrder(); const Integer& g = key_.GetSubGroupGenerator(); const Integer& x = key_.GetPrivatePart(); + byte* tmpPtr = sig; // initial signature output Integer k(rng, 1, q - 1); @@ -187,22 +188,23 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, return -1; int rSz = r_.ByteCount(); + int tmpSz = rSz; - if (rSz == 19) { - sig[0] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - + r_.Encode(sig, rSz); + sig = tmpPtr + SHA::DIGEST_SIZE; // advance sig output to s int sSz = s_.ByteCount(); + tmpSz = sSz; - if (sSz == 19) { - sig[rSz] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - s_.Encode(sig + rSz, sSz); + s_.Encode(sig, sSz); return 40; } diff --git a/cdk/extra/yassl/taocrypt/src/file.cpp b/cdk/extra/yassl/taocrypt/src/file.cpp index 7c2044bf3..929501f36 100644 --- a/cdk/extra/yassl/taocrypt/src/file.cpp +++ b/cdk/extra/yassl/taocrypt/src/file.cpp @@ -107,7 +107,7 @@ void FileSink::put(Source& source) // swap with other and reset to beginning void Source::reset(ByteBlock& otherBlock) { - buffer_.Swap(otherBlock); + buffer_.Swap(otherBlock); current_ = 0; } diff --git a/cdk/extra/yassl/taocrypt/src/hash.cpp b/cdk/extra/yassl/taocrypt/src/hash.cpp index c176e6a68..c479b7007 100644 --- a/cdk/extra/yassl/taocrypt/src/hash.cpp +++ b/cdk/extra/yassl/taocrypt/src/hash.cpp @@ -92,9 +92,9 @@ void HASHwithTransform::Final(byte* hash) buffLen_ = 0; } memset(&local[buffLen_], 0, padSz - buffLen_); - + ByteReverseIf(local, local, blockSz, order); - + memcpy(&local[padSz], order ? &preHiLen : &preLoLen, sizeof(preLoLen)); memcpy(&local[padSz+4], order ? &preLoLen : &preHiLen, sizeof(preLoLen)); @@ -172,9 +172,9 @@ void HASH64withTransform::Final(byte* hash) buffLen_ = 0; } memset(&local[buffLen_], 0, padSz - buffLen_); - + ByteReverseIf(buffer_, buffer_, padSz, order); - + buffer_[blockSz / sizeof(word64) - 2] = order ? preHiLen : preLoLen; buffer_[blockSz / sizeof(word64) - 1] = order ? preLoLen : preHiLen; diff --git a/cdk/extra/yassl/taocrypt/src/hc128.cpp b/cdk/extra/yassl/taocrypt/src/hc128.cpp index 1d329c87e..df2c3619e 100644 --- a/cdk/extra/yassl/taocrypt/src/hc128.cpp +++ b/cdk/extra/yassl/taocrypt/src/hc128.cpp @@ -60,7 +60,7 @@ namespace TaoCrypt { (T_[(u)]) += tem2+(tem0 ^ tem1); \ (X_[(a)]) = (T_[(u)]); \ (n) = tem3 ^ (T_[(u)]) ; \ -} +} /*one step of HC-128, update Q and generate 32 bits keystream*/ #define step_Q(u,v,a,b,c,d,n){ \ @@ -72,18 +72,18 @@ namespace TaoCrypt { (T_[(u)]) += tem2 + (tem0 ^ tem1); \ (Y_[(a)]) = (T_[(u)]); \ (n) = tem3 ^ (T_[(u)]) ; \ -} +} /*16 steps of HC-128, generate 512 bits keystream*/ -void HC128::GenerateKeystream(word32* keystream) +void HC128::GenerateKeystream(word32* keystream) { word32 cc,dd; cc = counter1024_ & 0x1ff; dd = (cc+16)&0x1ff; - if (counter1024_ < 512) - { + if (counter1024_ < 512) + { counter1024_ = (counter1024_ + 16) & 0x3ff; step_P(cc+0, cc+1, 0, 6, 13,4, keystream[0]); step_P(cc+1, cc+2, 1, 7, 14,5, keystream[1]); @@ -102,9 +102,9 @@ void HC128::GenerateKeystream(word32* keystream) step_P(cc+14,cc+15,14,4, 11,2, keystream[14]); step_P(cc+15,dd+0, 15,5, 12,3, keystream[15]); } - else + else { - counter1024_ = (counter1024_ + 16) & 0x3ff; + counter1024_ = (counter1024_ + 16) & 0x3ff; step_Q(512+cc+0, 512+cc+1, 0, 6, 13,4, keystream[0]); step_Q(512+cc+1, 512+cc+2, 1, 7, 14,5, keystream[1]); step_Q(512+cc+2, 512+cc+3, 2, 8, 15,6, keystream[2]); @@ -138,7 +138,7 @@ void HC128::GenerateKeystream(word32* keystream) h1((X_[(d)]),tem3); \ (T_[(u)]) = ((T_[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ (X_[(a)]) = (T_[(u)]); \ -} +} /*update table Q*/ #define update_Q(u,v,a,b,c,d){ \ @@ -149,7 +149,7 @@ void HC128::GenerateKeystream(word32* keystream) h2((Y_[(d)]),tem3); \ (T_[(u)]) = ((T_[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ (Y_[(a)]) = (T_[(u)]); \ -} +} /*16 steps of HC-128, without generating keystream, */ /*but use the outputs to update P and Q*/ @@ -159,8 +159,8 @@ void HC128::SetupUpdate() /*each time 16 steps*/ cc = counter1024_ & 0x1ff; dd = (cc+16)&0x1ff; - if (counter1024_ < 512) - { + if (counter1024_ < 512) + { counter1024_ = (counter1024_ + 16) & 0x3ff; update_P(cc+0, cc+1, 0, 6, 13, 4); update_P(cc+1, cc+2, 1, 7, 14, 5); @@ -177,9 +177,9 @@ void HC128::SetupUpdate() /*each time 16 steps*/ update_P(cc+12,cc+13,12,2, 9, 0); update_P(cc+13,cc+14,13,3, 10, 1); update_P(cc+14,cc+15,14,4, 11, 2); - update_P(cc+15,dd+0, 15,5, 12, 3); + update_P(cc+15,dd+0, 15,5, 12, 3); } - else + else { counter1024_ = (counter1024_ + 16) & 0x3ff; update_Q(512+cc+0, 512+cc+1, 0, 6, 13, 4); @@ -197,8 +197,8 @@ void HC128::SetupUpdate() /*each time 16 steps*/ update_Q(512+cc+12,512+cc+13,12,2, 9, 0); update_Q(512+cc+13,512+cc+14,13,3, 10, 1); update_Q(512+cc+14,512+cc+15,14,4, 11, 2); - update_Q(512+cc+15,512+dd+0, 15,5, 12, 3); - } + update_Q(512+cc+15,512+dd+0, 15,5, 12, 3); + } } @@ -220,46 +220,46 @@ void HC128::SetupUpdate() /*each time 16 steps*/ void HC128::SetIV(const byte* iv) -{ +{ word32 i; - - for (i = 0; i < (128 >> 5); i++) + + for (i = 0; i < (128 >> 5); i++) iv_[i] = LITTLE32(((word32*)iv)[i]); - + for (; i < 8; i++) iv_[i] = iv_[i-4]; - - /* expand the key and IV into the table T */ - /* (expand the key and IV into the table P and Q) */ - - for (i = 0; i < 8; i++) T_[i] = key_[i]; - for (i = 8; i < 16; i++) T_[i] = iv_[i-8]; - - for (i = 16; i < (256+16); i++) - T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+i; - - for (i = 0; i < 16; i++) T_[i] = T_[256+i]; - - for (i = 16; i < 1024; i++) - T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+256+i; - + + /* expand the key and IV into the table T */ + /* (expand the key and IV into the table P and Q) */ + + for (i = 0; i < 8; i++) T_[i] = key_[i]; + for (i = 8; i < 16; i++) T_[i] = iv_[i-8]; + + for (i = 16; i < (256+16); i++) + T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+i; + + for (i = 0; i < 16; i++) T_[i] = T_[256+i]; + + for (i = 16; i < 1024; i++) + T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+256+i; + /* initialize counter1024, X and Y */ - counter1024_ = 0; - for (i = 0; i < 16; i++) X_[i] = T_[512-16+i]; + counter1024_ = 0; + for (i = 0; i < 16; i++) X_[i] = T_[512-16+i]; for (i = 0; i < 16; i++) Y_[i] = T_[512+512-16+i]; - + /* run the cipher 1024 steps before generating the output */ - for (i = 0; i < 64; i++) SetupUpdate(); + for (i = 0; i < 64; i++) SetupUpdate(); } void HC128::SetKey(const byte* key, const byte* iv) -{ - word32 i; +{ + word32 i; - /* Key size in bits 128 */ + /* Key size in bits 128 */ for (i = 0; i < (128 >> 5); i++) key_[i] = LITTLE32(((word32*)key)[i]); - + for ( ; i < 8 ; i++) key_[i] = key_[i-4]; SetIV(iv); @@ -273,25 +273,25 @@ void HC128::Process(byte* output, const byte* input, word32 msglen) for ( ; msglen >= 64; msglen -= 64, input += 64, output += 64) { - GenerateKeystream(keystream); + GenerateKeystream(keystream); /* unroll loop */ - ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); - ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); - ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); - ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); - ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); - ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); - ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); - ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); - ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); - ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); - ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); - ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); - ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); - ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); - ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); - ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); + ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); + ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); + ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); + ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); + ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); + ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); + ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); + ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); + ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); + ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); + ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); + ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); + ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); + ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); + ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); + ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); } if (msglen > 0) @@ -302,13 +302,13 @@ void HC128::Process(byte* output, const byte* input, word32 msglen) { word32 wordsLeft = msglen / sizeof(word32); if (msglen % sizeof(word32)) wordsLeft++; - + ByteReverse(keystream, keystream, wordsLeft * sizeof(word32)); } #endif for (i = 0; i < msglen; i++) - output[i] = input[i] ^ ((byte*)keystream)[i]; + output[i] = input[i] ^ ((byte*)keystream)[i]; } } diff --git a/cdk/extra/yassl/taocrypt/src/integer.cpp b/cdk/extra/yassl/taocrypt/src/integer.cpp index 478a13cd8..d97376fe4 100644 --- a/cdk/extra/yassl/taocrypt/src/integer.cpp +++ b/cdk/extra/yassl/taocrypt/src/integer.cpp @@ -27,7 +27,7 @@ #endif #if defined(_M_X64) || defined(_M_IA64) - #include + #include #pragma intrinsic(_umul128) #endif @@ -359,7 +359,7 @@ S DivideThreeWordsByTwo(S* A, S B0, S B1, D* dummy_VC6_WorkAround = 0) D p = D::Multiply(B0, Q); D u = (D) A[0] - p.GetLowHalf(); A[0] = u.GetLowHalf(); - u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - + u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - D::Multiply(B1, Q); A[1] = u.GetLowHalf(); A[2] += u.GetHighHalf(); @@ -389,7 +389,7 @@ inline D DivideFourWordsByTwo(S *T, const D &Al, const D &Ah, const D &B) { S Q[2]; T[0] = Al.GetLowHalf(); - T[1] = Al.GetHighHalf(); + T[1] = Al.GetHighHalf(); T[2] = Ah.GetLowHalf(); T[3] = Ah.GetHighHalf(); Q[1] = DivideThreeWordsByTwo(T+1, B.GetLowHalf(), @@ -1083,7 +1083,7 @@ static PMul s_pMul4, s_pMul8, s_pMul8B; static void SetPentiumFunctionPointers() { if (!IsPentium()) - { + { s_pAdd = &Portable::Add; s_pSub = &Portable::Subtract; } @@ -1099,7 +1099,7 @@ static void SetPentiumFunctionPointers() } #ifdef SSE2_INTRINSICS_AVAILABLE - if (!IsPentium()) + if (!IsPentium()) { s_pMul4 = &Portable::Multiply4; s_pMul8 = &Portable::Multiply8; @@ -1406,7 +1406,7 @@ TAOCRYPT_NAKED word P4Optimized::Subtract(word *C, const word *A, #define MulStartup \ AS2(xor ebp, ebp) \ AS2(xor edi, edi) \ - AS2(xor ebx, ebx) + AS2(xor ebx, ebx) #define MulShiftCarry \ AS2(mov ebp, edx) \ @@ -2160,7 +2160,7 @@ void RecursiveMultiply(word *R, word *T, const word *A, const word *B, } -void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) +void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) { if (LowLevel::SquareRecursionLimit() >= 4 && N==4) LowLevel::Square4(R, A); @@ -2581,7 +2581,7 @@ void Integer::Decode(Source& source) source.prev(); if (source.IsLeft(length) == false) return; - + unsigned int words = (length + WORD_SIZE - 1) / WORD_SIZE; words = RoundupSize(words); if (words > reg_.size()) reg_.CleanNew(words); @@ -2596,7 +2596,7 @@ void Integer::Decode(Source& source) void Integer::Decode(const byte* input, unsigned int inputLen, Signedness s) { unsigned int idx(0); - byte b = 0; + byte b = 0; if (inputLen>0) b = input[idx]; // peek sign_ = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE; @@ -3174,7 +3174,7 @@ static inline void AtomicDivide(word *Q, const word *A, const word *B) #ifndef NDEBUG if (B[0] || B[1]) { - // multiply quotient and divisor and add remainder, make sure it + // multiply quotient and divisor and add remainder, make sure it // equals dividend word P[4]; Portable::Multiply2(P, Q, B); @@ -3558,7 +3558,7 @@ const Integer& ModularArithmetic::Half(const Integer &a) const const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Add(result.reg_.begin(), a.reg_.begin(), b.reg_.begin(), @@ -3582,7 +3582,7 @@ const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Add(a.reg_.get_buffer(), a.reg_.get_buffer(), @@ -3607,7 +3607,7 @@ Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const const Integer& ModularArithmetic::Subtract(const Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Subtract(result.reg_.begin(), a.reg_.begin(), @@ -3627,7 +3627,7 @@ const Integer& ModularArithmetic::Subtract(const Integer &a, Integer& ModularArithmetic::Reduce(Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Subtract(a.reg_.get_buffer(), a.reg_.get_buffer(), diff --git a/cdk/extra/yassl/taocrypt/src/md2.cpp b/cdk/extra/yassl/taocrypt/src/md2.cpp index 3dfc0d6e7..a2fe0a107 100644 --- a/cdk/extra/yassl/taocrypt/src/md2.cpp +++ b/cdk/extra/yassl/taocrypt/src/md2.cpp @@ -44,7 +44,7 @@ void MD2::Init() void MD2::Update(const byte* data, word32 len) { - static const byte S[256] = + static const byte S[256] = { 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, diff --git a/cdk/extra/yassl/taocrypt/src/md4.cpp b/cdk/extra/yassl/taocrypt/src/md4.cpp index 9364a1c23..9fb789781 100644 --- a/cdk/extra/yassl/taocrypt/src/md4.cpp +++ b/cdk/extra/yassl/taocrypt/src/md4.cpp @@ -29,7 +29,7 @@ namespace STL = STL_NAMESPACE; - + namespace TaoCrypt { @@ -47,8 +47,8 @@ void MD4::Init() MD4::MD4(const MD4& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -108,7 +108,7 @@ void MD4::Transform() function(C,D,A,B,14,11); function(B,C,D,A,15,19); -#undef function +#undef function #define function(a,b,c,d,k,s) a=rotlFixed(a+G(b,c,d)+buffer_[k]+0x5a827999,s); function(A,B,C,D, 0, 3); function(D,A,B,C, 4, 5); @@ -127,7 +127,7 @@ void MD4::Transform() function(C,D,A,B,11, 9); function(B,C,D,A,15,13); -#undef function +#undef function #define function(a,b,c,d,k,s) a=rotlFixed(a+H(b,c,d)+buffer_[k]+0x6ed9eba1,s); function(A,B,C,D, 0, 3); function(D,A,B,C, 8, 9); diff --git a/cdk/extra/yassl/taocrypt/src/md5.cpp b/cdk/extra/yassl/taocrypt/src/md5.cpp index 45cfa8a33..bdc17c063 100644 --- a/cdk/extra/yassl/taocrypt/src/md5.cpp +++ b/cdk/extra/yassl/taocrypt/src/md5.cpp @@ -48,8 +48,8 @@ void MD5::Init() MD5::MD5(const MD5& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -91,7 +91,7 @@ void MD5::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -174,7 +174,7 @@ void MD5::Update(const byte* data, word32 len) // esi already set up, after using set for next round // ebp already set up, set up using next round index - + #define MD5STEP1(w, x, y, z, index, data, s) \ AS2( xor esi, z ) \ AS2( and esi, x ) \ @@ -223,7 +223,7 @@ void MD5::Update(const byte* data, word32 len) #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -242,8 +242,8 @@ void MD5::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "a" (times) \ : "%esi", "%edx", "memory", "cc" \ @@ -272,7 +272,7 @@ void MD5::AsmTransform(const byte* data, word32 times) AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 8 ) - + #endif @@ -288,16 +288,16 @@ void MD5::AsmTransform(const byte* data, word32 times) AS2( movd mm2, eax ) // store times_ AS2( movd mm1, esi ) // store digest_ - + AS2( mov eax, [esi] ) // a AS2( mov ebx, [esi + 4] ) // b AS2( mov ecx, [esi + 8] ) // c AS2( mov edx, [esi + 12] ) // d - + #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif // set up @@ -375,7 +375,7 @@ void MD5::AsmTransform(const byte* data, word32 times) MD5STEP4( edx, eax, ebx, ecx, 2, 0xbd3af235, 10) MD5STEP4( ecx, edx, eax, ebx, 9, 0x2ad7d2bb, 15) MD5STEP4( ebx, ecx, edx, eax, 9, 0xeb86d391, 21) - + AS2( movd esi, mm1 ) // digest_ AS2( add [esi], eax ) // write out @@ -417,7 +417,7 @@ void MD5::Transform() #define MD5STEP(f, w, x, y, z, data, s) \ w = rotlFixed(w + f(x, y, z) + data, s) + x - // Copy context->state[] to working vars + // Copy context->state[] to working vars word32 a = digest_[0]; word32 b = digest_[1]; word32 c = digest_[2]; @@ -490,7 +490,7 @@ void MD5::Transform() MD5STEP(F4, d, a, b, c, buffer_[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, buffer_[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, buffer_[9] + 0xeb86d391, 21); - + // Add the working vars back into digest state[] digest_[0] += a; digest_[1] += b; diff --git a/cdk/extra/yassl/taocrypt/src/misc.cpp b/cdk/extra/yassl/taocrypt/src/misc.cpp index b576d3d59..26c494d74 100644 --- a/cdk/extra/yassl/taocrypt/src/misc.cpp +++ b/cdk/extra/yassl/taocrypt/src/misc.cpp @@ -185,7 +185,7 @@ bool HaveCpuId() { mov eax, 0 cpuid - } + } } __except (1) { diff --git a/cdk/extra/yassl/taocrypt/src/rabbit.cpp b/cdk/extra/yassl/taocrypt/src/rabbit.cpp index 5e32f3834..614e0b425 100644 --- a/cdk/extra/yassl/taocrypt/src/rabbit.cpp +++ b/cdk/extra/yassl/taocrypt/src/rabbit.cpp @@ -89,7 +89,7 @@ void Rabbit::NextState(RabbitCtx which) ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5])); ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6])); ctx->carry = (ctx->c[7] < c_old[7]); - + /* Calculate the g-values */ for (i=0;i<8;i++) g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i])); @@ -111,7 +111,7 @@ void Rabbit::SetIV(const byte* iv) { /* Temporary variables */ word32 i0, i1, i2, i3, i; - + /* Generate four subvectors */ i0 = LITTLE32(*(word32*)(iv+0)); i2 = LITTLE32(*(word32*)(iv+4)); @@ -189,7 +189,7 @@ void Rabbit::SetKey(const byte* key, const byte* iv) } workCtx_.carry = masterCtx_.carry; - if (iv) SetIV(iv); + if (iv) SetIV(iv); } @@ -238,11 +238,11 @@ void Rabbit::Process(byte* output, const byte* input, word32 msglen) /* Generate 16 bytes of pseudo-random data */ tmp[0] = LITTLE32(workCtx_.x[0] ^ (workCtx_.x[5]>>16) ^ U32V(workCtx_.x[3]<<16)); - tmp[1] = LITTLE32(workCtx_.x[2] ^ + tmp[1] = LITTLE32(workCtx_.x[2] ^ (workCtx_.x[7]>>16) ^ U32V(workCtx_.x[5]<<16)); - tmp[2] = LITTLE32(workCtx_.x[4] ^ + tmp[2] = LITTLE32(workCtx_.x[4] ^ (workCtx_.x[1]>>16) ^ U32V(workCtx_.x[7]<<16)); - tmp[3] = LITTLE32(workCtx_.x[6] ^ + tmp[3] = LITTLE32(workCtx_.x[6] ^ (workCtx_.x[3]>>16) ^ U32V(workCtx_.x[1]<<16)); /* Encrypt/decrypt the data */ diff --git a/cdk/extra/yassl/taocrypt/src/random.cpp b/cdk/extra/yassl/taocrypt/src/random.cpp index 26dae7d19..45df3bdba 100644 --- a/cdk/extra/yassl/taocrypt/src/random.cpp +++ b/cdk/extra/yassl/taocrypt/src/random.cpp @@ -107,7 +107,7 @@ OS_Seed::OS_Seed() } -OS_Seed::~OS_Seed() +OS_Seed::~OS_Seed() { close(fd_); } diff --git a/cdk/extra/yassl/taocrypt/src/ripemd.cpp b/cdk/extra/yassl/taocrypt/src/ripemd.cpp index 5d03dc61c..1c5c6f5d7 100644 --- a/cdk/extra/yassl/taocrypt/src/ripemd.cpp +++ b/cdk/extra/yassl/taocrypt/src/ripemd.cpp @@ -49,8 +49,8 @@ void RIPEMD160::Init() RIPEMD160::RIPEMD160(const RIPEMD160& that) - : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) -{ + : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -93,7 +93,7 @@ void RIPEMD160::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -131,7 +131,7 @@ void RIPEMD160::Update(const byte* data, word32 len) // for all -#define F(x, y, z) (x ^ y ^ z) +#define F(x, y, z) (x ^ y ^ z) #define G(x, y, z) (z ^ (x & (y^z))) #define H(x, y, z) (z ^ (x | ~y)) #define I(x, y, z) (y ^ (z & (x^y))) @@ -266,7 +266,7 @@ void RIPEMD160::Transform() Subround(J, b2, c2, d2, e2, a2, buffer_[ 3], 12, k5); Subround(J, a2, b2, c2, d2, e2, buffer_[12], 6, k5); - Subround(I, e2, a2, b2, c2, d2, buffer_[ 6], 9, k6); + Subround(I, e2, a2, b2, c2, d2, buffer_[ 6], 9, k6); Subround(I, d2, e2, a2, b2, c2, buffer_[11], 13, k6); Subround(I, c2, d2, e2, a2, b2, buffer_[ 3], 15, k6); Subround(I, b2, c2, d2, e2, a2, buffer_[ 7], 7, k6); @@ -362,7 +362,7 @@ void RIPEMD160::Transform() AS2( and esi, x ) \ AS2( xor esi, z ) - + // H(z ^ (x | ~y)) // place in esi #define ASMH(x, y, z) \ @@ -391,7 +391,7 @@ void RIPEMD160::Transform() // for 160 and 320 -// #define ASMSubround(f, a, b, c, d, e, i, s, k) +// #define ASMSubround(f, a, b, c, d, e, i, s, k) // a += f(b, c, d) + data[i] + k; // a = rotlFixed((word32)a, s) + e; // c = rotlFixed((word32)c, 10U) @@ -506,7 +506,7 @@ void RIPEMD160::Transform() #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -525,8 +525,8 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "d" (times) \ : "%esi", "%eax", "memory", "cc" \ @@ -555,7 +555,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 8 ) - + #endif PROLOG() @@ -568,11 +568,11 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS2( sub esp, 24 ) // make room for tmp a1 - e1 AS2( movd mm1, esi ) // store digest_ - + #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif AS2( movd mm2, edx ) // store times_ @@ -583,7 +583,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS2( mov edx, [esi + 12] ) // d1 AS2( mov ebp, [esi + 16] ) // e1 - // setup + // setup AS2( mov esi, ecx ) ASMSubroundF( eax, ebx, ecx, edx, ebp, 0, 11) @@ -713,7 +713,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) // setup AS2( mov esi, ebx ) - ASMSubroundI( ebp, eax, ebx, ecx, edx, 6, 9, k6) + ASMSubroundI( ebp, eax, ebx, ecx, edx, 6, 9, k6) ASMSubroundI( edx, ebp, eax, ebx, ecx, 11, 13, k6) ASMSubroundI( ecx, edx, ebp, eax, ebx, 3, 15, k6) ASMSubroundI( ebx, ecx, edx, ebp, eax, 7, 7, k6) @@ -831,7 +831,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS1( jnz 0b ) // loopStart #endif - // inline adjust + // inline adjust AS2( add esp, 24 ) // fix room on stack EPILOG() diff --git a/cdk/extra/yassl/taocrypt/src/rsa.cpp b/cdk/extra/yassl/taocrypt/src/rsa.cpp index 73f678e26..be8ca6fec 100644 --- a/cdk/extra/yassl/taocrypt/src/rsa.cpp +++ b/cdk/extra/yassl/taocrypt/src/rsa.cpp @@ -61,7 +61,7 @@ Integer RSA_PrivateKey::CalculateInverse(RandomNumberGenerator& rng, Integer y = ModularRoot(re, dq_, dp_, q_, p_, u_); y = modn.Divide(y, r); // unblind - + return y; } @@ -97,7 +97,7 @@ void RSA_BlockType2::Pad(const byte *input, word32 inputLen, byte *pkcsBlock, rng.GenerateBlock(&pkcsBlock[1], padLen); for (word32 i = 1; i < padLen; i++) if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01; - + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); } @@ -200,12 +200,12 @@ word32 RSA_BlockType1::UnPad(const byte* pkcsBlock, word32 pkcsBlockLen, word32 SSL_Decrypt(const RSA_PublicKey& key, const byte* sig, byte* plain) { PK_Lengths lengths(key.GetModulus()); - + ByteBlock paddedBlock(BitsToBytes(lengths.PaddedBlockBitLength())); Integer x = key.ApplyFunction(Integer(sig, lengths.FixedCiphertextLength())); if (x.ByteCount() > paddedBlock.size()) - x = Integer::Zero(); + x = Integer::Zero(); x.Encode(paddedBlock.get_buffer(), paddedBlock.size()); return RSA_BlockType1().UnPad(paddedBlock.get_buffer(), lengths.PaddedBlockBitLength(), plain); diff --git a/cdk/extra/yassl/taocrypt/src/sha.cpp b/cdk/extra/yassl/taocrypt/src/sha.cpp index 4206f7f64..0b2f39ee6 100644 --- a/cdk/extra/yassl/taocrypt/src/sha.cpp +++ b/cdk/extra/yassl/taocrypt/src/sha.cpp @@ -142,8 +142,8 @@ void SHA384::Init() SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -154,8 +154,8 @@ SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), SHA256::SHA256(const SHA256& that) : HASHwithTransform(DIGEST_SIZE / - sizeof(word32), BLOCK_SIZE) -{ + sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -166,8 +166,8 @@ SHA256::SHA256(const SHA256& that) : HASHwithTransform(DIGEST_SIZE / SHA224::SHA224(const SHA224& that) : HASHwithTransform(SHA256::DIGEST_SIZE / - sizeof(word32), BLOCK_SIZE) -{ + sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -177,11 +177,11 @@ SHA224::SHA224(const SHA224& that) : HASHwithTransform(SHA256::DIGEST_SIZE / } -#ifdef WORD64_AVAILABLE +#ifdef WORD64_AVAILABLE SHA512::SHA512(const SHA512& that) : HASH64withTransform(DIGEST_SIZE / - sizeof(word64), BLOCK_SIZE) -{ + sizeof(word64), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -192,8 +192,8 @@ SHA512::SHA512(const SHA512& that) : HASH64withTransform(DIGEST_SIZE / SHA384::SHA384(const SHA384& that) : HASH64withTransform(SHA512::DIGEST_SIZE / - sizeof(word64), BLOCK_SIZE) -{ + sizeof(word64), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -326,7 +326,7 @@ void SHA::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -368,14 +368,14 @@ void SHA::Transform() { word32 W[BLOCK_SIZE / sizeof(word32)]; - // Copy context->state[] to working vars + // Copy context->state[] to working vars word32 a = digest_[0]; word32 b = digest_[1]; word32 c = digest_[2]; word32 d = digest_[3]; word32 e = digest_[4]; - // 4 rounds of 20 operations each. Loop unrolled. + // 4 rounds of 20 operations each. Loop unrolled. R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); @@ -429,7 +429,7 @@ void SHA::Transform() #define h(i) T[(7-i)&7] #define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\ - d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) // for SHA256 #define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22)) @@ -439,22 +439,22 @@ void SHA::Transform() static const word32 K256[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; @@ -514,46 +514,46 @@ void SHA224::Transform() #ifdef WORD64_AVAILABLE static const word64 K512[80] = { - W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), - W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), - W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), - W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), - W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), - W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), - W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), - W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), - W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), - W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), - W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), - W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), - W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), - W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), - W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), - W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), - W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), - W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), - W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), - W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), - W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), - W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), - W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), - W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), - W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), - W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), - W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), - W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), - W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), - W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), - W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), - W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), - W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), - W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), - W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), - W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), - W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), - W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), - W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), - W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) }; @@ -582,7 +582,7 @@ static void Transform512(word64* digest_, word64* buffer_) R(12); R(13); R(14); R(15); } - // Add the working vars back into digest + // Add the working vars back into digest digest_[0] += a(0); digest_[1] += b(0); @@ -779,8 +779,8 @@ void SHA::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "a" (times) \ : "%esi", "%edx", "memory", "cc" \ @@ -808,7 +808,7 @@ void SHA::AsmTransform(const byte* data, word32 times) AS2( mov esp, ebp ) \ AS1( pop ebp ) \ AS1( emms ) \ - AS1( ret 8 ) + AS1( ret 8 ) #endif PROLOG() @@ -829,7 +829,7 @@ void SHA::AsmTransform(const byte* data, word32 times) #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif // byte reverse 16 words of input, 4 at a time, put on stack for W[] @@ -1007,12 +1007,12 @@ void SHA::AsmTransform(const byte* data, word32 times) // setup next round AS2( movd ebp, mm2 ) // times - + AS2( mov edi, DWORD PTR [esp + 64] ) // data - + AS2( add edi, 64 ) // next round of data AS2( mov [esp + 64], edi ) // restore - + AS1( dec ebp ) AS2( movd mm2, ebp ) #ifdef _MSC_VER @@ -1021,7 +1021,7 @@ void SHA::AsmTransform(const byte* data, word32 times) AS1( jnz 0b ) // loopStart #endif - // inline adjust + // inline adjust AS2( add esp, 68 ) // fix room on stack EPILOG() diff --git a/cdk/extra/yassl/taocrypt/test/test.cpp b/cdk/extra/yassl/taocrypt/test/test.cpp index a7d5cb3e8..fc1f0e876 100644 --- a/cdk/extra/yassl/taocrypt/test/test.cpp +++ b/cdk/extra/yassl/taocrypt/test/test.cpp @@ -1277,6 +1277,9 @@ int dsa_test() if (!verifier.Verify(digest, decoded)) return -90; + if (!verifier.Verify(digest, signature)) + return -91; + return 0; } diff --git a/cdk/extra/yassl/testsuite/test.hpp b/cdk/extra/yassl/testsuite/test.hpp index 3e15ce814..92d41706c 100644 --- a/cdk/extra/yassl/testsuite/test.hpp +++ b/cdk/extra/yassl/testsuite/test.hpp @@ -22,7 +22,6 @@ #define yaSSL_TEST_HPP #include "runtime.hpp" -#include "openssl/ssl.h" /* openssl compatibility test */ #include "error.hpp" #include #include @@ -56,6 +55,7 @@ #endif #define SOCKET_T int #endif /* _WIN32 */ +#include "openssl/ssl.h" /* openssl compatibility test */ #ifdef _MSC_VER @@ -469,9 +469,24 @@ inline void showPeer(SSL* ssl) if (peer) { char* issuer = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0); char* subject = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0); + X509_NAME_ENTRY* se = NULL; + ASN1_STRING* sd = NULL; + char* subCN = NULL; + X509_NAME* sub = X509_get_subject_name(peer); + int lastpos = -1; + if (sub) + lastpos = X509_NAME_get_index_by_NID(sub, NID_commonName, lastpos); + if (lastpos >= 0) { + se = X509_NAME_get_entry(sub, lastpos); + if (se) + sd = X509_NAME_ENTRY_get_data(se); + if (sd) + subCN = (char*)ASN1_STRING_data(sd); + } + + printf("peer's cert info:\n issuer : %s\n subject: %s\n" + " subject cn: %s\n", issuer, subject, subCN); - printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer, - subject); free(subject); free(issuer); } From ecae40c61a5a7cc5e28a8732b5004b971d168330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Thu, 9 Feb 2017 12:01:28 +0000 Subject: [PATCH 50/79] Fix when using Empty BaseResult which has m_sess = NULL (Bug #25515964 ) --- devapi/result.cc | 12 ++++++++---- devapi/tests/crud-t.cc | 7 +++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/devapi/result.cc b/devapi/result.cc index 8a4f5e881..27cd2c2e3 100644 --- a/devapi/result.cc +++ b/devapi/result.cc @@ -1345,10 +1345,14 @@ void mysqlx::internal::BaseResult::init(mysqlx::internal::BaseResult &&init_) m_sess = init_.m_sess; - // first deregister init result, since it registered itself on ctor - // otherwise it would trigger cache, and we are moving Result object - m_sess->deregister_result(&init_); - m_sess->register_result(this); + //On empty results, m_sess is NULL, so don't do anything with it! + if (m_sess) + { + // first deregister init result, since it registered itself on ctor + // otherwise it would trigger cache, and we are moving Result object + m_sess->deregister_result(&init_); + m_sess->register_result(this); + } } diff --git a/devapi/tests/crud-t.cc b/devapi/tests/crud-t.cc index a78e5dcde..033d45eaa 100644 --- a/devapi/tests/crud-t.cc +++ b/devapi/tests/crud-t.cc @@ -848,6 +848,13 @@ TEST_F(Crud, table) std::vector cols = {"_id"}; + //Inserting empty list + + //Bug #25515964 + //Adding empty list shouldn't do anything + std::list rList; + tbl.insert(cols, "age", string("name")).rows(rList).rows(rList).execute(); + //Using containers (vectors, const char* and string) auto insert = tbl.insert(cols, "age", string("name")); From d1442663b894d7f7066fcc945fa475d914ffef46 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 14 Feb 2017 20:42:57 +0100 Subject: [PATCH 51/79] Bug #25544129: CREATE VIEW DOES NOT SET WITHCHECKOPTION TO CASCADED --- devapi/table_crud.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index 10e878a36..efe3ffcf0 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -611,8 +611,10 @@ class Op_ViewCreateAlter { case CheckOption::CASCADED: options->check(cdk::api::View_check::CASCADED); + break; case CheckOption::LOCAL: options->check(cdk::api::View_check::LOCAL); + break; } switch(m_security) @@ -622,6 +624,7 @@ class Op_ViewCreateAlter break; case SQLSecurity::INVOKER: options->security(cdk::api::View_security::INVOKER); + break; } } From 2b4975a7847c471369c7f9e7a87dff0898047885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 14 Feb 2017 15:45:10 +0000 Subject: [PATCH 52/79] Bug#25530569 Fix "Invalid value type" when passing SSL_CA as SessionSettings --- devapi/session.cc | 13 +++++++-- devapi/tests/session-t.cc | 58 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/devapi/session.cc b/devapi/session.cc index 0979554fb..1f443d2fb 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -272,14 +272,21 @@ internal::XSession_base::XSession_base(SessionSettings settings) settings[SessionSettings::DB].get() ); - if (settings.has_option(SessionSettings::SSL_ENABLE)) + if (settings.has_option(SessionSettings::SSL_ENABLE) || + settings.has_option(SessionSettings::SSL_CA)) { #ifdef WITH_SSL - cdk::connection::TLS::Options opt_ssl(settings[SessionSettings::SSL_ENABLE]); + + //ssl_enable by default, unless SSL_ENABLE = false + bool ssl_enable = true; + if (settings.has_option(SessionSettings::SSL_ENABLE)) + ssl_enable = settings[SessionSettings::SSL_ENABLE]; + + cdk::connection::TLS::Options opt_ssl(ssl_enable); if (settings.has_option(SessionSettings::SSL_CA)) - opt_ssl.set_ca(settings[SessionSettings::SSL_ENABLE].get()); + opt_ssl.set_ca(settings[SessionSettings::SSL_CA].get()); opt.set_tls(opt_ssl); #else diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index e5df894c1..d7224cdb3 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -432,7 +432,7 @@ TEST_F(Sess, ssl_session) } - //using wrong ssl-ca and ssl-ca-path as SessionSettings + //using wrong ssl-ca as SessionSettings { EXPECT_THROW( mysqlx::XSession sess(SessionSettings::PORT, get_port(), @@ -497,4 +497,60 @@ TEST_F(Sess, ssl_session) EXPECT_FALSE(cipher.empty()); } + //using ssl-enable and ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, ssl_ca); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + + } + + //using ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_CA, ssl_ca); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + + } + + //using ssl-ca but ssl-enable = false on SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, false, + SessionSettings::SSL_CA, ssl_ca); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + + } + } From 03beb081e52849469973f44daeb6ac69a5cee0ed Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 14 Feb 2017 19:44:29 +0100 Subject: [PATCH 53/79] XAPI: Remove ssl-ca-path and slsl-key options. --- include/mysql_xapi.h | 1 - xapi/mysqlx.cc | 8 -------- xapi/mysqlx_cc_internal.h | 8 -------- xapi/tests/xapi-t.cc | 4 ---- 4 files changed, 21 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 9747459af..f5f5dcffe 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -336,7 +336,6 @@ typedef enum mysqlx_opt_type_enum MYSQLX_OPT_DB = 5, MYSQLX_OPT_SSL_ENABLE = 6, MYSQLX_OPT_SSL_CA = 7, - MYSQLX_OPT_SSL_CA_PATH = 8 } mysqlx_opt_type_t; diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index fb2789614..2ab253189 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -1725,10 +1725,6 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, char_data = va_arg(args, char*); opt->set_ssl_ca(char_data); break; - case MYSQLX_OPT_SSL_CA_PATH: - char_data = va_arg(args, char*); - opt->set_ssl_ca_path(char_data); - break; #else case MYSQLX_OPT_SSL_ENABLE: case MYSQLX_OPT_SSL_CA: @@ -1799,10 +1795,6 @@ mysqlx_session_option_get(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_tls().get_ca().data()); break; - case MYSQLX_OPT_SSL_CA_PATH: - CHECK_OUTPUT_BUF(char_data, char*) - strcpy(char_data, opt->get_tls().get_ca_path().data()); - break; #else case MYSQLX_OPT_SSL_ENABLE: case MYSQLX_OPT_SSL_CA: diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 12c1741b4..c823fbb07 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -502,14 +502,6 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, { set_ssl_ca(val); } - else if (key.compare("ssl-ca-path") == 0) - { - set_ssl_ca_path(val); - } - else if (key.compare("ssl-key") == 0) - { - set_ssl_key(val); - } #else set_diagnostic( "Can not create TLS session - this connector is built" diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 65f50d3bc..aef52cea7 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -525,10 +525,6 @@ TEST_F(xapi, conn_options_test) EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA, buf_check)); EXPECT_STREQ(ca_buf, buf_check); } - - EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA_PATH, capath_buf)); - EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA_PATH, buf_check)); - EXPECT_STREQ(capath_buf, buf_check); } goto DO_CONNECT; From 48aa13171c528bfa68a6bc636cc0a016a5da80a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 14 Feb 2017 23:37:31 +0000 Subject: [PATCH 54/79] Bug#25526187: SSL CONNECTION FAILS WHEN SSL-CA IS SET BUT SSL-ENABLE IS NOT SET --- devapi/session.cc | 1 + devapi/tests/session-t.cc | 101 ++++++++++++++++++++++---------------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/devapi/session.cc b/devapi/session.cc index 1f443d2fb..aa2681944 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -195,6 +195,7 @@ struct URI_parser if (key == "ssl-ca") { #ifdef WITH_SSL + m_tls_opt.set_use_tls(true); m_tls_opt.set_ca(val); #else throw_error( diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index d7224cdb3..647b52e62 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -358,20 +358,29 @@ TEST_F(Sess, ssl_session) SKIP_IF_NO_XPLUGIN; + //Test if ssl is enabled using cipher + auto check_ssl_impl = [](mysqlx::XSession &sess, bool enable, int line) { - mysqlx::XSession sess(SessionSettings::PORT, get_port(), - SessionSettings::USER,get_user(), - SessionSettings::PWD, get_password() ? get_password() : NULL , - SessionSettings::SSL_ENABLE, true); - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; + cout << "Line "<< line << ": " << row[0] << ":" << row[1] << endl; string cipher = row[1]; - EXPECT_FALSE(cipher.empty()); + EXPECT_EQ(enable, !cipher.empty()); + }; + +#define check_ssl(x,y) check_ssl_impl(x, y, __LINE__) + + + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true); + + check_ssl(sess, true); } { @@ -380,14 +389,7 @@ TEST_F(Sess, ssl_session) SessionSettings::PWD, get_password() ? get_password() : nullptr , SessionSettings::SSL_ENABLE, false); - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); - - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; - - string cipher = row[1]; - - EXPECT_TRUE(cipher.empty()); + check_ssl(sess, false); } //Using URI @@ -404,31 +406,17 @@ TEST_F(Sess, ssl_session) //URI without ssl_enable { mysqlx::XSession sess(uri.str()); - - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); - - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; - - string cipher = row[1]; - - EXPECT_TRUE(cipher.empty()); + check_ssl(sess, false); } - //Enable SSL - uri << "/?ssl-enable"; { - mysqlx::XSession sess(uri.str()); - - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); - - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; + std::stringstream uri_ssl; + //Enable SSL + uri_ssl << uri.str() << "/?ssl-enable"; - string cipher = row[1]; - - EXPECT_FALSE(cipher.empty()); + mysqlx::XSession sess(uri_ssl.str()); + check_ssl(sess, true); } @@ -437,7 +425,7 @@ TEST_F(Sess, ssl_session) EXPECT_THROW( mysqlx::XSession sess(SessionSettings::PORT, get_port(), SessionSettings::USER,get_user(), - SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::PWD, get_password() ? get_password() : nullptr , SessionSettings::SSL_ENABLE, true, SessionSettings::SSL_CA, "unknown") , mysqlx::Error); @@ -448,7 +436,7 @@ TEST_F(Sess, ssl_session) //using wrong ssl-ca and ssl-ca-path on URI { std::stringstream bad_uri; - bad_uri << uri.str() << "&ssl-ca=" << "unknown.file" << "&ssl-ca-path=" << "unknown.path"; + bad_uri << uri.str() << "/?ssl-ca=" << "unknown.file"; EXPECT_THROW(mysqlx::XSession sess(bad_uri.str()), mysqlx::Error); } @@ -482,19 +470,46 @@ TEST_F(Sess, ssl_session) ssl_ca = datadir + ssl_ca; } - uri << "&ssl-ca=" << ssl_ca; + uri << "/?ssl-ca=" << ssl_ca; { mysqlx::XSession sess(uri.str()); + check_ssl(sess, true); + } - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + //using ssl-enable and ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, ssl_ca); - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; + check_ssl(sess, true); - string cipher = row[1]; + } + + //using ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, true); + + } + + //using ssl-ca but ssl-enable = false on SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false, + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, false); - EXPECT_FALSE(cipher.empty()); } //using ssl-enable and ssl-ca as SessionSettings From 27448137dbb6d07425aa8fb6e5bd15bc673b02fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Wed, 15 Feb 2017 16:43:13 +0000 Subject: [PATCH 55/79] MYCPP-308: FIX CREATE VIEW USING SELECT WITH BIND GIVES ERROR. Allow TableSel::bind() to update value. --- cdk/mysqlx/delayed_op.h | 11 +++++++++-- devapi/impl.h | 9 +++++++-- devapi/tests/session-t.cc | 34 ++++++++++++++++++++++++++++++++++ include/devapi/statement.h | 4 ++-- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/cdk/mysqlx/delayed_op.h b/cdk/mysqlx/delayed_op.h index 1cbe4f856..898db31e4 100644 --- a/cdk/mysqlx/delayed_op.h +++ b/cdk/mysqlx/delayed_op.h @@ -749,6 +749,12 @@ class SndViewCrud return m_has_opts ? this : NULL; } + const protocol::mysqlx::api::Args_map* + get_args() + { + return m_find->m_param_conv.get(); + } + Proto_op* start() { @@ -758,11 +764,12 @@ class SndViewCrud case REPLACE: return &m_protocol.snd_CreateView(DM, *this, *m_find, get_cols(), REPLACE == m_type, - get_opts()); + get_opts(), get_args()); case UPDATE: return &m_protocol.snd_ModifyView(DM, *this, *m_find, - get_cols(), get_opts()); + get_cols(), get_opts(), + m_find->m_param_conv.get()); default: assert(false); return NULL; // quiet compile warnings diff --git a/devapi/impl.h b/devapi/impl.h index a0ae53fcc..cd1e69600 100644 --- a/devapi/impl.h +++ b/devapi/impl.h @@ -623,9 +623,14 @@ class Op_base // Parameters - void add_param(const mysqlx::string &name, Value val) + void add_param(const mysqlx::string &name, Value &&val) { - m_map.emplace(name, std::move(val)); + auto el = m_map.emplace(name, std::move(val)); + //substitute if exists + if (!el.second) + { + el.first->second = std::move(val); + } } void clear_params() diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 7b97e9764..1fb203bd2 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -589,6 +589,40 @@ TEST_F(Sess, view) } + std::cout << "Create view with select bind" << std::endl; + + { + TableSelect sel = tbl.select(); + sel.where("age = :age").bind("age", 40); + + sch.dropView(view_name).execute(); + + sch.createView(view_name).definedAs(sel).execute(); + + Table view = sch.getTable(view_name); + + RowResult res = view.select().execute(); + + EXPECT_EQ(1, res.count()); + + Row row = res.fetchOne(); + + EXPECT_EQ(40, row.get(1).get()); + + sel.bind("age", 30); + + sch.alterView(view_name).definedAs(sel).execute(); + + res = view.select().execute(); + + EXPECT_EQ(1, res.count()); + + row = res.fetchOne(); + + EXPECT_EQ(30, row.get(1).get()); + + } + std::cout << "Drop view" << std::endl; sch.dropView(view_name).execute(); diff --git a/include/devapi/statement.h b/include/devapi/statement.h index 9cb28cfd3..b21204235 100644 --- a/include/devapi/statement.h +++ b/include/devapi/statement.h @@ -136,7 +136,7 @@ namespace internal { struct Statement_impl : public Executable_impl { - virtual void add_param(const string&, Value) = 0; + virtual void add_param(const string&, Value&&) = 0; }; } // internal @@ -190,7 +190,7 @@ class Statement Statement& bind(const string ¶meter, Value val) { try { - get_impl()->add_param(parameter, val); + get_impl()->add_param(parameter, std::move(val)); return *this; } CATCH_AND_WRAP From eaeef691651178c0216e963f3c6a2e19ffd2a11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Thu, 16 Feb 2017 11:59:05 +0000 Subject: [PATCH 56/79] MYCPP-312: FIX FUNCTION .DEFINER() NOT SETTING VALUE IN VIEWCREATE() --- devapi/table_crud.cc | 2 ++ devapi/tests/session-t.cc | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index efe3ffcf0..788f21d13 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -594,6 +594,8 @@ class Op_ViewCreateAlter if (options) { + options->definer(m_user); + switch (m_algorythm) { case Algorithm::MERGE: diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 1fb203bd2..6fdab4e08 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -467,7 +467,7 @@ TEST_F(Sess, view) sch.createView(view_name, false) .security(mysqlx::SQLSecurity::DEFINER) - .definer("root") + .definer("root@localhost") .definedAs(tbl.select("name as view_name", "2016-age as view_birth")) .withCheckOption(mysqlx::CheckOption::LOCAL) .execute(); @@ -515,7 +515,7 @@ TEST_F(Sess, view) sch.alterView(view_name) .columns(columns_list, "one") .security(mysqlx::SQLSecurity::DEFINER) - .definer("root") + .definer("root@localhost") .definedAs(tbl_select) .withCheckOption(mysqlx::CheckOption::LOCAL) .execute() @@ -524,7 +524,7 @@ TEST_F(Sess, view) auto view_exec = sch.alterView(view_name) .columns(columns_list, "one", string("two")) .security(mysqlx::SQLSecurity::DEFINER) - .definer("root") + .definer("root@localhost") .definedAs(tbl_select) .withCheckOption(mysqlx::CheckOption::LOCAL); @@ -554,7 +554,7 @@ TEST_F(Sess, view) EXPECT_THROW( sch.alterView(view_name2) .columns("view_name", "fake") .security(mysqlx::SQLSecurity::DEFINER) - .definer("root") + .definer("root@localhost") .definedAs(tbl_select) .withCheckOption(mysqlx::CheckOption::LOCAL) .execute() @@ -621,6 +621,35 @@ TEST_F(Sess, view) EXPECT_EQ(30, row.get(1).get()); + } + + { + sch.dropView(view_name).execute(); + + sch.createView(view_name) + .algorithm(Algorithm::MERGE) + .security(SQLSecurity::INVOKER) + .definer("unknownUser") + .definedAs(tbl.select()) + .withCheckOption(mysqlx::CheckOption::CASCADED) + .execute(); + + std::stringstream qry; + + qry << "show create view " << schema_name << "." << view_name; + + SqlResult result = sql(qry.str()); + + Row r = result.fetchOne(); + std::string data = (string)r[1]; + + cout << r[0] << ": " << data << endl; + + EXPECT_TRUE(data.find("MERGE") != std::string::npos); + EXPECT_TRUE(data.find("INVOKER") != std::string::npos); + EXPECT_TRUE(data.find("unknownUser") != std::string::npos); + EXPECT_TRUE(data.find("CASCADED") != std::string::npos); + } std::cout << "Drop view" << std::endl; From 716e13b5349c129504277fe315f4d3e0597706a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Fri, 17 Feb 2017 10:35:41 +0000 Subject: [PATCH 57/79] MYCPP-311: Fix Seg Fault when passing NULL to mysqlx_set_view_definer --- xapi/tests/xapi-t.cc | 1 + xapi/view.cc | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 2ddf2ba36..b346989c2 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -66,6 +66,7 @@ TEST_F(xapi, view_ddl_test) EXPECT_EQ(RESULT_OK, mysqlx_set_view_algorithm(vstmt, VIEW_ALGORITHM_MERGE)); EXPECT_EQ(RESULT_OK, mysqlx_set_view_security(vstmt, VIEW_SECURITY_INVOKER)); EXPECT_EQ(RESULT_OK, mysqlx_set_view_check_option(vstmt, VIEW_CHECK_OPTION_CASCADED)); + EXPECT_EQ(RESULT_OK, mysqlx_set_view_definer(vstmt, NULL)); EXPECT_EQ(RESULT_OK, mysqlx_set_view_definer(vstmt, "root")); // Change parent SELECT STMT, it is not supposed to affect the VIEW STMT in any way diff --git a/xapi/view.cc b/xapi/view.cc index 85e3dbb63..135b0085e 100644 --- a/xapi/view.cc +++ b/xapi/view.cc @@ -99,8 +99,15 @@ void View_spec::set_check(int val) void View_spec::set_definer(const char* val) { - m_opts.m_definer_set = true; - m_opts.m_definer = val; + if (val) + { + m_opts.m_definer_set = true; + m_opts.m_definer = val; + } + else + { // If definer = NULL, we will not report it + m_opts.m_definer_set = false; + } } void View_spec::set_columns(va_list args) @@ -138,4 +145,4 @@ void View_spec::View_opts::process(Processor &prc) const if (m_definer_set) prc.definer(m_definer); -} \ No newline at end of file +} From fdf9ab0ba955349d110437431745b413aa54a889 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 17 Feb 2017 18:01:41 +0100 Subject: [PATCH 58/79] Bug #25575727: ALGORITHM, SQL SECURITY AND CHECK OPTION ARE NOT GETTING RESET AFTER CREATE VIEW Make sure that view creation options are set in the protocol message only when user specifies them explicitly. --- devapi/table_crud.cc | 99 +++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index 788f21d13..8a4cca78e 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include "impl.h" @@ -487,12 +488,16 @@ class Op_ViewCreateAlter private: op_type m_op_type; - CheckOption m_check_option; std::unique_ptr m_table_select; - SQLSecurity m_security; - Algorithm m_algorythm; - std::vector m_columns; - mysqlx::string m_user; + std::vector m_columns; + + CheckOption m_check_option; + SQLSecurity m_security; + Algorithm m_algorithm; + mysqlx::string m_definer; + + enum view_option { CHECK, SECURITY, ALGORITHM, DEFINER, LAST}; + std::bitset m_opts_mask; Executable_impl* clone() const override { @@ -503,11 +508,11 @@ class Op_ViewCreateAlter : Op_base(other) , Table_ref(other) , m_op_type (other.m_op_type ) + , m_columns (other.m_columns ) , m_check_option (other.m_check_option) , m_security (other.m_security ) - , m_algorythm (other.m_algorythm ) - , m_columns (other.m_columns ) - , m_user (other.m_user ) + , m_algorithm (other.m_algorithm ) + , m_definer (other.m_definer ) { if (other.m_table_select.get() != NULL) { @@ -527,6 +532,7 @@ class Op_ViewCreateAlter void with_check_option(CheckOption option) override { m_check_option = option; + m_opts_mask.set(CHECK); } void defined_as(TableSelect &&select) override @@ -537,17 +543,20 @@ class Op_ViewCreateAlter void definer(const mysqlx::string &user) override { - m_user = user; + m_definer = user; + m_opts_mask.set(DEFINER); } void security(SQLSecurity security) override { m_security = security; + m_opts_mask.set(SECURITY); } void algorithm(Algorithm algorythm) override { - m_algorythm = algorythm; + m_algorithm = algorythm; + m_opts_mask.set(ALGORITHM); } void add_columns(const mysqlx::string &name) override @@ -594,40 +603,44 @@ class Op_ViewCreateAlter if (options) { - options->definer(m_user); + if (m_opts_mask.test(DEFINER)) + options->definer(m_definer); - switch (m_algorythm) - { - case Algorithm::MERGE: - options->algorithm(cdk::api::View_algorithm::MERGE); - break; - case Algorithm::TEMPTABLE: - options->algorithm(cdk::api::View_algorithm::TEMPTABLE); - break; - case Algorithm::UNDEFINED: - options->algorithm(cdk::api::View_algorithm::UNDEFINED); - break; - } - - switch(m_check_option) - { - case CheckOption::CASCADED: - options->check(cdk::api::View_check::CASCADED); - break; - case CheckOption::LOCAL: - options->check(cdk::api::View_check::LOCAL); - break; - } - - switch(m_security) - { - case SQLSecurity::DEFINER: - options->security(cdk::api::View_security::DEFINER); - break; - case SQLSecurity::INVOKER: - options->security(cdk::api::View_security::INVOKER); - break; - } + if (m_opts_mask.test(ALGORITHM)) + switch (m_algorithm) + { + case Algorithm::MERGE: + options->algorithm(cdk::api::View_algorithm::MERGE); + break; + case Algorithm::TEMPTABLE: + options->algorithm(cdk::api::View_algorithm::TEMPTABLE); + break; + case Algorithm::UNDEFINED: + options->algorithm(cdk::api::View_algorithm::UNDEFINED); + break; + }; + + if (m_opts_mask.test(CHECK)) + switch(m_check_option) + { + case CheckOption::CASCADED: + options->check(cdk::api::View_check::CASCADED); + break; + case CheckOption::LOCAL: + options->check(cdk::api::View_check::LOCAL); + break; + }; + + if (m_opts_mask.test(SECURITY)) + switch(m_security) + { + case SQLSecurity::DEFINER: + options->security(cdk::api::View_security::DEFINER); + break; + case SQLSecurity::INVOKER: + options->security(cdk::api::View_security::INVOKER); + break; + }; } } From b5793e508cc827e35a8dc82b4ad7ddfee093335d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Fri, 17 Feb 2017 18:09:14 +0000 Subject: [PATCH 59/79] Fix for Bug #25547438: PASSING TABLE.SELECT() TO CREATE VIEW WITH ANY OPTION CAUSES COMPILATION ERROR Change Executable to Executable where Op is the top level operation --- include/devapi/collection_crud.h | 54 ++++++++++++------- include/devapi/crud.h | 34 ++++++------ include/devapi/result.h | 14 +++-- include/devapi/statement.h | 30 ++++++----- include/devapi/table_crud.h | 65 ++++++++++++++--------- include/mysql_devapi.h | 90 +++++++++++++++++++++----------- 6 files changed, 176 insertions(+), 111 deletions(-) diff --git a/include/devapi/collection_crud.h b/include/devapi/collection_crud.h index 7f216d215..384470c44 100644 --- a/include/devapi/collection_crud.h +++ b/include/devapi/collection_crud.h @@ -352,7 +352,7 @@ namespace internal { DLL_WARNINGS_PUSH class PUBLIC_API CollectionAdd - : public virtual Executable + : public virtual Executable , public internal::CollectionAddInterface { @@ -435,16 +435,16 @@ namespace internal { interface. */ - template + template class CollectionSort - : public Limit + : public Limit { protected: typedef internal::Sort_impl Impl; - using Limit::check_if_valid; - using Limit::m_impl; + using Limit::check_if_valid; + using Limit::m_impl; Impl* get_impl() { @@ -454,13 +454,13 @@ namespace internal { public: - Limit& sort(const string& ord_spec) + Limit& sort(const string& ord_spec) { get_impl()->add_sort(ord_spec); return *this; } - Limit& sort(const char* ord_spec) + Limit& sort(const char* ord_spec) { get_impl()->add_sort(ord_spec); return *this; @@ -474,7 +474,7 @@ namespace internal { */ template - Limit& sort(Ord ord) + Limit& sort(Ord ord) { for (auto el : ord) { @@ -491,7 +491,7 @@ namespace internal { */ template - Limit& sort(Ord ord, const Type...rest) + Limit& sort(Ord ord, const Type...rest) { get_impl()->add_sort(ord); return sort(rest...); @@ -509,12 +509,18 @@ namespace internal { Class defining .having() clause. */ + template class CollectionHaving - : public internal::CollectionSort + : public internal::CollectionSort { typedef internal::Having_impl Impl; - typedef internal::CollectionSort CollectionSort; + typedef internal::CollectionSort CollectionSort; + + protected: + + using internal::CollectionSort::check_if_valid; + using internal::CollectionSort::m_impl; Impl* get_impl() { @@ -546,12 +552,18 @@ namespace internal { Class defining .groupBy() clause. */ + template class CollectionGroupBy - : public internal::CollectionHaving + : public internal::CollectionHaving { typedef internal::Group_by_impl Impl; - typedef internal::CollectionHaving CollectionHaving; + typedef internal::CollectionHaving CollectionHaving; + + protected: + + using internal::CollectionHaving::check_if_valid; + using internal::CollectionHaving::m_impl; Impl* get_impl() { @@ -622,7 +634,7 @@ namespace internal { */ class PUBLIC_API CollectionRemove - : public internal::CollectionSort + : public internal::CollectionSort { public: @@ -721,7 +733,7 @@ namespace internal { DLL_WARNINGS_PUSH class PUBLIC_API CollectionFind - : public internal::CollectionGroupBy + : public internal::CollectionGroupBy { DLL_WARNINGS_POP @@ -729,7 +741,10 @@ DLL_WARNINGS_POP protected: typedef internal::Proj_impl Impl; - typedef internal::CollectionGroupBy CollectionGroupBy; + typedef internal::CollectionGroupBy CollectionGroupBy; + + using internal::CollectionGroupBy::get_impl; + using internal::CollectionGroupBy::m_impl; Impl* get_impl() { @@ -758,7 +773,7 @@ DIAGNOSTIC_PUSH DISABLE_WARNING(4100) #endif - CollectionFind(CollectionFind &other) : Executable(other) {} + CollectionFind(CollectionFind &other) : Executable(other) {} CollectionFind(CollectionFind &&other) : CollectionFind(other) {} DIAGNOSTIC_POP @@ -908,6 +923,7 @@ namespace internal { by the user. */ + struct CollectionModify_impl : public Sort_impl { enum Operation @@ -937,7 +953,7 @@ namespace internal { */ class PUBLIC_API CollectionModify - : public internal::CollectionSort + : public internal::CollectionSort { private: @@ -971,7 +987,7 @@ DIAGNOSTIC_PUSH DISABLE_WARNING(4100) #endif - CollectionModify(CollectionModify &other) : Executable(other) {} + CollectionModify(CollectionModify &other) : Executable(other) {} CollectionModify(CollectionModify &&other) : CollectionModify(other) {} DIAGNOSTIC_POP diff --git a/include/devapi/crud.h b/include/devapi/crud.h index c5acbcf6d..5cdd3c7c4 100644 --- a/include/devapi/crud.h +++ b/include/devapi/crud.h @@ -131,9 +131,9 @@ struct Limit_impl : public Statement_impl Base class defining operation's offset() clause. */ -template +template class Offset - : public Statement + : public Statement { protected: @@ -143,8 +143,8 @@ class Offset Offset() = default; - using Statement::check_if_valid; - using Statement::m_impl; + using Statement::check_if_valid; + using Statement::m_impl; Impl* get_impl() { @@ -159,7 +159,7 @@ class Offset to perform the operation. */ - Statement& offset(unsigned rows) + Statement& offset(unsigned rows) { get_impl()->set_offset(rows); return *this; @@ -175,18 +175,18 @@ class Offset method) is defined by LimitRet::type. */ -template struct LimitRet; +template struct LimitRet; -template -struct LimitRet +template +struct LimitRet { - typedef Offset type; + typedef Offset type; }; -template -struct LimitRet +template +struct LimitRet { - typedef Statement type; + typedef Statement type; }; @@ -196,9 +196,9 @@ struct LimitRet // TODO: Doxygen does not see the base class -template +template class Limit - : public LimitRet::type + : public LimitRet::type { protected: @@ -206,8 +206,8 @@ class Limit Limit() = default; - using LimitRet::type::check_if_valid; - using LimitRet::type::m_impl; + using LimitRet::type::check_if_valid; + using LimitRet::type::m_impl; Impl* get_impl() { @@ -221,7 +221,7 @@ class Limit %Limit the operation to the given number of items (rows or documents). */ - typename LimitRet::type& limit(unsigned items) + typename LimitRet::type& limit(unsigned items) { get_impl()->set_limit(items); return *this; diff --git a/include/devapi/result.h b/include/devapi/result.h index 3a7e8271f..2e93f3174 100644 --- a/include/devapi/result.h +++ b/include/devapi/result.h @@ -59,7 +59,7 @@ class SqlResult; class DbDoc; class DocResult; -template class Executable; +template class Executable; /* @@ -472,7 +472,8 @@ class PUBLIC_API Result : public internal::BaseResult init(std::move(other)); } - friend Executable; + template + friend class Executable; }; @@ -988,7 +989,8 @@ class PUBLIC_API RowResult return m_cur_row; } - friend Executable; + template + friend class Executable; friend SqlResult; friend DocResult; friend iterator; @@ -1050,7 +1052,8 @@ class PUBLIC_API SqlResult : public RowResult : RowResult(std::move(init_)) {} - friend Executable; + template + friend class Executable; }; @@ -1158,7 +1161,8 @@ class PUBLIC_API DocResult friend Impl; friend DbDoc; - friend Executable; + template + friend class Executable; friend iterator; }; diff --git a/include/devapi/statement.h b/include/devapi/statement.h index b21204235..63bab21c1 100644 --- a/include/devapi/statement.h +++ b/include/devapi/statement.h @@ -76,7 +76,7 @@ struct Executable_impl is returned by `execute()` method. */ -template +template class Executable { protected: @@ -107,6 +107,7 @@ class Executable : m_impl(other.m_impl) {} + virtual ~Executable() {} /// Execute given operation and wait for its result. @@ -134,7 +135,7 @@ namespace internal { bound to named parameters to the implementation. */ - struct Statement_impl : public Executable_impl +struct Statement_impl : public Executable_impl { virtual void add_param(const string&, Value&&) = 0; }; @@ -154,9 +155,9 @@ namespace internal { is returned by `execute()` method. */ -template +template class Statement - : public virtual Executable + : public virtual Executable { protected: @@ -164,11 +165,11 @@ class Statement Statement() = default; Statement(Impl *impl) - : Executable(impl) + : Executable(impl) {} - using Executable::check_if_valid; - using Executable::m_impl; + using Executable::check_if_valid; + using Executable::m_impl; Impl* get_impl() { @@ -179,10 +180,10 @@ class Statement public: Statement(Statement &other) - : Executable(other) + : Executable(other) {} - Statement(Statement &&other) : Executable(std::move(other)) {} + Statement(Statement &&other) : Executable(std::move(other)) {} /// Bind parameter with given name to the given value. @@ -202,7 +203,7 @@ class Statement */ template - Executable& bind(const Map &args) + Executable& bind(const Map &args) { check_if_valid(); for (const auto &keyval : args) @@ -248,6 +249,7 @@ namespace internal { not named but positional. */ + struct SqlStatement_impl : public Executable_impl { virtual void add_param(Value) = 0; @@ -271,7 +273,7 @@ struct SqlStatement_impl : public Executable_impl DLL_WARNINGS_PUSH class PUBLIC_API SqlStatement - : public virtual Executable + : public virtual Executable { DLL_WARNINGS_POP @@ -282,8 +284,8 @@ DLL_WARNINGS_POP SqlStatement() = default; - using Executable::check_if_valid; - using Executable::m_impl; + using Executable::check_if_valid; + using Executable::m_impl; Impl* get_impl() { @@ -296,7 +298,7 @@ DLL_WARNINGS_POP public: SqlStatement(SqlStatement &other) - : Executable(std::move(other)) + : Executable(std::move(other)) {} SqlStatement& bind(Value val) diff --git a/include/devapi/table_crud.h b/include/devapi/table_crud.h index e5b446ec1..0e545fd45 100644 --- a/include/devapi/table_crud.h +++ b/include/devapi/table_crud.h @@ -156,7 +156,7 @@ namespace internal { */ class PUBLIC_API TableInsert - : public Executable + : public Executable { typedef internal::TableInsert_impl Impl; @@ -261,6 +261,14 @@ class PUBLIC_API TableInsert TableInsert(TableInsert &&other) : TableInsert(other) {} + /* + TODO: Implement copy semantics for this and other crud operations. + Note that the ctor TableInsert(TableInsert &other) implements move + semantics, because m_row pointer is moved from one instance to the + other. + + TODO: Add ctor from the base Executable<> class. + */ /// Add given row to the list of rows to be inserted. @@ -392,16 +400,16 @@ namespace internal { Class defining table CRUD .orderBy() clause. */ - template + template class TableSort - : public Limit + : public Limit { protected: typedef internal::Sort_impl Impl; - using Limit::check_if_valid; - using Limit::m_impl; + using Limit::check_if_valid; + using Limit::m_impl; Impl* get_impl() { @@ -467,17 +475,18 @@ namespace internal { Class defining table CRUD .having() clause. */ + template class TableHaving - : public TableSort + : public TableSort { protected: typedef internal::Having_impl Impl; - using TableSort::check_if_valid; - using TableSort::m_impl; + using TableSort::check_if_valid; + using TableSort::m_impl; - typedef TableSort TableSort; +// typedef TableSort TableSort; Impl* get_impl() { @@ -493,7 +502,7 @@ namespace internal { Arguments are a string defining filter to be used. */ - TableSort& having(const string& having_spec) + TableSort& having(const string& having_spec) { get_impl()->set_having(having_spec); return *this; @@ -512,18 +521,19 @@ namespace internal { Class defining .groupBy() clause. */ + template class TableGroupBy - : public internal::TableHaving + : public internal::TableHaving { protected: typedef internal::Group_by_impl Impl; - using TableHaving::check_if_valid; - using TableHaving::m_impl; + using TableHaving::check_if_valid; + using TableHaving::m_impl; - typedef internal::TableHaving TableHaving; + typedef internal::TableHaving TableHaving; Impl* get_impl() { @@ -613,15 +623,15 @@ namespace internal { DLL_WARNINGS_PUSH class PUBLIC_API TableSelect - : public internal::TableGroupBy + : public internal::TableGroupBy { DLL_WARNINGS_POP typedef internal::TableSelect_impl Impl; - using TableGroupBy::check_if_valid; - using TableGroupBy::m_impl; + using TableGroupBy::check_if_valid; + using TableGroupBy::m_impl; Impl* get_impl() { @@ -680,8 +690,13 @@ DIAGNOSTIC_PUSH add_proj(proj...); } - TableSelect(const TableSelect &other) : Executable(other) {} - TableSelect(TableSelect &&other) : Executable(std::move(other)) {} + TableSelect(const Executable &other) + : Executable(other) + {} + + TableSelect(Executable &&other) + : Executable(std::move(other)) + {} DIAGNOSTIC_POP @@ -767,11 +782,11 @@ namespace internal { */ class PUBLIC_API TableUpdate -: public internal::TableSort +: public internal::TableSort { typedef internal::TableUpdate_impl Impl; - typedef internal::TableSort TableSort; + typedef internal::TableSort TableSort; Impl* get_impl() { @@ -796,7 +811,7 @@ DIAGNOSTIC_PUSH // TODO: ctor with where condition? - TableUpdate(TableUpdate &other) : Executable(other) {} + TableUpdate(TableUpdate &other) : Executable(other) {} TableUpdate(TableUpdate &&other) : TableUpdate(other) {} DIAGNOSTIC_POP @@ -889,11 +904,11 @@ namespace internal { class PUBLIC_API TableRemove - : public internal::TableSort + : public internal::TableSort { typedef internal::TableRemove_impl Impl; - typedef internal::TableSort TableSort; + typedef internal::TableSort TableSort; Impl* get_impl() { @@ -918,7 +933,7 @@ DIAGNOSTIC_PUSH // TODO: ctor with where condition? - TableRemove(TableRemove &other) : Executable(other) {} + TableRemove(TableRemove &other) : Executable(other) {} TableRemove(TableRemove &&other) : TableRemove(other) {} DIAGNOSTIC_POP diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 8af28cb13..8767208f4 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -205,11 +205,16 @@ struct View_impl virtual void with_check_option(CheckOption) = 0; }; -class PUBLIC_API View_check_opt -: public Executable + +template +class ViewCheckOpt +: public Executable { protected: + using Executable::check_if_valid; + using Executable::m_impl; + View_impl* get_impl() { check_if_valid(); @@ -221,16 +226,20 @@ class PUBLIC_API View_check_opt /** Set constraints on the View. */ - Executable withCheckOption(CheckOption option) + Executable withCheckOption(CheckOption option) { get_impl()->with_check_option(option); return std::move(*this); } }; -class PUBLIC_API View_defined_as -: protected View_check_opt +template +class ViewDefinedAs +: protected ViewCheckOpt { +protected: + + using ViewCheckOpt::get_impl; public: @@ -238,13 +247,13 @@ class PUBLIC_API View_defined_as Define the table select statement to generate the View. */ - View_check_opt definedAs(TableSelect&& table) + ViewCheckOpt definedAs(TableSelect&& table) { get_impl()->defined_as(std::move(table)); return std::move(*this); } - View_check_opt definedAs(const TableSelect& table) + ViewCheckOpt definedAs(const TableSelect& table) { TableSelect table_tmp(table); get_impl()->defined_as(std::move(table_tmp)); @@ -252,41 +261,53 @@ class PUBLIC_API View_defined_as } }; -class PUBLIC_API View_definer -: public View_defined_as +template +class ViewDefiner +: public ViewDefinedAs { +protected: + + using ViewDefinedAs::get_impl; public: /** Define the View’s definer. */ - View_defined_as definer(const string &user) + ViewDefinedAs definer(const string &user) { get_impl()->definer(user); return std::move(*this); } }; -class PUBLIC_API View_security - : public View_definer +template +class ViewSecurity + : public ViewDefiner { +protected: + + using ViewDefiner::get_impl; public: /** Define the View’s security scheme. */ - View_definer security(SQLSecurity sec) + ViewDefiner security(SQLSecurity sec) { get_impl()->security(sec); return std::move(*this); } }; -class PUBLIC_API View_algorithm - : public View_security +template +class ViewAlgorithm + : public ViewSecurity { +protected: + + using ViewSecurity::get_impl; public: @@ -294,7 +315,7 @@ class PUBLIC_API View_algorithm define the View’s algorithm. */ - View_security algorithm(Algorithm alg) + ViewSecurity algorithm(Algorithm alg) { get_impl()->algorithm(alg); return std::move(*this); @@ -306,9 +327,13 @@ class PUBLIC_API View_algorithm /* Base blass for Create/Alter View */ -class PUBLIC_API View_base - : public View_algorithm +template +class View_base + : public ViewAlgorithm { +protected: + + using ViewAlgorithm::get_impl; void add_columns(const char *name) { @@ -343,14 +368,14 @@ class PUBLIC_API View_base */ template - View_algorithm columns(const T&...names) + ViewAlgorithm columns(const T&...names) { add_columns(names...); return std::move(*this); } /// @cond IGNORED - friend class Schema; + friend Schema; friend ViewCreate; friend ViewAlter; /// @endcond @@ -358,8 +383,6 @@ class PUBLIC_API View_base }; - - } // namespace internal /** @@ -367,13 +390,13 @@ class PUBLIC_API View_base */ class PUBLIC_API ViewCreate - : public internal::View_base + : public internal::View_base { ViewCreate(Schema &sch, const string& name, bool replace); /// @cond IGNORED - friend class Schema; + friend Schema; /// @endcond }; @@ -384,13 +407,13 @@ class PUBLIC_API ViewCreate */ class PUBLIC_API ViewAlter - : public internal::View_base + : public internal::View_base { ViewAlter(Schema &sch, const string& name); /// @cond IGNORED - friend class Schema; + friend Schema; /// @endcond }; @@ -405,13 +428,18 @@ namespace internal { struct ViewDrop_impl : public Executable_impl { - virtual void if_exists() = 0; }; + +template class ViewDropIfExists - : public Executable + : public Executable { +protected: + + using Executable::check_if_valid; + using Executable::m_impl; ViewDrop_impl* get_impl() { @@ -421,7 +449,7 @@ class ViewDropIfExists public: - Executable ifExists() + Executable ifExists() { get_impl()->if_exists(); return std::move(*this); @@ -435,13 +463,13 @@ class ViewDropIfExists */ class PUBLIC_API ViewDrop - : public internal::ViewDropIfExists + : public internal::ViewDropIfExists { ViewDrop(Schema &sch, const string& name); /// @cond IGNORED - friend class Schema; + friend Schema; /// @endcond }; From 618fb3381b24d6e131e13881b5d6a78e586b2557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Sat, 18 Feb 2017 19:26:09 +0000 Subject: [PATCH 60/79] Fix Windows failing tests because m_opts_mask was not present on copy constructor --- devapi/table_crud.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index 8a4cca78e..b5edfe3bc 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -513,6 +513,7 @@ class Op_ViewCreateAlter , m_security (other.m_security ) , m_algorithm (other.m_algorithm ) , m_definer (other.m_definer ) + , m_opts_mask (other.m_opts_mask ) { if (other.m_table_select.get() != NULL) { From dad63f018d25d4412f050ace7718e7968a050652 Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Mon, 30 Jan 2017 21:50:10 +1100 Subject: [PATCH 61/79] Added ssl-enable, ssl-ca and ssl-ca-path options into XAPI --- include/mysql_xapi.h | 4 +- xapi/mysqlx.cc | 51 +++++++++++++++--- xapi/mysqlx_cc_internal.h | 83 ++++++++++++++++++++++++---- xapi/tests/xapi-t.cc | 110 ++++++++++++++++++++++++++++++++------ 4 files changed, 212 insertions(+), 36 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 36d652597..9747459af 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -334,7 +334,9 @@ typedef enum mysqlx_opt_type_enum MYSQLX_OPT_USER = 3, MYSQLX_OPT_PWD = 4, MYSQLX_OPT_DB = 5, - MYSQLX_OPT_SSL_ENABLE = 6 + MYSQLX_OPT_SSL_ENABLE = 6, + MYSQLX_OPT_SSL_CA = 7, + MYSQLX_OPT_SSL_CA_PATH = 8 } mysqlx_opt_type_t; diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index 0ac7c4370..fb2789614 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -1716,17 +1716,29 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, char_data = ""; opt->set_database(char_data); break; - case MYSQLX_OPT_SSL_ENABLE: #ifdef WITH_SSL + case MYSQLX_OPT_SSL_ENABLE: uint_data = va_arg(args, unsigned int); opt->set_tls(uint_data > 0); + break; + case MYSQLX_OPT_SSL_CA: + char_data = va_arg(args, char*); + opt->set_ssl_ca(char_data); + break; + case MYSQLX_OPT_SSL_CA_PATH: + char_data = va_arg(args, char*); + opt->set_ssl_ca_path(char_data); + break; #else + case MYSQLX_OPT_SSL_ENABLE: + case MYSQLX_OPT_SSL_CA: + case MYSQLX_OPT_SSL_CA_PATH: opt->set_diagnostic( "Can not create TLS session - this connector is built" " without TLS support.", 0 ); + break; #endif - break; default: opt->set_diagnostic("Invalid option value", 0); rc = RESULT_ERROR; @@ -1737,7 +1749,7 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, SAFE_EXCEPTION_END(opt, RESULT_ERROR) } -#define CHAR_OUTPUT_BUF(V) V = va_arg(args, char*); \ +#define CHECK_OUTPUT_BUF(V, T) V = va_arg(args, T); \ if (V == NULL) \ { \ opt->set_diagnostic(MYSQLX_ERROR_OUTPUT_BUFFER_NULL, 0); \ @@ -1759,25 +1771,48 @@ mysqlx_session_option_get(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, switch(type) { case MYSQLX_OPT_HOST: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_host().data()); break; case MYSQLX_OPT_PORT: - uint_data = va_arg(args, unsigned int*); + CHECK_OUTPUT_BUF(uint_data, unsigned int*) *uint_data = opt->get_port(); break; case MYSQLX_OPT_USER: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_user().data()); break; case MYSQLX_OPT_PWD: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_password().data()); break; case MYSQLX_OPT_DB: - CHAR_OUTPUT_BUF(char_data) + CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_db().data()); break; +#ifdef WITH_SSL + case MYSQLX_OPT_SSL_ENABLE: + CHECK_OUTPUT_BUF(uint_data, unsigned int*) + *uint_data = opt->get_tls().use_tls() ? 1 : 0; + break; + case MYSQLX_OPT_SSL_CA: + CHECK_OUTPUT_BUF(char_data, char*) + strcpy(char_data, opt->get_tls().get_ca().data()); + break; + case MYSQLX_OPT_SSL_CA_PATH: + CHECK_OUTPUT_BUF(char_data, char*) + strcpy(char_data, opt->get_tls().get_ca_path().data()); + break; +#else + case MYSQLX_OPT_SSL_ENABLE: + case MYSQLX_OPT_SSL_CA: + case MYSQLX_OPT_SSL_CA_PATH: + opt->set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); + break; +#endif default: opt->set_diagnostic("Invalid option value", 0); rc = RESULT_ERROR; diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 19b194e56..12c1741b4 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -366,6 +366,7 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, /* The pointer is used because TCPIP options can only be set in the constructor */ cdk::ds::TCPIP *m_tcp; + cdk::connection::TLS::Options m_tls_options; public: mysqlx_session_options_struct() : m_tcp(NULL) @@ -388,9 +389,10 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, if (db) set_database(*db); -#ifdef WITH_SSL + // This call must be made at all times because SSL is enabled by default set_tls(ssl_enable); -#else + +#ifndef WITH_SSL if (ssl_enable) set_diagnostic( "Can not create TLS session - this connector is built" @@ -401,6 +403,7 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, mysqlx_session_options_struct(const std::string &conn_str) : m_tcp(NULL) { + set_tls(false); parser::parse_conn_str(conn_str, *this); } @@ -434,30 +437,88 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, m_port = port; } + std::string get_host() { return m_host; } + unsigned int get_port() { return m_port; } + std::string get_user() { return m_usr; } + std::string get_password() { return m_pwd; } + std::string get_db() { return m_db; } + + void set_use_tls(bool tls) + { + if (tls) + set_tls(m_tls_options); + else + set_tls(false); + } + + void set_ssl_ca(const string &ca) + { + m_tls_options.set_ca(ca); + set_tls(m_tls_options); + } + + void set_ssl_ca_path(const string &ca_path) + { + m_tls_options.set_ca_path(ca_path); + set_tls(m_tls_options); + } + + void set_ssl_key(const string &key) + { + m_tls_options.set_key(key); + set_tls(m_tls_options); + } + // Implementing URI_Processor interface void path(const std::string &path) - { set_database(path); } + { + set_database(path); + } void key_val(const std::string& key) { - if (key.compare("ssl-enable") == 0) + if (key.find("ssl-", 0) == 0) { #ifdef WITH_SSL - set_tls(true); + if (key.compare("ssl-enable") == 0) + { + set_tls(true); + } #else set_diagnostic( "Can not create TLS session - this connector is built" " without TLS support.", 0 - ); + ); #endif } } - std::string get_host() { return m_host; } - unsigned int get_port() { return m_port; } - std::string get_user() { return m_usr; } - std::string get_password() { return m_pwd; } - std::string get_db() { return m_db; } + void key_val(const std::string& key, const std::string& val) + { + if (key.find("ssl-", 0) == 0) + { + #ifdef WITH_SSL + if (key.compare("ssl-ca") == 0) + { + set_ssl_ca(val); + } + else if (key.compare("ssl-ca-path") == 0) + { + set_ssl_ca_path(val); + } + else if (key.compare("ssl-key") == 0) + { + set_ssl_key(val); + } +#else + set_diagnostic( + "Can not create TLS session - this connector is built" + " without TLS support.", 0 + ); + #endif + } + } + ~mysqlx_session_options_struct() { diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 846e3a3ad..65f50d3bc 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -27,7 +27,6 @@ #include #include "test.h" - TEST_F(xapi, store_result_select) { SKIP_IF_NO_XPLUGIN @@ -317,7 +316,7 @@ TEST_F(xapi, conn_string_test) unsigned short port = 0; char conn_error[MYSQLX_MAX_ERROR_LEN] = { 0 }; - char conn_str[1024]; + char conn_str[4096]; int conn_err_code = 0; bool ssl_enable = false; const char *xplugin_port = getenv("XPLUGIN_PORT"); @@ -326,8 +325,8 @@ TEST_F(xapi, conn_string_test) const char *xplugin_host = getenv("XPLUGIN_HOST"); mysqlx_session_t *local_sess; - mysqlx_stmt_t *stmt; mysqlx_result_t *res; + mysqlx_stmt_t *stmt; mysqlx_row_t *row; if (xplugin_port) @@ -354,16 +353,19 @@ TEST_F(xapi, conn_string_test) } cout << "Connected to xplugin..." << endl; - RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SELECT 'foo'", MYSQLX_NULL_TERMINATED)); + RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SHOW STATUS LIKE 'mysqlx_ssl_cipher'", MYSQLX_NULL_TERMINATED)); CRUD_CHECK(res = mysqlx_execute(stmt), stmt); - while ((row = mysqlx_row_fetch_one(res)) != NULL) + if ((row = mysqlx_row_fetch_one(res)) != NULL) { - char data[32]; + char data[128] = { 0 }; size_t data_len = sizeof(data); - EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, data, &data_len)); - EXPECT_STREQ("foo", data); - cout << "ROW DATA: " << data << " " << endl; + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, data, &data_len)); + if (ssl_enable) + { + cout << "SSL Cipher: " << data << endl; + EXPECT_TRUE(data_len > 1); + } } mysqlx_session_close(local_sess); @@ -372,6 +374,33 @@ TEST_F(xapi, conn_string_test) { ssl_enable = true; strcat(conn_str, "/?ssl-enable"); + authenticate(); + + res = mysqlx_sql(get_session(), "select @@ssl_ca, @@ssl_capath, @@datadir", MYSQLX_NULL_TERMINATED); + if ((row = mysqlx_row_fetch_one(res)) != NULL) + { + char ca_buf[1024] = { 0 }, capath_buf[1024] = { 0 }; + size_t ca_len = sizeof(ca_buf), capath_len = sizeof(capath_buf); + int rc = mysqlx_get_bytes(row, 0, 0, ca_buf, &ca_len); + if (rc != RESULT_OK && ca_len < 2) + return; + + strcat(conn_str, "&ssl-ca="); + rc = mysqlx_get_bytes(row, 1, 0, capath_buf, &capath_len); + if (rc != RESULT_OK || capath_len < 2) + { + capath_len = sizeof(capath_buf); + rc = mysqlx_get_bytes(row, 2, 0, capath_buf, &capath_len); + if (rc != RESULT_OK && capath_len < 2) + return; // Could not collect enough data about certificates + + strcat(conn_str, capath_buf); + } + strcat(conn_str, ca_buf); + strcat(conn_str, "&ssl-ca-path="); + strcat(conn_str, capath_buf); + } + goto DO_CONNECT; } } @@ -390,6 +419,7 @@ TEST_F(xapi, conn_options_test) const char *xplugin_usr = getenv("XPLUGIN_USER"); const char *xplugin_pwd = getenv("XPLUGIN_PASSWORD"); const char *xplugin_host = getenv("XPLUGIN_HOST"); + bool ssl_ca_detected = false; char buf[1024]; @@ -436,23 +466,71 @@ TEST_F(xapi, conn_options_test) } cout << "Connected to xplugin..." << endl; - RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SELECT 'foo'", MYSQLX_NULL_TERMINATED)); + RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SHOW STATUS LIKE 'mysqlx_ssl_cipher'", MYSQLX_NULL_TERMINATED)); CRUD_CHECK(res = mysqlx_execute(stmt), stmt); - while ((row = mysqlx_row_fetch_one(res)) != NULL) + if ((row = mysqlx_row_fetch_one(res)) != NULL) { - char data[32]; + char data[128] = { 0 }; size_t data_len = sizeof(data); - EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, data, &data_len)); - EXPECT_STREQ("foo", data); - cout << "ROW DATA: " << data << " " << endl; + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, data, &data_len)); + if (ssl_ca_detected) + { + cout << "SSL Cipher: " << data << endl; + EXPECT_TRUE(data_len > 0); + } } mysqlx_session_close(local_sess); + if (!ssl_enable) { - ssl_enable = 1; + ssl_enable = true; + authenticate(); EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_ENABLE, ssl_enable)); + + res = mysqlx_sql(get_session(), "select @@ssl_ca, @@ssl_capath, @@datadir", MYSQLX_NULL_TERMINATED); + if ((row = mysqlx_row_fetch_one(res)) != NULL) + { + char ca_buf[1024] = { 0 }, capath_buf[1024] = { 0 }, combined_buf[1024] = { 0 }; + char buf_check[1024] = { 0 }; + size_t ca_len = sizeof(ca_buf), capath_len = sizeof(capath_buf); + int rc = mysqlx_get_bytes(row, 0, 0, ca_buf, &ca_len); + if (rc != RESULT_OK && ca_len < 2) + { + mysqlx_free_options(opt); + return; + } + + rc = mysqlx_get_bytes(row, 1, 0, capath_buf, &capath_len); + if (rc != RESULT_OK || capath_len < 2) + { + capath_len = sizeof(capath_buf); + rc = mysqlx_get_bytes(row, 2, 0, capath_buf, &capath_len); + if (rc != RESULT_OK && capath_len < 2) + { + mysqlx_free_options(opt); + return; + } + + strcat(combined_buf, capath_buf); + strcat(combined_buf, ca_buf); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA, combined_buf)); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA, buf_check)); + EXPECT_STREQ(combined_buf, buf_check); + } + else + { + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA, ca_buf)); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA, buf_check)); + EXPECT_STREQ(ca_buf, buf_check); + } + + EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA_PATH, capath_buf)); + EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA_PATH, buf_check)); + EXPECT_STREQ(capath_buf, buf_check); + } + goto DO_CONNECT; } From 03f4a0f17e370b1ded7cad0ee3e29c1c75a4a141 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Mon, 30 Jan 2017 16:25:58 +0100 Subject: [PATCH 62/79] Merge from CDK: Restrict allowed TLS ciphers. --- cdk/foundation/connection_yassl.cc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/cdk/foundation/connection_yassl.cc b/cdk/foundation/connection_yassl.cc index 3d619ae04..fef7d6a44 100644 --- a/cdk/foundation/connection_yassl.cc +++ b/cdk/foundation/connection_yassl.cc @@ -34,6 +34,15 @@ POP_SYS_WARNINGS #include "connection_tcpip_base.h" +static const char* tls_ciphers_list="DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" + "AES128-RMD:DES-CBC3-RMD:DHE-RSA-AES256-RMD:" + "DHE-RSA-AES128-RMD:DHE-RSA-DES-CBC3-RMD:" + "AES256-SHA:RC4-SHA:RC4-MD5:DES-CBC3-SHA:" + "DES-CBC-SHA:EDH-RSA-DES-CBC3-SHA:" + "EDH-RSA-DES-CBC-SHA:AES128-SHA:AES256-RMD:"; +static const char* tls_cipher_blocked= "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:!SSLv3:"; + + static void throw_yassl_error_msg(const char* msg) { throw cdk::foundation::Error(cdk::foundation::cdkerrc::tls_error, @@ -103,7 +112,7 @@ void connection_TLS_impl::do_connect() try { - yaSSL::SSL_METHOD* method = yaSSL::TLSv1_client_method(); + yaSSL::SSL_METHOD* method = yaSSL::TLSv1_1_client_method(); if (!method) throw_yassl_error(); @@ -112,6 +121,13 @@ void connection_TLS_impl::do_connect() if (!m_tls_ctx) throw_yassl_error(); + + std::string cipher_list; + cipher_list.append(tls_cipher_blocked); + cipher_list.append(tls_ciphers_list); + + SSL_CTX_set_cipher_list(m_tls_ctx, cipher_list.c_str()); + if (!m_options.get_ca().empty() || !m_options.get_ca_path().empty()) { From 630e17432eb012f8cd1e57ccb2dbc94562334a1a Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 9 Feb 2017 10:39:06 +0100 Subject: [PATCH 63/79] MYCPP-284: TLS Options implementation on DevAPI --- cdk/core/tests/session-t.cc | 5 ++ cdk/include/mysql/cdk/data_source.h | 6 +- .../mysql/cdk/foundation/connection_yassl.h | 1 + devapi/session.cc | 62 +++++++++++++---- devapi/tests/session-t.cc | 66 +++++++++++++++++++ include/mysql_devapi.h | 3 +- 6 files changed, 128 insertions(+), 15 deletions(-) diff --git a/cdk/core/tests/session-t.cc b/cdk/core/tests/session-t.cc index 21b26e617..aa4a0ae26 100644 --- a/cdk/core/tests/session-t.cc +++ b/cdk/core/tests/session-t.cc @@ -1032,6 +1032,11 @@ TEST_F(Session_core, tls_options) } } + if (ssl_ca.find('\\') == string::npos && ssl_ca.find('/') == string::npos) + { //not full path + ssl_ca = datadir + ssl_ca; + } + cout << "Setting CA to: " << ssl_ca << endl; tls_options.set_ca(ssl_ca); diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index b6d843d5a..16150130d 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -131,12 +131,16 @@ class TCPIP::Options : public ds::Options public: Options() +#ifdef WITH_SSL : m_tls_options(false) +#endif {} Options(const string &usr, const std::string *pwd =NULL) : ds::Options(usr, pwd) - , m_tls_options(false) + #ifdef WITH_SSL + ,m_tls_options(false) + #endif {} #ifdef WITH_SSL diff --git a/cdk/include/mysql/cdk/foundation/connection_yassl.h b/cdk/include/mysql/cdk/foundation/connection_yassl.h index 84c84dd78..cd7d764d5 100644 --- a/cdk/include/mysql/cdk/foundation/connection_yassl.h +++ b/cdk/include/mysql/cdk/foundation/connection_yassl.h @@ -75,6 +75,7 @@ class TLS::Options : m_use_tls(use_tls) {} + void set_use_tls(bool use_tls) { m_use_tls = use_tls; } bool use_tls() const { return m_use_tls; } void set_key(const string &key) { m_key = key; } diff --git a/devapi/session.cc b/devapi/session.cc index e9a580967..0979554fb 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -129,13 +129,18 @@ struct URI_parser , private endpoint::TCPIP , public parser::URI_processor { + +#ifdef WITH_SSL + // tls off by default on URI connection + cdk::connection::TLS::Options m_tls_opt = false; +#endif + URI_parser(const std::string &uri) { + parser::parse_conn_str(uri, *this); #ifdef WITH_SSL - // TLS OFF by default on URI - set_tls(false); + set_tls(m_tls_opt); #endif - parser::parse_conn_str(uri, *this); } @@ -173,14 +178,36 @@ struct URI_parser void key_val(const std::string &key) override { if (key == "ssl-enable") + { +#ifdef WITH_SSL + m_tls_opt.set_use_tls(true); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif + } + } + + void key_val(const std::string &key, const std::string &val) override + { + if (key == "ssl-ca") + { #ifdef WITH_SSL - set_tls(true); + m_tls_opt.set_ca(val); #else throw_error( - "Can not create TLS session - this connector is built" - " without TLS support." - ); + "Can not create TLS session - this connector is built" + " without TLS support." + ); #endif + } else + { + std::stringstream err; + err << "Unexpected key " << key << "=" << val << " on URI"; + throw_error(err.str().c_str()); + } } }; @@ -197,8 +224,8 @@ internal::XSession_base::XSession_base(SessionSettings settings) ); m_impl = new Impl( - static_cast(parser.get_endpoint()), - static_cast(parser)); + static_cast(parser.get_endpoint()), + static_cast(parser)); } else { @@ -246,16 +273,25 @@ internal::XSession_base::XSession_base(SessionSettings settings) ); if (settings.has_option(SessionSettings::SSL_ENABLE)) + { #ifdef WITH_SSL - opt.set_tls(settings[SessionSettings::SSL_ENABLE].get()); + cdk::connection::TLS::Options opt_ssl(settings[SessionSettings::SSL_ENABLE]); + + + if (settings.has_option(SessionSettings::SSL_CA)) + opt_ssl.set_ca(settings[SessionSettings::SSL_ENABLE].get()); + + opt.set_tls(opt_ssl); #else throw_error( - "Can not create TLS session - this connector is built" - " without TLS support." - ); + "Can not create TLS session - this connector is built" + " without TLS support." + ); #endif + } m_impl = new Impl(ep, opt); + } } CATCH_AND_WRAP diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index f7f0b5796..1befbb0e8 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -431,6 +431,72 @@ TEST_F(Sess, ssl_session) EXPECT_FALSE(cipher.empty()); } + + //using wrong ssl-ca and ssl-ca-path as SessionSettings + { + EXPECT_THROW( + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, "unknown") + , mysqlx::Error); + + + } + + //using wrong ssl-ca and ssl-ca-path on URI + { + std::stringstream bad_uri; + bad_uri << uri.str() << "&ssl-ca=" << "unknown.file" << "&ssl-ca-path=" << "unknown.path"; + + EXPECT_THROW(mysqlx::XSession sess(bad_uri.str()), mysqlx::Error); + } + + string ssl_ca; + string datadir; + + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard() + .sql("show global variables like 'ssl_ca'") + .execute(); + + ssl_ca = res.fetchOne().get(1); + + res = sess.bindToDefaultShard() + .sql("show global variables like 'datadir'") + .execute(); + + datadir = res.fetchOne().get(1); + + } + + std::cout << "ssl-ca:" << ssl_ca + << " datadir:" << datadir + << std::endl; + + if (ssl_ca.find('\\') == string::npos && ssl_ca.find('/') == string::npos) + { //not full path + ssl_ca = datadir + ssl_ca; + } + + uri << "&ssl-ca=" << ssl_ca; + + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } + } TEST_F(Sess, ipv6) diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 3464200dc..c54c2b28f 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -516,7 +516,8 @@ class PUBLIC_API SessionSettings USER, PWD, DB, - SSL_ENABLE + SSL_ENABLE, + SSL_CA }; From 53df4fefc09e0e3dc9d910bcc8bc0ed6011424e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 14 Feb 2017 15:45:10 +0000 Subject: [PATCH 64/79] Bug#25530569 Fix "Invalid value type" when passing SSL_CA as SessionSettings --- devapi/session.cc | 13 +++++++-- devapi/tests/session-t.cc | 58 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/devapi/session.cc b/devapi/session.cc index 0979554fb..1f443d2fb 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -272,14 +272,21 @@ internal::XSession_base::XSession_base(SessionSettings settings) settings[SessionSettings::DB].get() ); - if (settings.has_option(SessionSettings::SSL_ENABLE)) + if (settings.has_option(SessionSettings::SSL_ENABLE) || + settings.has_option(SessionSettings::SSL_CA)) { #ifdef WITH_SSL - cdk::connection::TLS::Options opt_ssl(settings[SessionSettings::SSL_ENABLE]); + + //ssl_enable by default, unless SSL_ENABLE = false + bool ssl_enable = true; + if (settings.has_option(SessionSettings::SSL_ENABLE)) + ssl_enable = settings[SessionSettings::SSL_ENABLE]; + + cdk::connection::TLS::Options opt_ssl(ssl_enable); if (settings.has_option(SessionSettings::SSL_CA)) - opt_ssl.set_ca(settings[SessionSettings::SSL_ENABLE].get()); + opt_ssl.set_ca(settings[SessionSettings::SSL_CA].get()); opt.set_tls(opt_ssl); #else diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 1befbb0e8..d83b6ba79 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -432,7 +432,7 @@ TEST_F(Sess, ssl_session) } - //using wrong ssl-ca and ssl-ca-path as SessionSettings + //using wrong ssl-ca as SessionSettings { EXPECT_THROW( mysqlx::XSession sess(SessionSettings::PORT, get_port(), @@ -497,6 +497,62 @@ TEST_F(Sess, ssl_session) EXPECT_FALSE(cipher.empty()); } + //using ssl-enable and ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, ssl_ca); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + + } + + //using ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_CA, ssl_ca); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + + } + + //using ssl-ca but ssl-enable = false on SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, false, + SessionSettings::SSL_CA, ssl_ca); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + + } + } TEST_F(Sess, ipv6) From 909cf8acaf22349bd61d2022606a1efd2a9a0125 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 14 Feb 2017 19:44:29 +0100 Subject: [PATCH 65/79] XAPI: Remove ssl-ca-path and slsl-key options. --- include/mysql_xapi.h | 1 - xapi/mysqlx.cc | 8 -------- xapi/mysqlx_cc_internal.h | 8 -------- xapi/tests/xapi-t.cc | 4 ---- 4 files changed, 21 deletions(-) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 9747459af..f5f5dcffe 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -336,7 +336,6 @@ typedef enum mysqlx_opt_type_enum MYSQLX_OPT_DB = 5, MYSQLX_OPT_SSL_ENABLE = 6, MYSQLX_OPT_SSL_CA = 7, - MYSQLX_OPT_SSL_CA_PATH = 8 } mysqlx_opt_type_t; diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index fb2789614..2ab253189 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -1725,10 +1725,6 @@ mysqlx_session_option_set(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, char_data = va_arg(args, char*); opt->set_ssl_ca(char_data); break; - case MYSQLX_OPT_SSL_CA_PATH: - char_data = va_arg(args, char*); - opt->set_ssl_ca_path(char_data); - break; #else case MYSQLX_OPT_SSL_ENABLE: case MYSQLX_OPT_SSL_CA: @@ -1799,10 +1795,6 @@ mysqlx_session_option_get(mysqlx_session_options_t *opt, mysqlx_opt_type_t type, CHECK_OUTPUT_BUF(char_data, char*) strcpy(char_data, opt->get_tls().get_ca().data()); break; - case MYSQLX_OPT_SSL_CA_PATH: - CHECK_OUTPUT_BUF(char_data, char*) - strcpy(char_data, opt->get_tls().get_ca_path().data()); - break; #else case MYSQLX_OPT_SSL_ENABLE: case MYSQLX_OPT_SSL_CA: diff --git a/xapi/mysqlx_cc_internal.h b/xapi/mysqlx_cc_internal.h index 12c1741b4..c823fbb07 100644 --- a/xapi/mysqlx_cc_internal.h +++ b/xapi/mysqlx_cc_internal.h @@ -502,14 +502,6 @@ typedef struct mysqlx_session_options_struct : public Mysqlx_diag, { set_ssl_ca(val); } - else if (key.compare("ssl-ca-path") == 0) - { - set_ssl_ca_path(val); - } - else if (key.compare("ssl-key") == 0) - { - set_ssl_key(val); - } #else set_diagnostic( "Can not create TLS session - this connector is built" diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 65f50d3bc..aef52cea7 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -525,10 +525,6 @@ TEST_F(xapi, conn_options_test) EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA, buf_check)); EXPECT_STREQ(ca_buf, buf_check); } - - EXPECT_EQ(RESULT_OK, mysqlx_session_option_set(opt, MYSQLX_OPT_SSL_CA_PATH, capath_buf)); - EXPECT_EQ(RESULT_OK, mysqlx_session_option_get(opt, MYSQLX_OPT_SSL_CA_PATH, buf_check)); - EXPECT_STREQ(capath_buf, buf_check); } goto DO_CONNECT; From ceefe25b71247e7eb76516ce52d6b0dc113bb8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 14 Feb 2017 23:37:31 +0000 Subject: [PATCH 66/79] Bug#25526187: SSL CONNECTION FAILS WHEN SSL-CA IS SET BUT SSL-ENABLE IS NOT SET --- devapi/session.cc | 1 + devapi/tests/session-t.cc | 101 ++++++++++++++++++++++---------------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/devapi/session.cc b/devapi/session.cc index 1f443d2fb..aa2681944 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -195,6 +195,7 @@ struct URI_parser if (key == "ssl-ca") { #ifdef WITH_SSL + m_tls_opt.set_use_tls(true); m_tls_opt.set_ca(val); #else throw_error( diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index d83b6ba79..827269ea7 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -358,20 +358,29 @@ TEST_F(Sess, ssl_session) SKIP_IF_NO_XPLUGIN; + //Test if ssl is enabled using cipher + auto check_ssl_impl = [](mysqlx::XSession &sess, bool enable, int line) { - mysqlx::XSession sess(SessionSettings::PORT, get_port(), - SessionSettings::USER,get_user(), - SessionSettings::PWD, get_password() ? get_password() : NULL , - SessionSettings::SSL_ENABLE, true); - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; + cout << "Line "<< line << ": " << row[0] << ":" << row[1] << endl; string cipher = row[1]; - EXPECT_FALSE(cipher.empty()); + EXPECT_EQ(enable, !cipher.empty()); + }; + +#define check_ssl(x,y) check_ssl_impl(x, y, __LINE__) + + + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true); + + check_ssl(sess, true); } { @@ -380,14 +389,7 @@ TEST_F(Sess, ssl_session) SessionSettings::PWD, get_password() ? get_password() : nullptr , SessionSettings::SSL_ENABLE, false); - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); - - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; - - string cipher = row[1]; - - EXPECT_TRUE(cipher.empty()); + check_ssl(sess, false); } //Using URI @@ -404,31 +406,17 @@ TEST_F(Sess, ssl_session) //URI without ssl_enable { mysqlx::XSession sess(uri.str()); - - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); - - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; - - string cipher = row[1]; - - EXPECT_TRUE(cipher.empty()); + check_ssl(sess, false); } - //Enable SSL - uri << "/?ssl-enable"; { - mysqlx::XSession sess(uri.str()); - - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + std::stringstream uri_ssl; + //Enable SSL + uri_ssl << uri.str() << "/?ssl-enable"; - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; - - string cipher = row[1]; - - EXPECT_FALSE(cipher.empty()); + mysqlx::XSession sess(uri_ssl.str()); + check_ssl(sess, true); } @@ -437,7 +425,7 @@ TEST_F(Sess, ssl_session) EXPECT_THROW( mysqlx::XSession sess(SessionSettings::PORT, get_port(), SessionSettings::USER,get_user(), - SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::PWD, get_password() ? get_password() : nullptr , SessionSettings::SSL_ENABLE, true, SessionSettings::SSL_CA, "unknown") , mysqlx::Error); @@ -448,7 +436,7 @@ TEST_F(Sess, ssl_session) //using wrong ssl-ca and ssl-ca-path on URI { std::stringstream bad_uri; - bad_uri << uri.str() << "&ssl-ca=" << "unknown.file" << "&ssl-ca-path=" << "unknown.path"; + bad_uri << uri.str() << "/?ssl-ca=" << "unknown.file"; EXPECT_THROW(mysqlx::XSession sess(bad_uri.str()), mysqlx::Error); } @@ -482,19 +470,46 @@ TEST_F(Sess, ssl_session) ssl_ca = datadir + ssl_ca; } - uri << "&ssl-ca=" << ssl_ca; + uri << "/?ssl-ca=" << ssl_ca; { mysqlx::XSession sess(uri.str()); + check_ssl(sess, true); + } - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + //using ssl-enable and ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, ssl_ca); - auto row = res.fetchOne(); - cout << row[0] << ":" << row[1] << endl; + check_ssl(sess, true); - string cipher = row[1]; + } + + //using ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, true); + + } + + //using ssl-ca but ssl-enable = false on SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false, + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, false); - EXPECT_FALSE(cipher.empty()); } //using ssl-enable and ssl-ca as SessionSettings From 8f92051f534d71d3fdae40beec3373c14ca7e8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 21 Feb 2017 00:07:15 +0000 Subject: [PATCH 67/79] Merge remote-tracking branch 'origin/2.0-wl9970' into 2.0 --- devapi/tests/session-t.cc | 13 ------------- xapi/tests/xapi-t.cc | 15 +++++++++------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 581ac40b1..9aca45128 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -361,11 +361,6 @@ TEST_F(Sess, ssl_session) //Test if ssl is enabled using cipher auto check_ssl_impl = [](mysqlx::XSession &sess, bool enable, int line) { - mysqlx::XSession sess(SessionSettings::PORT, get_port(), - SessionSettings::USER,get_user(), - SessionSettings::PWD, get_password() ? get_password() : NULL , - SessionSettings::SSL_ENABLE, true); - SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); auto row = res.fetchOne(); @@ -529,12 +524,4 @@ TEST_F(Sess, ssl_session) } - - //Enable SSL - uri << "/?ssl-enable"; - { - mysqlx::XSession sess(uri.str()); - - check_ssl(sess, true); } - } diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index b85957f9f..7e94335fa 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -778,16 +778,19 @@ TEST_F(xapi, conn_string_test) } cout << "Connected to xplugin..." << endl; - RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SELECT 'foo'", MYSQLX_NULL_TERMINATED)); + RESULT_CHECK(stmt = mysqlx_sql_new(local_sess, "SHOW STATUS LIKE 'mysqlx_ssl_cipher'", MYSQLX_NULL_TERMINATED)); CRUD_CHECK(res = mysqlx_execute(stmt), stmt); - while ((row = mysqlx_row_fetch_one(res)) != NULL) + if ((row = mysqlx_row_fetch_one(res)) != NULL) { - char data[32]; + char data[128] = { 0 }; size_t data_len = sizeof(data); - EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, data, &data_len)); - EXPECT_STREQ("foo", data); - cout << "ROW DATA: " << data << " " << endl; + EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 1, 0, data, &data_len)); + if (ssl_enable) + { + cout << "SSL Cipher: " << data << endl; + EXPECT_TRUE(data_len > 1); + } } mysqlx_session_close(local_sess); From ca755a6998888602fa56d16e8d87fcd4ea5e04dd Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 24 Feb 2017 09:39:40 +0100 Subject: [PATCH 68/79] Add IPv6 session test. --- devapi/tests/session-t.cc | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 9aca45128..52dc4ae2c 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -353,6 +353,7 @@ TEST_F(Sess, bind_node_session) cout << "Done!" << endl; } + TEST_F(Sess, ssl_session) { @@ -525,3 +526,58 @@ TEST_F(Sess, ssl_session) } } + + +TEST_F(Sess, ipv6) +{ + + SKIP_IF_NO_XPLUGIN; + + { + mysqlx::XSession sess(SessionSettings::HOST, "::1", + SessionSettings::PORT, get_port(), + SessionSettings::USER, get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false); + } + + //Using URI + + std::stringstream uri; + + uri << "mysqlx://" << get_user(); + + if (get_password() && *get_password()) + uri << ":"<< get_password(); + + uri << "@" << "[::1]:" << get_port(); + + //URI without ssl_enable + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + } + + //Enable SSL + uri << "/?ssl-enable"; + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } +} From 97a65477d2659c2ef40955cc19f7aa30676ad6a9 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 28 Feb 2017 18:38:09 +0100 Subject: [PATCH 69/79] WL#10037 (View DDL) Documenttion. --- include/mysql_devapi.h | 102 +++++++--- include/mysql_xapi.h | 416 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 473 insertions(+), 45 deletions(-) diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 54327ad29..c468c651c 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -162,26 +162,37 @@ class PUBLIC_API DatabaseObject /** - View creation and alter classes - */ + Check options for an updatable view. + @see https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html +*/ enum class CheckOption { - CASCADED, - LOCAL + CASCADED, //!< cascaded + LOCAL //!< local }; +/** + Algorithms used to process views. + @see https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html +*/ + enum class Algorithm { - UNDEFINED, - MERGE, - TEMPTABLE + UNDEFINED, //!< undefined + MERGE, //!< merge + TEMPTABLE //!< temptable }; +/** + View security settings. + @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html +*/ + enum class SQLSecurity { - DEFINER, - INVOKER + DEFINER, //!< definer + INVOKER //!< invoker }; @@ -224,8 +235,12 @@ class ViewCheckOpt public: /** - Set constraints on the View. + Specify checks that are done upon insertion of rows into an updatable + view. + + @see https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html */ + Executable withCheckOption(CheckOption option) { get_impl()->with_check_option(option); @@ -233,9 +248,10 @@ class ViewCheckOpt } }; + template class ViewDefinedAs -: protected ViewCheckOpt +: public ViewCheckOpt { protected: @@ -243,24 +259,34 @@ class ViewDefinedAs public: - /** - Define the table select statement to generate the View. - */ - + ///@{ + // TODO: How to copy documentation here? ViewCheckOpt definedAs(TableSelect&& table) { get_impl()->defined_as(std::move(table)); return std::move(*this); } + /** + Specify table select operation for which the view is created. + + @note In situations where select statement is modified after + passing it to definedAs() method, later changes do not afffect + view definition which uses the state of the statement at the time + of definedAs() call. + */ + ViewCheckOpt definedAs(const TableSelect& table) { TableSelect table_tmp(table); get_impl()->defined_as(std::move(table_tmp)); return std::move(*this); } + + ///@} }; + template class ViewDefiner : public ViewDefinedAs @@ -272,7 +298,12 @@ class ViewDefiner public: /** - Define the View’s definer. + Specify definer of a view. + + The definer is used to determine access rights for the view. It is specified + as a valid MySQL account name of the form "user@host". + + @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html */ ViewDefinedAs definer(const string &user) { @@ -281,6 +312,7 @@ class ViewDefiner } }; + template class ViewSecurity : public ViewDefiner @@ -292,8 +324,11 @@ class ViewSecurity public: /** - Define the View’s security scheme. + Specify security characteristisc of a view. + + @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html */ + ViewDefiner security(SQLSecurity sec) { get_impl()->security(sec); @@ -301,6 +336,7 @@ class ViewSecurity } }; + template class ViewAlgorithm : public ViewSecurity @@ -312,7 +348,9 @@ class ViewAlgorithm public: /** - define the View’s algorithm. + Specify algorithm used to process the view. + + @see https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html */ ViewSecurity algorithm(Algorithm alg) @@ -365,7 +403,7 @@ class View_base /** Define the column names of the created/altered View. - */ + */ template ViewAlgorithm columns(const T&...names) @@ -386,7 +424,12 @@ class View_base } // namespace internal /** - The ViewCreate class represents the creation of a view + Represents an operation which creates a view. + + The query for which the view is created must be specified with + `definedAs()` method. Other methods can specify different view creation + options. When operation is fully specified, it can be executed with + a call to `execute()`. */ class PUBLIC_API ViewCreate @@ -403,7 +446,11 @@ class PUBLIC_API ViewCreate /** - The ViewCreate class represents the creation of a view + Represents an operation which modifies an existing view. + + ViewAlter operation must specify new query for the view with + `definedAs()` method (it is not possible to change other characteristics + of a view without changing its query). */ class PUBLIC_API ViewAlter @@ -421,11 +468,8 @@ class PUBLIC_API ViewAlter namespace internal { -/* - View drop classes -*/ -struct ViewDrop_impl + struct ViewDrop_impl : public Executable_impl { virtual void if_exists() = 0; @@ -449,6 +493,11 @@ class ViewDropIfExists public: + /** + Modify drop view operation so that it checks existence of the view + before dropping it. + */ + Executable ifExists() { get_impl()->if_exists(); @@ -458,8 +507,9 @@ class ViewDropIfExists } // namespace internal + /** - The ViewDrop class represents the drop of a view + Represents an operation which drops a view. */ class PUBLIC_API ViewDrop diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 6114d0d3a..782c9a473 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -350,38 +350,42 @@ mysqlx_opt_type_t; /** Constants for defining the View algorithm using mysqlx_set_view_algorithm() function. + @see https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html */ typedef enum mysqlx_view_algorithm_enum { - VIEW_ALGORITHM_UNDEFINED = 0, - VIEW_ALGORITHM_MERGE = 1, - VIEW_ALGORITHM_TEMPTABLE = 2 -}mysqlx_view_algorithm_t; + VIEW_ALGORITHM_UNDEFINED = 0, /**< Undefined view algorithm */ + VIEW_ALGORITHM_MERGE = 1, /**< Merge view algorithm */ + VIEW_ALGORITHM_TEMPTABLE = 2 /**< Temptable view algorithm */ +} mysqlx_view_algorithm_t; /** Constants for defining the View security using mysqlx_set_view_security() function. + @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html */ typedef enum mysqlx_view_security_enum { - VIEW_SECURITY_DEFINER = 1, - VIEW_SECURITY_INVOKER = 2 -}mysqlx_view_security_t; + VIEW_SECURITY_DEFINER = 1, /**< Definer view security context */ + VIEW_SECURITY_INVOKER = 2 /**< Invoker view security context */ +} mysqlx_view_security_t; /** Constants for defining the View check options mysqlx_set_view_security() function. + @see https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html */ typedef enum mysqlx_view_check_option_enum { - VIEW_CHECK_OPTION_CASCADED = 1, - VIEW_CHECK_OPTION_LOCAL = 2 -}mysqlx_view_check_option_t; + VIEW_CHECK_OPTION_CASCADED = 1, /**< Cascaded view check option */ + VIEW_CHECK_OPTION_LOCAL = 2 /**< Local view check option */ +} mysqlx_view_check_option_t; + /* ==================================================================== @@ -2806,54 +2810,428 @@ PUBLIC_API unsigned int mysqlx_result_warning_count(mysqlx_result_t *res); PUBLIC_API mysqlx_error_t * mysqlx_result_next_warning(mysqlx_result_t *res); + #define VIEW_OPTION_ALGORITHM 100 #define VIEW_OPTION_SECURITY 101 #define VIEW_OPTION_CHECK_OPTION 102 #define VIEW_OPTION_DEFINER 103 #define VIEW_OPTION_COLUMNS 104 +/** @name Macros used to declare view attributes */ +/**@{*/ + +/** + Specify algorithm to be used for view processing. + @see `mysqlx_view_algorithm_t` +*/ #define VIEW_ALGORITHM(A) (void*)VIEW_OPTION_ALGORITHM, A + +/** + Specify view security context. + @see `mysqlx_view_security_t` +*/ #define VIEW_SECURITY(S) (void*)VIEW_OPTION_SECURITY, S -#define VIEW_CHECK_OPTION(C) (void*)VIEW_OPTION_CHECK_OPTION, C + +/** + Specify definer of a view. + + The definer is used to determine access rights for the view. It is specified + as a valid MySQL account name of the form "user@host". + + @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html +*/ #define VIEW_DEFINER(D) (void*)VIEW_OPTION_DEFINER, D + +/** + Specify checks to be performed for an updatable view. + @see `mysqlx_view_check_option_t` +*/ +#define VIEW_CHECK_OPTION(C) (void*)VIEW_OPTION_CHECK_OPTION, C + +/** + Specify names for view columns. + + The number of column names must match the number of columns of view's + query. +*/ #define VIEW_COLUMNS(...) (void*)VIEW_OPTION_COLUMNS, __VA_ARGS__ -PUBLIC_API mysqlx_stmt_t * -mysqlx_view_create_new(mysqlx_schema_t *schema, const char *name, - mysqlx_stmt_t *select_stmt); +/**@}*/ + + +/** + Create a new View + + Creates a new View in a given schema based on a previously + defined select statement. + + An attempt to call this function if a view with a specified name + already exists will result in an error. + + @param schema schema handle + + @param name view name + + @param select_stmt statement representing a table select query + which will be used for the view (see `mysqlx_table_select_new()`) + + @param ... variable list of view definition options terminated by `PARAM_END`. + Each option starts with a `VIEW_OPTION_X` constant followed + by option's value(s). See below for more details. + + @return handle containing the result of the view create operation or + NULL if an error has happened. This result can be used to examine + reported warnings, if any. + + There are convenience macros `VIEW_ALGORITHM()`, `VIEW_SECURITY()`, + `VIEW_CHECK_OPTION()`, `VIEW_DEFINER()` and `VIEW_COLUMNS()`which can be used + to specify view options. For instance: + ~~~~~~ + mysqlx_view_create(schema, "view_1", select_stmt, + VIEW_DEFINER("root"), + VIEW_ALGORITHM(VIEW_ALGORITHM_TEMPTABLE), + VIEW_COLUMNS("col_1", "col_2"), PARAM_END); + ~~~~~~ + The order of parameters in the list is not fixed, but if + `VIEW_COLUMNS()` (`VIEW_OPTION_COLUMNS`) is used it must be the + last parameter before terminating the list with `PARAM_END`. See documentation + of the convenience macros for more details on possible vuew definition + options + + + @note In case of error the error details can be obtained from the schema + object using `mysqlx_error()` or `mysqlx_error_message()`. + + @ingroup xapi_ddl +*/ PUBLIC_API mysqlx_result_t * mysqlx_view_create(mysqlx_schema_t *schema, const char *name, mysqlx_stmt_t *select_stmt, ...); + +/** + Return a new statement which careates a view + + Creates a statement which will be used for creating a new view + in a given schema based on a previously defined select statement. Before + executing this statement with `mysqlx_execute()` additional view options + can be specified using `mysqlx_set_view_x()` family of functions. + + An attempt to execute the returned statement if a view with a specified name + already exists will result in an error. + + @param schema schema handle + + @param name view name + + @param select_stmt statement representing a table select query + which will be used for the view (see `mysqlx_table_select_new()`) + + @return statement handle for view create operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the statement, the returned handle has to be + given to `mysqlx_execute()`. + + @note In case of error the error details can be obtained from the schema + object using `mysqlx_error()` or `mysqlx_error_message()`. + + @note Changing the select statement after the `mysqlx_view_create_new()` + call has no effect on the returned view create statement, which uses + the state of the select statement at the time of the + `mysqlx_view_create_new()` call. + + @see `mysqlx_set_view_algorithm()`, `mysqlx_set_view_security()`, + `mysqlx_set_view_check_option()`, `mysqlx_set_view_definer()`, + `mysqlx_set_view_columns()` + + @ingroup xapi_ddl +*/ + PUBLIC_API mysqlx_stmt_t * -mysqlx_view_modify_new(mysqlx_schema_t *schema, const char *name, +mysqlx_view_create_new(mysqlx_schema_t *schema, const char *name, mysqlx_stmt_t *select_stmt); + +/** + Modify an existing view + + Modifies a view in a given schema based on a previously defined select + statement. + + An attempt to call this function if a view with the specified name + does not exist will result in an error. + + @param schema schema handle + + @param name view name + + @param select_stmt statement representing a table select query + which will be used for the view (see `mysqlx_table_select_new()`) + + @param ... variable list of view definition options terminated by `PARAM_END`. + Each option starts with a `VIEW_OPTION_X` constant followed + by option's value(s). See `mysqlx_view_create()` for more details + on how view options are specified. + + @return handle containing result of view modify operation or NULL if an error + has happened. This result can be used to examine + reported warnings, if any. + + @note In case of error the error details can be obtained from the schema + object using `mysqlx_error()` or `mysqlx_error_message()`. + + @note A new select statement must be specified when updating a view. It is not + possible to change other view options without changing the main query. + + @ingroup xapi_ddl +*/ + PUBLIC_API mysqlx_result_t * mysqlx_view_modify(mysqlx_schema_t *schema, const char *name, mysqlx_stmt_t *select_stmt, ...); + +/** + Return a new statement which modifies an existing view + + Creates a statement which will modify an existing view in a given schema + based on a previously defined select statement. Before + executing this statement with `mysqlx_execute()` additional view options + can be specified using `mysqlx_set_view_x()` family of functions. + + An attempt to execute the returned statement if a view with a specified name + does not exist will result in an error. + + @param schema schema handle + + @param name view name + + @param select_stmt statement representing a table select query + which will be used for the view (see `mysqlx_table_select_new()`) + + @return statement handle for view modify operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the statement, the returned handle has to be + given to `mysqlx_execute()`. + + @note In case of error the error details can be obtained from the schema + object using `mysqlx_error()` or `mysqlx_error_message()`. + + @note Changing the select statement after the `mysqlx_view_modify_new()` + call has no effect on the returned view modify statement, which uses + the state of the select statement at the time of the + `mysqlx_view_modify_new()` call. + + @see `mysqlx_set_view_algorithm()`, `mysqlx_set_view_security()`, + `mysqlx_set_view_check_option()`, `mysqlx_set_view_definer()`, + `mysqlx_set_view_columns()` + + @ingroup xapi_ddl +*/ + PUBLIC_API mysqlx_stmt_t * -mysqlx_view_replace_new(mysqlx_schema_t *schema, const char *name, - mysqlx_stmt_t *select_stmt); +mysqlx_view_modify_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt); + + +/** + Modify an existing view or create a new one + + Modifies an existing view or creates a new one in a given schema + based on a previously defined select statement. + + @param schema schema handle + + @param name view name + + @param select_stmt statement representing a table select query + which will be used for the view (see `mysqlx_table_select_new()`) + + @param ... variable list of view definition options terminated by `PARAM_END`. + Each option starts with a `VIEW_OPTION_X` constant followed + by option's value(s). See `mysqlx_view_create()` for more details + on how view options are specified. + + @return handle containing result of view replace operation or + NULL if the error has happened. This result can be used to examine + reported warnings, if any. + + @note In case of error the error details can be obtained from the schema + object using `mysqlx_error()` or `mysqlx_error_message()`. + + @ingroup xapi_ddl +*/ PUBLIC_API mysqlx_result_t * mysqlx_view_replace(mysqlx_schema_t *schema, const char *name, mysqlx_stmt_t *select_stmt, ...); + +/** + Return a new statement which modifies an existing view or creates a new one + + Creates a statement which will create or modify an existing view in the given + schema based on a previously defined select statement. Before + executing this statement with `mysqlx_execute()` additional view options + can be specified using `mysqlx_set_view_x()` family of functions. + + @param schema schema handle + + @param name view name + + @param select_stmt statement representing a table select query + which will be used for the view (see `mysqlx_table_select_new()`) + + @return statement handle for view replace operation. + NULL can be returned only in case when there are problems + allocating memory, which normally should not happen. + It is very unlikely for this function to end with the error + because it does not do any parsing, parameters checking etc. + + @note To actually execute the statement, the returned handle has to be + given to `mysqlx_execute()`. + + @note In case of error the error details can be obtained from the schema + object using `mysqlx_error()` or `mysqlx_error_message()`. + + @note Changing the select statement after the `mysqlx_view_replace_new()` + call has no effect on the returned view replace statement, which uses + the state of the select statement at the time of the + `mysqlx_view_replace_new()` call. + + @see `mysqlx_set_view_algorithm()`, `mysqlx_set_view_security()`, + `mysqlx_set_view_check_option()`, `mysqlx_set_view_definer()`, + `mysqlx_set_view_columns()` + + @ingroup xapi_ddl +*/ + +PUBLIC_API mysqlx_stmt_t * +mysqlx_view_replace_new(mysqlx_schema_t *schema, const char *name, + mysqlx_stmt_t *select_stmt); + + +/** + Set an algorithm for a view + + @param view_stmt view statement handle + + @param algorithm a `mysqlx_view_algorithm_t` constant specifying + the algorithm. + + @return RESULT_OK if a call was successful, RESULT_ERROR otherwise + + @note In case of error the error details can be obtained from the + view statement object using `mysqlx_error()` or + `mysqlx_error_message()`. + + @see `mysqlx_view_algorithm_t` + + @ingroup xapi_ddl +*/ + PUBLIC_API int mysqlx_set_view_algorithm(mysqlx_stmt_t *view_stmt, int algorithm); + +/** + Set a security context for a view + + @param view_stmt view statement handle + + @param security a `mysqlx_view_security_t` constant specifying the security + context. + + @return RESULT_OK if a call was successful, RESULT_ERROR otherwise + + @note In case of error the error details can be obtained from the + view statement object using `mysqlx_error()` or + `mysqlx_error_message()`. + + @see `mysqlx_view_security_t` + + @ingroup xapi_ddl +*/ + PUBLIC_API int mysqlx_set_view_security(mysqlx_stmt_t *view_stmt, int security); -PUBLIC_API int -mysqlx_set_view_check_option(mysqlx_stmt_t *view_stmt, int option); + +/** + Set a definer for a view + + @param view_stmt view statement handle + + @param user a valid MySQL account name of the form "user@host" + + @return RESULT_OK if a call was successful, RESULT_ERROR otherwise + + @note In case of error the error details can be obtained from the + view statement object using `mysqlx_error()` or + `mysqlx_error_message()`. + + @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + + @ingroup xapi_ddl +*/ PUBLIC_API int mysqlx_set_view_definer(mysqlx_stmt_t *view_stmt, const char *user); + +/** + Set a check option for a view + + @param view_stmt view statement handle + + @param option a `mysqlx_view_check_option_t` constant specifying the + check option + + @return RESULT_OK if a call was successful, RESULT_ERROR otherwise + + @note In case of error the error details can be obtained from the + view statement object using `mysqlx_error()` or + `mysqlx_error_message()`. + + @see `mysqlx_view_check_option_t` + + @ingroup xapi_ddl +*/ + +PUBLIC_API int +mysqlx_set_view_check_option(mysqlx_stmt_t *view_stmt, int option); + + +/** + Set column names for a view + + @param view_stmt view statement handle + + @param ... variable parameters list containing strings that specify + the column names for a View. The list has to be terminated + by PARAM_END + + @return RESULT_OK if a call was successful, RESULT_ERROR otherwise + + @note In case of error the error details can be obtained from the + view statement object using `mysqlx_error()` or + `mysqlx_error_message()`. + + @note The number of column names must match the number of columns of + view's query. + + @ingroup xapi_ddl +*/ + PUBLIC_API int mysqlx_set_view_columns(mysqlx_stmt_t *view_stmt, ...); From 5543cf4fca9be44a462a67cb2d24afe8822d3cc6 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 2 Mar 2017 15:12:48 +0100 Subject: [PATCH 70/79] WL#9970 (Core SSL options) Documentation. --- include/mysql_devapi.h | 147 +++++++++++++++++++++++++++++++++-------- include/mysql_xapi.h | 35 ++++++---- 2 files changed, 139 insertions(+), 43 deletions(-) diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index c468c651c..3bc63e00f 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -271,7 +271,7 @@ class ViewDefinedAs Specify table select operation for which the view is created. @note In situations where select statement is modified after - passing it to definedAs() method, later changes do not afffect + passing it to definedAs() method, later changes do not affect view definition which uses the state of the statement at the time of definedAs() call. */ @@ -324,7 +324,7 @@ class ViewSecurity public: /** - Specify security characteristisc of a view. + Specify security characteristics of a view. @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html */ @@ -363,8 +363,9 @@ class ViewAlgorithm /* - Base blass for Create/Alter View + Base class for Create/Alter View */ + template class View_base : public ViewAlgorithm @@ -887,9 +888,27 @@ class PUBLIC_API Table Represents session options to be passed at XSession/NodeSession object creation. - SessionSettings can be constructed using uri, common connect options (host, - port, user, password, database) or using pairs of SessionSettings::Options - - Value objects. + SessionSettings can be constructed using URL string, common connect options + (host, port, user, password, database) or with a list + of `SessionSettings::Options` constants followed by option value (unless + given option has no value, like `SSL_ENABLE`). + + Examples: + ~~~~~~ + + SessionSettings from_url("mysqlx://user:pwd@host:port/db?ssl-enable"); + + SessionSettings from_options("host", port, "user", "pwd", "db"); + + SessionSettings from_option_list( + SessionSettings::USER, "user", + SessionSettings::PWD, "pwd", + SessionSettings::HOST, "host", + SessionSettings::PORT, port, + SessionSettings::DB, "db", + SessionSettings::SSL_ENABLE + ); + ~~~~~~ @ingroup devapi */ @@ -897,16 +916,23 @@ class PUBLIC_API Table class PUBLIC_API SessionSettings { public: + + /** + Session creation options + + @note Specifying `SSL_CA` option implies `SSL_ENABLE`. + */ + enum Options { - URI, - HOST, - PORT, - USER, - PWD, - DB, - SSL_ENABLE, - SSL_CA + URI, //!< connection URI or string + HOST, //!< host name or IP address + PORT, //!< X Plugin port to connect to + USER, //!< user name + PWD, //!< password + DB, //!< default database + SSL_ENABLE, //!< use TLS connection + SSL_CA //!< path to a PEM file specifying trusted root certificates }; @@ -922,6 +948,19 @@ class PUBLIC_API SessionSettings {} + /** + Create a session using connection string or URL. + + Connection sting has the form `"user:pass\@host:port/?option&option"`, + valid URL is like a connection string with a `mysqlx://` prefix. Possible + connection options are: + + - `ssl-enable` : use TLS connection + - `ssl-ca=` : path to a PEM file specifying trusted root certificates + + Specifying `ssl-ca` option implies `ssl-enable`. + */ + SessionSettings(const string &uri) { add(URI, uri); @@ -930,6 +969,9 @@ class PUBLIC_API SessionSettings /** Create session explicitly specifying session parameters. + + @note Session settings constructed this way request an SSL connection + by default. */ SessionSettings(const std::string &host, unsigned port, @@ -956,9 +998,12 @@ class PUBLIC_API SessionSettings : SessionSettings(host, port, user, pwd.c_str(), db) {} - /** - Create session using the default port - */ + /** + Create session using the default port + + @note Session settings constructed this way request an SSL connection + by default. + */ SessionSettings(const std::string &host, const string &user, @@ -974,9 +1019,12 @@ class PUBLIC_API SessionSettings : SessionSettings(host, DEFAULT_MYSQLX_PORT, user, pwd, db) {} - /** - Create session on localhost. - */ + /** + Create session on localhost. + + @note Session settings constructed this way request an SSL connection + by default. + */ SessionSettings(unsigned port, const string &user, @@ -1054,7 +1102,25 @@ class PUBLIC_API SessionSettings /** - Passing option - value pairs + Create session using a list of session options. + + The list of options consist of `SessionSettings::Options` constant + identifying the option to set, followed by option value (unless + not required, as in the case of `SSL_ENABLE`). + + Example: + ~~~~~~ + SessionSettings from_option_list( + SessionSettings::USER, "user", + SessionSettings::PWD, "pwd", + SessionSettings::HOST, "host", + SessionSettings::PORT, port, + SessionSettings::DB, "db", + SessionSettings::SSL_ENABLE + ); + ~~~~~~ + + @see `SessionSettings::Options`. */ template @@ -1155,14 +1221,6 @@ namespace internal { public: - /** - Create session specified by mysqlx connection string. - - Connection string can be either an utf8 encoded single-byte - string or a wide string (which is converted to utf8 before - parsing). - */ - XSession_base(SessionSettings settings); template @@ -1303,11 +1361,42 @@ class PUBLIC_API XSession public: + /** + Create session specified by `SessionSettings` object. + */ + XSession(SessionSettings settings) : XSession_base(settings) {} + /** + Create session using given session settings. + + This constructor forwards arguments to a `SessionSettings` constructor. + Thus all forms of specifying session options are also directly available + in `XSession` constructor. + + Examples: + ~~~~~~ + + XSession from_uri("mysqlx://user:pwd@host:port/db?ssl-enable"); + + XSession from_options("host", port, "user", "pwd", "db"); + + XSession from_option_list( + SessionSettings::USER, "user", + SessionSettings::PWD, "pwd", + SessionSettings::HOST, "host", + SessionSettings::PORT, port, + SessionSettings::DB, "db", + SessionSettings::SSL_ENABLE + ); + ~~~~~~ + + @see `SessionSettings` + */ + template XSession(T...options) : XSession_base(SessionSettings(options...)) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 782c9a473..c280ac26f 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -106,7 +106,7 @@ typedef object_id* MYSQLX_GUID; /** Return value flag indicating that the last reading operation did not finish reading to the end and there is still more data - to be fetched by functions suchs as mysqlx_get_bytes() + to be fetched by functions such as mysqlx_get_bytes() */ #define RESULT_MORE_DATA 8 @@ -331,17 +331,18 @@ typedef enum mysqlx_sort_direction_enum Session options for use with `mysqlx_session_option_get()` and `mysqlx_session_option_set()` functions. - TODO: Document the options and what data they expect + @note Specifying `MYSQLX_OPT_SSL_CA` option implies `MYSQLX_OPT_SSL_ENABLE`. */ typedef enum mysqlx_opt_type_enum { - MYSQLX_OPT_HOST = 1, - MYSQLX_OPT_PORT = 2, - MYSQLX_OPT_USER = 3, - MYSQLX_OPT_PWD = 4, - MYSQLX_OPT_DB = 5, - MYSQLX_OPT_SSL_ENABLE = 6, + MYSQLX_OPT_HOST = 1, /**< host name or IP address */ + MYSQLX_OPT_PORT = 2, /**< X Plugin port to connect to */ + MYSQLX_OPT_USER = 3, /**< user name */ + MYSQLX_OPT_PWD = 4, /**< password */ + MYSQLX_OPT_DB = 5, /**< default database */ + MYSQLX_OPT_SSL_ENABLE = 6, /**< use TLS connection */ + /** path to a PEM file specifying trusted root certificates */ MYSQLX_OPT_SSL_CA = 7, } mysqlx_opt_type_t; @@ -427,13 +428,19 @@ mysqlx_get_session(const char *host, int port, const char *user, /** Create a session using connection string or URL. - Connection sting has the form `"user:pass\@host:port/?option"`, valid URL - is like a connection string with a `mysqlx://` prefix. + Connection sting has the form `"user:pass\@host:port/?option&option"`, + valid URL is like a connection string with a `mysqlx://` prefix. Possible + connection options are: - @param conn_string character connection string + - `ssl-enable` : use TLS connection + - `ssl-ca=` : path to a PEM file specifying trusted root certificates + + Specifying `ssl-ca` option implies `ssl-enable`. + + @param conn_string connection string @param[out] out_error if error happens during connect the error message is returned through this parameter - @param[out] err_code if error happens during connect the error code + @param[out] err_code if error happens during connect the error code is returned through this parameter @return session handle if session could be created, otherwise NULL @@ -2895,7 +2902,7 @@ mysqlx_result_next_warning(mysqlx_result_t *res); The order of parameters in the list is not fixed, but if `VIEW_COLUMNS()` (`VIEW_OPTION_COLUMNS`) is used it must be the last parameter before terminating the list with `PARAM_END`. See documentation - of the convenience macros for more details on possible vuew definition + of the convenience macros for more details on possible view definition options @@ -2911,7 +2918,7 @@ mysqlx_view_create(mysqlx_schema_t *schema, const char *name, /** - Return a new statement which careates a view + Return a new statement which creates a view Creates a statement which will be used for creating a new view in a given schema based on a previously defined select statement. Before From 7f875c799ad66ec899933877954df20cfc501a93 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 2 Mar 2017 15:42:20 +0100 Subject: [PATCH 71/79] WL#10077 (IPv6 support) Documentation. --- include/mysql_devapi.h | 10 +++++++--- include/mysql_xapi.h | 20 +++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 3bc63e00f..e88201a00 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -926,7 +926,8 @@ class PUBLIC_API SessionSettings enum Options { URI, //!< connection URI or string - HOST, //!< host name or IP address + //! DNS name of the host, IPv4 address or IPv6 address + HOST, PORT, //!< X Plugin port to connect to USER, //!< user name PWD, //!< password @@ -952,8 +953,11 @@ class PUBLIC_API SessionSettings Create a session using connection string or URL. Connection sting has the form `"user:pass\@host:port/?option&option"`, - valid URL is like a connection string with a `mysqlx://` prefix. Possible - connection options are: + valid URL is like a connection string with a `mysqlx://` prefix. Host is + specified as either DNS name, IPv4 address of the form "nn.nn.nn.nn" or + IPv6 address of the form "[nn:nn:nn:...]". + + Possible connection options are: - `ssl-enable` : use TLS connection - `ssl-ca=` : path to a PEM file specifying trusted root certificates diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index c280ac26f..4a7be9f75 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -337,7 +337,8 @@ typedef enum mysqlx_sort_direction_enum typedef enum mysqlx_opt_type_enum { MYSQLX_OPT_HOST = 1, /**< host name or IP address */ - MYSQLX_OPT_PORT = 2, /**< X Plugin port to connect to */ + /** DNS name of the host, IPv4 address or IPv6 address */ + MYSQLX_OPT_PORT = 2, MYSQLX_OPT_USER = 3, /**< user name */ MYSQLX_OPT_PWD = 4, /**< password */ MYSQLX_OPT_DB = 5, /**< default database */ @@ -397,7 +398,7 @@ typedef enum mysqlx_view_check_option_enum /** Create a new session. - @param host server host address + @param host server host DNS name, IPv4 address or IPv6 address @param port port number @param user user name @param password password @@ -429,8 +430,11 @@ mysqlx_get_session(const char *host, int port, const char *user, Create a session using connection string or URL. Connection sting has the form `"user:pass\@host:port/?option&option"`, - valid URL is like a connection string with a `mysqlx://` prefix. Possible - connection options are: + valid URL is like a connection string with a `mysqlx://` prefix. Host is + specified as either DNS name, IPv4 address of the form "nn.nn.nn.nn" or + IPv6 address of the form "[nn:nn:nn:...]". + + Possible connection options are: - `ssl-enable` : use TLS connection - `ssl-ca=` : path to a PEM file specifying trusted root certificates @@ -489,7 +493,7 @@ mysqlx_get_session_from_options(mysqlx_session_options_t *opt, A node session connects only to one mysqld node at a time. - @param host server host address + @param host server host DNS name, IPv4 address or IPv6 address @param port port number @param user user name @param password password @@ -520,8 +524,8 @@ mysqlx_get_node_session(const char *host, int port, const char *user, /** Create a node session using connection string or URL. - Connection sting has the form `"user:pass\@host:port"`, valid URL - is like a connection string with `mysqlx://` prefix. + See `mysqlx_get_session_from_url()` for information on connection string + format. A node session connects only to one mysqld node at a time. @@ -540,6 +544,8 @@ mysqlx_get_node_session(const char *host, int port, const char *user, @note This type of session supports executing plain SQL queries + @see `mysqlx_get_session_from_url()` + @ingroup xapi_sess */ From 55db1c5d186c8b1bb150df43dc821aa2662b8721 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 2 Mar 2017 18:21:24 +0100 Subject: [PATCH 72/79] WL#10008 (Document UUIDs) Documentation. --- include/devapi/collection_crud.h | 20 +++++++++++++++++++- include/mysql_devapi.h | 10 +++++++++- include/mysql_xapi.h | 16 +++++++++++++--- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/devapi/collection_crud.h b/include/devapi/collection_crud.h index 384470c44..a99e30e13 100644 --- a/include/devapi/collection_crud.h +++ b/include/devapi/collection_crud.h @@ -201,15 +201,17 @@ namespace internal { Class which defines various variants of `add()` method. This class defines `add()` methods that append new documents to the - list of documents that should be inserted by a CollectionAdd operation. + list of documents that should be inserted by a `CollectionAdd` operation. Documents can be specified as JSON strings or DbDoc instances. Several documents can be added in a single call to `add()`. + @cond IGNORE Template is parametrized by return type of the `add()` method which is different in case of `CollectionAddBase` and `CollcetionAdd`. This return type is either `CollectionAdd` or reference to `CollectionAdd`, respectively. In either case `CollectionAdd::do_add()` method is used to append documents to the list. + @endcond */ template @@ -341,10 +343,26 @@ namespace internal { /** Operation which adds documents to a collection. + Documents to be added by this operation are specified with various variants + of `add()` method. + + Each document must have a unique identifier which is stored in `_id` + filed of the document. Document identifiers are character strings no longer + than 32 characters. If added document does not have `_id` field, a unique + identifier will be generated for it. Document identifier generated by given + collection add operation can be examined using `Result::getDocumentIds()` + method. Generated document identifiers are string of 32 hexadecimal digits, + like this one `0512020981044082E6119DFA0E4C0584`. + + @note Generated document identifiers are based on UUIDs but they are not + valid UUIDs (fields are reversed). + + @cond IGNORE The various `add()` methods defined by `CollectionAddInterface` call `do_add()` to append documents to the list one by one. This method, in turn, passes these documents to the internal implementation object. + @endcond @ingroup devapi_op */ diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index e88201a00..839fa94c5 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -960,7 +960,7 @@ class PUBLIC_API SessionSettings Possible connection options are: - `ssl-enable` : use TLS connection - - `ssl-ca=` : path to a PEM file specifying trusted root certificates + - `ssl-ca=`path : path to a PEM file specifying trusted root certificates Specifying `ssl-ca` option implies `ssl-enable`. */ @@ -1254,8 +1254,16 @@ namespace internal { Schema getSchema(const string&, bool check_existence = false); + /** + Get the default schema specified when session was created. + */ + Schema getDefaultSchema(); + /** + Get the name of the default schema specified when session was created. + */ + string getDefaultSchemaName(); /** diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 4a7be9f75..8fb1c1067 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -437,7 +437,7 @@ mysqlx_get_session(const char *host, int port, const char *user, Possible connection options are: - `ssl-enable` : use TLS connection - - `ssl-ca=` : path to a PEM file specifying trusted root certificates + - `ssl-ca=`path : path to a PEM file specifying trusted root certificates Specifying `ssl-ca` option implies `ssl-enable`. @@ -1024,8 +1024,18 @@ mysqlx_collection_find(mysqlx_collection_t *collection, const char *criteria); NULL is returned only in case of an error. The error details can be obtained using `mysqlx_error()` function - @see `mysqlx_collection_add_new()` for additional information about - adding documents to a collection. + Each document must have a unique identifier which is stored in `_id` + filed of the document. Document identifiers are character strings no longer + than 32 characters. If added document does not have `_id` field, a unique + identifier will be generated for it. Document identifier generated by given + collection add operation can be examined using `mysqlx_fetch_doc_id()` + function. Generated document identifiers are strings of 32 hexadecimal digits, + like this one `0512020981044082E6119DFA0E4C0584`. + + @note Generated document identifiers are based on UUIDs but they are not + valid UUIDs (fields are reversed). + + @see `mysqlx_collection_add_new()` @ingroup xapi_coll */ From d68c2b0a16d380221128d7b92b874c02ded293bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Mon, 6 Mar 2017 12:14:55 +0000 Subject: [PATCH 73/79] Update to version 2.0.4 --- version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.cmake b/version.cmake index 17c562a56..8bd5fc499 100644 --- a/version.cmake +++ b/version.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. # # The MySQL Connector/C++ is licensed under the terms of the GPLv2 # , like most @@ -28,7 +28,7 @@ set(API_VERSION "${API_VERSION_MAJOR}.${API_VERSION_MINOR}") set(CONCPP_VERSION_MAJOR 2) set(CONCPP_VERSION_MINOR 0) -set(CONCPP_VERSION_MICRO 3) +set(CONCPP_VERSION_MICRO 4) # Level is "-alpha", "-beta", empty if GA set(CONCPP_VERSION_LEVEL "") From a63696918a904f55673ea59e0f6d7811f15dc269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Wed, 8 Mar 2017 11:24:54 +0000 Subject: [PATCH 74/79] Update README.txt year --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 04545932f..fd2d5d8a9 100644 --- a/README.txt +++ b/README.txt @@ -7,7 +7,7 @@ copy of the software is released under the version 2 of the GNU General Public License. MySQL Connector/C++ is brought to you by Oracle. -Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. License information can be found in the COPYING file. From 01895c004ed82e137d246f318e7627792d18f0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Silva?= Date: Tue, 14 Mar 2017 14:59:57 +0000 Subject: [PATCH 75/79] Bump version file on docs --- doc/doxygen.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg index 9d4543ac0..40d3e5c69 100644 --- a/doc/doxygen.cfg +++ b/doc/doxygen.cfg @@ -60,7 +60,7 @@ PROJECT_NAME = "MySQL Connector/C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 2.0.3 +PROJECT_NUMBER = 2.0.4 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 1956bfcab04b3a558d3eed58397991d85ccf4526 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 14 Mar 2017 16:46:51 +0100 Subject: [PATCH 76/79] Docs: post-review fixes. --- include/devapi/collection_crud.h | 2 +- include/mysql_devapi.h | 14 ++++---- include/mysql_xapi.h | 58 ++++++++++++++++---------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/include/devapi/collection_crud.h b/include/devapi/collection_crud.h index a99e30e13..05d06d3be 100644 --- a/include/devapi/collection_crud.h +++ b/include/devapi/collection_crud.h @@ -347,7 +347,7 @@ namespace internal { of `add()` method. Each document must have a unique identifier which is stored in `_id` - filed of the document. Document identifiers are character strings no longer + field of the document. Document identifiers are character strings no longer than 32 characters. If added document does not have `_id` field, a unique identifier will be generated for it. Document identifier generated by given collection add operation can be examined using `Result::getDocumentIds()` diff --git a/include/mysql_devapi.h b/include/mysql_devapi.h index 839fa94c5..9eedfd068 100644 --- a/include/mysql_devapi.h +++ b/include/mysql_devapi.h @@ -163,7 +163,7 @@ class PUBLIC_API DatabaseObject /** Check options for an updatable view. - @see https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html + @see https://dev.mysql.com/doc/refman/en/view-check-option.html */ enum class CheckOption @@ -174,7 +174,7 @@ enum class CheckOption /** Algorithms used to process views. - @see https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html + @see https://dev.mysql.com/doc/refman/en/view-algorithms.html */ enum class Algorithm @@ -186,7 +186,7 @@ enum class Algorithm /** View security settings. - @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + @see https://dev.mysql.com/doc/refman/en/stored-programs-security.html */ enum class SQLSecurity @@ -238,7 +238,7 @@ class ViewCheckOpt Specify checks that are done upon insertion of rows into an updatable view. - @see https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html + @see https://dev.mysql.com/doc/refman/en/view-check-option.html */ Executable withCheckOption(CheckOption option) @@ -303,7 +303,7 @@ class ViewDefiner The definer is used to determine access rights for the view. It is specified as a valid MySQL account name of the form "user@host". - @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + @see https://dev.mysql.com/doc/refman/en/stored-programs-security.html */ ViewDefinedAs definer(const string &user) { @@ -326,7 +326,7 @@ class ViewSecurity /** Specify security characteristics of a view. - @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + @see https://dev.mysql.com/doc/refman/en/stored-programs-security.html */ ViewDefiner security(SQLSecurity sec) @@ -350,7 +350,7 @@ class ViewAlgorithm /** Specify algorithm used to process the view. - @see https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html + @see https://dev.mysql.com/doc/refman/en/view-algorithms.html */ ViewSecurity algorithm(Algorithm alg) diff --git a/include/mysql_xapi.h b/include/mysql_xapi.h index 8fb1c1067..c6d9f789a 100644 --- a/include/mysql_xapi.h +++ b/include/mysql_xapi.h @@ -352,7 +352,7 @@ mysqlx_opt_type_t; /** Constants for defining the View algorithm using mysqlx_set_view_algorithm() function. - @see https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html + @see https://dev.mysql.com/doc/refman/en/view-algorithms.html */ typedef enum mysqlx_view_algorithm_enum @@ -366,7 +366,7 @@ typedef enum mysqlx_view_algorithm_enum /** Constants for defining the View security using mysqlx_set_view_security() function. - @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + @see https://dev.mysql.com/doc/refman/en/stored-programs-security.html */ typedef enum mysqlx_view_security_enum @@ -379,7 +379,7 @@ typedef enum mysqlx_view_security_enum /** Constants for defining the View check options mysqlx_set_view_security() function. - @see https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html + @see https://dev.mysql.com/doc/refman/en/view-check-option.html */ typedef enum mysqlx_view_check_option_enum @@ -967,7 +967,7 @@ PUBLIC_API mysqlx_result_t * mysqlx_sql_param(mysqlx_session_t *sess, @return statement handle containing the results and/or error. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error + It is very unlikely for this function to end with an error because it does not do any parsing, parameter checking etc. @note To actually execute the SQL query the returned statement has to be @@ -1025,7 +1025,7 @@ mysqlx_collection_find(mysqlx_collection_t *collection, const char *criteria); can be obtained using `mysqlx_error()` function Each document must have a unique identifier which is stored in `_id` - filed of the document. Document identifiers are character strings no longer + field of the document. Document identifiers are character strings no longer than 32 characters. If added document does not have `_id` field, a unique identifier will be generated for it. Document identifier generated by given collection add operation can be examined using `mysqlx_fetch_doc_id()` @@ -1133,8 +1133,8 @@ mysqlx_collection_modify_unset(mysqlx_collection_t *collection, @return handle for the newly created FIND statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the operation, use `mysqlx_execute()`. @@ -1227,8 +1227,8 @@ A macro defining a function for setting GROUP BY for FIND operation. @return handle for the newly created ADD statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the operation, use `mysqlx_execute()` after specifying documents to be added. @@ -1277,8 +1277,8 @@ mysqlx_set_add_document(mysqlx_stmt_t *stmt, const char *json_doc); @return handle for the newly created REMOVE statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, use `mysqlx_execute()` @@ -1327,8 +1327,8 @@ mysqlx_collection_remove_new(mysqlx_collection_t *collection); @return handle for the newly created MODIFY statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, use `mysqlx_execute()` after specifying modifications that should be performed. @@ -1604,8 +1604,8 @@ mysqlx_table_update(mysqlx_table_t *table, @return handle to the newly created SELECT statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, the returned handle has to be given to `mysqlx_execute()`. @@ -1688,8 +1688,8 @@ A macro defining a function for setting GROUP BY for SELECT operation. @return statement handle for the newly created INSERT operation. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the SQL query the returned Statement has to be given to `mysqlx_execute()` @@ -1761,8 +1761,8 @@ mysqlx_set_insert_row(mysqlx_stmt_t *stmt, ...); @return handle for the newly created DELETE statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, use `mysqlx_execute()`. @@ -1812,8 +1812,8 @@ mysqlx_table_delete_new(mysqlx_table_t *table); @return handle for the newly created UPDATE statement. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, use `mysqlx_execute()` after specifying what updates should it perform. @@ -2861,7 +2861,7 @@ mysqlx_result_next_warning(mysqlx_result_t *res); The definer is used to determine access rights for the view. It is specified as a valid MySQL account name of the form "user@host". - @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + @see https://dev.mysql.com/doc/refman/en/stored-programs-security.html */ #define VIEW_DEFINER(D) (void*)VIEW_OPTION_DEFINER, D @@ -2954,8 +2954,8 @@ mysqlx_view_create(mysqlx_schema_t *schema, const char *name, @return statement handle for view create operation. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, the returned handle has to be given to `mysqlx_execute()`. @@ -3040,8 +3040,8 @@ mysqlx_view_modify(mysqlx_schema_t *schema, const char *name, @return statement handle for view modify operation. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, the returned handle has to be given to `mysqlx_execute()`. @@ -3117,8 +3117,8 @@ mysqlx_view_replace(mysqlx_schema_t *schema, const char *name, @return statement handle for view replace operation. NULL can be returned only in case when there are problems allocating memory, which normally should not happen. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. @note To actually execute the statement, the returned handle has to be given to `mysqlx_execute()`. @@ -3202,7 +3202,7 @@ mysqlx_set_view_security(mysqlx_stmt_t *view_stmt, int security); view statement object using `mysqlx_error()` or `mysqlx_error_message()`. - @see https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html + @see https://dev.mysql.com/doc/refman/en/stored-programs-security.html @ingroup xapi_ddl */ From e15daffbd8f3364a63aa33efa93fbcac80da442c Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Tue, 14 Mar 2017 16:51:15 +0100 Subject: [PATCH 77/79] Docs: fixes in non-public parts. --- cdk/core/tests/session_crud-t.cc | 2 +- cdk/include/mysql/cdk/api/processors.h | 2 +- cdk/include/mysql/cdk/charsets.h | 2 +- cdk/include/mysql/cdk/protocol/mysqlx.h | 2 +- cdk/parser/expr_parser.cc | 2 +- xapi/mysqlx.cc | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cdk/core/tests/session_crud-t.cc b/cdk/core/tests/session_crud-t.cc index 69f679ab1..7a6ce4b2c 100644 --- a/cdk/core/tests/session_crud-t.cc +++ b/cdk/core/tests/session_crud-t.cc @@ -1472,7 +1472,7 @@ CRUD_TEST_BEGIN(group_by) Note: By default sql_mode ONLY_FULL_GROUP_BY is enabled. This result in errors from queries generated by xplugin (select list refers to fields not listed in GROUP BY clause). - See: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by + See: https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_only_full_group_by */ Reply set_mode(sess.sql("set sql_mode=''")); set_mode.wait(); diff --git a/cdk/include/mysql/cdk/api/processors.h b/cdk/include/mysql/cdk/api/processors.h index b26315879..b4ca4e430 100644 --- a/cdk/include/mysql/cdk/api/processors.h +++ b/cdk/include/mysql/cdk/api/processors.h @@ -60,7 +60,7 @@ class Row_processor /* - Called before and after processing one filed within a row. The pos + Called before and after processing one field within a row. The pos parameter indicates 0-based position of the field within the row. Method field_begin() returns the amount of space available for storing field data - following field_data() calls should respect this limit. diff --git a/cdk/include/mysql/cdk/charsets.h b/cdk/include/mysql/cdk/charsets.h index 477a938bd..c1cdb861e 100644 --- a/cdk/include/mysql/cdk/charsets.h +++ b/cdk/include/mysql/cdk/charsets.h @@ -25,7 +25,7 @@ /* Lists of character sets known to CDK string codec (see codec.h). This is generally kept in sync with character sets known to the MySQL Server. - See: http://dev.mysql.com/doc/refman/5.7/en/charset-charsets.html + See: http://dev.mysql.com/doc/refman/en/charset-charsets.html Note: currently the codec can only convert utf8 strings. */ diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index 9a78f6160..d88c66a1d 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -533,7 +533,7 @@ class Protocol @param data Object defining rows/documents to be inserted. It is a sequence of tuples of expressions; each tuple in the sequence defines values of fields in a single row to be inserted (when inserting documents, - there should be just one filed with the document). + there should be just one field with the document). @param args defines values of named parameters, if any are used in the expressions of the row source object diff --git a/cdk/parser/expr_parser.cc b/cdk/parser/expr_parser.cc index bca4a9733..11464b6db 100644 --- a/cdk/parser/expr_parser.cc +++ b/cdk/parser/expr_parser.cc @@ -1261,7 +1261,7 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) /* Now we treat the identifiers "A.B" parsed by parse_schema_ident() and stored as table/schema name in m_col_ref (if any), as an initail segment - of a document filed reference and complete parsing the whole document + of a document field reference and complete parsing the whole document field. */ diff --git a/xapi/mysqlx.cc b/xapi/mysqlx.cc index c46caa259..2df5c4d01 100644 --- a/xapi/mysqlx.cc +++ b/xapi/mysqlx.cc @@ -239,8 +239,8 @@ mysqlx_get_node_session_from_url(const char *conn_string, RETURN: statement handler containing the results and/or error NULL is not supposed to be returned even in case of error. - It is very unlikely for this function to end with the error - because it does not do any parsing, parameters checking etc. + It is very unlikely for this function to end with an error + because it does not do any parsing, parameter checking etc. */ mysqlx_stmt_t * STDCALL mysqlx_sql_new(mysqlx_session_t *sess, const char *query, From 9e1e07f101cb7535e665a77b6e25fd53d4898f89 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 15 Mar 2017 09:23:19 +0100 Subject: [PATCH 78/79] Docs: Update copyright year to 2017. --- doc/building.txt | 2 +- doc/devapi_ref.txt | 2 +- doc/doxygen.cfg | 2 +- doc/doxygen.cfg.in | 2 +- doc/index.txt | 2 +- doc/usage.txt | 2 +- doc/xapi_ref.txt | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/building.txt b/doc/building.txt index 99870c1fe..0ba4ca344 100644 --- a/doc/building.txt +++ b/doc/building.txt @@ -242,7 +242,7 @@ C++ runtime library.