summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/amazon/carbonado')
-rw-r--r--src/main/java/com/amazon/carbonado/Query.java42
-rw-r--r--src/main/java/com/amazon/carbonado/qe/AbstractQuery.java22
-rw-r--r--src/main/java/com/amazon/carbonado/qe/AbstractQueryExecutor.java23
-rw-r--r--src/main/java/com/amazon/carbonado/qe/DelegatedQueryExecutor.java4
-rw-r--r--src/main/java/com/amazon/carbonado/qe/EmptyQuery.java16
-rw-r--r--src/main/java/com/amazon/carbonado/qe/QueryExecutor.java7
-rw-r--r--src/main/java/com/amazon/carbonado/qe/StandardQuery.java23
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/H2ExceptionTransformer.java35
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/H2SupportStrategy.java60
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java103
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupportStrategy.java35
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/MysqlSupportStrategy.java21
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/OracleSupportStrategy.java22
-rw-r--r--src/main/java/com/amazon/carbonado/repo/jdbc/PostgresqlSupportStrategy.java55
-rw-r--r--src/main/java/com/amazon/carbonado/repo/logging/LoggingQuery.java18
15 files changed, 483 insertions, 3 deletions
diff --git a/src/main/java/com/amazon/carbonado/Query.java b/src/main/java/com/amazon/carbonado/Query.java
index a729331..d1cebca 100644
--- a/src/main/java/com/amazon/carbonado/Query.java
+++ b/src/main/java/com/amazon/carbonado/Query.java
@@ -268,6 +268,23 @@ public interface Query<S extends Storable> {
Cursor<S> fetch() throws FetchException;
/**
+ * Fetches a slice of results for this query, as defined by a numerical
+ * range. A slice can be used to limit the number of results from a
+ * query. It is strongly recommended that the query be given a total {@link
+ * #orderBy ordering} in order for the slice results to be deterministic.
+ *
+ * @param from zero-based {@code from} record number, inclusive
+ * @param to optional zero-based {@code to} record number, exclusive
+ * @return fetch results
+ * @throws IllegalStateException if any blank parameters in this query
+ * @throws IllegalArgumentException if {@code from} is negative or if
+ * {@code from} is more than {@code to}
+ * @throws FetchException if storage layer throws an exception
+ * @since 1.2
+ */
+ Cursor<S> fetch(long from, Long to) throws FetchException;
+
+ /**
* Fetches results for this query after a given starting point, which is
* useful for re-opening a cursor. This is only effective when query has
* been given an explicit {@link #orderBy ordering}. If not a total
@@ -286,6 +303,31 @@ public interface Query<S extends Storable> {
Cursor<S> fetchAfter(S start) throws FetchException;
/**
+ * Fetches a slice of results for this query after a given starting point,
+ * which is useful for re-opening a cursor. This is only effective when
+ * query has been given an explicit {@link #orderBy ordering}. If not a
+ * total ordering, then returned cursor may start at an earlier position.
+ * It is strongly recommended that the query be given a total ordering in
+ * order for the slice results to be deterministic.
+ *
+ * <p>Note: This method can be very expensive to call repeatedly, if the
+ * query needs to perform a sort operation. Ideally, the query ordering
+ * should match the natural ordering of an index or key.
+ *
+ * @param start storable to attempt to start after; if null, fetch all results
+ * @param from zero-based {@code from} record number, inclusive
+ * @param to optional zero-based {@code to} record number, exclusive
+ * @return fetch results
+ * @throws IllegalStateException if any blank parameters in this query
+ * @throws IllegalArgumentException if {@code from} is negative or if
+ * {@code from} is more than {@code to}
+ * @throws FetchException if storage layer throws an exception
+ * @see Repository#enterTransaction(IsolationLevel)
+ * @since 1.2
+ */
+ Cursor<S> fetchAfter(S start, long from, Long to) throws FetchException;
+
+ /**
* Attempts to load exactly one matching object. If the number of matching
* records is zero or exceeds one, then an exception is thrown instead.
*
diff --git a/src/main/java/com/amazon/carbonado/qe/AbstractQuery.java b/src/main/java/com/amazon/carbonado/qe/AbstractQuery.java
index 7639348..767b039 100644
--- a/src/main/java/com/amazon/carbonado/qe/AbstractQuery.java
+++ b/src/main/java/com/amazon/carbonado/qe/AbstractQuery.java
@@ -129,4 +129,26 @@ public abstract class AbstractQuery<S extends Storable> implements Query<S>, App
@Override
public abstract boolean equals(Object obj);
+
+ /**
+ * Called by sliced fetch to ensure that arguments are valid.
+ *
+ * @return false if from is 0 and to is null
+ * @throws IllegalArgumentException if arguments are invalid
+ * @since 1.2
+ */
+ protected boolean checkSliceArguments(long from, Long to) {
+ if (from < 0) {
+ throw new IllegalArgumentException("Slice from is negative: " + from);
+ }
+ if (to == null) {
+ if (from == 0) {
+ return false;
+ }
+ } else if (from > to) {
+ throw new IllegalArgumentException
+ ("Slice from is more than to: " + from + " > " + to);
+ }
+ return true;
+ }
}
diff --git a/src/main/java/com/amazon/carbonado/qe/AbstractQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/AbstractQueryExecutor.java
index dc67fc1..8a8a127 100644
--- a/src/main/java/com/amazon/carbonado/qe/AbstractQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/AbstractQueryExecutor.java
@@ -24,6 +24,9 @@ import com.amazon.carbonado.Cursor;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.cursor.LimitCursor;
+import com.amazon.carbonado.cursor.SkipCursor;
+
import com.amazon.carbonado.filter.FilterValues;
/**
@@ -37,7 +40,25 @@ public abstract class AbstractQueryExecutor<S extends Storable> implements Query
}
/**
- * Counts results by opening a cursor and skipping entries.
+ * Produces a slice via skip and limit cursors. Subclasses are encouraged
+ * to override with a more efficient implementation.
+ *
+ * @since 1.2
+ */
+ public Cursor<S> fetch(FilterValues<S> values, long from, Long to) throws FetchException {
+ Cursor<S> cursor = fetch(values);
+ if (from > 0) {
+ cursor = new SkipCursor<S>(cursor, from);
+ }
+ if (to != null) {
+ cursor = new LimitCursor<S>(cursor, to - from);
+ }
+ return cursor;
+ }
+
+ /**
+ * Counts results by opening a cursor and skipping entries. Subclasses are
+ * encouraged to override with a more efficient implementation.
*/
public long count(FilterValues<S> values) throws FetchException {
Cursor<S> cursor = fetch(values);
diff --git a/src/main/java/com/amazon/carbonado/qe/DelegatedQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/DelegatedQueryExecutor.java
index b4bc0a3..3ec209d 100644
--- a/src/main/java/com/amazon/carbonado/qe/DelegatedQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/DelegatedQueryExecutor.java
@@ -95,6 +95,10 @@ public class DelegatedQueryExecutor<S extends Storable> implements QueryExecutor
return applyFilterValues(values).fetch();
}
+ public Cursor<S> fetch(FilterValues<S> values, long from, Long to) throws FetchException {
+ return applyFilterValues(values).fetch(from, to);
+ }
+
public long count(FilterValues<S> values) throws FetchException {
return applyFilterValues(values).count();
}
diff --git a/src/main/java/com/amazon/carbonado/qe/EmptyQuery.java b/src/main/java/com/amazon/carbonado/qe/EmptyQuery.java
index f3d54f5..9754019 100644
--- a/src/main/java/com/amazon/carbonado/qe/EmptyQuery.java
+++ b/src/main/java/com/amazon/carbonado/qe/EmptyQuery.java
@@ -215,11 +215,27 @@ public final class EmptyQuery<S extends Storable> extends AbstractQuery<S> {
/**
* Always returns an {@link EmptyCursor}.
*/
+ public Cursor<S> fetch(long from, Long to) {
+ checkSliceArguments(from, to);
+ return EmptyCursor.the();
+ }
+
+ /**
+ * Always returns an {@link EmptyCursor}.
+ */
public Cursor<S> fetchAfter(S start) {
return EmptyCursor.the();
}
/**
+ * Always returns an {@link EmptyCursor}.
+ */
+ public Cursor<S> fetchAfter(S start, long from, Long to) {
+ checkSliceArguments(from, to);
+ return EmptyCursor.the();
+ }
+
+ /**
* Always throws {@link PersistNoneException}.
*/
public void deleteOne() throws PersistNoneException {
diff --git a/src/main/java/com/amazon/carbonado/qe/QueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/QueryExecutor.java
index b0ab801..6b5a864 100644
--- a/src/main/java/com/amazon/carbonado/qe/QueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/QueryExecutor.java
@@ -46,6 +46,13 @@ public interface QueryExecutor<S extends Storable> {
Cursor<S> fetch(FilterValues<S> values) throws FetchException;
/**
+ * Returns a new cursor using the given filter values and slice.
+ *
+ * @since 1.2
+ */
+ Cursor<S> fetch(FilterValues<S> values, long from, Long to) throws FetchException;
+
+ /**
* Counts the query results using the given filter values.
*/
long count(FilterValues<S> values) throws FetchException;
diff --git a/src/main/java/com/amazon/carbonado/qe/StandardQuery.java b/src/main/java/com/amazon/carbonado/qe/StandardQuery.java
index 5596c32..10fdf43 100644
--- a/src/main/java/com/amazon/carbonado/qe/StandardQuery.java
+++ b/src/main/java/com/amazon/carbonado/qe/StandardQuery.java
@@ -217,6 +217,18 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
}
}
+ public Cursor<S> fetch(long from, Long to) throws FetchException {
+ if (!checkSliceArguments(from, to)) {
+ return fetch();
+ }
+ try {
+ QueryHints hints = QueryHints.emptyHints().with(QueryHint.CONSUME_SLICE);
+ return executorFactory().executor(mFilter, mOrdering, hints).fetch(mValues, from, to);
+ } catch (RepositoryException e) {
+ throw e.toFetchException();
+ }
+ }
+
public Cursor<S> fetchAfter(S start) throws FetchException {
OrderingList<S> orderings;
if (start == null || (orderings = mOrdering).size() == 0) {
@@ -225,6 +237,17 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
return buildAfter(start, orderings).fetch();
}
+ public Cursor<S> fetchAfter(S start, long from, Long to) throws FetchException {
+ if (!checkSliceArguments(from, to)) {
+ return fetchAfter(start);
+ }
+ OrderingList<S> orderings;
+ if (start == null || (orderings = mOrdering).size() == 0) {
+ return fetch(from, to);
+ }
+ return buildAfter(start, orderings).fetch(from, to);
+ }
+
private Query<S> buildAfter(S start, OrderingList<S> orderings) throws FetchException {
Class<S> storableType = getStorableType();
Filter<S> orderFilter = Filter.getClosedFilter(storableType);
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/H2ExceptionTransformer.java b/src/main/java/com/amazon/carbonado/repo/jdbc/H2ExceptionTransformer.java
new file mode 100644
index 0000000..e367cb0
--- /dev/null
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/H2ExceptionTransformer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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.
+ */
+
+package com.amazon.carbonado.repo.jdbc;
+
+import java.sql.SQLException;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ * @since 1.2
+ */
+class H2ExceptionTransformer extends JDBCExceptionTransformer {
+ public static int DUPLICATE_KEY = 23001;
+
+ public boolean isUniqueConstraintError(SQLException e) {
+ return DUPLICATE_KEY == e.getErrorCode();
+ }
+}
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/H2SupportStrategy.java b/src/main/java/com/amazon/carbonado/repo/jdbc/H2SupportStrategy.java
new file mode 100644
index 0000000..6850fbc
--- /dev/null
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/H2SupportStrategy.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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.
+ */
+
+package com.amazon.carbonado.repo.jdbc;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ * @since 1.2
+ */
+class H2SupportStrategy extends JDBCSupportStrategy {
+ private static final String TRUNCATE_STATEMENT = "TRUNCATE TABLE %s";
+
+ protected H2SupportStrategy(JDBCRepository repo) {
+ super(repo);
+
+ setTruncateTableStatement(TRUNCATE_STATEMENT);
+ }
+
+ @Override
+ JDBCExceptionTransformer createExceptionTransformer() {
+ return new H2ExceptionTransformer();
+ }
+
+ @Override
+ SliceOption getSliceOption() {
+ return SliceOption.LIMIT_AND_OFFSET;
+ }
+
+ @Override
+ String buildSelectWithSlice(String select, boolean limit, boolean offset) {
+ if (limit) {
+ if (offset) {
+ return select.concat(" LIMIT ? OFFSET ?");
+ } else {
+ return select.concat(" LIMIT ?");
+ }
+ } else if (offset) {
+ return select.concat(" LIMIT 2147483647 OFFSET ?");
+ } else {
+ return select;
+ }
+ }
+}
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java
index 54ff24a..8810c09 100644
--- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java
@@ -44,6 +44,8 @@ import com.amazon.carbonado.SupportException;
import com.amazon.carbonado.Transaction;
import com.amazon.carbonado.Trigger;
import com.amazon.carbonado.capability.IndexInfo;
+import com.amazon.carbonado.cursor.EmptyCursor;
+import com.amazon.carbonado.cursor.LimitCursor;
import com.amazon.carbonado.filter.AndFilter;
import com.amazon.carbonado.filter.Filter;
import com.amazon.carbonado.filter.FilterValues;
@@ -647,6 +649,98 @@ class JDBCStorage<S extends Storable> extends StandardQueryFactory<S>
}
@Override
+ public Cursor<S> fetch(FilterValues<S> values, long from, Long to) throws FetchException {
+ if (to != null && (to - from) <= 0) {
+ return EmptyCursor.the();
+ }
+
+ JDBCSupportStrategy.SliceOption option = mSupportStrategy.getSliceOption();
+
+ String select;
+
+ switch (option) {
+ case NOT_SUPPORTED: default:
+ return super.fetch(values, from, to);
+ case LIMIT_ONLY:
+ if (from > 0 || to == null) {
+ return super.fetch(values, from, to);
+ }
+ select = prepareSelect(values, false);
+ select = mSupportStrategy.buildSelectWithSlice(select, true, false);
+ break;
+ case OFFSET_ONLY:
+ if (from <= 0) {
+ return super.fetch(values, from, to);
+ }
+ select = prepareSelect(values, false);
+ select = mSupportStrategy.buildSelectWithSlice(select, false, true);
+ break;
+ case LIMIT_AND_OFFSET:
+ case OFFSET_AND_LIMIT:
+ select = prepareSelect(values, false);
+ select = mSupportStrategy.buildSelectWithSlice(select, to != null, from > 0);
+ break;
+ }
+
+ if (mRepository.localTransactionScope().isForUpdate()) {
+ select = select.concat(" FOR UPDATE");
+ }
+
+ Connection con = mRepository.getConnection();
+ try {
+ PreparedStatement ps = con.prepareStatement(select);
+ Integer fetchSize = mRepository.getFetchSize();
+ if (fetchSize != null) {
+ ps.setFetchSize(fetchSize);
+ }
+
+ try {
+ int psOrdinal = setParameters(ps, values);
+
+ if (from > 0) {
+ if (to != null) {
+ switch (option) {
+ case OFFSET_ONLY:
+ ps.setLong(psOrdinal, from);
+ Cursor<S> c = new JDBCCursor<S>(JDBCStorage.this, con, ps);
+ return new LimitCursor<S>(c, to - from);
+ case LIMIT_AND_OFFSET:
+ ps.setLong(psOrdinal, to - from);
+ ps.setLong(psOrdinal + 1, from);
+ break;
+ case OFFSET_AND_LIMIT:
+ ps.setLong(psOrdinal, from);
+ ps.setLong(psOrdinal + 1, to - from);
+ }
+ } else {
+ ps.setLong(psOrdinal, from);
+ }
+ } else if (to != null) {
+ ps.setLong(psOrdinal, to);
+ }
+
+ return new JDBCCursor<S>(JDBCStorage.this, con, ps);
+ } catch (Exception e) {
+ // in case of exception, close statement
+ try {
+ ps.close();
+ } catch (SQLException e2) {
+ // ignore and allow triggering exception to propagate
+ }
+ throw e;
+ }
+ } catch (Exception e) {
+ // in case of exception, yield connection
+ try {
+ mRepository.yieldConnection(con);
+ } catch (FetchException e2) {
+ // ignore and allow triggering exception to propagate
+ }
+ throw mRepository.toFetchException(e);
+ }
+ }
+
+ @Override
public long count(FilterValues<S> values) throws FetchException {
Connection con = mRepository.getConnection();
try {
@@ -758,13 +852,16 @@ class JDBCStorage<S extends Storable> extends StandardQueryFactory<S>
return b.toString();
}
- private void setParameters(PreparedStatement ps, FilterValues<S> filterValues)
+ /**
+ * @return next value ordinal
+ */
+ private int setParameters(PreparedStatement ps, FilterValues<S> filterValues)
throws Exception
{
PropertyFilter<S>[] propertyFilters = mPropertyFilters;
if (propertyFilters == null) {
- return;
+ return 1;
}
boolean[] propertyFilterNullable = mPropertyFilterNullable;
@@ -799,6 +896,8 @@ class JDBCStorage<S extends Storable> extends StandardQueryFactory<S>
ordinal++;
}
+
+ return psOrdinal;
}
}
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupportStrategy.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupportStrategy.java
index 3643c65..f3b0db5 100644
--- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupportStrategy.java
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupportStrategy.java
@@ -287,4 +287,39 @@ class JDBCSupportStrategy {
void setTruncateTableStatement(String truncateTableStatement) {
mTruncateTableStatement = truncateTableStatement;
}
+
+ /**
+ * @since 1.2
+ */
+ enum SliceOption {
+ // Slice is always emulated
+ NOT_SUPPORTED,
+ // Slice is emulated if from is not zero
+ LIMIT_ONLY,
+ // Slice is emulated if to is not null
+ OFFSET_ONLY,
+ // Slice is fully supported with limit parameter first
+ LIMIT_AND_OFFSET,
+ // Slice is fully supported with offset parameter first
+ OFFSET_AND_LIMIT,
+ }
+
+ /**
+ * @since 1.2
+ */
+ SliceOption getSliceOption() {
+ return SliceOption.NOT_SUPPORTED;
+ }
+
+ /**
+ * @param select base select statement
+ * @param limit when true, select must support limit parameter
+ * @param offset when true, select must support offset parameter
+ * @return revised select statement
+ * @throws UnsupportedOperationException
+ * @since 1.2
+ */
+ String buildSelectWithSlice(String select, boolean limit, boolean offset) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/MysqlSupportStrategy.java b/src/main/java/com/amazon/carbonado/repo/jdbc/MysqlSupportStrategy.java
index 27f813f..bf15ec6 100644
--- a/src/main/java/com/amazon/carbonado/repo/jdbc/MysqlSupportStrategy.java
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/MysqlSupportStrategy.java
@@ -32,7 +32,28 @@ class MysqlSupportStrategy extends JDBCSupportStrategy {
setTruncateTableStatement(TRUNCATE_STATEMENT);
}
+ @Override
JDBCExceptionTransformer createExceptionTransformer() {
return new MysqlExceptionTransformer();
}
+
+ @Override
+ SliceOption getSliceOption() {
+ return SliceOption.OFFSET_AND_LIMIT;
+ }
+
+ @Override
+ String buildSelectWithSlice(String select, boolean limit, boolean offset) {
+ if (limit) {
+ if (offset) {
+ return select.concat(" LIMIT ?,?");
+ } else {
+ return select.concat(" LIMIT ?");
+ }
+ } else if (offset) {
+ return select.concat(" LIMIT ?,18446744073709551615");
+ } else {
+ return select;
+ }
+ }
}
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/OracleSupportStrategy.java b/src/main/java/com/amazon/carbonado/repo/jdbc/OracleSupportStrategy.java
index 27ca7c5..582b299 100644
--- a/src/main/java/com/amazon/carbonado/repo/jdbc/OracleSupportStrategy.java
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/OracleSupportStrategy.java
@@ -220,6 +220,28 @@ class OracleSupportStrategy extends JDBCSupportStrategy {
}
}
+ @Override
+ SliceOption getSliceOption() {
+ return SliceOption.OFFSET_AND_LIMIT;
+ }
+
+ @Override
+ String buildSelectWithSlice(String select, boolean limit, boolean offset) {
+ if (limit) {
+ if (offset) {
+ return "SELECT * FROM (SELECT ROW_.*, ROWNUM ROWNUM_ FROM(" +
+ select + ") ROW_) WHERE ROWNUM_ > ? AND ROWNUM_ <= ?";
+ } else {
+ return "SELECT * FROM (" + select + ") WHERE ROWNUM <= ?";
+ }
+ } else if (offset) {
+ return "SELECT * FROM (SELECT ROW_.*, ROWNUM ROWNUM_ FROM(" +
+ select + ") ROW_) WHERE ROWNUM_ > ?";
+ } else {
+ return select;
+ }
+ }
+
/* FIXME
@Override
boolean printPlan(Appendable app, int indentLevel, String statement)
diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/PostgresqlSupportStrategy.java b/src/main/java/com/amazon/carbonado/repo/jdbc/PostgresqlSupportStrategy.java
new file mode 100644
index 0000000..43d35c2
--- /dev/null
+++ b/src/main/java/com/amazon/carbonado/repo/jdbc/PostgresqlSupportStrategy.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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.
+ */
+
+package com.amazon.carbonado.repo.jdbc;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ * @since 1.2
+ */
+class PostgresqlSupportStrategy extends JDBCSupportStrategy {
+ private static final String TRUNCATE_STATEMENT = "TRUNCATE TABLE %s";
+
+ protected PostgresqlSupportStrategy(JDBCRepository repo) {
+ super(repo);
+
+ setTruncateTableStatement(TRUNCATE_STATEMENT);
+ }
+
+ @Override
+ SliceOption getSliceOption() {
+ return SliceOption.LIMIT_AND_OFFSET;
+ }
+
+ @Override
+ String buildSelectWithSlice(String select, boolean limit, boolean offset) {
+ if (limit) {
+ if (offset) {
+ return select.concat(" LIMIT ? OFFSET ?");
+ } else {
+ return select.concat(" LIMIT ?");
+ }
+ } else if (offset) {
+ return select.concat(" LIMIT ALL OFFSET ?");
+ } else {
+ return select;
+ }
+ }
+}
diff --git a/src/main/java/com/amazon/carbonado/repo/logging/LoggingQuery.java b/src/main/java/com/amazon/carbonado/repo/logging/LoggingQuery.java
index d1f21ce..56e4e33 100644
--- a/src/main/java/com/amazon/carbonado/repo/logging/LoggingQuery.java
+++ b/src/main/java/com/amazon/carbonado/repo/logging/LoggingQuery.java
@@ -137,6 +137,15 @@ class LoggingQuery<S extends Storable> implements Query<S> {
return mQuery.fetch();
}
+ public Cursor<S> fetch(long from, Long to) throws FetchException {
+ Log log = mStorage.mLog;
+ if (log.isEnabled()) {
+ log.write("Query.fetch(start, to) on " + this +
+ ", from: " + from + ", to: " + to);
+ }
+ return mQuery.fetch(from, to);
+ }
+
public Cursor<S> fetchAfter(S start) throws FetchException {
Log log = mStorage.mLog;
if (log.isEnabled()) {
@@ -145,6 +154,15 @@ class LoggingQuery<S extends Storable> implements Query<S> {
return mQuery.fetchAfter(start);
}
+ public Cursor<S> fetchAfter(S start, long from, Long to) throws FetchException {
+ Log log = mStorage.mLog;
+ if (log.isEnabled()) {
+ log.write("Query.fetchAfter(start, from, to) on " + this + ", start: " + start +
+ ", from: " + from + ", to: " + to);
+ }
+ return mQuery.fetchAfter(start);
+ }
+
public S loadOne() throws FetchException {
Log log = mStorage.mLog;
if (log.isEnabled()) {