mysqlshdk/scripting/polyglot/utils/polyglot_utils.cc (213 lines of code) (raw):

/* * Copyright (c) 2024, 2025, Oracle and/or its affiliates. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, * as published by the Free Software Foundation. * * This program is designed to work with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, * as designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have either included with * the program or referenced in the documentation. * * 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, version 2.0, 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 "mysqlshdk/scripting/polyglot/utils/polyglot_utils.h" #include <limits> #include <numeric> #include <optional> #include <regex> #include <sstream> #include <vector> #include "mysqlshdk/scripting/polyglot/utils/polyglot_api_clean.h" #include "mysqlshdk/libs/utils/logger.h" #include "mysqlshdk/libs/utils/utils_string.h" #include "mysqlshdk/scripting/polyglot/native_wrappers/polyglot_collectable.h" #include "mysqlshdk/scripting/polyglot/utils/polyglot_error.h" namespace shcore { namespace polyglot { namespace { poly_value poly_string(poly_thread thread, poly_context context, const char *data, size_t size) { poly_value str; throw_if_error(poly_create_string_utf8, thread, context, data, size, &str); return str; } } // namespace /** * Parses the callback information sent by polyglot, returning if requested a * vector with the arguments as well as the collectable associated to the call */ size_t parse_callback_args(poly_thread thread, poly_callback_info args, std::vector<poly_value> *argv, void **data) { size_t argc = 0; void *tmp_data = nullptr; void **target_data = data ? data : &tmp_data; try { if (const auto rc = poly_get_callback_info(thread, args, &argc, nullptr, target_data); rc != poly_ok) { throw std::runtime_error(Polyglot_error(thread, rc).message()); } if (argc != 0 && argv != nullptr) { argv->resize(argc); if (const auto rc = poly_get_callback_info(thread, args, &argc, &(*argv)[0], target_data); rc != poly_ok) { throw std::runtime_error(Polyglot_error(thread, rc).message()); } } } catch (const Polyglot_generic_error &error) { throw std::runtime_error(error.message()); } return argc; } bool get_data(poly_thread thread, poly_callback_info args, std::string_view name, void **data) { try { if (0 != parse_callback_args(thread, args, nullptr, data)) { throw std::runtime_error( shcore::str_format("%.*s() takes no arguments", static_cast<int>(name.length()), name.data())); return false; } } catch (const std::runtime_error &error) { throw_callback_exception(thread, error.what()); return false; } return true; } bool get_args_and_data(poly_thread thread, poly_callback_info args, std::string_view name, void **data, size_t expected_argc, std::vector<poly_value> *argv) { try { if (expected_argc != parse_callback_args(thread, args, argv, data)) { throw std::runtime_error(shcore::str_format( "%.*s(...) takes %zd argument%s", static_cast<int>(name.length()), name.data(), expected_argc, expected_argc == 1 ? "" : "s")); } } catch (const std::runtime_error &error) { throw_callback_exception(thread, error.what()); return false; } return true; } bool is_native_type(poly_thread thread, poly_value value, Collectable_type type, void **native_data) { bool ret_val = false; void *data = nullptr; if (poly_ok == poly_value_get_native_data(thread, value, &data)) { if (!data) { return false; } else { ret_val = (static_cast<ICollectable *>(data))->type() == type; if (native_data) { *native_data = data; } } } return ret_val; } std::string to_string(poly_thread thread, poly_value obj) { size_t s{0}; throw_if_error(poly_value_as_string_utf8, thread, obj, nullptr, 0, &s); std::string value; value.resize(s++); throw_if_error(poly_value_as_string_utf8, thread, obj, &value[0], s, &s); return value; } int64_t to_int(poly_thread thread, poly_value obj) { int64_t value = 0; throw_if_error(poly_value_as_int64, thread, obj, &value); return value; } double to_double(poly_thread thread, poly_value obj) { double value = 0; throw_if_error(poly_value_as_double, thread, obj, &value); return value; } bool to_boolean(poly_thread thread, poly_value obj) { bool value = false; throw_if_error(poly_value_as_boolean, thread, obj, &value); return value; } poly_value poly_string(poly_thread thread, poly_context context, std::string_view data) { return poly_string(thread, context, data.data(), data.length()); } poly_value poly_bool(poly_thread thread, poly_context context, bool value) { poly_value boolean; throw_if_error(poly_create_boolean, thread, context, value, &boolean); return boolean; } poly_value poly_int(poly_thread thread, poly_context context, int64_t value) { poly_value integer; throw_if_error(poly_create_int64, thread, context, value, &integer); return integer; } poly_value poly_uint(poly_thread thread, poly_context context, uint64_t value) { poly_value integer; if (value <= std::numeric_limits<uint32_t>::max()) { throw_if_error(poly_create_uint32, thread, context, value, &integer); } else { throw std::runtime_error("Only 32 bit unsigned integers are supported"); } return integer; } poly_value poly_double(poly_thread thread, poly_context context, double value) { poly_value result; throw_if_error(poly_create_double, thread, context, value, &result); return result; } poly_value poly_null(poly_thread thread, poly_context context) { poly_value result; throw_if_error(poly_create_null, thread, context, &result); return result; } poly_value poly_array(poly_thread thread, poly_context context, const std::vector<poly_value> &values) { poly_value array; throw_if_error(poly_create_array, thread, context, &values[0], values.size(), &array); return array; } std::vector<std::string> get_member_keys(poly_thread thread, poly_context context, poly_value object) { size_t size{0}; throw_if_error(poly_value_get_member_keys, thread, context, object, &size, nullptr); std::vector<poly_value> poly_keys; poly_keys.resize(size); throw_if_error(poly_value_get_member_keys, thread, context, object, &size, &poly_keys[0]); std::vector<std::string> keys; for (auto key : poly_keys) { keys.push_back(to_string(thread, key)); } return keys; } void throw_callback_exception(poly_thread thread, const char *error) { try { throw_if_error(poly_throw_exception, thread, error); } catch (const std::exception &err) { log_error("Error while throwing exception on C callback: %s", err.what()); } } poly_value get_member(poly_thread thread, poly_value object, const std::string &name) { poly_value member; throw_if_error(poly_value_get_member, thread, object, name.c_str(), &member); return member; } bool is_executable(poly_thread thread, poly_value object) { bool callable = false; throw_if_error(poly_value_can_execute, thread, object, &callable); return callable; } bool get_member(poly_thread thread, poly_value object, const char *name, poly_value *member) { bool has_member{false}; throw_if_error(poly_value_has_member, thread, object, name, &has_member); if (has_member) { throw_if_error(poly_value_get_member, thread, object, name, member); } return has_member; } bool is_object(poly_thread thread, poly_value object, std::string *class_name) { poly_value constructor; if (get_member(thread, object, "constructor", &constructor)) { if (class_name) { poly_value poly_class_name; throw_if_error(poly_value_get_member, thread, constructor, "name", &poly_class_name); *class_name = to_string(thread, poly_class_name); } return true; } return false; } } // namespace polyglot } // namespace shcore