001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.storage.sql.jdbc;
020
021import java.io.Serializable;
022import java.sql.PreparedStatement;
023import java.sql.ResultSet;
024import java.sql.SQLException;
025import java.util.ArrayList;
026import java.util.Iterator;
027import java.util.List;
028
029import org.nuxeo.ecm.core.storage.sql.Model;
030import org.nuxeo.ecm.core.storage.sql.RowMapper.RowUpdate;
031import org.nuxeo.ecm.core.storage.sql.jdbc.db.Column;
032
033/**
034 * Collection IO for arrays of scalar values.
035 */
036public class ScalarCollectionIO implements CollectionIO {
037
038    /** Whether we always insert all the rows in the row update or just the values starting from pos. */
039    protected final boolean insertAll;
040
041    public ScalarCollectionIO(boolean insertAll) {
042        this.insertAll = insertAll;
043    }
044
045    @Override
046    public Serializable getCurrentFromResultSet(ResultSet rs, List<Column> columns, Model model,
047            Serializable[] returnId, int[] returnPos) throws SQLException {
048        Serializable id = null;
049        Serializable value = null;
050        int i = 0;
051        for (Column column : columns) {
052            i++;
053            String key = column.getKey();
054            Serializable v = column.getFromResultSet(rs, i);
055            if (key.equals(model.MAIN_KEY)) {
056                id = v;
057            } else if (key.equals(model.COLL_TABLE_POS_KEY)) {
058                // (the pos column is ignored, results are already ordered by id
059                // then pos)
060            } else if (key.equals(model.COLL_TABLE_VALUE_KEY)) {
061                value = v;
062            } else {
063                throw new RuntimeException(key);
064            }
065        }
066        Serializable prevId = returnId[0];
067        returnId[0] = id;
068        int pos = (id != null && !id.equals(prevId)) ? 0 : returnPos[0] + 1;
069        returnPos[0] = pos;
070        return value;
071    }
072
073    @Override
074    public void executeInserts(PreparedStatement ps, List<RowUpdate> rowus, List<Column> columns,
075            boolean supportsBatchUpdates, String sql, JDBCConnection connection) throws SQLException {
076        List<Serializable> debugValues = connection.logger.isLogEnabled() ? new ArrayList<Serializable>() : null;
077        boolean batched = supportsBatchUpdates && rowus.size() > 1;
078        String loggedSql = batched ? sql + " -- BATCHED" : sql;
079        int batch = 0;
080        for (Iterator<RowUpdate> rowIt = rowus.iterator(); rowIt.hasNext();) {
081            RowUpdate rowu = rowIt.next();
082            int start;
083            if (rowu.pos == -1 || insertAll) {
084                start = 0;
085            } else {
086                start = rowu.pos;
087            }
088            Serializable id = rowu.row.id;
089            Serializable[] array = rowu.row.values;
090            for (int i = start; i < array.length; i++) {
091                int n = 0;
092                for (Column column : columns) {
093                    n++;
094                    String key = column.getKey();
095                    Serializable v;
096                    if (key.equals(Model.MAIN_KEY)) {
097                        v = id;
098                    } else if (key.equals(Model.COLL_TABLE_POS_KEY)) {
099                        v = Long.valueOf((long) i);
100                    } else if (key.equals(Model.COLL_TABLE_VALUE_KEY)) {
101                        v = array[i];
102                    } else {
103                        throw new RuntimeException(key);
104                    }
105                    column.setToPreparedStatement(ps, n, v);
106                    if (debugValues != null) {
107                        debugValues.add(v);
108                    }
109                }
110                if (debugValues != null) {
111                    connection.logger.logSQL(loggedSql, debugValues);
112                    debugValues.clear();
113                }
114                if (batched) {
115                    ps.addBatch();
116                    batch++;
117                    if (batch % JDBCRowMapper.UPDATE_BATCH_SIZE == 0 || !rowIt.hasNext()) {
118                        ps.executeBatch();
119                        connection.countExecute();
120                    }
121                } else {
122                    ps.execute();
123                    connection.countExecute();
124                }
125            }
126        }
127    }
128
129}