OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 149 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 149 Rev 182
Line 1... Line 1...
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
9
 * language governing permissions and limitations under the License.
Line 13... Line 13...
13
 
13
 
14
 package org.openconcerto.sql.model;
14
 package org.openconcerto.sql.model;
15
 
15
 
16
import org.openconcerto.utils.CollectionUtils;
16
import org.openconcerto.utils.CollectionUtils;
17
import org.openconcerto.utils.StringUtils;
17
import org.openconcerto.utils.StringUtils;
18
import org.openconcerto.utils.cc.ITransformer;
-
 
19
 
18
 
20
import java.util.ArrayList;
19
import java.util.ArrayList;
21
import java.util.Arrays;
20
import java.util.Arrays;
22
import java.util.Collection;
21
import java.util.Collection;
23
import java.util.Collections;
22
import java.util.Collections;
24
import java.util.List;
23
import java.util.List;
25
import java.util.Map;
24
import java.util.Map;
26
import java.util.Map.Entry;
25
import java.util.Map.Entry;
27
 
-
 
-
 
26
import java.util.Objects;
28
import org.apache.commons.collections.functors.InstanceofPredicate;
27
import java.util.stream.Collectors;
29
 
28
 
30
import net.jcip.annotations.Immutable;
29
import net.jcip.annotations.Immutable;
31
 
30
 
32
/**
31
/**
33
 * Une clause WHERE dans une requete SQL. Une clause peut être facilement combinée avec d'autre,
32
 * Une clause WHERE dans une requete SQL. Une clause peut être facilement combinée avec d'autre,
Line 125... Line 124...
125
 
124
 
126
    static public Where notInSubqueries(final FieldRef ref, final List<String> subQueries) {
125
    static public Where notInSubqueries(final FieldRef ref, final List<String> subQueries) {
127
        return subqueries(ref, false, subQueries);
126
        return subqueries(ref, false, subQueries);
128
    }
127
    }
129
 
128
 
-
 
129
    static public Where inValues(final FieldRef ref, final Collection<?> values) {
-
 
130
        return compareValues(ref, RowComparison.IN, values);
-
 
131
    }
-
 
132
 
-
 
133
    static public Where notInValues(final FieldRef ref, final Collection<?> values) {
-
 
134
        return compareValues(ref, RowComparison.NOT_IN, values);
-
 
135
    }
-
 
136
 
-
 
137
    static public Where compareValues(final FieldRef ref, final RowComparison cmp, final Collection<?> values) {
-
 
138
        return compareValues(ref, cmp, NullValue.IS_FORBIDDEN, values);
-
 
139
    }
-
 
140
 
-
 
141
    static public Where compareValues(final FieldRef ref, final RowComparison cmp, final NullValue nullMode, final Collection<?> values) {
-
 
142
        if (values.isEmpty()) {
-
 
143
            return cmp == RowComparison.IN ? FALSE : TRUE;
-
 
144
        }
-
 
145
        return createRaw(getCompareValuesClause(ref.getFieldRef(), cmp, nullMode, values, ref.getField().getType()), ref);
-
 
146
    }
-
 
147
 
130
    /**
148
    /**
131
     * Create a Where for a field value contained or not contained in sub-queries.
149
     * Create a Where for a field value contained or not contained in sub-queries.
132
     * 
150
     * 
133
     * @param ref the field.
151
     * @param ref the field.
134
     * @param in <code>true</code> if the field should be contained in the sub-queries.
152
     * @param in <code>true</code> if the field should be contained in the sub-queries.
Line 151... Line 169...
151
    }
169
    }
152
 
170
 
153
    /**
171
    /**
154
     * To create complex Where not possible with constructors.
172
     * To create complex Where not possible with constructors.
155
     * 
173
     * 
-
 
174
     * @param s the syntax to use.
156
     * @param pattern a pattern to be passed to {@link SQLSelect#quote(String, Object...)}, eg
175
     * @param pattern a pattern to be passed to {@link SQLBase#quoteStd(String, Object...)}, eg
157
     *        "EXTRACT(YEAR FROM %n) = 3007".
176
     *        "EXTRACT(YEAR FROM %n) = 3007".
158
     * @param params the params to be passed to <code>quote()</code>, eg [|MISSION.DATE_DBT|].
177
     * @param params the params to be passed to <code>quote()</code>, eg [|MISSION.DATE_DBT|].
159
     * @return a new Where with the result from <code>quote()</code> as its clause, and all
178
     * @return a new Where with the result from <code>quote()</code> as its clause, and all
160
     *         <code>FieldRef</code> in params as its fields, eg {EXTRACT(YEAR FROM "DATE_DBT") =
179
     *         <code>FieldRef</code> in params as its fields, eg {EXTRACT(YEAR FROM "DATE_DBT") =
161
     *         3007 , |MISSION.DATE_DBT|}.
180
     *         3007 , |MISSION.DATE_DBT|}.
162
     */
