• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

evolvedbinary / elemental / 982

29 Apr 2025 08:34PM UTC coverage: 56.409% (+0.007%) from 56.402%
982

push

circleci

adamretter
[feature] Improve README.md badges

28451 of 55847 branches covered (50.94%)

Branch coverage included in aggregate %.

77468 of 131924 relevant lines covered (58.72%)

0.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.42
/exist-core/src/main/java/org/exist/xquery/FunctionFactory.java
1
/*
2
 * Elemental
3
 * Copyright (C) 2024, Evolved Binary Ltd
4
 *
5
 * admin@evolvedbinary.com
6
 * https://www.evolvedbinary.com | https://www.elemental.xyz
7
 *
8
 * Use of this software is governed by the Business Source License 1.1
9
 * included in the LICENSE file and at www.mariadb.com/bsl11.
10
 *
11
 * Change Date: 2028-04-27
12
 *
13
 * On the date above, in accordance with the Business Source License, use
14
 * of this software will be governed by the Apache License, Version 2.0.
15
 *
16
 * Additional Use Grant: Production use of the Licensed Work for a permitted
17
 * purpose. A Permitted Purpose is any purpose other than a Competing Use.
18
 * A Competing Use means making the Software available to others in a commercial
19
 * product or service that: substitutes for the Software; substitutes for any
20
 * other product or service we offer using the Software that exists as of the
21
 * date we make the Software available; or offers the same or substantially
22
 * similar functionality as the Software.
23
 *
24
 * NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25
 *       The original license header is included below.
26
 *
27
 * =====================================================================
28
 *
29
 * eXist-db Open Source Native XML Database
30
 * Copyright (C) 2001 The eXist-db Authors
31
 *
32
 * info@exist-db.org
33
 * http://www.exist-db.org
34
 *
35
 * This library is free software; you can redistribute it and/or
36
 * modify it under the terms of the GNU Lesser General Public
37
 * License as published by the Free Software Foundation; either
38
 * version 2.1 of the License, or (at your option) any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43
 * Lesser General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU Lesser General Public
46
 * License along with this library; if not, write to the Free Software
47
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
48
 */
49
package org.exist.xquery;
50

51
import java.util.ArrayList;
52
import java.util.List;
53

54
import org.exist.Namespaces;
55
import org.exist.dom.QName;
56
import org.exist.source.Source;
57
import org.exist.xquery.Constants.Comparison;
58
import org.exist.xquery.Constants.StringTruncationOperator;
59
import org.exist.xquery.parser.XQueryAST;
60
import org.exist.xquery.value.SequenceType;
61
import org.exist.xquery.value.StringValue;
62
import org.exist.xquery.value.Type;
63

64
import javax.annotation.Nullable;
65
import javax.xml.XMLConstants;
66

