MySQL 9.3.0
Source Code Documentation
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
polyglot_native_wrapper.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024, 2025, Oracle and/or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is designed to work with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have either included with
14 * the program or referenced in the documentation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
19 * the GNU General Public License, version 2.0, for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#ifndef MYSQLSHDK_SCRIPTING_POLYGLOT_NATIVE_WRAPPERS_POLYGLOT_NATIVE_WRAPPER_
27#define MYSQLSHDK_SCRIPTING_POLYGLOT_NATIVE_WRAPPERS_POLYGLOT_NATIVE_WRAPPER_
28
29#include <cassert>
30#include <concepts>
31#include <memory>
32#include <type_traits>
33
35
40
41namespace shcore {
42namespace polyglot {
43
44class Polyglot_language;
45
46/**
47 * Exposure of C++ objects to the polyglot library is done through the usage of
48 * Proxy objects provided by the polyglot library. Those proxy objects implement
49 * the needed operations to treat a C++ object as a standard polyglot object,
50 * each of those operations require a C++ callback for the execution.
51 *
52 * In the C++ side it is needed to create the callbacks required by the proxy
53 * objects in the polyglot library, for each C++ object type to be supported
54 * there's a wrapper class which provides the needed callbacks.
55 *
56 * When a C++ object is given to the polyglot library, 2 things are needed:
57 *
58 * - The registrations of the C++ callbacks
59 * - The identification of the target C++ instance to be used on the callbacks
60 *
61 * Each object wrapper provides the above. For the second item, a Collectable
62 * object is created and given to the polyglot proxy object. This Collectable
63 * object contains the necessary information to identify the target C++ object
64 * on which the operation will be executed.
65 *
66 * This class holds general callback function to be used to release the created
67 * Collectable objects once the Proxy object is garbage collected in the
68 * Polyglot library.
69 */
70template <typename T, Collectable_type t>
72 public:
74 using Native_ptr = std::shared_ptr<T>;
75
77
78 explicit Polyglot_native_wrapper(std::weak_ptr<Polyglot_language> language)
79 : m_language(std::move(language)) {}
80
83
86
87 virtual ~Polyglot_native_wrapper() = default;
88
89 poly_value wrap(const Native_ptr &native_value) const {
90 auto collectable =
91 std::make_unique<Collectable_t>(native_value, m_language);
92 auto language = collectable->language();
93
94 auto value = create_wrapper(language->thread(), language->context(),
95 collectable.get());
96
97 collectable->registry()->add(collectable.release());
98
99 return value;
100 }
101
102 static bool unwrap(poly_thread thread, poly_value value,
103 Native_ptr *ret_object) {
104 assert(ret_object);
105
106 void *data = nullptr;
107
108 if (!is_native_type(thread, value, t, &data)) {
109 return false;
110 }
111
112 assert(data);
113
114 const auto collectable = static_cast<Collectable_t *>(data);
115
116 if (const auto &target_native = collectable->data()) {
117 *ret_object = target_native;
118 }
119
120 return true;
121 }
122
123 protected:
124 static poly_value handler_release_collectable(poly_thread thread,
125 poly_callback_info args) {
126 void *data = nullptr;
127
128 if (get_data(thread, args, "destroy", &data)) {
129 assert(data);
130 const auto collectable = static_cast<ICollectable *>(data);
131
132 // TODO(rennox): Safety code, found cases where registry is gone,
133 // investigate why?
134 auto registry = collectable->registry();
135 if (registry) {
136 registry->remove(collectable);
137 }
138 }
139
140 return nullptr;
141 }
142
143 virtual poly_value create_wrapper(poly_thread thread, poly_context context,
144 ICollectable *collectable) const = 0;
145
146 /**
147 * Generic handler to be used with pure native functions, no interaction with
148 * the polyglot library is done:
149 *
150 * - Receive no arguments
151 * - Return a Value as result
152 */
153 template <typename Config>
154 static poly_value native_handler_no_args(poly_thread thread,
155 poly_callback_info args) {
156 void *data = nullptr;
157 poly_value value = nullptr;
158 if (get_data(thread, args, Config::name, &data)) {
159 assert(data);
160 const auto collectable = static_cast<Collectable_t *>(data);
161 const auto language = collectable->language();
162 try {
163 value = language->convert(Config::callback(collectable->data()));
164 } catch (const Polyglot_error &exc) {
165 language->throw_exception_object(exc);
166 } catch (const Jit_executor_exception &exc) {
167 language->throw_jit_executor_exception(exc);
168 } catch (const std::exception &e) {
169 throw_callback_exception(thread, e.what());
170 }
171 }
172 return value;
173 }
174
175 /**
176 * Generic handler to be used with functions that interact with the polyglot
177 * library:
178 *
179 * - Receive no arguments
180 * - Return a poly_value as result
181 */
182 template <typename Config>
183 static poly_value polyglot_handler_no_args(poly_thread thread,
184 poly_callback_info args) {
185 void *data = nullptr;
186 poly_value value = nullptr;
187 if (get_data(thread, args, Config::name, &data)) {
188 assert(data);
189 const auto collectable = static_cast<Collectable_t *>(data);
190 const auto language = collectable->language();
191 try {
192 value = Config::callback(language, collectable->data());
193 } catch (const Polyglot_error &exc) {
194 language->throw_exception_object(exc);
195 } catch (const Jit_executor_exception &exc) {
196 language->throw_jit_executor_exception(exc);
197 } catch (const std::exception &e) {
198 throw_callback_exception(thread, e.what());
199 }
200 }
201 return value;
202 }
203
204 /**
205 * Generic handler to be used with pure native functions, no interaction with
206 * the polyglot library is done:
207 *
208 * - Receive a vector of Values as arguments
209 * - Return a Value as result
210 */
211 template <typename Config>
212 static poly_value native_handler_fixed_args(poly_thread thread,
213 poly_callback_info args) {
214 std::vector<poly_value> argv;
215 void *data = nullptr;
216 poly_value value = nullptr;
217 try {
218 if (get_args_and_data(thread, args, Config::name, &data, Config::argc,
219 &argv)) {
220 assert(data);
221 const auto collectable = static_cast<Collectable_t *>(data);
222 const auto language = collectable->language();
223 try {
224 value = language->convert(Config::callback(
225 collectable->data(), language->convert_args(argv)));
226 } catch (const Polyglot_error &exc) {
227 language->throw_exception_object(exc);
228 } catch (const Jit_executor_exception &exc) {
229 language->throw_jit_executor_exception(exc);
230 }
231 }
232 } catch (const std::exception &e) {
233 throw_callback_exception(thread, e.what());
234 }
235 return value;
236 }
237
238 /**
239 * Generic handler to be used with functions that interact with the polyglot
240 * library, this is:
241 *
242 * - Require the language instance for the execution
243 * - Receive a vector of polyglot values as arguments
244 * - Return a polyglot value as result
245 */
246 template <typename Config>
247 static poly_value polyglot_handler_fixed_args(poly_thread thread,
248 poly_callback_info args) {
249 std::vector<poly_value> argv;
250 void *data = nullptr;
251 poly_value value = nullptr;
252 try {
253 if (get_args_and_data(thread, args, Config::name, &data, Config::argc,
254 &argv)) {
255 assert(data);
256 const auto collectable = static_cast<Collectable_t *>(data);
257 const auto language = collectable->language();
258 try {
259 value = Config::callback(language, collectable->data(), argv);
260 } catch (const Polyglot_error &exc) {
261 language->throw_exception_object(exc);
262 } catch (const Jit_executor_exception &exc) {
263 language->throw_jit_executor_exception(exc);
264 }
265 }
266 } catch (const std::exception &e) {
267 throw_callback_exception(thread, e.what());
268 }
269 return value;
270 }
271
272 /**
273 * Generic handler to be used with pure native functions, no interaction with
274 * the polyglot library is done:
275 *
276 * - Receive a vector of Values as arguments
277 * - Return a Value as result
278 */
279 template <typename Config>
280 static poly_value native_handler_variable_args(poly_thread thread,
281 poly_callback_info args) {
282 std::vector<poly_value> argv;
283 void *data = nullptr;
284 poly_value value = nullptr;
285 std::shared_ptr<Polyglot_language> language = {};
286
287 try {
288 parse_callback_args(thread, args, &argv, &data);
289 assert(data);
290 const auto collectable = static_cast<Collectable_t *>(data);
291
292 // Since the polyglot library will not raise an interrupted exception when
293 // calling native code, we have to handle that here
294 // bool interrupted = false;
295 // Interrupt_handler handler([&]() {
296 // interrupted = true;
297 // return true;
298 // });
299
300 language = collectable->language();
301 const auto v =
302 Config::callback(collectable->data(), language->convert_args(argv));
303
304 // if (interrupted) {
305 // throw std::runtime_error(k_interrupted_error);
306 // }
307
308 value = language->convert(v);
309 } catch (const Polyglot_error &exc) {
310 language->throw_exception_object(exc);
311 } catch (const Jit_executor_exception &exc) {
312 language->throw_jit_executor_exception(exc);
313 } catch (const std::exception &e) {
314 throw_callback_exception(thread, e.what());
315 }
316
317 return value;
318 }
319
320 std::weak_ptr<Polyglot_language> m_language;
321};
322
323} // namespace polyglot
324} // namespace shcore
325
326#endif // MYSQLSHDK_SCRIPTING_POLYGLOT_NATIVE_WRAPPERS_POLYGLOT_NATIVE_WRAPPER_
void remove(ICollectable *target)
Definition: polyglot_collectable.cc:73
Represents a data object to be associated to a Polyglot wrapper for C++ elements.
Definition: polyglot_collectable.h:79
Base collectable interface to be able to determine the type of a collectable object without with no n...
Definition: polyglot_collectable.h:55
std::shared_ptr< Polyglot_language > language() const
Definition: polyglot_collectable.cc:54
Collectable_registry * registry() const
Definition: polyglot_collectable.cc:58
Definition: jit_executor_exceptions.h:34
Represents polyglot errors that will be created from information available in the polyglot library st...
Definition: polyglot_error.h:77
Exposure of C++ objects to the polyglot library is done through the usage of Proxy objects provided b...
Definition: polyglot_native_wrapper.h:71
static poly_value native_handler_no_args(poly_thread thread, poly_callback_info args)
Generic handler to be used with pure native functions, no interaction with the polyglot library is do...
Definition: polyglot_native_wrapper.h:154
Polyglot_native_wrapper(std::weak_ptr< Polyglot_language > language)
Definition: polyglot_native_wrapper.h:78
static poly_value polyglot_handler_no_args(poly_thread thread, poly_callback_info args)
Generic handler to be used with functions that interact with the polyglot library:
Definition: polyglot_native_wrapper.h:183
static poly_value native_handler_fixed_args(poly_thread thread, poly_callback_info args)
Generic handler to be used with pure native functions, no interaction with the polyglot library is do...
Definition: polyglot_native_wrapper.h:212
std::weak_ptr< Polyglot_language > m_language
Definition: polyglot_native_wrapper.h:320
Polyglot_native_wrapper & operator=(Polyglot_native_wrapper &&)=delete
Polyglot_native_wrapper(Polyglot_native_wrapper &&)=delete
static bool unwrap(poly_thread thread, poly_value value, Native_ptr *ret_object)
Definition: polyglot_native_wrapper.h:102
static poly_value handler_release_collectable(poly_thread thread, poly_callback_info args)
Definition: polyglot_native_wrapper.h:124
Polyglot_native_wrapper & operator=(const Polyglot_native_wrapper &)=delete
static poly_value polyglot_handler_fixed_args(poly_thread thread, poly_callback_info args)
Generic handler to be used with functions that interact with the polyglot library,...
Definition: polyglot_native_wrapper.h:247
Polyglot_native_wrapper(const Polyglot_native_wrapper &)=delete
std::shared_ptr< T > Native_ptr
Definition: polyglot_native_wrapper.h:74
poly_value wrap(const Native_ptr &native_value) const
Definition: polyglot_native_wrapper.h:89
virtual poly_value create_wrapper(poly_thread thread, poly_context context, ICollectable *collectable) const =0
static poly_value native_handler_variable_args(poly_thread thread, poly_callback_info args)
Generic handler to be used with pure native functions, no interaction with the polyglot library is do...
Definition: polyglot_native_wrapper.h:280
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
void throw_callback_exception(poly_thread thread, const char *error)
The integration of the PolyglotAPI is mostly centered in the registration of C++ callbacks to impleme...
Definition: polyglot_utils.cc:251
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)
Returns the collectable and arguments sent by Polyglot on a call to a C++ function.
Definition: polyglot_utils.cc:109
bool is_native_type(poly_thread thread, poly_value value, Collectable_type type, void **native_data)
Identifies if a given poly_value corresponds to a wrapped C++ element.
Definition: polyglot_utils.cc:126
size_t parse_callback_args(poly_thread thread, poly_callback_info args, std::vector< poly_value > *argv, void **data)
Parses the callback information sent by polyglot, returning if requested a vector with the arguments ...
Definition: polyglot_utils.cc:63
bool get_data(poly_thread thread, poly_callback_info args, std::string_view name, void **data)
Returns the collectable sent by Polyglot on a call to a C++ function.
Definition: polyglot_utils.cc:92
Definition: file_system_exceptions.h:34
Definition: gcs_xcom_synode.h:64
case opt name
Definition: sslopt-case.h:29