• 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

25.0
/extensions/modules/sql/src/main/java/org/exist/xquery/modules/sql/GetConnectionFunction.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
package org.exist.xquery.modules.sql;
25

26
import com.zaxxer.hikari.HikariDataSource;
27
import org.apache.logging.log4j.LogManager;
28
import org.apache.logging.log4j.Logger;
29

30
import org.exist.dom.QName;
31
import org.exist.util.ParametersExtractor;
32
import org.exist.xquery.*;
33
import org.exist.xquery.value.FunctionParameterSequenceType;
34
import org.exist.xquery.value.FunctionReturnSequenceType;
35
import org.exist.xquery.value.IntegerValue;
36
import org.exist.xquery.value.NodeValue;
37
import org.exist.xquery.value.Sequence;
38
import org.exist.xquery.value.Type;
39

40
import java.sql.Connection;
41
import java.sql.DriverManager;
42
import java.sql.SQLException;
43

44
import java.util.Properties;
45

46
import static org.exist.xquery.FunctionDSL.*;
47
import static org.exist.xquery.modules.sql.SQLModule.NAMESPACE_URI;
48
import static org.exist.xquery.modules.sql.SQLModule.PREFIX;
49

50

51
/**
52
 * SQL Module Extension function for XQuery to retrieve a connection.
53
 *
54
 * @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
55
 */
56
public class GetConnectionFunction extends BasicFunction {
57
    private static final FunctionReturnSequenceType RETURN_TYPE = returnsOpt(Type.LONG, "an xs:long representing the connection handle. The connection will be closed (or returned to the pool) automatically when the calling XQuery finishes execution, if you need to return it sooner you can call sql:close-connection#1");
1✔
58
    private static final FunctionParameterSequenceType JDBC_PASSWORD_PARAM = param("password", Type.STRING, "The SQL database password");
1✔
59
    private static final FunctionParameterSequenceType JDBC_USERNAME_PARAM = param("username", Type.STRING, "The SQL database username");
1✔
60
    private static final FunctionParameterSequenceType JDBC_PROPERTIES_PARAM = optParam("properties", Type.ELEMENT, "The JDBC database connection properties in the form <properties><property name=\"\" value=\"\"/></properties>.");
1✔
61
    private static final FunctionParameterSequenceType JDBC_URL_PARAM = param("url", Type.STRING, "The JDBC connection URL");
1✔
62
    private static final FunctionParameterSequenceType JDBC_DRIVER_CLASSNAME_PARAM = param("driver-classname", Type.STRING, "The JDBC driver classname");
1✔
63
    private static final FunctionParameterSequenceType CONNECTION_POOL_PARAM = param("pool-name", Type.STRING, "The connection pool name (as configured in conf.xml)");
1✔
64

65
    private static final Logger LOGGER = LogManager.getLogger(GetConnectionFunction.class);
1✔
66

67
    private static final String FN_GET_CONNECTION = "get-connection";
68
    public static final FunctionSignature[] FS_GET_CONNECTION = functionSignatures(
1✔
69
        FN_GET_CONNECTION,
70
        "Opens a connection to a SQL Database",
71
        RETURN_TYPE,
72
        arities(
1✔
73
                arity(JDBC_DRIVER_CLASSNAME_PARAM, JDBC_URL_PARAM),
1✔
74
                arity(JDBC_DRIVER_CLASSNAME_PARAM, JDBC_URL_PARAM, JDBC_PROPERTIES_PARAM),
1✔
75
                arity(JDBC_DRIVER_CLASSNAME_PARAM, JDBC_URL_PARAM, JDBC_USERNAME_PARAM, JDBC_PASSWORD_PARAM)
1✔
76
        )
77
    );
78

79
    private static final String FN_GET_CONNECTION_FROM_POOL = "get-connection-from-pool";
80
    public static final FunctionSignature[] FS_GET_CONNECTION_FROM_POOL = functionSignatures(
1✔
81
            FN_GET_CONNECTION_FROM_POOL,
82
            "Retrieves a connection to a SQL Database from a connection pool",
83
            RETURN_TYPE,
84
            arities(
1✔
85
                    arity(CONNECTION_POOL_PARAM),
1✔
86
                    arity(CONNECTION_POOL_PARAM, JDBC_USERNAME_PARAM, JDBC_PASSWORD_PARAM)
1✔
87
            )
88
    );
89

90
    public GetConnectionFunction(final XQueryContext context, final FunctionSignature signature) {
91
        super(context, signature);
×
92
    }
×
93

94
    /**
95
     * Evaluate the call to the xquery get-connection() or get-connection-from-pool() functions,
96
     * it is really the main entry point of this class.
97
     *
98
     * @param args arguments from the get-connection() function call
99
     * @param contextSequence the Context Sequence to operate on (not used here internally!)
100
     *
101
     * @return A xs:long representing a handle to the connection
102
     *
103
     * @throws XPathException if an error occurs.
104
     */
105
    @Override
106
    public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
107
        final Connection connection;
108
        if (isCalledAs(FN_GET_CONNECTION)) {
×
109
            // was a db driver and url specified?
110
            if (args[0].isEmpty() || args[1].isEmpty()) {
×
111
                return Sequence.EMPTY_SEQUENCE;
×
112
            }
113
            connection = getConnection(args);
×
114

115
        } else if (isCalledAs(FN_GET_CONNECTION_FROM_POOL)) {
×
116
            connection = getConnectionFromPool(args);
×
117

118
        } else {
119
            throw new XPathException(this, "No function: " + getName() + "#" + getSignature().getArgumentCount());
×
120
        }
121

122
        // store the Connection and return the uid handle of the Connection
123
        return new IntegerValue(this, SQLModule.storeConnection(context, connection), Type.LONG);
×
124
    }