67
public class FunctionFactory {
×
68

69
    public static final String ENABLE_JAVA_BINDING_ATTRIBUTE = "enable-java-binding";
70
    public static final String PROPERTY_ENABLE_JAVA_BINDING = "xquery.enable-java-binding";
71
    public static final String DISABLE_DEPRECATED_FUNCTIONS_ATTRIBUTE = "disable-deprecated-functions";
72
    public static final String PROPERTY_DISABLE_DEPRECATED_FUNCTIONS = "xquery.disable-deprecated-functions";
73
    public static final boolean DISABLE_DEPRECATED_FUNCTIONS_BY_DEFAULT = false;
74

75
    public static Expression createFunction(XQueryContext context, XQueryAST ast, PathExpr parent, List<Expression> params) throws XPathException {
76
            QName qname = null;
1✔
77
        try {
78
            qname = QName.parse(context, ast.getText(), context.getDefaultFunctionNamespace());
1✔
79
        } catch(final QName.IllegalQNameException xpe) {
1✔
80
            throw new XPathException(ast, ErrorCodes.XPST0081, "Invalid qname " +  ast.getText() + ". " + xpe.getMessage());
1✔
81
        }
82
        return createFunction(context, qname, ast, parent, params);
1✔
83
    }
84

85
    public static Expression createFunction(XQueryContext context, QName qname, XQueryAST ast, PathExpr parent, List<Expression> params) throws XPathException {
86
        return createFunction(context, qname, ast, parent, params, true);
1✔
87
    }
88

89
    /**
90
     * Create a function call.
91
     *
92
     * This method handles all calls to built-in or user-defined
93
     * functions. It also deals with constructor functions and
94
     * optimizes some function calls like starts-with, ends-with or
95
     * contains.
96
     *
97
     * @param context the XQuery context
98
     * @param qname the name of the function
99
     * @param ast the AST node of the function
100
     * @param parent the parent expression of the function
101
     * @param params the parameters to the function
102
     * @param optimizeStrFuncs true if string functions be optimized
103
     *
104
     * @return the function expression
105
     *
106
     * @throws XPathException if an error occurs creating the function
107
     */
108
    public static Expression createFunction(XQueryContext context, QName qname, XQueryAST ast, PathExpr parent, List<Expression> params,
109
        boolean optimizeStrFuncs) throws XPathException {
110
        final String local = qname.getLocalPart();
1✔
111
        final String uri = qname.getNamespaceURI();
1✔
112
        Expression step = null;
1✔
113
        if (optimizeStrFuncs && (Namespaces.XPATH_FUNCTIONS_NS.equals(uri) || Namespaces.XSL_NS.equals(uri))) {
1!
114
            if("starts-with".equals(local)) {
1✔
115
                step = startsWith(context, ast, parent, params);
1✔
116
            } else if("ends-with".equals(local)) {
1✔
117
                step = endsWith(context, ast, parent, params);
1✔
118
            } else if("contains".equals(local)) {
1✔
119
                step = contains(context, ast, parent, params);
1✔
120
            } else if("equals".equals(local)) {
1!
121
                step = equals(context, ast, parent, params);
×
122
            }
123
        //Check if the namespace belongs to one of the schema namespaces.
124
        //If yes, the function is a constructor function
125
        } else if (uri.equals(Namespaces.SCHEMA_NS) ||
1✔
126
                uri.equals(Namespaces.XPATH_DATATYPES_NS)) {
1✔
127
            step = castExpression(context, ast, params, qname);
1✔
128
        //Check if the namespace URI starts with "java:". If yes, treat
129
        //the function call as a call to an arbitrary Java function.
130
        } else if (uri.startsWith("java:")) {
1✔
131
            step = javaFunctionBinding(context, ast, params, qname);
×
132
        }
133
        //None of the above matched: function is either a built-in function or
134
        //a user-defined function
135
        if (step == null) {
1✔
136
            step = functionCall(context, ast, params, qname);
1✔
137
        }
138
        return step;
1✔
139
    }
140

141
    /**
142
     * starts-with(node-set, string)
143
     */
144
    private static GeneralComparison startsWith(XQueryContext context,
145
            XQueryAST ast, PathExpr parent, List<Expression> params) throws XPathException {
146
        if (params.size() < 2) {
1!
147
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
148
                        ErrorCodes.XPST0017, "Function starts-with() requires two or three arguments");
×
149
        }
150
        if (params.size() > 3) {
1!
151
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
152
                        ErrorCodes.XPST0017, "Function starts-with() requires two or three arguments");
×
153
        }
154
        final PathExpr p0 = (PathExpr) params.get(0);
1✔
155
        final PathExpr p1 = (PathExpr) params.get(1);
1✔
156
        if (p1.getLength() == 0) {
1!
157
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
158
                "Second argument of starts-with() is empty");
×
159
        }
160
        final GeneralComparison op = new GeneralComparison(context, p0, p1,
1✔
161
            Comparison.EQ, StringTruncationOperator.RIGHT);
1✔
162
        op.setLocation(ast.getLine(), ast.getColumn());
1✔
163
        //TODO : not sure for parent -pb
164
        context.getProfiler().message(parent, Profiler.OPTIMIZATIONS,
1✔
165
                "OPTIMIZATION", "Rewritten start-with as a general comparison with a right truncations");
1✔
166
        if (params.size() == 3) {
1✔
167
            op.setCollation((Expression) params.get(2));
1✔
168
        }
169
        return op;
1✔
170
    }
171

172
    /**
173
     * ends-with(node-set, string)
174
     */
