@@ -124,7 +124,8 @@ static PyUDFSignature analyzeSignature(const py::function& udf) {
124124 return UDFSignature;
125125}
126126
127- static scalar_func_exec_t getUDFExecFunc (const py::function& udf) {
127+ static scalar_func_exec_t getUDFExecFunc (const py::function& udf, bool defaultNull,
128+ bool catchExceptions) {
128129 return [=](const std::vector<std::shared_ptr<ValueVector>>& params, ValueVector& result,
129130 void * /* dataPtr */ ) -> void {
130131 py::gil_scoped_acquire acquire;
@@ -133,16 +134,33 @@ static scalar_func_exec_t getUDFExecFunc(const py::function& udf) {
133134 for (auto i = 0u ; i < resultSelVector.getSelSize (); ++i) {
134135 auto resultPos = resultSelVector[i];
135136 py::list pyParams;
137+ bool hasNull = false ;
136138 for (const auto & param : params) {
137139 auto paramPos =
138140 param->state ->isFlat () ? param->state ->getSelVector ()[0 ] : resultPos;
139141 auto value = param->getAsValue (paramPos);
142+ if (value->isNull ()) {
143+ hasNull = true ;
144+ }
140145 auto pyValue = PyQueryResult::convertValueToPyObject (*value);
141146 pyParams.append (pyValue);
142147 }
143- auto pyResult = udf (*pyParams);
144- auto resultValue = PyConnection::transformPythonValueAs (pyResult, result.dataType );
145- result.copyFromValue (resultPos, resultValue);
148+ if (defaultNull && hasNull) {
149+ result.setNull (resultPos, true );
150+ } else {
151+ try {
152+ auto pyResult = udf (*pyParams);
153+ auto resultValue =
154+ PyConnection::transformPythonValueAs (pyResult, result.dataType );
155+ result.copyFromValue (resultPos, resultValue);
156+ } catch (py::error_already_set& e) {
157+ if (catchExceptions) {
158+ result.setNull (resultPos, true );
159+ } else {
160+ throw common::RuntimeException (e.what ());
161+ }
162+ }
163+ }
146164 }
147165 };
148166}
@@ -155,7 +173,8 @@ static scalar_bind_func getUDFBindFunc(const PyUDFSignature& signature) {
155173}
156174
157175function_set PyUDF::toFunctionSet (const std::string& name, const py::function& udf,
158- const py::list& paramTypes, const std::string& resultType) {
176+ const py::list& paramTypes, const std::string& resultType, bool defaultNull,
177+ bool catchExceptions) {
159178 auto pySignature = analyzeSignature (udf);
160179 auto explicitParamTypes = pyListToParams (paramTypes);
161180 if (explicitParamTypes.size () > 0 ) {
@@ -183,7 +202,7 @@ function_set PyUDF::toFunctionSet(const std::string& name, const py::function& u
183202
184203 function_set definitions;
185204 definitions.push_back (std::make_unique<ScalarFunction>(name, paramIDTypes,
186- pySignature.resultType .getLogicalTypeID (), getUDFExecFunc (udf),
187- getUDFBindFunc (pySignature)));
205+ pySignature.resultType .getLogicalTypeID (),
206+ getUDFExecFunc (udf, defaultNull, catchExceptions), getUDFBindFunc (pySignature)));
188207 return definitions;
189208}
0 commit comments