OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 132 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
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
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.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.sql.model;
15
 
142 ilm 16
import org.openconcerto.sql.model.SQLSelect.LockStrength;
17 ilm 17
import org.openconcerto.utils.Tuple2;
18
 
19
import java.sql.ResultSet;
20
import java.sql.SQLException;
21
import java.util.ArrayList;
83 ilm 22
import java.util.Collections;
93 ilm 23
import java.util.HashSet;
17 ilm 24
import java.util.List;
93 ilm 25
import java.util.Set;
17 ilm 26
 
27
import org.apache.commons.dbutils.ResultSetHandler;
28
 
29
public final class SQLRowListRSH implements ResultSetHandler {
30
 
63 ilm 31
    // hashCode()/equals() needed for data source cache
83 ilm 32
    public static final class RSH implements ResultSetHandler {
63 ilm 33
        private final Tuple2<SQLTable, List<String>> names;
34
 
83 ilm 35
        // allow to create rows from arbitrary columns (and not just directly from actual fields of
36
        // the same table)
37
        // ATTN doesn't check that the types of columns are coherent with the types of the fields
38
        public RSH(final SQLTable t, final List<String> names) {
39
            this(Tuple2.create(t, names));
40
            if (!t.getFieldsName().containsAll(names))
41
                throw new IllegalArgumentException("Not all names are fields of " + t + " : " + names);
42
        }
43
 
63 ilm 44
        private RSH(Tuple2<SQLTable, List<String>> names) {
45
            this.names = names;
46
        }
47
 
48
        @Override
49
        public List<SQLRow> handle(ResultSet rs) throws SQLException {
83 ilm 50
            // since the result will be cached, disallow its modification (e.g.avoid
51
            // ConcurrentModificationException)
52
            return Collections.unmodifiableList(SQLRow.createListFromRS(this.names.get0(), rs, this.names.get1()));
63 ilm 53
        }
54
 
55
        @Override
56
        public int hashCode() {
57
            return this.names.hashCode();
58
        }
59
 
60
        @Override
61
        public boolean equals(Object obj) {
62
            if (this == obj)
63
                return true;
64
            if (obj == null)
65
                return false;
66
            if (getClass() != obj.getClass())
67
                return false;
68
            final RSH other = (RSH) obj;
69
            return this.names.equals(other.names);
70
        }
71
    }
72
 
83 ilm 73
    private static TableRef checkTable(final TableRef t) {
74
        if (t == null)
75
            throw new IllegalArgumentException("null table");
76
        if (!t.getTable().isRowable())
77
            throw new IllegalArgumentException("table isn't rowable : " + t);
78
        return t;
79
    }
80
 
93 ilm 81
    static Tuple2<SQLTable, List<String>> getIndexes(SQLSelect sel, final TableRef passedTable, final boolean findTable) {
83 ilm 82
        final List<FieldRef> selectFields = sel.getSelectFields();
17 ilm 83
        final int size = selectFields.size();
84
        if (size == 0)
85
            throw new IllegalArgumentException("empty select : " + sel);
83 ilm 86
        TableRef t;
17 ilm 87
        if (findTable) {
88
            if (passedTable != null)
89
                throw new IllegalArgumentException("non null table " + passedTable);
83 ilm 90
            t = null;
17 ilm 91
        } else {
83 ilm 92
            t = checkTable(passedTable);
17 ilm 93
        }
94
        final List<String> l = new ArrayList<String>(size);
95
        for (int i = 0; i < size; i++) {
83 ilm 96
            final FieldRef field = selectFields.get(i);
97
            if (field == null) {
98
                // computed field
17 ilm 99
                l.add(null);
83 ilm 100
            } else {
101
                if (t == null) {
102
                    assert findTable;
103
                    t = checkTable(field.getTableRef());
104
                }
105
                assert t != null && t.getTable().isRowable();
106
 
107
                if (field.getTableRef().equals(t)) {
108
                    l.add(field.getField().getName());
109
                } else if (findTable) {
110
                    // prevent ambiguity : either specify a table or there must be only one table
111
                    throw new IllegalArgumentException(field + " is not in " + t);
112
                } else {
113
                    l.add(null);
114
                }
115
            }
17 ilm 116
        }
83 ilm 117
        return Tuple2.create(t.getTable(), l);
17 ilm 118
    }
119
 
120
    /**
121
     * Create a handler that don't need metadata.
122
     *
123
     * @param sel the select that will produce the result set, must only have one table.
124
     * @return a handler creating a list of {@link SQLRow}.
93 ilm 125
     * @deprecated use {@link SQLSelectHandlerBuilder}
17 ilm 126
     */
127
    static public ResultSetHandler createFromSelect(final SQLSelect sel) {
128
        return create(getIndexes(sel, null, true));
129
    }
130
 
131
    /**
132
     * Create a handler that don't need metadata. Useful since some JDBC drivers perform queries for
133
     * each metadata.
134
     *
135
     * @param sel the select that will produce the result set.
83 ilm 136
     * @param t the table for which to create rows.
17 ilm 137
     * @return a handler creating a list of {@link SQLRow}.
93 ilm 138
     * @deprecated use {@link SQLSelectHandlerBuilder}
17 ilm 139
     */
83 ilm 140
    static public ResultSetHandler createFromSelect(final SQLSelect sel, final TableRef t) {
17 ilm 141
        return create(getIndexes(sel, t, false));
142
    }
143
 
93 ilm 144
    static ResultSetHandler create(final Tuple2<SQLTable, List<String>> names) {
63 ilm 145
        return new RSH(names);
17 ilm 146
    }
147
 
93 ilm 148
    /**
149
     * Execute the passed select and return rows. NOTE if there's more than one table in the query
150
     * {@link #execute(SQLSelect, TableRef)} must be used.
151
     *
152
     * @param sel the query to execute.
153
     * @return rows.
154
     * @throws IllegalArgumentException if there's more than one table in the query.
155
     */
156
    static public List<SQLRow> execute(final SQLSelect sel) throws IllegalArgumentException {
157
        return execute(sel, true, true);
17 ilm 158
    }
159
 
93 ilm 160
    static public List<SQLRow> execute(final SQLSelect sel, final boolean readCache, final boolean writeCache) {
161
        return new SQLSelectHandlerBuilder(sel).setReadCache(readCache).setWriteCache(writeCache).execute();
162
    }
163
 
164
    /**
165
     * Execute the passed select and return rows of <code>t</code>. NOTE if there's only one table
166
     * in the query {@link #execute(SQLSelect)} should be used.
167
     *
168
     * @param sel the query to execute.
169
     * @param t the table to use.
170
     * @return rows of <code>t</code>.
171
     * @throws NullPointerException if <code>t</code> is <code>null</code>.
172
     */
173
    static public List<SQLRow> execute(final SQLSelect sel, final TableRef t) throws NullPointerException {
174
        return new SQLSelectHandlerBuilder(sel).setTableRef(t).execute();
175
    }
176
 
177
    static IResultSetHandler createFromSelect(final SQLSelect sel, final Tuple2<SQLTable, List<String>> indexes, final boolean readCache, final boolean writeCache) {
178
        final Set<SQLTable> tables = new HashSet<SQLTable>();
179
        // not just tables of the fields of the SELECT clause since inner joins can change the rows
180
        // returned
181
        for (final TableRef ref : sel.getTableRefs().values()) {
182
            tables.add(ref.getTable());
183
        }
184
 
142 ilm 185
        // the SELECT requesting a lock means the caller expects the DB to be accessed
186
        final boolean acquireLock = sel.getLockStrength() != LockStrength.NONE;
187
        return new IResultSetHandler(create(indexes), readCache && !acquireLock, writeCache && !acquireLock) {
93 ilm 188
            @Override
189
            public Set<? extends SQLData> getCacheModifiers() {
190
                return tables;
191
            }
192
        };
193
    }
194
 
17 ilm 195
    private final SQLTable t;
196
    private final boolean tableOnly;
197
 
198
    public SQLRowListRSH(SQLTable t) {
199
        this(t, false);
200
    }
201
 
202
    public SQLRowListRSH(SQLTable t, final boolean tableOnly) {
203
        super();
204
        this.t = t;
205
        this.tableOnly = tableOnly;
206
    }
207
 
208
    public Object handle(ResultSet rs) throws SQLException {
209
        return SQLRow.createListFromRS(this.t, rs, this.tableOnly);
210
    }
211
}