175
    private static GeneralComparison endsWith(XQueryContext context, XQueryAST ast,
176
            PathExpr parent, List<Expression> params) throws XPathException {
177
        if (params.size() < 2) {
1!
178
            throw new XPathException(ast.getLine(), ast.getColumn(), 
×
179
                        ErrorCodes.XPST0017, "Function ends-with() requires two or three arguments");
×
180
        }
181
        if (params.size() > 3) {
1!
182
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
183
                        ErrorCodes.XPST0017, "Function ends-with() requires two or three arguments");
×
184
        }
185
        final PathExpr p0 = (PathExpr) params.get(0);
1✔
186
        final PathExpr p1 = (PathExpr) params.get(1);
1✔
187
        if (p1.getLength() == 0) {
1!
188
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
189
                "Second argument of ends-with() is empty");
×
190
        }
191
        final GeneralComparison op = new GeneralComparison(context, p0, p1, Comparison.EQ, StringTruncationOperator.LEFT);
1✔
192
        //TODO : not sure for parent -pb
193
        context.getProfiler().message(parent, Profiler.OPTIMIZATIONS,
1✔
194
            "OPTIMIZATION", "Rewritten ends-with as a general comparison with a left truncations");
1✔
195
        op.setLocation(ast.getLine(), ast.getColumn());
1✔
196
        if(params.size() == 3) {
1✔
197
            op.setCollation((Expression) params.get(2));
1✔
198
        }
199
        return op;
1✔
200
    }
201

202
    /**
203
     * contains(node-set, string)
204
     */
205
    private static GeneralComparison contains(XQueryContext context, XQueryAST ast,
206
            PathExpr parent, List<Expression> params) throws XPathException {
207
        if (params.size() < 2) {
1!
208
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
209
                        ErrorCodes.XPST0017, "Function contains() requires two or three arguments");
×
210
        }
211
        if (params.size() > 3) {
1!
212
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
213
                        ErrorCodes.XPST0017, "Function contains() requires two or three arguments");
×
214
        }
215
        final PathExpr p0 = (PathExpr) params.get(0);
1✔
216
        final PathExpr p1 = (PathExpr) params.get(1);
1✔
217
        if (p1.getLength() == 0) {
1!
218
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
219
                "Second argument of contains() is empty");
×
220
        }
221
        final GeneralComparison op = new GeneralComparison(context, p0, p1,
1✔
222
            Comparison.EQ, StringTruncationOperator.BOTH);
1✔
223
        //TODO : not sure for parent -pb
224
        context.getProfiler().message(parent, Profiler.OPTIMIZATIONS,
1✔
225
            "OPTIMIZATION", "Rewritten contains() as a general comparison with left and right truncations");
1✔
226
        op.setLocation(ast.getLine(), ast.getColumn());
1✔
227
        if (params.size() == 3) {
1✔
228
            op.setCollation((Expression) params.get(2));
1✔
229
        }
230
        return op;
1✔
231
    }
232

233
    /**
234
     * equals(node-set, string)
235
     */
236
    private static GeneralComparison equals(XQueryContext context, XQueryAST ast,
237
            PathExpr parent, List<Expression> params) throws XPathException {
238
        if (params.size() < 2) {
×
239
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
240
                        ErrorCodes.XPST0017, "Function equals() requires two or three arguments");
×
241
        }
242
        if (params.size() > 3) {
×
243
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
244
                        ErrorCodes.XPST0017, "Function equals() requires two or three arguments");
×
245
        }
246
        final PathExpr p0 = (PathExpr) params.get(0);
×
247
        final PathExpr p1 = (PathExpr) params.get(1);
×
248
        if (p1.getLength() == 0) {
×
249
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
250
                "Second argument of equals() is empty");
×
251
        }
252
        final GeneralComparison op = new GeneralComparison(context, p0, p1,
×
253
            Comparison.EQ, StringTruncationOperator.EQUALS);
×
254
        //TODO : not sure for parent -pb
255
        context.getProfiler().message(parent, Profiler.OPTIMIZATIONS,
×
256
            "OPTIMIZATION", "Rewritten contains() as a general comparison with no truncations");
×
257
        op.setLocation(ast.getLine(), ast.getColumn());
×
258
        if (params.size() == 3) {
×
259
            op.setCollation((Expression) params.get(2));
×
260
        } else {
×
261
            op.setCollation(new StringValue("?strength=identical"));
×
262
        }