125

126
    private Connection getConnection(final Sequence[] args) throws XPathException {
127
        // get the db connection details
128
        final String dbURL = args[1].getStringValue();
×
129

130
        try {
131

132
            if (args.length == 2) {
×
133

134
                // try and get the connection
135
                return DriverManager.getConnection(dbURL);
×
136

137
            } else if (args.length == 3) {
×
138

139
                // try and get the connection
140
                final Properties props = ParametersExtractor.parseProperties(((NodeValue) args[2].itemAt(0)).getNode());
×
141
                return DriverManager.getConnection(dbURL, props);
×
142

143
            } else if (args.length == 4) {
×
144
                final String dbUser = args[2].getStringValue();
×
145
                final String dbPassword = args[3].getStringValue();
×
146

147
                // try and get the connection
148
                return DriverManager.getConnection(dbURL, dbUser, dbPassword);
×
149

150
            } else {
151
                throw new XPathException(this, "No function: " + getName() + "#" + getSignature().getArgumentCount());
×
152
            }
153

154
        } catch (final SQLException sqle) {
×
155
            LOGGER.error("sql:get-connection() Cannot connect to database: {}", dbURL, sqle);
×
156
            throw new XPathException(this, "sql:get-connection() Cannot connect to database: " + dbURL, sqle);
×
157
        }
158
    }
159

160
    private Connection getConnectionFromPool(final Sequence[] args) throws XPathException {
161
        final String poolName = args[0].getStringValue();
×
162
        final HikariDataSource pool = SQLModule.getPool(poolName);
×
163
        if (pool == null) {
×
164
            throw new XPathException(this, "There is no configured connection pool named: " + poolName);
×
165
        }
166

167
        try {
168
            if (args.length == 3) {
×
169
                final String username = args[1].getStringValue();
×
170
                final String password = args[2].getStringValue();
×
171
                return pool.getConnection(username, password);
×
172
            } else {
173
                return pool.getConnection();
×
174
            }
175
        } catch (final SQLException sqle) {
×
176
            LOGGER.error("sql:get-connection-from-pool() Cannot retrieve connection from pool: " + poolName, sqle);
×
177
            throw new XPathException(this, "sql:get-connection-from-pool() Cannot retrieve connection from pool: " + poolName, sqle);
×
178
        }
179
    }
180

181
    private static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) {
182
        return FunctionDSL.functionSignatures(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, variableParamTypes);
1✔
183
    }
184
}
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