Details
-
Improvement
-
Status: Done
-
Medium
-
Resolution: Done
-
8.0.x
-
None
-
None
Description
In order to create a new UDF developer needs to include mysqlpp/udf_wrappers.hpp file.
#include <mysqlpp/udf_wrappers.hpp>
Developer needs to declare a class with the following requirements:
- the class must have a constructor that accepts mysqlpp::udf_context
by non-const reference. - the class must have a calculate() method that accepts mysqlpp::udf_context by const reference and returns one of the following:
- mysqlpp::udf_result_t<STRING_RESULT> (currently, ext::optional<std::string>) for STRING_RESULT UDFs
- mysqlpp::udf_result_t<REAL_RESULT> (currently, ext::optional<double>) for REAL_RESULT UDFs
- mysqlpp::udf_result_t<INT_RESULT> (currently, ext::optional<long long>) for INT_RESULT UDFs
- mysqlpp::udf_result_t<DECIMAL_RESULT> (currently, ext::optional<std::string>) for DECIMAL_RESULT UDFs
- the class may have a destructor with necessary cleanup logic.
Developer needs to instantiate a set of c-style functions required by UDF
(f_init() / f() / f_deinit()) via one of the following macros:
- DECLARE_STRING_UDF() for STRING_RESULT UDFs
- DECLARE_REAL_UDF() for REAL_RESULT UDFs
- DECLARE_INT_UDF() for INT_RESULT UDFs
- DECLARE_DECIMAL_UDF() for DECIMAL_RESULT UDFs
For instance,
class blah_impl { public: blah_impl(mysqlpp::udf_context& ctx) { // we expect the number of arguments to be exactly 1 if (ctx.get_number_of_args() != 1) throw std::invalid_argument( "BLAH() requires exactly one argument"); // specify whether function always return the same value ctx.mark_result_const(false); // specify whether function result may be null ctx.mark_result_nullable(false); // we do not expect the first argument to be null ctx.mark_arg_nullable(0, false); // we expect the first argument to be of string type ctx.set_arg_type(0, STRING_RESULT); } mysqlpp::udf_result_t<STRING_RESULT> calculate(const mysqlpp::udf_context &ctx) { return "modified-" + ctx.get_arg<STRING_RESULT>(0); } } DECLARE_STRING_UDF(blah_impl, blah)
Create and use the UDF as usually
CREATE FUNCTION blah RETURNS STRING SONAME "libblah.so"; SELECT blah('foo') AS result; +--------------+ | result | +--------------+ | modified-foo | +--------------+ DROP FUNCTION blah;
Developer is allowed to throw exceptions from both the _impl class constructor and from the calculate() method in indicate errors.
- Exception e derived from std::exception thrown from the constructor will be translated into ER_CANT_INITIALIZE_UDF MySQL error with the custom message e.what()
ERROR HY000: Can't initialize function 'wrapped_udf_string'; function requires exactly one argument
- Exception e not derived from std::exception thrown from the constructor will be translated into ER_CANT_INITIALIZE_UDF MySQL error with the predefined error message unexpected exception
ERROR HY000: Can't initialize function 'wrapped_udf_string'; unexpected exception
- Exception e derived from std::exception thrown from the calculate() method will be translated into ER_UDF_ERROR MySQL error with the custom message e.what()
ERROR HY000: <function_name> UDF failed; test runtime_error
- Exception e not derived from std::exception thrown from the calculate() method will be translated into ER_UDF_ERROR MySQL error with the predefined error message unexpected exception
ERROR HY000: <function_name> UDF failed; unexpected exception
- Exception e derived from mysqlpp::udf_exception thrown from the calculate() method will be translated into e.get_error_code() MySQL error with the custom message e.what()
ERROR HY000: Wrapped UDF exception in function '<function_name>'; test udf_exception without sentinel
-
- Please notice that custom error code supplied to mysqlpp::udf_exception constructor (when an instance of this exception is thrown) must correspond to a string resource with exactly two %s parameters (one for the function name
and another one for the custom message) - mysqlpp::udf_exception exceptions constructed without error code (with single string only), result in not calling my_error() at all. This construct can be used in cases when one of the internal MySQL functions already set the error code and developer does not want to overwrite it.
- Predefined ER_WRAPPED_UDF_EXCEPTION custom error code can be used to signal general purpose errors from the wrapped UDFs
throw mysqlpp::udf_exception("<message>", ER_WRAPPED_UDF_EXCEPTION);
- Please notice that custom error code supplied to mysqlpp::udf_exception constructor (when an instance of this exception is thrown) must correspond to a string resource with exactly two %s parameters (one for the function name