Search in sources :

Example 1 with PGType

use of io.crate.protocols.postgres.types.PGType in project crate by crate.

the class Messages method sendDataRow.

/**
     * Byte1('D')
     * Identifies the message as a data row.
     * <p>
     * Int32
     * Length of message contents in bytes, including self.
     * <p>
     * Int16
     * The number of column values that follow (possibly zero).
     * <p>
     * Next, the following pair of fields appear for each column:
     * <p>
     * Int32
     * The length of the column value, in bytes (this count does not include itself).
     * Can be zero. As a special case, -1 indicates a NULL column value. No value bytes follow in the NULL case.
     * <p>
     * ByteN
     * The value of the column, in the format indicated by the associated format code. n is the above length.
     */
static void sendDataRow(Channel channel, Row row, List<? extends DataType> columnTypes, @Nullable FormatCodes.FormatCode[] formatCodes) {
    int length = 4 + 2;
    assert columnTypes.size() == row.numColumns() : "Number of columns in the row must match number of columnTypes. Row: " + row + " types: " + columnTypes;
    ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
    buffer.writeByte('D');
    // will be set at the end
    buffer.writeInt(0);
    buffer.writeShort(row.numColumns());
    for (int i = 0; i < row.numColumns(); i++) {
        DataType dataType = columnTypes.get(i);
        PGType pgType = PGTypes.get(dataType);
        Object value = row.get(i);
        if (value == null) {
            buffer.writeInt(-1);
            length += 4;
        } else {
            FormatCodes.FormatCode formatCode = FormatCodes.getFormatCode(formatCodes, i);
            switch(formatCode) {
                case TEXT:
                    length += pgType.writeAsText(buffer, value);
                    break;
                case BINARY:
                    length += pgType.writeAsBinary(buffer, value);
                    break;
                default:
                    throw new AssertionError("Unrecognized formatCode: " + formatCode);
            }
        }
    }
    buffer.setInt(1, length);
    channel.write(buffer);
}
Also used : PGType(io.crate.protocols.postgres.types.PGType) DataType(io.crate.types.DataType) ChannelBuffer(org.jboss.netty.buffer.ChannelBuffer)

Example 2 with PGType

use of io.crate.protocols.postgres.types.PGType in project crate by crate.

the class Messages method sendRowDescription.

/**
     * RowDescription (B)
     * <p>
     * | 'T' | int32 len | int16 numCols
     * <p>
     * For each field:
     * <p>
     * | string name | int32 table_oid | int16 attr_num | int32 oid | int16 typlen | int32 type_modifier | int16 format_code
     * <p>
     * See https://www.postgresql.org/docs/current/static/protocol-message-formats.html
     */
static void sendRowDescription(Channel channel, Collection<Field> columns, @Nullable FormatCodes.FormatCode[] formatCodes) {
    int length = 4 + 2;
    int columnSize = 4 + 2 + 4 + 2 + 4 + 2;
    ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(// use 10 as an estimate for columnName length
    length + (columns.size() * (10 + columnSize)));
    buffer.writeByte('T');
    // will be set at the end
    buffer.writeInt(0);
    buffer.writeShort(columns.size());
    int idx = 0;
    for (Field column : columns) {
        byte[] nameBytes = column.path().outputName().getBytes(StandardCharsets.UTF_8);
        length += nameBytes.length + 1;
        length += columnSize;
        writeCString(buffer, nameBytes);
        // table_oid
        buffer.writeInt(0);
        // attr_num
        buffer.writeShort(0);
        PGType pgType = PGTypes.get(column.valueType());
        buffer.writeInt(pgType.oid());
        buffer.writeShort(pgType.typeLen());
        buffer.writeInt(pgType.typeMod());
        buffer.writeShort(FormatCodes.getFormatCode(formatCodes, idx).ordinal());
        idx++;
    }
    buffer.setInt(1, length);
    ChannelFuture channelFuture = channel.write(buffer);
    if (LOGGER.isTraceEnabled()) {
        channelFuture.addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                LOGGER.trace("sentRowDescription");
            }
        });
    }
}
Also used : ChannelFuture(org.jboss.netty.channel.ChannelFuture) Field(io.crate.analyze.symbol.Field) PGType(io.crate.protocols.postgres.types.PGType) ChannelFutureListener(org.jboss.netty.channel.ChannelFutureListener) ChannelBuffer(org.jboss.netty.buffer.ChannelBuffer)

Example 3 with PGType

use of io.crate.protocols.postgres.types.PGType in project crate by crate.

the class ConnectionContext method handleBindMessage.

