/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.sql.pg;
import com.foundationdb.server.error.ExternalRoutineInvocationException;
import com.foundationdb.server.error.SQLParserInternalException;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.types.DataTypeDescriptor;
import com.foundationdb.sql.types.TypeId;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class PostgresDynamicResultSetOutputter extends PostgresOutputter<ResultSet>
{
private int ncols;
private PostgresType[] columnTypes;
private String[] columnNames;
public PostgresDynamicResultSetOutputter(PostgresQueryContext context,
PostgresJavaRoutine statement) {
super(context, statement);
}
public void setMetaData(ResultSetMetaData metaData, PostgresQueryContext context) throws SQLException {
TypesTranslator typesTranslator = context.getTypesTranslator();
ncols = metaData.getColumnCount();
columnTypes = new PostgresType[ncols];
columnNames = new String[ncols];
for (int i = 0; i < ncols; i++) {
columnTypes[i] = typeFromSQL(metaData, i+1, typesTranslator);
columnNames[i] = metaData.getColumnName(i+1);
}
}
public void sendDescription() throws IOException {
messenger.beginMessage(PostgresMessages.ROW_DESCRIPTION_TYPE.code());
messenger.writeShort(ncols);
for (int i = 0; i < columnTypes.length; i++) {
PostgresType type = columnTypes[i];
messenger.writeString(columnNames[i]); // attname
messenger.writeInt(0); // attrelid
messenger.writeShort(0); // attnum
messenger.writeInt(type.getOid()); // atttypid
messenger.writeShort(type.getLength()); // attlen
messenger.writeInt(type.getModifier()); // atttypmod
messenger.writeShort(0);
}
messenger.sendMessage();
}
@Override
public void output(ResultSet resultSet) throws IOException {
messenger.beginMessage(PostgresMessages.DATA_ROW_TYPE.code());
messenger.writeShort(ncols);
for (int i = 0; i < ncols; i++) {
Object column;
try {
column = resultSet.getObject(i+1);
}
catch (SQLException ex) {
throw new ExternalRoutineInvocationException(((PostgresJavaRoutine)statement).getInvocation().getRoutineName(), ex);
}
PostgresType type = columnTypes[i];
boolean binary = false;
ByteArrayOutputStream bytes = encoder.encodePObject(column, type, binary);
if (bytes == null) {
messenger.writeInt(-1);
}
else {
messenger.writeInt(bytes.size());
messenger.writeByteStream(bytes);
}
}
messenger.sendMessage();
}
protected static PostgresType typeFromSQL(ResultSetMetaData metaData, int columnIndex, TypesTranslator typesTranslator) throws SQLException {
TypeId typeId = TypeId.getBuiltInTypeId(metaData.getColumnType(columnIndex));
if (typeId == null) {
try {
typeId = TypeId.getUserDefinedTypeId(metaData.getColumnTypeName(columnIndex),
false);
}
catch (StandardException ex) {
throw new SQLParserInternalException(ex);
}
}
DataTypeDescriptor sqlType;
if (typeId.isDecimalTypeId() || typeId.isNumericTypeId()) {
sqlType = new DataTypeDescriptor(typeId,
metaData.getPrecision(columnIndex),
metaData.getScale(columnIndex),
metaData.isNullable(columnIndex) != ResultSetMetaData.columnNoNulls,
metaData.getColumnDisplaySize(columnIndex));
}
else {
sqlType = new DataTypeDescriptor(typeId,
metaData.isNullable(columnIndex) != ResultSetMetaData.columnNoNulls,
metaData.getColumnDisplaySize(columnIndex));
}
TInstance type = typesTranslator.typeForSQLType(sqlType);
return PostgresType.fromDerby(sqlType, type);
}
}