346 lines
11 KiB
Java
346 lines
11 KiB
Java
package org.postgresql.jdbc2;
|
|
|
|
import java.text.*;
|
|
import java.sql.*;
|
|
import java.util.*;
|
|
import java.math.BigDecimal;
|
|
import org.postgresql.Field;
|
|
import org.postgresql.util.*;
|
|
|
|
/*
|
|
* Array is used collect one column of query result data.
|
|
*
|
|
* <p>Read a field of type Array into either a natively-typed
|
|
* Java array object or a ResultSet. Accessor methods provide
|
|
* the ability to capture array slices.
|
|
*
|
|
* <p>Other than the constructor all methods are direct implementations
|
|
* of those specified for java.sql.Array. Please refer to the javadoc
|
|
* for java.sql.Array for detailed descriptions of the functionality
|
|
* and parameters of the methods of this class.
|
|
*
|
|
* @see ResultSet#getArray
|
|
*/
|
|
|
|
|
|
public class Array implements java.sql.Array
|
|
{
|
|
private org.postgresql.Connection conn = null;
|
|
private org.postgresql.Field field = null;
|
|
private org.postgresql.jdbc2.ResultSet rs = null;
|
|
private int idx = 0;
|
|
private String rawString = null;
|
|
|
|
/*
|
|
* Create a new Array
|
|
*
|
|
* @param conn a database connection
|
|
* @param idx 1-based index of the query field to load into this Array
|
|
* @param field the Field descriptor for the field to load into this Array
|
|
* @param rs the ResultSet from which to get the data for this Array
|
|
*/
|
|
public Array( org.postgresql.Connection conn, int idx, Field field, org.postgresql.jdbc2.ResultSet rs )
|
|
throws SQLException
|
|
{
|
|
this.conn = conn;
|
|
this.field = field;
|
|
this.rs = rs;
|
|
this.idx = idx;
|
|
this.rawString = rs.getFixedString(idx);
|
|
}
|
|
|
|
public Object getArray() throws SQLException
|
|
{
|
|
return getArray( 1, 0, null );
|
|
}
|
|
|
|
public Object getArray(long index, int count) throws SQLException
|
|
{
|
|
return getArray( index, count, null );
|
|
}
|
|
|
|
public Object getArray(Map map) throws SQLException
|
|
{
|
|
return getArray( 1, 0, map );
|
|
}
|
|
|
|
public Object getArray(long index, int count, Map map) throws SQLException
|
|
{
|
|
if ( map != null ) // For now maps aren't supported.
|
|
throw org.postgresql.Driver.notImplemented();
|
|
|
|
if (index < 1)
|
|
throw new PSQLException("postgresql.arr.range");
|
|
Object retVal = null;
|
|
|
|
ArrayList array = new ArrayList();
|
|
if ( rawString != null )
|
|
{
|
|
char[] chars = rawString.toCharArray();
|
|
StringBuffer sbuf = new StringBuffer();
|
|
boolean foundOpen = false;
|
|
boolean insideString = false;
|
|
for ( int i = 0; i < chars.length; i++ )
|
|
{
|
|
if ( chars[i] == '{' )
|
|
{
|
|
if ( foundOpen ) // Only supports 1-D arrays for now
|
|
throw org.postgresql.Driver.notImplemented();
|
|
foundOpen = true;
|
|
continue;
|
|
}
|
|
if ( chars[i] == '"' )
|
|
{
|
|
insideString = !insideString;
|
|
continue;
|
|
}
|
|
if ( (!insideString && chars[i] == ',') || chars[i] == '}' || i == chars.length - 1)
|
|
{
|
|
if ( chars[i] != '"' && chars[i] != '}' && chars[i] != ',' )
|
|
sbuf.append(chars[i]);
|
|
array.add( sbuf.toString() );
|
|
sbuf = new StringBuffer();
|
|
continue;
|
|
}
|
|
sbuf.append( chars[i] );
|
|
}
|
|
}
|
|
String[] arrayContents = (String[]) array.toArray( new String[array.size()] );
|
|
if ( count == 0 )
|
|
count = arrayContents.length;
|
|
index--;
|
|
if ( index + count > arrayContents.length )
|
|
throw new PSQLException("postgresql.arr.range");
|
|
|
|
int i = 0;
|
|
switch ( getBaseType() )
|
|
{
|
|
case Types.BIT:
|
|
retVal = new boolean[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((boolean[])retVal)[i++] = ResultSet.toBoolean( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.SMALLINT:
|
|
case Types.INTEGER:
|
|
retVal = new int[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((int[])retVal)[i++] = ResultSet.toInt( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.BIGINT:
|
|
retVal = new long[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((long[])retVal)[i++] = ResultSet.toLong( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.NUMERIC:
|
|
retVal = new BigDecimal[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((BigDecimal[])retVal)[i] = ResultSet.toBigDecimal( arrayContents[(int)index++], 0 );
|
|
break;
|
|
case Types.REAL:
|
|
retVal = new float[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((float[])retVal)[i++] = ResultSet.toFloat( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.DOUBLE:
|
|
retVal = new double[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((double[])retVal)[i++] = ResultSet.toDouble( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.CHAR:
|
|
case Types.VARCHAR:
|
|
retVal = new String[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((String[])retVal)[i++] = arrayContents[(int)index++];
|
|
break;
|
|
case Types.DATE:
|
|
retVal = new java.sql.Date[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((java.sql.Date[])retVal)[i++] = ResultSet.toDate( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.TIME:
|
|
retVal = new java.sql.Time[ count ];
|
|
for ( ; count > 0; count-- )
|
|
((java.sql.Time[])retVal)[i++] = ResultSet.toTime( arrayContents[(int)index++] );
|
|
break;
|
|
case Types.TIMESTAMP:
|
|
retVal = new Timestamp[ count ];
|
|
StringBuffer sbuf = null;
|
|
for ( ; count > 0; count-- )
|
|
((java.sql.Timestamp[])retVal)[i++] = ResultSet.toTimestamp( arrayContents[(int)index], rs );
|
|
break;
|
|
|
|
// Other datatypes not currently supported. If you are really using other types ask
|
|
// yourself if an array of non-trivial data types is really good database design.
|
|
default:
|
|
throw org.postgresql.Driver.notImplemented();
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
public int getBaseType() throws SQLException
|
|
{
|
|
return conn.getSQLType(getBaseTypeName());
|
|
}
|
|
|
|
public String getBaseTypeName() throws SQLException
|
|
{
|
|
String fType = field.getPGType();
|
|
if ( fType.charAt(0) == '_' )
|
|
fType = fType.substring(1);
|
|
return fType;
|
|
}
|
|
|
|
public java.sql.ResultSet getResultSet() throws SQLException
|
|
{
|
|
return getResultSet( 1, 0, null );
|
|
}
|
|
|
|
public java.sql.ResultSet getResultSet(long index, int count) throws SQLException
|
|
{
|
|
return getResultSet( index, count, null );
|
|
}
|
|
|
|
public java.sql.ResultSet getResultSet(Map map) throws SQLException
|
|
{
|
|
return getResultSet( 1, 0, map );
|
|
}
|
|
|
|
public java.sql.ResultSet getResultSet(long index, int count, java.util.Map map) throws SQLException
|
|
{
|
|
Object array = getArray( index, count, map );
|
|
Vector rows = new Vector();
|
|
Field[] fields = new Field[2];
|
|
fields[0] = new Field(conn, "INDEX", conn.getOID("int2"), 2);
|
|
switch ( getBaseType() )
|
|
{
|
|
case Types.BIT:
|
|
boolean[] booleanArray = (boolean[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("bool"), 1);
|
|
for ( int i = 0; i < booleanArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( (booleanArray[i] ? "YES" : "NO") ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
case Types.SMALLINT:
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("int2"), 2);
|
|
case Types.INTEGER:
|
|
int[] intArray = (int[]) array;
|
|
if ( fields[1] == null )
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("int4"), 4);
|
|
for ( int i = 0; i < intArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( Integer.toString(intArray[i]) ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.BIGINT:
|
|
long[] longArray = (long[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("int8"), 8);
|
|
for ( int i = 0; i < longArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( Long.toString(longArray[i]) ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.NUMERIC:
|
|
BigDecimal[] bdArray = (BigDecimal[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("numeric"), -1);
|
|
for ( int i = 0; i < bdArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( bdArray[i].toString() ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.REAL:
|
|
float[] floatArray = (float[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("float4"), 4);
|
|
for ( int i = 0; i < floatArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( Float.toString(floatArray[i]) ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.DOUBLE:
|
|
double[] doubleArray = (double[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("float8"), 8);
|
|
for ( int i = 0; i < doubleArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( Double.toString(doubleArray[i]) ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.CHAR:
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("char"), 1);
|
|
case Types.VARCHAR:
|
|
String[] strArray = (String[]) array;
|
|
if ( fields[1] == null )
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("varchar"), -1);
|
|
for ( int i = 0; i < strArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( strArray[i] ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.DATE:
|
|
java.sql.Date[] dateArray = (java.sql.Date[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("date"), 4);
|
|
for ( int i = 0; i < dateArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( dateArray[i].toString() ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.TIME:
|
|
java.sql.Time[] timeArray = (java.sql.Time[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("time"), 8);
|
|
for ( int i = 0; i < timeArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( timeArray[i].toString() ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
case Types.TIMESTAMP:
|
|
java.sql.Timestamp[] timestampArray = (java.sql.Timestamp[]) array;
|
|
fields[1] = new Field(conn, "VALUE", conn.getOID("timestamp"), 8);
|
|
for ( int i = 0; i < timestampArray.length; i++ )
|
|
{
|
|
byte[][] tuple = new byte[2][0];
|
|
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
|
|
tuple[1] = conn.getEncoding().encode( timestampArray[i].toString() ); // Value
|
|
rows.addElement(tuple);
|
|
}
|
|
break;
|
|
|
|
// Other datatypes not currently supported. If you are really using other types ask
|
|
// yourself if an array of non-trivial data types is really good database design.
|
|
default:
|
|
throw org.postgresql.Driver.notImplemented();
|
|
}
|
|
return new ResultSet((org.postgresql.jdbc2.Connection)conn, fields, rows, "OK", 1 );
|
|
}
|
|
|
|
public String toString()
|
|
{
|
|
return rawString;
|
|
}
|
|
}
|
|
|