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

torand / FasterSQL / 16990059345

15 Aug 2025 12:34PM UTC coverage: 66.782% (-6.6%) from 73.399%
16990059345

push

github

torand
chore: access central snapshots

294 of 598 branches covered (49.16%)

Branch coverage included in aggregate %.

1638 of 2295 relevant lines covered (71.37%)

3.83 hits per line

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

90.0
/src/main/java/io/github/torand/fastersql/dialect/Dialect.java
1
/*
2
 * Copyright (c) 2024-2025 Tore Eide Andersen
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package io.github.torand.fastersql.dialect;
17

18
import io.github.torand.fastersql.function.singlerow.cast.DataType;
19
import io.github.torand.fastersql.setoperation.SetOperator;
20

21
import java.sql.Connection;
22
import java.sql.SQLException;
23
import java.util.List;
24
import java.util.Optional;
25
import java.util.stream.IntStream;
26

27
import static io.github.torand.javacommons.collection.ArrayHelper.nonEmpty;
28
import static java.util.stream.Collectors.joining;
29

30
/**
31
 * Defines an SQL dialect as implemented by a specific database vendor.
32
 */
33
public interface Dialect {
34
    /**
35
     * Gets the name of the RDBMS product associated with this SQL dialect.
36
     * @return the name of the RDBMS product.
37
     */
38
    String getProductName();
39

40
    /**
41
     * Indicates whether <i>offset</i> clause must be specified before <i>limit</i> clause; if supported.
42
     * @return whether <i>offset</i> clause must be specified before <i>limit</i> clause; if supported.
43
     */
44
    boolean offsetBeforeLimit();
45

46
    /**
47
     * Returns the <i>row offset</i> clause formatted for a specific SQL dialect.
48
     * @return the <i>row offset</i> clause formatted for a specific SQL dialect.
49
     */
50
    Optional<String> formatRowOffsetClause();
51

52
    /**
53
     * Returns the <i>row limit</i> clause formatted for a specific SQL dialect.
54
     * @return the <i>row limit</i> clause formatted for a specific SQL dialect.
55
     */
56
    Optional<String> formatRowLimitClause();
57

58
    /**
59
     * Returns the <i>row number</i> literal formatted for a specific SQL dialect.
60
     * @return the <i>row number</i> literal formatted for a specific SQL dialect.
61
     */
62
    Optional<String> formatRowNumLiteral();
63

64
    /**
65
     * Returns the specified set operator formatted for a specific SQL dialect.
66
     * @param setOperator the set operator.
67
     * @return the set operator for a specific SQL dialect.
68
     */
69
    default String formatSetOperator(SetOperator setOperator) {
70
        return setOperator.sql();
3✔
71
    }
72

73
    /**
74
     * Returns the 'to_number' function formatted for a specific SQL dialect.
75
     * @param operand the string expression to be evaluated as a number
76
     * @param precision the precision that represents the number of significant digits
77
     * @param scale the scale that that represents the number of digits after the decimal point. Must be less than or equal to the precision.
78
     * @return the 'to_number' function for a specific SQL dialect.
79
     */
80
    String formatToNumberFunction(String operand, int precision, int scale);
81

82
    /**
83
     * Returns the 'to_char' function formatted for a specific SQL dialect.
84
     * @param operand the expression to be evaluated as a string
85
     * @param format the vendor-specific format mask
86
     * @return the 'to_char' function for a specific SQL dialect.
87
     */
88
    String formatToCharFunction(String operand, String format);
89

90
    /**
91
     * Returns the 'substring' function formatted for a specific SQL dialect.
92
     * @param operand the string expression to get substring from
93
     * @param startPos the start position (1-based) of the substring
94
     * @param length the length of the substring
95
     * @return the 'substring' function for a specific SQL dialect.
96
     */
97
    String formatSubstringFunction(String operand, int startPos, int length);
98

99
    /**
100
     * Returns the 'concat' function formatted for a specific SQL dialect.
101
     * @param operands the string expressions to concatenate
102
     * @return the 'concat' function for a specific SQL dialect.
103
     */
104
    String formatConcatFunction(List<String> operands);
105

106
    /**
107
     * Returns the 'length' function formatted for a specific SQL dialect.
108
     * @param operand the string expression to get length of
109
     * @return the 'length' function for a specific SQL dialect.
110
     */
111
    String formatLengthFunction(String operand);
112

113
    /**
114
     * Returns the 'ceil' function formatted for a specific SQL dialect.
115
     * @param operand the numeric expression to get ceiling of
116
     * @return the 'ceil' function for a specific SQL dialect.
117
     */
118
    String formatCeilFunction(String operand);
119

120
    /**
121
     * Returns the 'ln' function formatted for a specific SQL dialect.
122
     * @param operand the numeric expression to get natural logarithm of
123
     * @return the 'ln' function for a specific SQL dialect.
124
     */
125
    String formatLnFunction(String operand);
126

127
    /**
128
     * Returns the 'pow' function formatted for a specific SQL dialect.
129
     * @param base the numeric expression for base operand
130
     * @param exponent the numeric expression for exponent operand
131
     * @return the 'pow' function for a specific SQL dialect.
132
     */
133
    default String formatPowerFunction(String base, String exponent) {
134
        return "power(%s, %s)".formatted(base, exponent);
13✔
135
    }
136

137
    /**
138
     * Returns the 'round' function formatted for a specific SQL dialect.
139
     * @param operand the numeric expression to perform rounding on
140
     * @return the 'round' function for a specific SQL dialect.
141
     */
142
    String formatRoundFunction(String operand);
143

144
    /**
145
     * Returns the 'mod' function formatted for a specific SQL dialect.
146
     * @param divisor the numeric expression for divisor operand
147
     * @param dividend the numeric expression for dividend operand
148
     * @return the 'mod' function for a specific SQL dialect.
149
     */
150
    String formatModuloFunction(String divisor, String dividend);
151

152
    /**
153
     * Returns the 'current_date' system function formatted for a specific SQL dialect.
154
     * @return the 'current_date' function for a specific SQL dialect.
155
     */
156
    String formatCurrentDateFunction();
157

158
    /**
159
     * Returns the 'cast' function formatted for a specific SQL dialect.
160
     * @param operand  the expression to cast.
161
     * @param targetType the data type to cast to.
162
     * @return the 'cast' function formatted for a specific SQL dialect.
163
     */
164
    default String formatCastFunction(String operand, DataType targetType) {
165
        String dataType = getDataType(targetType).orElseThrow(
9✔
166
            () -> new UnsupportedOperationException("%s does not support the %s data type".formatted(getProductName(), targetType.getIsoDataType().name())));
×
167

168
        if (nonEmpty(targetType.getArgs())) {
4✔
169
            String args = IntStream.of(targetType.getArgs()).boxed().map(Object::toString).collect(joining(", "));
11✔
170
            dataType += "(" + args + ")";
4✔
171
        }
172

173
        return "cast(%s as %s)".formatted(operand, dataType);
13✔
174
    }
175

176
    /**
177
     * Returns the data type for a specific SQL dialect.
178
     * @param dataType the ISO data type
179
     * @return the data type for a specific SQL dialect.
180
     */
181
    Optional<String> getDataType(DataType dataType);
182

183
    /**
184
     * Returns the string concatenation operator for a specific SQL Dialect.
185
     * @return the string concatenation operator for a specific SQL Dialect.
186
     */
187
    Optional<String> getConcatOperator();
188

189
    /**
190
     * Indicates whether a capability is supported by a specific SQL dialect.
191
     * @param capability the capability to check support for
192
     * @return true if specified capability is supported; else false
193
     */
194
    boolean supports(Capability capability);
195

196
    /**
197
     * Creates the {@link Dialect} instance corresponding to database vendor associated with specified connection.
198
     * @param connection the connection.
199
     * @return the {@link Dialect} instance.
200
     */
201
    static Dialect fromConnection(Connection connection) {
202
        try {
203
            String productName = connection.getMetaData().getDatabaseProductName().toLowerCase();
5✔
204

205
            if (productName.contains("h2")) {
4✔
206
                return new H2Dialect().withCustomizations(connection);
6✔
207
            } else if (productName.contains("mysql")) {
4✔
208
                return new MySqlDialect();
4✔
209
            } else if (productName.contains("mariadb")) {
4✔
210
                return new MariaDbDialect();
4✔
211
            } else if (productName.contains("postgresql")) {
4✔
212
                return new PostgreSqlDialect();
4✔
213
            } else if (productName.contains("oracle")) {
4✔
214
                return new OracleDialect();
4✔
215
            } else if (productName.contains("sql server")) {
4✔
216
                return new SqlServerDialect();
4✔
217
            } else if (productName.contains("access")) {
4✔
218
                return new AccessDialect();
4✔
219
            } else if (productName.contains("sqlite")) {
4✔
220
                return new SqliteDialect();
4✔
221
            } else if (productName.contains("hsql")) {
4!
222
                return new HsqldbDialect();
4✔
223
            } else {
224
                throw new UnsupportedOperationException("Database with product name " + productName + " not supported");
×
225
            }
226
        } catch (SQLException e) {
×
227
            throw new RuntimeException("Failed to detect SQL dialect from connection metadata", e);
×
228
        }
229
    }
230
}
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

© 2026 Coveralls, Inc