181
     */
-
 
182
    static public Where quote(final SQLSyntax s, final String pattern, final Object... params) {
-
 
183
        final List<FieldRef> fields = new ArrayList<>();
-
 
184
        for (final Object param : params) {
163
    @SuppressWarnings("unchecked")
185
            if (param instanceof FieldRef) {
164
    static public Where quote(final String pattern, final Object... params) {
186
                fields.add((FieldRef) param);
-
 
187
            }
-
 
188
        }
165
        return new Where(SQLSelect.quote(pattern, params), org.apache.commons.collections.CollectionUtils.select(Arrays.asList(params), new InstanceofPredicate(FieldRef.class)));
189
        return new Where(SQLBase.quote(s, pattern, params), fields);
166
    }
190
    }
167
 
191
 
168
    static private final String normalizeOperator(final String op) {
192
    static private final String normalizeOperator(final String op) {
169
        String res = op.trim();
193
        String res = op.trim();
170
        if (res.equals("!="))
194
        if (res.equals("!="))
171
            res = "<>";
195
            res = "<>";
172
        return res;
196
        return res;
173
    }
197
    }
174
 
198
 
175
    static private final String comparison(final FieldRef ref, final String op, final String y) {
199
    static public final String comparison(final FieldRef ref, final String op, final String y) {
-
 
200
        return comparison(null, ref.getField(), ref.getFieldRef(), op, y);
-
 
201
    }
-
 
202
 
-
 
203
    static public final String comparison(final SQLSyntax s, final String x, final String op, final String y) {
-
 
204
        return comparison(Objects.requireNonNull(s, "Missing syntax"), null, x, op, y);
-
 
205
    }
-
 
206
 
-
 
207
    static private final String comparison(SQLSyntax s, final DBStructureItem<?> syntaxSupplier, final String x, final String op, final String y) {
-
 
208
        Objects.requireNonNull(op, "Missing operator");
176
        if (op == NULL_IS_DATA_EQ || op == NULL_IS_DATA_NEQ) {
209
        if (op == NULL_IS_DATA_EQ || op == NULL_IS_DATA_NEQ) {
-
 
210
            if (s == null)
-
 
211
                s = syntaxSupplier.getDBSystemRoot().getSyntax();
177
            return ref.getField().getDBSystemRoot().getSyntax().getNullIsDataComparison(ref.getFieldRef(), op == NULL_IS_DATA_EQ, y);
212
            return s.getNullIsDataComparison(x, op == NULL_IS_DATA_EQ, y);
178
        } else {
213
        } else {
179
            return ref.getFieldRef() + " " + op + " " + y;
214
            return x + ' ' + op + ' ' + y;
180
        }
215
        }
181
    }
216
    }
182
 
217
 