263
        return op;
×
264
    }
265

266
    private static CastExpression castExpression(XQueryContext context,
267
            XQueryAST ast, List<Expression> params, QName qname) throws XPathException {
268
        if (params.size() != 1) {
1!
269
            throw new XPathException(ast.getLine(), ast.getColumn(),
×
270
                        ErrorCodes.XPST0017, "Wrong number of arguments for constructor function");
×
271
        }
272
        final Expression arg = params.get(0);
1✔
273
        final int code = Type.getType(qname);
1✔
274
        final CastExpression castExpr = new CastExpression(context, arg, code, Cardinality.ZERO_OR_ONE);
1✔
275
        castExpr.setLocation(ast.getLine(), ast.getColumn());
1✔
276
        return castExpr;
1✔
277
    }
278

279
    private static JavaCall javaFunctionBinding(XQueryContext context,
280
            XQueryAST ast, List<Expression> params, QName qname) throws XPathException {
281
        //Only allow java binding if specified in config file <xquery enable-java-binding="yes">
282
        final String javabinding = (String) context.getBroker().getConfiguration()
1✔
283
            .getProperty(PROPERTY_ENABLE_JAVA_BINDING);
1✔
284
        if(javabinding == null || !"yes".equals(javabinding)) {
1!
285
            throw new XPathException(ast.getLine(), ast.getColumn(),
1✔
286
                "Java binding is disabled in the current configuration (see conf.xml)." +
1✔
287
                " Call to " + qname.getStringValue() + " denied.");
1✔
288
        }
289
        final JavaCall call = new JavaCall(context, qname);
×
290
        call.setLocation(ast.getLine(), ast.getColumn());
×
291
        call.setArguments(params);
×
292
        return call;
×
293
    }
294

295
    private static Function functionCall(final XQueryContext context,
296
            final XQueryAST ast, final List<Expression> params, final QName qname) throws XPathException {
297
        Function fn = null;
1✔
298
        final String uri = qname.getNamespaceURI();
1✔
299
        final Module[] modules = context.getModules(uri);
1✔
300
        if (modules != null) {
1✔
301
            // Function might belongs to a module
302
            for (int i = 0; i < modules.length; i++) {
1!
303
                final Module module = modules[i];
1✔
304
                final boolean throwOnNotFound = i == modules.length - 1;
1✔
305
                if (module.isInternalModule()) {
1✔
306
                    // Function is from an Internal Module
307
                    fn = getInternalModuleFunction(context, ast, params, qname, module, throwOnNotFound);
1✔
308
                } else {
1✔
309
                    // Function is from an imported XQuery module
310
                    fn = getXQueryModuleFunction(context, ast, params, qname, module, throwOnNotFound);
1✔
311
                }
312

313
                if (fn != null) {
1✔
314
                    break;
1✔
315
                }
316
            }
317
        }
318

319
        if (fn == null) {
1✔
320
            // Function is a user-defined XQuery function in the same module as the caller
321
            fn = getUserDefinedFunction(context, ast, params, qname);
1✔
322
        }
323

324
        return fn;
1✔
325
    }
326

327
    /**
328
     * Gets a Java function from an Java XQuery Extension Module
329
     *
330
     * @param throwOnNotFound true to throw an XPST0017 if the functions is not found, false to just return null
331
     */
