Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
6a061da2
Commit
6a061da2
authored
Aug 31, 1997
by
Marc G. Fournier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update patch from Peter <patches@maidast.demon.co.uk>
parent
0b6dc93b
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
4657 additions
and
3969 deletions
+4657
-3969
src/interfaces/jdbc/postgresql/CallableStatement.java
src/interfaces/jdbc/postgresql/CallableStatement.java
+124
-117
src/interfaces/jdbc/postgresql/Connection.java
src/interfaces/jdbc/postgresql/Connection.java
+806
-807
src/interfaces/jdbc/postgresql/DatabaseMetaData.java
src/interfaces/jdbc/postgresql/DatabaseMetaData.java
+2048
-1521
src/interfaces/jdbc/postgresql/Driver.java
src/interfaces/jdbc/postgresql/Driver.java
+264
-236
src/interfaces/jdbc/postgresql/Field.java
src/interfaces/jdbc/postgresql/Field.java
+87
-73
src/interfaces/jdbc/postgresql/PG_Object.java
src/interfaces/jdbc/postgresql/PG_Object.java
+128
-14
src/interfaces/jdbc/postgresql/ResultSet.java
src/interfaces/jdbc/postgresql/ResultSet.java
+789
-791
src/interfaces/jdbc/postgresql/ResultSetMetaData.java
src/interfaces/jdbc/postgresql/ResultSetMetaData.java
+411
-410
No files found.
src/interfaces/jdbc/postgresql/CallableStatement.java
View file @
6a061da2
package
postgresql
;
import
java.math.*
;
import
java.sql.*
;
import
java.math.*
;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* CallableStatement is used to execute SQL stored procedures.
*
* JDBC provides a stored procedure SQL escape that allows stored procedures
* to be called in a standard way for all RDBMS's. This escape syntax has
* one form that includes a result parameter and one that does not. If used,
* the result parameter must be generated as an OUT parameter. The other
* parameters may be used for input, output or both. Parameters are refered
* to sequentially, by number. The first parameter is 1.
*
* <PRE>
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
* </PRE>
*
* IN parameters are set using the set methods inherited from
* PreparedStatement. The type of all OUT parameters must be registered
* prior to executing the stored procedure; their values are retrieved
* after execution via the get methods provided here.
*
* A CallableStatement may return a ResultSet or multiple ResultSets. Multiple
* ResultSets are handled using operations inherited from Statement.
*
* For maximum portability, a call's ResultSets and update counts should be
* processed prior to getting the values of output parameters.
*
* @see java.sql.Connection#prepareCall
* @see java.sql.ResultSet
* @see java.sql.CallableStatement
* JDBC Interface to Postgres95 functions
*/
public
class
CallableStatement
implements
java
.
sql
.
CallableStatement
{
public
void
registerOutParameter
(
int
paramterIndex
,
int
sqlType
)
throws
SQLException
{
// XXX-Not Implemented
}
public
void
registerOutParameter
(
int
parameterIndex
,
int
sqlType
,
int
scale
)
throws
SQLException
{
// XXX-Not Implemented
}
public
boolean
wasNull
()
throws
SQLException
{
// XXX-Not Implemented
}
public
String
getString
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
boolean
getBoolean
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
byte
getByte
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
short
getShort
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
int
getInt
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
long
getLong
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
float
getFloat
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
double
getDouble
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
BigDecimal
getBigDecimal
(
int
parameterIndex
,
int
scale
)
throws
SQLException
{
// XXX-Not Implemented
}
public
byte
[]
getBytes
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
Date
getDate
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
Time
getTime
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
Timestamp
getTimestamp
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
public
Object
getObject
(
int
parameterIndex
)
throws
SQLException
{
// XXX-Not Implemented
}
// Copy methods from the Result set object here.
public
class
CallableStatement
extends
PreparedStatement
implements
java
.
sql
.
CallableStatement
{
CallableStatement
(
Connection
c
,
String
q
)
throws
SQLException
{
super
(
c
,
q
);
}
// Before executing a stored procedure call you must explicitly
// call registerOutParameter to register the java.sql.Type of each
// out parameter.
public
void
registerOutParameter
(
int
parameterIndex
,
int
sqlType
)
throws
SQLException
{
}
// You must also specify the scale for numeric/decimal types:
public
void
registerOutParameter
(
int
parameterIndex
,
int
sqlType
,
int
scale
)
throws
SQLException
{
}
public
boolean
isNull
(
int
parameterIndex
)
throws
SQLException
{
return
true
;
}
// New API (JPM)
public
boolean
wasNull
()
throws
SQLException
{
// check to see if the last access threw an exception
return
false
;
// fake it for now
}
// Methods for retrieving OUT parameters from this statement.
public
String
getChar
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
// New API (JPM)
public
String
getString
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
//public String getVarChar(int parameterIndex) throws SQLException {
// return null;
//}
public
String
getLongVarChar
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
// New API (JPM) (getBit)
public
boolean
getBoolean
(
int
parameterIndex
)
throws
SQLException
{
return
false
;
}
// New API (JPM) (getTinyInt)
public
byte
getByte
(
int
parameterIndex
)
throws
SQLException
{
return
0
;
}
// New API (JPM) (getSmallInt)
public
short
getShort
(
int
parameterIndex
)
throws
SQLException
{
return
0
;
}
// New API (JPM) (getInteger)
public
int
getInt
(
int
parameterIndex
)
throws
SQLException
{
return
0
;
}
// New API (JPM) (getBigInt)
public
long
getLong
(
int
parameterIndex
)
throws
SQLException
{
return
0
;
}
public
float
getFloat
(
int
parameterIndex
)
throws
SQLException
{
return
(
float
)
0.0
;
}
public
double
getDouble
(
int
parameterIndex
)
throws
SQLException
{
return
0.0
;
}
public
BigDecimal
getBigDecimal
(
int
parameterIndex
,
int
scale
)
throws
SQLException
{
return
null
;
}
// New API (JPM) (getBinary)
public
byte
[]
getBytes
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
// New API (JPM) (getLongVarBinary)
public
byte
[]
getBinaryStream
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
public
java
.
sql
.
Date
getDate
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
public
java
.
sql
.
Time
getTime
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
public
java
.
sql
.
Timestamp
getTimestamp
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
//----------------------------------------------------------------------
// Advanced features:
// You can obtain a ParameterMetaData object to get information
// about the parameters to this CallableStatement.
public
DatabaseMetaData
getMetaData
()
{
return
null
;
}
// getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details.
public
Object
getObject
(
int
parameterIndex
)
throws
SQLException
{
return
null
;
}
}
src/interfaces/jdbc/postgresql/Connection.java
View file @
6a061da2
...
...
@@ -28,570 +28,569 @@ import postgresql.*;
*/
public
class
Connection
implements
java
.
sql
.
Connection
{
private
PG_Stream
pg_stream
;
private
String
PG_HOST
;
private
int
PG_PORT
;
private
String
PG_USER
;
private
String
PG_PASSWORD
;
private
String
PG_DATABASE
;
private
boolean
PG_STATUS
;
public
boolean
CONNECTION_OK
=
true
;
public
boolean
CONNECTION_BAD
=
false
;
private
int
STARTUP_CODE
=
7
;
private
boolean
autoCommit
=
true
;
private
boolean
readOnly
=
false
;
private
Driver
this_driver
;
private
String
this_url
;
private
String
cursor
=
null
;
// The positioned update cursor name
/**
* Connect to a PostgreSQL database back end.
*
* @param host the hostname of the database back end
* @param port the port number of the postmaster process
* @param info a Properties[] thing of the user and password
* @param database the database to connect to
* @param u the URL of the connection
* @param d the Driver instantation of the connection
* @return a valid connection profile
* @exception SQLException if a database access error occurs
*/
public
Connection
(
String
host
,
int
port
,
Properties
info
,
String
database
,
String
url
,
Driver
d
)
throws
SQLException
{
int
len
=
288
;
// Length of a startup packet
this_driver
=
d
;
this_url
=
new
String
(
url
);
PG_DATABASE
=
new
String
(
database
);
PG_PASSWORD
=
new
String
(
info
.
getProperty
(
"password"
));
PG_USER
=
new
String
(
info
.
getProperty
(
"user"
));
PG_PORT
=
port
;
PG_HOST
=
new
String
(
host
);
PG_STATUS
=
CONNECTION_BAD
;
try
{
pg_stream
=
new
PG_Stream
(
host
,
port
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Connection failed: "
+
e
.
toString
());
}
// Now we need to construct and send a startup packet
try
{
pg_stream
.
SendInteger
(
len
,
4
);
len
-=
4
;
pg_stream
.
SendInteger
(
STARTUP_CODE
,
4
);
len
-=
4
;
pg_stream
.
Send
(
database
.
getBytes
(),
64
);
len
-=
64
;
pg_stream
.
Send
(
PG_USER
.
getBytes
(),
len
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Connection failed: "
+
e
.
toString
());
}
ExecSQL
(
" "
);
// Test connection
PG_STATUS
=
CONNECTION_OK
;
}
/**
* SQL statements without parameters are normally executed using
* Statement objects. If the same SQL statement is executed many
* times, it is more efficient to use a PreparedStatement
*
* @return a new Statement object
* @exception SQLException passed through from the constructor
*/
public
java
.
sql
.
Statement
createStatement
()
throws
SQLException
{
return
new
Statement
(
this
);
}
/**
* A SQL statement with or without IN parameters can be pre-compiled
* and stored in a PreparedStatement object. This object can then
* be used to efficiently execute this statement multiple times.
*
* <B>Note:</B> This method is optimized for handling parametric
* SQL statements that benefit from precompilation if the drivers
* supports precompilation. PostgreSQL does not support precompilation.
* In this case, the statement is not sent to the database until the
* PreparedStatement is executed. This has no direct effect on users;
* however it does affect which method throws certain SQLExceptions
*
* @param sql a SQL statement that may contain one or more '?' IN
* parameter placeholders
* @return a new PreparedStatement object containing the pre-compiled
* statement.
* @exception SQLException if a database access error occurs.
*/
public
java
.
sql
.
PreparedStatement
prepareStatement
(
String
sql
)
throws
SQLException
{
return
new
PreparedStatement
(
this
,
sql
);
}
/**
* A SQL stored procedure call statement is handled by creating a
* CallableStatement for it. The CallableStatement provides methods
* for setting up its IN and OUT parameters and methods for executing
* it.
*
* <B>Note:</B> This method is optimised for handling stored procedure
* call statements. Some drivers may send the call statement to the
* database when the prepareCall is done; others may wait until the
* CallableStatement is executed. This has no direct effect on users;
* however, it does affect which method throws certain SQLExceptions
*
* @param sql a SQL statement that may contain one or more '?' parameter
* placeholders. Typically this statement is a JDBC function call
* escape string.
* @return a new CallableStatement object containing the pre-compiled
* SQL statement
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
CallableStatement
prepareCall
(
String
sql
)
throws
SQLException
{
throw
new
SQLException
(
"Callable Statements are not supported at this time"
);
// return new CallableStatement(this, sql);
}
/**
* A driver may convert the JDBC sql grammar into its system's
* native SQL grammar prior to sending it; nativeSQL returns the
* native form of the statement that the driver would have sent.
*
* @param sql a SQL statement that may contain one or more '?'
* parameter placeholders
* @return the native form of this statement
* @exception SQLException if a database access error occurs
*/
public
String
nativeSQL
(
String
sql
)
throws
SQLException
{
return
sql
;
}
/**
* If a connection is in auto-commit mode, than all its SQL
* statements will be executed and committed as individual
* transactions. Otherwise, its SQL statements are grouped
* into transactions that are terminated by either commit()
* or rollback(). By default, new connections are in auto-
* commit mode. The commit occurs when the statement completes
* or the next execute occurs, whichever comes first. In the
* case of statements returning a ResultSet, the statement
* completes when the last row of the ResultSet has been retrieved
* or the ResultSet has been closed. In advanced cases, a single
* statement may return multiple results as well as output parameter
* values. Here the commit occurs when all results and output param
* values have been retrieved.
*
* @param autoCommit - true enables auto-commit; false disables it
* @exception SQLException if a database access error occurs
*/
public
void
setAutoCommit
(
boolean
autoCommit
)
throws
SQLException
{
if
(
this
.
autoCommit
==
autoCommit
)
return
;
if
(
autoCommit
)
ExecSQL
(
"end"
);
else
ExecSQL
(
"begin"
);
this
.
autoCommit
=
autoCommit
;
}
/**
* gets the current auto-commit state
*
* @return Current state of the auto-commit mode
* @exception SQLException (why?)
* @see setAutoCommit
*/
public
boolean
getAutoCommit
()
throws
SQLException
{
return
this
.
autoCommit
;
}
/**
* The method commit() makes all changes made since the previous
* commit/rollback permanent and releases any database locks currently
* held by the Connection. This method should only be used when
* auto-commit has been disabled. (If autoCommit == true, then we
* just return anyhow)
*
* @exception SQLException if a database access error occurs
* @see setAutoCommit
*/
public
void
commit
()
throws
SQLException
{
if
(
autoCommit
)
return
;
ExecSQL
(
"commit"
);
autoCommit
=
true
;
ExecSQL
(
"begin"
);
autoCommit
=
false
;
}
/**
* The method rollback() drops all changes made since the previous
* commit/rollback and releases any database locks currently held by
* the Connection.
*
* @exception SQLException if a database access error occurs
* @see commit
*/
public
void
rollback
()
throws
SQLException
{
if
(
autoCommit
)
return
;
ExecSQL
(
"rollback"
);
autoCommit
=
true
;
ExecSQL
(
"begin"
);
autoCommit
=
false
;
}
/**
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head)
*
* <B>Note:</B> A Connection is automatically closed when it is
* garbage collected. Certain fatal errors also result in a closed
* connection.
*
* @exception SQLException if a database access error occurs
*/
public
void
close
()
throws
SQLException
{
if
(
pg_stream
!=
null
)
{
try
{
pg_stream
.
close
();
}
catch
(
IOException
e
)
{}
pg_stream
=
null
;
}
}
/**
* Tests to see if a Connection is closed
*
* @return the status of the connection
* @exception SQLException (why?)
*/
public
boolean
isClosed
()
throws
SQLException
{
return
(
pg_stream
==
null
);
}
/**
* A connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is made
* available through a DatabaseMetaData object.
*
* @return a DatabaseMetaData object for this connection
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
DatabaseMetaData
getMetaData
()
throws
SQLException
{
// return new DatabaseMetaData(this);
throw
new
SQLException
(
"DatabaseMetaData not supported"
);
}
/**
* You can put a connection in read-only mode as a hunt to enable
* database optimizations
*
* <B>Note:</B> setReadOnly cannot be called while in the middle
* of a transaction
*
* @param readOnly - true enables read-only mode; false disables it
* @exception SQLException if a database access error occurs
*/
public
void
setReadOnly
(
boolean
readOnly
)
throws
SQLException
{
this
.
readOnly
=
readOnly
;
}
/**
* Tests to see if the connection is in Read Only Mode. Note that
* we cannot really put the database in read only mode, but we pretend
* we can by returning the value of the readOnly flag
*
* @return true if the connection is read only
* @exception SQLException if a database access error occurs
*/
public
boolean
isReadOnly
()
throws
SQLException
{
return
readOnly
;
}
/**
* A sub-space of this Connection's database may be selected by
* setting a catalog name. If the driver does not support catalogs,
* it will silently ignore this request
*
* @exception SQLException if a database access error occurs
*/
public
void
setCatalog
(
String
catalog
)
throws
SQLException
{
// No-op
}
/**
* Return the connections current catalog name, or null if no
* catalog name is set, or we dont support catalogs.
*
* @return the current catalog name or null
* @exception SQLException if a database access error occurs
*/
public
String
getCatalog
()
throws
SQLException
{
return
null
;
}
/**
* You can call this method to try to change the transaction
* isolation level using one of the TRANSACTION_* values.
*
* <B>Note:</B> setTransactionIsolation cannot be called while
* in the middle of a transaction
*
* @param level one of the TRANSACTION_* isolation values with
* the exception of TRANSACTION_NONE; some databases may
* not support other values
* @exception SQLException if a database access error occurs
* @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
*/
public
void
setTransactionIsolation
(
int
level
)
throws
SQLException
{
throw
new
SQLException
(
"Transaction Isolation Levels are not implemented"
);
}
/**
* Get this Connection's current transaction isolation mode.
*
* @return the current TRANSACTION_* mode value
* @exception SQLException if a database access error occurs
*/
public
int
getTransactionIsolation
()
throws
SQLException
{
return
java
.
sql
.
Connection
.
TRANSACTION_SERIALIZABLE
;
}
/**
* The first warning reported by calls on this Connection is
* returned.
*
* <B>Note:</B> Sebsequent warnings will be changed to this
* SQLWarning
*
* @return the first SQLWarning or null
* @exception SQLException if a database access error occurs
*/
public
SQLWarning
getWarnings
()
throws
SQLException
{
return
null
;
// We handle warnings as errors
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this connection.
*
* @exception SQLException if a database access error occurs
*/
public
void
clearWarnings
()
throws
SQLException
{
// Not handles since we handle wanrings as errors
}
// **********************************************************
// END OF PUBLIC INTERFACE
// **********************************************************
/**
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param sql the SQL statement to be executed
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public
synchronized
ResultSet
ExecSQL
(
String
sql
)
throws
SQLException
{
Field
[]
fields
=
null
;
Vector
tuples
=
new
Vector
();
byte
[]
buf
=
new
byte
[
sql
.
length
()];
int
fqp
=
0
;
boolean
hfr
=
false
;
String
recv_status
=
null
,
msg
;
SQLException
final_error
=
null
;
if
(
sql
.
length
()
>
8192
)
throw
new
SQLException
(
"SQL Statement too long: "
+
sql
);
try
{
pg_stream
.
SendChar
(
'Q'
);
buf
=
sql
.
getBytes
();
pg_stream
.
Send
(
buf
);
pg_stream
.
SendChar
(
0
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"I/O Error: "
+
e
.
toString
());
}
while
(!
hfr
||
fqp
>
0
)
{
int
c
=
pg_stream
.
ReceiveChar
();
switch
(
c
)
{
case
'A'
:
// Asynchronous Notify
int
pid
=
pg_stream
.
ReceiveInteger
(
4
);
msg
=
pg_stream
.
ReceiveString
(
8192
);
break
;
case
'B'
:
// Binary Data Transfer
if
(
fields
==
null
)
throw
new
SQLException
(
"Tuple received before MetaData"
);
tuples
.
addElement
(
pg_stream
.
ReceiveTuple
(
fields
.
length
,
true
));
break
;
case
'C'
:
// Command Status
recv_status
=
pg_stream
.
ReceiveString
(
8192
);
if
(
fields
!=
null
)
hfr
=
true
;
else
{
try
{
pg_stream
.
SendChar
(
'Q'
);
pg_stream
.
SendChar
(
' '
);
pg_stream
.
SendChar
(
0
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"I/O Error: "
+
e
.
toString
());
}
fqp
++;
}
break
;
case
'D'
:
// Text Data Transfer
if
(
fields
==
null
)
throw
new
SQLException
(
"Tuple received before MetaData"
);
tuples
.
addElement
(
pg_stream
.
ReceiveTuple
(
fields
.
length
,
false
));
break
;
case
'E'
:
// Error Message
msg
=
pg_stream
.
ReceiveString
(
4096
);
final_error
=
new
SQLException
(
msg
);
hfr
=
true
;
break
;
case
'I'
:
// Empty Query
int
t
=
pg_stream
.
ReceiveChar
();
if
(
t
!=
0
)
throw
new
SQLException
(
"Garbled Data"
);
if
(
fqp
>
0
)
fqp
--;
if
(
fqp
==
0
)
hfr
=
true
;
break
;
case
'N'
:
// Error Notification
msg
=
pg_stream
.
ReceiveString
(
4096
);
PrintStream
log
=
DriverManager
.
getLogStream
();
log
.
println
(
msg
);
break
;
case
'P'
:
// Portal Name
String
pname
=
pg_stream
.
ReceiveString
(
8192
);
break
;
case
'T'
:
// MetaData Field Description
if
(
fields
!=
null
)
throw
new
SQLException
(
"Cannot handle multiple result groups"
);
fields
=
ReceiveFields
();
break
;
default
:
throw
new
SQLException
(
"Unknown Response Type: "
+
(
char
)
c
);
}
}
if
(
final_error
!=
null
)
throw
final_error
;
return
new
ResultSet
(
this
,
fields
,
tuples
,
recv_status
,
1
);
}
/**
* Receive the field descriptions from the back end
*
* @return an array of the Field object describing the fields
* @exception SQLException if a database error occurs
*/
private
Field
[]
ReceiveFields
()
throws
SQLException
{
int
nf
=
pg_stream
.
ReceiveInteger
(
2
),
i
;
Field
[]
fields
=
new
Field
[
nf
];
for
(
i
=
0
;
i
<
nf
;
++
i
)
private
PG_Stream
pg_stream
;
private
String
PG_HOST
;
private
int
PG_PORT
;
private
String
PG_USER
;
private
String
PG_PASSWORD
;
private
String
PG_DATABASE
;
private
boolean
PG_STATUS
;
public
boolean
CONNECTION_OK
=
true
;
public
boolean
CONNECTION_BAD
=
false
;
private
int
STARTUP_CODE
=
7
;
private
boolean
autoCommit
=
true
;
private
boolean
readOnly
=
false
;
protected
Driver
this_driver
;
private
String
this_url
;
private
String
cursor
=
null
;
// The positioned update cursor name
/**
* Connect to a PostgreSQL database back end.
*
* @param host the hostname of the database back end
* @param port the port number of the postmaster process
* @param info a Properties[] thing of the user and password
* @param database the database to connect to
* @param u the URL of the connection
* @param d the Driver instantation of the connection
* @return a valid connection profile
* @exception SQLException if a database access error occurs
*/
public
Connection
(
String
host
,
int
port
,
Properties
info
,
String
database
,
String
url
,
Driver
d
)
throws
SQLException
{
int
len
=
288
;
// Length of a startup packet
this_driver
=
d
;
this_url
=
new
String
(
url
);
PG_DATABASE
=
new
String
(
database
);
PG_PASSWORD
=
new
String
(
info
.
getProperty
(
"password"
));
PG_USER
=
new
String
(
info
.
getProperty
(
"user"
));
PG_PORT
=
port
;
PG_HOST
=
new
String
(
host
);
PG_STATUS
=
CONNECTION_BAD
;
try
{
pg_stream
=
new
PG_Stream
(
host
,
port
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Connection failed: "
+
e
.
toString
());
}
// Now we need to construct and send a startup packet
try
{
pg_stream
.
SendInteger
(
len
,
4
);
len
-=
4
;
pg_stream
.
SendInteger
(
STARTUP_CODE
,
4
);
len
-=
4
;
pg_stream
.
Send
(
database
.
getBytes
(),
64
);
len
-=
64
;
pg_stream
.
Send
(
PG_USER
.
getBytes
(),
len
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Connection failed: "
+
e
.
toString
());
}
ExecSQL
(
" "
);
// Test connection
PG_STATUS
=
CONNECTION_OK
;
}
/**
* SQL statements without parameters are normally executed using
* Statement objects. If the same SQL statement is executed many
* times, it is more efficient to use a PreparedStatement
*
* @return a new Statement object
* @exception SQLException passed through from the constructor
*/
public
java
.
sql
.
Statement
createStatement
()
throws
SQLException
{
return
new
Statement
(
this
);
}
/**
* A SQL statement with or without IN parameters can be pre-compiled
* and stored in a PreparedStatement object. This object can then
* be used to efficiently execute this statement multiple times.
*
* <B>Note:</B> This method is optimized for handling parametric
* SQL statements that benefit from precompilation if the drivers
* supports precompilation. PostgreSQL does not support precompilation.
* In this case, the statement is not sent to the database until the
* PreparedStatement is executed. This has no direct effect on users;
* however it does affect which method throws certain SQLExceptions
*
* @param sql a SQL statement that may contain one or more '?' IN
* parameter placeholders
* @return a new PreparedStatement object containing the pre-compiled
* statement.
* @exception SQLException if a database access error occurs.
*/
public
java
.
sql
.
PreparedStatement
prepareStatement
(
String
sql
)
throws
SQLException
{
return
new
PreparedStatement
(
this
,
sql
);
}
/**
* A SQL stored procedure call statement is handled by creating a
* CallableStatement for it. The CallableStatement provides methods
* for setting up its IN and OUT parameters and methods for executing
* it.
*
* <B>Note:</B> This method is optimised for handling stored procedure
* call statements. Some drivers may send the call statement to the
* database when the prepareCall is done; others may wait until the
* CallableStatement is executed. This has no direct effect on users;
* however, it does affect which method throws certain SQLExceptions
*
* @param sql a SQL statement that may contain one or more '?' parameter
* placeholders. Typically this statement is a JDBC function call
* escape string.
* @return a new CallableStatement object containing the pre-compiled
* SQL statement
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
CallableStatement
prepareCall
(
String
sql
)
throws
SQLException
{
throw
new
SQLException
(
"Callable Statements are not supported at this time"
);
// return new CallableStatement(this, sql);
}
/**
* A driver may convert the JDBC sql grammar into its system's
* native SQL grammar prior to sending it; nativeSQL returns the
* native form of the statement that the driver would have sent.
*
* @param sql a SQL statement that may contain one or more '?'
* parameter placeholders
* @return the native form of this statement
* @exception SQLException if a database access error occurs
*/
public
String
nativeSQL
(
String
sql
)
throws
SQLException
{
return
sql
;
}
/**
* If a connection is in auto-commit mode, than all its SQL
* statements will be executed and committed as individual
* transactions. Otherwise, its SQL statements are grouped
* into transactions that are terminated by either commit()
* or rollback(). By default, new connections are in auto-
* commit mode. The commit occurs when the statement completes
* or the next execute occurs, whichever comes first. In the
* case of statements returning a ResultSet, the statement
* completes when the last row of the ResultSet has been retrieved
* or the ResultSet has been closed. In advanced cases, a single
* statement may return multiple results as well as output parameter
* values. Here the commit occurs when all results and output param
* values have been retrieved.
*
* @param autoCommit - true enables auto-commit; false disables it
* @exception SQLException if a database access error occurs
*/
public
void
setAutoCommit
(
boolean
autoCommit
)
throws
SQLException
{
if
(
this
.
autoCommit
==
autoCommit
)
return
;
if
(
autoCommit
)
ExecSQL
(
"end"
);
else
ExecSQL
(
"begin"
);
this
.
autoCommit
=
autoCommit
;
}
/**
* gets the current auto-commit state
*
* @return Current state of the auto-commit mode
* @exception SQLException (why?)
* @see setAutoCommit
*/
public
boolean
getAutoCommit
()
throws
SQLException
{
return
this
.
autoCommit
;
}
/**
* The method commit() makes all changes made since the previous
* commit/rollback permanent and releases any database locks currently
* held by the Connection. This method should only be used when
* auto-commit has been disabled. (If autoCommit == true, then we
* just return anyhow)
*
* @exception SQLException if a database access error occurs
* @see setAutoCommit
*/
public
void
commit
()
throws
SQLException
{
if
(
autoCommit
)
return
;
ExecSQL
(
"commit"
);
autoCommit
=
true
;
ExecSQL
(
"begin"
);
autoCommit
=
false
;
}
/**
* The method rollback() drops all changes made since the previous
* commit/rollback and releases any database locks currently held by
* the Connection.
*
* @exception SQLException if a database access error occurs
* @see commit
*/
public
void
rollback
()
throws
SQLException
{
if
(
autoCommit
)
return
;
ExecSQL
(
"rollback"
);
autoCommit
=
true
;
ExecSQL
(
"begin"
);
autoCommit
=
false
;
}
/**
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head)
*
* <B>Note:</B> A Connection is automatically closed when it is
* garbage collected. Certain fatal errors also result in a closed
* connection.
*
* @exception SQLException if a database access error occurs
*/
public
void
close
()
throws
SQLException
{
if
(
pg_stream
!=
null
)
{
try
{
pg_stream
.
close
();
}
catch
(
IOException
e
)
{}
pg_stream
=
null
;
}
}
/**
* Tests to see if a Connection is closed
*
* @return the status of the connection
* @exception SQLException (why?)
*/
public
boolean
isClosed
()
throws
SQLException
{
return
(
pg_stream
==
null
);
}
/**
* A connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is made
* available through a DatabaseMetaData object.
*
* @return a DatabaseMetaData object for this connection
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
DatabaseMetaData
getMetaData
()
throws
SQLException
{
return
new
DatabaseMetaData
(
this
);
}
/**
* You can put a connection in read-only mode as a hunt to enable
* database optimizations
*
* <B>Note:</B> setReadOnly cannot be called while in the middle
* of a transaction
*
* @param readOnly - true enables read-only mode; false disables it
* @exception SQLException if a database access error occurs
*/
public
void
setReadOnly
(
boolean
readOnly
)
throws
SQLException
{
this
.
readOnly
=
readOnly
;
}
/**
* Tests to see if the connection is in Read Only Mode. Note that
* we cannot really put the database in read only mode, but we pretend
* we can by returning the value of the readOnly flag
*
* @return true if the connection is read only
* @exception SQLException if a database access error occurs
*/
public
boolean
isReadOnly
()
throws
SQLException
{
return
readOnly
;
}
/**
* A sub-space of this Connection's database may be selected by
* setting a catalog name. If the driver does not support catalogs,
* it will silently ignore this request
*
* @exception SQLException if a database access error occurs
*/
public
void
setCatalog
(
String
catalog
)
throws
SQLException
{
// No-op
}
/**
* Return the connections current catalog name, or null if no
* catalog name is set, or we dont support catalogs.
*
* @return the current catalog name or null
* @exception SQLException if a database access error occurs
*/
public
String
getCatalog
()
throws
SQLException
{
return
null
;
}
/**
* You can call this method to try to change the transaction
* isolation level using one of the TRANSACTION_* values.
*
* <B>Note:</B> setTransactionIsolation cannot be called while
* in the middle of a transaction
*
* @param level one of the TRANSACTION_* isolation values with
* the exception of TRANSACTION_NONE; some databases may
* not support other values
* @exception SQLException if a database access error occurs
* @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
*/
public
void
setTransactionIsolation
(
int
level
)
throws
SQLException
{
throw
new
SQLException
(
"Transaction Isolation Levels are not implemented"
);
}
/**
* Get this Connection's current transaction isolation mode.
*
* @return the current TRANSACTION_* mode value
* @exception SQLException if a database access error occurs
*/
public
int
getTransactionIsolation
()
throws
SQLException
{
return
java
.
sql
.
Connection
.
TRANSACTION_SERIALIZABLE
;
}
/**
* The first warning reported by calls on this Connection is
* returned.
*
* <B>Note:</B> Sebsequent warnings will be changed to this
* SQLWarning
*
* @return the first SQLWarning or null
* @exception SQLException if a database access error occurs
*/
public
SQLWarning
getWarnings
()
throws
SQLException
{
return
null
;
// We handle warnings as errors
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this connection.
*
* @exception SQLException if a database access error occurs
*/
public
void
clearWarnings
()
throws
SQLException
{
// Not handles since we handle wanrings as errors
}
// **********************************************************
// END OF PUBLIC INTERFACE
// **********************************************************
/**
* Send a query to the backend. Returns one of the ResultSet
* objects.
*
* <B>Note:</B> there does not seem to be any method currently
* in existance to return the update count.
*
* @param sql the SQL statement to be executed
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public
synchronized
ResultSet
ExecSQL
(
String
sql
)
throws
SQLException
{
Field
[]
fields
=
null
;
Vector
tuples
=
new
Vector
();
byte
[]
buf
=
new
byte
[
sql
.
length
()];
int
fqp
=
0
;
boolean
hfr
=
false
;
String
recv_status
=
null
,
msg
;
SQLException
final_error
=
null
;
if
(
sql
.
length
()
>
8192
)
throw
new
SQLException
(
"SQL Statement too long: "
+
sql
);
try
{
pg_stream
.
SendChar
(
'Q'
);
buf
=
sql
.
getBytes
();
pg_stream
.
Send
(
buf
);
pg_stream
.
SendChar
(
0
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"I/O Error: "
+
e
.
toString
());
}
while
(!
hfr
||
fqp
>
0
)
{
int
c
=
pg_stream
.
ReceiveChar
();
switch
(
c
)
{
case
'A'
:
// Asynchronous Notify
int
pid
=
pg_stream
.
ReceiveInteger
(
4
);
msg
=
pg_stream
.
ReceiveString
(
8192
);
break
;
case
'B'
:
// Binary Data Transfer
if
(
fields
==
null
)
throw
new
SQLException
(
"Tuple received before MetaData"
);
tuples
.
addElement
(
pg_stream
.
ReceiveTuple
(
fields
.
length
,
true
));
break
;
case
'C'
:
// Command Status
recv_status
=
pg_stream
.
ReceiveString
(
8192
);
if
(
fields
!=
null
)
hfr
=
true
;
else
{
String
typname
=
pg_stream
.
ReceiveString
(
8192
);
int
typid
=
pg_stream
.
ReceiveInteger
(
4
);
int
typlen
=
pg_stream
.
ReceiveInteger
(
2
);
fields
[
i
]
=
new
Field
(
this
,
typname
,
typid
,
typlen
);
try
{
pg_stream
.
SendChar
(
'Q'
);
pg_stream
.
SendChar
(
' '
);
pg_stream
.
SendChar
(
0
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"I/O Error: "
+
e
.
toString
());
}
fqp
++;
}
return
fields
;
}
/**
* In SQL, a result table can be retrieved through a cursor that
* is named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references the
* cursor name.
*
* We support one cursor per connection.
*
* setCursorName sets the cursor name.
*
* @param cursor the cursor name
* @exception SQLException if a database access error occurs
*/
public
void
setCursorName
(
String
cursor
)
throws
SQLException
{
this
.
cursor
=
cursor
;
}
/**
* getCursorName gets the cursor name.
*
* @return the current cursor name
* @exception SQLException if a database access error occurs
*/
public
String
getCursorName
()
throws
SQLException
{
return
cursor
;
}
/**
* We are required to bring back certain information by
* the DatabaseMetaData class. These functions do that.
*
* Method getURL() brings back the URL (good job we saved it)
*
* @return the url
* @exception SQLException just in case...
*/
public
String
getURL
()
throws
SQLException
{
return
this_url
;
}
/**
* Method getUserName() brings back the User Name (again, we
* saved it)
*
* @return the user name
* @exception SQLException just in case...
*/
public
String
getUserName
()
throws
SQLException
{
return
PG_USER
;
}
break
;
case
'D'
:
// Text Data Transfer
if
(
fields
==
null
)
throw
new
SQLException
(
"Tuple received before MetaData"
);
tuples
.
addElement
(
pg_stream
.
ReceiveTuple
(
fields
.
length
,
false
));
break
;
case
'E'
:
// Error Message
msg
=
pg_stream
.
ReceiveString
(
4096
);
final_error
=
new
SQLException
(
msg
);
hfr
=
true
;
break
;
case
'I'
:
// Empty Query
int
t
=
pg_stream
.
ReceiveChar
();
if
(
t
!=
0
)
throw
new
SQLException
(
"Garbled Data"
);
if
(
fqp
>
0
)
fqp
--;
if
(
fqp
==
0
)
hfr
=
true
;
break
;
case
'N'
:
// Error Notification
msg
=
pg_stream
.
ReceiveString
(
4096
);
PrintStream
log
=
DriverManager
.
getLogStream
();
log
.
println
(
msg
);
break
;
case
'P'
:
// Portal Name
String
pname
=
pg_stream
.
ReceiveString
(
8192
);
break
;
case
'T'
:
// MetaData Field Description
if
(
fields
!=
null
)
throw
new
SQLException
(
"Cannot handle multiple result groups"
);
fields
=
ReceiveFields
();
break
;
default
:
throw
new
SQLException
(
"Unknown Response Type: "
+
(
char
)
c
);
}
}
if
(
final_error
!=
null
)
throw
final_error
;
return
new
ResultSet
(
this
,
fields
,
tuples
,
recv_status
,
1
);
}
/**
* Receive the field descriptions from the back end
*
* @return an array of the Field object describing the fields
* @exception SQLException if a database error occurs
*/
private
Field
[]
ReceiveFields
()
throws
SQLException
{
int
nf
=
pg_stream
.
ReceiveInteger
(
2
),
i
;
Field
[]
fields
=
new
Field
[
nf
];
for
(
i
=
0
;
i
<
nf
;
++
i
)
{
String
typname
=
pg_stream
.
ReceiveString
(
8192
);
int
typid
=
pg_stream
.
ReceiveInteger
(
4
);
int
typlen
=
pg_stream
.
ReceiveInteger
(
2
);
fields
[
i
]
=
new
Field
(
this
,
typname
,
typid
,
typlen
);
}
return
fields
;
}
/**
* In SQL, a result table can be retrieved through a cursor that
* is named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references the
* cursor name.
*
* We support one cursor per connection.
*
* setCursorName sets the cursor name.
*
* @param cursor the cursor name
* @exception SQLException if a database access error occurs
*/
public
void
setCursorName
(
String
cursor
)
throws
SQLException
{
this
.
cursor
=
cursor
;
}
/**
* getCursorName gets the cursor name.
*
* @return the current cursor name
* @exception SQLException if a database access error occurs
*/
public
String
getCursorName
()
throws
SQLException
{
return
cursor
;
}
/**
* We are required to bring back certain information by
* the DatabaseMetaData class. These functions do that.
*
* Method getURL() brings back the URL (good job we saved it)
*
* @return the url
* @exception SQLException just in case...
*/
public
String
getURL
()
throws
SQLException
{
return
this_url
;
}
/**
* Method getUserName() brings back the User Name (again, we
* saved it)
*
* @return the user name
* @exception SQLException just in case...
*/
public
String
getUserName
()
throws
SQLException
{
return
PG_USER
;
}
}
// ***********************************************************************
...
...
@@ -599,249 +598,249 @@ public class Connection implements java.sql.Connection
// This class handles all the Streamed I/O for a postgresql connection
class
PG_Stream
{
private
Socket
connection
;
private
InputStream
pg_input
;
private
OutputStream
pg_output
;
/**
* Constructor: Connect to the PostgreSQL back end and return
* a stream connection.
*
* @param host the hostname to connect to
* @param port the port number that the postmaster is sitting on
* @exception IOException if an IOException occurs below it.
*/
public
PG_Stream
(
String
host
,
int
port
)
throws
IOException
{
connection
=
new
Socket
(
host
,
port
);
pg_input
=
connection
.
getInputStream
();
pg_output
=
connection
.
getOutputStream
();
}
/**
* Sends a single character to the back end
*
* @param val the character to be sent
* @exception IOException if an I/O error occurs
*/
public
void
SendChar
(
int
val
)
throws
IOException
{
pg_output
.
write
(
val
);
}
/**
* Sends an integer to the back end
*
* @param val the integer to be sent
* @param siz the length of the integer in bytes (size of structure)
* @exception IOException if an I/O error occurs
*/
public
void
SendInteger
(
int
val
,
int
siz
)
throws
IOException
{
byte
[]
buf
=
new
byte
[
siz
];
while
(
siz
--
>
0
)
{
buf
[
siz
]
=
(
byte
)(
val
&
0xff
);
val
>>=
8
;
}
Send
(
buf
);
}
/**
* Send an array of bytes to the backend
*
* @param buf The array of bytes to be sent
* @exception IOException if an I/O error occurs
*/
public
void
Send
(
byte
buf
[])
throws
IOException
{
pg_output
.
write
(
buf
);
}
/**
* Send an exact array of bytes to the backend - if the length
* has not been reached, send nulls until it has.
*
* @param buf the array of bytes to be sent
* @param siz the number of bytes to be sent
* @exception IOException if an I/O error occurs
*/
public
void
Send
(
byte
buf
[],
int
siz
)
throws
IOException
{
int
i
;
pg_output
.
write
(
buf
,
0
,
(
buf
.
length
<
siz
?
buf
.
length
:
siz
));
if
(
buf
.
length
<
siz
)
{
for
(
i
=
buf
.
length
;
i
<
siz
;
++
i
)
{
pg_output
.
write
(
0
);
}
}
}
/**
* Receives a single character from the backend
*
* @return the character received
* @exception SQLException if an I/O Error returns
*/
public
int
ReceiveChar
()
throws
SQLException
{
int
c
=
0
;
try
{
c
=
pg_input
.
read
();
if
(
c
<
0
)
throw
new
IOException
(
"EOF"
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
return
c
;
}
/**
* Receives an integer from the backend
*
* @param siz length of the integer in bytes
* @return the integer received from the backend
* @exception SQLException if an I/O error occurs
*/
public
int
ReceiveInteger
(
int
siz
)
throws
SQLException
{
int
n
=
0
;
try
{
for
(
int
i
=
0
;
i
<
siz
;
i
++)
{
int
b
=
pg_input
.
read
();
if
(
b
<
0
)
throw
new
IOException
(
"EOF"
);
n
=
n
|
(
b
>>
(
8
*
i
))
;
}
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
return
n
;
}
/**
* Receives a null-terminated string from the backend. Maximum of
* maxsiz bytes - if we don't see a null, then we assume something
* has gone wrong.
*
* @param maxsiz maximum length of string
* @return string from back end
* @exception SQLException if an I/O error occurs
*/
public
String
ReceiveString
(
int
maxsiz
)
throws
SQLException
{
byte
[]
rst
=
new
byte
[
maxsiz
];
int
s
=
0
;
try
{
while
(
s
<
maxsiz
)
{
int
c
=
pg_input
.
read
();
if
(
c
<
0
)
throw
new
IOException
(
"EOF"
);
else
if
(
c
==
0
)
break
;
else
rst
[
s
++]
=
(
byte
)
c
;
}
if
(
s
>=
maxsiz
)
throw
new
IOException
(
"Too Much Data"
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
String
v
=
new
String
(
rst
,
0
,
s
);
return
v
;
}
/**
* Read a tuple from the back end. A tuple is a two dimensional
* array of bytes
*
* @param nf the number of fields expected
* @param bin true if the tuple is a binary tuple
* @return null if the current response has no more tuples, otherwise
* an array of strings
* @exception SQLException if a data I/O error occurs
*/
public
byte
[][]
ReceiveTuple
(
int
nf
,
boolean
bin
)
throws
SQLException
{
int
i
,
bim
=
(
nf
+
7
)/
8
;
byte
[]
bitmask
=
Receive
(
bim
);
byte
[][]
answer
=
new
byte
[
nf
][
0
];
int
whichbit
=
0x80
;
int
whichbyte
=
0
;
for
(
i
=
0
;
i
<
nf
;
++
i
)
{
boolean
isNull
=
((
bitmask
[
whichbyte
]
&
whichbit
)
==
0
);
whichbit
>>=
1
;
if
(
whichbit
==
0
)
{
++
whichbyte
;
whichbit
=
0x80
;
}
if
(
isNull
)
answer
[
i
]
=
null
;
else
{
int
len
=
ReceiveInteger
(
4
);
if
(!
bin
)
len
-=
4
;
if
(
len
<
0
)
len
=
0
;
answer
[
i
]
=
Receive
(
len
);
}
}
return
answer
;
}
/**
* Reads in a given number of bytes from the backend
*
* @param siz number of bytes to read
* @return array of bytes received
* @exception SQLException if a data I/O error occurs
*/
private
byte
[]
Receive
(
int
siz
)
throws
SQLException
{
byte
[]
answer
=
new
byte
[
siz
];
int
s
=
0
;
try
{
while
(
s
<
siz
)
{
int
w
=
pg_input
.
read
(
answer
,
s
,
siz
-
s
);
if
(
w
<
0
)
throw
new
IOException
(
"EOF"
);
s
+=
w
;
}
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
return
answer
;
}
/**
* Closes the connection
*
* @exception IOException if a IO Error occurs
*/
public
void
close
()
throws
IOException
{
pg_output
.
close
();
pg_input
.
close
();
connection
.
close
();
}
private
Socket
connection
;
private
InputStream
pg_input
;
private
OutputStream
pg_output
;
/**
* Constructor: Connect to the PostgreSQL back end and return
* a stream connection.
*
* @param host the hostname to connect to
* @param port the port number that the postmaster is sitting on
* @exception IOException if an IOException occurs below it.
*/
public
PG_Stream
(
String
host
,
int
port
)
throws
IOException
{
connection
=
new
Socket
(
host
,
port
);
pg_input
=
connection
.
getInputStream
();
pg_output
=
connection
.
getOutputStream
();
}
/**
* Sends a single character to the back end
*
* @param val the character to be sent
* @exception IOException if an I/O error occurs
*/
public
void
SendChar
(
int
val
)
throws
IOException
{
pg_output
.
write
(
val
);
}
/**
* Sends an integer to the back end
*
* @param val the integer to be sent
* @param siz the length of the integer in bytes (size of structure)
* @exception IOException if an I/O error occurs
*/
public
void
SendInteger
(
int
val
,
int
siz
)
throws
IOException
{
byte
[]
buf
=
new
byte
[
siz
];
while
(
siz
--
>
0
)
{
buf
[
siz
]
=
(
byte
)(
val
&
0xff
);
val
>>=
8
;
}
Send
(
buf
);
}
/**
* Send an array of bytes to the backend
*
* @param buf The array of bytes to be sent
* @exception IOException if an I/O error occurs
*/
public
void
Send
(
byte
buf
[])
throws
IOException
{
pg_output
.
write
(
buf
);
}
/**
* Send an exact array of bytes to the backend - if the length
* has not been reached, send nulls until it has.
*
* @param buf the array of bytes to be sent
* @param siz the number of bytes to be sent
* @exception IOException if an I/O error occurs
*/
public
void
Send
(
byte
buf
[],
int
siz
)
throws
IOException
{
int
i
;
pg_output
.
write
(
buf
,
0
,
(
buf
.
length
<
siz
?
buf
.
length
:
siz
));
if
(
buf
.
length
<
siz
)
{
for
(
i
=
buf
.
length
;
i
<
siz
;
++
i
)
{
pg_output
.
write
(
0
);
}
}
}
/**
* Receives a single character from the backend
*
* @return the character received
* @exception SQLException if an I/O Error returns
*/
public
int
ReceiveChar
()
throws
SQLException
{
int
c
=
0
;
try
{
c
=
pg_input
.
read
();
if
(
c
<
0
)
throw
new
IOException
(
"EOF"
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
return
c
;
}
/**
* Receives an integer from the backend
*
* @param siz length of the integer in bytes
* @return the integer received from the backend
* @exception SQLException if an I/O error occurs
*/
public
int
ReceiveInteger
(
int
siz
)
throws
SQLException
{
int
n
=
0
;
try
{
for
(
int
i
=
0
;
i
<
siz
;
i
++)
{
int
b
=
pg_input
.
read
();
if
(
b
<
0
)
throw
new
IOException
(
"EOF"
);
n
=
n
|
(
b
>>
(
8
*
i
))
;
}
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
return
n
;
}
/**
* Receives a null-terminated string from the backend. Maximum of
* maxsiz bytes - if we don't see a null, then we assume something
* has gone wrong.
*
* @param maxsiz maximum length of string
* @return string from back end
* @exception SQLException if an I/O error occurs
*/
public
String
ReceiveString
(
int
maxsiz
)
throws
SQLException
{
byte
[]
rst
=
new
byte
[
maxsiz
];
int
s
=
0
;
try
{
while
(
s
<
maxsiz
)
{
int
c
=
pg_input
.
read
();
if
(
c
<
0
)
throw
new
IOException
(
"EOF"
);
else
if
(
c
==
0
)
break
;
else
rst
[
s
++]
=
(
byte
)
c
;
}
if
(
s
>=
maxsiz
)
throw
new
IOException
(
"Too Much Data"
);
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
String
v
=
new
String
(
rst
,
0
,
s
);
return
v
;
}
/**
* Read a tuple from the back end. A tuple is a two dimensional
* array of bytes
*
* @param nf the number of fields expected
* @param bin true if the tuple is a binary tuple
* @return null if the current response has no more tuples, otherwise
* an array of strings
* @exception SQLException if a data I/O error occurs
*/
public
byte
[][]
ReceiveTuple
(
int
nf
,
boolean
bin
)
throws
SQLException
{
int
i
,
bim
=
(
nf
+
7
)/
8
;
byte
[]
bitmask
=
Receive
(
bim
);
byte
[][]
answer
=
new
byte
[
nf
][
0
];
int
whichbit
=
0x80
;
int
whichbyte
=
0
;
for
(
i
=
0
;
i
<
nf
;
++
i
)
{
boolean
isNull
=
((
bitmask
[
whichbyte
]
&
whichbit
)
==
0
);
whichbit
>>=
1
;
if
(
whichbit
==
0
)
{
++
whichbyte
;
whichbit
=
0x80
;
}
if
(
isNull
)
answer
[
i
]
=
null
;
else
{
int
len
=
ReceiveInteger
(
4
);
if
(!
bin
)
len
-=
4
;
if
(
len
<
0
)
len
=
0
;
answer
[
i
]
=
Receive
(
len
);
}
}
return
answer
;
}
/**
* Reads in a given number of bytes from the backend
*
* @param siz number of bytes to read
* @return array of bytes received
* @exception SQLException if a data I/O error occurs
*/
private
byte
[]
Receive
(
int
siz
)
throws
SQLException
{
byte
[]
answer
=
new
byte
[
siz
];
int
s
=
0
;
try
{
while
(
s
<
siz
)
{
int
w
=
pg_input
.
read
(
answer
,
s
,
siz
-
s
);
if
(
w
<
0
)
throw
new
IOException
(
"EOF"
);
s
+=
w
;
}
}
catch
(
IOException
e
)
{
throw
new
SQLException
(
"Error reading from backend: "
+
e
.
toString
());
}
return
answer
;
}
/**
* Closes the connection
*
* @exception IOException if a IO Error occurs
*/
public
void
close
()
throws
IOException
{
pg_output
.
close
();
pg_input
.
close
();
connection
.
close
();
}
}
src/interfaces/jdbc/postgresql/DatabaseMetaData.java
View file @
6a061da2
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/interfaces/jdbc/postgresql/Driver.java
View file @
6a061da2
...
...
@@ -2,12 +2,8 @@ package postgresql;
import
java.sql.*
;
import
java.util.*
;
import
postgresql.*
;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* The Java SQL framework allows for multiple database drivers. Each
* driver should supply a class that implements the Driver interface
*
...
...
@@ -28,242 +24,274 @@ import postgresql.*;
*/
public
class
Driver
implements
java
.
sql
.
Driver
{
static
{
try
{
new
Driver
();
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
// These should be in sync with the backend that the driver was
// distributed with
static
final
int
MAJORVERSION
=
6
;
static
final
int
MINORVERSION
=
2
;
static
{
try
{
// moved the registerDriver from the constructor to here
// because some clients call the driver themselves (I know, as
// my early jdbc work did - and that was based on other examples).
// Placing it here, means that the driver is registered once only.
java
.
sql
.
DriverManager
.
registerDriver
(
new
Driver
());
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Construct a new driver and register it with DriverManager
*
* @exception SQLException for who knows what!
*/
public
Driver
()
throws
SQLException
{
}
/**
* Try to make a database connection to the given URL. The driver
* should return "null" if it realizes it is the wrong kind of
* driver to connect to the given URL. This will be common, as
* when the JDBC driverManager is asked to connect to a given URL,
* it passes the URL to each loaded driver in turn.
*
* The driver should raise an SQLException if it is the right driver
* to connect to the given URL, but has trouble connecting to the
* database.
*
* The java.util.Properties argument can be used to pass arbitrary
* string tag/value pairs as connection arguments. Normally, at least
* "user" and "password" properties should be included in the
* properties.
*
* Our protocol takes the form:
* <PRE>
* jdbc:postgresql://host:port/database
* </PRE>
*
* @param url the URL of the database to connect to
* @param info a list of arbitrary tag/value pairs as connection
* arguments
* @return a connection to the URL or null if it isnt us
* @exception SQLException if a database access error occurs
* @see java.sql.Driver#connect
*/
public
java
.
sql
.
Connection
connect
(
String
url
,
Properties
info
)
throws
SQLException
{
if
((
props
=
parseURL
(
url
,
info
))==
null
)
return
null
;
return
new
Connection
(
host
(),
port
(),
props
,
database
(),
url
,
this
);
}
/**
* Returns true if the driver thinks it can open a connection to the
* given URL. Typically, drivers will return true if they understand
* the subprotocol specified in the URL and false if they don't. Our
* protocols start with jdbc:postgresql:
*
* @see java.sql.Driver#acceptsURL
* @param url the URL of the driver
* @return true if this driver accepts the given URL
* @exception SQLException if a database-access error occurs
* (Dont know why it would *shrug*)
*/
public
boolean
acceptsURL
(
String
url
)
throws
SQLException
{
if
(
parseURL
(
url
,
null
)==
null
)
return
false
;
return
true
;
}
/**
* The getPropertyInfo method is intended to allow a generic GUI
* tool to discover what properties it should prompt a human for
* in order to get enough information to connect to a database.
* Note that depending on the values the human has supplied so
* far, additional values may become necessary, so it may be necessary
* to iterate through several calls to getPropertyInfo
*
* @param url the Url of the database to connect to
* @param info a proposed list of tag/value pairs that will be sent on
* connect open.
* @return An array of DriverPropertyInfo objects describing
* possible properties. This array may be an empty array if
* no properties are required
* @exception SQLException if a database-access error occurs
* @see java.sql.Driver#getPropertyInfo
*/
public
DriverPropertyInfo
[]
getPropertyInfo
(
String
url
,
Properties
info
)
throws
SQLException
{
return
null
;
// We don't need anything except
// the username, which is a default
}
/**
* Gets the drivers major version number
*
* @return the drivers major version number
*/
public
int
getMajorVersion
()
{
return
MAJORVERSION
;
}
/**
* Get the drivers minor version number
*
* @return the drivers minor version number
*/
public
int
getMinorVersion
()
{
return
MINORVERSION
;
}
/**
* Report whether the driver is a genuine JDBC compliant driver. A
* driver may only report "true" here if it passes the JDBC compliance
* tests, otherwise it is required to return false. JDBC compliance
* requires full support for the JDBC API and full support for SQL 92
* Entry Level.
*/
public
boolean
jdbcCompliant
()
{
return
false
;
}
private
Properties
props
;
static
private
String
[]
protocols
=
{
"jdbc"
,
"postgresql"
};
/**
* Constructs a new DriverURL, splitting the specified URL into its
* component parts
*/
Properties
parseURL
(
String
url
,
Properties
defaults
)
throws
SQLException
{
int
state
=
-
1
;
Properties
urlProps
=
new
Properties
(
defaults
);
String
key
=
new
String
();
String
value
=
new
String
();
StringTokenizer
st
=
new
StringTokenizer
(
url
,
":/;=&?"
,
true
);
for
(
int
count
=
0
;
(
st
.
hasMoreTokens
());
count
++)
{
String
token
=
st
.
nextToken
();
// PM June 29 1997
// Added this, to help me understand how this works.
// Unless you want each token to be processed, leave this commented out
// but don't delete it.
//DriverManager.println("wellFormedURL: state="+state+" count="+count+" token='"+token+"'");
// PM Aug 2 1997 - Modified to allow multiple backends
if
(
count
<=
3
)
{
if
((
count
%
2
)
==
1
&&
token
.
equals
(
":"
))
;
else
if
((
count
%
2
)
==
0
)
{
boolean
found
=(
count
==
0
)?
true
:
false
;
for
(
int
tmp
=
0
;
tmp
<
protocols
.
length
;
tmp
++)
{
if
(
token
.
equals
(
protocols
[
tmp
]))
{
// PM June 29 1997 Added this property to enable the driver
// to handle multiple backend protocols.
if
(
count
==
2
&&
tmp
>
0
)
{
urlProps
.
put
(
"Protocol"
,
token
);
found
=
true
;
}
}
}
if
(
found
==
false
)
return
null
;
}
else
return
null
;
}
else
if
(
count
>
3
)
{
if
(
count
==
4
&&
token
.
equals
(
"/"
))
state
=
0
;
else
if
(
count
==
4
)
{
urlProps
.
put
(
"PGDBNAME"
,
token
);
state
=
-
2
;
}
/**
* Construct a new driver and register it with DriverManager
*
* @exception SQLException for who knows what!
*/
public
Driver
()
throws
SQLException
{
java
.
sql
.
DriverManager
.
registerDriver
(
this
);
else
if
(
count
==
5
&&
state
==
0
&&
token
.
equals
(
"/"
))
state
=
1
;
else
if
(
count
==
5
&&
state
==
0
)
return
null
;
else
if
(
count
==
6
&&
state
==
1
)
urlProps
.
put
(
"PGHOST"
,
token
);
else
if
(
count
==
7
&&
token
.
equals
(
":"
))
state
=
2
;
else
if
(
count
==
8
&&
state
==
2
)
{
try
{
Integer
portNumber
=
Integer
.
decode
(
token
);
urlProps
.
put
(
"PGPORT"
,
portNumber
.
toString
());
}
catch
(
Exception
e
)
{
return
null
;
}
}
/**
* Try to make a database connection to the given URL. The driver
* should return "null" if it realizes it is the wrong kind of
* driver to connect to the given URL. This will be common, as
* when the JDBC driverManager is asked to connect to a given URL,
* it passes the URL to each loaded driver in turn.
*
* The driver should raise an SQLException if it is the right driver
* to connect to the given URL, but has trouble connecting to the
* database.
*
* The java.util.Properties argument can be used to pass arbitrary
* string tag/value pairs as connection arguments. Normally, at least
* "user" and "password" properties should be included in the
* properties.
*
* Our protocol takes the form:
* <PRE>
* jdbc:postgresql://host:port/database
* </PRE>
*
* @param url the URL of the database to connect to
* @param info a list of arbitrary tag/value pairs as connection
* arguments
* @return a connection to the URL or null if it isnt us
* @exception SQLException if a database access error occurs
* @see java.sql.Driver#connect
*/
public
java
.
sql
.
Connection
connect
(
String
url
,
Properties
info
)
throws
SQLException
{
DriverURL
dr
=
new
DriverURL
(
url
);
int
port
;
if
(!(
dr
.
protocol
().
equals
(
"jdbc"
)))
return
null
;
if
(!(
dr
.
subprotocol
().
equals
(
"postgresql"
)))
return
null
;
if
(
dr
.
host
().
equals
(
"unknown"
))
return
null
;
port
=
dr
.
port
();
if
(
port
==
-
1
)
port
=
5432
;
// Default PostgreSQL port
return
new
Connection
(
dr
.
host
(),
port
,
info
,
dr
.
database
(),
url
,
this
);
else
if
((
count
==
7
||
count
==
9
)
&&
(
state
==
1
||
state
==
2
)
&&
token
.
equals
(
"/"
))
state
=
-
1
;
else
if
(
state
==
-
1
)
{
urlProps
.
put
(
"PGDBNAME"
,
token
);
state
=
-
2
;
}
/**
* Returns true if the driver thinks it can open a connection to the
* given URL. Typically, drivers will return true if they understand
* the subprotocol specified in the URL and false if they don't. Our
* protocols start with jdbc:postgresql:
*
* @see java.sql.Driver#acceptsURL
* @param url the URL of the driver
* @return true if this driver accepts the given URL
* @exception SQLException if a database-access error occurs
* (Dont know why it would *shrug*)
*/
public
boolean
acceptsURL
(
String
url
)
throws
SQLException
{
DriverURL
dr
=
new
DriverURL
(
url
);
if
(
dr
.
protocol
().
equals
(
"jdbc"
))
if
(
dr
.
subprotocol
().
equals
(
"postgresql"
))
return
true
;
return
false
;
else
if
(
state
<=
-
2
&&
(
count
%
2
)
==
1
)
{
// PM Aug 2 1997 - added tests for ? and &
if
(
token
.
equals
(
";"
)
||
token
.
equals
(
"?"
)
||
token
.
equals
(
"&"
)
)
state
=
-
3
;
else
if
(
token
.
equals
(
"="
))
state
=
-
5
;
}
/**
* The getPropertyInfo method is intended to allow a generic GUI
* tool to discover what properties it should prompt a human for
* in order to get enough information to connect to a database.
* Note that depending on the values the human has supplied so
* far, additional values may become necessary, so it may be necessary
* to iterate through several calls to getPropertyInfo
*
* @param url the Url of the database to connect to
* @param info a proposed list of tag/value pairs that will be sent on
* connect open.
* @return An array of DriverPropertyInfo objects describing
* possible properties. This array may be an empty array if
* no properties are required
* @exception SQLException if a database-access error occurs
* @see java.sql.Driver#getPropertyInfo
*/
public
DriverPropertyInfo
[]
getPropertyInfo
(
String
url
,
Properties
info
)
throws
SQLException
{
return
null
;
// We don't need anything except
// the username, which is a default
}
/**
* Gets the drivers major version number
*
* @return the drivers major version number
*/
public
int
getMajorVersion
()
{
return
1
;
}
/**
* Get the drivers minor version number
*
* @return the drivers minor version number
*/
public
int
getMinorVersion
()
{
return
0
;
}
/**
* Report whether the driver is a genuine JDBC compliant driver. A
* driver may only report "true" here if it passes the JDBC compliance
* tests, otherwise it is required to return false. JDBC compliance
* requires full support for the JDBC API and full support for SQL 92
* Entry Level.
*/
public
boolean
jdbcCompliant
()
{
return
false
;
else
if
(
state
<=
-
2
&&
(
count
%
2
)
==
0
)
{
if
(
state
==
-
3
)
key
=
token
;
else
if
(
state
==
-
5
)
{
value
=
token
;
//DriverManager.println("put("+key+","+value+")");
urlProps
.
put
(
key
,
value
);
state
=
-
2
;
}
}
}
}
// PM June 29 1997
// This now outputs the properties only if we are logging
if
(
DriverManager
.
getLogStream
()
!=
null
)
urlProps
.
list
(
DriverManager
.
getLogStream
());
return
urlProps
;
}
/**
* Returns the hostname portion of the URL
*/
public
String
host
()
{
return
props
.
getProperty
(
"PGHOST"
,
"localhost"
);
}
/**
* Returns the port number portion of the URL
* or -1 if no port was specified
*/
public
int
port
()
{
return
Integer
.
parseInt
(
props
.
getProperty
(
"PGPORT"
,
"5432"
));
}
/**
* Returns the database name of the URL
*/
public
String
database
()
{
return
props
.
getProperty
(
"PGDBNAME"
);
}
/**
* Returns any property
*/
public
String
property
(
String
name
)
{
return
props
.
getProperty
(
name
);
}
}
/**
* The DriverURL class splits a JDBC URL into its subcomponents
*
* protocol:subprotocol:/[/host[:port]/][database]
*/
class
DriverURL
{
private
String
protocol
,
subprotocol
,
host
,
database
;
private
int
port
=
-
1
;
/**
* Constructs a new DriverURL, splitting the specified URL into its
* component parts
*/
public
DriverURL
(
String
url
)
throws
SQLException
{
int
a
,
b
,
c
;
String
tmp
,
hostport
,
dbportion
;
a
=
url
.
indexOf
(
':'
);
if
(
a
==
-
1
)
throw
new
SQLException
(
"Bad URL Protocol specifier"
);
b
=
url
.
indexOf
(
':'
,
a
+
1
);
if
(
b
==
-
1
)
throw
new
SQLException
(
"Bad URL Subprotocol specifier"
);
protocol
=
new
String
(
url
.
substring
(
0
,
a
));
subprotocol
=
new
String
(
url
.
substring
(
a
+
1
,
b
));
tmp
=
new
String
(
url
.
substring
(
b
+
1
,
url
.
length
()));
if
(
tmp
.
length
()
<
2
)
throw
new
SQLException
(
"Bad URL Database specifier"
);
if
(!
tmp
.
substring
(
0
,
2
).
equals
(
"//"
))
{
host
=
new
String
(
"unknown"
);
port
=
-
1
;
database
=
new
String
(
tmp
.
substring
(
1
,
tmp
.
length
()));
return
;
}
dbportion
=
new
String
(
tmp
.
substring
(
2
,
tmp
.
length
()));
c
=
dbportion
.
indexOf
(
'/'
);
if
(
c
==
-
1
)
throw
new
SQLException
(
"Bad URL Database specifier"
);
a
=
dbportion
.
indexOf
(
':'
);
if
(
a
==
-
1
)
{
host
=
new
String
(
dbportion
.
substring
(
0
,
c
));
port
=
-
1
;
database
=
new
String
(
dbportion
.
substring
(
c
+
1
,
dbportion
.
length
()));
}
else
{
host
=
new
String
(
dbportion
.
substring
(
0
,
a
));
port
=
Integer
.
valueOf
(
dbportion
.
substring
(
a
+
1
,
c
)).
intValue
();
database
=
new
String
(
dbportion
.
substring
(
c
+
1
,
dbportion
.
length
()));
}
}
/**
* Returns the protocol name of the DriverURL
*/
public
String
protocol
()
{
return
protocol
;
}
/**
* Returns the subprotocol name of the DriverURL
*/
public
String
subprotocol
()
{
return
subprotocol
;
}
/**
* Returns the hostname portion of the URL
*/
public
String
host
()
{
return
host
;
}
/**
* Returns the port number portion of the URL
* or -1 if no port was specified
*/
public
int
port
()
{
return
port
;
}
/**
* Returns the database name of the URL
*/
public
String
database
()
{
return
database
;
}
}
src/interfaces/jdbc/postgresql/Field.java
View file @
6a061da2
...
...
@@ -13,77 +13,91 @@ import postgresql.*;
*/
public
class
Field
{
int
length
;
// Internal Length of this field
int
oid
;
// OID of the type
Connection
conn
;
// Connection Instantation
String
name
;
// Name of this field
int
sql_type
=
-
1
;
// The entry in java.sql.Types for this field
String
type_name
=
null
;
// The sql type name
/**
* Construct a field based on the information fed to it.
*
* @param conn the connection this field came from
* @param name the name of the field
* @param oid the OID of the field
* @param len the length of the field
*/
public
Field
(
Connection
conn
,
String
name
,
int
oid
,
int
length
)
{
this
.
conn
=
conn
;
this
.
name
=
name
;
this
.
oid
=
oid
;
this
.
length
=
length
;
}
/**
* the ResultSet and ResultMetaData both need to handle the SQL
* type, which is gained from another query. Note that we cannot
* use getObject() in this, since getObject uses getSQLType().
*
* @return the entry in Types that refers to this field
* @exception SQLException if a database access error occurs
*/
public
int
getSQLType
()
throws
SQLException
{
if
(
sql_type
==
-
1
)
{
ResultSet
result
=
(
postgresql
.
ResultSet
)
conn
.
ExecSQL
(
"select typname from pg_type where oid = "
+
oid
);
if
(
result
.
getColumnCount
()
!=
1
||
result
.
getTupleCount
()
!=
1
)
throw
new
SQLException
(
"Unexpected return from query for type"
);
result
.
next
();
type_name
=
result
.
getString
(
1
);
if
(
type_name
.
equals
(
"int2"
))
sql_type
=
Types
.
SMALLINT
;
else
if
(
type_name
.
equals
(
"int4"
))
sql_type
=
Types
.
INTEGER
;
else
if
(
type_name
.
equals
(
"int8"
))
sql_type
=
Types
.
BIGINT
;
else
if
(
type_name
.
equals
(
"cash"
))
sql_type
=
Types
.
DECIMAL
;
else
if
(
type_name
.
equals
(
"money"
))
sql_type
=
Types
.
DECIMAL
;
else
if
(
type_name
.
equals
(
"float4"
))
sql_type
=
Types
.
REAL
;
else
if
(
type_name
.
equals
(
"float8"
))
sql_type
=
Types
.
DOUBLE
;
else
if
(
type_name
.
equals
(
"bpchar"
))
sql_type
=
Types
.
CHAR
;
else
if
(
type_name
.
equals
(
"varchar"
))
sql_type
=
Types
.
VARCHAR
;
else
if
(
type_name
.
equals
(
"bool"
))
sql_type
=
Types
.
BIT
;
else
if
(
type_name
.
equals
(
"date"
))
sql_type
=
Types
.
DATE
;
else
if
(
type_name
.
equals
(
"time"
))
sql_type
=
Types
.
TIME
;
else
if
(
type_name
.
equals
(
"abstime"
))
sql_type
=
Types
.
TIMESTAMP
;
else
sql_type
=
Types
.
OTHER
;
}
return
sql_type
;
}
/**
* We also need to get the type name as returned by the back end.
* This is held in type_name AFTER a call to getSQLType. Since
* we get this information within getSQLType (if it isn't already
* done), we can just call getSQLType and throw away the result.
*
* @return the String representation of the type of this field
* @exception SQLException if a database access error occurs
*/
public
String
getTypeName
()
throws
SQLException
{
int
sql
=
getSQLType
();
return
type_name
;
}
int
length
;
// Internal Length of this field
int
oid
;
// OID of the type
Connection
conn
;
// Connection Instantation
String
name
;
// Name of this field
int
sql_type
=
-
1
;
// The entry in java.sql.Types for this field
String
type_name
=
null
;
// The sql type name
/**
* Construct a field based on the information fed to it.
*
* @param conn the connection this field came from
* @param name the name of the field
* @param oid the OID of the field
* @param len the length of the field
*/
public
Field
(
Connection
conn
,
String
name
,
int
oid
,
int
length
)
{
this
.
conn
=
conn
;
this
.
name
=
name
;
this
.
oid
=
oid
;
this
.
length
=
length
;
}
/**
* the ResultSet and ResultMetaData both need to handle the SQL
* type, which is gained from another query. Note that we cannot
* use getObject() in this, since getObject uses getSQLType().
*
* @return the entry in Types that refers to this field
* @exception SQLException if a database access error occurs
*/
public
int
getSQLType
()
throws
SQLException
{
if
(
sql_type
==
-
1
)
{
ResultSet
result
=
(
postgresql
.
ResultSet
)
conn
.
ExecSQL
(
"select typname from pg_type where oid = "
+
oid
);
if
(
result
.
getColumnCount
()
!=
1
||
result
.
getTupleCount
()
!=
1
)
throw
new
SQLException
(
"Unexpected return from query for type"
);
result
.
next
();
type_name
=
result
.
getString
(
1
);
if
(
type_name
.
equals
(
"int2"
))
sql_type
=
Types
.
SMALLINT
;
else
if
(
type_name
.
equals
(
"int4"
))
sql_type
=
Types
.
INTEGER
;
else
if
(
type_name
.
equals
(
"int8"
))
sql_type
=
Types
.
BIGINT
;
else
if
(
type_name
.
equals
(
"cash"
))
sql_type
=
Types
.
DECIMAL
;
else
if
(
type_name
.
equals
(
"money"
))
sql_type
=
Types
.
DECIMAL
;
else
if
(
type_name
.
equals
(
"float4"
))
sql_type
=
Types
.
REAL
;
else
if
(
type_name
.
equals
(
"float8"
))
sql_type
=
Types
.
DOUBLE
;
else
if
(
type_name
.
equals
(
"bpchar"
))
sql_type
=
Types
.
CHAR
;
else
if
(
type_name
.
equals
(
"varchar"
))
sql_type
=
Types
.
VARCHAR
;
else
if
(
type_name
.
equals
(
"bool"
))
sql_type
=
Types
.
BIT
;
else
if
(
type_name
.
equals
(
"date"
))
sql_type
=
Types
.
DATE
;
else
if
(
type_name
.
equals
(
"time"
))
sql_type
=
Types
.
TIME
;
else
if
(
type_name
.
equals
(
"abstime"
))
sql_type
=
Types
.
TIMESTAMP
;
else
sql_type
=
Types
.
OTHER
;
}
return
sql_type
;
}
/**
* We also need to get the type name as returned by the back end.
* This is held in type_name AFTER a call to getSQLType. Since
* we get this information within getSQLType (if it isn't already
* done), we can just call getSQLType and throw away the result.
*
* @return the String representation of the type of this field
* @exception SQLException if a database access error occurs
*/
public
String
getTypeName
()
throws
SQLException
{
int
sql
=
getSQLType
();
return
type_name
;
}
}
src/interfaces/jdbc/postgresql/PG_Object.java
View file @
6a061da2
...
...
@@ -14,18 +14,132 @@ import postgresql.*;
*/
public
class
PG_Object
{
public
String
type
;
public
String
value
;
/**
* Constructor for the PostgreSQL generic object
*
* @param type a string describing the type of the object
* @param value a string representation of the value of the object
*/
public
PG_Object
(
String
type
,
String
value
)
{
this
.
type
=
type
;
this
.
value
=
value
;
}
public
String
type
;
public
String
value
;
/**
* Constructor for the PostgreSQL generic object
*
* @param type a string describing the type of the object
* @param value a string representation of the value of the object
*/
public
PG_Object
(
String
type
,
String
value
)
throws
SQLException
{
this
.
type
=
type
;
this
.
value
=
value
;
}
/**
* This returns true if the object is a 'box'
*/
public
boolean
isBox
()
{
return
type
.
equals
(
"box"
);
}
/**
* This returns a PGbox object, or null if it's not
* @return PGbox
*/
public
PGbox
getBox
()
throws
SQLException
{
if
(
isBox
())
return
new
PGbox
(
value
);
return
null
;
}
/**
* This returns true if the object is a 'point'
*/
public
boolean
isCircle
()
{
return
type
.
equals
(
"circle"
);
}
/**
* This returns a PGcircle object, or null if it's not
* @return PGcircle
*/
public
PGcircle
getCircle
()
throws
SQLException
{
if
(
isCircle
())
return
new
PGcircle
(
value
);
return
null
;
}
/**
* This returns true if the object is a 'lseg' (line segment)
*/
public
boolean
isLseg
()
{
return
type
.
equals
(
"lseg"
);
}
/**
* This returns a PGlsegobject, or null if it's not
* @return PGlseg
*/
public
PGlseg
getLseg
()
throws
SQLException
{
if
(
isLseg
())
return
new
PGlseg
(
value
);
return
null
;
}
/**
* This returns true if the object is a 'path'
*/
public
boolean
isPath
()
{
return
type
.
equals
(
"path"
);
}
/**
* This returns a PGpath object, or null if it's not
* @return PGpath
*/
public
PGpath
getPath
()
throws
SQLException
{
if
(
isPath
())
return
new
PGpath
(
value
);
return
null
;
}
/**
* This returns true if the object is a 'point'
*/
public
boolean
isPoint
()
{
return
type
.
equals
(
"point"
);
}
/**
* This returns a PGpoint object, or null if it's not
* @return PGpoint object
*/
public
PGpoint
getPoint
()
throws
SQLException
{
if
(
isPoint
())
return
new
PGpoint
(
value
);
return
null
;
}
/**
* This returns true if the object is a 'polygon'
*/
public
boolean
isPolygon
()
{
return
type
.
equals
(
"polygon"
);
}
/**
* This returns a PGpolygon object, or null if it's not
* @return PGpolygon
*/
public
PGpolygon
getPolygon
()
throws
SQLException
{
if
(
isPolygon
())
return
new
PGpolygon
(
value
);
return
null
;
}
}
src/interfaces/jdbc/postgresql/ResultSet.java
View file @
6a061da2
...
...
@@ -9,9 +9,6 @@ import java.sql.*;
import
postgresql.*
;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* A ResultSet provides access to a table of data generated by executing a
* Statement. The table rows are retrieved in sequence. Within a row its
* column values can be accessed in any order.
...
...
@@ -54,792 +51,793 @@ import postgresql.*;
*/
public
class
ResultSet
implements
java
.
sql
.
ResultSet
{
Vector
rows
;
// The results
Field
fields
[];
// The field descriptions
String
status
;
// Status of the result
int
updateCount
;
// How many rows did we get back?
int
current_row
;
// Our pointer to where we are at
byte
[][]
this_row
;
// the current row result
Connection
connection
;
// the connection which we returned from
SQLWarning
warnings
=
null
;
// The warning chain
boolean
wasNullFlag
=
false
;
// the flag for wasNull()
// We can chain multiple resultSets together - this points to
// next resultSet in the chain.
private
ResultSet
next
=
null
;
/**
* Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything.
*
* @param fields an array of Field objects (basically, the
* ResultSet MetaData)
* @param tuples Vector of the actual data
* @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name
*/
public
ResultSet
(
Connection
conn
,
Field
[]
fields
,
Vector
tuples
,
String
status
,
int
updateCount
)
{
this
.
connection
=
conn
;
this
.
fields
=
fields
;
this
.
rows
=
tuples
;
this
.
status
=
status
;
this
.
updateCount
=
updateCount
;
this
.
this_row
=
null
;
this
.
current_row
=
-
1
;
}
/**
* A ResultSet is initially positioned before its first row,
* the first call to next makes the first row the current row;
* the second call makes the second row the current row, etc.
*
* If an input stream from the previous row is open, it is
* implicitly closed. The ResultSet's warning chain is cleared
* when a new row is read
*
* @return true if the new current is valid; false if there are no
* more rows
* @exception SQLException if a database access error occurs
*/
public
boolean
next
()
throws
SQLException
{
if
(++
current_row
>=
rows
.
size
())
return
false
;
this_row
=
(
byte
[][])
rows
.
elementAt
(
current_row
);
return
true
;
}
/**
* In some cases, it is desirable to immediately release a ResultSet
* database and JDBC resources instead of waiting for this to happen
* when it is automatically closed. The close method provides this
* immediate release.
*
* <B>Note:</B> A ResultSet is automatically closed by the Statement
* the Statement that generated it when that Statement is closed,
* re-executed, or is used to retrieve the next result from a sequence
* of multiple results. A ResultSet is also automatically closed
* when it is garbage collected.
*
* @exception SQLException if a database access error occurs
*/
public
void
close
()
throws
SQLException
{
// No-op
}
/**
* A column may have the value of SQL NULL; wasNull() reports whether
* the last column read had this special value. Note that you must
* first call getXXX on a column to try to read its value and then
* call wasNull() to find if the value was SQL NULL
*
* @return true if the last column read was SQL NULL
* @exception SQLException if a database access error occurred
*/
public
boolean
wasNull
()
throws
SQLException
{
return
wasNullFlag
;
}
/**
* Get the value of a column in the current row as a Java String
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value, null for SQL NULL
* @exception SQLException if a database access error occurs
*/
public
String
getString
(
int
columnIndex
)
throws
SQLException
{
byte
[]
bytes
=
getBytes
(
columnIndex
);
if
(
bytes
==
null
)
return
null
;
return
new
String
(
bytes
);
}
/**
* Get the value of a column in the current row as a Java boolean
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value, false for SQL NULL
* @exception SQLException if a database access error occurs
*/
public
boolean
getBoolean
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
int
c
=
s
.
charAt
(
0
);
return
((
c
==
't'
)
||
(
c
==
'T'
));
}
return
false
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java byte.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
byte
getByte
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Byte
.
parseByte
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Byte Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java short.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
short
getShort
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Short
.
parseShort
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Short Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java int.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
int
getInt
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Integer
.
parseInt
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Integer Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java long.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
long
getLong
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Long
.
parseLong
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Long Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java float.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
float
getFloat
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Float
.
valueOf
(
s
).
floatValue
();
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Float Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java double.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
double
getDouble
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Double
.
valueOf
(
s
).
doubleValue
();
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Double Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a
* java.lang.BigDecimal object
*
* @param columnIndex the first column is 1, the second is 2...
* @param scale the number of digits to the right of the decimal
* @return the column value; if the value is SQL NULL, null
* @exception SQLException if a database access error occurs
*/
public
BigDecimal
getBigDecimal
(
int
columnIndex
,
int
scale
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
BigDecimal
val
;
if
(
s
!=
null
)
{
try
{
val
=
new
BigDecimal
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad BigDecimal Form: "
+
s
);
}
try
{
return
val
.
setScale
(
scale
);
}
catch
(
ArithmeticException
e
)
{
throw
new
SQLException
(
"Bad BigDecimal Form: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java byte array
* The bytes represent the raw values returned by the driver.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @return the column value; if the value is SQL NULL, the result
* is null
* @exception SQLException if a database access error occurs
*/
public
byte
[]
getBytes
(
int
columnIndex
)
throws
SQLException
{
if
(
columnIndex
<
1
||
columnIndex
>
fields
.
length
)
throw
new
SQLException
(
"Column Index out of range"
);
wasNullFlag
=
(
this_row
[
columnIndex
-
1
]
==
null
);
return
this_row
[
columnIndex
-
1
];
}
/**
* Get the value of a column in the current row as a java.sql.Date
* object
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value; null if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
Date
getDate
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
if
(
s
.
length
()
!=
10
)
throw
new
NumberFormatException
(
"Wrong Length!"
);
int
mon
=
Integer
.
parseInt
(
s
.
substring
(
0
,
2
));
int
day
=
Integer
.
parseInt
(
s
.
substring
(
3
,
5
));
int
yr
=
Integer
.
parseInt
(
s
.
substring
(
6
));
return
new
java
.
sql
.
Date
(
yr
-
1900
,
mon
-
1
,
day
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Date Form: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a java.sql.Time
* object
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value; null if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
Time
getTime
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
if
(
s
.
length
()
!=
5
&&
s
.
length
()
!=
8
)
throw
new
NumberFormatException
(
"Wrong Length!"
);
int
hr
=
Integer
.
parseInt
(
s
.
substring
(
0
,
2
));
int
min
=
Integer
.
parseInt
(
s
.
substring
(
3
,
5
));
int
sec
=
(
s
.
length
()
==
5
)
?
0
:
Integer
.
parseInt
(
s
.
substring
(
6
));
return
new
Time
(
hr
,
min
,
sec
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Time Form: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a
* java.sql.Timestamp object
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value; null if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
Timestamp
getTimestamp
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
DateFormat
df
=
DateFormat
.
getDateInstance
();
if
(
s
!=
null
)
{
try
{
java
.
sql
.
Date
d
=
(
java
.
sql
.
Date
)
df
.
parse
(
s
);
return
new
Timestamp
(
d
.
getTime
());
}
catch
(
ParseException
e
)
{
throw
new
SQLException
(
"Bad Timestamp Format: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* A column value can be retrieved as a stream of ASCII characters
* and then read in chunks from the stream. This method is
* particular suitable for retrieving large LONGVARCHAR values.
* The JDBC driver will do any necessary conversion from the
* database format into ASCII.
*
* <B>Note:</B> All the data in the returned stream must be read
* prior to getting the value of any other column. The next call
* to a get method implicitly closes the stream. Also, a stream
* may return 0 for available() whether there is data available
* or not.
*
* We implement an ASCII stream as a Binary stream - we should really
* do the data conversion, but I cannot be bothered to implement this
* right now.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @return a Java InputStream that delivers the database column
* value as a stream of one byte ASCII characters. If the
* value is SQL NULL then the result is null
* @exception SQLException if a database access error occurs
* @see getBinaryStream
*/
public
InputStream
getAsciiStream
(
int
columnIndex
)
throws
SQLException
{
return
getBinaryStream
(
columnIndex
);
}
/**
* A column value can also be retrieved as a stream of Unicode
* characters. We implement this as a binary stream.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Java InputStream that delivers the database column value
* as a stream of two byte Unicode characters. If the value is
* SQL NULL, then the result is null
* @exception SQLException if a database access error occurs
* @see getAsciiStream
* @see getBinaryStream
*/
public
InputStream
getUnicodeStream
(
int
columnIndex
)
throws
SQLException
{
return
getBinaryStream
(
columnIndex
);
}
/**
* A column value can also be retrieved as a binary strea. This
* method is suitable for retrieving LONGVARBINARY values.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Java InputStream that delivers the database column value
* as a stream of two byte Unicode characters. If the value is
* SQL NULL, then the result is null
* @exception SQLException if a database access error occurs
* @see getAsciiStream
* @see getUnicodeStream
*/
public
InputStream
getBinaryStream
(
int
columnIndex
)
throws
SQLException
{
byte
b
[]
=
getBytes
(
columnIndex
);
if
(
b
!=
null
)
return
new
ByteArrayInputStream
(
b
);
return
null
;
// SQL NULL
}
/**
* The following routines simply convert the columnName into
* a columnIndex and then call the appropriate routine above.
*
* @param columnName is the SQL name of the column
* @return the column value
* @exception SQLException if a database access error occurs
*/
public
String
getString
(
String
columnName
)
throws
SQLException
{
return
getString
(
findColumn
(
columnName
));
}
public
boolean
getBoolean
(
String
columnName
)
throws
SQLException
{
return
getBoolean
(
findColumn
(
columnName
));
}
public
byte
getByte
(
String
columnName
)
throws
SQLException
{
return
getByte
(
findColumn
(
columnName
));
}
public
short
getShort
(
String
columnName
)
throws
SQLException
{
return
getShort
(
findColumn
(
columnName
));
}
public
int
getInt
(
String
columnName
)
throws
SQLException
{
return
getInt
(
findColumn
(
columnName
));
}
public
long
getLong
(
String
columnName
)
throws
SQLException
{
return
getLong
(
findColumn
(
columnName
));
}
public
float
getFloat
(
String
columnName
)
throws
SQLException
{
return
getFloat
(
findColumn
(
columnName
));
}
public
double
getDouble
(
String
columnName
)
throws
SQLException
{
return
getDouble
(
findColumn
(
columnName
));
}
public
BigDecimal
getBigDecimal
(
String
columnName
,
int
scale
)
throws
SQLException
{
return
getBigDecimal
(
findColumn
(
columnName
),
scale
);
}
public
byte
[]
getBytes
(
String
columnName
)
throws
SQLException
{
return
getBytes
(
findColumn
(
columnName
));
}
public
java
.
sql
.
Date
getDate
(
String
columnName
)
throws
SQLException
{
return
getDate
(
findColumn
(
columnName
));
}
public
Time
getTime
(
String
columnName
)
throws
SQLException
{
return
getTime
(
findColumn
(
columnName
));
}
public
Timestamp
getTimestamp
(
String
columnName
)
throws
SQLException
{
return
getTimestamp
(
findColumn
(
columnName
));
}
public
InputStream
getAsciiStream
(
String
columnName
)
throws
SQLException
{
return
getAsciiStream
(
findColumn
(
columnName
));
}
public
InputStream
getUnicodeStream
(
String
columnName
)
throws
SQLException
{
return
getUnicodeStream
(
findColumn
(
columnName
));
}
public
InputStream
getBinaryStream
(
String
columnName
)
throws
SQLException
{
return
getBinaryStream
(
findColumn
(
columnName
));
}
/**
* The first warning reported by calls on this ResultSet is
* returned. Subsequent ResultSet warnings will be chained
* to this SQLWarning.
*
* The warning chain is automatically cleared each time a new
* row is read.
*
* <B>Note:</B> This warning chain only covers warnings caused by
* ResultSet methods. Any warnings caused by statement methods
* (such as reading OUT parameters) will be chained on the
* Statement object.
*
* @return the first SQLWarning or null;
* @exception SQLException if a database access error occurs.
*/
public
SQLWarning
getWarnings
()
throws
SQLException
{
return
warnings
;
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this ResultSet
*
* @exception SQLException if a database access error occurs
*/
public
void
clearWarnings
()
throws
SQLException
{
warnings
=
null
;
}
/**
* Get the name of the SQL cursor used by this ResultSet
*
* In SQL, a result table is retrieved though a cursor that is
* named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references
* the cursor name.
*
* JDBC supports this SQL feature by providing the name of the
* SQL cursor used by a ResultSet. The current row of a ResulSet
* is also the current row of this SQL cursor.
*
* <B>Note:</B> If positioned update is not supported, a SQLException
* is thrown.
*
* @return the ResultSet's SQL cursor name.
* @exception SQLException if a database access error occurs
*/
public
String
getCursorName
()
throws
SQLException
{
return
connection
.
getCursorName
();
}
/**
* The numbers, types and properties of a ResultSet's columns are
* provided by the getMetaData method
*
* @return a description of the ResultSet's columns
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
ResultSetMetaData
getMetaData
()
throws
SQLException
{
return
new
ResultSetMetaData
(
rows
,
fields
);
}
/**
* Get the value of a column in the current row as a Java object
*
* This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* This method may also be used to read database specific abstract
* data types.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public
Object
getObject
(
int
columnIndex
)
throws
SQLException
{
Field
field
;
if
(
columnIndex
<
1
||
columnIndex
>
fields
.
length
)
throw
new
SQLException
(
"Column index out of range"
);
field
=
fields
[
columnIndex
-
1
];
switch
(
field
.
getSQLType
())
{
case
Types
.
BIT
:
return
new
Boolean
(
getBoolean
(
columnIndex
));
case
Types
.
SMALLINT
:
return
new
Integer
(
getInt
(
columnIndex
));
case
Types
.
INTEGER
:
return
new
Integer
(
getInt
(
columnIndex
));
case
Types
.
BIGINT
:
return
new
Long
(
getLong
(
columnIndex
));
case
Types
.
NUMERIC
:
return
getBigDecimal
(
columnIndex
,
0
);
case
Types
.
REAL
:
return
new
Float
(
getFloat
(
columnIndex
));
case
Types
.
DOUBLE
:
return
new
Double
(
getDouble
(
columnIndex
));
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
getString
(
columnIndex
);
case
Types
.
DATE
:
return
getDate
(
columnIndex
);
case
Types
.
TIME
:
return
getTime
(
columnIndex
);
case
Types
.
TIMESTAMP
:
return
getTimestamp
(
columnIndex
);
default
:
return
new
PG_Object
(
field
.
getTypeName
(),
getString
(
columnIndex
));
}
}
/**
* Get the value of a column in the current row as a Java object
*
* This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* This method may also be used to read database specific abstract
* data types.
*
* @param columnName is the SQL name of the column
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public
Object
getObject
(
String
columnName
)
throws
SQLException
{
return
getObject
(
findColumn
(
columnName
));
}
/**
* Map a ResultSet column name to a ResultSet column index
*
* @param columnName the name of the column
* @return the column index
* @exception SQLException if a database access error occurs
*/
public
int
findColumn
(
String
columnName
)
throws
SQLException
{
int
i
;
for
(
i
=
0
;
i
<
fields
.
length
;
++
i
)
if
(
fields
[
i
].
name
.
equalsIgnoreCase
(
columnName
))
return
(
i
+
1
);
throw
new
SQLException
(
"Column name not found"
);
}
// ************************************************************
// END OF PUBLIC INTERFACE
// ************************************************************
/**
* We at times need to know if the resultSet we are working
* with is the result of an UPDATE, DELETE or INSERT (in which
* case, we only have a row count), or of a SELECT operation
* (in which case, we have multiple fields) - this routine
* tells us.
*
* @return true if we have tuples available
*/
public
boolean
reallyResultSet
()
{
return
(
fields
!=
null
);
}
/**
* Since ResultSets can be chained, we need some method of
* finding the next one in the chain. The method getNext()
* returns the next one in the chain.
*
* @return the next ResultSet, or null if there are none
*/
public
ResultSet
getNext
()
{
return
next
;
}
/**
* This following method allows us to add a ResultSet object
* to the end of the current chain.
*
* @param r the resultset to add to the end of the chain.
*/
public
void
append
(
ResultSet
r
)
{
if
(
next
==
null
)
next
=
r
;
else
next
.
append
(
r
);
}
/**
* If we are just a place holder for results, we still need
* to get an updateCount. This method returns it.
*
* @return the updateCount
*/
public
int
getResultCount
()
{
return
updateCount
;
}
/**
* We also need to provide a couple of auxiliary functions for
* the implementation of the ResultMetaData functions. In
* particular, we need to know the number of rows and the
* number of columns. Rows are also known as Tuples
*
* getTupleCount returns the number of rows
*
* @return the number of rows
*/
public
int
getTupleCount
()
{
return
rows
.
size
();
}
/**
* getColumnCount returns the number of columns
*
* @return the number of columns
*/
public
int
getColumnCount
()
{
return
fields
.
length
;
}
Vector
rows
;
// The results
Field
fields
[];
// The field descriptions
String
status
;
// Status of the result
int
updateCount
;
// How many rows did we get back?
int
current_row
;
// Our pointer to where we are at
byte
[][]
this_row
;
// the current row result
Connection
connection
;
// the connection which we returned from
SQLWarning
warnings
=
null
;
// The warning chain
boolean
wasNullFlag
=
false
;
// the flag for wasNull()
// We can chain multiple resultSets together - this points to
// next resultSet in the chain.
private
ResultSet
next
=
null
;
/**
* Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything.
*
* @param fields an array of Field objects (basically, the
* ResultSet MetaData)
* @param tuples Vector of the actual data
* @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name
*/
public
ResultSet
(
Connection
conn
,
Field
[]
fields
,
Vector
tuples
,
String
status
,
int
updateCount
)
{
this
.
connection
=
conn
;
this
.
fields
=
fields
;
this
.
rows
=
tuples
;
this
.
status
=
status
;
this
.
updateCount
=
updateCount
;
this
.
this_row
=
null
;
this
.
current_row
=
-
1
;
}
/**
* A ResultSet is initially positioned before its first row,
* the first call to next makes the first row the current row;
* the second call makes the second row the current row, etc.
*
* If an input stream from the previous row is open, it is
* implicitly closed. The ResultSet's warning chain is cleared
* when a new row is read
*
* @return true if the new current is valid; false if there are no
* more rows
* @exception SQLException if a database access error occurs
*/
public
boolean
next
()
throws
SQLException
{
if
(++
current_row
>=
rows
.
size
())
return
false
;
this_row
=
(
byte
[][])
rows
.
elementAt
(
current_row
);
return
true
;
}
/**
* In some cases, it is desirable to immediately release a ResultSet
* database and JDBC resources instead of waiting for this to happen
* when it is automatically closed. The close method provides this
* immediate release.
*
* <B>Note:</B> A ResultSet is automatically closed by the Statement
* the Statement that generated it when that Statement is closed,
* re-executed, or is used to retrieve the next result from a sequence
* of multiple results. A ResultSet is also automatically closed
* when it is garbage collected.
*
* @exception SQLException if a database access error occurs
*/
public
void
close
()
throws
SQLException
{
// No-op
}
/**
* A column may have the value of SQL NULL; wasNull() reports whether
* the last column read had this special value. Note that you must
* first call getXXX on a column to try to read its value and then
* call wasNull() to find if the value was SQL NULL
*
* @return true if the last column read was SQL NULL
* @exception SQLException if a database access error occurred
*/
public
boolean
wasNull
()
throws
SQLException
{
return
wasNullFlag
;
}
/**
* Get the value of a column in the current row as a Java String
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value, null for SQL NULL
* @exception SQLException if a database access error occurs
*/
public
String
getString
(
int
columnIndex
)
throws
SQLException
{
byte
[]
bytes
=
getBytes
(
columnIndex
);
if
(
bytes
==
null
)
return
null
;
return
new
String
(
bytes
);
}
/**
* Get the value of a column in the current row as a Java boolean
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value, false for SQL NULL
* @exception SQLException if a database access error occurs
*/
public
boolean
getBoolean
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
int
c
=
s
.
charAt
(
0
);
return
((
c
==
't'
)
||
(
c
==
'T'
));
}
return
false
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java byte.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
byte
getByte
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Byte
.
parseByte
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Byte Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java short.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
short
getShort
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Short
.
parseShort
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Short Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java int.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
int
getInt
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Integer
.
parseInt
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Integer Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java long.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
long
getLong
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Long
.
parseLong
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Long Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java float.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
float
getFloat
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Float
.
valueOf
(
s
).
floatValue
();
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Float Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java double.
*
* @param columnIndex the first column is 1, the second is 2,...
* @return the column value; 0 if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
double
getDouble
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
return
Double
.
valueOf
(
s
).
doubleValue
();
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Double Form: "
+
s
);
}
}
return
0
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a
* java.lang.BigDecimal object
*
* @param columnIndex the first column is 1, the second is 2...
* @param scale the number of digits to the right of the decimal
* @return the column value; if the value is SQL NULL, null
* @exception SQLException if a database access error occurs
*/
public
BigDecimal
getBigDecimal
(
int
columnIndex
,
int
scale
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
BigDecimal
val
;
if
(
s
!=
null
)
{
try
{
val
=
new
BigDecimal
(
s
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad BigDecimal Form: "
+
s
);
}
try
{
return
val
.
setScale
(
scale
);
}
catch
(
ArithmeticException
e
)
{
throw
new
SQLException
(
"Bad BigDecimal Form: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a Java byte array
* The bytes represent the raw values returned by the driver.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @return the column value; if the value is SQL NULL, the result
* is null
* @exception SQLException if a database access error occurs
*/
public
byte
[]
getBytes
(
int
columnIndex
)
throws
SQLException
{
if
(
columnIndex
<
1
||
columnIndex
>
fields
.
length
)
throw
new
SQLException
(
"Column Index out of range"
);
wasNullFlag
=
(
this_row
[
columnIndex
-
1
]
==
null
);
return
this_row
[
columnIndex
-
1
];
}
/**
* Get the value of a column in the current row as a java.sql.Date
* object
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value; null if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
Date
getDate
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
if
(
s
.
length
()
!=
10
)
throw
new
NumberFormatException
(
"Wrong Length!"
);
int
mon
=
Integer
.
parseInt
(
s
.
substring
(
0
,
2
));
int
day
=
Integer
.
parseInt
(
s
.
substring
(
3
,
5
));
int
yr
=
Integer
.
parseInt
(
s
.
substring
(
6
));
return
new
java
.
sql
.
Date
(
yr
-
1900
,
mon
-
1
,
day
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Date Form: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a java.sql.Time
* object
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value; null if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
Time
getTime
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
if
(
s
!=
null
)
{
try
{
if
(
s
.
length
()
!=
5
&&
s
.
length
()
!=
8
)
throw
new
NumberFormatException
(
"Wrong Length!"
);
int
hr
=
Integer
.
parseInt
(
s
.
substring
(
0
,
2
));
int
min
=
Integer
.
parseInt
(
s
.
substring
(
3
,
5
));
int
sec
=
(
s
.
length
()
==
5
)
?
0
:
Integer
.
parseInt
(
s
.
substring
(
6
));
return
new
Time
(
hr
,
min
,
sec
);
}
catch
(
NumberFormatException
e
)
{
throw
new
SQLException
(
"Bad Time Form: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* Get the value of a column in the current row as a
* java.sql.Timestamp object
*
* @param columnIndex the first column is 1, the second is 2...
* @return the column value; null if SQL NULL
* @exception SQLException if a database access error occurs
*/
public
Timestamp
getTimestamp
(
int
columnIndex
)
throws
SQLException
{
String
s
=
getString
(
columnIndex
);
DateFormat
df
=
DateFormat
.
getDateInstance
();
if
(
s
!=
null
)
{
try
{
java
.
sql
.
Date
d
=
(
java
.
sql
.
Date
)
df
.
parse
(
s
);
return
new
Timestamp
(
d
.
getTime
());
}
catch
(
ParseException
e
)
{
throw
new
SQLException
(
"Bad Timestamp Format: "
+
s
);
}
}
return
null
;
// SQL NULL
}
/**
* A column value can be retrieved as a stream of ASCII characters
* and then read in chunks from the stream. This method is
* particular suitable for retrieving large LONGVARCHAR values.
* The JDBC driver will do any necessary conversion from the
* database format into ASCII.
*
* <B>Note:</B> All the data in the returned stream must be read
* prior to getting the value of any other column. The next call
* to a get method implicitly closes the stream. Also, a stream
* may return 0 for available() whether there is data available
* or not.
*
* We implement an ASCII stream as a Binary stream - we should really
* do the data conversion, but I cannot be bothered to implement this
* right now.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @return a Java InputStream that delivers the database column
* value as a stream of one byte ASCII characters. If the
* value is SQL NULL then the result is null
* @exception SQLException if a database access error occurs
* @see getBinaryStream
*/
public
InputStream
getAsciiStream
(
int
columnIndex
)
throws
SQLException
{
return
getBinaryStream
(
columnIndex
);
}
/**
* A column value can also be retrieved as a stream of Unicode
* characters. We implement this as a binary stream.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Java InputStream that delivers the database column value
* as a stream of two byte Unicode characters. If the value is
* SQL NULL, then the result is null
* @exception SQLException if a database access error occurs
* @see getAsciiStream
* @see getBinaryStream
*/
public
InputStream
getUnicodeStream
(
int
columnIndex
)
throws
SQLException
{
return
getBinaryStream
(
columnIndex
);
}
/**
* A column value can also be retrieved as a binary strea. This
* method is suitable for retrieving LONGVARBINARY values.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Java InputStream that delivers the database column value
* as a stream of two byte Unicode characters. If the value is
* SQL NULL, then the result is null
* @exception SQLException if a database access error occurs
* @see getAsciiStream
* @see getUnicodeStream
*/
public
InputStream
getBinaryStream
(
int
columnIndex
)
throws
SQLException
{
byte
b
[]
=
getBytes
(
columnIndex
);
if
(
b
!=
null
)
return
new
ByteArrayInputStream
(
b
);
return
null
;
// SQL NULL
}
/**
* The following routines simply convert the columnName into
* a columnIndex and then call the appropriate routine above.
*
* @param columnName is the SQL name of the column
* @return the column value
* @exception SQLException if a database access error occurs
*/
public
String
getString
(
String
columnName
)
throws
SQLException
{
return
getString
(
findColumn
(
columnName
));
}
public
boolean
getBoolean
(
String
columnName
)
throws
SQLException
{
return
getBoolean
(
findColumn
(
columnName
));
}
public
byte
getByte
(
String
columnName
)
throws
SQLException
{
return
getByte
(
findColumn
(
columnName
));
}
public
short
getShort
(
String
columnName
)
throws
SQLException
{
return
getShort
(
findColumn
(
columnName
));
}
public
int
getInt
(
String
columnName
)
throws
SQLException
{
return
getInt
(
findColumn
(
columnName
));
}
public
long
getLong
(
String
columnName
)
throws
SQLException
{
return
getLong
(
findColumn
(
columnName
));
}
public
float
getFloat
(
String
columnName
)
throws
SQLException
{
return
getFloat
(
findColumn
(
columnName
));
}
public
double
getDouble
(
String
columnName
)
throws
SQLException
{
return
getDouble
(
findColumn
(
columnName
));
}
public
BigDecimal
getBigDecimal
(
String
columnName
,
int
scale
)
throws
SQLException
{
return
getBigDecimal
(
findColumn
(
columnName
),
scale
);
}
public
byte
[]
getBytes
(
String
columnName
)
throws
SQLException
{
return
getBytes
(
findColumn
(
columnName
));
}
public
java
.
sql
.
Date
getDate
(
String
columnName
)
throws
SQLException
{
return
getDate
(
findColumn
(
columnName
));
}
public
Time
getTime
(
String
columnName
)
throws
SQLException
{
return
getTime
(
findColumn
(
columnName
));
}
public
Timestamp
getTimestamp
(
String
columnName
)
throws
SQLException
{
return
getTimestamp
(
findColumn
(
columnName
));
}
public
InputStream
getAsciiStream
(
String
columnName
)
throws
SQLException
{
return
getAsciiStream
(
findColumn
(
columnName
));
}
public
InputStream
getUnicodeStream
(
String
columnName
)
throws
SQLException
{
return
getUnicodeStream
(
findColumn
(
columnName
));
}
public
InputStream
getBinaryStream
(
String
columnName
)
throws
SQLException
{
return
getBinaryStream
(
findColumn
(
columnName
));
}
/**
* The first warning reported by calls on this ResultSet is
* returned. Subsequent ResultSet warnings will be chained
* to this SQLWarning.
*
* The warning chain is automatically cleared each time a new
* row is read.
*
* <B>Note:</B> This warning chain only covers warnings caused by
* ResultSet methods. Any warnings caused by statement methods
* (such as reading OUT parameters) will be chained on the
* Statement object.
*
* @return the first SQLWarning or null;
* @exception SQLException if a database access error occurs.
*/
public
SQLWarning
getWarnings
()
throws
SQLException
{
return
warnings
;
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this ResultSet
*
* @exception SQLException if a database access error occurs
*/
public
void
clearWarnings
()
throws
SQLException
{
warnings
=
null
;
}
/**
* Get the name of the SQL cursor used by this ResultSet
*
* In SQL, a result table is retrieved though a cursor that is
* named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references
* the cursor name.
*
* JDBC supports this SQL feature by providing the name of the
* SQL cursor used by a ResultSet. The current row of a ResulSet
* is also the current row of this SQL cursor.
*
* <B>Note:</B> If positioned update is not supported, a SQLException
* is thrown.
*
* @return the ResultSet's SQL cursor name.
* @exception SQLException if a database access error occurs
*/
public
String
getCursorName
()
throws
SQLException
{
return
connection
.
getCursorName
();
}
/**
* The numbers, types and properties of a ResultSet's columns are
* provided by the getMetaData method
*
* @return a description of the ResultSet's columns
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
ResultSetMetaData
getMetaData
()
throws
SQLException
{
return
new
ResultSetMetaData
(
rows
,
fields
);
}
/**
* Get the value of a column in the current row as a Java object
*
* This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* This method may also be used to read database specific abstract
* data types.
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public
Object
getObject
(
int
columnIndex
)
throws
SQLException
{
Field
field
;
if
(
columnIndex
<
1
||
columnIndex
>
fields
.
length
)
throw
new
SQLException
(
"Column index out of range"
);
field
=
fields
[
columnIndex
-
1
];
switch
(
field
.
getSQLType
())
{
case
Types
.
BIT
:
return
new
Boolean
(
getBoolean
(
columnIndex
));
case
Types
.
SMALLINT
:
return
new
Integer
(
getInt
(
columnIndex
));
case
Types
.
INTEGER
:
return
new
Integer
(
getInt
(
columnIndex
));
case
Types
.
BIGINT
:
return
new
Long
(
getLong
(
columnIndex
));
case
Types
.
NUMERIC
:
return
getBigDecimal
(
columnIndex
,
0
);
case
Types
.
REAL
:
return
new
Float
(
getFloat
(
columnIndex
));
case
Types
.
DOUBLE
:
return
new
Double
(
getDouble
(
columnIndex
));
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
getString
(
columnIndex
);
case
Types
.
DATE
:
return
getDate
(
columnIndex
);
case
Types
.
TIME
:
return
getTime
(
columnIndex
);
case
Types
.
TIMESTAMP
:
return
getTimestamp
(
columnIndex
);
default
:
return
new
PG_Object
(
field
.
getTypeName
(),
getString
(
columnIndex
));
}
}
/**
* Get the value of a column in the current row as a Java object
*
* This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* This method may also be used to read database specific abstract
* data types.
*
* @param columnName is the SQL name of the column
* @return a Object holding the column value
* @exception SQLException if a database access error occurs
*/
public
Object
getObject
(
String
columnName
)
throws
SQLException
{
return
getObject
(
findColumn
(
columnName
));
}
/**
* Map a ResultSet column name to a ResultSet column index
*
* @param columnName the name of the column
* @return the column index
* @exception SQLException if a database access error occurs
*/
public
int
findColumn
(
String
columnName
)
throws
SQLException
{
int
i
;
for
(
i
=
0
;
i
<
fields
.
length
;
++
i
)
if
(
fields
[
i
].
name
.
equalsIgnoreCase
(
columnName
))
return
(
i
+
1
);
throw
new
SQLException
(
"Column name not found"
);
}
// ************************************************************
// END OF PUBLIC INTERFACE
// ************************************************************
/**
* We at times need to know if the resultSet we are working
* with is the result of an UPDATE, DELETE or INSERT (in which
* case, we only have a row count), or of a SELECT operation
* (in which case, we have multiple fields) - this routine
* tells us.
*
* @return true if we have tuples available
*/
public
boolean
reallyResultSet
()
{
return
(
fields
!=
null
);
}
/**
* Since ResultSets can be chained, we need some method of
* finding the next one in the chain. The method getNext()
* returns the next one in the chain.
*
* @return the next ResultSet, or null if there are none
*/
public
ResultSet
getNext
()
{
return
next
;
}
/**
* This following method allows us to add a ResultSet object
* to the end of the current chain.
*
* @param r the resultset to add to the end of the chain.
*/
public
void
append
(
ResultSet
r
)
{
if
(
next
==
null
)
next
=
r
;
else
next
.
append
(
r
);
}
/**
* If we are just a place holder for results, we still need
* to get an updateCount. This method returns it.
*
* @return the updateCount
*/
public
int
getResultCount
()
{
return
updateCount
;
}
/**
* We also need to provide a couple of auxiliary functions for
* the implementation of the ResultMetaData functions. In
* particular, we need to know the number of rows and the
* number of columns. Rows are also known as Tuples
*
* getTupleCount returns the number of rows
*
* @return the number of rows
*/
public
int
getTupleCount
()
{
return
rows
.
size
();
}
/**
* getColumnCount returns the number of columns
*
* @return the number of columns
*/
public
int
getColumnCount
()
{
return
fields
.
length
;
}
}
src/interfaces/jdbc/postgresql/ResultSetMetaData.java
View file @
6a061da2
...
...
@@ -16,414 +16,415 @@ import postgresql.*;
*/
public
class
ResultSetMetaData
implements
java
.
sql
.
ResultSetMetaData
{
Vector
rows
;
Field
[]
fields
;
/**
* Initialise for a result with a tuple set and
* a field descriptor set
*
* @param rows the Vector of rows returned by the ResultSet
* @param fields the array of field descriptors
*/
public
ResultSetMetaData
(
Vector
rows
,
Field
[]
fields
)
{
this
.
rows
=
rows
;
this
.
fields
=
fields
;
}
/**
* Whats the number of columns in the ResultSet?
*
* @return the number
* @exception SQLException if a database access error occurs
*/
public
int
getColumnCount
()
throws
SQLException
{
return
fields
.
length
;
}
/**
* Is the column automatically numbered (and thus read-only)
* I believe that PostgreSQL does not support this feature.
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isAutoIncrement
(
int
column
)
throws
SQLException
{
return
false
;
}
/**
* Does a column's case matter? ASSUMPTION: Any field that is
* not obviously case insensitive is assumed to be case sensitive
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isCaseSensitive
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
case
Types
.
INTEGER
:
case
Types
.
FLOAT
:
case
Types
.
REAL
:
case
Types
.
DOUBLE
:
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
return
false
;
default
:
return
true
;
}
}
/**
* Can the column be used in a WHERE clause? Basically for
* this, I split the functions into two types: recognised
* types (which are always useable), and OTHER types (which
* may or may not be useable). The OTHER types, for now, I
* will assume they are useable. We should really query the
* catalog to see if they are useable.
*
* @param column the first column is 1, the second is 2...
* @return true if they can be used in a WHERE clause
* @exception SQLException if a database access error occurs
*/
public
boolean
isSearchable
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
// This switch is pointless, I know - but it is a set-up
// for further expansion.
switch
(
sql_type
)
{
case
Types
.
OTHER
:
return
true
;
default
:
return
true
;
}
}
/**
* Is the column a cash value? 6.1 introduced the cash/money
* type, which haven't been incorporated as of 970414, so I
* just check the type name for both 'cash' and 'money'
*
* @param column the first column is 1, the second is 2...
* @return true if its a cash column
* @exception SQLException if a database access error occurs
*/
public
boolean
isCurrency
(
int
column
)
throws
SQLException
{
String
type_name
=
getField
(
column
).
getTypeName
();
if
(
type_name
.
equals
(
"cash"
))
return
true
;
if
(
type_name
.
equals
(
"money"
))
return
true
;
return
false
;
}
/**
* Can you put a NULL in this column? I think this is always
* true in 6.1's case. It would only be false if the field had
* been defined NOT NULL (system catalogs could be queried?)
*
* @param column the first column is 1, the second is 2...
* @return one of the columnNullable values
* @exception SQLException if a database access error occurs
*/
public
int
isNullable
(
int
column
)
throws
SQLException
{
return
columnNullable
;
// We can always put NULL in
}
/**
* Is the column a signed number? In PostgreSQL, all numbers
* are signed, so this is trivial. However, strings are not
* signed (duh!)
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isSigned
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
case
Types
.
INTEGER
:
case
Types
.
FLOAT
:
case
Types
.
REAL
:
case
Types
.
DOUBLE
:
return
true
;
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
return
false
;
// I don't know about these?
default
:
return
false
;
}
}
/**
* What is the column's normal maximum width in characters?
*
* @param column the first column is 1, the second is 2, etc.
* @return the maximum width
* @exception SQLException if a database access error occurs
*/
public
int
getColumnDisplaySize
(
int
column
)
throws
SQLException
{
int
max
=
getColumnLabel
(
column
).
length
();
int
i
;
for
(
i
=
0
;
i
<
rows
.
size
();
++
i
)
{
byte
[][]
x
=
(
byte
[][])(
rows
.
elementAt
(
i
));
int
xl
=
x
[
column
-
1
].
length
;
if
(
xl
>
max
)
max
=
xl
;
}
return
max
;
}
/**
* What is the suggested column title for use in printouts and
* displays? We suggest the ColumnName!
*
* @param column the first column is 1, the second is 2, etc.
* @return the column label
* @exception SQLException if a database access error occurs
*/
public
String
getColumnLabel
(
int
column
)
throws
SQLException
{
return
getColumnName
(
column
);
}
/**
* What's a column's name?
*
* @param column the first column is 1, the second is 2, etc.
* @return the column name
* @exception SQLException if a databvase access error occurs
*/
public
String
getColumnName
(
int
column
)
throws
SQLException
{
return
getField
(
column
).
name
;
}
/**
* What is a column's table's schema? This relies on us knowing
* the table name....which I don't know how to do as yet. The
* JDBC specification allows us to return "" if this is not
* applicable.
*
* @param column the first column is 1, the second is 2...
* @return the Schema
* @exception SQLException if a database access error occurs
*/
public
String
getSchemaName
(
int
column
)
throws
SQLException
{
String
table_name
=
getTableName
(
column
);
// If the table name is invalid, so are we.
if
(
table_name
.
equals
(
""
))
return
""
;
return
""
;
// Ok, so I don't know how to
// do this as yet.
}
/**
* What is a column's number of decimal digits.
*
* @param column the first column is 1, the second is 2...
* @return the precision
* @exception SQLException if a database access error occurs
*/
public
int
getPrecision
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
return
5
;
case
Types
.
INTEGER
:
return
10
;
case
Types
.
REAL
:
return
8
;
case
Types
.
FLOAT
:
return
16
;
case
Types
.
DOUBLE
:
return
16
;
default
:
throw
new
SQLException
(
"no precision for non-numeric data types."
);
}
}
/**
* What is a column's number of digits to the right of the
* decimal point?
*
* @param column the first column is 1, the second is 2...
* @return the scale
* @exception SQLException if a database access error occurs
*/
public
int
getScale
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
return
0
;
case
Types
.
INTEGER
:
return
0
;
case
Types
.
REAL
:
return
8
;
case
Types
.
FLOAT
:
return
16
;
case
Types
.
DOUBLE
:
return
16
;
default
:
throw
new
SQLException
(
"no scale for non-numeric data types"
);
}
}
/**
* Whats a column's table's name? How do I find this out? Both
* getSchemaName() and getCatalogName() rely on knowing the table
* Name, so we need this before we can work on them.
*
* @param column the first column is 1, the second is 2...
* @return column name, or "" if not applicable
* @exception SQLException if a database access error occurs
*/
public
String
getTableName
(
int
column
)
throws
SQLException
{
return
""
;
}
/**
* What's a column's table's catalog name? As with getSchemaName(),
* we can say that if getTableName() returns n/a, then we can too -
* otherwise, we need to work on it.
*
* @param column the first column is 1, the second is 2...
* @return catalog name, or "" if not applicable
* @exception SQLException if a database access error occurs
*/
public
String
getCatalogName
(
int
column
)
throws
SQLException
{
String
table_name
=
getTableName
(
column
);
if
(
table_name
.
equals
(
""
))
return
""
;
return
""
;
// As with getSchemaName(), this
// is just the start of it.
}
/**
* What is a column's SQL Type? (java.sql.Type int)
*
* @param column the first column is 1, the second is 2, etc.
* @return the java.sql.Type value
* @exception SQLException if a database access error occurs
* @see postgresql.Field#getSQLType
* @see java.sql.Types
*/
public
int
getColumnType
(
int
column
)
throws
SQLException
{
return
getField
(
column
).
getSQLType
();
}
/**
* Whats is the column's data source specific type name?
*
* @param column the first column is 1, the second is 2, etc.
* @return the type name
* @exception SQLException if a database access error occurs
*/
public
String
getColumnTypeName
(
int
column
)
throws
SQLException
{
return
getField
(
column
).
getTypeName
();
}
/**
* Is the column definitely not writable? In reality, we would
* have to check the GRANT/REVOKE stuff for this to be effective,
* and I haven't really looked into that yet, so this will get
* re-visited.
*
* @param column the first column is 1, the second is 2, etc.
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isReadOnly
(
int
column
)
throws
SQLException
{
return
false
;
}
/**
* Is it possible for a write on the column to succeed? Again, we
* would in reality have to check the GRANT/REVOKE stuff, which
* I haven't worked with as yet. However, if it isn't ReadOnly, then
* it is obviously writable.
*
* @param column the first column is 1, the second is 2, etc.
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isWritable
(
int
column
)
throws
SQLException
{
if
(
isReadOnly
(
column
))
return
true
;
else
return
false
;
}
/**
* Will a write on this column definately succeed? Hmmm...this
* is a bad one, since the two preceding functions have not been
* really defined. I cannot tell is the short answer. I thus
* return isWritable() just to give us an idea.
*
* @param column the first column is 1, the second is 2, etc..
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isDefinitelyWritable
(
int
column
)
throws
SQLException
{
return
isWritable
(
column
);
}
// ********************************************************
// END OF PUBLIC INTERFACE
// ********************************************************
/**
* For several routines in this package, we need to convert
* a columnIndex into a Field[] descriptor. Rather than do
* the same code several times, here it is.
*
* @param columnIndex the first column is 1, the second is 2...
* @return the Field description
* @exception SQLException if a database access error occurs
*/
private
Field
getField
(
int
columnIndex
)
throws
SQLException
{
if
(
columnIndex
<
1
||
columnIndex
>
fields
.
length
)
throw
new
SQLException
(
"Column index out of range"
);
return
fields
[
columnIndex
-
1
];
}
Vector
rows
;
Field
[]
fields
;
/**
* Initialise for a result with a tuple set and
* a field descriptor set
*
* @param rows the Vector of rows returned by the ResultSet
* @param fields the array of field descriptors
*/
public
ResultSetMetaData
(
Vector
rows
,
Field
[]
fields
)
{
this
.
rows
=
rows
;
this
.
fields
=
fields
;
}
/**
* Whats the number of columns in the ResultSet?
*
* @return the number
* @exception SQLException if a database access error occurs
*/
public
int
getColumnCount
()
throws
SQLException
{
return
fields
.
length
;
}
/**
* Is the column automatically numbered (and thus read-only)
* I believe that PostgreSQL does not support this feature.
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isAutoIncrement
(
int
column
)
throws
SQLException
{
return
false
;
}
/**
* Does a column's case matter? ASSUMPTION: Any field that is
* not obviously case insensitive is assumed to be case sensitive
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isCaseSensitive
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
case
Types
.
INTEGER
:
case
Types
.
FLOAT
:
case
Types
.
REAL
:
case
Types
.
DOUBLE
:
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
return
false
;
default
:
return
true
;
}
}
/**
* Can the column be used in a WHERE clause? Basically for
* this, I split the functions into two types: recognised
* types (which are always useable), and OTHER types (which
* may or may not be useable). The OTHER types, for now, I
* will assume they are useable. We should really query the
* catalog to see if they are useable.
*
* @param column the first column is 1, the second is 2...
* @return true if they can be used in a WHERE clause
* @exception SQLException if a database access error occurs
*/
public
boolean
isSearchable
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
// This switch is pointless, I know - but it is a set-up
// for further expansion.
switch
(
sql_type
)
{
case
Types
.
OTHER
:
return
true
;
default
:
return
true
;
}
}
/**
* Is the column a cash value? 6.1 introduced the cash/money
* type, which haven't been incorporated as of 970414, so I
* just check the type name for both 'cash' and 'money'
*
* @param column the first column is 1, the second is 2...
* @return true if its a cash column
* @exception SQLException if a database access error occurs
*/
public
boolean
isCurrency
(
int
column
)
throws
SQLException
{
String
type_name
=
getField
(
column
).
getTypeName
();
if
(
type_name
.
equals
(
"cash"
))
return
true
;
if
(
type_name
.
equals
(
"money"
))
return
true
;
return
false
;
}
/**
* Can you put a NULL in this column? I think this is always
* true in 6.1's case. It would only be false if the field had
* been defined NOT NULL (system catalogs could be queried?)
*
* @param column the first column is 1, the second is 2...
* @return one of the columnNullable values
* @exception SQLException if a database access error occurs
*/
public
int
isNullable
(
int
column
)
throws
SQLException
{
return
columnNullable
;
// We can always put NULL in
}
/**
* Is the column a signed number? In PostgreSQL, all numbers
* are signed, so this is trivial. However, strings are not
* signed (duh!)
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isSigned
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
case
Types
.
INTEGER
:
case
Types
.
FLOAT
:
case
Types
.
REAL
:
case
Types
.
DOUBLE
:
return
true
;
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
return
false
;
// I don't know about these?
default
:
return
false
;
}
}
/**
* What is the column's normal maximum width in characters?
*
* @param column the first column is 1, the second is 2, etc.
* @return the maximum width
* @exception SQLException if a database access error occurs
*/
public
int
getColumnDisplaySize
(
int
column
)
throws
SQLException
{
int
max
=
getColumnLabel
(
column
).
length
();
int
i
;
for
(
i
=
0
;
i
<
rows
.
size
();
++
i
)
{
byte
[][]
x
=
(
byte
[][])(
rows
.
elementAt
(
i
));
int
xl
=
x
[
column
-
1
].
length
;
if
(
xl
>
max
)
max
=
xl
;
}
return
max
;
}
/**
* What is the suggested column title for use in printouts and
* displays? We suggest the ColumnName!
*
* @param column the first column is 1, the second is 2, etc.
* @return the column label
* @exception SQLException if a database access error occurs
*/
public
String
getColumnLabel
(
int
column
)
throws
SQLException
{
return
getColumnName
(
column
);
}
/**
* What's a column's name?
*
* @param column the first column is 1, the second is 2, etc.
* @return the column name
* @exception SQLException if a databvase access error occurs
*/
public
String
getColumnName
(
int
column
)
throws
SQLException
{
return
getField
(
column
).
name
;
}
/**
* What is a column's table's schema? This relies on us knowing
* the table name....which I don't know how to do as yet. The
* JDBC specification allows us to return "" if this is not
* applicable.
*
* @param column the first column is 1, the second is 2...
* @return the Schema
* @exception SQLException if a database access error occurs
*/
public
String
getSchemaName
(
int
column
)
throws
SQLException
{
String
table_name
=
getTableName
(
column
);
// If the table name is invalid, so are we.
if
(
table_name
.
equals
(
""
))
return
""
;
return
""
;
// Ok, so I don't know how to
// do this as yet.
}
/**
* What is a column's number of decimal digits.
*
* @param column the first column is 1, the second is 2...
* @return the precision
* @exception SQLException if a database access error occurs
*/
public
int
getPrecision
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
return
5
;
case
Types
.
INTEGER
:
return
10
;
case
Types
.
REAL
:
return
8
;
case
Types
.
FLOAT
:
return
16
;
case
Types
.
DOUBLE
:
return
16
;
default
:
throw
new
SQLException
(
"no precision for non-numeric data types."
);
}
}
/**
* What is a column's number of digits to the right of the
* decimal point?
*
* @param column the first column is 1, the second is 2...
* @return the scale
* @exception SQLException if a database access error occurs
*/
public
int
getScale
(
int
column
)
throws
SQLException
{
int
sql_type
=
getField
(
column
).
getSQLType
();
switch
(
sql_type
)
{
case
Types
.
SMALLINT
:
return
0
;
case
Types
.
INTEGER
:
return
0
;
case
Types
.
REAL
:
return
8
;
case
Types
.
FLOAT
:
return
16
;
case
Types
.
DOUBLE
:
return
16
;
default
:
throw
new
SQLException
(
"no scale for non-numeric data types"
);
}
}
/**
* Whats a column's table's name? How do I find this out? Both
* getSchemaName() and getCatalogName() rely on knowing the table
* Name, so we need this before we can work on them.
*
* @param column the first column is 1, the second is 2...
* @return column name, or "" if not applicable
* @exception SQLException if a database access error occurs
*/
public
String
getTableName
(
int
column
)
throws
SQLException
{
return
""
;
}
/**
* What's a column's table's catalog name? As with getSchemaName(),
* we can say that if getTableName() returns n/a, then we can too -
* otherwise, we need to work on it.
*
* @param column the first column is 1, the second is 2...
* @return catalog name, or "" if not applicable
* @exception SQLException if a database access error occurs
*/
public
String
getCatalogName
(
int
column
)
throws
SQLException
{
String
table_name
=
getTableName
(
column
);
if
(
table_name
.
equals
(
""
))
return
""
;
return
""
;
// As with getSchemaName(), this
// is just the start of it.
}
/**
* What is a column's SQL Type? (java.sql.Type int)
*
* @param column the first column is 1, the second is 2, etc.
* @return the java.sql.Type value
* @exception SQLException if a database access error occurs
* @see postgresql.Field#getSQLType
* @see java.sql.Types
*/
public
int
getColumnType
(
int
column
)
throws
SQLException
{
return
getField
(
column
).
getSQLType
();
}
/**
* Whats is the column's data source specific type name?
*
* @param column the first column is 1, the second is 2, etc.
* @return the type name
* @exception SQLException if a database access error occurs
*/
public
String
getColumnTypeName
(
int
column
)
throws
SQLException
{
return
getField
(
column
).
getTypeName
();
}
/**
* Is the column definitely not writable? In reality, we would
* have to check the GRANT/REVOKE stuff for this to be effective,
* and I haven't really looked into that yet, so this will get
* re-visited.
*
* @param column the first column is 1, the second is 2, etc.
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isReadOnly
(
int
column
)
throws
SQLException
{
return
false
;
}
/**
* Is it possible for a write on the column to succeed? Again, we
* would in reality have to check the GRANT/REVOKE stuff, which
* I haven't worked with as yet. However, if it isn't ReadOnly, then
* it is obviously writable.
*
* @param column the first column is 1, the second is 2, etc.
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isWritable
(
int
column
)
throws
SQLException
{
if
(
isReadOnly
(
column
))
return
true
;
else
return
false
;
}
/**
* Will a write on this column definately succeed? Hmmm...this
* is a bad one, since the two preceding functions have not been
* really defined. I cannot tell is the short answer. I thus
* return isWritable() just to give us an idea.
*
* @param column the first column is 1, the second is 2, etc..
* @return true if so
* @exception SQLException if a database access error occurs
*/
public
boolean
isDefinitelyWritable
(
int
column
)
throws
SQLException
{
return
isWritable
(
column
);
}
// ********************************************************
// END OF PUBLIC INTERFACE
// ********************************************************
/**
* For several routines in this package, we need to convert
* a columnIndex into a Field[] descriptor. Rather than do
* the same code several times, here it is.
*
* @param columnIndex the first column is 1, the second is 2...
* @return the Field description
* @exception SQLException if a database access error occurs
*/
private
Field
getField
(
int
columnIndex
)
throws
SQLException
{
if
(
columnIndex
<
1
||
columnIndex
>
fields
.
length
)
throw
new
SQLException
(
"Column index out of range"
);
return
fields
[
columnIndex
-
1
];
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment