From e2765eae9621704d85bbdfb55e44b8c806471386 Mon Sep 17 00:00:00 2001 From: lukaseder Date: Thu, 7 May 2015 17:43:09 +0200 Subject: [PATCH] [#4218] Add LoaderSourceStep.loadRows(Iterable) --- .../main/java/org/jooq/LoaderRowsStep.java | 67 ++++++++++ .../main/java/org/jooq/LoaderSourceStep.java | 78 ++++++----- .../java/org/jooq/impl/LoaderErrorImpl.java | 15 ++- .../main/java/org/jooq/impl/LoaderImpl.java | 123 ++++++++++++------ 4 files changed, 207 insertions(+), 76 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/LoaderRowsStep.java diff --git a/jOOQ/src/main/java/org/jooq/LoaderRowsStep.java b/jOOQ/src/main/java/org/jooq/LoaderRowsStep.java new file mode 100644 index 0000000000..96e3bd3276 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/LoaderRowsStep.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2009-2015, Data Geekery GmbH (http://www.datageekery.com) + * All rights reserved. + * + * This work is dual-licensed + * - under the Apache Software License 2.0 (the "ASL") + * - under the jOOQ License and Maintenance Agreement (the "jOOQ License") + * ============================================================================= + * You may choose which license applies to you: + * + * - If you're using this work with Open Source databases, you may choose + * either ASL or jOOQ License. + * - If you're using this work with at least one commercial database, you must + * choose jOOQ License + * + * For more information, please visit http://www.jooq.org/licenses + * + * Apache Software License 2.0: + * ----------------------------------------------------------------------------- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * jOOQ License and Maintenance Agreement: + * ----------------------------------------------------------------------------- + * Data Geekery grants the Customer the non-exclusive, timely limited and + * non-transferable license to install and use the Software under the terms of + * the jOOQ License and Maintenance Agreement. + * + * This library is distributed with a LIMITED WARRANTY. See the jOOQ License + * and Maintenance Agreement for more details: http://www.jooq.org/licensing + */ +package org.jooq; + +import java.util.Collection; + +/** + * The Loader API is used for configuring data loads. + *

+ * The step in constructing the {@link Loader} object where you can set the + * mandatory row loader options. + * + * @author Lukas Eder + */ +public interface LoaderRowsStep> { + + /** + * Specify the the fields to be loaded into the table in the correct order. + */ + @Support + LoaderListenerStep fields(Field... fields); + + /** + * Specify the the fields to be loaded into the table in the correct order. + */ + @Support + LoaderListenerStep fields(Collection> fields); + +} diff --git a/jOOQ/src/main/java/org/jooq/LoaderSourceStep.java b/jOOQ/src/main/java/org/jooq/LoaderSourceStep.java index 931d872aff..4f5d5ee4e6 100644 --- a/jOOQ/src/main/java/org/jooq/LoaderSourceStep.java +++ b/jOOQ/src/main/java/org/jooq/LoaderSourceStep.java @@ -47,6 +47,7 @@ import java.io.Reader; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; +import java.util.Iterator; import org.xml.sax.InputSource; @@ -62,187 +63,202 @@ import org.xml.sax.InputSource; public interface LoaderSourceStep> { /** - * Load CSV data + * Load in-memory data. + */ + LoaderRowsStep loadRows(Object[]... rows); + + /** + * Load in-memory data. + */ + LoaderRowsStep loadRows(Iterable rows); + + /** + * Load in-memory data. + */ + LoaderRowsStep loadRows(Iterator rows); + + /** + * Load CSV data. */ @Support LoaderCSVStep loadCSV(File file) throws FileNotFoundException; /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(File file, String charsetName) throws FileNotFoundException, UnsupportedEncodingException; /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(File file, Charset cs) throws FileNotFoundException; /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(File file, CharsetDecoder dec) throws FileNotFoundException; /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(String data); /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(InputStream stream); /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(InputStream stream, String charsetName) throws UnsupportedEncodingException; /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(InputStream stream, Charset cs); /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(InputStream stream, CharsetDecoder dec); /** - * Load CSV data + * Load CSV data. */ @Support LoaderCSVStep loadCSV(Reader reader); /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(File file) throws FileNotFoundException; /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(File file, String charsetName) throws FileNotFoundException, UnsupportedEncodingException; /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(File file, Charset cs) throws FileNotFoundException; /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(File file, CharsetDecoder dec) throws FileNotFoundException; /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(String data); /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(InputStream stream); /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(InputStream stream, String charsetName) throws UnsupportedEncodingException; /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(InputStream stream, Charset cs); /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(InputStream stream, CharsetDecoder dec); /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(Reader reader); /** - * Load XML data + * Load XML data. */ @Support LoaderXMLStep loadXML(InputSource source); /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(File file) throws FileNotFoundException; /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(File file, String charsetName) throws FileNotFoundException, UnsupportedEncodingException; /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(File file, Charset cs) throws FileNotFoundException; /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(File file, CharsetDecoder dec) throws FileNotFoundException; /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(String data); /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(InputStream stream); /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(InputStream stream, String charsetName) throws UnsupportedEncodingException; /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(InputStream stream, Charset cs); /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(InputStream stream, CharsetDecoder dec); /** - * Load JSON data + * Load JSON data. */ @Support LoaderJSONStep loadJSON(Reader reader); diff --git a/jOOQ/src/main/java/org/jooq/impl/LoaderErrorImpl.java b/jOOQ/src/main/java/org/jooq/impl/LoaderErrorImpl.java index b2cd989c08..328e43f54a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LoaderErrorImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/LoaderErrorImpl.java @@ -54,13 +54,24 @@ class LoaderErrorImpl implements LoaderError { private final String[] row; private final Query query; - LoaderErrorImpl(DataAccessException exception, String[] row, int rowIndex, Query query) { + LoaderErrorImpl(DataAccessException exception, Object[] row, int rowIndex, Query query) { this.exception = exception; - this.row = row; + this.row = strings(row); this.rowIndex = rowIndex; this.query = query; } + private static String[] strings(Object[] row) { + if (row == null) + return null; + + String[] result = new String[row.length]; + for (int i = 0; i < result.length; i++) + result[i] = row[i] == null ? null : row[i].toString(); + + return result; + } + @Override public DataAccessException exception() { return exception; diff --git a/jOOQ/src/main/java/org/jooq/impl/LoaderImpl.java b/jOOQ/src/main/java/org/jooq/impl/LoaderImpl.java index 526750440d..e838b9af8a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LoaderImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/LoaderImpl.java @@ -56,6 +56,7 @@ import java.nio.charset.CharsetDecoder; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -75,6 +76,7 @@ import org.jooq.LoaderJSONOptionsStep; import org.jooq.LoaderJSONStep; import org.jooq.LoaderOptionsStep; import org.jooq.LoaderRowListener; +import org.jooq.LoaderRowsStep; import org.jooq.LoaderXMLStep; import org.jooq.SelectQuery; import org.jooq.Table; @@ -95,6 +97,7 @@ class LoaderImpl> implements // Cascading interface implementations for Loader behaviour LoaderOptionsStep, + LoaderRowsStep, LoaderXMLStep, LoaderCSVStep, LoaderCSVOptionsStep, @@ -104,58 +107,60 @@ class LoaderImpl> implements // Configuration constants // ----------------------- - private static final int ON_DUPLICATE_KEY_ERROR = 0; - private static final int ON_DUPLICATE_KEY_IGNORE = 1; - private static final int ON_DUPLICATE_KEY_UPDATE = 2; + private static final int ON_DUPLICATE_KEY_ERROR = 0; + private static final int ON_DUPLICATE_KEY_IGNORE = 1; + private static final int ON_DUPLICATE_KEY_UPDATE = 2; - private static final int ON_ERROR_ABORT = 0; - private static final int ON_ERROR_IGNORE = 1; + private static final int ON_ERROR_ABORT = 0; + private static final int ON_ERROR_IGNORE = 1; - private static final int COMMIT_NONE = 0; - private static final int COMMIT_AFTER = 1; - private static final int COMMIT_ALL = 2; + private static final int COMMIT_NONE = 0; + private static final int COMMIT_AFTER = 1; + private static final int COMMIT_ALL = 2; - private static final int BATCH_NONE = 0; - private static final int BATCH_AFTER = 1; - private static final int BATCH_ALL = 2; + private static final int BATCH_NONE = 0; + private static final int BATCH_AFTER = 1; + private static final int BATCH_ALL = 2; - private static final int BULK_NONE = 0; - private static final int BULK_AFTER = 1; - private static final int BULK_ALL = 2; + private static final int BULK_NONE = 0; + private static final int BULK_AFTER = 1; + private static final int BULK_ALL = 2; - private static final int CONTENT_CSV = 0; - private static final int CONTENT_XML = 1; - private static final int CONTENT_JSON = 2; + private static final int CONTENT_CSV = 0; + private static final int CONTENT_XML = 1; + private static final int CONTENT_JSON = 2; + private static final int CONTENT_ROWS = 3; // Configuration data // ------------------ - private final DSLContext create; - private final Configuration configuration; - private final Table table; - private int onDuplicate = ON_DUPLICATE_KEY_ERROR; - private int onError = ON_ERROR_ABORT; - private int commit = COMMIT_NONE; - private int commitAfter = 1; - private int batch = BATCH_NONE; - private int batchAfter = 1; - private int bulk = BULK_NONE; - private int bulkAfter = 1; - private int content = CONTENT_CSV; - private BufferedReader data; + private final DSLContext create; + private final Configuration configuration; + private final Table table; + private int onDuplicate = ON_DUPLICATE_KEY_ERROR; + private int onError = ON_ERROR_ABORT; + private int commit = COMMIT_NONE; + private int commitAfter = 1; + private int batch = BATCH_NONE; + private int batchAfter = 1; + private int bulk = BULK_NONE; + private int bulkAfter = 1; + private int content = CONTENT_CSV; + private BufferedReader data; + private Iterator rows; // CSV configuration data // ---------------------- - private int ignoreRows = 1; - private char quote = CSVParser.DEFAULT_QUOTE_CHARACTER; - private char separator = CSVParser.DEFAULT_SEPARATOR; - private String nullString = null; - private Field[] fields; - private boolean[] primaryKey; + private int ignoreRows = 1; + private char quote = CSVParser.DEFAULT_QUOTE_CHARACTER; + private char separator = CSVParser.DEFAULT_SEPARATOR; + private String nullString = null; + private Field[] fields; + private boolean[] primaryKey; // Result data // ----------- private LoaderRowListener listener; - private LoaderContext result = new DefaultLoaderContext(); + private LoaderContext result = new DefaultLoaderContext(); private int ignored; private int processed; private int stored; @@ -275,6 +280,23 @@ class LoaderImpl> implements return this; } + @Override + public final LoaderRowsStep loadRows(Object[]... r) { + return loadRows(Arrays.asList(r)); + } + + @Override + public final LoaderRowsStep loadRows(Iterable r) { + return loadRows(r.iterator()); + } + + @Override + public final LoaderRowsStep loadRows(Iterator r) { + content = CONTENT_ROWS; + this.rows = r; + return this; + } + @Override public final LoaderImpl loadCSV(File file) throws FileNotFoundException { return loadCSV(new FileReader(file)); @@ -520,6 +542,9 @@ class LoaderImpl> implements else if (content == CONTENT_JSON) { executeJSON(); } + else if (content == CONTENT_ROWS) { + executeRows(); + } else { throw new IllegalStateException(); } @@ -573,13 +598,25 @@ class LoaderImpl> implements } } - private void executeSQL(Iterator reader) throws SQLException { - String[] row = null; + private void executeRows() { + try { + executeSQL(rows); + } + + // SQLExceptions originating from rollbacks or commits are always fatal + // They are propagated, and not swallowed + catch (SQLException e) { + throw Utils.translate(null, e); + } + } + + private void executeSQL(Iterator iterator) throws SQLException { + Object[] row = null; BatchBindStep bind = null; InsertQuery insert = null; execution: { - rows: while (reader.hasNext() && ((row = reader.next()) != null)) { + rows: while (iterator.hasNext() && ((row = iterator.next()) != null)) { try { // [#1627] Handle NULL values @@ -760,21 +797,21 @@ class LoaderImpl> implements /** * Type-safety... */ - private void addValue0(InsertQuery insert, Field field, String row) { + private void addValue0(InsertQuery insert, Field field, Object row) { insert.addValue(field, field.getDataType().convert(row)); } /** * Type-safety... */ - private void addValueForUpdate0(InsertQuery insert, Field field, String row) { + private void addValueForUpdate0(InsertQuery insert, Field field, Object row) { insert.addValueForUpdate(field, field.getDataType().convert(row)); } /** * Get a type-safe condition */ - private Condition getCondition(Field field, String string) { + private Condition getCondition(Field field, Object string) { return field.equal(field.getDataType().convert(string)); }