001: /*-------------------------------------------------------------------------
002: *
003: * Copyright (c) 2004-2005, PostgreSQL Global Development Group
004: * Copyright (c) 2004, Open Cloud Limited.
005: *
006: * IDENTIFICATION
007: * $PostgreSQL: pgjdbc/org/postgresql/core/v3/SimpleParameterList.java,v 1.14 2007/06/13 07:25:01 jurka Exp $
008: *
009: *-------------------------------------------------------------------------
010: */
011: package org.postgresql.core.v3;
012:
013: import java.io.InputStream;
014: import java.io.IOException;
015: import java.sql.SQLException;
016: import java.util.Arrays;
017:
018: import org.postgresql.core.*;
019: import org.postgresql.util.PSQLException;
020: import org.postgresql.util.PSQLState;
021: import org.postgresql.util.StreamWrapper;
022: import org.postgresql.util.GT;
023:
024: /**
025: * Parameter list for a single-statement V3 query.
026: *
027: * @author Oliver Jowett (oliver@opencloud.com)
028: */
029: class SimpleParameterList implements V3ParameterList {
030:
031: private final static int IN = 1;
032: private final static int OUT = 2;
033: private final static int INOUT = IN | OUT;
034:
035: SimpleParameterList(int paramCount) {
036: this .paramValues = new Object[paramCount];
037: this .paramTypes = new int[paramCount];
038: this .encoded = new byte[paramCount][];
039: this .direction = new int[paramCount];
040: }
041:
042: public void registerOutParameter(int index, int sqlType)
043: throws SQLException {
044: if (index < 1 || index > paramValues.length)
045: throw new PSQLException(
046: GT
047: .tr(
048: "The column index is out of range: {0}, number of columns: {1}.",
049: new Object[] {
050: new Integer(index),
051: new Integer(
052: paramValues.length) }),
053: PSQLState.INVALID_PARAMETER_VALUE);
054:
055: direction[index - 1] |= OUT;
056: }
057:
058: private void bind(int index, Object value, int oid)
059: throws SQLException {
060: if (index < 1 || index > paramValues.length)
061: throw new PSQLException(
062: GT
063: .tr(
064: "The column index is out of range: {0}, number of columns: {1}.",
065: new Object[] {
066: new Integer(index),
067: new Integer(
068: paramValues.length) }),
069: PSQLState.INVALID_PARAMETER_VALUE);
070:
071: --index;
072:
073: encoded[index] = null;
074: paramValues[index] = value;
075: direction[index] |= IN;
076:
077: // If we are setting something to an UNSPECIFIED NULL, don't overwrite
078: // our existing type for it. We don't need the correct type info to
079: // send this value, and we don't want to overwrite and require a
080: // reparse.
081: if (oid == Oid.UNSPECIFIED
082: && paramTypes[index] != Oid.UNSPECIFIED
083: && value == NULL_OBJECT)
084: return;
085:
086: paramTypes[index] = oid;
087: }
088:
089: public int getParameterCount() {
090: return paramValues.length;
091: }
092:
093: public int getOutParameterCount() {
094: int count = 0;
095: for (int i = paramTypes.length; --i >= 0;) {
096: if ((direction[i] & OUT) == OUT) {
097: count++;
098: }
099: }
100: // Every function has at least one output.
101: if (count == 0)
102: count = 1;
103: return count;
104:
105: }
106:
107: public int getInParameterCount() {
108: int count = 0;
109: for (int i = 0; i < paramTypes.length; i++) {
110: if (direction[i] != OUT) {
111: count++;
112: }
113: }
114: return count;
115: }
116:
117: public void setIntParameter(int index, int value)
118: throws SQLException {
119: byte[] data = new byte[4];
120: data[3] = (byte) value;
121: data[2] = (byte) (value >> 8);
122: data[1] = (byte) (value >> 16);
123: data[0] = (byte) (value >> 24);
124: bind(index, data, Oid.INT4);
125: }
126:
127: public void setLiteralParameter(int index, String value, int oid)
128: throws SQLException {
129: bind(index, value, oid);
130: }
131:
132: public void setStringParameter(int index, String value, int oid)
133: throws SQLException {
134: bind(index, value, oid);
135: }
136:
137: public void setBytea(int index, byte[] data, int offset, int length)
138: throws SQLException {
139: bind(index, new StreamWrapper(data, offset, length), Oid.BYTEA);
140: }
141:
142: public void setBytea(int index, InputStream stream, int length)
143: throws SQLException {
144: bind(index, new StreamWrapper(stream, length), Oid.BYTEA);
145: }
146:
147: public void setNull(int index, int oid) throws SQLException {
148: bind(index, NULL_OBJECT, oid);
149: }
150:
151: public String toString(int index) {
152: --index;
153: if (paramValues[index] == null)
154: return "?";
155: else if (paramValues[index] == NULL_OBJECT)
156: return "NULL";
157: else
158: return paramValues[index].toString();
159: }
160:
161: public void checkAllParametersSet() throws SQLException {
162: for (int i = 0; i < paramTypes.length; ++i) {
163: if (direction[i] != OUT && paramValues[i] == null)
164: throw new PSQLException(GT.tr(
165: "No value specified for parameter {0}.",
166: new Integer(i + 1)),
167: PSQLState.INVALID_PARAMETER_VALUE);
168: }
169: }
170:
171: //
172: // bytea helper
173: //
174:
175: private static void streamBytea(PGStream pgStream,
176: StreamWrapper wrapper) throws IOException {
177: byte[] rawData = wrapper.getBytes();
178: if (rawData != null) {
179: pgStream.Send(rawData, wrapper.getOffset(), wrapper
180: .getLength());
181: return;
182: }
183:
184: pgStream.SendStream(wrapper.getStream(), wrapper.getLength());
185: }
186:
187: public int[] getTypeOIDs() {
188: return paramTypes;
189: }
190:
191: //
192: // Package-private V3 accessors
193: //
194:
195: int getTypeOID(int index) {
196: if (direction[index - 1] == OUT) {
197: paramTypes[index - 1] = Oid.VOID;
198: paramValues[index - 1] = "null";
199: }
200:
201: return paramTypes[index - 1];
202: }
203:
204: boolean hasUnresolvedTypes() {
205: for (int i = 0; i < paramTypes.length; i++) {
206: if (paramTypes[i] == Oid.UNSPECIFIED)
207: return true;
208: }
209: return false;
210: }
211:
212: void setResolvedType(int index, int oid) {
213: // only allow overwriting an unknown value
214: if (paramTypes[index - 1] == Oid.UNSPECIFIED) {
215: paramTypes[index - 1] = oid;
216: } else if (paramTypes[index - 1] != oid) {
217: throw new IllegalArgumentException(
218: "Can't change resolved type for param: " + index
219: + " from " + paramTypes[index - 1] + " to "
220: + oid);
221: }
222: }
223:
224: boolean isNull(int index) {
225: return (paramValues[index - 1] == NULL_OBJECT);
226: }
227:
228: boolean isBinary(int index) {
229: // Currently, only StreamWrapper uses the binary parameter form.
230: return (paramValues[index - 1] instanceof StreamWrapper);
231: }
232:
233: int getV3Length(int index) {
234: --index;
235:
236: // Null?
237: if (paramValues[index] == NULL_OBJECT)
238: throw new IllegalArgumentException(
239: "can't getV3Length() on a null parameter");
240:
241: // Directly encoded?
242: if (paramValues[index] instanceof byte[])
243: return ((byte[]) paramValues[index]).length;
244:
245: // Binary-format bytea?
246: if (paramValues[index] instanceof StreamWrapper)
247: return ((StreamWrapper) paramValues[index]).getLength();
248:
249: // Already encoded?
250: if (encoded[index] == null) {
251: // Encode value and compute actual length using UTF-8.
252: encoded[index] = Utils.encodeUTF8(paramValues[index]
253: .toString());
254: }
255:
256: return encoded[index].length;
257: }
258:
259: void writeV3Value(int index, PGStream pgStream) throws IOException {
260: --index;
261:
262: // Null?
263: if (paramValues[index] == NULL_OBJECT)
264: throw new IllegalArgumentException(
265: "can't writeV3Value() on a null parameter");
266:
267: // Directly encoded?
268: if (paramValues[index] instanceof byte[]) {
269: pgStream.Send((byte[]) paramValues[index]);
270: return;
271: }
272:
273: // Binary-format bytea?
274: if (paramValues[index] instanceof StreamWrapper) {
275: streamBytea(pgStream, (StreamWrapper) paramValues[index]);
276: return;
277: }
278:
279: // Encoded string.
280: if (encoded[index] == null)
281: encoded[index] = Utils
282: .encodeUTF8((String) paramValues[index]);
283: pgStream.Send(encoded[index]);
284: }
285:
286: public ParameterList copy() {
287: SimpleParameterList newCopy = new SimpleParameterList(
288: paramValues.length);
289: System.arraycopy(paramValues, 0, newCopy.paramValues, 0,
290: paramValues.length);
291: System.arraycopy(paramTypes, 0, newCopy.paramTypes, 0,
292: paramTypes.length);
293: System.arraycopy(direction, 0, newCopy.direction, 0,
294: direction.length);
295: return newCopy;
296: }
297:
298: public void clear() {
299: Arrays.fill(paramValues, null);
300: Arrays.fill(paramTypes, 0);
301: Arrays.fill(encoded, null);
302: Arrays.fill(direction, 0);
303: }
304:
305: public SimpleParameterList[] getSubparams() {
306: return null;
307: }
308:
309: private final Object[] paramValues;
310: private final int[] paramTypes;
311: private final int[] direction;
312: private final byte[][] encoded;
313:
314: /**
315: * Marker object representing NULL; this distinguishes
316: * "parameter never set" from "parameter set to null".
317: */
318: private final static Object NULL_OBJECT = new Object();
319: }
|