183
    static private final String getInClause(final FieldRef field1, final boolean in, final String inParens) {
218
    static private final String getInClause(final FieldRef field1, final boolean in, final String inParens) {
-
 
219
        return getInClause(field1.getFieldRef(), in ? RowComparison.IN : RowComparison.NOT_IN, inParens);
-
 
220
    }
-
 
221
 
-
 
222
    static private final String getInClause(final String expr, final RowComparison cmp, final String inParens) {
184
        final String op = in ? " in (" : " not in (";
223
        final String op = cmp == RowComparison.IN ? " in (" : " not in (";
185
        return field1.getFieldRef() + op + inParens + ")";
224
        return expr + op + inParens + ')';
-
 
225
    }
-
 
226
 
-
 
227
    static public enum RowComparison {
-
 
228
        IN, NOT_IN
-
 
229
    }
-
 
230
 
-
 
231
    static public enum NullValue {
-
 
232
        IS_DATA, IS_FORBIDDEN, IS_UNKNOWN
-
 
233
    }
-
 
234
 
-
 
235
    static public final String getCompareValuesClause(final String expr, final RowComparison cmp, final Collection<?> values, final SQLType type) {
-
 
236
        return getCompareValuesClause(expr, cmp, NullValue.IS_FORBIDDEN, values, type);
-
 
237
    }
-
 
238
 
-
 
239
    static public final String getCompareValuesClause(final String expr, final RowComparison cmp, final NullValue nullMode, Collection<?> values, final SQLType type) {
-
 
240
        final boolean addNull;
-
 
241
        if (nullMode != NullValue.IS_UNKNOWN && values.contains(null)) {
-
 
242
            if (nullMode == NullValue.IS_FORBIDDEN)
-
 
243
                throw new IllegalArgumentException("Values contains a null value : " + values);
-
 
244
            assert nullMode == NullValue.IS_DATA;
-
 
245
            addNull = true;
-
 
246
        } else {
-
 
247
            addNull = false;
-
 
248
        }
-
 
249
        if (addNull) {
-
 
250
            values = values.stream().filter((i) -> i != null).collect(Collectors.toList());
-
 
251
        }
-
 
252
        String res = getInClause(expr, cmp, CollectionUtils.join(values, ",", (input) -> type.toString(input)));
-
 
253
        if (addNull) {
-
 
254
            if (cmp == RowComparison.IN) {
-
 
255
                res = expr + " is null or " + res;
-
 
256
            } else {
-
 
257
                res = expr + " is not null and " + res;
-
 
258
            }
-
 
259
        }
-
 
260
        return res;
186
    }
261
    }
187
 
262
 
188
    private final List<FieldRef> fields;
263
    private final List<FieldRef> fields;
189
    private final String clause;
264
    private final String clause;
190
 
265
 
Line 224... Line 299...
224
     * Crée une clause "field1 in (values)". Some databases won't accept empty values (impossible
299
     * Crée une clause "field1 in (values)". Some databases won't accept empty values (impossible
225
     * where clause), so we return false.
300
     * where clause), so we return false.
226
     * 
301
     * 
227
     * @param field1 le champs à tester.
302
     * @param field1 le champs à tester.
228
     * @param values les valeurs.
303
     * @param values les valeurs.
-
 
304
     * @deprecated use {@link #inValues(FieldRef, Collection)}
229
     */
305
     */
230
    public Where(final FieldRef field1, final Collection<?> values) {
306
    public Where(final FieldRef field1, final Collection<?> values) {
231
        this(field1, true, values);
307
        this(field1, true, values);
232
    }
308
    }
233
 
309
 
Line 235... Line 311...
235
     * Construct a clause like "field1 not in (value, ...)".
311
     * Construct a clause like "field1 not in (value, ...)".
236
     * 
312
     * 
237
     * @param field1 le champs à tester.
313
     * @param field1 le champs à tester.
238
     * @param in <code>true</code> for "in", <code>false</code> for "not in".
314
     * @param in <code>true</code> for "in", <code>false</code> for "not in".
239
     * @param values les valeurs.
315
     * @param values les valeurs.
-
 
316
     * @deprecated use {@link #inValues(FieldRef, Collection)} or
-
 
317
     *             {@link #notInValues(FieldRef, Collection)}
240
     */
318
     */
241
    public Where(final FieldRef field1, final boolean in, final Collection<?> values) {
319
    public Where(final FieldRef field1, final boolean in, final Collection<?> values) {
242
        if (values.isEmpty()) {
320
        if (values.isEmpty()) {
243
            this.fields = Collections.emptyList();
321
            this.fields = Collections.emptyList();
244
            this.clause = in ? FALSE.getClause() : TRUE.getClause();
322
            this.clause = in ? FALSE.getClause() : TRUE.getClause();
245
        } else {
323
        } else {
246
            this.fields = Collections.singletonList(field1);
324
            this.fields = Collections.singletonList(field1);
247
            this.clause = getInClause(field1, in, CollectionUtils.join(values, ",", new ITransformer<Object, String>() {
325
            this.clause = getCompareValuesClause(field1.getFieldRef(), in ? RowComparison.IN : RowComparison.NOT_IN, values, field1.getField().getType());
248
                @Override
-
 
249
                public String transformChecked(final Object input) {
-
 
250
                    return field1.getField().getType().toString(input);
-
 
251
                }
-
 
252
            }));
-
 
253
        }
326
        }
254
    }
327
    }
255
 
328
 
256
    public Where(final FieldRef field1, final boolean in, final SQLSelect subQuery) {
329
    public Where(final FieldRef field1, final boolean in, final SQLSelect subQuery) {
257
        this.fields = Collections.singletonList(field1);
330
        this.fields = Collections.singletonList(field1);