View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.extended.bind;
19  
20  import lombok.Getter;
21  import org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLValueFormat;
22  import org.apache.shardingsphere.db.protocol.postgresql.packet.command.PostgreSQLCommandPacket;
23  import org.apache.shardingsphere.db.protocol.postgresql.packet.command.PostgreSQLCommandPacketType;
24  import org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.extended.PostgreSQLColumnType;
25  import org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.extended.bind.protocol.PostgreSQLBinaryProtocolValue;
26  import org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.extended.bind.protocol.PostgreSQLBinaryProtocolValueFactory;
27  import org.apache.shardingsphere.db.protocol.postgresql.packet.identifier.PostgreSQLIdentifierTag;
28  import org.apache.shardingsphere.db.protocol.postgresql.payload.PostgreSQLPacketPayload;
29  
30  import java.util.ArrayList;
31  import java.util.Collections;
32  import java.util.List;
33  
34  /**
35   * Command bind packet for PostgreSQL.
36   */
37  public final class PostgreSQLComBindPacket extends PostgreSQLCommandPacket {
38      
39      private final PostgreSQLPacketPayload payload;
40      
41      @Getter
42      private final String portal;
43      
44      @Getter
45      private final String statementId;
46      
47      public PostgreSQLComBindPacket(final PostgreSQLPacketPayload payload) {
48          this.payload = payload;
49          payload.readInt4();
50          portal = payload.readStringNul();
51          statementId = payload.readStringNul();
52      }
53      
54      /**
55       * Read parameters from bind message.
56       *
57       * @param paramTypes parameter types
58       * @return values of parameter
59       */
60      public List<Object> readParameters(final List<PostgreSQLColumnType> paramTypes) {
61          List<Integer> paramFormats = getParameterFormats();
62          int parameterCount = payload.readInt2();
63          List<Object> result = new ArrayList<>(parameterCount);
64          for (int paramIndex = 0; paramIndex < parameterCount; paramIndex++) {
65              int parameterValueLength = payload.readInt4();
66              if (-1 == parameterValueLength) {
67                  result.add(null);
68                  continue;
69              }
70              Object paramValue = isTextParameterValue(paramFormats, paramIndex)
71                      ? getTextParameterValue(payload, parameterValueLength, paramTypes.get(paramIndex))
72                      : getBinaryParameterValue(payload, parameterValueLength, paramTypes.get(paramIndex));
73              result.add(paramValue);
74          }
75          return result;
76      }
77      
78      private List<Integer> getParameterFormats() {
79          int parameterFormatCount = payload.readInt2();
80          List<Integer> result = new ArrayList<>(parameterFormatCount);
81          for (int i = 0; i < parameterFormatCount; i++) {
82              result.add(payload.readInt2());
83          }
84          return result;
85      }
86      
87      private boolean isTextParameterValue(final List<Integer> paramFormats, final int paramIndex) {
88          if (paramFormats.isEmpty()) {
89              return true;
90          }
91          return PostgreSQLValueFormat.TEXT.getCode() == paramFormats.get(1 == paramFormats.size() ? 0 : paramIndex);
92      }
93      
94      private Object getTextParameterValue(final PostgreSQLPacketPayload payload, final int paramValueLength, final PostgreSQLColumnType paramType) {
95          String value = payload.getByteBuf().readCharSequence(paramValueLength, payload.getCharset()).toString();
96          return paramType.getTextValueParser().parse(value);
97      }
98      
99      private Object getBinaryParameterValue(final PostgreSQLPacketPayload payload, final int paramValueLength, final PostgreSQLColumnType paramType) {
100         PostgreSQLBinaryProtocolValue binaryProtocolValue = PostgreSQLBinaryProtocolValueFactory.getBinaryProtocolValue(paramType);
101         return binaryProtocolValue.read(payload, paramValueLength);
102     }
103     
104     /**
105      * Read result formats from bind message.
106      *
107      * @return formats of value
108      */
109     public List<PostgreSQLValueFormat> readResultFormats() {
110         int resultFormatsLength = payload.readInt2();
111         if (0 == resultFormatsLength) {
112             return Collections.emptyList();
113         }
114         if (1 == resultFormatsLength) {
115             return Collections.singletonList(PostgreSQLValueFormat.valueOf(payload.readInt2()));
116         }
117         List<PostgreSQLValueFormat> result = new ArrayList<>(resultFormatsLength);
118         for (int i = 0; i < resultFormatsLength; i++) {
119             result.add(PostgreSQLValueFormat.valueOf(payload.readInt2()));
120         }
121         return result;
122     }
123     
124     @Override
125     protected void write(final PostgreSQLPacketPayload payload) {
126     }
127     
128     @Override
129     public PostgreSQLIdentifierTag getIdentifier() {
130         return PostgreSQLCommandPacketType.BIND_COMMAND;
131     }
132 }