OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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