332
    private static @Nullable Function getInternalModuleFunction(final XQueryContext context,
333
            final XQueryAST ast, final List<Expression> params, QName qname, Module module,
334
            final boolean throwOnNotFound) throws XPathException {
335
        //For internal modules: create a new function instance from the class
336
        FunctionDef def = ((InternalModule) module).getFunctionDef(qname, params.size());
1✔
337
        //TODO: rethink: xsl namespace function should search xpath one too
338
        if (def == null && Namespaces.XSL_NS.equals(qname.getNamespaceURI())) {
1!
339
            //Search xpath namespace
340
            @Nullable final Module[] _modules_ = context.getModules(Namespaces.XPATH_FUNCTIONS_NS);
×
341
            if (_modules_ != null) {
×
342
                // there can be only one!
343
                for (final Module _module_ : _modules_) {
×
344
                    if (_module_ != null) {
×
345
                        final QName _qname_ = new QName(qname.getLocalPart(), Namespaces.XPATH_FUNCTIONS_NS, qname.getPrefix());
×
346
                        def = ((InternalModule) _module_).getFunctionDef(qname, params.size());
×
347
                        if (def != null) {
×
348
                            module = _module_;
×
349
                            qname = _qname_;
×
350
                            break;
×
351
                        }
352
                    }
353
                }
354
            }
355
        }
356
        if (def == null) {
1✔
357
            final List<FunctionSignature> funcs = ((InternalModule) module).getFunctionsByName(qname);
1✔
358
            if (funcs.isEmpty()) {
1!
359
                if (throwOnNotFound) {
1!
360
                    throw new XPathException(ast.getLine(), ast.getColumn(),
1✔
361
                            ErrorCodes.XPST0017, "Function " + qname.getStringValue() + "() " +
1✔
362
                            " is not defined in module namespace: " + qname.getNamespaceURI());
1✔
363
                } else {
364
                    return null;
×
365
                }
366
            } else {
367
                final StringBuilder buf = new StringBuilder();
×
368
                buf.append("Unexpectedly received ");
×
369
                buf.append(params.size());
×
370
                buf.append(" parameter(s) in call to function ");
×
371
                buf.append("'");
×
372
                buf.append(qname.getStringValue());
×
373
                buf.append("()'. ");
×
374
                buf.append("Defined function signatures are:\r\n");
×
375
                for (final FunctionSignature sig : funcs) {
×
376
                    buf.append(sig.toString()).append("\r\n");
×
377
                }
378
                throw new XPathException(ast.getLine(), ast.getColumn(), ErrorCodes.XPST0017, buf.toString());
×
379
            }
380
        }
381
        if (context.getConfiguration() != null &&
1✔
382
                (Boolean) context.getConfiguration().getProperty(PROPERTY_DISABLE_DEPRECATED_FUNCTIONS) &&
1!
383
                def.getSignature().isDeprecated()) {
×
384
            throw new XPathException(ast.getLine(), ast.getColumn(), ErrorCodes.XPST0017,
×
385
                    "Access to deprecated functions is not allowed. Call to '" + qname.getStringValue() + "()' denied. " + def.getSignature().getDeprecated());
×
386
        }
387
        final Function fn = Function.createFunction(context, ast, module, def);
1✔
388
        fn.setArguments(params);
1✔
389
        fn.setASTNode(ast);
1✔
390
        return new InternalFunctionCall(fn);
1✔
391
    }
392

393
    /**
394
     * Gets an user defined function from the XQuery
395
     */
396
    private static FunctionCall getUserDefinedFunction(XQueryContext context, XQueryAST ast, List<Expression> params, QName qname) throws XPathException {
397
        final FunctionCall fc;
398
        final UserDefinedFunction func = context.resolveFunction(qname, params.size());
1✔
399
        if (func != null) {
1✔
400
            fc = new FunctionCall(context, func);
1✔
401
            fc.setLocation(ast.getLine(), ast.getColumn());
1✔
402
            fc.setArguments(params);
1✔
403
        } else {
1✔
404
            //Create a forward reference which will be resolved later
405
            fc = new FunctionCall(context, qname, params);
1✔
406
            fc.setLocation(ast.getLine(), ast.getColumn());
1✔
407
            context.addForwardReference(fc);
1✔
408
        }
409
        return fc;
1✔
410
    }
411

412
    /**
413
     * Gets an XQuery function from an XQuery Module
414
     *
415
     * @param throwOnNotFound true to throw an XPST0017 if the functions is not found, false to just return null
416
     */