/**
     * Bind Message
     * Header:
     * | 'B' | int32 len
     * <p>
     * Body:
     * <pre>
     * | string portalName | string statementName
     * | int16 numFormatCodes
     *      foreach
     *      | int16 formatCode
     * | int16 numParams
     *      foreach
     *      | int32 valueLength
     *      | byteN value
     * | int16 numResultColumnFormatCodes
     *      foreach
     *      | int16 formatCode
     * </pre>
     */
private void handleBindMessage(ChannelBuffer buffer, Channel channel) {
    String portalName = readCString(buffer);
    String statementName = readCString(buffer);
    FormatCodes.FormatCode[] formatCodes = FormatCodes.fromBuffer(buffer);
    short numParams = buffer.readShort();
    List<Object> params = createList(numParams);
    for (int i = 0; i < numParams; i++) {
        int valueLength = buffer.readInt();
        if (valueLength == -1) {
            params.add(null);
        } else {
            DataType paramType = session.getParamType(statementName, i);
            PGType pgType = PGTypes.get(paramType);
            FormatCodes.FormatCode formatCode = getFormatCode(formatCodes, i);
            switch(formatCode) {
                case TEXT:
                    params.add(pgType.readTextValue(buffer, valueLength));
                    break;
                case BINARY:
                    params.add(pgType.readBinaryValue(buffer, valueLength));
                    break;
                default:
                    Messages.sendErrorResponse(channel, new UnsupportedOperationException(String.format(Locale.ENGLISH, "Unsupported format code '%d' for param '%s'", formatCode.ordinal(), paramType.getName())));
                    return;
            }
        }
    }
    FormatCodes.FormatCode[] resultFormatCodes = FormatCodes.fromBuffer(buffer);
    session.bind(portalName, statementName, params, resultFormatCodes);
    Messages.sendBindComplete(channel);
}
Also used : FormatCodes.getFormatCode(io.crate.protocols.postgres.FormatCodes.getFormatCode) PGType(io.crate.protocols.postgres.types.PGType) DataType(io.crate.types.DataType)

Example 4 with PGType

use of io.crate.protocols.postgres.types.PGType in project crate by crate.

the class SQLTransportExecutor method toJdbcCompatObject.

private static Object toJdbcCompatObject(Connection connection, Object arg) {
    if (arg == null) {
        return null;
    }
    if (arg instanceof Map) {
        // setObject with a Map would use hstore. But that only supports text values
        try {
            return toPGObjectJson(toJsonString(((Map) arg)));
        } catch (SQLException | IOException e) {
            throw Throwables.propagate(e);
        }
    }
    if (arg.getClass().isArray()) {
        arg = Arrays.asList((Object[]) arg);
    }
    if (arg instanceof Collection) {
        Collection values = (Collection) arg;
        if (values.isEmpty()) {
            // TODO: can't insert empty list without knowing the type
            return null;
        }
        if (values.iterator().next() instanceof Map) {
            try {
                return toPGObjectJson(toJsonString(values));
            } catch (SQLException | IOException e) {
                throw Throwables.propagate(e);
            }
        }
        List<Object> convertedValues = new ArrayList<>(values.size());
        PGType pgType = null;
        for (Object value : values) {
            convertedValues.add(toJdbcCompatObject(connection, value));
            if (pgType == null && value != null) {
                pgType = PGTypes.get(DataTypes.guessType(value));
            }
        }
        try {
            return connection.createArrayOf(pgType.typName(), convertedValues.toArray(new Object[0]));
        } catch (SQLException e) {
            /*
                 * pg error message doesn't include a stacktrace.
                 * Set a breakpoint in {@link io.crate.protocols.postgres.Messages#sendErrorResponse(Channel, Throwable)}
                 * to inspect the error
                 */
            throw Throwables.propagate(e);
        }
    }
    return arg;
}
Also used : PSQLException(io.crate.shade.org.postgresql.util.PSQLException) PGType(io.crate.protocols.postgres.types.PGType) IOException(java.io.IOException)

Aggregations

PGType (io.crate.protocols.postgres.types.PGType)4 DataType (io.crate.types.DataType)2 ChannelBuffer (org.jboss.netty.buffer.ChannelBuffer)2 Field (io.crate.analyze.symbol.Field)1 FormatCodes.getFormatCode (io.crate.protocols.postgres.FormatCodes.getFormatCode)1 PSQLException (io.crate.shade.org.postgresql.util.PSQLException)1 IOException (java.io.IOException)1 ChannelFuture (org.jboss.netty.channel.ChannelFuture)1 ChannelFutureListener (org.jboss.netty.channel.ChannelFutureListener)1