diff --git a/src/main/ftl/sql.ftl b/src/main/ftl/sql.ftl
index 821f8ac..ee43936 100644
--- a/src/main/ftl/sql.ftl
+++ b/src/main/ftl/sql.ftl
@@ -135,3 +135,27 @@
<#local ftl_call += ')'/>
<#return ftl_call?eval/>
#function>
+
+
+<#--
+-- Extracts the specified column from the specified FetchedResultSet, which
+-- is represented as a row set (using .hash_rows or .seq_rows). May be useful
+-- if your function returns a row set, but you need to use its single column as
+-- a simple sequence. The resulting sequence doesn't contain null elements.
+--
+-- @deprecated Use new .transpose() method to access a result set as a sequence
+-- or a hash of columnar sequences, e.g. ${res.transpose().COL1}.
+--
+-- @param row_set the FetchedResultSet object, represented as a row set
+-- @param column the name or the index (from 0) of the column
+-- @return the column as a sequence
+--->
+<#function get_column row_set column>
+ <#local seq = []/>
+ <#list row_set as row>
+ <#if row[column]??>
+ <#local seq = seq + [row[column]]/>
+ #if>
+ #list>
+ <#return seq/>
+#function>
diff --git a/src/main/java/ftldb/DefaultObjectWrapper.java b/src/main/java/ftldb/DefaultObjectWrapper.java
index e728e60..4c61cfd 100644
--- a/src/main/java/ftldb/DefaultObjectWrapper.java
+++ b/src/main/java/ftldb/DefaultObjectWrapper.java
@@ -35,6 +35,7 @@
*
{@link ClobModel} - treats CLOBs ({@link Clob}) as strings
* {@link StructModel} - treats UDTs ({@link Struct}) as sequences of elements
* {@link FetchedResultSetModel} - treats fetched result sets ({@link FetchedResultSet}) as 2-layer objects
+ * {@link FetchedResultSetTransposedModel} - wraps transposed result sets
*
*/
public class DefaultObjectWrapper extends freemarker.template.DefaultObjectWrapper {
@@ -58,6 +59,9 @@ protected TemplateModel handleUnknownType(Object obj) throws TemplateModelExcept
if (obj instanceof FetchedResultSet) {
return new FetchedResultSetModel((FetchedResultSet) obj, this);
}
+ if (obj instanceof FetchedResultSetTransposed) {
+ return new FetchedResultSetTransposedModel((FetchedResultSetTransposed) obj, this);
+ }
return super.handleUnknownType(obj);
}
diff --git a/src/main/java/ftldb/ext/sql/FetchedResultSet.java b/src/main/java/ftldb/ext/sql/FetchedResultSet.java
index 773f520..e67b038 100644
--- a/src/main/java/ftldb/ext/sql/FetchedResultSet.java
+++ b/src/main/java/ftldb/ext/sql/FetchedResultSet.java
@@ -54,7 +54,10 @@ public FetchedResultSet(ResultSet rs) throws SQLException {
for (int i = 0; i < columnCount; i++) {
columnNames[i] = metaData.getColumnName(i + 1);
- columnIndices.put(columnNames[i], new Integer(i));
+ // if two columns have same names, save only the 1st one
+ if (columnIndices.get(columnNames[i]) == null) {
+ columnIndices.put(columnNames[i], new Integer(i));
+ }
}
List rows = new ArrayList(64);
@@ -87,4 +90,100 @@ public ResultSetMetaData getMetaData() {
}
+ /**
+ * Returns the specified column's index starting from 0.
+ *
+ * @param name the column's name
+ * @return the column's index or {@code null} if no column with such name exists
+ */
+ public Integer getColumnIndex(String name) {
+ return (Integer) columnIndices.get(name);
+ }
+
+
+ /**
+ * Returns the specified column's position starting from 1.
+ *
+ * @param name the column's name
+ * @return the column's position or {@code null} if no column with such name exists
+ */
+ public Integer getColumnPosition(String name) {
+ Integer index = getColumnIndex(name);
+ if (index == null) return null;
+ return new Integer(index.intValue() + 1);
+ }
+
+
+ /**
+ * @return this object
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSet getHashRows() {
+ return this;
+ }
+
+
+ /**
+ * @return this object
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSet getHash_rows() {
+ return getHashRows();
+ }
+
+
+ /**
+ * @return this object
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSet getSeqRows() {
+ return this;
+ }
+
+
+ /**
+ * @return this object
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSet getSeq_rows() {
+ return getSeqRows();
+ }
+
+
+ /**
+ * @return this object transposed
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSetTransposed getColHash() {
+ return new FetchedResultSetTransposed(this);
+ }
+
+
+ /**
+ * @return this object transposed
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSetTransposed getCol_hash() {
+ return getColHash();
+ }
+
+
+ /**
+ * @return this object transposed
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSetTransposed getColSeq() {
+ return new FetchedResultSetTransposed(this);
+ }
+
+
+ /**
+ * @return this object transposed
+ * @deprecated Emulates v1.3.0 access method.
+ */
+ public FetchedResultSetTransposed getCol_seq() {
+ return getColSeq();
+ }
+
+
}
diff --git a/src/main/java/ftldb/ext/sql/FetchedResultSetModel.java b/src/main/java/ftldb/ext/sql/FetchedResultSetModel.java
index b5254de..e426ae1 100644
--- a/src/main/java/ftldb/ext/sql/FetchedResultSetModel.java
+++ b/src/main/java/ftldb/ext/sql/FetchedResultSetModel.java
@@ -90,7 +90,7 @@ public Object exec(List args) throws TemplateModelException {
if (args.size() != 0) {
throw new TemplateModelException("No arguments needed");
}
- return new FetchedResultSetTransposedModel(frs, wrapper);
+ return wrap(new FetchedResultSetTransposed(frs));
}
};
}
diff --git a/src/main/java/ftldb/ext/sql/FetchedResultSetTransposed.java b/src/main/java/ftldb/ext/sql/FetchedResultSetTransposed.java
new file mode 100644
index 0000000..edd8585
--- /dev/null
+++ b/src/main/java/ftldb/ext/sql/FetchedResultSetTransposed.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014-2015 Victor Osolovskiy, Sergey Navrotskiy
+ *
+ * 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 ftldb.ext.sql;
+
+
+/**
+ * This class is a transposed {@link FetchedResultSet}.
+ */
+public class FetchedResultSetTransposed {
+
+
+ public final FetchedResultSet resultSet;
+ public final Object[][] transposedData;
+
+
+ public FetchedResultSetTransposed(FetchedResultSet frs) {
+
+ this.resultSet = frs;
+
+ transposedData = new Object[resultSet.columnNames.length][];
+ for (int ri = 0; ri < resultSet.data.length; ri++) {
+ for (int ci = 0; ci < resultSet.columnNames.length; ci++) {
+ if (transposedData[ci] == null) transposedData[ci] = new Object[resultSet.data.length];
+ transposedData[ci][ri] = resultSet.data[ri][ci];
+ }
+ }
+ }
+
+
+}
diff --git a/src/main/java/ftldb/ext/sql/FetchedResultSetTransposedModel.java b/src/main/java/ftldb/ext/sql/FetchedResultSetTransposedModel.java
index b3839c7..bcbcd4c 100644
--- a/src/main/java/ftldb/ext/sql/FetchedResultSetTransposedModel.java
+++ b/src/main/java/ftldb/ext/sql/FetchedResultSetTransposedModel.java
@@ -18,33 +18,22 @@
import freemarker.template.*;
-import java.util.List;
-
/**
- * This class wraps {@link java.sql.ResultSet} and adapts it for using in FTL both as a sequence and a hash of columns.
+ * This class wraps {@link FetchedResultSetTransposed} and adapts it for using in FTL both as a sequence and a hash of
+ * columns.
*/
public class FetchedResultSetTransposedModel extends WrappingTemplateModel implements TemplateSequenceModel,
TemplateHashModelEx {
- public final FetchedResultSet resultSet;
- public final Object[][] transposedData;
+ public final FetchedResultSetTransposed frst;
- public FetchedResultSetTransposedModel(FetchedResultSet frs, ObjectWrapper wrapper)
+ public FetchedResultSetTransposedModel(FetchedResultSetTransposed frst, ObjectWrapper wrapper)
throws TemplateModelException {
super(wrapper);
-
- this.resultSet = frs;
-
- transposedData = new Object[resultSet.columnNames.length][];
- for (int ri = 0; ri < resultSet.data.length; ri++) {
- for (int ci = 0; ci < resultSet.columnNames.length; ci++) {
- if (transposedData[ci] == null) transposedData[ci] = new Object[resultSet.data.length];
- transposedData[ci][ri] = resultSet.data[ri][ci];
- }
- }
+ this.frst = frst;
}
@@ -54,7 +43,7 @@ public FetchedResultSetTransposedModel(FetchedResultSet frs, ObjectWrapper wrapp
* @return the column at the specified index
*/
public TemplateModel get(int index) throws TemplateModelException {
- return wrap(transposedData[index]);
+ return wrap(frst.transposedData[index]);
}
@@ -64,7 +53,7 @@ public TemplateModel get(int index) throws TemplateModelException {
* @return the specified column as an array
*/
public TemplateModel get(String key) throws TemplateModelException {
- return wrap(transposedData[((Integer) resultSet.columnIndices.get(key)).intValue()]);
+ return wrap(frst.transposedData[((Integer) frst.resultSet.columnIndices.get(key)).intValue()]);
}
@@ -74,7 +63,7 @@ public TemplateModel get(String key) throws TemplateModelException {
* @return the number of columns in this result set
*/
public int size() {
- return transposedData.length;
+ return frst.transposedData.length;
}
@@ -84,7 +73,7 @@ public int size() {
* @return a list of column names ordered by position
*/
public TemplateCollectionModel keys() throws TemplateModelException {
- return new SimpleCollection(java.util.Arrays.asList(resultSet.columnNames), getObjectWrapper());
+ return new SimpleCollection(java.util.Arrays.asList(frst.resultSet.columnNames), getObjectWrapper());
}
@@ -94,7 +83,7 @@ public TemplateCollectionModel keys() throws TemplateModelException {
* @return the list of column arrays ordered by position
*/
public TemplateCollectionModel values() throws TemplateModelException {
- return new SimpleCollection(java.util.Arrays.asList(transposedData), getObjectWrapper());
+ return new SimpleCollection(java.util.Arrays.asList(frst.transposedData), getObjectWrapper());
}
@@ -104,7 +93,7 @@ public TemplateCollectionModel values() throws TemplateModelException {
* @return always {@code false}
*/
public boolean isEmpty() throws TemplateModelException {
- return transposedData.length == 0;
+ return frst.transposedData.length == 0;
}