417
    private static FunctionCall getXQueryModuleFunction(final XQueryContext context,
418
            final XQueryAST ast, final List<Expression> params, final QName qname, final Module module, final boolean throwOnNotFound) throws XPathException {
419
        final FunctionCall fc;
420
        final UserDefinedFunction func = ((ExternalModule) module).getFunction(qname, params.size(), context);
1✔
421
        if (func == null) {
1✔
422
            // check if the module has been compiled already
423
            if (module.isReady()) {
1✔
424
                final StringBuilder msg = new StringBuilder("Function ")
1✔
425
                        .append(qname.getStringValue()).append('#').append(params.size())
1✔
426
                        .append(" is not defined in namespace '").append(qname.getNamespaceURI()).append('\'');
1✔
427
                if (module instanceof ExternalModule) {
1!
428
                    final Source moduleSource = ((ExternalModule) module).getSource();
1✔
429
                    msg.append(" for module: ").append(moduleSource.pathOrShortIdentifier());
1✔
430
                }
431
                if (throwOnNotFound) {
1!
432
                    throw new XPathException(ast.getLine(), ast.getColumn(),
×
433
                            ErrorCodes.XPST0017, msg.toString());
×
434
                } else {
435
                    return null;
1✔
436
                }
437

438
            // If not, postpone the function resolution
439
            // Register a forward reference with the root module, so it gets resolved
440
            // when the main query has been compiled.
441
            } else {
442
                fc = new FunctionCall(((ExternalModule) module).getContext(), qname, params);
1✔
443
                fc.setLocation(ast.getLine(), ast.getColumn());
1✔
444
                if(((ExternalModule) module).getContext() == context) {
1✔
445
                    context.addForwardReference(fc);
1✔
446
                } else {
1✔
447
                    context.getRootContext().addForwardReference(fc);
1✔
448
                }
449
            }
450
        } else {
1✔
451
            fc = new FunctionCall(context, func);
1✔
452
            fc.setArguments(params);
1✔
453
            fc.setLocation(ast.getLine(), ast.getColumn());
1✔
454
        }
455
        return fc;
1✔
456
    }
457
 
458
    /**
459
     * Wrap a function call into a user defined function.
460
     * This is used to handle dynamic function calls or partial
461
     * function applications on built in functions.
462
     * 
463
     * @param context current context
464
     * @param call the function call to be wrapped
465
     * @return a new function call referencing an inline function
466
     * @throws XPathException in case of a static error
467
     */
468
    public static FunctionCall wrap(XQueryContext context, Function call) throws XPathException {
469
                final int argCount = call.getArgumentCount();
1✔
470
                final QName[] variables = new QName[argCount];
1✔
471
                final List<Expression> innerArgs = new ArrayList<>(argCount);
1✔
472
                final List<Expression> wrapperArgs = new ArrayList<>(argCount);
1✔
473
                final FunctionSignature signature = call.getSignature();
1✔
474
                // the parameters of the newly created inline function:
475
                final List<SequenceType> newParamTypes = new ArrayList<>();
1✔
476
                final SequenceType[] paramTypes = signature.getArgumentTypes();
1✔
477
                for (int i = 0; i < argCount; i++) {
1✔
478
                        final Expression param = call.getArgument(i);
1✔
479
                        wrapperArgs.add(param);
1✔
480
                        QName varName = new QName("vp" + i, XMLConstants.NULL_NS_URI);
1✔
481
                        variables[i] = varName;
1✔
482
                        final VariableReference ref = new VariableReference(context, varName);
1✔
483
                        innerArgs.add(ref);
1✔
484
                        
485
                        // copy parameter sequence types
486
                        // overloaded functions like concat may have an arbitrary number of arguments
487
                        if (i < paramTypes.length)
1✔
488
                                {newParamTypes.add(paramTypes[i]);}
1✔
489
                        else
490
                                // overloaded function: add last sequence type
491
                                {newParamTypes.add(paramTypes[paramTypes.length - 1]);}
1✔
492
                }
493
                final SequenceType[] newParamArray = newParamTypes.toArray(new SequenceType[0]);
1✔
494
                final FunctionSignature newSignature = new FunctionSignature(signature);
1✔
495
                newSignature.setArgumentTypes(newParamArray);
1✔
496

497
                final UserDefinedFunction func = new UserDefinedFunction(context, newSignature);
1✔
498
                for (final QName varName: variables) {
1✔
499
                        func.addVariable(varName);
1✔
500
                }
501
                
502
                call.setArguments(innerArgs);
1✔
503
                
504
                func.setFunctionBody(call);
1✔
505
                
506
                final FunctionCall wrappedCall = new FunctionCall(context, func);
1✔
507
                wrappedCall.setArguments(wrapperArgs);
1✔
508
                return wrappedCall;
1✔
509
        }
510
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc