1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

pgjindent jdbc files. First time jdbc files were formatted.

This commit is contained in:
Bruce Momjian
2001-10-25 06:00:05 +00:00
parent b81844b173
commit d2e27b0674
85 changed files with 23804 additions and 22165 deletions

View File

@ -33,432 +33,486 @@ import org.postgresql.largeobject.*;
public class ImageViewer implements ItemListener
{
Connection db;
Statement stat;
LargeObjectManager lom;
Frame frame;
Label label; // Label used to display the current name
List list; // The list of available images
imageCanvas canvas; // Canvas used to display the image
String currentImage; // The current images name
// This is a simple component to display our image
public class imageCanvas extends Canvas
{
// holds the image
private Image image;
// holds the background buffer
private Image bkg;
// the size of the buffer
private Dimension size;
public imageCanvas()
{
image=null;
}
public void setImage(Image img)
{
image=img;
repaint();
}
// This defines our minimum size
public Dimension getMinimumSize()
{
return new Dimension(400,400);
}
public Dimension getPreferedSize()
{
return getMinimumSize();
}
public void update(Graphics g)
{
paint(g);
}
/**
* Paints the image, using double buffering to prevent screen flicker
*/
public void paint(Graphics gr)
{
Dimension s = getSize();
if(size==null || bkg==null || !s.equals(size)) {
size = s;
bkg = createImage(size.width,size.height);
}
// now set the background
Graphics g = bkg.getGraphics();
g.setColor(Color.gray);
g.fillRect(0,0,s.width,s.height);
// now paint the image over the background
if(image!=null)
g.drawImage(image,0,0,this);
// dispose the graphics instance
g.dispose();
// paint the image onto the component
gr.drawImage(bkg,0,0,this);
}
}
public ImageViewer(Frame f,String url,String user,String password) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
frame = f;
MenuBar mb = new MenuBar();
Menu m;
MenuItem i;
f.setMenuBar(mb);
mb.add(m = new Menu("PostgreSQL"));
m.add(i= new MenuItem("Initialise"));
i.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.init();
}
});
m.add(i= new MenuItem("Exit"));
ActionListener exitListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.close();
}
};
m.addActionListener(exitListener);
mb.add(m = new Menu("Image"));
m.add(i= new MenuItem("Import"));
ActionListener importListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.importImage();
}
};
i.addActionListener(importListener);
m.add(i= new MenuItem("Remove"));
ActionListener removeListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.removeImage();
}
};
i.addActionListener(removeListener);
// To the north is a label used to display the current images name
f.add("North",label = new Label());
// We have a panel to the south of the frame containing the controls
Panel p = new Panel();
p.setLayout(new FlowLayout());
Button b;
p.add(b=new Button("Refresh List"));
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.refreshList();
}
});
p.add(b=new Button("Import new image"));
b.addActionListener(importListener);
p.add(b=new Button("Remove image"));
b.addActionListener(removeListener);
p.add(b=new Button("Quit"));
b.addActionListener(exitListener);
f.add("South",p);
// And a panel to the west containing the list of available images
f.add("West",list=new List());
list.addItemListener(this);
// Finally the centre contains our image
f.add("Center",canvas = new imageCanvas());
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
db = DriverManager.getConnection(url, user, password);
// Create a statement
stat = db.createStatement();
// Also, get the LargeObjectManager for this connection
lom = ((org.postgresql.Connection)db).getLargeObjectAPI();
// Now refresh the image selection list
refreshList();
}
/**
* This method initialises the database by creating a table that contains
* the image names, and Large Object OID's
*/
public void init()
{
try {
//db.setAutoCommit(true);
stat.executeUpdate("create table images (imgname name,imgoid oid)");
label.setText("Initialised database");
db.commit();
} catch(SQLException ex) {
label.setText(ex.toString());
}
// This must run outside the previous try{} catch{} segment
//try {
//db.setAutoCommit(true);
//} catch(SQLException ex) {
//label.setText(ex.toString());
//}
}
/**
* This closes the connection, and ends the application
*/
public void close()
{
try {
db.close();
} catch(SQLException ex) {
System.err.println(ex.toString());
}
System.exit(0);
}
/**
* This imports an image into the database, using a Thread to do this in the
* background.
*/
public void importImage()
{
FileDialog d = new FileDialog(frame,"Import Image",FileDialog.LOAD);
d.setVisible(true);
String name = d.getFile();
String dir = d.getDirectory();
d.dispose();
// now start the true importer
Thread t = new importer(db,name,dir);
//t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
/**
* This is an example of using a thread to import a file into a Large Object.
* It uses the Large Object extension, to write blocks of the file to the
* database.
*/
class importer extends Thread
{
String name,dir;
Connection db;
public importer(Connection db,String name,String dir) {
this.db = db;
this.name = name;
this.dir = dir;
}
public void run() {
// Now the real import stuff
if(name!=null && dir!=null) {
Statement stat = null;
try {
// fetch the large object manager
LargeObjectManager lom = ((org.postgresql.Connection)db).getLargeObjectAPI();
db.setAutoCommit(false);
// A temporary buffer - this can be as large as you like
byte buf[] = new byte[2048];
// Open the file
FileInputStream fis = new FileInputStream(new File(dir,name));
// Now create the large object
int oid = lom.create();
LargeObject blob = lom.open(oid);
// Now copy the file into the object.
//
// Note: we dont use write(buf), as the last block is rarely the same
// size as our buffer, so we have to use the amount read.
int s,t=0;
while((s=fis.read(buf,0,buf.length))>0) {
t+=s;
blob.write(buf,0,s);
}
// Close the object
blob.close();
// Now store the entry into the table
// As we are a different thread to the other window, we must use
// our own thread
stat = db.createStatement();
stat.executeUpdate("insert into images values ('"+name+"',"+oid+")");
db.commit();
db.setAutoCommit(false);
// Finally refresh the names list, and display the current image
ImageViewer.this.refreshList();
ImageViewer.this.displayImage(name);
} catch(Exception ex) {
label.setText(ex.toString());
} finally {
// ensure the statement is closed after us
try {
if(stat != null)
stat.close();
} catch(SQLException se) {
System.err.println("closing of Statement failed");
}
Connection db;
Statement stat;
LargeObjectManager lom;
Frame frame;
Label label; // Label used to display the current name
List list; // The list of available images
imageCanvas canvas; // Canvas used to display the image
String currentImage; // The current images name
// This is a simple component to display our image
public class imageCanvas extends Canvas
{
// holds the image
private Image image;
// holds the background buffer
private Image bkg;
// the size of the buffer
private Dimension size;
public imageCanvas()
{
image = null;
}
public void setImage(Image img)
{
image = img;
repaint();
}
// This defines our minimum size
public Dimension getMinimumSize()
{
return new Dimension(400, 400);
}
public Dimension getPreferedSize()
{
return getMinimumSize();
}
public void update(Graphics g)
{
paint(g);
}
/**
* Paints the image, using double buffering to prevent screen flicker
*/
public void paint(Graphics gr)
{
Dimension s = getSize();
if (size == null || bkg == null || !s.equals(size))
{
size = s;
bkg = createImage(size.width, size.height);
}
// now set the background
Graphics g = bkg.getGraphics();
g.setColor(Color.gray);
g.fillRect(0, 0, s.width, s.height);
// now paint the image over the background
if (image != null)
g.drawImage(image, 0, 0, this);
// dispose the graphics instance
g.dispose();
// paint the image onto the component
gr.drawImage(bkg, 0, 0, this);
}
}
}
}
}
/**
* This refreshes the list of available images
*/
public void refreshList()
{
try {
// First, we'll run a query, retrieving all of the image names
ResultSet rs = stat.executeQuery("select imgname from images order by imgname");
if(rs!=null) {
list.removeAll();
while(rs.next())
list.addItem(rs.getString(1));
rs.close();
}
} catch(SQLException ex) {
label.setText(ex.toString()+" Have you initialised the database?");
}
}
/**
* This removes an image from the database
*
* Note: With postgresql, this is the only way of deleting a large object
* using Java.
*/
public void removeImage()
{
try {
//
// Delete any large objects for the current name
//
// Note: We don't need to worry about being in a transaction
// here, because we are not opening any blobs, only deleting
// them
//
ResultSet rs = stat.executeQuery("select imgoid from images where imgname='"+currentImage+"'");
if(rs!=null) {
// Even though there should only be one image, we still have to
// cycle through the ResultSet
while(rs.next()) {
lom.delete(rs.getInt(1));
public ImageViewer(Frame f, String url, String user, String password) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
frame = f;
MenuBar mb = new MenuBar();
Menu m;
MenuItem i;
f.setMenuBar(mb);
mb.add(m = new Menu("PostgreSQL"));
m.add(i = new MenuItem("Initialise"));
i.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ImageViewer.this.init();
}
}
);
m.add(i = new MenuItem("Exit"));
ActionListener exitListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ImageViewer.this.close();
}
};
m.addActionListener(exitListener);
mb.add(m = new Menu("Image"));
m.add(i = new MenuItem("Import"));
ActionListener importListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ImageViewer.this.importImage();
}
};
i.addActionListener(importListener);
m.add(i = new MenuItem("Remove"));
ActionListener removeListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ImageViewer.this.removeImage();
}
};
i.addActionListener(removeListener);
// To the north is a label used to display the current images name
f.add("North", label = new Label());
// We have a panel to the south of the frame containing the controls
Panel p = new Panel();
p.setLayout(new FlowLayout());
Button b;
p.add(b = new Button("Refresh List"));
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ImageViewer.this.refreshList();
}
}
);
p.add(b = new Button("Import new image"));
b.addActionListener(importListener);
p.add(b = new Button("Remove image"));
b.addActionListener(removeListener);
p.add(b = new Button("Quit"));
b.addActionListener(exitListener);
f.add("South", p);
// And a panel to the west containing the list of available images
f.add("West", list = new List());
list.addItemListener(this);
// Finally the centre contains our image
f.add("Center", canvas = new imageCanvas());
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
db = DriverManager.getConnection(url, user, password);
// Create a statement
stat = db.createStatement();
// Also, get the LargeObjectManager for this connection
lom = ((org.postgresql.Connection)db).getLargeObjectAPI();
// Now refresh the image selection list
refreshList();
}
}
rs.close();
// Finally delete any entries for that name
stat.executeUpdate("delete from images where imgname='"+currentImage+"'");
label.setText(currentImage+" deleted");
currentImage=null;
refreshList();
} catch(SQLException ex) {
label.setText(ex.toString());
}
}
/**
* This displays an image from the database.
*
* For images, this is the easiest method.
*/
public void displayImage(String name)
{
try {
//
// Now as we are opening and reading a large object we must
// turn on Transactions. This includes the ResultSet.getBytes()
// method when it's used on a field of type oid!
//
db.setAutoCommit(false);
ResultSet rs = stat.executeQuery("select imgoid from images where imgname='"+name+"'");
if(rs!=null) {
// Even though there should only be one image, we still have to
// cycle through the ResultSet
while(rs.next()) {
canvas.setImage(canvas.getToolkit().createImage(rs.getBytes(1)));
label.setText(currentImage = name);
/**
* This method initialises the database by creating a table that contains
* the image names, and Large Object OID's
*/
public void init()
{
try
{
//db.setAutoCommit(true);
stat.executeUpdate("create table images (imgname name,imgoid oid)");
label.setText("Initialised database");
db.commit();
}
catch (SQLException ex)
{
label.setText(ex.toString());
}
// This must run outside the previous try{} catch{} segment
//try {
//db.setAutoCommit(true);
//} catch(SQLException ex) {
//label.setText(ex.toString());
//}
}
}
rs.close();
} catch(SQLException ex) {
label.setText(ex.toString());
} finally {
try {
db.setAutoCommit(true);
} catch(SQLException ex2) {
/**
* This closes the connection, and ends the application
*/
public void close()
{
try
{
db.close();
}
catch (SQLException ex)
{
System.err.println(ex.toString());
}
System.exit(0);
}
/**
* This imports an image into the database, using a Thread to do this in the
* background.
*/
public void importImage()
{
FileDialog d = new FileDialog(frame, "Import Image", FileDialog.LOAD);
d.setVisible(true);
String name = d.getFile();
String dir = d.getDirectory();
d.dispose();
// now start the true importer
Thread t = new importer(db, name, dir);
//t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
/**
* This is an example of using a thread to import a file into a Large Object.
* It uses the Large Object extension, to write blocks of the file to the
* database.
*/
class importer extends Thread
{
String name, dir;
Connection db;
public importer(Connection db, String name, String dir)
{
this.db = db;
this.name = name;
this.dir = dir;
}
public void run()
{
// Now the real import stuff
if (name != null && dir != null)
{
Statement stat = null;
try
{
// fetch the large object manager
LargeObjectManager lom = ((org.postgresql.Connection)db).getLargeObjectAPI();
db.setAutoCommit(false);
// A temporary buffer - this can be as large as you like
byte buf[] = new byte[2048];
// Open the file
FileInputStream fis = new FileInputStream(new File(dir, name));
// Now create the large object
int oid = lom.create();
LargeObject blob = lom.open(oid);
// Now copy the file into the object.
//
// Note: we dont use write(buf), as the last block is rarely the same
// size as our buffer, so we have to use the amount read.
int s, t = 0;
while ((s = fis.read(buf, 0, buf.length)) > 0)
{
t += s;
blob.write(buf, 0, s);
}
// Close the object
blob.close();
// Now store the entry into the table
// As we are a different thread to the other window, we must use
// our own thread
stat = db.createStatement();
stat.executeUpdate("insert into images values ('" + name + "'," + oid + ")");
db.commit();
db.setAutoCommit(false);
// Finally refresh the names list, and display the current image
ImageViewer.this.refreshList();
ImageViewer.this.displayImage(name);
}
catch (Exception ex)
{
label.setText(ex.toString());
}
finally
{
// ensure the statement is closed after us
try
{
if (stat != null)
stat.close();
}
catch (SQLException se)
{
System.err.println("closing of Statement failed");
}
}
}
}
}
/**
* This refreshes the list of available images
*/
public void refreshList()
{
try
{
// First, we'll run a query, retrieving all of the image names
ResultSet rs = stat.executeQuery("select imgname from images order by imgname");
if (rs != null)
{
list.removeAll();
while (rs.next())
list.addItem(rs.getString(1));
rs.close();
}
}
catch (SQLException ex)
{
label.setText(ex.toString() + " Have you initialised the database?");
}
}
/**
* This removes an image from the database
*
* Note: With postgresql, this is the only way of deleting a large object
* using Java.
*/
public void removeImage()
{
try
{
//
// Delete any large objects for the current name
//
// Note: We don't need to worry about being in a transaction
// here, because we are not opening any blobs, only deleting
// them
//
ResultSet rs = stat.executeQuery("select imgoid from images where imgname='" + currentImage + "'");
if (rs != null)
{
// Even though there should only be one image, we still have to
// cycle through the ResultSet
while (rs.next())
{
lom.delete(rs.getInt(1));
}
}
rs.close();
// Finally delete any entries for that name
stat.executeUpdate("delete from images where imgname='" + currentImage + "'");
label.setText(currentImage + " deleted");
currentImage = null;
refreshList();
}
catch (SQLException ex)
{
label.setText(ex.toString());
}
}
/**
* This displays an image from the database.
*
* For images, this is the easiest method.
*/
public void displayImage(String name)
{
try
{
//
// Now as we are opening and reading a large object we must
// turn on Transactions. This includes the ResultSet.getBytes()
// method when it's used on a field of type oid!
//
db.setAutoCommit(false);
ResultSet rs = stat.executeQuery("select imgoid from images where imgname='" + name + "'");
if (rs != null)
{
// Even though there should only be one image, we still have to
// cycle through the ResultSet
while (rs.next())
{
canvas.setImage(canvas.getToolkit().createImage(rs.getBytes(1)));
label.setText(currentImage = name);
}
}
rs.close();
}
catch (SQLException ex)
{
label.setText(ex.toString());
}
finally
{
try
{
db.setAutoCommit(true);
}
catch (SQLException ex2)
{}
}
}
public void itemStateChanged(ItemEvent e)
{
displayImage(list.getItem(((Integer)e.getItem()).intValue()));
}
/**
* This is the command line instructions
*/
public static void instructions()
{
System.err.println("java example.ImageViewer jdbc-url user password");
System.err.println("\nExamples:\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.ImageViewer jdbc:postgresql:test postgres password\n");
System.err.println("This example tests the binary large object api of the driver.\nBasically, it will allow you to store and view images held in the database.");
System.err.println("Note: If you are running this for the first time on a particular database,\nyou have to select \"Initialise\" in the \"PostgreSQL\" menu.\nThis will create a table used to store image names.");
}
/**
* This is the application entry point
*/
public static void main(String args[])
{
if (args.length != 3)
{
instructions();
System.exit(1);
}
try
{
Frame frame = new Frame("PostgreSQL ImageViewer v7.0 rev 1");
frame.setLayout(new BorderLayout());
ImageViewer viewer = new ImageViewer(frame, args[0], args[1], args[2]);
frame.pack();
frame.setLocation(0, 50);
frame.setVisible(true);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
}
}
public void itemStateChanged(ItemEvent e) {
displayImage(list.getItem(((Integer)e.getItem()).intValue()));
}
/**
* This is the command line instructions
*/
public static void instructions()
{
System.err.println("java example.ImageViewer jdbc-url user password");
System.err.println("\nExamples:\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.ImageViewer jdbc:postgresql:test postgres password\n");
System.err.println("This example tests the binary large object api of the driver.\nBasically, it will allow you to store and view images held in the database.");
System.err.println("Note: If you are running this for the first time on a particular database,\nyou have to select \"Initialise\" in the \"PostgreSQL\" menu.\nThis will create a table used to store image names.");
}
/**
* This is the application entry point
*/
public static void main(String args[])
{
if(args.length!=3) {
instructions();
System.exit(1);
}
try {
Frame frame = new Frame("PostgreSQL ImageViewer v7.0 rev 1");
frame.setLayout(new BorderLayout());
ImageViewer viewer = new ImageViewer(frame,args[0],args[1],args[2]);
frame.pack();
frame.setLocation(0,50);
frame.setVisible(true);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
}

View File

@ -5,236 +5,274 @@ import java.sql.*;
import java.util.*;
/**
* Test inserting and extracting Unicode-encoded strings.
* Test inserting and extracting Unicode-encoded strings.
*
* Synopsis:
* example.Unicode <url> <user> <password>
* where <url> must specify an existing database to which <user> and
* <password> give access and which has UNICODE as its encoding.
* (To create a database with UNICODE encoding, you need to compile
* postgres with "--enable-multibyte" and run createdb with the
* flag "-E UNICODE".)
* Synopsis:
* example.Unicode <url> <user> <password>
* where <url> must specify an existing database to which <user> and
* <password> give access and which has UNICODE as its encoding.
* (To create a database with UNICODE encoding, you need to compile
* postgres with "--enable-multibyte" and run createdb with the
* flag "-E UNICODE".)
*
* This test only produces output on error.
* This test only produces output on error.
*
* @author William Webber <william@live.com.au>
* @author William Webber <william@live.com.au>
*/
public class Unicode {
/**
* The url for the database to connect to.
*/
private String url;
public class Unicode
{
/**
* The user to connect as.
*/
private String user;
/**
* The url for the database to connect to.
*/
private String url;
/**
* The password to connect with.
*/
private String password;
/**
* The user to connect as.
*/
private String user;
private static void usage() {
log("usage: example.Unicode <url> <user> <password>");
}
/**
* The password to connect with.
*/
private String password;
private static void log(String message) {
System.err.println(message);
}
private static void usage()
{
log("usage: example.Unicode <url> <user> <password>");
}
private static void log(String message, Exception e) {
System.err.println(message);
e.printStackTrace();
}
private static void log(String message)
{
System.err.println(message);
}
private static void log(String message, Exception e)
{
System.err.println(message);
e.printStackTrace();
}
public Unicode(String url, String user, String password) {
this.url = url;
this.user = user;
this.password = password;
}
public Unicode(String url, String user, String password)
{
this.url = url;
this.user = user;
this.password = password;
}
/**
* Establish and return a connection to the database.
*/
private Connection getConnection() throws SQLException,
ClassNotFoundException {
Class.forName("org.postgresql.Driver");
Properties info = new Properties();
info.put("user", user);
info.put("password", password);
info.put("charSet", "utf-8");
return DriverManager.getConnection(url, info);
}
/**
* Establish and return a connection to the database.
*/
private Connection getConnection() throws SQLException,
ClassNotFoundException
{
Class.forName("org.postgresql.Driver");
Properties info = new Properties();
info.put("user", user);
info.put("password", password);
info.put("charSet", "utf-8");
return DriverManager.getConnection(url, info);
}
/**
* Get string representing a block of 256 consecutive unicode characters.
* We exclude the null character, "'", and "\".
*/
private String getSqlSafeUnicodeBlock(int blockNum) {
if (blockNum < 0 || blockNum > 255)
throw new IllegalArgumentException("blockNum must be from 0 to "
+ "255: " + blockNum);
StringBuffer sb = new StringBuffer(256);
int blockFirst = blockNum * 256;
int blockLast = blockFirst + 256;
for (int i = blockFirst; i < blockLast; i++) {
char c = (char) i;
if (c == '\0' || c == '\'' || c == '\\')
continue;
sb.append(c);
}
return sb.toString();
}
/**
* Get string representing a block of 256 consecutive unicode characters.
* We exclude the null character, "'", and "\".
*/
private String getSqlSafeUnicodeBlock(int blockNum)
{
if (blockNum < 0 || blockNum > 255)
throw new IllegalArgumentException("blockNum must be from 0 to "
+ "255: " + blockNum);
StringBuffer sb = new StringBuffer(256);
int blockFirst = blockNum * 256;
int blockLast = blockFirst + 256;
for (int i = blockFirst; i < blockLast; i++)
{
char c = (char) i;
if (c == '\0' || c == '\'' || c == '\\')
continue;
sb.append(c);
}
return sb.toString();
}
/**
* Is the block a block of valid unicode values.
* d800 to db7f is the "unassigned high surrogate" range.
* db80 to dbff is the "private use" range.
* These should not be used in actual Unicode strings;
* at least, jdk1.2 will not convert them to utf-8.
*/
private boolean isValidUnicodeBlock(int blockNum) {
if (blockNum >= 0xd8 && blockNum <= 0xdb)
return false;
else
return true;
}
/**
* Is the block a block of valid unicode values.
* d800 to db7f is the "unassigned high surrogate" range.
* db80 to dbff is the "private use" range.
* These should not be used in actual Unicode strings;
* at least, jdk1.2 will not convert them to utf-8.
*/
private boolean isValidUnicodeBlock(int blockNum)
{
if (blockNum >= 0xd8 && blockNum <= 0xdb)
return false;
else
return true;
}
/**
* Report incorrect block retrieval.
*/
private void reportRetrievalError(int blockNum, String block,
String retrieved) {
String message = "Block " + blockNum + " returned incorrectly: ";
int i = 0;
for (i = 0; i < block.length(); i++) {
if (i >= retrieved.length()) {
message += "too short";
break;
} else if (retrieved.charAt(i) != block.charAt(i)) {
message +=
"first changed character at position " + i + ", sent as 0x"
+ Integer.toHexString((int) block.charAt(i))
+ ", retrieved as 0x"
+ Integer.toHexString ((int) retrieved.charAt(i));
break;
}
}
if (i >= block.length())
message += "too long";
log(message);
}
/**
* Do the testing.
*/
public void runTest() {
Connection connection = null;
Statement statement = null;
int blockNum = 0;
final int CREATE = 0;
final int INSERT = 1;
final int SELECT = 2;
final int LIKE = 3;
int mode = CREATE;
try {
connection = getConnection();
statement = connection.createStatement();
statement.executeUpdate("CREATE TABLE test_unicode "
+ "( blockNum INT PRIMARY KEY, "
+ "block TEXT );");
mode = INSERT;
for (blockNum = 0; blockNum < 256; blockNum++) {
if (isValidUnicodeBlock(blockNum)) {
String block = getSqlSafeUnicodeBlock(blockNum);
statement.executeUpdate
("INSERT INTO test_unicode VALUES ( " + blockNum
+ ", '" + block + "');");
}
}
mode = SELECT;
for (blockNum = 0; blockNum < 256; blockNum++) {
if (isValidUnicodeBlock(blockNum)) {
String block = getSqlSafeUnicodeBlock(blockNum);
ResultSet rs = statement.executeQuery
("SELECT block FROM test_unicode WHERE blockNum = "
+ blockNum + ";");
if (!rs.next())
log("Could not retrieve block " + blockNum);
else {
String retrieved = rs.getString(1);
if (!retrieved.equals(block)) {
reportRetrievalError(blockNum, block, retrieved);
}
}
}
}
mode = LIKE;
for (blockNum = 0; blockNum < 256; blockNum++) {
if (isValidUnicodeBlock(blockNum)) {
String block = getSqlSafeUnicodeBlock(blockNum);
String likeString = "%" +
block.substring(2, block.length() - 3) + "%" ;
ResultSet rs = statement.executeQuery
("SELECT blockNum FROM test_unicode WHERE block LIKE '"
+ likeString + "';");
if (!rs.next())
log("Could get block " + blockNum + " using LIKE");
}
}
} catch (SQLException sqle) {
switch (mode) {
case CREATE:
log("Exception creating database", sqle);
break;
case INSERT:
log("Exception inserting block " + blockNum, sqle);
break;
case SELECT:
log("Exception selecting block " + blockNum, sqle);
break;
case LIKE:
log("Exception doing LIKE on block " + blockNum, sqle);
break;
default:
log("Exception", sqle);
break;
}
} catch (ClassNotFoundException cnfe) {
log("Unable to load driver", cnfe);
return;
}
try {
if (statement != null)
statement.close();
if (connection != null)
connection.close();
} catch (SQLException sqle) {
log("Exception closing connections", sqle);
}
if (mode > CREATE) {
// If the backend gets what it regards as garbage on a connection,
// that connection may become unusable. To be safe, we create
// a fresh connection to delete the table.
try {
connection = getConnection();
statement = connection.createStatement();
statement.executeUpdate("DROP TABLE test_unicode;");
} catch (Exception sqle) {
log("*** ERROR: unable to delete test table "
+ "test_unicode; must be deleted manually", sqle);
}
}
}
/**
* Report incorrect block retrieval.
*/
private void reportRetrievalError(int blockNum, String block,
String retrieved)
{
String message = "Block " + blockNum + " returned incorrectly: ";
int i = 0;
for (i = 0; i < block.length(); i++)
{
if (i >= retrieved.length())
{
message += "too short";
break;
}
else if (retrieved.charAt(i) != block.charAt(i))
{
message +=
"first changed character at position " + i + ", sent as 0x"
+ Integer.toHexString((int) block.charAt(i))
+ ", retrieved as 0x"
+ Integer.toHexString ((int) retrieved.charAt(i));
break;
}
}
if (i >= block.length())
message += "too long";
log(message);
}
public static void main(String [] args) {
if (args.length != 3) {
usage();
System.exit(1);
}
new Unicode(args[0], args[1], args[2]).runTest();
}
/**
* Do the testing.
*/
public void runTest()
{
Connection connection = null;
Statement statement = null;
int blockNum = 0;
final int CREATE = 0;
final int INSERT = 1;
final int SELECT = 2;
final int LIKE = 3;
int mode = CREATE;
try
{
connection = getConnection();
statement = connection.createStatement();
statement.executeUpdate("CREATE TABLE test_unicode "
+ "( blockNum INT PRIMARY KEY, "
+ "block TEXT );");
mode = INSERT;
for (blockNum = 0; blockNum < 256; blockNum++)
{
if (isValidUnicodeBlock(blockNum))
{
String block = getSqlSafeUnicodeBlock(blockNum);
statement.executeUpdate
("INSERT INTO test_unicode VALUES ( " + blockNum
+ ", '" + block + "');");
}
}
mode = SELECT;
for (blockNum = 0; blockNum < 256; blockNum++)
{
if (isValidUnicodeBlock(blockNum))
{
String block = getSqlSafeUnicodeBlock(blockNum);
ResultSet rs = statement.executeQuery
("SELECT block FROM test_unicode WHERE blockNum = "
+ blockNum + ";");
if (!rs.next())
log("Could not retrieve block " + blockNum);
else
{
String retrieved = rs.getString(1);
if (!retrieved.equals(block))
{
reportRetrievalError(blockNum, block, retrieved);
}
}
}
}
mode = LIKE;
for (blockNum = 0; blockNum < 256; blockNum++)
{
if (isValidUnicodeBlock(blockNum))
{
String block = getSqlSafeUnicodeBlock(blockNum);
String likeString = "%" +
block.substring(2, block.length() - 3) + "%" ;
ResultSet rs = statement.executeQuery
("SELECT blockNum FROM test_unicode WHERE block LIKE '"
+ likeString + "';");
if (!rs.next())
log("Could get block " + blockNum + " using LIKE");
}
}
}
catch (SQLException sqle)
{
switch (mode)
{
case CREATE:
log("Exception creating database", sqle);
break;
case INSERT:
log("Exception inserting block " + blockNum, sqle);
break;
case SELECT:
log("Exception selecting block " + blockNum, sqle);
break;
case LIKE:
log("Exception doing LIKE on block " + blockNum, sqle);
break;
default:
log("Exception", sqle);
break;
}
}
catch (ClassNotFoundException cnfe)
{
log("Unable to load driver", cnfe);
return ;
}
try
{
if (statement != null)
statement.close();
if (connection != null)
connection.close();
}
catch (SQLException sqle)
{
log("Exception closing connections", sqle);
}
if (mode > CREATE)
{
// If the backend gets what it regards as garbage on a connection,
// that connection may become unusable. To be safe, we create
// a fresh connection to delete the table.
try
{
connection = getConnection();
statement = connection.createStatement();
statement.executeUpdate("DROP TABLE test_unicode;");
}
catch (Exception sqle)
{
log("*** ERROR: unable to delete test table "
+ "test_unicode; must be deleted manually", sqle);
}
}
}
public static void main(String [] args)
{
if (args.length != 3)
{
usage();
System.exit(1);
}
new Unicode(args[0], args[1], args[2]).runTest();
}
}

View File

@ -6,7 +6,7 @@ import java.text.*;
/**
*
* $Id: basic.java,v 1.7 2001/01/31 09:23:45 peter Exp $
* $Id: basic.java,v 1.8 2001/10/25 05:59:58 momjian Exp $
*
* This example tests the basic components of the JDBC driver, and shows
* how even the simplest of queries can be implemented.
@ -20,184 +20,198 @@ import java.text.*;
public class basic
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
public basic(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
public basic(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise
cleanup();
// Clean up the database (in case we failed earlier) then initialise
cleanup();
// Now run tests using JDBC methods
doexample();
// Now run tests using JDBC methods
doexample();
// Clean up the database
cleanup();
// Clean up the database
cleanup();
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
//throw postgresql.Driver.notImplemented();
}
//throw postgresql.Driver.notImplemented();
}
/**
* This drops the table (if it existed). No errors are reported.
*/
public void cleanup()
{
try {
st.executeUpdate("drop table basic");
} catch(Exception ex) {
// We ignore any errors here
}
}
/**
* This drops the table (if it existed). No errors are reported.
*/
public void cleanup()
{
try
{
st.executeUpdate("drop table basic");
}
catch (Exception ex)
{
// We ignore any errors here
}
}
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nRunning tests:");
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nRunning tests:");
// First we need a table to store data in
st.executeUpdate("create table basic (a int2, b int2)");
// First we need a table to store data in
st.executeUpdate("create table basic (a int2, b int2)");
// Now insert some data, using the Statement
st.executeUpdate("insert into basic values (1,1)");
st.executeUpdate("insert into basic values (2,1)");
st.executeUpdate("insert into basic values (3,1)");
// Now insert some data, using the Statement
st.executeUpdate("insert into basic values (1,1)");
st.executeUpdate("insert into basic values (2,1)");
st.executeUpdate("insert into basic values (3,1)");
// This shows how to get the oid of a just inserted row
// updated for 7.1
st.executeUpdate("insert into basic values (4,1)");
int insertedOID = ((org.postgresql.Statement)st).getInsertedOID();
System.out.println("Inserted row with oid "+insertedOID);
// This shows how to get the oid of a just inserted row
// updated for 7.1
st.executeUpdate("insert into basic values (4,1)");
int insertedOID = ((org.postgresql.Statement)st).getInsertedOID();
System.out.println("Inserted row with oid " + insertedOID);
// Now change the value of b from 1 to 8
st.executeUpdate("update basic set b=8");
System.out.println("Updated "+st.getUpdateCount()+" rows");
// Now change the value of b from 1 to 8
st.executeUpdate("update basic set b=8");
System.out.println("Updated " + st.getUpdateCount() + " rows");
// Now delete 2 rows
st.executeUpdate("delete from basic where a<3");
System.out.println("deleted "+st.getUpdateCount()+" rows");
// Now delete 2 rows
st.executeUpdate("delete from basic where a<3");
System.out.println("deleted " + st.getUpdateCount() + " rows");
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc).
//
// Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic values (?,?)");
for(int i=2;i<5;i++) {
ps.setInt(1,4); // "column a" = 5
ps.setInt(2,i); // "column b" = i
ps.executeUpdate(); // executeUpdate because insert returns no data
}
ps.close(); // Always close when we are done with it
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc).
//
// Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic values (?,?)");
for (int i = 2;i < 5;i++)
{
ps.setInt(1, 4); // "column a" = 5
ps.setInt(2, i); // "column b" = i
ps.executeUpdate(); // executeUpdate because insert returns no data
}
ps.close(); // Always close when we are done with it
// Finally perform a query on the table
System.out.println("performing a query");
ResultSet rs = st.executeQuery("select a, b from basic");
if(rs!=null) {
// Now we run through the result set, printing out the result.
// Note, we must call .next() before attempting to read any results
while(rs.next()) {
int a = rs.getInt("a"); // This shows how to get the value by name
int b = rs.getInt(2); // This shows how to get the value by column
System.out.println(" a="+a+" b="+b);
}
rs.close(); // again, you must close the result when done
}
// Finally perform a query on the table
System.out.println("performing a query");
ResultSet rs = st.executeQuery("select a, b from basic");
if (rs != null)
{
// Now we run through the result set, printing out the result.
// Note, we must call .next() before attempting to read any results
while (rs.next())
{
int a = rs.getInt("a"); // This shows how to get the value by name
int b = rs.getInt(2); // This shows how to get the value by column
System.out.println(" a=" + a + " b=" + b);
}
rs.close(); // again, you must close the result when done
}
// Now run the query again, showing a more efficient way of getting the
// result if you don't know what column number a value is in
System.out.println("performing another query");
rs = st.executeQuery("select * from basic where b>1");
if(rs!=null) {
// First find out the column numbers.
//
// It's best to do this here, as calling the methods with the column
// numbers actually performs this call each time they are called. This
// really speeds things up on large queries.
//
int col_a = rs.findColumn("a");
int col_b = rs.findColumn("b");
// Now run the query again, showing a more efficient way of getting the
// result if you don't know what column number a value is in
// Now we run through the result set, printing out the result.
// Again, we must call .next() before attempting to read any results
while(rs.next()) {
int a = rs.getInt(col_a); // This shows how to get the value by name
int b = rs.getInt(col_b); // This shows how to get the value by column
System.out.println(" a="+a+" b="+b);
}
rs.close(); // again, you must close the result when done
}
System.out.println("performing another query");
rs = st.executeQuery("select * from basic where b>1");
if (rs != null)
{
// First find out the column numbers.
//
// It's best to do this here, as calling the methods with the column
// numbers actually performs this call each time they are called. This
// really speeds things up on large queries.
//
int col_a = rs.findColumn("a");
int col_b = rs.findColumn("b");
// Now test maxrows by setting it to 3 rows
st.setMaxRows(3);
System.out.println("performing a query limited to "+st.getMaxRows());
rs = st.executeQuery("select a, b from basic");
while(rs.next()) {
int a = rs.getInt("a"); // This shows how to get the value by name
int b = rs.getInt(2); // This shows how to get the value by column
System.out.println(" a="+a+" b="+b);
}
rs.close(); // again, you must close the result when done
// Now we run through the result set, printing out the result.
// Again, we must call .next() before attempting to read any results
while (rs.next())
{
int a = rs.getInt(col_a); // This shows how to get the value by name
int b = rs.getInt(col_b); // This shows how to get the value by column
System.out.println(" a=" + a + " b=" + b);
}
rs.close(); // again, you must close the result when done
}
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
}
// Now test maxrows by setting it to 3 rows
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis example tests the basic components of the JDBC driver, demonstrating\nhow to build simple queries in java.\n");
System.out.println("Useage:\n java example.basic jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
st.setMaxRows(3);
System.out.println("performing a query limited to " + st.getMaxRows());
rs = st.executeQuery("select a, b from basic");
while (rs.next())
{
int a = rs.getInt("a"); // This shows how to get the value by name
int b = rs.getInt(2); // This shows how to get the value by column
System.out.println(" a=" + a + " b=" + b);
}
rs.close(); // again, you must close the result when done
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL basic test v6.3 rev 1\n");
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
}
if(args.length<3)
instructions();
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis example tests the basic components of the JDBC driver, demonstrating\nhow to build simple queries in java.\n");
System.out.println("Useage:\n java example.basic jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL basic test v6.3 rev 1\n");
// Now run the tests
try {
basic test = new basic(args);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
if (args.length < 3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// Now run the tests
try
{
basic test = new basic(args);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
}

View File

@ -24,224 +24,236 @@ import org.postgresql.largeobject.*;
public class blobtest
{
Connection db;
Statement s;
LargeObjectManager lobj;
public blobtest(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
// This is required for all LargeObject calls
System.out.println("Connected... First turn off autoCommit()");
db.setAutoCommit(false);
System.out.println("Now creating a statement");
s = db.createStatement();
// Now run tests using postgresql's own Large object api
// NOTE: The methods shown in this example are _NOT_ JDBC, but are
// an implementation of the calls found in libpq. Unless you need to
// use this functionality, look at the jdbc tests on how to access blobs.
ownapi();
// Now run tests using JDBC methods
//jdbcapi(db,s);
// Finally close the database
System.out.println("Now closing the connection");
s.close();
db.close();
}
/**
* Now this is an extension to JDBC, unique to postgresql. Here we fetch
* an PGlobj object, which provides us with access to postgresql's
* large object api.
*/
public void ownapi() throws FileNotFoundException, IOException, SQLException
{
System.out.println("\n----------------------------------------------------------------------\nTesting postgresql large object api\n----------------------------------------------------------------------\n");
// Internally, the driver provides JDBC compliant methods to access large
// objects, however the unique methods available to postgresql makes
// things a little easier.
System.out.println("Gaining access to large object api");
lobj = ((org.postgresql.Connection)db).getLargeObjectAPI();
int oid = ownapi_test1();
ownapi_test2(oid);
// Now call the jdbc2api test
jdbc2api(oid);
// finally delete the large object
ownapi_test3(oid);
System.out.println("\n\nOID="+oid);
}
private int ownapi_test1() throws FileNotFoundException, IOException, SQLException
{
System.out.println("Test 1 Creating a large object\n");
// Ok, test 1 is to create a large object. To do this, we use the create
// method.
System.out.println("Creating a large object");
int oid = lobj.create(LargeObjectManager.READ|LargeObjectManager.WRITE);
DriverManager.println("got large object oid="+oid);
LargeObject obj = lobj.open(oid,LargeObjectManager.WRITE);
DriverManager.println("got large object obj="+obj);
// Now open a test file - this class will do
System.out.println("Opening test source object");
FileInputStream fis = new FileInputStream("example/blobtest.java");
// copy the data
System.out.println("Copying file to large object");
byte buf[] = new byte[2048];
int s,tl=0;
while((s=fis.read(buf,0,2048))>0) {
System.out.println("Block size="+s+" offset="+tl);
//System.out.write(buf);
obj.write(buf,0,s);
tl+=s;
}
DriverManager.println("Copied "+tl+" bytes");
// Close the object
System.out.println("Closing object");
obj.close();
return oid;
}
private void ownapi_test2(int oid) throws FileNotFoundException, IOException, SQLException
{
System.out.println("Test 2 Reading a large object and save as a file\n");
// Now open the large object
System.out.println("Opening large object "+oid);
LargeObject obj = lobj.open(oid,LargeObjectManager.READ);
DriverManager.println("got obj="+obj);
// Now open a test file - this class will do
System.out.println("Opening test destination object");
FileOutputStream fos = new FileOutputStream("blob_testoutput");
// copy the data
System.out.println("Copying large object to file");
byte buf[] = new byte[512];
int s=obj.size();
int tl=0;
while(s>0) {
int rs = buf.length;
if(s<rs) rs=s;
obj.read(buf,0,rs);
fos.write(buf,0,rs);
tl+=rs;
s-=rs;
}
DriverManager.println("Copied "+tl+"/"+obj.size()+" bytes");
// Close the object
System.out.println("Closing object");
obj.close();
}
private void ownapi_test3(int oid) throws SQLException
{
System.out.println("Test 3 Deleting a large object\n");
// Now open the large object
System.out.println("Deleting large object "+oid);
lobj.unlink(oid);
}
//=======================================================================
// This tests the Blob interface of the JDBC 2.0 specification
public void jdbc2api(int oid) throws SQLException, IOException
{
System.out.println("Testing JDBC2 Blob interface:");
jdbc2api_cleanup();
System.out.println("Creating Blob on large object "+oid);
s.executeUpdate("create table basic (a oid)");
System.out.println("Inserting row");
s.executeUpdate("insert into basic values ("+oid+")");
System.out.println("Selecting row");
ResultSet rs = s.executeQuery("select a from basic");
if(rs!=null) {
while(rs.next()) {
System.out.println("Fetching Blob");
Blob b = rs.getBlob("a");
System.out.println("Blob.length() = "+b.length());
System.out.println("Characters 400-500:");
System.out.write(b.getBytes(400l,100));
System.out.println();
}
rs.close();
Connection db;
Statement s;
LargeObjectManager lobj;
public blobtest(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
// This is required for all LargeObject calls
System.out.println("Connected... First turn off autoCommit()");
db.setAutoCommit(false);
System.out.println("Now creating a statement");
s = db.createStatement();
// Now run tests using postgresql's own Large object api
// NOTE: The methods shown in this example are _NOT_ JDBC, but are
// an implementation of the calls found in libpq. Unless you need to
// use this functionality, look at the jdbc tests on how to access blobs.
ownapi();
// Now run tests using JDBC methods
//jdbcapi(db,s);
// Finally close the database
System.out.println("Now closing the connection");
s.close();
db.close();
}
System.out.println("Cleaning up");
jdbc2api_cleanup();
}
private void jdbc2api_cleanup() throws SQLException
{
db.setAutoCommit(true);
try {
s.executeUpdate("drop table basic");
} catch(Exception ex) {
// We ignore any errors here
/**
* Now this is an extension to JDBC, unique to postgresql. Here we fetch
* an PGlobj object, which provides us with access to postgresql's
* large object api.
*/
public void ownapi() throws FileNotFoundException, IOException, SQLException
{
System.out.println("\n----------------------------------------------------------------------\nTesting postgresql large object api\n----------------------------------------------------------------------\n");
// Internally, the driver provides JDBC compliant methods to access large
// objects, however the unique methods available to postgresql makes
// things a little easier.
System.out.println("Gaining access to large object api");
lobj = ((org.postgresql.Connection)db).getLargeObjectAPI();
int oid = ownapi_test1();
ownapi_test2(oid);
// Now call the jdbc2api test
jdbc2api(oid);
// finally delete the large object
ownapi_test3(oid);
System.out.println("\n\nOID=" + oid);
}
private int ownapi_test1() throws FileNotFoundException, IOException, SQLException
{
System.out.println("Test 1 Creating a large object\n");
// Ok, test 1 is to create a large object. To do this, we use the create
// method.
System.out.println("Creating a large object");
int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
DriverManager.println("got large object oid=" + oid);
LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
DriverManager.println("got large object obj=" + obj);
// Now open a test file - this class will do
System.out.println("Opening test source object");
FileInputStream fis = new FileInputStream("example/blobtest.java");
// copy the data
System.out.println("Copying file to large object");
byte buf[] = new byte[2048];
int s, tl = 0;
while ((s = fis.read(buf, 0, 2048)) > 0)
{
System.out.println("Block size=" + s + " offset=" + tl);
//System.out.write(buf);
obj.write(buf, 0, s);
tl += s;
}
DriverManager.println("Copied " + tl + " bytes");
// Close the object
System.out.println("Closing object");
obj.close();
return oid;
}
private void ownapi_test2(int oid) throws FileNotFoundException, IOException, SQLException
{
System.out.println("Test 2 Reading a large object and save as a file\n");
// Now open the large object
System.out.println("Opening large object " + oid);
LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
DriverManager.println("got obj=" + obj);
// Now open a test file - this class will do
System.out.println("Opening test destination object");
FileOutputStream fos = new FileOutputStream("blob_testoutput");
// copy the data
System.out.println("Copying large object to file");
byte buf[] = new byte[512];
int s = obj.size();
int tl = 0;
while (s > 0)
{
int rs = buf.length;
if (s < rs)
rs = s;
obj.read(buf, 0, rs);
fos.write(buf, 0, rs);
tl += rs;
s -= rs;
}
DriverManager.println("Copied " + tl + "/" + obj.size() + " bytes");
// Close the object
System.out.println("Closing object");
obj.close();
}
private void ownapi_test3(int oid) throws SQLException
{
System.out.println("Test 3 Deleting a large object\n");
// Now open the large object
System.out.println("Deleting large object " + oid);
lobj.unlink(oid);
}
//=======================================================================
// This tests the Blob interface of the JDBC 2.0 specification
public void jdbc2api(int oid) throws SQLException, IOException
{
System.out.println("Testing JDBC2 Blob interface:");
jdbc2api_cleanup();
System.out.println("Creating Blob on large object " + oid);
s.executeUpdate("create table basic (a oid)");
System.out.println("Inserting row");
s.executeUpdate("insert into basic values (" + oid + ")");
System.out.println("Selecting row");
ResultSet rs = s.executeQuery("select a from basic");
if (rs != null)
{
while (rs.next())
{
System.out.println("Fetching Blob");
Blob b = rs.getBlob("a");
System.out.println("Blob.length() = " + b.length());
System.out.println("Characters 400-500:");
System.out.write(b.getBytes(400l, 100));
System.out.println();
}
rs.close();
}
System.out.println("Cleaning up");
jdbc2api_cleanup();
}
private void jdbc2api_cleanup() throws SQLException
{
db.setAutoCommit(true);
try
{
s.executeUpdate("drop table basic");
}
catch (Exception ex)
{
// We ignore any errors here
}
db.setAutoCommit(false);
}
//=======================================================================
public static void instructions()
{
System.err.println("java example.blobtest jdbc-url user password [debug]");
System.err.println("\nExamples:\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.blobtest jdbc:postgresql:test postgres password\nThis will run the tests on the database test on the local host.\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.blobtest jdbc:postgresql:test postgres password debug\nThis is the same as above, but will output debug information.\n");
System.err.println("This example tests the binary large object api of the driver.\nThis allows images or java objects to be stored in the database, and retrieved\nusing both postgresql's own api, and the standard JDBC api.");
}
public static void main(String args[])
{
System.out.println("PostgreSQL blobtest v7.0 rev 1\n");
if (args.length < 3)
{
instructions();
System.exit(1);
}
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// Now run the tests
try
{
blobtest test = new blobtest(args);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
db.setAutoCommit(false);
}
//=======================================================================
public static void instructions()
{
System.err.println("java example.blobtest jdbc-url user password [debug]");
System.err.println("\nExamples:\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.blobtest jdbc:postgresql:test postgres password\nThis will run the tests on the database test on the local host.\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.blobtest jdbc:postgresql:test postgres password debug\nThis is the same as above, but will output debug information.\n");
System.err.println("This example tests the binary large object api of the driver.\nThis allows images or java objects to be stored in the database, and retrieved\nusing both postgresql's own api, and the standard JDBC api.");
}
public static void main(String args[])
{
System.out.println("PostgreSQL blobtest v7.0 rev 1\n");
if(args.length<3) {
instructions();
System.exit(1);
}
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
// Now run the tests
try {
blobtest test = new blobtest(args);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
}

View File

@ -9,280 +9,340 @@ import org.omg.CosNaming.*;
*
* It has no GUI, just a text frontend to keep it simple.
*
* $Id: StockClient.java,v 1.1 1999/01/25 21:22:03 scrappy Exp $
* $Id: StockClient.java,v 1.2 2001/10/25 05:59:58 momjian Exp $
*/
public class StockClient
{
org.omg.CosNaming.NamingContext nameService;
stock.StockDispenser dispenser;
stock.StockItem item;
BufferedReader in;
public StockClient(String[] args) {
try {
// We need this for our IO
in = new BufferedReader(new InputStreamReader(System.in));
// Initialize the orb
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
// Get a reference to the Naming Service
org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
if(nameServiceObj==null) {
System.err.println("nameServiceObj == null");
return;
}
nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if(nameService==null) {
System.err.println("nameService == null");
return;
}
// Resolve the dispenser
NameComponent[] dispName = {
new NameComponent("StockDispenser","Stock")
};
dispenser = stock.StockDispenserHelper.narrow(nameService.resolve(dispName));
if(dispenser==null) {
System.err.println("dispenser == null");
return;
}
// Now run the front end.
run();
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
new StockClient(args);
}
public void run() {
// First reserve a StockItem
try {
item = dispenser.reserveItem();
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
System.exit(1);
}
mainMenu();
// finally free the StockItem
try {
dispenser.releaseItem(item);
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
System.exit(1);
}
}
private void mainMenu() {
boolean run=true;
while(run) {
System.out.println("\nCORBA Stock System\n");
System.out.println(" 1 Display stock item");
System.out.println(" 2 Remove item from stock");
System.out.println(" 3 Put item into stock");
System.out.println(" 4 Order item");
System.out.println(" 5 Display all items");
System.out.println(" 0 Exit");
int i = getMenu("Main",5);
switch(i)
org.omg.CosNaming.NamingContext nameService;
stock.StockDispenser dispenser;
stock.StockItem item;
BufferedReader in;
public StockClient(String[] args)
{
try
{
case 0:
run=false;
break;
case 1:
displayItem();
break;
case 2:
bookOut();
break;
case 3:
bookIn();
break;
case 4:
order(0);
break;
case 5:
displayAll();
break;
}
}
}
private void displayItem() {
try {
int id = getMenu("\nStockID to display",item.getLastID());
if(id>0) {
item.fetchItem(id);
System.out.println("========================================");
String status = "";
if(!item.isItemValid())
status=" ** Superceded **";
int av = item.getAvailable();
System.out.println(" Stock ID: "+id+status+
"\nItems Available: "+av+
"\nItems on order: "+item.getOrdered()+
"\n Description: "+item.getDescription());
System.out.println("========================================");
if(av>0)
if(yn("Take this item out of stock?")) {
int rem=1;
if(av>1)
rem=getMenu("How many?",av);
if(rem>0)
item.removeStock(rem);
}
}
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
private void bookOut() {
try {
int id = getMenu("\nStockID to take out",item.getLastID());
if(id>0) {
item.fetchItem(id);
int av = item.getAvailable();
if(av>0)
if(yn("Take this item out of stock?")) {
int rem=1;
if(av>1)
rem=getMenu("How many?",av);
if(rem>0)
item.removeStock(rem);
}
else {
System.out.println("This item is not in stock.");
int order = item.getOrdered();
if(order>0)
System.out.println("There are "+item.getOrdered()+" items on order.");
else {
if(item.isItemValid()) {
System.out.println("You will need to order some more "+item.getDescription());
order(id);
} else
System.out.println("This item is now obsolete");
// We need this for our IO
in = new BufferedReader(new InputStreamReader(System.in));
// Initialize the orb
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
// Get a reference to the Naming Service
org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
if (nameServiceObj == null)
{
System.err.println("nameServiceObj == null");
return ;
}
}
} else
System.out.println(item.getDescription()+"\nThis item is out of stock");
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
// book an item into stock
private void bookIn() {
try {
int id = getMenu("\nStockID to book in",item.getLastID());
item.fetchItem(id);
System.out.println(item.getDescription());
if(item.getOrdered()>0) {
int am = getMenu("How many do you want to book in",item.getOrdered());
if(am>0)
item.addNewStock(am);
} else
System.out.println("You don't have any of this item on ordered");
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
// Order an item
private void order(int id) {
try {
if(id==0)
id = getMenu("\nStockID to order",item.getLastID());
item.fetchItem(id);
System.out.println(item.getDescription());
int am = getMenu("How many do you want to order",999);
if(am>0)
item.orderStock(am);
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
private void displayAll() {
try {
boolean cont=true;
int nr=item.getLastID();
String header = "\nId\tAvail\tOrdered\tDescription";
System.out.println(header);
for(int i=1;i<=nr && cont;i++) {
item.fetchItem(i);
System.out.println(""+i+"\t"+item.getAvailable()+"\t"+item.getOrdered()+"\t"+item.getDescription());
if((i%20)==0) {
if((cont=yn("Continue?")))
System.out.println(header);
nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if (nameService == null)
{
System.err.println("nameService == null");
return ;
}
// Resolve the dispenser
NameComponent[] dispName = {
new NameComponent("StockDispenser", "Stock")
};
dispenser = stock.StockDispenserHelper.narrow(nameService.resolve(dispName));
if (dispenser == null)
{
System.err.println("dispenser == null");
return ;
}
// Now run the front end.
run();
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
System.exit(1);
}
}
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
private int getMenu(String title,int max) {
int v=-1;
while(v<0 || v>max) {
System.out.print(title);
System.out.print(" [0-"+max+"]: ");
System.out.flush();
try {
v = Integer.parseInt(in.readLine());
} catch(Exception nfe) {
v=-1;
}
public static void main(String[] args)
{
new StockClient(args);
}
return v;
}
private boolean yn(String title) {
try {
while(true) {
System.out.print(title);
System.out.flush();
String s = in.readLine();
if(s.startsWith("y") || s.startsWith("Y"))
return true;
if(s.startsWith("n") || s.startsWith("N"))
return false;
}
} catch(Exception nfe) {
System.out.println(nfe.toString());
nfe.printStackTrace();
System.exit(1);
public void run()
{
// First reserve a StockItem
try
{
item = dispenser.reserveItem();
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
System.exit(1);
}
mainMenu();
// finally free the StockItem
try
{
dispenser.releaseItem(item);
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
System.exit(1);
}
}
private void mainMenu()
{
boolean run = true;
while (run)
{
System.out.println("\nCORBA Stock System\n");
System.out.println(" 1 Display stock item");
System.out.println(" 2 Remove item from stock");
System.out.println(" 3 Put item into stock");
System.out.println(" 4 Order item");
System.out.println(" 5 Display all items");
System.out.println(" 0 Exit");
int i = getMenu("Main", 5);
switch (i)
{
case 0:
run = false;
break;
case 1:
displayItem();
break;
case 2:
bookOut();
break;
case 3:
bookIn();
break;
case 4:
order(0);
break;
case 5:
displayAll();
break;
}
}
}
private void displayItem()
{
try
{
int id = getMenu("\nStockID to display", item.getLastID());
if (id > 0)
{
item.fetchItem(id);
System.out.println("========================================");
String status = "";
if (!item.isItemValid())
status = " ** Superceded **";
int av = item.getAvailable();
System.out.println(" Stock ID: " + id + status +
"\nItems Available: " + av +
"\nItems on order: " + item.getOrdered() +
"\n Description: " + item.getDescription());
System.out.println("========================================");
if (av > 0)
if (yn("Take this item out of stock?"))
{
int rem = 1;
if (av > 1)
rem = getMenu("How many?", av);
if (rem > 0)
item.removeStock(rem);
}
}
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
}
private void bookOut()
{
try
{
int id = getMenu("\nStockID to take out", item.getLastID());
if (id > 0)
{
item.fetchItem(id);
int av = item.getAvailable();
if (av > 0)
if (yn("Take this item out of stock?"))
{
int rem = 1;
if (av > 1)
rem = getMenu("How many?", av);
if (rem > 0)
item.removeStock(rem);
}
else
{
System.out.println("This item is not in stock.");
int order = item.getOrdered();
if (order > 0)
System.out.println("There are " + item.getOrdered() + " items on order.");
else
{
if (item.isItemValid())
{
System.out.println("You will need to order some more " + item.getDescription());
order(id);
}
else
System.out.println("This item is now obsolete");
}
}
}
else
System.out.println(item.getDescription() + "\nThis item is out of stock");
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
}
// book an item into stock
private void bookIn()
{
try
{
int id = getMenu("\nStockID to book in", item.getLastID());
item.fetchItem(id);
System.out.println(item.getDescription());
if (item.getOrdered() > 0)
{
int am = getMenu("How many do you want to book in", item.getOrdered());
if (am > 0)
item.addNewStock(am);
}
else
System.out.println("You don't have any of this item on ordered");
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
}
// Order an item
private void order(int id)
{
try
{
if (id == 0)
id = getMenu("\nStockID to order", item.getLastID());
item.fetchItem(id);
System.out.println(item.getDescription());
int am = getMenu("How many do you want to order", 999);
if (am > 0)
item.orderStock(am);
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
}
private void displayAll()
{
try
{
boolean cont = true;
int nr = item.getLastID();
String header = "\nId\tAvail\tOrdered\tDescription";
System.out.println(header);
for (int i = 1;i <= nr && cont;i++)
{
item.fetchItem(i);
System.out.println("" + i + "\t" + item.getAvailable() + "\t" + item.getOrdered() + "\t" + item.getDescription());
if ((i % 20) == 0)
{
if ((cont = yn("Continue?")))
System.out.println(header);
}
}
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
}
private int getMenu(String title, int max)
{
int v = -1;
while (v < 0 || v > max)
{
System.out.print(title);
System.out.print(" [0-" + max + "]: ");
System.out.flush();
try
{
v = Integer.parseInt(in.readLine());
}
catch (Exception nfe)
{
v = -1;
}
}
return v;
}
private boolean yn(String title)
{
try
{
while (true)
{
System.out.print(title);
System.out.flush();
String s = in.readLine();
if (s.startsWith("y") || s.startsWith("Y"))
return true;
if (s.startsWith("n") || s.startsWith("N"))
return false;
}
}
catch (Exception nfe)
{
System.out.println(nfe.toString());
nfe.printStackTrace();
System.exit(1);
}
return false;
}
return false;
}
}

View File

@ -13,105 +13,122 @@ import java.sql.*;
* that an object could be changed by another client, and we need to ensure that
* the returned data is live and accurate.
*
* $Id: StockDB.java,v 1.2 2000/04/26 05:32:01 peter Exp $
* $Id: StockDB.java,v 1.3 2001/10/25 05:59:58 momjian Exp $
*/
public class StockDB
{
Connection con;
Statement st;
// the current stock number
int id = -1;
public void connect(String url,String usr,String pwd) throws Exception {
Class.forName("org.postgresql.Driver");
System.out.println("Connecting to "+url);
con = DriverManager.getConnection(url,usr,pwd);
st = con.createStatement();
}
public void closeConnection() throws Exception {
con.close();
}
public void fetchItem(int id) throws Exception {
this.id = id;
}
public int newItem() throws Exception {
// tba
return -1;
}
public String getDescription() throws SQLException {
ResultSet rs = st.executeQuery("select description from stock where id="+id);
if(rs!=null) {
rs.next();
String s = rs.getString(1);
rs.close();
return s;
Connection con;
Statement st;
// the current stock number
int id = -1;
public void connect(String url, String usr, String pwd) throws Exception
{
Class.forName("org.postgresql.Driver");
System.out.println("Connecting to " + url);
con = DriverManager.getConnection(url, usr, pwd);
st = con.createStatement();
}
throw new SQLException("No ResultSet");
}
public int getAvailable() throws SQLException {
ResultSet rs = st.executeQuery("select avail from stock where id="+id);
if(rs!=null) {
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
public void closeConnection() throws Exception
{
con.close();
}
throw new SQLException("No ResultSet");
}
public int getOrdered() throws SQLException {
ResultSet rs = st.executeQuery("select ordered from stock where id="+id);
if(rs!=null) {
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
public void fetchItem(int id) throws Exception
{
this.id = id;
}
throw new SQLException("No ResultSet");
}
public boolean isItemValid() throws SQLException {
ResultSet rs = st.executeQuery("select valid from stock where id="+id);
if(rs!=null) {
rs.next();
boolean b = rs.getBoolean(1);
rs.close();
return b;
public int newItem() throws Exception
{
// tba
return -1;
}
throw new SQLException("No ResultSet");
}
public void addNewStock(int amount) throws SQLException {
st.executeUpdate("update stock set avail=avail+"+amount+
", ordered=ordered-"+amount+
" where id="+id+" and ordered>="+amount);
}
public void removeStock(int amount) throws SQLException {
st.executeUpdate("update stock set avail=avail-"+amount+
" where id="+id);
}
public void orderStock(int amount) throws SQLException {
st.executeUpdate("update stock set ordered=ordered+"+amount+
" where id="+id);
}
public int getLastID() throws SQLException {
ResultSet rs = st.executeQuery("select max(id) from stock");
if(rs!=null) {
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
public String getDescription() throws SQLException
{
ResultSet rs = st.executeQuery("select description from stock where id=" + id);
if (rs != null)
{
rs.next();
String s = rs.getString(1);
rs.close();
return s;
}
throw new SQLException("No ResultSet");
}
throw new SQLException("No ResultSet");
}
public int getAvailable() throws SQLException
{
ResultSet rs = st.executeQuery("select avail from stock where id=" + id);
if (rs != null)
{
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
}
throw new SQLException("No ResultSet");
}
public int getOrdered() throws SQLException
{
ResultSet rs = st.executeQuery("select ordered from stock where id=" + id);
if (rs != null)
{
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
}
throw new SQLException("No ResultSet");
}
public boolean isItemValid() throws SQLException
{
ResultSet rs = st.executeQuery("select valid from stock where id=" + id);
if (rs != null)
{
rs.next();
boolean b = rs.getBoolean(1);
rs.close();
return b;
}
throw new SQLException("No ResultSet");
}
public void addNewStock(int amount) throws SQLException
{
st.executeUpdate("update stock set avail=avail+" + amount +
", ordered=ordered-" + amount +
" where id=" + id + " and ordered>=" + amount);
}
public void removeStock(int amount) throws SQLException
{
st.executeUpdate("update stock set avail=avail-" + amount +
" where id=" + id);
}
public void orderStock(int amount) throws SQLException
{
st.executeUpdate("update stock set ordered=ordered+" + amount +
" where id=" + id);
}
public int getLastID() throws SQLException
{
ResultSet rs = st.executeQuery("select max(id) from stock");
if (rs != null)
{
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
}
throw new SQLException("No ResultSet");
}
}

View File

@ -5,79 +5,88 @@ import org.omg.CosNaming.*;
/**
* This class implements the server side of the example.
*
* $Id: StockDispenserImpl.java,v 1.1 1999/01/25 21:22:03 scrappy Exp $
* $Id: StockDispenserImpl.java,v 1.2 2001/10/25 05:59:58 momjian Exp $
*/
public class StockDispenserImpl extends stock._StockDispenserImplBase
{
private int maxObjects = 10;
private int numObjects = 0;
private StockItemStatus[] stock = new StockItemStatus[maxObjects];
public StockDispenserImpl(String[] args,String name,int num)
{
super();
try {
// get reference to orb
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
// prestart num objects
if(num>=maxObjects)
num=maxObjects;
numObjects = num;
for(int i=0;i<numObjects;i++) {
stock[i] = new StockItemStatus();
stock[i].ref = new StockItemImpl(args,"StockItem"+(i+1));
orb.connect(stock[i].ref);
}
} catch(org.omg.CORBA.SystemException e) {
e.printStackTrace();
private int maxObjects = 10;
private int numObjects = 0;
private StockItemStatus[] stock = new StockItemStatus[maxObjects];
public StockDispenserImpl(String[] args, String name, int num)
{
super();
try
{
// get reference to orb
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
// prestart num objects
if (num >= maxObjects)
num = maxObjects;
numObjects = num;
for (int i = 0;i < numObjects;i++)
{
stock[i] = new StockItemStatus();
stock[i].ref = new StockItemImpl(args, "StockItem" + (i + 1));
orb.connect(stock[i].ref);
}
}
catch (org.omg.CORBA.SystemException e)
{
e.printStackTrace();
}
}
}
/**
* This method, defined in stock.idl, reserves a slot in the dispenser
*/
public stock.StockItem reserveItem() throws stock.StockException
{
for(int i=0;i<numObjects;i++) {
if(!stock[i].inUse) {
stock[i].inUse = true;
System.out.println("Reserving slot "+i);
return stock[i].ref;
}
/**
* This method, defined in stock.idl, reserves a slot in the dispenser
*/
public stock.StockItem reserveItem() throws stock.StockException
{
for (int i = 0;i < numObjects;i++)
{
if (!stock[i].inUse)
{
stock[i].inUse = true;
System.out.println("Reserving slot " + i);
return stock[i].ref;
}
}
return null;
}
return null;
}
/**
* This releases a slot from the dispenser
*/
public void releaseItem(stock.StockItem item) throws stock.StockException
{
for(int i=0;i<numObjects;i++) {
if(stock[i].ref.getInstanceName().equals(item.getInstanceName())) {
stock[i].inUse = false;
System.out.println("Releasing slot "+i);
return;
}
/**
* This releases a slot from the dispenser
*/
public void releaseItem(stock.StockItem item) throws stock.StockException
{
for (int i = 0;i < numObjects;i++)
{
if (stock[i].ref.getInstanceName().equals(item.getInstanceName()))
{
stock[i].inUse = false;
System.out.println("Releasing slot " + i);
return ;
}
}
System.out.println("Reserved object not a member of this dispenser");
return ;
}
System.out.println("Reserved object not a member of this dispenser");
return;
}
/**
* This class defines a slot in the dispenser
*/
class StockItemStatus
{
StockItemImpl ref;
boolean inUse;
StockItemStatus() {
ref = null;
inUse = false;
/**
* This class defines a slot in the dispenser
*/
class StockItemStatus
{
StockItemImpl ref;
boolean inUse;
StockItemStatus()
{
ref = null;
inUse = false;
}
}
}
}

View File

@ -5,159 +5,204 @@ import org.omg.CosNaming.*;
/**
* This class implements the server side of the example.
*
* $Id: StockItemImpl.java,v 1.1 1999/01/25 21:22:04 scrappy Exp $
* $Id: StockItemImpl.java,v 1.2 2001/10/25 05:59:58 momjian Exp $
*/
public class StockItemImpl extends stock._StockItemImplBase
{
private StockDB db;
private String instanceName;
public StockItemImpl(String[] args,String iname) {
super();
try {
db =new StockDB();
db.connect(args[1],args[2],args[3]);
System.out.println("StockDB object "+iname+" created");
instanceName = iname;
} catch(Exception e) {
e.printStackTrace();
}
}
/**
* This is defined in stock.idl
*
* It sets the item to view
*/
public void fetchItem(int id) throws stock.StockException {
try {
db.fetchItem(id);
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It sets the item to view
*/
public int newItem() throws stock.StockException {
try {
return db.newItem();
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public String getDescription() throws stock.StockException {
try {
return db.getDescription();
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public int getAvailable() throws stock.StockException {
try {
return db.getAvailable();
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public int getOrdered() throws stock.StockException {
try {
return db.getOrdered();
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public boolean isItemValid() throws stock.StockException {
try {
return db.isItemValid();
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public void addNewStock(int id) throws stock.StockException {
try {
db.addNewStock(id);
} catch(Exception e) {
throw new stock.StockException(e.toString());
}
}
private StockDB db;
private String instanceName;
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public void removeStock(int id) throws stock.StockException {
try {
db.removeStock(id);
} catch(Exception e) {
throw new stock.StockException(e.toString());
public StockItemImpl(String[] args, String iname)
{
super();
try
{
db = new StockDB();
db.connect(args[1], args[2], args[3]);
System.out.println("StockDB object " + iname + " created");
instanceName = iname;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public void orderStock(int id) throws stock.StockException {
try {
db.orderStock(id);
} catch(Exception e) {
throw new stock.StockException(e.toString());
/**
* This is defined in stock.idl
*
* It sets the item to view
*/
public void fetchItem(int id) throws stock.StockException
{
try
{
db.fetchItem(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
}
/**
* This returns the highest id used, hence the number of items available
*/
public int getLastID() throws stock.StockException {
try {
return db.getLastID();
} catch(Exception e) {
throw new stock.StockException(e.toString());
/**
* This is defined in stock.idl
*
* It sets the item to view
*/
public int newItem() throws stock.StockException
{
try
{
return db.newItem();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public String getDescription() throws stock.StockException
{
try
{
return db.getDescription();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public int getAvailable() throws stock.StockException
{
try
{
return db.getAvailable();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public int getOrdered() throws stock.StockException
{
try
{
return db.getOrdered();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public boolean isItemValid() throws stock.StockException
{
try
{
return db.isItemValid();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public void addNewStock(int id) throws stock.StockException
{
try
{
db.addNewStock(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public void removeStock(int id) throws stock.StockException
{
try
{
db.removeStock(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is defined in stock.idl
*
* It returns the description of a Stock item
*/
public void orderStock(int id) throws stock.StockException
{
try
{
db.orderStock(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This returns the highest id used, hence the number of items available
*/
public int getLastID() throws stock.StockException
{
try
{
return db.getLastID();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
}
/**
* This is used by our Dispenser
*/
public String getInstanceName()
{
return instanceName;
}
}
/**
* This is used by our Dispenser
*/
public String getInstanceName() {
return instanceName;
}
}

View File

@ -5,49 +5,54 @@ import org.omg.CosNaming.*;
/**
* This class implements the server side of the example.
*
* $Id: StockServer.java,v 1.1 1999/01/25 21:22:04 scrappy Exp $
* $Id: StockServer.java,v 1.2 2001/10/25 05:59:58 momjian Exp $
*/
public class StockServer
{
public static void main(String[] args)
{
int numInstances = 3;
try {
// Initialise the ORB
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
// Create the StockDispenser object
StockDispenserImpl dispenser = new StockDispenserImpl(args,"Stock Dispenser",numInstances);
// Export the new object
orb.connect(dispenser);
// Get the naming service
org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
if(nameServiceObj == null) {
System.err.println("nameServiceObj = null");
return;
}
org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if(nameService == null) {
System.err.println("nameService = null");
return;
}
// bind the dispenser into the naming service
NameComponent[] dispenserName = {
new NameComponent("StockDispenser","Stock")
};
nameService.rebind(dispenserName,dispenser);
// Now wait forever for the current thread to die
Thread.currentThread().join();
} catch(Exception e) {
e.printStackTrace();
public static void main(String[] args)
{
int numInstances = 3;
try
{
// Initialise the ORB
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
// Create the StockDispenser object
StockDispenserImpl dispenser = new StockDispenserImpl(args, "Stock Dispenser", numInstances);
// Export the new object
orb.connect(dispenser);
// Get the naming service
org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
if (nameServiceObj == null)
{
System.err.println("nameServiceObj = null");
return ;
}
org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if (nameService == null)
{
System.err.println("nameService = null");
return ;
}
// bind the dispenser into the naming service
NameComponent[] dispenserName = {
new NameComponent("StockDispenser", "Stock")
};
nameService.rebind(dispenserName, dispenser);
// Now wait forever for the current thread to die
Thread.currentThread().join();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

View File

@ -14,168 +14,176 @@ import java.text.*;
public class datestyle
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
// This is our standard to compare results with.
java.sql.Date standard;
// This is a list of the available date styles including variants.
// These have to match what the "set datestyle" statement accepts.
String styles[] = {
"postgres,european",
"postgres,us",
"iso", // iso has no variants - us/european has no affect
"sql,european",
"sql,us",
"german" // german has no variants - us/european has no affect
};
public datestyle(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise
cleanup();
init();
// Now run tests using JDBC methods
doexample();
// Clean up the database
cleanup();
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
}
/**
* This drops the table (if it existed). No errors are reported.
*/
public void cleanup()
{
try {
st.executeUpdate("drop table datestyle");
} catch(Exception ex) {
// We ignore any errors here
}
}
/**
* This initialises the database for this example
*/
public void init() throws SQLException
{
// Create a table holding a single date
st.executeUpdate("create table datestyle (dt date)");
// Now create our standard date for the test.
//
// NB: each component of the date should be different, otherwise the tests
// will not be valid.
//
// NB: January = 0 here
//
standard = new java.sql.Date(98,0,8);
// Now store the result.
//
// This is an example of how to set a date in a date style independent way.
// The only way of doing this is by using a PreparedStatement.
//
PreparedStatement ps = db.prepareStatement("insert into datestyle values (?)");
ps.setDate(1,standard);
ps.executeUpdate();
ps.close();
}
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nRunning tests:");
for(int i=0;i<styles.length;i++) {
System.out.print("Test "+i+" - "+styles[i]);
System.out.flush();
// set the style
st.executeUpdate("set datestyle='"+styles[i]+"'");
// Now because the driver needs to know what the current style is,
// we have to run the following:
st.executeUpdate("show datestyle");
// This is a limitation, but there is no real way around this.
// Now we query the table.
ResultSet rs = st.executeQuery("select dt from datestyle");
// Throw an exception if there is no result (if the table is empty
// there should still be a result).
if(rs==null)
throw new SQLException("The test query returned no data");
while(rs.next()) {
// The JDBC spec states we should only read each column once.
// In the current implementation of the driver, this is not necessary.
// Here we use this fact to see what the query really returned.
if(standard.equals(rs.getDate(1)))
System.out.println(" passed, returned "+rs.getString(1));
else
System.out.println(" failed, returned "+rs.getString(1));
}
rs.close();
}
}
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis example tests the drivers ability to handle dates correctly if the\nbackend is running any of the various date styles that it supports.\nIdealy this should work fine. If it doesn't, then there is something wrong\npossibly in postgresql.Connection or in the backend itself. If this does occur\nthen please email a bug report.\n");
System.out.println("Useage:\n java example.datestyle jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL datestyle test v6.3 rev 1\n");
if(args.length<3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
// Now run the tests
try {
datestyle test = new datestyle(args);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
// This is our standard to compare results with.
java.sql.Date standard;
// This is a list of the available date styles including variants.
// These have to match what the "set datestyle" statement accepts.
String styles[] = {
"postgres,european",
"postgres,us",
"iso", // iso has no variants - us/european has no affect
"sql,european",
"sql,us",
"german" // german has no variants - us/european has no affect
};
public datestyle(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise
cleanup();
init();
// Now run tests using JDBC methods
doexample();
// Clean up the database
cleanup();
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
}
/**
* This drops the table (if it existed). No errors are reported.
*/
public void cleanup()
{
try
{
st.executeUpdate("drop table datestyle");
}
catch (Exception ex)
{
// We ignore any errors here
}
}
/**
* This initialises the database for this example
*/
public void init() throws SQLException
{
// Create a table holding a single date
st.executeUpdate("create table datestyle (dt date)");
// Now create our standard date for the test.
//
// NB: each component of the date should be different, otherwise the tests
// will not be valid.
//
// NB: January = 0 here
//
standard = new java.sql.Date(98, 0, 8);
// Now store the result.
//
// This is an example of how to set a date in a date style independent way.
// The only way of doing this is by using a PreparedStatement.
//
PreparedStatement ps = db.prepareStatement("insert into datestyle values (?)");
ps.setDate(1, standard);
ps.executeUpdate();
ps.close();
}
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nRunning tests:");
for (int i = 0;i < styles.length;i++)
{
System.out.print("Test " + i + " - " + styles[i]);
System.out.flush();
// set the style
st.executeUpdate("set datestyle='" + styles[i] + "'");
// Now because the driver needs to know what the current style is,
// we have to run the following:
st.executeUpdate("show datestyle");
// This is a limitation, but there is no real way around this.
// Now we query the table.
ResultSet rs = st.executeQuery("select dt from datestyle");
// Throw an exception if there is no result (if the table is empty
// there should still be a result).
if (rs == null)
throw new SQLException("The test query returned no data");
while (rs.next())
{
// The JDBC spec states we should only read each column once.
// In the current implementation of the driver, this is not necessary.
// Here we use this fact to see what the query really returned.
if (standard.equals(rs.getDate(1)))
System.out.println(" passed, returned " + rs.getString(1));
else
System.out.println(" failed, returned " + rs.getString(1));
}
rs.close();
}
}
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis example tests the drivers ability to handle dates correctly if the\nbackend is running any of the various date styles that it supports.\nIdealy this should work fine. If it doesn't, then there is something wrong\npossibly in postgresql.Connection or in the backend itself. If this does occur\nthen please email a bug report.\n");
System.out.println("Useage:\n java example.datestyle jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL datestyle test v6.3 rev 1\n");
if (args.length < 3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// Now run the tests
try
{
datestyle test = new datestyle(args);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
}

View File

@ -15,260 +15,284 @@ import java.text.*;
public class metadata
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
DatabaseMetaData dbmd; // This defines the structure of the database
/**
* These are the available tests on DatabaseMetaData
*/
public void doDatabaseMetaData() throws SQLException {
if(doTest("getProcedures() - should show all available procedures"))
displayResult(dbmd.getProcedures(null,null,null));
if(doTest("getProcedures() with pattern - should show all circle procedures"))
displayResult(dbmd.getProcedures(null,null,"circle%"));
if(doTest("getProcedureColumns() on circle procedures"))
displayResult(dbmd.getProcedureColumns(null,null,"circle%",null));
if(doTest("getTables()"))
displayResult(dbmd.getTables(null,null,null,null));
if(doTest("getColumns() - should show all tables, can take a while to run"))
displayResult(dbmd.getColumns(null,null,null,null));
if(doTest("getColumns() - should show the test_b table"))
displayResult(dbmd.getColumns(null,null,"test_b",null));
if(doTest("getColumnPrivileges() - should show all tables"))
displayResult(dbmd.getColumnPrivileges(null,null,null,null));
if(doTest("getPrimaryKeys()"))
displayResult(dbmd.getPrimaryKeys(null,null,null));
if(doTest("getTypeInfo()"))
displayResult(dbmd.getTypeInfo());
}
/**
* These are the available tests on ResultSetMetaData
*/
public void doResultSetMetaData() throws SQLException {
String sql = "select imagename,descr,source,cost from test_a,test_b,test_c where test_a.id=test_b.imageid and test_a.id=test_c.imageid";
System.out.println("Executing query for tests");
ResultSet rs = st.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
if(doTest("isCurrency()"))
System.out.println("isCurrency on col 1 = "+rsmd.isCurrency(1)+" should be false\nisCurrency on col 4 = "+rsmd.isCurrency(4)+" should be true");
// Finally close the query. Now give the user a chance to display the
// ResultSet.
//
// NB: displayResult() actually closes the ResultSet.
if(doTest("Display query result")) {
System.out.println("Query: "+sql);
displayResult(rs);
} else
rs.close();
}
/**
* This creates some test data
*/
public void init() throws SQLException {
System.out.println("Creating some tables");
cleanup();
st.executeUpdate("create table test_a (imagename name,image oid,id int4)");
st.executeUpdate("create table test_b (descr text,imageid int4,id int4)");
st.executeUpdate("create table test_c (source text,cost money,imageid int4)");
System.out.println("Adding some data");
st.executeUpdate("insert into test_a values ('test1',0,1)");
st.executeUpdate("insert into test_b values ('A test description',1,2)");
st.executeUpdate("insert into test_c values ('nowhere particular','$10.99',1)");
}
/**
* This removes the test data
*/
public void cleanup() throws SQLException {
try {
st.executeUpdate("drop table test_a");
st.executeUpdate("drop table test_b");
st.executeUpdate("drop table test_c");
} catch(Exception ex) {
// We ignore any errors here
}
}
public metadata(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
dbmd = db.getMetaData();
st = db.createStatement();
// This prints the backend's version
System.out.println("Connected to "+dbmd.getDatabaseProductName()+" "+dbmd.getDatabaseProductVersion());
init();
System.out.println();
// Now the tests
if(doTest("Test DatabaseMetaData"))
doDatabaseMetaData();
if(doTest("Test ResultSetMetaData"))
doResultSetMetaData();
System.out.println("\nNow closing the connection");
st.close();
db.close();
cleanup();
}
/**
* This asks if the user requires to run a test.
*/
public boolean doTest(String s) {
System.out.println();
System.out.print(s);
System.out.print(" Perform test? Y or N:");
System.out.flush();
char c = ' ';
try {
while(!(c=='n' || c=='y' || c=='N' || c=='Y')) {
c=(char)System.in.read();
}
} catch(IOException ioe) {
return false;
}
return c=='y' || c=='Y';
}
/**
* This displays a result set.
* Note: it closes the result once complete.
*/
public void displayResult(ResultSet rs) throws SQLException
{
ResultSetMetaData rsmd = rs.getMetaData();
int count=0;
// Print the result column names
int cols = rsmd.getColumnCount();
for(int i=1;i<=cols;i++)
System.out.print(rsmd.getColumnLabel(i)+(i<cols?"\t":"\n"));
// now the results
while(rs.next()) {
count++;
for(int i=1;i<=cols;i++) {
Object o = rs.getObject(i);
if(rs.wasNull())
System.out.print("{null}"+(i<cols?"\t":"\n"));
else
System.out.print(o.toString()+(i<cols?"\t":"\n"));
}
}
System.out.println("Result returned "+count+" rows.");
// finally close the result set
rs.close();
}
/**
* This process / commands (for now just /d)
*/
public void processSlashCommand(String line) throws SQLException
{
if(line.startsWith("\\d")) {
if(line.startsWith("\\d ")) {
// Display details about a table
String table=line.substring(3);
displayResult(dbmd.getColumns(null,null,table,"%"));
} else {
String types[] = null;
if(line.equals("\\d"))
types=allUserTables;
else if(line.equals("\\di"))
types=usrIndices;
else if(line.equals("\\dt"))
types=usrTables;
else if(line.equals("\\ds"))
types=usrSequences;
else if(line.equals("\\dS"))
types=sysTables;
else
throw new SQLException("Unsupported \\d command: "+line);
// Display details about all system tables
//
// Note: the first two arguments are ignored. To keep to the spec,
// you must put null here
//
displayResult(dbmd.getTables(null,null,"%",types));
}
} else
throw new SQLException("Unsupported \\ command: "+line);
}
private static final String allUserTables[] = {"TABLE","INDEX","SEQUENCE"};
private static final String usrIndices[] = {"INDEX"};
private static final String usrTables[] = {"TABLE"};
private static final String usrSequences[] = {"SEQUENCE"};
private static final String sysTables[] = {"SYSTEM TABLE","SYSTEM INDEX"};
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis is not really an example, but is used to test the various methods in\nthe DatabaseMetaData and ResultSetMetaData classes.\n");
System.out.println("Useage:\n java example.metadata jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of debug items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL metdata tester v6.4 rev 1\n");
if(args.length<3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
// Now run the tests
try {
metadata test = new metadata(args);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
DatabaseMetaData dbmd; // This defines the structure of the database
/**
* These are the available tests on DatabaseMetaData
*/
public void doDatabaseMetaData() throws SQLException
{
if (doTest("getProcedures() - should show all available procedures"))
displayResult(dbmd.getProcedures(null, null, null));
if (doTest("getProcedures() with pattern - should show all circle procedures"))
displayResult(dbmd.getProcedures(null, null, "circle%"));
if (doTest("getProcedureColumns() on circle procedures"))
displayResult(dbmd.getProcedureColumns(null, null, "circle%", null));
if (doTest("getTables()"))
displayResult(dbmd.getTables(null, null, null, null));
if (doTest("getColumns() - should show all tables, can take a while to run"))
displayResult(dbmd.getColumns(null, null, null, null));
if (doTest("getColumns() - should show the test_b table"))
displayResult(dbmd.getColumns(null, null, "test_b", null));
if (doTest("getColumnPrivileges() - should show all tables"))
displayResult(dbmd.getColumnPrivileges(null, null, null, null));
if (doTest("getPrimaryKeys()"))
displayResult(dbmd.getPrimaryKeys(null, null, null));
if (doTest("getTypeInfo()"))
displayResult(dbmd.getTypeInfo());
}
/**
* These are the available tests on ResultSetMetaData
*/
public void doResultSetMetaData() throws SQLException
{
String sql = "select imagename,descr,source,cost from test_a,test_b,test_c where test_a.id=test_b.imageid and test_a.id=test_c.imageid";
System.out.println("Executing query for tests");
ResultSet rs = st.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
if (doTest("isCurrency()"))
System.out.println("isCurrency on col 1 = " + rsmd.isCurrency(1) + " should be false\nisCurrency on col 4 = " + rsmd.isCurrency(4) + " should be true");
// Finally close the query. Now give the user a chance to display the
// ResultSet.
//
// NB: displayResult() actually closes the ResultSet.
if (doTest("Display query result"))
{
System.out.println("Query: " + sql);
displayResult(rs);
}
else
rs.close();
}
/**
* This creates some test data
*/
public void init() throws SQLException
{
System.out.println("Creating some tables");
cleanup();
st.executeUpdate("create table test_a (imagename name,image oid,id int4)");
st.executeUpdate("create table test_b (descr text,imageid int4,id int4)");
st.executeUpdate("create table test_c (source text,cost money,imageid int4)");
System.out.println("Adding some data");
st.executeUpdate("insert into test_a values ('test1',0,1)");
st.executeUpdate("insert into test_b values ('A test description',1,2)");
st.executeUpdate("insert into test_c values ('nowhere particular','$10.99',1)");
}
/**
* This removes the test data
*/
public void cleanup() throws SQLException
{
try
{
st.executeUpdate("drop table test_a");
st.executeUpdate("drop table test_b");
st.executeUpdate("drop table test_c");
}
catch (Exception ex)
{
// We ignore any errors here
}
}
public metadata(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
dbmd = db.getMetaData();
st = db.createStatement();
// This prints the backend's version
System.out.println("Connected to " + dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
init();
System.out.println();
// Now the tests
if (doTest("Test DatabaseMetaData"))
doDatabaseMetaData();
if (doTest("Test ResultSetMetaData"))
doResultSetMetaData();
System.out.println("\nNow closing the connection");
st.close();
db.close();
cleanup();
}
/**
* This asks if the user requires to run a test.
*/
public boolean doTest(String s)
{
System.out.println();
System.out.print(s);
System.out.print(" Perform test? Y or N:");
System.out.flush();
char c = ' ';
try
{
while (!(c == 'n' || c == 'y' || c == 'N' || c == 'Y'))
{
c = (char)System.in.read();
}
}
catch (IOException ioe)
{
return false;
}
return c == 'y' || c == 'Y';
}
/**
* This displays a result set.
* Note: it closes the result once complete.
*/
public void displayResult(ResultSet rs) throws SQLException
{
ResultSetMetaData rsmd = rs.getMetaData();
int count = 0;
// Print the result column names
int cols = rsmd.getColumnCount();
for (int i = 1;i <= cols;i++)
System.out.print(rsmd.getColumnLabel(i) + (i < cols ? "\t" : "\n"));
// now the results
while (rs.next())
{
count++;
for (int i = 1;i <= cols;i++)
{
Object o = rs.getObject(i);
if (rs.wasNull())
System.out.print("{null}" + (i < cols ? "\t" : "\n"));
else
System.out.print(o.toString() + (i < cols ? "\t" : "\n"));
}
}
System.out.println("Result returned " + count + " rows.");
// finally close the result set
rs.close();
}
/**
* This process / commands (for now just /d)
*/
public void processSlashCommand(String line) throws SQLException
{
if (line.startsWith("\\d"))
{
if (line.startsWith("\\d "))
{
// Display details about a table
String table = line.substring(3);
displayResult(dbmd.getColumns(null, null, table, "%"));
}
else
{
String types[] = null;
if (line.equals("\\d"))
types = allUserTables;
else if (line.equals("\\di"))
types = usrIndices;
else if (line.equals("\\dt"))
types = usrTables;
else if (line.equals("\\ds"))
types = usrSequences;
else if (line.equals("\\dS"))
types = sysTables;
else
throw new SQLException("Unsupported \\d command: " + line);
// Display details about all system tables
//
// Note: the first two arguments are ignored. To keep to the spec,
// you must put null here
//
displayResult(dbmd.getTables(null, null, "%", types));
}
}
else
throw new SQLException("Unsupported \\ command: " + line);
}
private static final String allUserTables[] = {"TABLE", "INDEX", "SEQUENCE"};
private static final String usrIndices[] = {"INDEX"};
private static final String usrTables[] = {"TABLE"};
private static final String usrSequences[] = {"SEQUENCE"};
private static final String sysTables[] = {"SYSTEM TABLE", "SYSTEM INDEX"};
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis is not really an example, but is used to test the various methods in\nthe DatabaseMetaData and ResultSetMetaData classes.\n");
System.out.println("Useage:\n java example.metadata jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of debug items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL metdata tester v6.4 rev 1\n");
if (args.length < 3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// Now run the tests
try
{
metadata test = new metadata(args);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
}

View File

@ -1,213 +1,236 @@
package example;
import java.io.*;
import java.sql.*;
import java.text.*;
/**
* This example application demonstrates some of the drivers other features
* by implementing a simple psql replacement in Java.
*
*/
public class psql
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
DatabaseMetaData dbmd; // This defines the structure of the database
boolean done = false; // Added by CWJ to permit \q command
public psql(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
dbmd = db.getMetaData();
st = db.createStatement();
// This prints the backend's version
System.out.println("Connected to "+dbmd.getDatabaseProductName()+" "+dbmd.getDatabaseProductVersion());
System.out.println();
// This provides us the means of reading from stdin
StreamTokenizer input = new StreamTokenizer(new InputStreamReader(System.in));
input.resetSyntax();
input.slashSlashComments(true); // allow // as a comment delimiter
input.eolIsSignificant(false); // treat eol's as spaces
input.wordChars(32,126);
input.whitespaceChars(59,59);
// input.quoteChar(39); *** CWJ: messes up literals in query string ***
// Now the main loop.
int tt=0,lineno=1;
while(tt!=StreamTokenizer.TT_EOF && ! done) { // done added by CWJ to permit \q command
System.out.print("["+lineno+"] ");
System.out.flush();
// Here, we trap SQLException so they don't terminate the application
try {
if((tt=input.nextToken())==StreamTokenizer.TT_WORD) {
processLine(input.sval);
lineno++;
}
} catch(SQLException ex) {
System.out.println(ex.getMessage());
}
}
System.out.println("Now closing the connection");
st.close();
db.close();
}
/**
* This processes a statement
*/
public void processLine(String line) throws SQLException
{
if(line.startsWith("\\")) {
processSlashCommand(line);
return;
}
boolean type = st.execute(line);
boolean loop=true;
while(loop) {
if(type) {
// A ResultSet was returned
ResultSet rs=st.getResultSet();
displayResult(rs);
} else {
int count = st.getUpdateCount();
if(count==-1) {
// This indicates nothing left
loop=false;
} else {
// An update count was returned
System.out.println("Updated "+st.getUpdateCount()+" rows");
}
}
if(loop)
type = st.getMoreResults();
}
}
/**
* This displays a result set.
* Note: it closes the result once complete.
*/
public void displayResult(ResultSet rs) throws SQLException
{
ResultSetMetaData rsmd = rs.getMetaData();
// Print the result column names
int cols = rsmd.getColumnCount();
for(int i=1;i<=cols;i++)
System.out.print(rsmd.getColumnLabel(i)+(i<cols?"\t":"\n"));
// now the results
while(rs.next()) {
for(int i=1;i<=cols;i++) {
Object o = rs.getObject(i);
if(rs.wasNull())
System.out.print("{null}"+(i<cols?"\t":"\n"));
else
System.out.print(o.toString()+(i<cols?"\t":"\n"));
}
}
// finally close the result set
rs.close();
}
/**
* This process / commands (for now just /d)
*/
public void processSlashCommand(String line) throws SQLException
{
if(line.startsWith("\\d")) {
if(line.startsWith("\\d ")) {
// Display details about a table
String table=line.substring(3);
displayResult(dbmd.getColumns(null,null,table,"%"));
} else {
String types[] = null;
if(line.equals("\\d"))
types=allUserTables;
else if(line.equals("\\di"))
types=usrIndices;
else if(line.equals("\\dt"))
types=usrTables;
else if(line.equals("\\ds"))
types=usrSequences;
else if(line.equals("\\dS"))
types=sysTables;
else
throw new SQLException("Unsupported \\d command: "+line);
// Display details about all system tables
//
// Note: the first two arguments are ignored. To keep to the spec,
// you must put null here
//
displayResult(dbmd.getTables(null,null,"%",types));
}
} else if(line.equals("\\q")) // Added by CWJ to permit \q command
done = true;
else
throw new SQLException("Unsupported \\ command: "+line);
}
private static final String allUserTables[] = {"TABLE","INDEX","SEQUENCE"};
private static final String usrIndices[] = {"INDEX"};
private static final String usrTables[] = {"TABLE"};
private static final String usrSequences[] = {"SEQUENCE"};
private static final String sysTables[] = {"SYSTEM TABLE","SYSTEM INDEX"};
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis example shows how some of the other JDBC features work within the\ndriver. It does this by implementing a very simple psql equivalent in java.\nNot everything that psql does is implemented.\n");
System.out.println("Useage:\n java example.psql jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL psql example v6.3 rev 1\n");
if(args.length<3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
// Now run the tests
try {
psql test = new psql(args);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
}
package example;
import java.io.*;
import java.sql.*;
import java.text.*;
/**
* This example application demonstrates some of the drivers other features
* by implementing a simple psql replacement in Java.
*
*/
public class psql
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
DatabaseMetaData dbmd; // This defines the structure of the database
boolean done = false; // Added by CWJ to permit \q command
public psql(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
dbmd = db.getMetaData();
st = db.createStatement();
// This prints the backend's version
System.out.println("Connected to " + dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
System.out.println();
// This provides us the means of reading from stdin
StreamTokenizer input = new StreamTokenizer(new InputStreamReader(System.in));
input.resetSyntax();
input.slashSlashComments(true); // allow // as a comment delimiter
input.eolIsSignificant(false); // treat eol's as spaces
input.wordChars(32, 126);
input.whitespaceChars(59, 59);
// input.quoteChar(39); *** CWJ: messes up literals in query string ***
// Now the main loop.
int tt = 0, lineno = 1;
while (tt != StreamTokenizer.TT_EOF && ! done)
{ // done added by CWJ to permit \q command
System.out.print("[" + lineno + "] ");
System.out.flush();
// Here, we trap SQLException so they don't terminate the application
try
{
if ((tt = input.nextToken()) == StreamTokenizer.TT_WORD)
{
processLine(input.sval);
lineno++;
}
}
catch (SQLException ex)
{
System.out.println(ex.getMessage());
}
}
System.out.println("Now closing the connection");
st.close();
db.close();
}
/**
* This processes a statement
*/
public void processLine(String line) throws SQLException
{
if (line.startsWith("\\"))
{
processSlashCommand(line);
return ;
}
boolean type = st.execute(line);
boolean loop = true;
while (loop)
{
if (type)
{
// A ResultSet was returned
ResultSet rs = st.getResultSet();
displayResult(rs);
}
else
{
int count = st.getUpdateCount();
if (count == -1)
{
// This indicates nothing left
loop = false;
}
else
{
// An update count was returned
System.out.println("Updated " + st.getUpdateCount() + " rows");
}
}
if (loop)
type = st.getMoreResults();
}
}
/**
* This displays a result set.
* Note: it closes the result once complete.
*/
public void displayResult(ResultSet rs) throws SQLException
{
ResultSetMetaData rsmd = rs.getMetaData();
// Print the result column names
int cols = rsmd.getColumnCount();
for (int i = 1;i <= cols;i++)
System.out.print(rsmd.getColumnLabel(i) + (i < cols ? "\t" : "\n"));
// now the results
while (rs.next())
{
for (int i = 1;i <= cols;i++)
{
Object o = rs.getObject(i);
if (rs.wasNull())
System.out.print("{null}" + (i < cols ? "\t" : "\n"));
else
System.out.print(o.toString() + (i < cols ? "\t" : "\n"));
}
}
// finally close the result set
rs.close();
}
/**
* This process / commands (for now just /d)
*/
public void processSlashCommand(String line) throws SQLException
{
if (line.startsWith("\\d"))
{
if (line.startsWith("\\d "))
{
// Display details about a table
String table = line.substring(3);
displayResult(dbmd.getColumns(null, null, table, "%"));
}
else
{
String types[] = null;
if (line.equals("\\d"))
types = allUserTables;
else if (line.equals("\\di"))
types = usrIndices;
else if (line.equals("\\dt"))
types = usrTables;
else if (line.equals("\\ds"))
types = usrSequences;
else if (line.equals("\\dS"))
types = sysTables;
else
throw new SQLException("Unsupported \\d command: " + line);
// Display details about all system tables
//
// Note: the first two arguments are ignored. To keep to the spec,
// you must put null here
//
displayResult(dbmd.getTables(null, null, "%", types));
}
}
else if (line.equals("\\q")) // Added by CWJ to permit \q command
done = true;
else
throw new SQLException("Unsupported \\ command: " + line);
}
private static final String allUserTables[] = {"TABLE", "INDEX", "SEQUENCE"};
private static final String usrIndices[] = {"INDEX"};
private static final String usrTables[] = {"TABLE"};
private static final String usrSequences[] = {"SEQUENCE"};
private static final String sysTables[] = {"SYSTEM TABLE", "SYSTEM INDEX"};
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis example shows how some of the other JDBC features work within the\ndriver. It does this by implementing a very simple psql equivalent in java.\nNot everything that psql does is implemented.\n");
System.out.println("Useage:\n java example.psql jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL psql example v6.3 rev 1\n");
if (args.length < 3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// Now run the tests
try
{
psql test = new psql(args);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
}

View File

@ -18,350 +18,388 @@ import org.postgresql.largeobject.*;
public class threadsafe
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
public threadsafe(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise
cleanup();
// Because we use LargeObjects, we must use Transactions
db.setAutoCommit(false);
// Now run tests using JDBC methods, then LargeObjects
doexample();
// Clean up the database
cleanup();
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
}
/**
* This drops the table (if it existed). No errors are reported.
*/
public void cleanup()
{
try {
st.executeUpdate("drop table basic1");
} catch(Exception ex) {
// We ignore any errors here
}
try {
st.executeUpdate("drop table basic2");
} catch(Exception ex) {
// We ignore any errors here
}
}
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nThis test runs three Threads. Two simply insert data into a table, then\nthey perform a query. While they are running, a third thread is running,\nand it load data into, then reads from a Large Object.\n\nIf alls well, this should run without any errors. If so, we are Thread Safe.\nWhy test JDBC & LargeObject's? Because both will run over the network\nconnection, and if locking on the stream isn't done correctly, the backend\nwill get pretty confused!\n");
thread3 thread3=null;
try {
// create the two threads
Thread thread0 = Thread.currentThread();
Thread thread1 = new thread1(db);
Thread thread2 = new thread2(db);
thread3 = new thread3(db);
// now run, and wait for them
thread1.start();
thread2.start();
thread3.start();
// ok, I know this is bad, but it does the trick here as our main thread
// will yield as long as either of the children are still running
System.out.println("Waiting for threads to run");
while(thread1.isAlive() || thread2.isAlive() || thread3.isAlive())
thread0.yield();
} finally {
// clean up after thread3 (the finally ensures this is run even
// if an exception is thrown inside the try { } construct)
if(thread3 != null)
thread3.cleanup();
}
System.out.println("No Exceptions have been thrown. This is a good omen, as it means that we are\npretty much thread safe as we can get.");
}
// This is the first thread. It's the same as the basic test
class thread1 extends Thread
{
Connection c;
Statement st;
public thread1(Connection c) throws SQLException {
this.c = c;
st = c.createStatement();
}
public void run() {
try {
System.out.println("Thread 1 running...");
// First we need a table to store data in
st.executeUpdate("create table basic1 (a int2, b int2)");
// Now insert some data, using the Statement
st.executeUpdate("insert into basic1 values (1,1)");
st.executeUpdate("insert into basic1 values (2,1)");
st.executeUpdate("insert into basic1 values (3,1)");
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc).
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
public threadsafe(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise
cleanup();
// Because we use LargeObjects, we must use Transactions
db.setAutoCommit(false);
// Now run tests using JDBC methods, then LargeObjects
doexample();
// Clean up the database
cleanup();
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
}
/**
* This drops the table (if it existed). No errors are reported.
*/
public void cleanup()
{
try
{
st.executeUpdate("drop table basic1");
}
catch (Exception ex)
{
// We ignore any errors here
}
try
{
st.executeUpdate("drop table basic2");
}
catch (Exception ex)
{
// We ignore any errors here
}
}
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nThis test runs three Threads. Two simply insert data into a table, then\nthey perform a query. While they are running, a third thread is running,\nand it load data into, then reads from a Large Object.\n\nIf alls well, this should run without any errors. If so, we are Thread Safe.\nWhy test JDBC & LargeObject's? Because both will run over the network\nconnection, and if locking on the stream isn't done correctly, the backend\nwill get pretty confused!\n");
thread3 thread3 = null;
try
{
// create the two threads
Thread thread0 = Thread.currentThread();
Thread thread1 = new thread1(db);
Thread thread2 = new thread2(db);
thread3 = new thread3(db);
// now run, and wait for them
thread1.start();
thread2.start();
thread3.start();
// ok, I know this is bad, but it does the trick here as our main thread
// will yield as long as either of the children are still running
System.out.println("Waiting for threads to run");
while (thread1.isAlive() || thread2.isAlive() || thread3.isAlive())
thread0.yield();
}
finally
{
// clean up after thread3 (the finally ensures this is run even
// if an exception is thrown inside the try { } construct)
if (thread3 != null)
thread3.cleanup();
}
System.out.println("No Exceptions have been thrown. This is a good omen, as it means that we are\npretty much thread safe as we can get.");
}
// This is the first thread. It's the same as the basic test
class thread1 extends Thread
{
Connection c;
Statement st;
public thread1(Connection c) throws SQLException
{
this.c = c;
st = c.createStatement();
}
public void run()
{
try
{
System.out.println("Thread 1 running...");
// First we need a table to store data in
st.executeUpdate("create table basic1 (a int2, b int2)");
// Now insert some data, using the Statement
st.executeUpdate("insert into basic1 values (1,1)");
st.executeUpdate("insert into basic1 values (2,1)");
st.executeUpdate("insert into basic1 values (3,1)");
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc).
//
// Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic1 values (?,?)");
for (int i = 2;i < 2000;i++)
{
ps.setInt(1, 4); // "column a" = 5
ps.setInt(2, i); // "column b" = i
ps.executeUpdate(); // executeUpdate because insert returns no data
// c.commit();
if ((i % 50) == 0)
DriverManager.println("Thread 1 done " + i + " inserts");
}
ps.close(); // Always close when we are done with it
// Finally perform a query on the table
DriverManager.println("Thread 1 performing a query");
ResultSet rs = st.executeQuery("select a, b from basic1");
int cnt = 0;
if (rs != null)
{
// Now we run through the result set, printing out the result.
// Note, we must call .next() before attempting to read any results
while (rs.next())
{
int a = rs.getInt("a"); // This shows how to get the value by name
int b = rs.getInt(2); // This shows how to get the value by column
//System.out.println(" a="+a+" b="+b);
cnt++;
}
rs.close(); // again, you must close the result when done
}
DriverManager.println("Thread 1 read " + cnt + " rows");
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
System.out.println("Thread 1 finished");
}
catch (SQLException se)
{
System.err.println("Thread 1: " + se.toString());
se.printStackTrace();
System.exit(1);
}
}
}
// This is the second thread. It's the similar to the basic test, and thread1
// except it works on another table.
class thread2 extends Thread
{
Connection c;
Statement st;
public thread2(Connection c) throws SQLException
{
this.c = c;
st = c.createStatement();
}
public void run()
{
try
{
System.out.println("Thread 2 running...");
// First we need a table to store data in
st.executeUpdate("create table basic2 (a int2, b int2)");
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc).
//
// Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic2 values (?,?)");
for (int i = 2;i < 2000;i++)
{
ps.setInt(1, 4); // "column a" = 5
ps.setInt(2, i); // "column b" = i
ps.executeUpdate(); // executeUpdate because insert returns no data
// c.commit();
if ((i % 50) == 0)
DriverManager.println("Thread 2 done " + i + " inserts");
}
ps.close(); // Always close when we are done with it
// Finally perform a query on the table
DriverManager.println("Thread 2 performing a query");
ResultSet rs = st.executeQuery("select * from basic2 where b>1");
int cnt = 0;
if (rs != null)
{
// First find out the column numbers.
//
// It's best to do this here, as calling the methods with the column
// numbers actually performs this call each time they are called. This
// really speeds things up on large queries.
//
int col_a = rs.findColumn("a");
int col_b = rs.findColumn("b");
// Now we run through the result set, printing out the result.
// Again, we must call .next() before attempting to read any results
while (rs.next())
{
int a = rs.getInt(col_a); // This shows how to get the value by name
int b = rs.getInt(col_b); // This shows how to get the value by column
//System.out.println(" a="+a+" b="+b);
cnt++;
}
rs.close(); // again, you must close the result when done
}
DriverManager.println("Thread 2 read " + cnt + " rows");
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
System.out.println("Thread 2 finished");
}
catch (SQLException se)
{
System.err.println("Thread 2: " + se.toString());
se.printStackTrace();
System.exit(1);
}
}
}
// This is the third thread. It loads, then reads from a LargeObject, using
// our LargeObject api.
//
// Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic1 values (?,?)");
for(int i=2;i<2000;i++) {
ps.setInt(1,4); // "column a" = 5
ps.setInt(2,i); // "column b" = i
ps.executeUpdate(); // executeUpdate because insert returns no data
// c.commit();
if((i%50)==0)
DriverManager.println("Thread 1 done "+i+" inserts");
// The purpose of this is to test that FastPath will work in between normal
// JDBC queries.
class thread3 extends Thread
{
Connection c;
Statement st;
LargeObjectManager lom;
LargeObject lo;
int oid;
public thread3(Connection c) throws SQLException
{
this.c = c;
//st = c.createStatement();
// create a blob
lom = ((org.postgresql.Connection)c).getLargeObjectAPI();
oid = lom.create();
System.out.println("Thread 3 has created a blob of oid " + oid);
}
public void run()
{
try
{
System.out.println("Thread 3 running...");
DriverManager.println("Thread 3: Loading data into blob " + oid);
lo = lom.open(oid);
FileInputStream fis = new FileInputStream("example/threadsafe.java");
// keep the buffer size small, to allow the other thread a chance
byte buf[] = new byte[128];
int rc, bc = 1, bs = 0;
while ((rc = fis.read(buf)) > 0)
{
DriverManager.println("Thread 3 read block " + bc + " " + bs + " bytes");
lo.write(buf, 0, rc);
bc++;
bs += rc;
}
lo.close();
fis.close();
DriverManager.println("Thread 3: Reading blob " + oid);
lo = lom.open(oid);
bc = 0;
while (buf.length > 0)
{
buf = lo.read(buf.length);
if (buf.length > 0)
{
String s = new String(buf);
bc++;
DriverManager.println("Thread 3 block " + bc);
DriverManager.println("Block " + bc + " got " + s);
}
}
lo.close();
System.out.println("Thread 3 finished");
}
catch (Exception se)
{
System.err.println("Thread 3: " + se.toString());
se.printStackTrace();
System.exit(1);
}
}
public void cleanup() throws SQLException
{
if (lom != null && oid != 0)
{
System.out.println("Thread 3: Removing blob oid=" + oid);
lom.delete(oid);
}
}
}
ps.close(); // Always close when we are done with it
// Finally perform a query on the table
DriverManager.println("Thread 1 performing a query");
ResultSet rs = st.executeQuery("select a, b from basic1");
int cnt=0;
if(rs!=null) {
// Now we run through the result set, printing out the result.
// Note, we must call .next() before attempting to read any results
while(rs.next()) {
int a = rs.getInt("a"); // This shows how to get the value by name
int b = rs.getInt(2); // This shows how to get the value by column
//System.out.println(" a="+a+" b="+b);
cnt++;
}
rs.close(); // again, you must close the result when done
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis tests the thread safety of the driver.\n\nThis is done in two parts, the first with standard JDBC calls, and the\nsecond mixing FastPath and LargeObject calls with queries.\n");
System.out.println("Useage:\n java example.threadsafe jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
DriverManager.println("Thread 1 read "+cnt+" rows");
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
System.out.println("Thread 1 finished");
} catch(SQLException se) {
System.err.println("Thread 1: "+se.toString());
se.printStackTrace();
System.exit(1);
}
}
}
// This is the second thread. It's the similar to the basic test, and thread1
// except it works on another table.
class thread2 extends Thread
{
Connection c;
Statement st;
public thread2(Connection c) throws SQLException {
this.c = c;
st = c.createStatement();
}
public void run() {
try {
System.out.println("Thread 2 running...");
// First we need a table to store data in
st.executeUpdate("create table basic2 (a int2, b int2)");
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc).
//
// Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic2 values (?,?)");
for(int i=2;i<2000;i++) {
ps.setInt(1,4); // "column a" = 5
ps.setInt(2,i); // "column b" = i
ps.executeUpdate(); // executeUpdate because insert returns no data
// c.commit();
if((i%50)==0)
DriverManager.println("Thread 2 done "+i+" inserts");
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL Thread Safety test v6.4 rev 1\n");
if (args.length < 3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// Now run the tests
try
{
threadsafe test = new threadsafe(args);
}
catch (Exception ex)
{
System.err.println("Exception caught.\n" + ex);
ex.printStackTrace();
}
}
ps.close(); // Always close when we are done with it
// Finally perform a query on the table
DriverManager.println("Thread 2 performing a query");
ResultSet rs = st.executeQuery("select * from basic2 where b>1");
int cnt=0;
if(rs!=null) {
// First find out the column numbers.
//
// It's best to do this here, as calling the methods with the column
// numbers actually performs this call each time they are called. This
// really speeds things up on large queries.
//
int col_a = rs.findColumn("a");
int col_b = rs.findColumn("b");
// Now we run through the result set, printing out the result.
// Again, we must call .next() before attempting to read any results
while(rs.next()) {
int a = rs.getInt(col_a); // This shows how to get the value by name
int b = rs.getInt(col_b); // This shows how to get the value by column
//System.out.println(" a="+a+" b="+b);
cnt++;
}
rs.close(); // again, you must close the result when done
}
DriverManager.println("Thread 2 read "+cnt+" rows");
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
System.out.println("Thread 2 finished");
} catch(SQLException se) {
System.err.println("Thread 2: "+se.toString());
se.printStackTrace();
System.exit(1);
}
}
}
// This is the third thread. It loads, then reads from a LargeObject, using
// our LargeObject api.
//
// The purpose of this is to test that FastPath will work in between normal
// JDBC queries.
class thread3 extends Thread
{
Connection c;
Statement st;
LargeObjectManager lom;
LargeObject lo;
int oid;
public thread3(Connection c) throws SQLException {
this.c = c;
//st = c.createStatement();
// create a blob
lom = ((org.postgresql.Connection)c).getLargeObjectAPI();
oid = lom.create();
System.out.println("Thread 3 has created a blob of oid "+oid);
}
public void run() {
try {
System.out.println("Thread 3 running...");
DriverManager.println("Thread 3: Loading data into blob "+oid);
lo = lom.open(oid);
FileInputStream fis = new FileInputStream("example/threadsafe.java");
// keep the buffer size small, to allow the other thread a chance
byte buf[] = new byte[128];
int rc,bc=1,bs=0;
while((rc=fis.read(buf))>0) {
DriverManager.println("Thread 3 read block "+bc+" "+bs+" bytes");
lo.write(buf,0,rc);
bc++;
bs+=rc;
}
lo.close();
fis.close();
DriverManager.println("Thread 3: Reading blob "+oid);
lo=lom.open(oid);
bc=0;
while(buf.length>0) {
buf=lo.read(buf.length);
if(buf.length>0) {
String s = new String(buf);
bc++;
DriverManager.println("Thread 3 block "+bc);
DriverManager.println("Block "+bc+" got "+s);
}
}
lo.close();
System.out.println("Thread 3 finished");
} catch(Exception se) {
System.err.println("Thread 3: "+se.toString());
se.printStackTrace();
System.exit(1);
}
}
public void cleanup() throws SQLException {
if(lom!=null && oid!=0) {
System.out.println("Thread 3: Removing blob oid="+oid);
lom.delete(oid);
}
}
}
/**
* Display some instructions on how to run the example
*/
public static void instructions()
{
System.out.println("\nThis tests the thread safety of the driver.\n\nThis is done in two parts, the first with standard JDBC calls, and the\nsecond mixing FastPath and LargeObject calls with queries.\n");
System.out.println("Useage:\n java example.threadsafe jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL Thread Safety test v6.4 rev 1\n");
if(args.length<3)
instructions();
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
// Now run the tests
try {
threadsafe test = new threadsafe(args);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -12,96 +12,96 @@ import org.postgresql.util.*;
*/
public class Field
{
private int length; // Internal Length of this field
private int oid; // OID of the type
private int mod; // type modifier of this field
private String name; // Name of this field
private int length; // Internal Length of this field
private int oid; // OID of the type
private int mod; // type modifier of this field
private String name; // Name of this field
private Connection conn; // Connection Instantation
private Connection conn; // Connection Instantation
/**
* 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,int mod)
{
this.conn = conn;
this.name = name;
this.oid = oid;
this.length = length;
this.mod = mod;
}
/**
* 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, int mod)
{
this.conn = conn;
this.name = name;
this.oid = oid;
this.length = length;
this.mod = mod;
}
/**
* Constructor without mod parameter.
*
* @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,name,oid,length,0);
}
/**
* Constructor without mod parameter.
*
* @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, name, oid, length, 0);
}
/**
* @return the oid of this Field's data type
*/
public int getOID()
{
return oid;
}
/**
* @return the oid of this Field's data type
*/
public int getOID()
{
return oid;
}
/**
* @return the mod of this Field's data type
*/
public int getMod()
{
return mod;
}
/**
* @return the mod of this Field's data type
*/
public int getMod()
{
return mod;
}
/**
* @return the name of this Field's data type
*/
public String getName()
{
return name;
}
/**
* @return the name of this Field's data type
*/
public String getName()
{
return name;
}
/**
* @return the length of this Field's data type
*/
public int getLength()
{
return length;
}
/**
* @return the length of this Field's data type
*/
public int getLength()
{
return length;
}
/**
* We also need to get the PG type name as returned by the back end.
*
* @return the String representation of the PG type of this field
* @exception SQLException if a database access error occurs
*/
public String getPGType() throws SQLException
{
return conn.getPGType(oid);
}
/**
* We also need to get the PG type name as returned by the back end.
*
* @return the String representation of the PG type of this field
* @exception SQLException if a database access error occurs
*/
public String getPGType() throws SQLException
{
return conn.getPGType(oid);
}
/**
* We also need to get the java.sql.types type.
*
* @return the int representation of the java.sql.types type of this field
* @exception SQLException if a database access error occurs
*/
public int getSQLType() throws SQLException
{
return conn.getSQLType(oid);
}
/**
* We also need to get the java.sql.types type.
*
* @return the int representation of the java.sql.types type of this field
* @exception SQLException if a database access error occurs
*/
public int getSQLType() throws SQLException
{
return conn.getSQLType(oid);
}
}

View File

@ -10,345 +10,366 @@ import org.postgresql.core.*;
import org.postgresql.util.*;
/**
* $Id: PG_Stream.java,v 1.13 2001/08/26 17:08:48 momjian Exp $
* $Id: PG_Stream.java,v 1.14 2001/10/25 05:59:59 momjian Exp $
*
* This class is used by Connection & PGlobj for communicating with the
* backend.
*
* @see java.sql.Connection
*/
// This class handles all the Streamed I/O for a org.postgresql connection
// This class handles all the Streamed I/O for a org.postgresql connection
public class PG_Stream
{
private Socket connection;
private InputStream pg_input;
private BufferedOutputStream pg_output;
private byte[] byte_buf = new byte[8*1024];
private Socket connection;
private InputStream pg_input;
private BufferedOutputStream pg_output;
private byte[] byte_buf = new byte[8*1024];
BytePoolDim1 bytePoolDim1 = new BytePoolDim1();
BytePoolDim2 bytePoolDim2 = new BytePoolDim2();
BytePoolDim1 bytePoolDim1 = new BytePoolDim1();
BytePoolDim2 bytePoolDim2 = new BytePoolDim2();
/**
* 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);
/**
* 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);
// Submitted by Jason Venner <jason@idiom.com> adds a 10x speed
// improvement on FreeBSD machines (caused by a bug in their TCP Stack)
connection.setTcpNoDelay(true);
// Submitted by Jason Venner <jason@idiom.com> adds a 10x speed
// improvement on FreeBSD machines (caused by a bug in their TCP Stack)
connection.setTcpNoDelay(true);
// Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
pg_input = new BufferedInputStream(connection.getInputStream(), 8192);
pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
}
// Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
pg_input = new BufferedInputStream(connection.getInputStream(), 8192);
pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
}
/**
* 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((byte)val);
}
/**
* 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((byte)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 = bytePoolDim1.allocByte(siz);
/**
* 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 = bytePoolDim1.allocByte(siz);
while (siz-- > 0)
{
buf[siz] = (byte)(val & 0xff);
val >>= 8;
}
Send(buf);
}
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 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
{
Send(buf,0,siz);
}
/**
* 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
{
Send(buf, 0, siz);
}
/**
* 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 off offset in the array to start sending from
* @param siz the number of bytes to be sent
* @exception IOException if an I/O error occurs
*/
public void Send(byte buf[], int off, int siz) throws IOException
{
int i;
/**
* 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 off offset in the array to start sending from
* @param siz the number of bytes to be sent
* @exception IOException if an I/O error occurs
*/
public void Send(byte buf[], int off, int siz) throws IOException
{
int i;
pg_output.write(buf, off, ((buf.length-off) < siz ? (buf.length-off) : siz));
if((buf.length-off) < siz)
{
for (i = buf.length-off ; i < siz ; ++i)
{
pg_output.write(0);
}
}
}
pg_output.write(buf, off, ((buf.length - off) < siz ? (buf.length - off) : siz));
if ((buf.length - off) < siz)
{
for (i = buf.length - off ; 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;
/**
* 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 PSQLException("postgresql.stream.eof");
} catch (IOException e) {
throw new PSQLException("postgresql.stream.ioerror",e);
}
return c;
}
try
{
c = pg_input.read();
if (c < 0)
throw new PSQLException("postgresql.stream.eof");
}
catch (IOException e)
{
throw new PSQLException("postgresql.stream.ioerror", e);
}
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;
/**
* 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();
try
{
for (int i = 0 ; i < siz ; i++)
{
int b = pg_input.read();
if (b < 0)
throw new PSQLException("postgresql.stream.eof");
n = n | (b << (8 * i)) ;
}
} catch (IOException e) {
throw new PSQLException("postgresql.stream.ioerror",e);
}
return n;
}
if (b < 0)
throw new PSQLException("postgresql.stream.eof");
n = n | (b << (8 * i)) ;
}
}
catch (IOException e)
{
throw new PSQLException("postgresql.stream.ioerror", e);
}
return n;
}
/**
* 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 ReceiveIntegerR(int siz) throws SQLException
{
int n = 0;
/**
* 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 ReceiveIntegerR(int siz) throws SQLException
{
int n = 0;
try
{
for (int i = 0 ; i < siz ; i++)
{
int b = pg_input.read();
try
{
for (int i = 0 ; i < siz ; i++)
{
int b = pg_input.read();
if (b < 0)
throw new PSQLException("postgresql.stream.eof");
n = b | (n << 8);
}
} catch (IOException e) {
throw new PSQLException("postgresql.stream.ioerror",e);
}
return n;
}
if (b < 0)
throw new PSQLException("postgresql.stream.eof");
n = b | (n << 8);
}
}
catch (IOException e)
{
throw new PSQLException("postgresql.stream.ioerror", e);
}
return n;
}
/**
* Receives a null-terminated string from the backend. If we don't see a
* null, then we assume something has gone wrong.
*
* @param encoding the charset encoding to use.
* @return string from back end
* @exception SQLException if an I/O error occurs, or end of file
*/
public String ReceiveString(Encoding encoding)
throws SQLException
{
int s = 0;
byte[] rst = byte_buf;
try {
int buflen = rst.length;
boolean done = false;
while (!done) {
while (s < buflen) {
int c = pg_input.read();
if (c < 0)
throw new PSQLException("postgresql.stream.eof");
else if (c == 0) {
rst[s] = 0;
done = true;
break;
} else {
rst[s++] = (byte)c;
}
if (s >= buflen) { // Grow the buffer
buflen = (int)(buflen*2); // 100% bigger
byte[] newrst = new byte[buflen];
System.arraycopy(rst, 0, newrst, 0, s);
rst = newrst;
}
}
}
} catch (IOException e) {
throw new PSQLException("postgresql.stream.ioerror",e);
}
return encoding.decode(rst, 0, s);
}
/**
* Receives a null-terminated string from the backend. If we don't see a
* null, then we assume something has gone wrong.
*
* @param encoding the charset encoding to use.
* @return string from back end
* @exception SQLException if an I/O error occurs, or end of file
*/
public String ReceiveString(Encoding encoding)
throws SQLException
{
int s = 0;
byte[] rst = byte_buf;
try
{
int buflen = rst.length;
boolean done = false;
while (!done)
{
while (s < buflen)
{
int c = pg_input.read();
if (c < 0)
throw new PSQLException("postgresql.stream.eof");
else if (c == 0)
{
rst[s] = 0;
done = true;
break;
}
else
{
rst[s++] = (byte)c;
}
if (s >= buflen)
{ // Grow the buffer
buflen = (int)(buflen * 2); // 100% bigger
byte[] newrst = new byte[buflen];
System.arraycopy(rst, 0, newrst, 0, s);
rst = newrst;
}
}
}
}
catch (IOException e)
{
throw new PSQLException("postgresql.stream.ioerror", e);
}
return encoding.decode(rst, 0, s);
}
/**
* 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 = bytePoolDim2.allocByte(nf);
/**
* 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 = bytePoolDim2.allocByte(nf);
int whichbit = 0x80;
int whichbyte = 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 = ReceiveIntegerR(4);
if (!bin)
len -= 4;
if (len < 0)
len = 0;
answer[i] = Receive(len);
}
}
return answer;
}
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 = ReceiveIntegerR(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 = bytePoolDim1.allocByte(siz);
Receive(answer,0,siz);
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 = bytePoolDim1.allocByte(siz);
Receive(answer, 0, siz);
return answer;
}
/**
* Reads in a given number of bytes from the backend
*
* @param buf buffer to store result
* @param off offset in buffer
* @param siz number of bytes to read
* @exception SQLException if a data I/O error occurs
*/
public void Receive(byte[] b,int off,int siz) throws SQLException
{
int s = 0;
/**
* Reads in a given number of bytes from the backend
*
* @param buf buffer to store result
* @param off offset in buffer
* @param siz number of bytes to read
* @exception SQLException if a data I/O error occurs
*/
public void Receive(byte[] b, int off, int siz) throws SQLException
{
int s = 0;
try
{
while (s < siz)
{
int w = pg_input.read(b, off+s, siz - s);
if (w < 0)
throw new PSQLException("postgresql.stream.eof");
s += w;
}
} catch (IOException e) {
throw new PSQLException("postgresql.stream.ioerror",e);
}
}
try
{
while (s < siz)
{
int w = pg_input.read(b, off + s, siz - s);
if (w < 0)
throw new PSQLException("postgresql.stream.eof");
s += w;
}
}
catch (IOException e)
{
throw new PSQLException("postgresql.stream.ioerror", e);
}
}
/**
* This flushes any pending output to the backend. It is used primarily
* by the Fastpath code.
* @exception SQLException if an I/O error occurs
*/
public void flush() throws SQLException
{
try {
pg_output.flush();
} catch (IOException e) {
throw new PSQLException("postgresql.stream.flush",e);
}
}
/**
* This flushes any pending output to the backend. It is used primarily
* by the Fastpath code.
* @exception SQLException if an I/O error occurs
*/
public void flush() throws SQLException
{
try
{
pg_output.flush();
}
catch (IOException e)
{
throw new PSQLException("postgresql.stream.flush", e);
}
}
/**
* Closes the connection
*
* @exception IOException if a IO Error occurs
*/
public void close() throws IOException
{
pg_output.close();
pg_input.close();
connection.close();
}
/**
* Closes the connection
*
* @exception IOException if a IO Error occurs
*/
public void close() throws IOException
{
pg_output.close();
pg_input.close();
connection.close();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -15,198 +15,201 @@ import org.postgresql.util.*;
*/
public abstract class ResultSet
{
protected Vector rows; // The results
protected Field fields[]; // The field descriptions
protected String status; // Status of the result
protected boolean binaryCursor = false; // is the data binary or Strings
protected int updateCount; // How many rows did we get back?
protected int insertOID; // The oid of an inserted row
protected int current_row; // Our pointer to where we are at
protected byte[][] this_row; // the current row result
protected Connection connection; // the connection which we returned from
protected SQLWarning warnings = null; // The warning chain
protected boolean wasNullFlag = false; // the flag for wasNull()
protected Vector rows; // The results
protected Field fields[]; // The field descriptions
protected String status; // Status of the result
protected boolean binaryCursor = false; // is the data binary or Strings
protected int updateCount; // How many rows did we get back?
protected int insertOID; // The oid of an inserted row
protected int current_row; // Our pointer to where we are at
protected byte[][] this_row; // the current row result
protected Connection connection; // the connection which we returned from
protected SQLWarning warnings = null; // The warning chain
protected boolean wasNullFlag = false; // the flag for wasNull()
// We can chain multiple resultSets together - this points to
// next resultSet in the chain.
protected ResultSet next = null;
// We can chain multiple resultSets together - this points to
// next resultSet in the chain.
protected 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,int insertOID, boolean binaryCursor)
{
this.connection = conn;
this.fields = fields;
this.rows = tuples;
this.status = status;
this.updateCount = updateCount;
this.insertOID = insertOID;
this.this_row = null;
this.current_row = -1;
this.binaryCursor = binaryCursor;
}
/**
* 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, int insertOID, boolean binaryCursor)
{
this.connection = conn;
this.fields = fields;
this.rows = tuples;
this.status = status;
this.updateCount = updateCount;
this.insertOID = insertOID;
this.this_row = null;
this.current_row = -1;
this.binaryCursor = binaryCursor;
}
/**
* 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(conn,fields,tuples,status,updateCount,0,false);
}
/**
* 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(conn, fields, tuples, status, updateCount, 0, false);
}
/**
* 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);
}
/**
* 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 java.sql.ResultSet getNext()
{
return (java.sql.ResultSet)next;
}
/**
* 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 java.sql.ResultSet getNext()
{
return (java.sql.ResultSet)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);
}
/**
* 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;
}
/**
* 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
*
* @return the number of rows
*/
public int getTupleCount()
{
return rows.size();
}
/**
* 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
*
* @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;
}
/**
* getColumnCount returns the number of columns
*
* @return the number of columns
*/
public int getColumnCount()
{
return fields.length;
}
/**
* Returns the status message from the backend.<p>
* It is used internally by the driver.
*
* @return the status string from the backend
*/
public String getStatusString()
{
return status;
}
/**
* Returns the status message from the backend.<p>
* It is used internally by the driver.
*
* @return the status string from the backend
*/
public String getStatusString()
{
return status;
}
/**
* returns the OID of a field.<p>
* It is used internally by the driver.
*
* @param field field id
* @return the oid of that field's type
*/
public int getColumnOID(int field)
{
return fields[field-1].getOID();
}
/**
* returns the OID of a field.<p>
* It is used internally by the driver.
*
* @param field field id
* @return the oid of that field's type
*/
public int getColumnOID(int field)
{
return fields[field -1].getOID();
}
/**
* returns the OID of the last inserted row
*/
public int getInsertedOID()
{
return insertOID;
}
/**
* returns the OID of the last inserted row
*/
public int getInsertedOID()
{
return insertOID;
}
/**
* This is part of the JDBC API, but is required by org.postgresql.Field
*/
public abstract void close() throws SQLException;
public abstract boolean next() throws SQLException;
public abstract String getString(int i) throws SQLException;
/**
* This is part of the JDBC API, but is required by org.postgresql.Field
*/
public abstract void close() throws SQLException;
public abstract boolean next() throws SQLException;
public abstract String getString(int i) throws SQLException;
/**
* This is used to fix get*() methods on Money fields. It should only be
* used by those methods!
*
* It converts ($##.##) to -##.## and $##.## to ##.##
*/
public String getFixedString(int col) throws SQLException {
String s = getString(col);
/**
* This is used to fix get*() methods on Money fields. It should only be
* used by those methods!
*
* It converts ($##.##) to -##.## and $##.## to ##.##
*/
public String getFixedString(int col) throws SQLException
{
String s = getString(col);
// Handle SQL Null
wasNullFlag = (this_row[col - 1] == null);
if(wasNullFlag)
return null;
// Handle SQL Null
wasNullFlag = (this_row[col - 1] == null);
if (wasNullFlag)
return null;
// Handle Money
if(s.charAt(0)=='(') {
s="-"+org.postgresql.util.PGtokenizer.removePara(s).substring(1);
}
if(s.charAt(0)=='$') {
s=s.substring(1);
}
// Handle Money
if (s.charAt(0) == '(')
{
s = "-" + org.postgresql.util.PGtokenizer.removePara(s).substring(1);
}
if (s.charAt(0) == '$')
{
s = s.substring(1);
}
return s;
}
return s;
}
}

View File

@ -23,284 +23,299 @@ import org.postgresql.util.PSQLException;
* JDBC3.
*/
public abstract class Statement {
public abstract class Statement
{
/** The warnings chain. */
protected SQLWarning warnings = null;
/** The warnings chain. */
protected SQLWarning warnings = null;
/** The current results */
protected java.sql.ResultSet result = null;
/** The current results */
protected java.sql.ResultSet result = null;
/** Maximum number of rows to return, 0 = unlimited */
protected int maxrows = 0;
/** Maximum number of rows to return, 0 = unlimited */
protected int maxrows = 0;
/** Timeout (in seconds) for a query (not used) */
protected int timeout = 0;
/** Timeout (in seconds) for a query (not used) */
protected int timeout = 0;
protected boolean escapeProcessing = true;
protected boolean escapeProcessing = true;
// Static variables for parsing SQL when escapeProcessing is true.
private static final short IN_SQLCODE = 0;
private static final short IN_STRING = 1;
private static final short BACKSLASH =2;
private static final short ESC_TIMEDATE = 3;
// Static variables for parsing SQL when escapeProcessing is true.
private static final short IN_SQLCODE = 0;
private static final short IN_STRING = 1;
private static final short BACKSLASH = 2;
private static final short ESC_TIMEDATE = 3;
public Statement() {
}
public Statement()
{}
/**
* Returns the status message from the current Result.<p>
* This is used internally by the driver.
*
* @return status message from backend
*/
public String getResultStatusString() {
if (result == null)
return null;
return ((org.postgresql.ResultSet) result).getStatusString();
}
/**
* Returns the status message from the current Result.<p>
* This is used internally by the driver.
*
* @return status message from backend
*/
public String getResultStatusString()
{
if (result == null)
return null;
return ((org.postgresql.ResultSet) result).getStatusString();
}
/**
* The maxRows limit is set to limit the number of rows that
* any ResultSet can contain. If the limit is exceeded, the
* excess rows are silently dropped.
*
* @return the current maximum row limit; zero means unlimited
* @exception SQLException if a database access error occurs
*/
public int getMaxRows() throws SQLException {
return maxrows;
}
/**
* The maxRows limit is set to limit the number of rows that
* any ResultSet can contain. If the limit is exceeded, the
* excess rows are silently dropped.
*
* @return the current maximum row limit; zero means unlimited
* @exception SQLException if a database access error occurs
*/
public int getMaxRows() throws SQLException
{
return maxrows;
}
/**
* Set the maximum number of rows
*
* @param max the new max rows limit; zero means unlimited
* @exception SQLException if a database access error occurs
* @see getMaxRows
*/
public void setMaxRows(int max) throws SQLException {
maxrows = max;
}
/**
* Set the maximum number of rows
*
* @param max the new max rows limit; zero means unlimited
* @exception SQLException if a database access error occurs
* @see getMaxRows
*/
public void setMaxRows(int max) throws SQLException
{
maxrows = max;
}
/**
* If escape scanning is on (the default), the driver will do escape
* substitution before sending the SQL to the database.
*
* @param enable true to enable; false to disable
* @exception SQLException if a database access error occurs
*/
public void setEscapeProcessing(boolean enable) throws SQLException {
escapeProcessing = enable;
}
/**
* If escape scanning is on (the default), the driver will do escape
* substitution before sending the SQL to the database.
*
* @param enable true to enable; false to disable
* @exception SQLException if a database access error occurs
*/
public void setEscapeProcessing(boolean enable) throws SQLException
{
escapeProcessing = enable;
}
/**
* The queryTimeout limit is the number of seconds the driver
* will wait for a Statement to execute. If the limit is
* exceeded, a SQLException is thrown.
*
* @return the current query timeout limit in seconds; 0 = unlimited
* @exception SQLException if a database access error occurs
*/
public int getQueryTimeout() throws SQLException {
return timeout;
}
/**
* The queryTimeout limit is the number of seconds the driver
* will wait for a Statement to execute. If the limit is
* exceeded, a SQLException is thrown.
*
* @return the current query timeout limit in seconds; 0 = unlimited
* @exception SQLException if a database access error occurs
*/
public int getQueryTimeout() throws SQLException
{
return timeout;
}
/**
* Sets the queryTimeout limit
*
* @param seconds - the new query timeout limit in seconds
* @exception SQLException if a database access error occurs
*/
public void setQueryTimeout(int seconds) throws SQLException {
timeout = seconds;
}
/**
* Sets the queryTimeout limit
*
* @param seconds - the new query timeout limit in seconds
* @exception SQLException if a database access error occurs
*/
public void setQueryTimeout(int seconds) throws SQLException
{
timeout = seconds;
}
/**
* The first warning reported by calls on this Statement is
* returned. A Statement's execute methods clear its SQLWarning
* chain. Subsequent Statement warnings will be chained to this
* SQLWarning.
*
* <p>The Warning chain is automatically cleared each time a statement
* is (re)executed.
*
* <p><B>Note:</B> If you are processing a ResultSet then any warnings
* associated with ResultSet reads will be chained on the ResultSet
* object.
*
* @return the first SQLWarning on null
* @exception SQLException if a database access error occurs
*/
public SQLWarning getWarnings() throws SQLException {
return warnings;
}
/**
* The first warning reported by calls on this Statement is
* returned. A Statement's execute methods clear its SQLWarning
* chain. Subsequent Statement warnings will be chained to this
* SQLWarning.
*
* <p>The Warning chain is automatically cleared each time a statement
* is (re)executed.
*
* <p><B>Note:</B> If you are processing a ResultSet then any warnings
* associated with ResultSet reads will be chained on the ResultSet
* object.
*
* @return the first SQLWarning on null
* @exception SQLException if a database access error occurs
*/
public SQLWarning getWarnings() throws SQLException
{
return warnings;
}
/**
* The maxFieldSize limit (in bytes) is the maximum amount of
* data returned for any column value; it only applies to
* BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR
* columns. If the limit is exceeded, the excess data is silently
* discarded.
*
* @return the current max column size limit; zero means unlimited
* @exception SQLException if a database access error occurs
*/
public int getMaxFieldSize() throws SQLException {
return 8192; // We cannot change this
}
/**
* The maxFieldSize limit (in bytes) is the maximum amount of
* data returned for any column value; it only applies to
* BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR
* columns. If the limit is exceeded, the excess data is silently
* discarded.
*
* @return the current max column size limit; zero means unlimited
* @exception SQLException if a database access error occurs
*/
public int getMaxFieldSize() throws SQLException
{
return 8192; // We cannot change this
}
/**
* Sets the maxFieldSize - NOT! - We throw an SQLException just
* to inform them to stop doing this.
*
* @param max the new max column size limit; zero means unlimited
* @exception SQLException if a database access error occurs
*/
public void setMaxFieldSize(int max) throws SQLException {
throw new PSQLException("postgresql.stat.maxfieldsize");
}
/**
* Sets the maxFieldSize - NOT! - We throw an SQLException just
* to inform them to stop doing this.
*
* @param max the new max column size limit; zero means unlimited
* @exception SQLException if a database access error occurs
*/
public void setMaxFieldSize(int max) throws SQLException
{
throw new PSQLException("postgresql.stat.maxfieldsize");
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this Statement.
*
* @exception SQLException if a database access error occurs
*/
public void clearWarnings() throws SQLException {
warnings = null;
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this Statement.
*
* @exception SQLException if a database access error occurs
*/
public void clearWarnings() throws SQLException
{
warnings = null;
}
/**
* Cancel can be used by one thread to cancel a statement that
* is being executed by another thread.
* <p>
* Not implemented, this method is a no-op.
*
* @exception SQLException only because thats the spec.
*/
public void cancel() throws SQLException {
// FIXME: Cancel feature has been available since 6.4. Implement it here!
}
/**
* Cancel can be used by one thread to cancel a statement that
* is being executed by another thread.
* <p>
* Not implemented, this method is a no-op.
*
* @exception SQLException only because thats the spec.
*/
public void cancel() throws SQLException
{
// FIXME: Cancel feature has been available since 6.4. Implement it here!
}
/**
* New in 7.1: Returns the Last inserted oid. This should be used, rather
* than the old method using getResultSet, which for executeUpdate returns
* null.
* @return OID of last insert
*/
public int getInsertedOID() throws SQLException {
if (result == null)
return 0;
return ((org.postgresql.ResultSet) result).getInsertedOID();
}
/**
* New in 7.1: Returns the Last inserted oid. This should be used, rather
* than the old method using getResultSet, which for executeUpdate returns
* null.
* @return OID of last insert
*/
public int getInsertedOID() throws SQLException
{
if (result == null)
return 0;
return ((org.postgresql.ResultSet) result).getInsertedOID();
}
/**
* getResultSet returns the current result as a ResultSet. It
* should only be called once per result.
*
* @return the current result set; null if there are no more
* @exception SQLException if a database access error occurs (why?)
*/
public java.sql.ResultSet getResultSet() throws SQLException {
if (result != null && ((org.postgresql.ResultSet) result).reallyResultSet())
return result;
return null;
}
/**
* getResultSet returns the current result as a ResultSet. It
* should only be called once per result.
*
* @return the current result set; null if there are no more
* @exception SQLException if a database access error occurs (why?)
*/
public java.sql.ResultSet getResultSet() throws SQLException
{
if (result != null && ((org.postgresql.ResultSet) result).reallyResultSet())
return result;
return null;
}
/**
* In many cases, it is desirable to immediately release a
* Statement's database and JDBC resources instead of waiting
* for this to happen when it is automatically closed. The
* close method provides this immediate release.
*
* <p><B>Note:</B> A Statement is automatically closed when it is
* garbage collected. When a Statement is closed, its current
* ResultSet, if one exists, is also closed.
*
* @exception SQLException if a database access error occurs (why?)
*/
public void close() throws SQLException {
// Force the ResultSet to close
java.sql.ResultSet rs = getResultSet();
if(rs!=null)
rs.close();
/**
* In many cases, it is desirable to immediately release a
* Statement's database and JDBC resources instead of waiting
* for this to happen when it is automatically closed. The
* close method provides this immediate release.
*
* <p><B>Note:</B> A Statement is automatically closed when it is
* garbage collected. When a Statement is closed, its current
* ResultSet, if one exists, is also closed.
*
* @exception SQLException if a database access error occurs (why?)
*/
public void close() throws SQLException
{
// Force the ResultSet to close
java.sql.ResultSet rs = getResultSet();
if (rs != null)
rs.close();
// Disasociate it from us (For Garbage Collection)
result = null;
}
// Disasociate it from us (For Garbage Collection)
result = null;
}
/**
* Filter the SQL string of Java SQL Escape clauses.
*
* Currently implemented Escape clauses are those mentioned in 11.3
* in the specification. Basically we look through the sql string for
* {d xxx}, {t xxx} or {ts xxx} in non-string sql code. When we find
* them, we just strip the escape part leaving only the xxx part.
* So, something like "select * from x where d={d '2001-10-09'}" would
* return "select * from x where d= '2001-10-09'".
*/
protected static String escapeSQL(String sql)
{
// Since escape codes can only appear in SQL CODE, we keep track
// of if we enter a string or not.
StringBuffer newsql = new StringBuffer();
short state = IN_SQLCODE;
/**
* Filter the SQL string of Java SQL Escape clauses.
*
* Currently implemented Escape clauses are those mentioned in 11.3
* in the specification. Basically we look through the sql string for
* {d xxx}, {t xxx} or {ts xxx} in non-string sql code. When we find
* them, we just strip the escape part leaving only the xxx part.
* So, something like "select * from x where d={d '2001-10-09'}" would
* return "select * from x where d= '2001-10-09'".
*/
protected static String escapeSQL(String sql)
{
// Since escape codes can only appear in SQL CODE, we keep track
// of if we enter a string or not.
StringBuffer newsql = new StringBuffer();
short state = IN_SQLCODE;
int i = -1;
int len = sql.length();
while(++i < len)
{
char c = sql.charAt(i);
switch(state)
{
case IN_SQLCODE:
if(c == '\'') // start of a string?
state = IN_STRING;
else if(c == '{') // start of an escape code?
if(i+1 < len)
{
char next = sql.charAt(i+1);
if(next == 'd')
{
state = ESC_TIMEDATE;
i++;
break;
}
else if(next == 't')
{
state = ESC_TIMEDATE;
i += (i+2 < len && sql.charAt(i+2) == 's') ? 2 : 1;
break;
}
}
newsql.append(c);
break;
int i = -1;
int len = sql.length();
while (++i < len)
{
char c = sql.charAt(i);
switch (state)
{
case IN_SQLCODE:
if (c == '\'') // start of a string?
state = IN_STRING;
else if (c == '{') // start of an escape code?
if (i + 1 < len)
{
char next = sql.charAt(i + 1);
if (next == 'd')
{
state = ESC_TIMEDATE;
i++;
break;
}
else if (next == 't')
{
state = ESC_TIMEDATE;
i += (i + 2 < len && sql.charAt(i + 2) == 's') ? 2 : 1;
break;
}
}
newsql.append(c);
break;
case IN_STRING:
if(c == '\'') // end of string?
state = IN_SQLCODE;
else if(c == '\\') // a backslash?
state = BACKSLASH;
case IN_STRING:
if (c == '\'') // end of string?
state = IN_SQLCODE;
else if (c == '\\') // a backslash?
state = BACKSLASH;
newsql.append(c);
break;
newsql.append(c);
break;
case BACKSLASH:
state = IN_STRING;
case BACKSLASH:
state = IN_STRING;
newsql.append(c);
break;
newsql.append(c);
break;
case ESC_TIMEDATE:
if(c == '}')
state = IN_SQLCODE; // end of escape code.
else
newsql.append(c);
break;
} // end switch
}
case ESC_TIMEDATE:
if (c == '}')
state = IN_SQLCODE; // end of escape code.
else
newsql.append(c);
break;
} // end switch
}
return newsql.toString();
}
return newsql.toString();
}
}

View File

@ -4,92 +4,98 @@ package org.postgresql.core;
* A simple and efficient class to pool one dimensional byte arrays
* of different sizes.
*/
public class BytePoolDim1 {
public class BytePoolDim1
{
/**
* The maximum size of the array we manage.
*/
int maxsize = 256;
/**
* The pools not currently in use
*/
ObjectPool notusemap[] = new ObjectPool[maxsize+1];
/**
* The pools currently in use
*/
ObjectPool inusemap[] = new ObjectPool[maxsize+1];
/**
*
*/
byte binit[][] = new byte[maxsize+1][0];
/**
* The maximum size of the array we manage.
*/
int maxsize = 256;
/**
* The pools not currently in use
*/
ObjectPool notusemap[] = new ObjectPool[maxsize + 1];
/**
* The pools currently in use
*/
ObjectPool inusemap[] = new ObjectPool[maxsize + 1];
/**
*
*/
byte binit[][] = new byte[maxsize + 1][0];
/**
* Construct a new pool
*/
public BytePoolDim1(){
for(int i = 0; i <= maxsize; i++){
binit[i] = new byte[i];
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
}
}
/**
* Allocate a byte[] of a specified size and put it in the pool. If it's
* larger than maxsize then it is not pooled.
* @return the byte[] allocated
*/
public byte[] allocByte(int size) {
// for now until the bug can be removed
return new byte[size];
/*
// Don't pool if >maxsize
if(size > maxsize){
return new byte[size];
/**
* Construct a new pool
*/
public BytePoolDim1()
{
for (int i = 0; i <= maxsize; i++)
{
binit[i] = new byte[i];
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
}
}
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[] = null;
/**
* Allocate a byte[] of a specified size and put it in the pool. If it's
* larger than maxsize then it is not pooled.
* @return the byte[] allocated
*/
public byte[] allocByte(int size)
{
// for now until the bug can be removed
return new byte[size];
/*
// Don't pool if >maxsize
if(size > maxsize){
return new byte[size];
}
// Fetch from the unused pool if available otherwise allocate a new
// now array
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[]) o;
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[] = null;
// Fetch from the unused pool if available otherwise allocate a new
// now array
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[]) o;
} else
b = new byte[size];
in_usel.add(b);
b = new byte[size];
in_usel.add(b);
return b;
*/
}
return b;
*/
}
/**
* Release an array
* @param b byte[] to release
*/
public void release(byte[] b) {
// If it's larger than maxsize then we don't touch it
if(b.length>maxsize)
return;
/**
* Release an array
* @param b byte[] to release
*/
public void release(byte[] b)
{
// If it's larger than maxsize then we don't touch it
if (b.length > maxsize)
return ;
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
in_usel.remove(b);
not_usel.add(b);
}
in_usel.remove(b);
not_usel.add(b);
}
/**
* Deallocate all
* @deprecated Real bad things happen if this is called!
*/
public void deallocate() {
//for(int i = 0; i <= maxsize; i++){
// notusemap[i].addAll(inusemap[i]);
// inusemap[i].clear();
//}
}
/**
* Deallocate all
* @deprecated Real bad things happen if this is called!
*/
public void deallocate()
{
//for(int i = 0; i <= maxsize; i++){
// notusemap[i].addAll(inusemap[i]);
// inusemap[i].clear();
//}
}
}

View File

@ -1,62 +1,69 @@
package org.postgresql.core;
public class BytePoolDim2 {
int maxsize = 32;
ObjectPool notusemap[] = new ObjectPool[maxsize+1];
ObjectPool inusemap[] = new ObjectPool[maxsize+1];
public class BytePoolDim2
{
int maxsize = 32;
ObjectPool notusemap[] = new ObjectPool[maxsize + 1];
ObjectPool inusemap[] = new ObjectPool[maxsize + 1];
public BytePoolDim2(){
for(int i = 0; i <= maxsize; i++){
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
public BytePoolDim2()
{
for (int i = 0; i <= maxsize; i++)
{
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
}
}
}
public byte[][] allocByte(int size){
// For now until the bug can be removed
return new byte[size][0];
/*
if(size > maxsize){
return new byte[size][0];
public byte[][] allocByte(int size)
{
// For now until the bug can be removed
return new byte[size][0];
/*
if(size > maxsize){
return new byte[size][0];
}
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[][] = null;
byte b[][] = null;
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[][]) o;
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[][]) o;
} else
b = new byte[size][0];
in_usel.add(b);
return b;
*/
}
public void release(byte[][] b){
if(b.length > maxsize){
return;
b = new byte[size][0];
in_usel.add(b);
return b;
*/
}
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
in_usel.remove(b);
not_usel.add(b);
}
public void release(byte[][] b)
{
if (b.length > maxsize)
{
return ;
}
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
/**
* Deallocate the object cache.
* PM 17/01/01: Commented out this code as it blows away any hope of
* multiple queries on the same connection. I'll redesign the allocation
* code to use some form of Statement context, so the buffers are per
* Statement and not per Connection/PG_Stream as it is now.
*/
public void deallocate(){
//for(int i = 0; i <= maxsize; i++){
// notusemap[i].addAll(inusemap[i]);
// inusemap[i].clear();
//}
}
in_usel.remove(b);
not_usel.add(b);
}
/**
* Deallocate the object cache.
* PM 17/01/01: Commented out this code as it blows away any hope of
* multiple queries on the same connection. I'll redesign the allocation
* code to use some form of Statement context, so the buffers are per
* Statement and not per Connection/PG_Stream as it is now.
*/
public void deallocate()
{
//for(int i = 0; i <= maxsize; i++){
// notusemap[i].addAll(inusemap[i]);
// inusemap[i].clear();
//}
}
}

View File

@ -8,173 +8,213 @@ import org.postgresql.util.*;
/**
* Converts to and from the character encoding used by the backend.
*
* $Id: Encoding.java,v 1.2 2001/10/16 20:07:17 barry Exp $
* $Id: Encoding.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*/
public class Encoding {
public class Encoding
{
private static final Encoding DEFAULT_ENCODING = new Encoding(null);
private static final Encoding DEFAULT_ENCODING = new Encoding(null);
/**
* Preferred JVM encodings for backend encodings.
*/
private static final Hashtable encodings = new Hashtable();
/**
* Preferred JVM encodings for backend encodings.
*/
private static final Hashtable encodings = new Hashtable();
static {
//Note: this list should match the set of supported server
// encodings found in backend/util/mb/encnames.c
encodings.put("SQL_ASCII", new String[] { "ASCII", "us-ascii" });
encodings.put("UNICODE", new String[] { "UTF-8", "UTF8" });
encodings.put("LATIN1", new String[] { "ISO8859_1" });
encodings.put("LATIN2", new String[] { "ISO8859_2" });
encodings.put("LATIN3", new String[] { "ISO8859_3" });
encodings.put("LATIN4", new String[] { "ISO8859_4" });
encodings.put("ISO_8859_5", new String[] { "ISO8859_5" });
encodings.put("ISO_8859_6", new String[] { "ISO8859_6" });
encodings.put("ISO_8859_7", new String[] { "ISO8859_7" });
encodings.put("ISO_8859_8", new String[] { "ISO8859_8" });
encodings.put("LATIN5", new String[] { "ISO8859_9" });
encodings.put("LATIN7", new String[] { "ISO8859_13" });
encodings.put("LATIN9", new String[] { "ISO8859_15_FDIS" });
encodings.put("EUC_JP", new String[] { "EUC_JP" });
encodings.put("EUC_CN", new String[] { "EUC_CN" });
encodings.put("EUC_KR", new String[] { "EUC_KR" });
encodings.put("EUC_TW", new String[] { "EUC_TW" });
encodings.put("SJIS", new String[] { "SJIS" });
encodings.put("BIG5", new String[] { "Big5" });
encodings.put("WIN1250", new String[] { "Cp1250" });
encodings.put("WIN", new String[] { "Cp1251" });
encodings.put("ALT", new String[] { "Cp866" });
// We prefer KOI8-U, since it is a superset of KOI8-R.
encodings.put("KOI8", new String[] { "KOI8_U", "KOI8_R" });
// If the database isn't encoding-aware then we can't have
// any preferred encodings.
encodings.put("UNKNOWN", new String[0]);
// The following encodings do not have a java equivalent
encodings.put("MULE_INTERNAL", new String[0]);
encodings.put("LATIN6", new String[0]);
encodings.put("LATIN8", new String[0]);
encodings.put("LATIN10", new String[0]);
}
private final String encoding;
private Encoding(String encoding) {
this.encoding = encoding;
}
/**
* Get an Encoding for from the given database encoding and
* the encoding passed in by the user.
*/
public static Encoding getEncoding(String databaseEncoding,
String passedEncoding)
{
if (passedEncoding != null) {
if (isAvailable(passedEncoding)) {
return new Encoding(passedEncoding);
} else {
return defaultEncoding();
}
} else {
return encodingForDatabaseEncoding(databaseEncoding);
static {
//Note: this list should match the set of supported server
// encodings found in backend/util/mb/encnames.c
encodings.put("SQL_ASCII", new String[] { "ASCII", "us-ascii" });
encodings.put("UNICODE", new String[] { "UTF-8", "UTF8" });
encodings.put("LATIN1", new String[] { "ISO8859_1" });
encodings.put("LATIN2", new String[] { "ISO8859_2" });
encodings.put("LATIN3", new String[] { "ISO8859_3" });
encodings.put("LATIN4", new String[] { "ISO8859_4" });
encodings.put("ISO_8859_5", new String[] { "ISO8859_5" });
encodings.put("ISO_8859_6", new String[] { "ISO8859_6" });
encodings.put("ISO_8859_7", new String[] { "ISO8859_7" });
encodings.put("ISO_8859_8", new String[] { "ISO8859_8" });
encodings.put("LATIN5", new String[] { "ISO8859_9" });
encodings.put("LATIN7", new String[] { "ISO8859_13" });
encodings.put("LATIN9", new String[] { "ISO8859_15_FDIS" });
encodings.put("EUC_JP", new String[] { "EUC_JP" });
encodings.put("EUC_CN", new String[] { "EUC_CN" });
encodings.put("EUC_KR", new String[] { "EUC_KR" });
encodings.put("EUC_TW", new String[] { "EUC_TW" });
encodings.put("SJIS", new String[] { "SJIS" });
encodings.put("BIG5", new String[] { "Big5" });
encodings.put("WIN1250", new String[] { "Cp1250" });
encodings.put("WIN", new String[] { "Cp1251" });
encodings.put("ALT", new String[] { "Cp866" });
// We prefer KOI8-U, since it is a superset of KOI8-R.
encodings.put("KOI8", new String[] { "KOI8_U", "KOI8_R" });
// If the database isn't encoding-aware then we can't have
// any preferred encodings.
encodings.put("UNKNOWN", new String[0]);
// The following encodings do not have a java equivalent
encodings.put("MULE_INTERNAL", new String[0]);
encodings.put("LATIN6", new String[0]);
encodings.put("LATIN8", new String[0]);
encodings.put("LATIN10", new String[0]);
}
}
/**
* Get an Encoding matching the given database encoding.
*/
private static Encoding encodingForDatabaseEncoding(String databaseEncoding) {
// If the backend encoding is known and there is a suitable
// encoding in the JVM we use that. Otherwise we fall back
// to the default encoding of the JVM.
private final String encoding;
if (encodings.containsKey(databaseEncoding)) {
String[] candidates = (String[]) encodings.get(databaseEncoding);
for (int i = 0; i < candidates.length; i++) {
if (isAvailable(candidates[i])) {
return new Encoding(candidates[i]);
private Encoding(String encoding)
{
this.encoding = encoding;
}
/**
* Get an Encoding for from the given database encoding and
* the encoding passed in by the user.
*/
public static Encoding getEncoding(String databaseEncoding,
String passedEncoding)
{
if (passedEncoding != null)
{
if (isAvailable(passedEncoding))
{
return new Encoding(passedEncoding);
}
else
{
return defaultEncoding();
}
}
else
{
return encodingForDatabaseEncoding(databaseEncoding);
}
}
}
return defaultEncoding();
}
/**
* Name of the (JVM) encoding used.
*/
public String name() {
return encoding;
}
/**
* Get an Encoding matching the given database encoding.
*/
private static Encoding encodingForDatabaseEncoding(String databaseEncoding)
{
// If the backend encoding is known and there is a suitable
// encoding in the JVM we use that. Otherwise we fall back
// to the default encoding of the JVM.
/**
* Encode a string to an array of bytes.
*/
public byte[] encode(String s) throws SQLException {
try {
if (encoding == null) {
return s.getBytes();
} else {
return s.getBytes(encoding);
}
} catch (UnsupportedEncodingException e) {
throw new PSQLException("postgresql.stream.encoding", e);
if (encodings.containsKey(databaseEncoding))
{
String[] candidates = (String[]) encodings.get(databaseEncoding);
for (int i = 0; i < candidates.length; i++)
{
if (isAvailable(candidates[i]))
{
return new Encoding(candidates[i]);
}
}
}
return defaultEncoding();
}
}
/**
* Decode an array of bytes into a string.
*/
public String decode(byte[] encodedString, int offset, int length) throws SQLException {
try {
if (encoding == null) {
return new String(encodedString, offset, length);
} else {
return new String(encodedString, offset, length, encoding);
}
} catch (UnsupportedEncodingException e) {
throw new PSQLException("postgresql.stream.encoding", e);
/**
* Name of the (JVM) encoding used.
*/
public String name()
{
return encoding;
}
}
/**
* Decode an array of bytes into a string.
*/
public String decode(byte[] encodedString) throws SQLException {
return decode(encodedString, 0, encodedString.length);
}
/**
* Get a Reader that decodes the given InputStream.
*/
public Reader getDecodingReader(InputStream in) throws SQLException {
try {
if (encoding == null) {
return new InputStreamReader(in);
} else {
return new InputStreamReader(in, encoding);
}
} catch (UnsupportedEncodingException e) {
throw new PSQLException("postgresql.res.encoding", e);
/**
* Encode a string to an array of bytes.
*/
public byte[] encode(String s) throws SQLException
{
try
{
if (encoding == null)
{
return s.getBytes();
}
else
{
return s.getBytes(encoding);
}
}
catch (UnsupportedEncodingException e)
{
throw new PSQLException("postgresql.stream.encoding", e);
}
}
}
/**
* Get an Encoding using the default encoding for the JVM.
*/
public static Encoding defaultEncoding() {
return DEFAULT_ENCODING;
}
/**
* Test if an encoding is available in the JVM.
*/
private static boolean isAvailable(String encodingName) {
try {
"DUMMY".getBytes(encodingName);
return true;
} catch (UnsupportedEncodingException e) {
return false;
/**
* Decode an array of bytes into a string.
*/
public String decode(byte[] encodedString, int offset, int length) throws SQLException
{
try
{
if (encoding == null)
{
return new String(encodedString, offset, length);
}
else
{
return new String(encodedString, offset, length, encoding);
}
}
catch (UnsupportedEncodingException e)
{
throw new PSQLException("postgresql.stream.encoding", e);
}
}
/**
* Decode an array of bytes into a string.
*/
public String decode(byte[] encodedString) throws SQLException
{
return decode(encodedString, 0, encodedString.length);
}
/**
* Get a Reader that decodes the given InputStream.
*/
public Reader getDecodingReader(InputStream in) throws SQLException
{
try
{
if (encoding == null)
{
return new InputStreamReader(in);
}
else
{
return new InputStreamReader(in, encoding);
}
}
catch (UnsupportedEncodingException e)
{
throw new PSQLException("postgresql.res.encoding", e);
}
}
/**
* Get an Encoding using the default encoding for the JVM.
*/
public static Encoding defaultEncoding()
{
return DEFAULT_ENCODING;
}
/**
* Test if an encoding is available in the JVM.
*/
private static boolean isAvailable(String encodingName)
{
try
{
"DUMMY".getBytes(encodingName);
return true;
}
catch (UnsupportedEncodingException e)
{
return false;
}
}
}
}

View File

@ -3,16 +3,17 @@ package org.postgresql.core;
/**
* This interface defines the methods to access the memory pool classes.
*/
public interface MemoryPool {
/**
* Allocate an array from the pool
* @return byte[] allocated
*/
public byte[] allocByte(int size);
public interface MemoryPool
{
/**
* Allocate an array from the pool
* @return byte[] allocated
*/
public byte[] allocByte(int size);
/**
* Frees an object back to the pool
* @param o Object to release
*/
public void release(Object o);
}
/**
* Frees an object back to the pool
* @param o Object to release
*/
public void release(Object o);
}

View File

@ -6,43 +6,44 @@ package org.postgresql.core;
* other for jdk1.2+
*/
public interface ObjectPool {
/**
* Adds an object to the pool
* @param o Object to add
*/
public void add(Object o);
public interface ObjectPool
{
/**
* Adds an object to the pool
* @param o Object to add
*/
public void add(Object o);
/**
* Removes an object from the pool
* @param o Object to remove
*/
public void remove(Object o);
/**
* Removes an object from the pool
* @param o Object to remove
*/
public void remove(Object o);
/**
* Removes the top object from the pool
* @return Object from the top.
*/
public Object remove();
/**
* Removes the top object from the pool
* @return Object from the top.
*/
public Object remove();
/**
* @return true if the pool is empty
*/
public boolean isEmpty();
/**
* @return true if the pool is empty
*/
public boolean isEmpty();
/**
* @return the number of objects in the pool
*/
public int size();
/**
* @return the number of objects in the pool
*/
public int size();
/**
* Adds all objects in one pool to this one
* @param pool The pool to take the objects from
*/
public void addAll(ObjectPool pool);
/**
* Adds all objects in one pool to this one
* @param pool The pool to take the objects from
*/
public void addAll(ObjectPool pool);
/**
* Clears the pool of all objects
*/
public void clear();
/**
* Clears the pool of all objects
*/
public void clear();
}

View File

@ -13,176 +13,195 @@ import org.postgresql.util.PSQLException;
* <p>The lifetime of a QueryExecutor object is from sending the query
* until the response has been received from the backend.
*
* $Id: QueryExecutor.java,v 1.2 2001/10/09 20:47:35 barry Exp $
* $Id: QueryExecutor.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*/
public class QueryExecutor {
public class QueryExecutor
{
private final String sql;
private final java.sql.Statement statement;
private final PG_Stream pg_stream;
private final org.postgresql.Connection connection;
private final String sql;
private final java.sql.Statement statement;
private final PG_Stream pg_stream;
private final org.postgresql.Connection connection;
public QueryExecutor(String sql,
java.sql.Statement statement,
PG_Stream pg_stream,
org.postgresql.Connection connection)
throws SQLException
{
this.sql = sql;
this.statement = statement;
this.pg_stream = pg_stream;
this.connection = connection;
public QueryExecutor(String sql,
java.sql.Statement statement,
PG_Stream pg_stream,
org.postgresql.Connection connection)
throws SQLException
{
this.sql = sql;
this.statement = statement;
this.pg_stream = pg_stream;
this.connection = connection;
if (statement != null)
maxRows = statement.getMaxRows();
else
maxRows = 0;
}
if (statement != null)
maxRows = statement.getMaxRows();
else
maxRows = 0;
}
private Field[] fields = null;
private Vector tuples = new Vector();
private boolean binaryCursor = false;
private String status = null;
private int update_count = 1;
private int insert_oid = 0;
private int maxRows;
private Field[] fields = null;
private Vector tuples = new Vector();
private boolean binaryCursor = false;
private String status = null;
private int update_count = 1;
private int insert_oid = 0;
private int maxRows;
/**
* Execute a query on the backend.
*/
public java.sql.ResultSet execute() throws SQLException {
/**
* Execute a query on the backend.
*/
public java.sql.ResultSet execute() throws SQLException
{
int fqp = 0;
boolean hfr = false;
int fqp = 0;
boolean hfr = false;
synchronized(pg_stream) {
synchronized (pg_stream)
{
sendQuery(sql);
sendQuery(sql);
while (!hfr || fqp > 0) {
int c = pg_stream.ReceiveChar();
while (!hfr || fqp > 0)
{
int c = pg_stream.ReceiveChar();
switch (c)
{
case 'A': // Asynchronous Notify
int pid = pg_stream.ReceiveInteger(4);
String msg = pg_stream.ReceiveString(connection.getEncoding());
break;
case 'B': // Binary Data Transfer
receiveTuple(true);
break;
case 'C': // Command Status
receiveCommandStatus();
switch (c)
{
case 'A': // Asynchronous Notify
int pid = pg_stream.ReceiveInteger(4);
String msg = pg_stream.ReceiveString(connection.getEncoding());
break;
case 'B': // Binary Data Transfer
receiveTuple(true);
break;
case 'C': // Command Status
receiveCommandStatus();
if (fields != null)
hfr = true;
else {
sendQuery(" ");
fqp++;
}
break;
case 'D': // Text Data Transfer
receiveTuple(false);
break;
case 'E': // Error Message
throw new SQLException(pg_stream.ReceiveString(connection.getEncoding()));
case 'I': // Empty Query
int t = pg_stream.ReceiveChar();
if (t != 0)
throw new PSQLException("postgresql.con.garbled");
if (fields != null)
hfr = true;
else
{
sendQuery(" ");
fqp++;
}
break;
case 'D': // Text Data Transfer
receiveTuple(false);
break;
case 'E': // Error Message
throw new SQLException(pg_stream.ReceiveString(connection.getEncoding()));
case 'I': // Empty Query
int t = pg_stream.ReceiveChar();
if (t != 0)
throw new PSQLException("postgresql.con.garbled");
if (fqp > 0)
fqp--;
if (fqp == 0)
hfr = true;
break;
case 'N': // Error Notification
connection.addWarning(pg_stream.ReceiveString(connection.getEncoding()));
break;
case 'P': // Portal Name
String pname = pg_stream.ReceiveString(connection.getEncoding());
break;
case 'T': // MetaData Field Description
receiveFields();
break;
case 'Z': // backend ready for query, ignore for now :-)
break;
default:
throw new PSQLException("postgresql.con.type",
new Character((char) c));
}
}
return connection.getResultSet(connection, statement, fields, tuples, status, update_count, insert_oid, binaryCursor);
}
}
if (fqp > 0)
fqp--;
if (fqp == 0)
hfr = true;
break;
case 'N': // Error Notification
connection.addWarning(pg_stream.ReceiveString(connection.getEncoding()));
break;
case 'P': // Portal Name
String pname = pg_stream.ReceiveString(connection.getEncoding());
break;
case 'T': // MetaData Field Description
receiveFields();
break;
case 'Z': // backend ready for query, ignore for now :-)
break;
default:
throw new PSQLException("postgresql.con.type",
new Character((char) c));
}
}
return connection.getResultSet(connection, statement, fields, tuples, status, update_count, insert_oid, binaryCursor);
}
}
/**
* Send a query to the backend.
*/
private void sendQuery(String query) throws SQLException {
try {
pg_stream.SendChar('Q');
pg_stream.Send(connection.getEncoding().encode(query));
pg_stream.SendChar(0);
pg_stream.flush();
/**
* Send a query to the backend.
*/
private void sendQuery(String query) throws SQLException
{
try
{
pg_stream.SendChar('Q');
pg_stream.Send(connection.getEncoding().encode(query));
pg_stream.SendChar(0);
pg_stream.flush();
} catch (IOException e) {
throw new PSQLException("postgresql.con.ioerror", e);
}
}
}
catch (IOException e)
{
throw new PSQLException("postgresql.con.ioerror", e);
}
}
/**
* Receive a tuple from the backend.
*
* @param isBinary set if the tuple should be treated as binary data
*/
private void receiveTuple(boolean isBinary) throws SQLException {
if (fields == null)
throw new PSQLException("postgresql.con.tuple");
Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary);
if (isBinary) binaryCursor = true;
if (maxRows == 0 || tuples.size() < maxRows)
tuples.addElement(tuple);
}
/**
* Receive a tuple from the backend.
*
* @param isBinary set if the tuple should be treated as binary data
*/
private void receiveTuple(boolean isBinary) throws SQLException
{
if (fields == null)
throw new PSQLException("postgresql.con.tuple");
Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary);
if (isBinary)
binaryCursor = true;
if (maxRows == 0 || tuples.size() < maxRows)
tuples.addElement(tuple);
}
/**
* Receive command status from the backend.
*/
private void receiveCommandStatus() throws SQLException {
/**
* Receive command status from the backend.
*/
private void receiveCommandStatus() throws SQLException
{
status = pg_stream.ReceiveString(connection.getEncoding());
status = pg_stream.ReceiveString(connection.getEncoding());
try {
// Now handle the update count correctly.
if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE")) {
update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' ')));
}
if (status.startsWith("INSERT")) {
insert_oid = Integer.parseInt(status.substring(1 + status.indexOf(' '),
status.lastIndexOf(' ')));
}
} catch (NumberFormatException nfe) {
throw new PSQLException("postgresql.con.fathom", status);
}
}
try
{
// Now handle the update count correctly.
if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE"))
{
update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' ')));
}
if (status.startsWith("INSERT"))
{
insert_oid = Integer.parseInt(status.substring(1 + status.indexOf(' '),
status.lastIndexOf(' ')));
}
}
catch (NumberFormatException nfe)
{
throw new PSQLException("postgresql.con.fathom", status);
}
}
/**
* Receive the field descriptions from the back end.
*/
private void receiveFields() throws SQLException {
if (fields != null)
throw new PSQLException("postgresql.con.multres");
/**
* Receive the field descriptions from the back end.
*/
private void receiveFields() throws SQLException
{
if (fields != null)
throw new PSQLException("postgresql.con.multres");
int size = pg_stream.ReceiveIntegerR(2);
fields = new Field[size];
int size = pg_stream.ReceiveIntegerR(2);
fields = new Field[size];
for (int i = 0; i < fields.length; i++) {
String typeName = pg_stream.ReceiveString(connection.getEncoding());
int typeOid = pg_stream.ReceiveIntegerR(4);
int typeLength = pg_stream.ReceiveIntegerR(2);
int typeModifier = pg_stream.ReceiveIntegerR(4);
fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier);
}
}
for (int i = 0; i < fields.length; i++)
{
String typeName = pg_stream.ReceiveString(connection.getEncoding());
int typeOid = pg_stream.ReceiveIntegerR(4);
int typeLength = pg_stream.ReceiveIntegerR(2);
int typeModifier = pg_stream.ReceiveIntegerR(4);
fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier);
}
}
}

View File

@ -8,90 +8,99 @@ package org.postgresql.core;
public class SimpleObjectPool implements ObjectPool
{
// This was originally in PG_Stream but moved out to fix the major problem
// where more than one query (usually all the time) overwrote the results
// of another query.
int cursize = 0;
int maxsize = 16;
Object arr[] = new Object[maxsize];
// This was originally in PG_Stream but moved out to fix the major problem
// where more than one query (usually all the time) overwrote the results
// of another query.
int cursize = 0;
int maxsize = 16;
Object arr[] = new Object[maxsize];
/**
* Adds an object to the pool
* @param o Object to add
*/
public void add(Object o)
{
if(cursize >= maxsize){
Object newarr[] = new Object[maxsize*2];
System.arraycopy(arr, 0, newarr, 0, maxsize);
maxsize = maxsize * 2;
arr = newarr;
/**
* Adds an object to the pool
* @param o Object to add
*/
public void add(Object o)
{
if (cursize >= maxsize)
{
Object newarr[] = new Object[maxsize * 2];
System.arraycopy(arr, 0, newarr, 0, maxsize);
maxsize = maxsize * 2;
arr = newarr;
}
arr[cursize++] = o;
}
arr[cursize++] = o;
}
/**
* Removes the top object from the pool
* @return Object from the top.
*/
public Object remove(){
return arr[--cursize];
}
/**
* Removes the given object from the pool
* @param o Object to remove
*/
public void remove(Object o) {
int p=0;
while(p<cursize && !arr[p].equals(o))
p++;
if(arr[p].equals(o)) {
// This should be ok as there should be no overlap conflict
System.arraycopy(arr,p+1,arr,p,cursize-p);
cursize--;
}
}
/**
* @return true if the pool is empty
*/
public boolean isEmpty(){
return cursize == 0;
}
/**
* @return the number of objects in the pool
*/
public int size(){
return cursize;
}
/**
* Adds all objects in one pool to this one
* @param pool The pool to take the objects from
*/
public void addAll(ObjectPool p){
SimpleObjectPool pool = (SimpleObjectPool)p;
int srcsize = pool.size();
if(srcsize == 0)
return;
int totalsize = srcsize + cursize;
if(totalsize > maxsize){
Object newarr[] = new Object[totalsize*2];
System.arraycopy(arr, 0, newarr, 0, cursize);
maxsize = maxsize = totalsize * 2;
arr = newarr;
/**
* Removes the top object from the pool
* @return Object from the top.
*/
public Object remove()
{
return arr[--cursize];
}
System.arraycopy(pool.arr, 0, arr, cursize, srcsize);
cursize = totalsize;
}
/**
* Clears the pool of all objects
*/
public void clear(){
cursize = 0;
}
/**
* Removes the given object from the pool
* @param o Object to remove
*/
public void remove(Object o)
{
int p = 0;
while (p < cursize && !arr[p].equals(o))
p++;
if (arr[p].equals(o))
{
// This should be ok as there should be no overlap conflict
System.arraycopy(arr, p + 1, arr, p, cursize - p);
cursize--;
}
}
/**
* @return true if the pool is empty
*/
public boolean isEmpty()
{
return cursize == 0;
}
/**
* @return the number of objects in the pool
*/
public int size()
{
return cursize;
}
/**
* Adds all objects in one pool to this one
* @param pool The pool to take the objects from
*/
public void addAll(ObjectPool p)
{
SimpleObjectPool pool = (SimpleObjectPool)p;
int srcsize = pool.size();
if (srcsize == 0)
return ;
int totalsize = srcsize + cursize;
if (totalsize > maxsize)
{
Object newarr[] = new Object[totalsize * 2];
System.arraycopy(arr, 0, newarr, 0, cursize);
maxsize = maxsize = totalsize * 2;
arr = newarr;
}
System.arraycopy(pool.arr, 0, arr, cursize, srcsize);
cursize = totalsize;
}
/**
* Clears the pool of all objects
*/
public void clear()
{
cursize = 0;
}
}

View File

@ -23,266 +23,273 @@ import org.postgresql.util.*;
*/
public class Fastpath
{
// This maps the functions names to their id's (possible unique just
// to a connection).
protected Hashtable func = new Hashtable();
protected org.postgresql.Connection conn; // our connection
protected org.postgresql.PG_Stream stream; // the network stream
/**
* Initialises the fastpath system
*
* <p><b>Important Notice</b>
* <br>This is called from org.postgresql.Connection, and should not be called
* from client code.
*
* @param conn org.postgresql.Connection to attach to
* @param stream The network stream to the backend
*/
public Fastpath(org.postgresql.Connection conn,org.postgresql.PG_Stream stream)
{
this.conn=conn;
this.stream=stream;
//DriverManager.println("Fastpath initialised");
}
/**
* Send a function call to the PostgreSQL backend
*
* @param fnid Function id
* @param resulttype True if the result is an integer, false for other results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if a database-access error occurs.
*/
public Object fastpath(int fnid,boolean resulttype,FastpathArg[] args) throws SQLException
{
// added Oct 7 1998 to give us thread safety
synchronized(stream) {
// send the function call
try {
// 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
// that confuses the backend. The 0 terminates the command line.
stream.SendInteger(70,1);
stream.SendInteger(0,1);
// This maps the functions names to their id's (possible unique just
// to a connection).
protected Hashtable func = new Hashtable();
stream.SendInteger(fnid,4);
stream.SendInteger(args.length,4);
for(int i=0;i<args.length;i++)
args[i].send(stream);
// This is needed, otherwise data can be lost
stream.flush();
} catch(IOException ioe) {
throw new PSQLException("postgresql.fp.send",new Integer(fnid),ioe);
}
// Now handle the result
// We should get 'V' on sucess or 'E' on error. Anything else is treated
// as an error.
//int in = stream.ReceiveChar();
//DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
//if(in!='V') {
//if(in=='E')
//throw new SQLException(stream.ReceiveString(conn.getEncoding()));
//throw new SQLException("Fastpath: expected 'V' from backend, got "+((char)in));
//}
// Now loop, reading the results
Object result = null; // our result
while(true) {
int in = stream.ReceiveChar();
//DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
switch(in)
protected org.postgresql.Connection conn; // our connection
protected org.postgresql.PG_Stream stream; // the network stream
/**
* Initialises the fastpath system
*
* <p><b>Important Notice</b>
* <br>This is called from org.postgresql.Connection, and should not be called
* from client code.
*
* @param conn org.postgresql.Connection to attach to
* @param stream The network stream to the backend
*/
public Fastpath(org.postgresql.Connection conn, org.postgresql.PG_Stream stream)
{
case 'V':
break;
//------------------------------
// Function returned properly
//
case 'G':
int sz = stream.ReceiveIntegerR(4);
//DriverManager.println("G: size="+sz); //debug
// Return an Integer if
if(resulttype)
result = new Integer(stream.ReceiveIntegerR(sz));
else {
byte buf[] = new byte[sz];
stream.Receive(buf,0,sz);
result = buf;
}
break;
//------------------------------
// Error message returned
case 'E':
throw new PSQLException("postgresql.fp.error",stream.ReceiveString(conn.getEncoding()));
//------------------------------
// Notice from backend
case 'N':
conn.addWarning(stream.ReceiveString(conn.getEncoding()));
break;
//------------------------------
// End of results
//
// Here we simply return res, which would contain the result
// processed earlier. If no result, this already contains null
case '0':
//DriverManager.println("returning "+result);
return result;
case 'Z':
break;
default:
throw new PSQLException("postgresql.fp.protocol",new Character((char)in));
this.conn = conn;
this.stream = stream;
//DriverManager.println("Fastpath initialised");
}
/**
* Send a function call to the PostgreSQL backend
*
* @param fnid Function id
* @param resulttype True if the result is an integer, false for other results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if a database-access error occurs.
*/
public Object fastpath(int fnid, boolean resulttype, FastpathArg[] args) throws SQLException
{
// added Oct 7 1998 to give us thread safety
synchronized (stream)
{
// send the function call
try
{
// 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
// that confuses the backend. The 0 terminates the command line.
stream.SendInteger(70, 1);
stream.SendInteger(0, 1);
stream.SendInteger(fnid, 4);
stream.SendInteger(args.length, 4);
for (int i = 0;i < args.length;i++)
args[i].send(stream);
// This is needed, otherwise data can be lost
stream.flush();
}
catch (IOException ioe)
{
throw new PSQLException("postgresql.fp.send", new Integer(fnid), ioe);
}
// Now handle the result
// We should get 'V' on sucess or 'E' on error. Anything else is treated
// as an error.
//int in = stream.ReceiveChar();
//DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
//if(in!='V') {
//if(in=='E')
//throw new SQLException(stream.ReceiveString(conn.getEncoding()));
//throw new SQLException("Fastpath: expected 'V' from backend, got "+((char)in));
//}
// Now loop, reading the results
Object result = null; // our result
while (true)
{
int in = stream.ReceiveChar();
//DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
switch (in)
{
case 'V':
break;
//------------------------------
// Function returned properly
//
case 'G':
int sz = stream.ReceiveIntegerR(4);
//DriverManager.println("G: size="+sz); //debug
// Return an Integer if
if (resulttype)
result = new Integer(stream.ReceiveIntegerR(sz));
else
{
byte buf[] = new byte[sz];
stream.Receive(buf, 0, sz);
result = buf;
}
break;
//------------------------------
// Error message returned
case 'E':
throw new PSQLException("postgresql.fp.error", stream.ReceiveString(conn.getEncoding()));
//------------------------------
// Notice from backend
case 'N':
conn.addWarning(stream.ReceiveString(conn.getEncoding()));
break;
//------------------------------
// End of results
//
// Here we simply return res, which would contain the result
// processed earlier. If no result, this already contains null
case '0':
//DriverManager.println("returning "+result);
return result;
case 'Z':
break;
default:
throw new PSQLException("postgresql.fp.protocol", new Character((char)in));
}
}
}
}
/**
* Send a function call to the PostgreSQL backend by name.
*
* Note: the mapping for the procedure name to function id needs to exist,
* usually to an earlier call to addfunction().
*
* This is the prefered method to call, as function id's can/may change
* between versions of the backend.
*
* For an example of how this works, refer to org.postgresql.LargeObject
*
* @param name Function name
* @param resulttype True if the result is an integer, false for other
* results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if name is unknown or if a database-access error
* occurs.
* @see org.postgresql.LargeObject
*/
public Object fastpath(String name, boolean resulttype, FastpathArg[] args) throws SQLException
{
//DriverManager.println("Fastpath: calling "+name);
return fastpath(getID(name), resulttype, args);
}
/**
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return integer result
* @exception SQLException if a database-access error occurs or no result
*/
public int getInteger(String name, FastpathArg[] args) throws SQLException
{
Integer i = (Integer)fastpath(name, true, args);
if (i == null)
throw new PSQLException("postgresql.fp.expint", name);
return i.intValue();
}
/**
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return byte[] array containing result
* @exception SQLException if a database-access error occurs or no result
*/
public byte[] getData(String name, FastpathArg[] args) throws SQLException
{
return (byte[])fastpath(name, false, args);
}
/**
* This adds a function to our lookup table.
*
* <p>User code should use the addFunctions method, which is based upon a
* query, rather than hard coding the oid. The oid for a function is not
* guaranteed to remain static, even on different servers of the same
* version.
*
* @param name Function name
* @param fnid Function id
*/
public void addFunction(String name, int fnid)
{
func.put(name, new Integer(fnid));
}
/**
* This takes a ResultSet containing two columns. Column 1 contains the
* function name, Column 2 the oid.
*
* <p>It reads the entire ResultSet, loading the values into the function
* table.
*
* <p><b>REMEMBER</b> to close() the resultset after calling this!!
*
* <p><b><em>Implementation note about function name lookups:</em></b>
*
* <p>PostgreSQL stores the function id's and their corresponding names in
* the pg_proc table. To speed things up locally, instead of querying each
* function from that table when required, a Hashtable is used. Also, only
* the function's required are entered into this table, keeping connection
* times as fast as possible.
*
* <p>The org.postgresql.LargeObject class performs a query upon it's startup,
* and passes the returned ResultSet to the addFunctions() method here.
*
* <p>Once this has been done, the LargeObject api refers to the functions by
* name.
*
* <p>Dont think that manually converting them to the oid's will work. Ok,
* they will for now, but they can change during development (there was some
* discussion about this for V7.0), so this is implemented to prevent any
* unwarranted headaches in the future.
*
* @param rs ResultSet
* @exception SQLException if a database-access error occurs.
* @see org.postgresql.LargeObjectManager
*/
public void addFunctions(ResultSet rs) throws SQLException
{
while (rs.next())
{
func.put(rs.getString(1), new Integer(rs.getInt(2)));
}
}
/**
* This returns the function id associated by its name
*
* <p>If addFunction() or addFunctions() have not been called for this name,
* then an SQLException is thrown.
*
* @param name Function name to lookup
* @return Function ID for fastpath call
* @exception SQLException is function is unknown.
*/
public int getID(String name) throws SQLException
{
Integer id = (Integer)func.get(name);
// may be we could add a lookup to the database here, and store the result
// in our lookup table, throwing the exception if that fails.
// We must, however, ensure that if we do, any existing ResultSet is
// unaffected, otherwise we could break user code.
//
// so, until we know we can do this (needs testing, on the TODO list)
// for now, we throw the exception and do no lookups.
if (id == null)
throw new PSQLException("postgresql.fp.unknown", name);
return id.intValue();
}
}
}
}
/**
* Send a function call to the PostgreSQL backend by name.
*
* Note: the mapping for the procedure name to function id needs to exist,
* usually to an earlier call to addfunction().
*
* This is the prefered method to call, as function id's can/may change
* between versions of the backend.
*
* For an example of how this works, refer to org.postgresql.LargeObject
*
* @param name Function name
* @param resulttype True if the result is an integer, false for other
* results
* @param args FastpathArguments to pass to fastpath
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception SQLException if name is unknown or if a database-access error
* occurs.
* @see org.postgresql.LargeObject
*/
public Object fastpath(String name,boolean resulttype,FastpathArg[] args) throws SQLException
{
//DriverManager.println("Fastpath: calling "+name);
return fastpath(getID(name),resulttype,args);
}
/**
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return integer result
* @exception SQLException if a database-access error occurs or no result
*/
public int getInteger(String name,FastpathArg[] args) throws SQLException
{
Integer i = (Integer)fastpath(name,true,args);
if(i==null)
throw new PSQLException("postgresql.fp.expint",name);
return i.intValue();
}
/**
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return byte[] array containing result
* @exception SQLException if a database-access error occurs or no result
*/
public byte[] getData(String name,FastpathArg[] args) throws SQLException
{
return (byte[])fastpath(name,false,args);
}
/**
* This adds a function to our lookup table.
*
* <p>User code should use the addFunctions method, which is based upon a
* query, rather than hard coding the oid. The oid for a function is not
* guaranteed to remain static, even on different servers of the same
* version.
*
* @param name Function name
* @param fnid Function id
*/
public void addFunction(String name,int fnid)
{
func.put(name,new Integer(fnid));
}
/**
* This takes a ResultSet containing two columns. Column 1 contains the
* function name, Column 2 the oid.
*
* <p>It reads the entire ResultSet, loading the values into the function
* table.
*
* <p><b>REMEMBER</b> to close() the resultset after calling this!!
*
* <p><b><em>Implementation note about function name lookups:</em></b>
*
* <p>PostgreSQL stores the function id's and their corresponding names in
* the pg_proc table. To speed things up locally, instead of querying each
* function from that table when required, a Hashtable is used. Also, only
* the function's required are entered into this table, keeping connection
* times as fast as possible.
*
* <p>The org.postgresql.LargeObject class performs a query upon it's startup,
* and passes the returned ResultSet to the addFunctions() method here.
*
* <p>Once this has been done, the LargeObject api refers to the functions by
* name.
*
* <p>Dont think that manually converting them to the oid's will work. Ok,
* they will for now, but they can change during development (there was some
* discussion about this for V7.0), so this is implemented to prevent any
* unwarranted headaches in the future.
*
* @param rs ResultSet
* @exception SQLException if a database-access error occurs.
* @see org.postgresql.LargeObjectManager
*/
public void addFunctions(ResultSet rs) throws SQLException
{
while(rs.next()) {
func.put(rs.getString(1),new Integer(rs.getInt(2)));
}
}
/**
* This returns the function id associated by its name
*
* <p>If addFunction() or addFunctions() have not been called for this name,
* then an SQLException is thrown.
*
* @param name Function name to lookup
* @return Function ID for fastpath call
* @exception SQLException is function is unknown.
*/
public int getID(String name) throws SQLException
{
Integer id = (Integer)func.get(name);
// may be we could add a lookup to the database here, and store the result
// in our lookup table, throwing the exception if that fails.
// We must, however, ensure that if we do, any existing ResultSet is
// unaffected, otherwise we could break user code.
//
// so, until we know we can do this (needs testing, on the TODO list)
// for now, we throw the exception and do no lookups.
if(id==null)
throw new PSQLException("postgresql.fp.unknown",name);
return id.intValue();
}
}

View File

@ -22,85 +22,88 @@ import org.postgresql.util.*;
*/
public class FastpathArg
{
/**
* Type of argument, true=integer, false=byte[]
*/
public boolean type;
/**
* Integer value if type=true
*/
public int value;
/**
* Byte value if type=false;
*/
public byte[] bytes;
/**
* Constructs an argument that consists of an integer value
* @param value int value to set
*/
public FastpathArg(int value)
{
type=true;
this.value=value;
}
/**
* Constructs an argument that consists of an array of bytes
* @param bytes array to store
*/
public FastpathArg(byte bytes[])
{
type=false;
this.bytes=bytes;
}
/**
* Constructs an argument that consists of part of a byte array
* @param buf source array
* @param off offset within array
* @param len length of data to include
*/
public FastpathArg(byte buf[],int off,int len)
{
type=false;
bytes = new byte[len];
System.arraycopy(buf,off,bytes,0,len);
}
/**
* Constructs an argument that consists of a String.
* @param s String to store
*/
public FastpathArg(String s)
{
this(s.getBytes());
}
/**
* This sends this argument down the network stream.
*
* <p>The stream sent consists of the length.int4 then the contents.
*
* <p><b>Note:</b> This is called from Fastpath, and cannot be called from
* client code.
*
* @param s output stream
* @exception IOException if something failed on the network stream
*/
protected void send(org.postgresql.PG_Stream s) throws IOException
{
if(type) {
// argument is an integer
s.SendInteger(4,4); // size of an integer
s.SendInteger(value,4); // integer value of argument
} else {
// argument is a byte array
s.SendInteger(bytes.length,4); // size of array
s.Send(bytes);
}
}
/**
* Type of argument, true=integer, false=byte[]
*/
public boolean type;
/**
* Integer value if type=true
*/
public int value;
/**
* Byte value if type=false;
*/
public byte[] bytes;
/**
* Constructs an argument that consists of an integer value
* @param value int value to set
*/
public FastpathArg(int value)
{
type = true;
this.value = value;
}
/**
* Constructs an argument that consists of an array of bytes
* @param bytes array to store
*/
public FastpathArg(byte bytes[])
{
type = false;
this.bytes = bytes;
}
/**
* Constructs an argument that consists of part of a byte array
* @param buf source array
* @param off offset within array
* @param len length of data to include
*/
public FastpathArg(byte buf[], int off, int len)
{
type = false;
bytes = new byte[len];
System.arraycopy(buf, off, bytes, 0, len);
}
/**
* Constructs an argument that consists of a String.
* @param s String to store
*/
public FastpathArg(String s)
{
this(s.getBytes());
}
/**
* This sends this argument down the network stream.
*
* <p>The stream sent consists of the length.int4 then the contents.
*
* <p><b>Note:</b> This is called from Fastpath, and cannot be called from
* client code.
*
* @param s output stream
* @exception IOException if something failed on the network stream
*/
protected void send(org.postgresql.PG_Stream s) throws IOException
{
if (type)
{
// argument is an integer
s.SendInteger(4, 4); // size of an integer
s.SendInteger(value, 4); // integer value of argument
}
else
{
// argument is a byte array
s.SendInteger(bytes.length, 4); // size of array
s.Send(bytes);
}
}
}

View File

@ -7,99 +7,100 @@ import org.postgresql.util.*;
/**
* This represents the box datatype within org.postgresql.
*/
public class PGbox extends PGobject implements Serializable,Cloneable
public class PGbox extends PGobject implements Serializable, Cloneable
{
/**
* These are the two points.
*/
public PGpoint point[] = new PGpoint[2];
/**
* @param x1 first x coordinate
* @param y1 first y coordinate
* @param x2 second x coordinate
* @param y2 second y coordinate
*/
public PGbox(double x1,double y1,double x2,double y2)
{
this();
this.point[0] = new PGpoint(x1,y1);
this.point[1] = new PGpoint(x2,y2);
}
/**
* @param p1 first point
* @param p2 second point
*/
public PGbox(PGpoint p1,PGpoint p2)
{
this();
this.point[0] = p1;
this.point[1] = p2;
}
/**
* @param s Box definition in PostgreSQL syntax
* @exception SQLException if definition is invalid
*/
public PGbox(String s) throws SQLException
{
this();
setValue(s);
}
/**
* Required constructor
*/
public PGbox()
{
setType("box");
}
/**
* This method sets the value of this object. It should be overidden,
* but still called by subclasses.
*
* @param value a string representation of the value of the object
* @exception SQLException thrown if value is invalid for this type
*/
public void setValue(String value) throws SQLException
{
PGtokenizer t = new PGtokenizer(value,',');
if(t.getSize() != 2)
throw new PSQLException("postgresql.geo.box",value);
point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGbox) {
PGbox p = (PGbox)obj;
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGbox((PGpoint)point[0].clone(),(PGpoint)point[1].clone());
}
/**
* @return the PGbox in the syntax expected by org.postgresql
*/
public String getValue()
{
return point[0].toString()+","+point[1].toString();
}
/**
* These are the two points.
*/
public PGpoint point[] = new PGpoint[2];
/**
* @param x1 first x coordinate
* @param y1 first y coordinate
* @param x2 second x coordinate
* @param y2 second y coordinate
*/
public PGbox(double x1, double y1, double x2, double y2)
{
this();
this.point[0] = new PGpoint(x1, y1);
this.point[1] = new PGpoint(x2, y2);
}
/**
* @param p1 first point
* @param p2 second point
*/
public PGbox(PGpoint p1, PGpoint p2)
{
this();
this.point[0] = p1;
this.point[1] = p2;
}
/**
* @param s Box definition in PostgreSQL syntax
* @exception SQLException if definition is invalid
*/
public PGbox(String s) throws SQLException
{
this();
setValue(s);
}
/**
* Required constructor
*/
public PGbox()
{
setType("box");
}
/**
* This method sets the value of this object. It should be overidden,
* but still called by subclasses.
*
* @param value a string representation of the value of the object
* @exception SQLException thrown if value is invalid for this type
*/
public void setValue(String value) throws SQLException
{
PGtokenizer t = new PGtokenizer(value, ',');
if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.box", value);
point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGbox)
{
PGbox p = (PGbox)obj;
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGbox((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
}
/**
* @return the PGbox in the syntax expected by org.postgresql
*/
public String getValue()
{
return point[0].toString() + "," + point[1].toString();
}
}

View File

@ -8,101 +8,105 @@ import org.postgresql.util.*;
* This represents org.postgresql's circle datatype, consisting of a point and
* a radius
*/
public class PGcircle extends PGobject implements Serializable,Cloneable
public class PGcircle extends PGobject implements Serializable, Cloneable
{
/**
* This is the centre point
*/
public PGpoint center;
/**
* This is the radius
*/
double radius;
/**
* @param x coordinate of centre
* @param y coordinate of centre
* @param r radius of circle
*/
public PGcircle(double x,double y,double r)
{
this(new PGpoint(x,y),r);
}
/**
* @param c PGpoint describing the circle's centre
* @param r radius of circle
*/
public PGcircle(PGpoint c,double r)
{
this();
this.center = c;
this.radius = r;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGcircle(String s) throws SQLException
{
this();
setValue(s);
}
/**
* This constructor is used by the driver.
*/
public PGcircle()
{
setType("circle");
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removeAngle(s),',');
if(t.getSize() != 2)
throw new PSQLException("postgresql.geo.circle",s);
try {
center = new PGpoint(t.getToken(0));
radius = Double.valueOf(t.getToken(1)).doubleValue();
} catch(NumberFormatException e) {
throw new PSQLException("postgresql.geo.circle",e);
}
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGcircle) {
PGcircle p = (PGcircle)obj;
return p.center.equals(center) && p.radius==radius;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGcircle((PGpoint)center.clone(),radius);
}
/**
* @return the PGcircle in the syntax expected by org.postgresql
*/
public String getValue()
{
return "<"+center+","+radius+">";
}
/**
* This is the centre point
*/
public PGpoint center;
/**
* This is the radius
*/
double radius;
/**
* @param x coordinate of centre
* @param y coordinate of centre
* @param r radius of circle
*/
public PGcircle(double x, double y, double r)
{
this(new PGpoint(x, y), r);
}
/**
* @param c PGpoint describing the circle's centre
* @param r radius of circle
*/
public PGcircle(PGpoint c, double r)
{
this();
this.center = c;
this.radius = r;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGcircle(String s) throws SQLException
{
this();
setValue(s);
}
/**
* This constructor is used by the driver.
*/
public PGcircle()
{
setType("circle");
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removeAngle(s), ',');
if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.circle", s);
try
{
center = new PGpoint(t.getToken(0));
radius = Double.valueOf(t.getToken(1)).doubleValue();
}
catch (NumberFormatException e)
{
throw new PSQLException("postgresql.geo.circle", e);
}
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGcircle)
{
PGcircle p = (PGcircle)obj;
return p.center.equals(center) && p.radius == radius;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGcircle((PGpoint)center.clone(), radius);
}
/**
* @return the PGcircle in the syntax expected by org.postgresql
*/
public String getValue()
{
return "<" + center + "," + radius + ">";
}
}

View File

@ -10,94 +10,95 @@ import org.postgresql.util.*;
* Currently line is not yet implemented in the backend, but this class
* ensures that when it's done were ready for it.
*/
public class PGline extends PGobject implements Serializable,Cloneable
public class PGline extends PGobject implements Serializable, Cloneable
{
/**
* These are the two points.
*/
public PGpoint point[] = new PGpoint[2];
/**
* @param x1 coordinate for first point
* @param y1 coordinate for first point
* @param x2 coordinate for second point
* @param y2 coordinate for second point
*/
public PGline(double x1,double y1,double x2,double y2)
{
this(new PGpoint(x1,y1),new PGpoint(x2,y2));
}
/**
* @param p1 first point
* @param p2 second point
*/
public PGline(PGpoint p1,PGpoint p2)
{
this();
this.point[0] = p1;
this.point[1] = p2;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGline(String s) throws SQLException
{
this();
setValue(s);
}
/**
* reuired by the driver
*/
public PGline()
{
setType("line");
}
/**
* @param s Definition of the line segment in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s),',');
if(t.getSize() != 2)
throw new PSQLException("postgresql.geo.line",s);
point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGline) {
PGline p = (PGline)obj;
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGline((PGpoint)point[0].clone(),(PGpoint)point[1].clone());
}
/**
* @return the PGline in the syntax expected by org.postgresql
*/
public String getValue()
{
return "["+point[0]+","+point[1]+"]";
}
/**
* These are the two points.
*/
public PGpoint point[] = new PGpoint[2];
/**
* @param x1 coordinate for first point
* @param y1 coordinate for first point
* @param x2 coordinate for second point
* @param y2 coordinate for second point
*/
public PGline(double x1, double y1, double x2, double y2)
{
this(new PGpoint(x1, y1), new PGpoint(x2, y2));
}
/**
* @param p1 first point
* @param p2 second point
*/
public PGline(PGpoint p1, PGpoint p2)
{
this();
this.point[0] = p1;
this.point[1] = p2;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGline(String s) throws SQLException
{
this();
setValue(s);
}
/**
* reuired by the driver
*/
public PGline()
{
setType("line");
}
/**
* @param s Definition of the line segment in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s), ',');
if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.line", s);
point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGline)
{
PGline p = (PGline)obj;
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGline((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
}
/**
* @return the PGline in the syntax expected by org.postgresql
*/
public String getValue()
{
return "[" + point[0] + "," + point[1] + "]";
}
}

View File

@ -7,94 +7,95 @@ import org.postgresql.util.*;
/**
* This implements a lseg (line segment) consisting of two points
*/
public class PGlseg extends PGobject implements Serializable,Cloneable
public class PGlseg extends PGobject implements Serializable, Cloneable
{
/**
* These are the two points.
*/
public PGpoint point[] = new PGpoint[2];
/**
* @param x1 coordinate for first point
* @param y1 coordinate for first point
* @param x2 coordinate for second point
* @param y2 coordinate for second point
*/
public PGlseg(double x1,double y1,double x2,double y2)
{
this(new PGpoint(x1,y1),new PGpoint(x2,y2));
}
/**
* @param p1 first point
* @param p2 second point
*/
public PGlseg(PGpoint p1,PGpoint p2)
{
this();
this.point[0] = p1;
this.point[1] = p2;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGlseg(String s) throws SQLException
{
this();
setValue(s);
}
/**
* reuired by the driver
*/
public PGlseg()
{
setType("lseg");
}
/**
* @param s Definition of the line segment in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s),',');
if(t.getSize() != 2)
throw new PSQLException("postgresql.geo.lseg");
point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGlseg) {
PGlseg p = (PGlseg)obj;
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGlseg((PGpoint)point[0].clone(),(PGpoint)point[1].clone());
}
/**
* @return the PGlseg in the syntax expected by org.postgresql
*/
public String getValue()
{
return "["+point[0]+","+point[1]+"]";
}
/**
* These are the two points.
*/
public PGpoint point[] = new PGpoint[2];
/**
* @param x1 coordinate for first point
* @param y1 coordinate for first point
* @param x2 coordinate for second point
* @param y2 coordinate for second point
*/
public PGlseg(double x1, double y1, double x2, double y2)
{
this(new PGpoint(x1, y1), new PGpoint(x2, y2));
}
/**
* @param p1 first point
* @param p2 second point
*/
public PGlseg(PGpoint p1, PGpoint p2)
{
this();
this.point[0] = p1;
this.point[1] = p2;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGlseg(String s) throws SQLException
{
this();
setValue(s);
}
/**
* reuired by the driver
*/
public PGlseg()
{
setType("lseg");
}
/**
* @param s Definition of the line segment in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s), ',');
if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.lseg");
point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGlseg)
{
PGlseg p = (PGlseg)obj;
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGlseg((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
}
/**
* @return the PGlseg in the syntax expected by org.postgresql
*/
public String getValue()
{
return "[" + point[0] + "," + point[1] + "]";
}
}

View File

@ -7,139 +7,146 @@ import org.postgresql.util.*;
/**
* This implements a path (a multiple segmented line, which may be closed)
*/
public class PGpath extends PGobject implements Serializable,Cloneable
public class PGpath extends PGobject implements Serializable, Cloneable
{
/**
* True if the path is open, false if closed
*/
public boolean open;
/**
* The points defining this path
*/
public PGpoint points[];
/**
* @param points the PGpoints that define the path
* @param open True if the path is open, false if closed
*/
public PGpath(PGpoint[] points,boolean open)
{
this();
this.points = points;
this.open = open;
}
/**
* Required by the driver
*/
public PGpath()
{
setType("path");
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGpath(String s) throws SQLException
{
this();
setValue(s);
}
/**
* @param s Definition of the path in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
// First test to see if were open
if(s.startsWith("[") && s.endsWith("]")) {
open = true;
s = PGtokenizer.removeBox(s);
} else if(s.startsWith("(") && s.endsWith(")")) {
open = false;
s = PGtokenizer.removePara(s);
} else
throw new PSQLException("postgresql.geo.path");
PGtokenizer t = new PGtokenizer(s,',');
int npoints = t.getSize();
points = new PGpoint[npoints];
for(int p=0;p<npoints;p++)
points[p] = new PGpoint(t.getToken(p));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGpath) {
PGpath p = (PGpath)obj;
if(p.points.length != points.length)
return false;
if(p.open != open)
return false;
for(int i=0;i<points.length;i++)
if(!points[i].equals(p.points[i]))
return false;
return true;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
PGpoint ary[] = new PGpoint[points.length];
for(int i=0;i<points.length;i++)
ary[i]=(PGpoint)points[i].clone();
return new PGpath(ary,open);
}
/**
* This returns the polygon in the syntax expected by org.postgresql
*/
public String getValue()
{
StringBuffer b = new StringBuffer(open?"[":"(");
for(int p=0;p<points.length;p++) {
if(p>0) b.append(",");
b.append(points[p].toString());
}
b.append(open?"]":")");
return b.toString();
}
public boolean isOpen()
{
return open;
}
public boolean isClosed()
{
return !open;
}
public void closePath()
{
open = false;
}
public void openPath()
{
open = true;
}
/**
* True if the path is open, false if closed
*/
public boolean open;
/**
* The points defining this path
*/
public PGpoint points[];
/**
* @param points the PGpoints that define the path
* @param open True if the path is open, false if closed
*/
public PGpath(PGpoint[] points, boolean open)
{
this();
this.points = points;
this.open = open;
}
/**
* Required by the driver
*/
public PGpath()
{
setType("path");
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGpath(String s) throws SQLException
{
this();
setValue(s);
}
/**
* @param s Definition of the path in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
// First test to see if were open
if (s.startsWith("[") && s.endsWith("]"))
{
open = true;
s = PGtokenizer.removeBox(s);
}
else if (s.startsWith("(") && s.endsWith(")"))
{
open = false;
s = PGtokenizer.removePara(s);
}
else
throw new PSQLException("postgresql.geo.path");
PGtokenizer t = new PGtokenizer(s, ',');
int npoints = t.getSize();
points = new PGpoint[npoints];
for (int p = 0;p < npoints;p++)
points[p] = new PGpoint(t.getToken(p));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGpath)
{
PGpath p = (PGpath)obj;
if (p.points.length != points.length)
return false;
if (p.open != open)
return false;
for (int i = 0;i < points.length;i++)
if (!points[i].equals(p.points[i]))
return false;
return true;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
PGpoint ary[] = new PGpoint[points.length];
for (int i = 0;i < points.length;i++)
ary[i] = (PGpoint)points[i].clone();
return new PGpath(ary, open);
}
/**
* This returns the polygon in the syntax expected by org.postgresql
*/
public String getValue()
{
StringBuffer b = new StringBuffer(open ? "[" : "(");
for (int p = 0;p < points.length;p++)
{
if (p > 0)
b.append(",");
b.append(points[p].toString());
}
b.append(open ? "]" : ")");
return b.toString();
}
public boolean isOpen()
{
return open;
}
public boolean isClosed()
{
return !open;
}
public void closePath()
{
open = false;
}
public void openPath()
{
open = true;
}
}

View File

@ -12,156 +12,160 @@ import org.postgresql.util.*;
*
* <p>It maps to the point datatype in org.postgresql.
*/
public class PGpoint extends PGobject implements Serializable,Cloneable
public class PGpoint extends PGobject implements Serializable, Cloneable
{
/**
* The X coordinate of the point
*/
public double x;
/**
* The Y coordinate of the point
*/
public double y;
/**
* @param x coordinate
* @param y coordinate
*/
public PGpoint(double x,double y)
{
this();
this.x = x;
this.y = y;
}
/**
* This is called mainly from the other geometric types, when a
* point is imbeded within their definition.
*
* @param value Definition of this point in PostgreSQL's syntax
*/
public PGpoint(String value) throws SQLException
{
this();
setValue(value);
}
/**
* Required by the driver
*/
public PGpoint()
{
setType("point");
}
/**
* @param s Definition of this point in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s),',');
try {
x = Double.valueOf(t.getToken(0)).doubleValue();
y = Double.valueOf(t.getToken(1)).doubleValue();
} catch(NumberFormatException e) {
throw new PSQLException("postgresql.geo.point",e.toString());
}
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGpoint) {
PGpoint p = (PGpoint)obj;
return x == p.x && y == p.y;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGpoint(x,y);
}
/**
* @return the PGpoint in the syntax expected by org.postgresql
*/
public String getValue()
{
return "("+x+","+y+")";
}
/**
* Translate the point with the supplied amount.
* @param x integer amount to add on the x axis
* @param y integer amount to add on the y axis
*/
public void translate(int x,int y)
{
translate((double)x,(double)y);
}
/**
* Translate the point with the supplied amount.
* @param x double amount to add on the x axis
* @param y double amount to add on the y axis
*/
public void translate(double x,double y)
{
this.x += x;
this.y += y;
}
/**
* Moves the point to the supplied coordinates.
* @param x integer coordinate
* @param y integer coordinate
*/
public void move(int x,int y)
{
setLocation(x,y);
}
/**
* Moves the point to the supplied coordinates.
* @param x double coordinate
* @param y double coordinate
*/
public void move(double x,double y)
{
this.x = x;
this.y = y;
}
/**
* Moves the point to the supplied coordinates.
* refer to java.awt.Point for description of this
* @param x integer coordinate
* @param y integer coordinate
* @see java.awt.Point
*/
public void setLocation(int x,int y)
{
move((double)x,(double)y);
}
/**
* Moves the point to the supplied java.awt.Point
* refer to java.awt.Point for description of this
* @param p Point to move to
* @see java.awt.Point
*/
public void setLocation(Point p)
{
setLocation(p.x,p.y);
}
/**
* The X coordinate of the point
*/
public double x;
/**
* The Y coordinate of the point
*/
public double y;
/**
* @param x coordinate
* @param y coordinate
*/
public PGpoint(double x, double y)
{
this();
this.x = x;
this.y = y;
}
/**
* This is called mainly from the other geometric types, when a
* point is imbeded within their definition.
*
* @param value Definition of this point in PostgreSQL's syntax
*/
public PGpoint(String value) throws SQLException
{
this();
setValue(value);
}
/**
* Required by the driver
*/
public PGpoint()
{
setType("point");
}
/**
* @param s Definition of this point in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s), ',');
try
{
x = Double.valueOf(t.getToken(0)).doubleValue();
y = Double.valueOf(t.getToken(1)).doubleValue();
}
catch (NumberFormatException e)
{
throw new PSQLException("postgresql.geo.point", e.toString());
}
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGpoint)
{
PGpoint p = (PGpoint)obj;
return x == p.x && y == p.y;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGpoint(x, y);
}
/**
* @return the PGpoint in the syntax expected by org.postgresql
*/
public String getValue()
{
return "(" + x + "," + y + ")";
}
/**
* Translate the point with the supplied amount.
* @param x integer amount to add on the x axis
* @param y integer amount to add on the y axis
*/
public void translate(int x, int y)
{
translate((double)x, (double)y);
}
/**
* Translate the point with the supplied amount.
* @param x double amount to add on the x axis
* @param y double amount to add on the y axis
*/
public void translate(double x, double y)
{
this.x += x;
this.y += y;
}
/**
* Moves the point to the supplied coordinates.
* @param x integer coordinate
* @param y integer coordinate
*/
public void move(int x, int y)
{
setLocation(x, y);
}
/**
* Moves the point to the supplied coordinates.
* @param x double coordinate
* @param y double coordinate
*/
public void move(double x, double y)
{
this.x = x;
this.y = y;
}
/**
* Moves the point to the supplied coordinates.
* refer to java.awt.Point for description of this
* @param x integer coordinate
* @param y integer coordinate
* @see java.awt.Point
*/
public void setLocation(int x, int y)
{
move((double)x, (double)y);
}
/**
* Moves the point to the supplied java.awt.Point
* refer to java.awt.Point for description of this
* @param p Point to move to
* @see java.awt.Point
*/
public void setLocation(Point p)
{
setLocation(p.x, p.y);
}
}

View File

@ -7,99 +7,102 @@ import org.postgresql.util.*;
/**
* This implements the polygon datatype within PostgreSQL.
*/
public class PGpolygon extends PGobject implements Serializable,Cloneable
public class PGpolygon extends PGobject implements Serializable, Cloneable
{
/**
* The points defining the polygon
*/
public PGpoint points[];
/**
* Creates a polygon using an array of PGpoints
*
* @param points the points defining the polygon
*/
public PGpolygon(PGpoint[] points)
{
this();
this.points = points;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGpolygon(String s) throws SQLException
{
this();
setValue(s);
}
/**
* Required by the driver
*/
public PGpolygon()
{
setType("polygon");
}
/**
* @param s Definition of the polygon in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s),',');
int npoints = t.getSize();
points = new PGpoint[npoints];
for(int p=0;p<npoints;p++)
points[p] = new PGpoint(t.getToken(p));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGpolygon) {
PGpolygon p = (PGpolygon)obj;
if(p.points.length != points.length)
return false;
for(int i=0;i<points.length;i++)
if(!points[i].equals(p.points[i]))
return false;
return true;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
PGpoint ary[] = new PGpoint[points.length];
for(int i=0;i<points.length;i++)
ary[i] = (PGpoint)points[i].clone();
return new PGpolygon(ary);
}
/**
* @return the PGpolygon in the syntax expected by org.postgresql
*/
public String getValue()
{
StringBuffer b = new StringBuffer();
b.append("(");
for(int p=0;p<points.length;p++) {
if(p>0) b.append(",");
b.append(points[p].toString());
}
b.append(")");
return b.toString();
}
/**
* The points defining the polygon
*/
public PGpoint points[];
/**
* Creates a polygon using an array of PGpoints
*
* @param points the points defining the polygon
*/
public PGpolygon(PGpoint[] points)
{
this();
this.points = points;
}
/**
* @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure
*/
public PGpolygon(String s) throws SQLException
{
this();
setValue(s);
}
/**
* Required by the driver
*/
public PGpolygon()
{
setType("polygon");
}
/**
* @param s Definition of the polygon in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s), ',');
int npoints = t.getSize();
points = new PGpoint[npoints];
for (int p = 0;p < npoints;p++)
points[p] = new PGpoint(t.getToken(p));
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGpolygon)
{
PGpolygon p = (PGpolygon)obj;
if (p.points.length != points.length)
return false;
for (int i = 0;i < points.length;i++)
if (!points[i].equals(p.points[i]))
return false;
return true;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
PGpoint ary[] = new PGpoint[points.length];
for (int i = 0;i < points.length;i++)
ary[i] = (PGpoint)points[i].clone();
return new PGpolygon(ary);
}
/**
* @return the PGpolygon in the syntax expected by org.postgresql
*/
public String getValue()
{
StringBuffer b = new StringBuffer();
b.append("(");
for (int p = 0;p < points.length;p++)
{
if (p > 0)
b.append(",");
b.append(points[p].toString());
}
b.append(")");
return b.toString();
}
}

View File

@ -19,8 +19,8 @@ import java.math.*;
* Parameters are refered to sequentially, by number. The first parameter
* is 1.
*
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
*
*
* <p>IN parameter values are set using the set methods inherited from
@ -33,7 +33,7 @@ import java.math.*;
* Statement.
*
* <p>For maximum portability, a call's ResultSets and update counts should
* be processed prior to getting the values of output parameters.
* be processed prior to getting the values of output parameters.
*
* @see Connection#prepareCall
* @see ResultSet
@ -41,268 +41,282 @@ import java.math.*;
public class CallableStatement extends PreparedStatement implements java.sql.CallableStatement
{
/**
* @exception SQLException on failure
*/
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.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
}
/**
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{
}
// Old api?
//public boolean isNull(int parameterIndex) throws SQLException {
//return true;
//}
/**
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException {
// check to see if the last access threw an exception
return false; // fake it for now
}
// Old api?
//public String getChar(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
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;
//}
/**
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException {
return false;
}
/**
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException {
return (float) 0.0;
}
/**
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException {
return 0.0;
}
/**
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException {
return null;
}
/**
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException {
return null;
}
// New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
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.
/**
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException {
return null;
}
/**
* @exception SQLException on failure
*/
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.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
{}
/**
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{}
// Old api?
//public boolean isNull(int parameterIndex) throws SQLException {
//return true;
//}
/**
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException
{
// check to see if the last access threw an exception
return false; // fake it for now
}
// Old api?
//public String getChar(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
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;
//}
/**
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException
{
return false;
}
/**
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException
{
return (float) 0.0;
}
/**
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException
{
return 0.0;
}
/**
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException
{
return null;
}
/**
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException
{
return null;
}
// New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException
{
return null;
}
/**
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException
{
return null;
}
/**
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
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.
/**
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException
{
return null;
}
}

View File

@ -17,9 +17,9 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/**
* $Id: Connection.java,v 1.11 2001/10/09 20:47:35 barry Exp $
* $Id: Connection.java,v 1.12 2001/10/25 05:59:59 momjian Exp $
*
* A Connection represents a session with a specific database. Within the
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
* returned.
*
@ -29,181 +29,183 @@ import org.postgresql.util.*;
* with the getMetaData method.
*
* <p><B>Note:</B> By default, the Connection automatically commits changes
* after executing each statement. If auto-commit has been disabled, an
* after executing each statement. If auto-commit has been disabled, an
* explicit commit must be done or database changes will not be saved.
*
* @see java.sql.Connection
*/
public class Connection extends org.postgresql.Connection implements java.sql.Connection
{
// This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata;
// This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata;
/**
* 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);
}
/**
* 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 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 PSQLException("postgresql.con.call");
// return new CallableStatement(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 PSQLException("postgresql.con.call");
// return new CallableStatement(this, sql);
}
/**
* 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);
}
/**
* 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
{
if(metadata==null)
metadata = new DatabaseMetaData(this);
return metadata;
}
/**
* 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
{
if (metadata == null)
metadata = new DatabaseMetaData(this);
return metadata;
}
/**
* This overides the method in org.postgresql.Connection and returns a
* ResultSet.
*/
public java.sql.ResultSet getResultSet(org.postgresql.Connection conn,java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount,int insertOID, boolean binaryCursor) throws SQLException
{
// in jdbc1 stat is ignored.
return new org.postgresql.jdbc1.ResultSet((org.postgresql.jdbc1.Connection)conn,fields,tuples,status,updateCount,insertOID,binaryCursor);
}
/**
* This overides the method in org.postgresql.Connection and returns a
* ResultSet.
*/
public java.sql.ResultSet getResultSet(org.postgresql.Connection conn, java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, int insertOID, boolean binaryCursor) throws SQLException
{
// in jdbc1 stat is ignored.
return new org.postgresql.jdbc1.ResultSet((org.postgresql.jdbc1.Connection)conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
/* An implementation of the abstract method in the parent class.
* This implemetation uses the jdbc1Types array to support the jdbc1
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types.
*/
public int getSQLType(String pgTypeName)
{
int sqlType = Types.OTHER; // default value
for(int i=0;i<jdbc1Types.length;i++) {
if(pgTypeName.equals(jdbc1Types[i])) {
sqlType=jdbc1Typei[i];
break;
}
}
return sqlType;
}
/* An implementation of the abstract method in the parent class.
* This implemetation uses the jdbc1Types array to support the jdbc1
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types.
*/
public int getSQLType(String pgTypeName)
{
int sqlType = Types.OTHER; // default value
for (int i = 0;i < jdbc1Types.length;i++)
{
if (pgTypeName.equals(jdbc1Types[i]))
{
sqlType = jdbc1Typei[i];
break;
}
}
return sqlType;
}
/**
* This table holds the org.postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String jdbc1Types[] = {
"int2",
"int4","oid",
"int8",
"cash","money",
"numeric",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
"bytea",
"bool",
"date",
"time",
"abstime","timestamp"
};
/**
* This table holds the org.postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String jdbc1Types[] = {
"int2",
"int4", "oid",
"int8",
"cash", "money",
"numeric",
"float4",
"float8",
"bpchar", "char", "char2", "char4", "char8", "char16",
"varchar", "text", "name", "filename",
"bytea",
"bool",
"date",
"time",
"abstime", "timestamp"
};
/**
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int jdbc1Typei[] = {
Types.SMALLINT,
Types.INTEGER,Types.INTEGER,
Types.BIGINT,
Types.DOUBLE,Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP
};
/**
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int jdbc1Typei[] = {
Types.SMALLINT,
Types.INTEGER, Types.INTEGER,
Types.BIGINT,
Types.DOUBLE, Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP, Types.TIMESTAMP
};
}

File diff suppressed because it is too large Load Diff

View File

@ -23,13 +23,13 @@ import org.postgresql.util.*;
* parameter. For instance, if the IN parameter has SQL type Integer, then
* setInt should be used.
*
* <p>If arbitrary parameter type conversions are required, then the setObject
* <p>If arbitrary parameter type conversions are required, then the setObject
* method should be used with a target SQL type.
*
* @see ResultSet
* @see java.sql.PreparedStatement
*/
public class PreparedStatement extends Statement implements java.sql.PreparedStatement
public class PreparedStatement extends Statement implements java.sql.PreparedStatement
{
String sql;
String[] templateStrings;
@ -82,7 +82,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* A Prepared SQL query is executed and its ResultSet is returned
*
* @return a ResultSet that contains the data produced by the
* * query - never null
* * query - never null
* @exception SQLException if a database access error occurs
*/
public java.sql.ResultSet executeQuery() throws SQLException
@ -93,12 +93,12 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
for (i = 0 ; i < inStrings.length ; ++i)
{
if (inStrings[i] == null)
throw new PSQLException("postgresql.prep.param",new Integer(i + 1));
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
s.append (templateStrings[i]);
s.append (inStrings[i]);
}
s.append(templateStrings[inStrings.length]);
return super.executeQuery(s.toString()); // in Statement class
return super.executeQuery(s.toString()); // in Statement class
}
/**
@ -107,7 +107,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* be executed.
*
* @return either the row count for INSERT, UPDATE or DELETE; or
* * 0 for SQL statements that return nothing.
* * 0 for SQL statements that return nothing.
* @exception SQLException if a database access error occurs
*/
public int executeUpdate() throws SQLException
@ -118,13 +118,13 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
for (i = 0 ; i < inStrings.length ; ++i)
{
if (inStrings[i] == null)
throw new PSQLException("postgresql.prep.param",new Integer(i + 1));
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
s.append (templateStrings[i]);
s.append (inStrings[i]);
}
s.append(templateStrings[inStrings.length]);
return super.executeUpdate(s.toString()); // in Statement class
}
return super.executeUpdate(s.toString()); // in Statement class
}
/**
* Set a parameter to SQL NULL
@ -220,7 +220,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
}
/**
* Set a parameter to a Java double value. The driver converts this
* Set a parameter to a Java double value. The driver converts this
* to a SQL DOUBLE value when it sends it to the database
*
* @param parameterIndex the first parameter is 1...
@ -247,7 +247,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
}
/**
* Set a parameter to a Java String value. The driver converts this
* Set a parameter to a Java String value. The driver converts this
* to a SQL VARCHAR or LONGVARCHAR value (depending on the arguments
* size relative to the driver's limits on VARCHARs) when it sends it
* to the database.
@ -258,59 +258,66 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setString(int parameterIndex, String x) throws SQLException
{
// if the passed string is null, then set this column to null
if(x==null)
setNull(parameterIndex,Types.OTHER);
else {
StringBuffer b = new StringBuffer();
int i;
b.append('\'');
for (i = 0 ; i < x.length() ; ++i)
{
char c = x.charAt(i);
if (c == '\\' || c == '\'')
b.append((char)'\\');
b.append(c);
}
b.append('\'');
set(parameterIndex, b.toString());
}
// if the passed string is null, then set this column to null
if (x == null)
setNull(parameterIndex, Types.OTHER);
else
{
StringBuffer b = new StringBuffer();
int i;
b.append('\'');
for (i = 0 ; i < x.length() ; ++i)
{
char c = x.charAt(i);
if (c == '\\' || c == '\'')
b.append((char)'\\');
b.append(c);
}
b.append('\'');
set(parameterIndex, b.toString());
}
}
/**
* Set a parameter to a Java array of bytes. The driver converts this
* to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
* size relative to the driver's limits on VARBINARYs) when it sends
* it to the database.
*
* <p>Implementation note:
* <br>With org.postgresql, this creates a large object, and stores the
* objects oid in this column.
*
* @param parameterIndex the first parameter is 1...
* @param x the parameter value
* @exception SQLException if a database access error occurs
*/
public void setBytes(int parameterIndex, byte x[]) throws SQLException
{
if (connection.haveMinimumCompatibleVersion("7.2")) {
//Version 7.2 supports the bytea datatype for byte arrays
if(null == x){
setNull(parameterIndex,Types.OTHER);
} else {
setString(parameterIndex, PGbytea.toPGString(x));
}
} else {
//Version 7.1 and earlier support done as LargeObjects
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
lob.write(x);
lob.close();
setInt(parameterIndex,oid);
}
}
/**
* Set a parameter to a Java array of bytes. The driver converts this
* to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
* size relative to the driver's limits on VARBINARYs) when it sends
* it to the database.
*
* <p>Implementation note:
* <br>With org.postgresql, this creates a large object, and stores the
* objects oid in this column.
*
* @param parameterIndex the first parameter is 1...
* @param x the parameter value
* @exception SQLException if a database access error occurs
*/
public void setBytes(int parameterIndex, byte x[]) throws SQLException
{
if (connection.haveMinimumCompatibleVersion("7.2"))
{
//Version 7.2 supports the bytea datatype for byte arrays
if (null == x)
{
setNull(parameterIndex, Types.OTHER);
}
else
{
setString(parameterIndex, PGbytea.toPGString(x));
}
}
else
{
//Version 7.1 and earlier support done as LargeObjects
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
lob.write(x);
lob.close();
setInt(parameterIndex, oid);
}
}
/**
* Set a parameter to a java.sql.Date value. The driver converts this
@ -322,24 +329,27 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
{
if (null == x){
setNull(parameterIndex,Types.OTHER);
}else{
SimpleDateFormat df = new SimpleDateFormat("''yyyy-MM-dd''");
set(parameterIndex, df.format(x));
}
// The above is how the date should be handled.
//
// However, in JDK's prior to 1.1.6 (confirmed with the
// Linux jdk1.1.3 and the Win95 JRE1.1.5), SimpleDateFormat seems
// to format a date to the previous day. So the fix is to add a day
// before formatting.
//
// PS: 86400000 is one day
//
//set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000)));
if (null == x)
{
setNull(parameterIndex, Types.OTHER);
}
else
{
SimpleDateFormat df = new SimpleDateFormat("''yyyy-MM-dd''");
set(parameterIndex, df.format(x));
}
// The above is how the date should be handled.
//
// However, in JDK's prior to 1.1.6 (confirmed with the
// Linux jdk1.1.3 and the Win95 JRE1.1.5), SimpleDateFormat seems
// to format a date to the previous day. So the fix is to add a day
// before formatting.
//
// PS: 86400000 is one day
//
//set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000)));
}
/**
* Set a parameter to a java.sql.Time value. The driver converts
* this to a SQL TIME value when it sends it to the database.
@ -350,11 +360,14 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setTime(int parameterIndex, Time x) throws SQLException
{
if (null == x){
setNull(parameterIndex,Types.OTHER);
}else{
set(parameterIndex, "'" + x.toString() + "'");
}
if (null == x)
{
setNull(parameterIndex, Types.OTHER);
}
else
{
set(parameterIndex, "'" + x.toString() + "'");
}
}
/**
@ -366,16 +379,19 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* @exception SQLException if a database access error occurs
*/
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
{
if (null == x){
setNull(parameterIndex,Types.OTHER);
}else{
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
StringBuffer strBuf = new StringBuffer("'");
strBuf.append(df.format(x)).append('.').append(x.getNanos()/10000000).append("+00'");
set(parameterIndex, strBuf.toString());
}
{
if (null == x)
{
setNull(parameterIndex, Types.OTHER);
}
else
{
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
StringBuffer strBuf = new StringBuffer("'");
strBuf.append(df.format(x)).append('.').append(x.getNanos() / 10000000).append("+00'");
set(parameterIndex, strBuf.toString());
}
}
/**
@ -396,29 +412,37 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
{
if (connection.haveMinimumCompatibleVersion("7.2")) {
//Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
//As the spec/javadoc for this method indicate this is to be used for
//large String values (i.e. LONGVARCHAR) PG doesn't have a separate
//long varchar datatype, but with toast all text datatypes are capable of
//handling very large values. Thus the implementation ends up calling
//setString() since there is no current way to stream the value to the server
try {
InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
char[] l_chars = new char[length];
int l_charsRead = l_inStream.read(l_chars,0,length);
setString(parameterIndex, new String(l_chars,0,l_charsRead));
} catch (UnsupportedEncodingException l_uee) {
throw new PSQLException("postgresql.unusual",l_uee);
} catch (IOException l_ioe) {
throw new PSQLException("postgresql.unusual",l_ioe);
}
} else {
//Version 7.1 supported only LargeObjects by treating everything
//as binary data
setBinaryStream(parameterIndex, x, length);
if (connection.haveMinimumCompatibleVersion("7.2"))
{
//Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
//As the spec/javadoc for this method indicate this is to be used for
//large String values (i.e. LONGVARCHAR) PG doesn't have a separate
//long varchar datatype, but with toast all text datatypes are capable of
//handling very large values. Thus the implementation ends up calling
//setString() since there is no current way to stream the value to the server
try
{
InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
char[] l_chars = new char[length];
int l_charsRead = l_inStream.read(l_chars, 0, length);
setString(parameterIndex, new String(l_chars, 0, l_charsRead));
}
catch (UnsupportedEncodingException l_uee)
{
throw new PSQLException("postgresql.unusual", l_uee);
}
catch (IOException l_ioe)
{
throw new PSQLException("postgresql.unusual", l_ioe);
}
}
else
{
//Version 7.1 supported only LargeObjects by treating everything
//as binary data
setBinaryStream(parameterIndex, x, length);
}
}
}
/**
* When a very large Unicode value is input to a LONGVARCHAR parameter,
@ -437,35 +461,43 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
{
if (connection.haveMinimumCompatibleVersion("7.2")) {
//Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
//As the spec/javadoc for this method indicate this is to be used for
//large String values (i.e. LONGVARCHAR) PG doesn't have a separate
//long varchar datatype, but with toast all text datatypes are capable of
//handling very large values. Thus the implementation ends up calling
//setString() since there is no current way to stream the value to the server
try {
InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
char[] l_chars = new char[length];
int l_charsRead = l_inStream.read(l_chars,0,length);
setString(parameterIndex, new String(l_chars,0,l_charsRead));
} catch (UnsupportedEncodingException l_uee) {
throw new PSQLException("postgresql.unusual",l_uee);
} catch (IOException l_ioe) {
throw new PSQLException("postgresql.unusual",l_ioe);
}
} else {
//Version 7.1 supported only LargeObjects by treating everything
//as binary data
setBinaryStream(parameterIndex, x, length);
if (connection.haveMinimumCompatibleVersion("7.2"))
{
//Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
//As the spec/javadoc for this method indicate this is to be used for
//large String values (i.e. LONGVARCHAR) PG doesn't have a separate
//long varchar datatype, but with toast all text datatypes are capable of
//handling very large values. Thus the implementation ends up calling
//setString() since there is no current way to stream the value to the server
try
{
InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
char[] l_chars = new char[length];
int l_charsRead = l_inStream.read(l_chars, 0, length);
setString(parameterIndex, new String(l_chars, 0, l_charsRead));
}
catch (UnsupportedEncodingException l_uee)
{
throw new PSQLException("postgresql.unusual", l_uee);
}
catch (IOException l_ioe)
{
throw new PSQLException("postgresql.unusual", l_ioe);
}
}
else
{
//Version 7.1 supported only LargeObjects by treating everything
//as binary data
setBinaryStream(parameterIndex, x, length);
}
}
}
/**
* When a very large binary value is input to a LONGVARBINARY parameter,
* it may be more practical to send it via a java.io.InputStream.
* JDBC will read the data from the stream as needed, until it reaches
* end-of-file.
* end-of-file.
*
* <P><B>Note:</B> This stream object can either be a standard Java
* stream object or your own subclass that implements the standard
@ -477,60 +509,73 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
{
if (connection.haveMinimumCompatibleVersion("7.2")) {
//Version 7.2 supports BinaryStream for for the PG bytea type
//As the spec/javadoc for this method indicate this is to be used for
//large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
//long binary datatype, but with toast the bytea datatype is capable of
//handling very large values. Thus the implementation ends up calling
//setBytes() since there is no current way to stream the value to the server
byte[] l_bytes = new byte[length];
int l_bytesRead;
try {
l_bytesRead = x.read(l_bytes,0,length);
} catch (IOException l_ioe) {
throw new PSQLException("postgresql.unusual",l_ioe);
}
if (l_bytesRead == length) {
setBytes(parameterIndex, l_bytes);
} else {
//the stream contained less data than they said
byte[] l_bytes2 = new byte[l_bytesRead];
System.arraycopy(l_bytes,0,l_bytes2,0,l_bytesRead);
setBytes(parameterIndex, l_bytes2);
}
} else {
//Version 7.1 only supported streams for LargeObjects
//but the jdbc spec indicates that streams should be
//available for LONGVARBINARY instead
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
OutputStream los = lob.getOutputStream();
try {
// could be buffered, but then the OutputStream returned by LargeObject
// is buffered internally anyhow, so there would be no performance
// boost gained, if anything it would be worse!
int c=x.read();
int p=0;
while(c>-1 && p<length) {
los.write(c);
c=x.read();
p++;
}
los.close();
} catch(IOException se) {
throw new PSQLException("postgresql.unusual",se);
}
// lob is closed by the stream so don't call lob.close()
setInt(parameterIndex,oid);
}
if (connection.haveMinimumCompatibleVersion("7.2"))
{
//Version 7.2 supports BinaryStream for for the PG bytea type
//As the spec/javadoc for this method indicate this is to be used for
//large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
//long binary datatype, but with toast the bytea datatype is capable of
//handling very large values. Thus the implementation ends up calling
//setBytes() since there is no current way to stream the value to the server
byte[] l_bytes = new byte[length];
int l_bytesRead;
try
{
l_bytesRead = x.read(l_bytes, 0, length);
}
catch (IOException l_ioe)
{
throw new PSQLException("postgresql.unusual", l_ioe);
}
if (l_bytesRead == length)
{
setBytes(parameterIndex, l_bytes);
}
else
{
//the stream contained less data than they said
byte[] l_bytes2 = new byte[l_bytesRead];
System.arraycopy(l_bytes, 0, l_bytes2, 0, l_bytesRead);
setBytes(parameterIndex, l_bytes2);
}
}
else
{
//Version 7.1 only supported streams for LargeObjects
//but the jdbc spec indicates that streams should be
//available for LONGVARBINARY instead
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
OutputStream los = lob.getOutputStream();
try
{
// could be buffered, but then the OutputStream returned by LargeObject
// is buffered internally anyhow, so there would be no performance
// boost gained, if anything it would be worse!
int c = x.read();
int p = 0;
while (c > -1 && p < length)
{
los.write(c);
c = x.read();
p++;
}
los.close();
}
catch (IOException se)
{
throw new PSQLException("postgresql.unusual", se);
}
// lob is closed by the stream so don't call lob.close()
setInt(parameterIndex, oid);
}
}
/**
* In general, parameter values remain in force for repeated used of a
* Statement. Setting a parameter value automatically clears its
* previous value. However, in coms cases, it is useful to immediately
* previous value. However, in coms cases, it is useful to immediately
* release the resources used by the current parameter values; this
* can be done by calling clearParameters
*
@ -559,62 +604,66 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* @param x the object containing the input parameter value
* @param targetSqlType The SQL type to be send to the database
* @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC
* * types this is the number of digits after the decimal. For
* * all other types this value will be ignored.
* * types this is the number of digits after the decimal. For
* * all other types this value will be ignored.
* @exception SQLException if a database access error occurs
*/
public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException
{
if (x == null){
setNull(parameterIndex,Types.OTHER);
return;
if (x == null)
{
setNull(parameterIndex, Types.OTHER);
return ;
}
switch (targetSqlType)
{
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
case Types.DECIMAL:
case Types.NUMERIC:
if (x instanceof Boolean)
set(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0");
else
set(parameterIndex, x.toString());
break;
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
setString(parameterIndex, x.toString());
break;
case Types.DATE:
setDate(parameterIndex, (java.sql.Date)x);
break;
case Types.TIME:
setTime(parameterIndex, (Time)x);
break;
case Types.TIMESTAMP:
setTimestamp(parameterIndex, (Timestamp)x);
break;
case Types.BIT:
if (x instanceof Boolean) {
set(parameterIndex, ((Boolean)x).booleanValue() ? "TRUE" : "FALSE");
} else {
throw new PSQLException("postgresql.prep.type");
}
break;
case Types.BINARY:
case Types.VARBINARY:
setObject(parameterIndex,x);
break;
case Types.OTHER:
setString(parameterIndex, ((PGobject)x).getValue());
break;
default:
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
case Types.DECIMAL:
case Types.NUMERIC:
if (x instanceof Boolean)
set(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0");
else
set(parameterIndex, x.toString());
break;
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
setString(parameterIndex, x.toString());
break;
case Types.DATE:
setDate(parameterIndex, (java.sql.Date)x);
break;
case Types.TIME:
setTime(parameterIndex, (Time)x);
break;
case Types.TIMESTAMP:
setTimestamp(parameterIndex, (Timestamp)x);
break;
case Types.BIT:
if (x instanceof Boolean)
{
set(parameterIndex, ((Boolean)x).booleanValue() ? "TRUE" : "FALSE");
}
else
{
throw new PSQLException("postgresql.prep.type");
}
break;
case Types.BINARY:
case Types.VARBINARY:
setObject(parameterIndex, x);
break;
case Types.OTHER:
setString(parameterIndex, ((PGobject)x).getValue());
break;
default:
throw new PSQLException("postgresql.prep.type");
}
}
@ -622,18 +671,19 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
{
setObject(parameterIndex, x, targetSqlType, 0);
}
/**
* This stores an Object into a parameter.
* <p>New for 6.4, if the object is not recognised, but it is
* Serializable, then the object is serialised using the
* org.postgresql.util.Serialize class.
*/
/**
* This stores an Object into a parameter.
* <p>New for 6.4, if the object is not recognised, but it is
* Serializable, then the object is serialised using the
* org.postgresql.util.Serialize class.
*/
public void setObject(int parameterIndex, Object x) throws SQLException
{
if (x == null){
setNull(parameterIndex,Types.OTHER);
return;
if (x == null)
{
setNull(parameterIndex, Types.OTHER);
return ;
}
if (x instanceof String)
setString(parameterIndex, (String)x);
@ -667,11 +717,11 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
/**
* Some prepared statements return multiple results; the execute method
* handles these complex statements as well as the simpler form of
* handles these complex statements as well as the simpler form of
* statements handled by executeQuery and executeUpdate
*
* @return true if the next result is a ResultSet; false if it is an
* * update count or there are no more results
* * update count or there are no more results
* @exception SQLException if a database access error occurs
*/
public boolean execute() throws SQLException
@ -682,19 +732,20 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
for (i = 0 ; i < inStrings.length ; ++i)
{
if (inStrings[i] == null)
throw new PSQLException("postgresql.prep.param",new Integer(i + 1));
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
s.append (templateStrings[i]);
s.append (inStrings[i]);
}
s.append(templateStrings[inStrings.length]);
return super.execute(s.toString()); // in Statement class
return super.execute(s.toString()); // in Statement class
}
/**
* Returns the SQL statement with the current template values
* substituted.
*/
public String toString() {
public String toString()
{
StringBuffer s = new StringBuffer();
int i;
@ -709,14 +760,14 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
s.append(templateStrings[inStrings.length]);
return s.toString();
}
// **************************************************************
// END OF PUBLIC INTERFACE
// END OF PUBLIC INTERFACE
// **************************************************************
/**
* There are a lot of setXXX classes which all basically do
* the same thing. We need a method which actually does the
* the same thing. We need a method which actually does the
* set for us.
*
* @param paramIndex the index into the inString

File diff suppressed because it is too large Load Diff

View File

@ -22,442 +22,455 @@ import java.sql.Types;
*
* @see java.sql.ResultSetMetaData
*/
public class ResultSetMetaData implements java.sql.ResultSetMetaData
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).getPGType();
return type_name.equals("cash") || type_name.equals("money");
}
/**
* Indicates the nullability of values in the designated column.
*
* @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
{
/*
* TODO This needs a real implementation, taking into account columns
* defined with NOT NULL or PRIMARY KEY, CHECK constraints, views,
* functions etc.
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
*/
return columnNullableUnknown;
}
public ResultSetMetaData(Vector rows, Field[] fields)
{
this.rows = rows;
this.fields = fields;
}
/**
* 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
{
Field f = getField(column);
String type_name = f.getPGType();
int sql_type = f.getSQLType();
int typmod = f.getMod();
/**
* 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;
}
// I looked at other JDBC implementations and couldn't find a consistent
// interpretation of the "display size" for numeric values, so this is our's
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
/**
* 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;
}
// fixed length data types
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign)
if (type_name.equals( "int4" )
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2)
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits
if (type_name.equals( "float8" )) return 20; // dito, 20
if (type_name.equals( "char" )) return 1;
if (type_name.equals( "bool" )) return 1;
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD"
if (type_name.equals( "time" )) return 8; // 00:00:00-23:59:59
if (type_name.equals( "timestamp" )) return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
/**
* 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();
// variable length fields
typmod -= 4;
if (type_name.equals( "bpchar" )
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff )
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
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;
}
}
// if we don't know better
return f.getLength();
}
/**
* 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 database access error occurs
*/
public String getColumnName(int column) throws SQLException
{
Field f = getField(column);
if(f!=null)
return f.getName();
return "field"+column;
}
/**
* 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
{
return "";
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if(f != null)
return ((0xFFFF0000)&f.getMod())>>16;
else
return 0;
default:
return 0;
}
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if(f != null)
return (((0x0000FFFF)&f.getMod())-4);
else
return 0;
default:
return 0;
}
}
/**
* 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
{
return "";
}
/**
* 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 org.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).getPGType();
}
/**
* 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
{
return !isReadOnly(column);
}
/**
* 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 false;
}
// ********************************************************
// 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 PSQLException("postgresql.res.colrange");
return fields[columnIndex - 1];
}
/**
* 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).getPGType();
return type_name.equals("cash") || type_name.equals("money");
}
/**
* Indicates the nullability of values in the designated column.
*
* @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
{
/*
* TODO This needs a real implementation, taking into account columns
* defined with NOT NULL or PRIMARY KEY, CHECK constraints, views,
* functions etc.
*/
return columnNullableUnknown;
}
/**
* 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
{
Field f = getField(column);
String type_name = f.getPGType();
int sql_type = f.getSQLType();
int typmod = f.getMod();
// I looked at other JDBC implementations and couldn't find a consistent
// interpretation of the "display size" for numeric values, so this is our's
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
// fixed length data types
if (type_name.equals( "int2" ))
return 6; // -32768 to +32768 (5 digits and a sign)
if (type_name.equals( "int4" )
|| type_name.equals( "oid" ))
return 11; // -2147483648 to +2147483647
if (type_name.equals( "int8" ))
return 20; // -9223372036854775808 to +9223372036854775807
if (type_name.equals( "money" ))
return 12; // MONEY = DECIMAL(9,2)
if (type_name.equals( "float4" ))
return 11; // i checked it out ans wasn't able to produce more than 11 digits
if (type_name.equals( "float8" ))
return 20; // dito, 20
if (type_name.equals( "char" ))
return 1;
if (type_name.equals( "bool" ))
return 1;
if (type_name.equals( "date" ))
return 14; // "01/01/4713 BC" - "31/12/32767 AD"
if (type_name.equals( "time" ))
return 8; // 00:00:00-23:59:59
if (type_name.equals( "timestamp" ))
return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
// variable length fields
typmod -= 4;
if (type_name.equals( "bpchar" )
|| type_name.equals( "varchar" ))
return typmod; // VARHDRSZ=sizeof(int32)=4
if (type_name.equals( "numeric" ))
return ( (typmod >> 16) & 0xffff )
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
// if we don't know better
return f.getLength();
}
/**
* 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 database access error occurs
*/
public String getColumnName(int column) throws SQLException
{
Field f = getField(column);
if (f != null)
return f.getName();
return "field" + column;
}
/**
* 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
{
return "";
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if (f != null)
return ((0xFFFF0000)&f.getMod()) >> 16;
else
return 0;
default:
return 0;
}
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if (f != null)
return (((0x0000FFFF)&f.getMod()) - 4);
else
return 0;
default:
return 0;
}
}
/**
* 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
{
return "";
}
/**
* 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 org.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).getPGType();
}
/**
* 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
{
return !isReadOnly(column);
}
/**
* 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 false;
}
// ********************************************************
// 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 PSQLException("postgresql.res.colrange");
return fields[columnIndex - 1];
}
}

View File

@ -16,7 +16,7 @@ import org.postgresql.util.PSQLException;
* <p>Only one ResultSet per Statement can be open at any point in time.
* Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different
* Statements. All statement execute methods implicitly close a
* Statements. All statement execute methods implicitly close a
* statement's current ResultSet if an open one exists.
*
* @see java.sql.Statement
@ -24,7 +24,7 @@ import org.postgresql.util.PSQLException;
*/
public class Statement extends org.postgresql.Statement implements java.sql.Statement
{
private Connection connection; // The connection who created us
private Connection connection; // The connection who created us
/**
* Constructor for a Statement. It simply sets the connection
@ -73,7 +73,7 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
/**
* setCursorName defines the SQL cursor name that will be used by
* subsequent execute methods. This name can then be used in SQL
* subsequent execute methods. This name can then be used in SQL
* positioned update/delete statements to identify the current row
* in the ResultSet generated by this statement. If a database
* doesn't support positioned update/delete, this method is a
@ -81,10 +81,10 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
*
* <p><B>Note:</B> By definition, positioned update/delete execution
* must be done by a different Statement than the one which
* generated the ResultSet being used for positioning. Also, cursor
* generated the ResultSet being used for positioning. Also, cursor
* names must be unique within a Connection.
*
* <p>We throw an additional constriction. There can only be one
* <p>We throw an additional constriction. There can only be one
* cursor active at any one time.
*
* @param name the new cursor name
@ -98,20 +98,20 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
/**
* Execute a SQL statement that may return multiple results. We
* don't have to worry about this since we do not support multiple
* ResultSets. You can use getResultSet or getUpdateCount to
* ResultSets. You can use getResultSet or getUpdateCount to
* retrieve the result.
*
* @param sql any SQL statement
* @return true if the next result is a ResulSet, false if it is
* an update count or there are no more results
* an update count or there are no more results
* @exception SQLException if a database access error occurs
*/
public boolean execute(String sql) throws SQLException
{
if (escapeProcessing)
sql = escapeSQL(sql);
result = connection.ExecSQL(sql);
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
if (escapeProcessing)
sql = escapeSQL(sql);
result = connection.ExecSQL(sql);
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
}
/**
@ -124,8 +124,10 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
*/
public int getUpdateCount() throws SQLException
{
if (result == null) return -1;
if (((org.postgresql.ResultSet)result).reallyResultSet()) return -1;
if (result == null)
return -1;
if (((org.postgresql.ResultSet)result).reallyResultSet())
return -1;
return ((org.postgresql.ResultSet)result).getResultCount();
}

View File

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

View File

@ -41,322 +41,336 @@ import java.math.*;
public class CallableStatement extends org.postgresql.jdbc2.PreparedStatement implements java.sql.CallableStatement
{
/**
* @exception SQLException on failure
*/
public CallableStatement(Connection c,String q) throws SQLException
{
super(c,q);
}
/**
* @exception SQLException on failure
*/
public 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.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
}
/**
* Before executing a stored procedure call you must explicitly
* call registerOutParameter to register the java.sql.Type of each
* out parameter.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
{}
/**
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{
}
/**
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{}
// Old api?
//public boolean isNull(int parameterIndex) throws SQLException {
//return true;
//}
// Old api?
//public boolean isNull(int parameterIndex) throws SQLException {
//return true;
//}
/**
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException {
// check to see if the last access threw an exception
return false; // fake it for now
}
/**
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException
{
// check to see if the last access threw an exception
return false; // fake it for now
}
// Old api?
//public String getChar(int parameterIndex) throws SQLException {
//return null;
//}
// Old api?
//public String getChar(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public String getString(int parameterIndex) throws SQLException {
return null;
}
//public String getVarChar(int parameterIndex) throws SQLException {
// return null;
//}
/**
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
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;
//}
//public String getLongVarChar(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException {
return false;
}
/**
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException
{
return false;
}
/**
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException
{
return 0;
}
/**
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException {
return (float) 0.0;
}
/**
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException
{
return (float) 0.0;
}
/**
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException {
return 0.0;
}
/**
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException
{
return 0.0;
}
/**
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
* @deprecated in Java2.0
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException {
return null;
}
/**
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
* @deprecated in Java2.0
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException
{
return null;
}
/**
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException
{
return null;
}
// New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
// New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException
{
return null;
}
/**
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException
{
return null;
}
/**
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException {
return null;
}
/**
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException
{
return null;
}
//----------------------------------------------------------------------
// Advanced features:
//----------------------------------------------------------------------
// Advanced features:
// You can obtain a ParameterMetaData object to get information
// about the parameters to this CallableStatement.
//public DatabaseMetaData getMetaData() {
//return null;
//}
// 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.
/**
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException {
return null;
}
// getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details.
/**
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException
{
return null;
}
// ** JDBC 2 Extensions **
// ** JDBC 2 Extensions **
public java.sql.Array getArray(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.sql.Array getArray(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.math.BigDecimal getBigDecimal(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.math.BigDecimal getBigDecimal(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Blob getBlob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Blob getBlob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Clob getClob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Clob getClob(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Object getObject(int i,java.util.Map map) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Object getObject(int i, java.util.Map map) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Ref getRef(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Ref getRef(int i) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.sql.Date getDate(int i,java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Time getTime(int i,java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Time getTime(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Timestamp getTimestamp(int i,java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public void registerOutParameter(int parameterIndex, int sqlType,String typeName) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}

View File

@ -17,9 +17,9 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/**
* $Id: Connection.java,v 1.13 2001/10/09 20:47:35 barry Exp $
* $Id: Connection.java,v 1.14 2001/10/25 05:59:59 momjian Exp $
*
* A Connection represents a session with a specific database. Within the
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
* returned.
*
@ -29,306 +29,314 @@ import org.postgresql.util.*;
* with the getMetaData method.
*
* <p><B>Note:</B> By default, the Connection automatically commits changes
* after executing each statement. If auto-commit has been disabled, an
* after executing each statement. If auto-commit has been disabled, an
* explicit commit must be done or database changes will not be saved.
*
* @see java.sql.Connection
*/
public class Connection extends org.postgresql.Connection implements java.sql.Connection
{
// This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata;
// This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata;
/**
* The current type mappings
*/
protected java.util.Map typemap;
/**
* The current type mappings
*/
protected java.util.Map typemap;
/**
* 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
{
// The spec says default of TYPE_FORWARD_ONLY but everyone is used to
// using TYPE_SCROLL_INSENSITIVE
return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
}
/**
* 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
{
// The spec says default of TYPE_FORWARD_ONLY but everyone is used to
// using TYPE_SCROLL_INSENSITIVE
return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
/**
* 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
*
* @param resultSetType to use
* @param resultSetCuncurrency to use
* @return a new Statement object
* @exception SQLException passed through from the constructor
*/
public java.sql.Statement createStatement(int resultSetType,int resultSetConcurrency) throws SQLException
{
Statement s = new Statement(this);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
/**
* 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
*
* @param resultSetType to use
* @param resultSetCuncurrency to use
* @return a new Statement object
* @exception SQLException passed through from the constructor
*/
public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
Statement s = new Statement(this);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
/**
* 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 prepareStatement(sql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
}
/**
* 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 prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public java.sql.PreparedStatement prepareStatement(String sql,int resultSetType,int resultSetConcurrency) throws SQLException
{
PreparedStatement s = new PreparedStatement(this,sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
PreparedStatement s = new PreparedStatement(this, sql);
s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency);
return s;
}
/**
* 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
{
return prepareCall(sql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
}
/**
* 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
{
return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
}
public java.sql.CallableStatement prepareCall(String sql,int resultSetType,int resultSetConcurrency) throws SQLException
{
throw new PSQLException("postgresql.con.call");
//CallableStatement s = new CallableStatement(this,sql);
//s.setResultSetType(resultSetType);
//s.setResultSetConcurrency(resultSetConcurrency);
//return s;
}
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
throw new PSQLException("postgresql.con.call");
//CallableStatement s = new CallableStatement(this,sql);
//s.setResultSetType(resultSetType);
//s.setResultSetConcurrency(resultSetConcurrency);
//return s;
}
/**
* Tests to see if a Connection is closed.
*
* Peter Feb 7 2000: Now I've discovered that this doesn't actually obey the
* specifications. Under JDBC2.1, this should only be valid _after_ close()
* has been called. It's result is not guraranteed to be valid before, and
* client code should not use it to see if a connection is open. The spec says
* that the client should monitor the SQLExceptions thrown when their queries
* fail because the connection is dead.
*
* I don't like this definition. As it doesn't hurt breaking it here, our
* isClosed() implementation does test the connection, so for PostgreSQL, you
* can rely on isClosed() returning a valid result.
*
* @return the status of the connection
* @exception SQLException (why?)
*/
public boolean isClosed() throws SQLException
{
// If the stream is gone, then close() was called
if(pg_stream == null)
return true;
/**
* Tests to see if a Connection is closed.
*
* Peter Feb 7 2000: Now I've discovered that this doesn't actually obey the
* specifications. Under JDBC2.1, this should only be valid _after_ close()
* has been called. It's result is not guraranteed to be valid before, and
* client code should not use it to see if a connection is open. The spec says
* that the client should monitor the SQLExceptions thrown when their queries
* fail because the connection is dead.
*
* I don't like this definition. As it doesn't hurt breaking it here, our
* isClosed() implementation does test the connection, so for PostgreSQL, you
* can rely on isClosed() returning a valid result.
*
* @return the status of the connection
* @exception SQLException (why?)
*/
public boolean isClosed() throws SQLException
{
// If the stream is gone, then close() was called
if (pg_stream == null)
return true;
// ok, test the connection
try {
// by sending an empty query. If we are dead, then an SQLException should
// be thrown
java.sql.ResultSet rs = ExecSQL(" ");
if(rs!=null)
rs.close();
// ok, test the connection
try
{
// by sending an empty query. If we are dead, then an SQLException should
// be thrown
java.sql.ResultSet rs = ExecSQL(" ");
if (rs != null)
rs.close();
// By now, we must be alive
return false;
} catch(SQLException se) {
// Why throw an SQLException as this may fail without throwing one,
// ie isClosed() is called incase the connection has died, and we don't
// want to find out by an Exception, so instead we return true, as its
// most likely why it was thrown in the first place.
return true;
}
}
// By now, we must be alive
return false;
}
catch (SQLException se)
{
// Why throw an SQLException as this may fail without throwing one,
// ie isClosed() is called incase the connection has died, and we don't
// want to find out by an Exception, so instead we return true, as its
// most likely why it was thrown in the first place.
return true;
}
}
/**
* 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
{
if(metadata==null)
metadata = new DatabaseMetaData(this);
return metadata;
}
/**
* 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
{
if (metadata == null)
metadata = new DatabaseMetaData(this);
return metadata;
}
/**
* This overides the method in org.postgresql.Connection and returns a
* ResultSet.
*/
public java.sql.ResultSet getResultSet(org.postgresql.Connection conn, java.sql.Statement stat,Field[] fields, Vector tuples, String status, int updateCount, int insertOID, boolean binaryCursor) throws SQLException
{
// In 7.1 we now test concurrency to see which class to return. If we are not working with a
// Statement then default to a normal ResultSet object.
if(stat!=null) {
if(stat.getResultSetConcurrency()==java.sql.ResultSet.CONCUR_UPDATABLE)
return new org.postgresql.jdbc2.UpdateableResultSet((org.postgresql.jdbc2.Connection)conn,fields,tuples,status,updateCount,insertOID,binaryCursor);
}
/**
* This overides the method in org.postgresql.Connection and returns a
* ResultSet.
*/
public java.sql.ResultSet getResultSet(org.postgresql.Connection conn, java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount, int insertOID, boolean binaryCursor) throws SQLException
{
// In 7.1 we now test concurrency to see which class to return. If we are not working with a
// Statement then default to a normal ResultSet object.
if (stat != null)
{
if (stat.getResultSetConcurrency() == java.sql.ResultSet.CONCUR_UPDATABLE)
return new org.postgresql.jdbc2.UpdateableResultSet((org.postgresql.jdbc2.Connection)conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
return new org.postgresql.jdbc2.ResultSet((org.postgresql.jdbc2.Connection)conn,fields,tuples,status,updateCount,insertOID,binaryCursor);
}
return new org.postgresql.jdbc2.ResultSet((org.postgresql.jdbc2.Connection)conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
// *****************
// JDBC 2 extensions
// *****************
// *****************
// JDBC 2 extensions
// *****************
public java.util.Map getTypeMap() throws SQLException
{
// new in 7.1
return typemap;
}
public java.util.Map getTypeMap() throws SQLException
{
// new in 7.1
return typemap;
}
public void setTypeMap(java.util.Map map) throws SQLException
{
// new in 7.1
typemap=map;
}
public void setTypeMap(java.util.Map map) throws SQLException
{
// new in 7.1
typemap = map;
}
/**
* This overides the standard internal getObject method so that we can
* check the jdbc2 type map first
*
* @return PGobject for this type, and set to value
* @exception SQLException if value is not correct for this type
* @see org.postgresql.util.Serialize
*/
public Object getObject(String type,String value) throws SQLException
{
if(typemap!=null) {
SQLData d = (SQLData) typemap.get(type);
if(d!=null) {
// Handle the type (requires SQLInput & SQLOutput classes to be implemented)
throw org.postgresql.Driver.notImplemented();
}
}
/**
* This overides the standard internal getObject method so that we can
* check the jdbc2 type map first
*
* @return PGobject for this type, and set to value
* @exception SQLException if value is not correct for this type
* @see org.postgresql.util.Serialize
*/
public Object getObject(String type, String value) throws SQLException
{
if (typemap != null)
{
SQLData d = (SQLData) typemap.get(type);
if (d != null)
{
// Handle the type (requires SQLInput & SQLOutput classes to be implemented)
throw org.postgresql.Driver.notImplemented();
}
}
// Default to the original method
return super.getObject(type,value);
}
// Default to the original method
return super.getObject(type, value);
}
/* An implementation of the abstract method in the parent class.
* This implemetation uses the jdbc2Types array to support the jdbc2
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types.
*/
public int getSQLType(String pgTypeName)
{
int sqlType = Types.OTHER; // default value
for(int i=0;i<jdbc2Types.length;i++) {
if(pgTypeName.equals(jdbc2Types[i])) {
sqlType=jdbc2Typei[i];
break;
}
}
return sqlType;
}
/* An implementation of the abstract method in the parent class.
* This implemetation uses the jdbc2Types array to support the jdbc2
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types.
*/
public int getSQLType(String pgTypeName)
{
int sqlType = Types.OTHER; // default value
for (int i = 0;i < jdbc2Types.length;i++)
{
if (pgTypeName.equals(jdbc2Types[i]))
{
sqlType = jdbc2Typei[i];
break;
}
}
return sqlType;
}
/**
* This table holds the org.postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String jdbc2Types[] = {
"int2",
"int4","oid",
"int8",
"cash","money",
"numeric",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
"bytea",
"bool",
"date",
"time",
"abstime","timestamp",
"_bool", "_char", "_int2", "_int4", "_text",
"_oid", "_varchar", "_int8", "_float4", "_float8",
"_abstime", "_date", "_time", "_timestamp", "_numeric",
"_bytea"
};
/**
* This table holds the org.postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String jdbc2Types[] = {
"int2",
"int4", "oid",
"int8",
"cash", "money",
"numeric",
"float4",
"float8",
"bpchar", "char", "char2", "char4", "char8", "char16",
"varchar", "text", "name", "filename",
"bytea",
"bool",
"date",
"time",
"abstime", "timestamp",
"_bool", "_char", "_int2", "_int4", "_text",
"_oid", "_varchar", "_int8", "_float4", "_float8",
"_abstime", "_date", "_time", "_timestamp", "_numeric",
"_bytea"
};
/**
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int jdbc2Typei[] = {
Types.SMALLINT,
Types.INTEGER,Types.INTEGER,
Types.BIGINT,
Types.DOUBLE,Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY
};
/**
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int jdbc2Typei[] = {
Types.SMALLINT,
Types.INTEGER, Types.INTEGER,
Types.BIGINT,
Types.DOUBLE, Types.DOUBLE,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP, Types.TIMESTAMP,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
Types.ARRAY
};
}

File diff suppressed because it is too large Load Diff

View File

@ -4,26 +4,29 @@ import org.postgresql.util.*;
import java.sql.*;
/**
* This class extends java.sql.BatchUpdateException, and provides our
* This class extends java.sql.BatchUpdateException, and provides our
* internationalisation handling.
*/
class PBatchUpdateException extends java.sql.BatchUpdateException {
class PBatchUpdateException extends java.sql.BatchUpdateException
{
private String message;
public PBatchUpdateException(
String error, Object arg1, Object arg2, int[] updateCounts ) {
String error, Object arg1, Object arg2, int[] updateCounts )
{
super(updateCounts);
Object[] argv = new Object[2];
argv[0] = arg1;
argv[1] = arg2;
translate(error,argv);
translate(error, argv);
}
private void translate(String error, Object[] args) {
message = MessageTranslator.translate(error,args);
private void translate(String error, Object[] args)
{
message = MessageTranslator.translate(error, args);
}
// Overides Throwable
@ -32,7 +35,7 @@ class PBatchUpdateException extends java.sql.BatchUpdateException {
return message;
}
// Overides Throwable
// Overides Throwable
public String getMessage()
{
return message;
@ -41,6 +44,6 @@ class PBatchUpdateException extends java.sql.BatchUpdateException {
// Overides Object
public String toString()
{
return message;
return message;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,451 +17,464 @@ import org.postgresql.util.*;
*
* @see java.sql.ResultSetMetaData
*/
public class ResultSetMetaData implements java.sql.ResultSetMetaData
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).getPGType();
return type_name.equals("cash") || type_name.equals("money");
}
/**
* Indicates the nullability of values in the designated column.
*
* @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
{
/*
* TODO This needs a real implementation, taking into account columns
* defined with NOT NULL or PRIMARY KEY, CHECK constraints, views,
* functions etc.
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
*/
return columnNullableUnknown;
}
/**
* 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
{
Field f = getField(column);
String type_name = f.getPGType();
int sql_type = f.getSQLType();
int typmod = f.getMod();
public ResultSetMetaData(Vector rows, Field[] fields)
{
this.rows = rows;
this.fields = fields;
}
// I looked at other JDBC implementations and couldn't find a consistent
// interpretation of the "display size" for numeric values, so this is our's
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
/**
* 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;
}
// fixed length data types
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign)
if (type_name.equals( "int4" )
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2)
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits
if (type_name.equals( "float8" )) return 20; // dito, 20
if (type_name.equals( "char" )) return 1;
if (type_name.equals( "bool" )) return 1;
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD"
if (type_name.equals( "time" )) return 8; // 00:00:00-23:59:59
if (type_name.equals( "timestamp" )) return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
/**
* 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;
}
// variable length fields
typmod -= 4;
if (type_name.equals( "bpchar" )
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff )
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
/**
* 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).getPGType();
return type_name.equals("cash") || type_name.equals("money");
}
/**
* Indicates the nullability of values in the designated column.
*
* @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
{
/*
* TODO This needs a real implementation, taking into account columns
* defined with NOT NULL or PRIMARY KEY, CHECK constraints, views,
* functions etc.
*/
return columnNullableUnknown;
}
/**
* 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
{
Field f = getField(column);
String type_name = f.getPGType();
int sql_type = f.getSQLType();
int typmod = f.getMod();
// I looked at other JDBC implementations and couldn't find a consistent
// interpretation of the "display size" for numeric values, so this is our's
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
// fixed length data types
if (type_name.equals( "int2" ))
return 6; // -32768 to +32768 (5 digits and a sign)
if (type_name.equals( "int4" )
|| type_name.equals( "oid" ))
return 11; // -2147483648 to +2147483647
if (type_name.equals( "int8" ))
return 20; // -9223372036854775808 to +9223372036854775807
if (type_name.equals( "money" ))
return 12; // MONEY = DECIMAL(9,2)
if (type_name.equals( "float4" ))
return 11; // i checked it out ans wasn't able to produce more than 11 digits
if (type_name.equals( "float8" ))
return 20; // dito, 20
if (type_name.equals( "char" ))
return 1;
if (type_name.equals( "bool" ))
return 1;
if (type_name.equals( "date" ))
return 14; // "01/01/4713 BC" - "31/12/32767 AD"
if (type_name.equals( "time" ))
return 8; // 00:00:00-23:59:59
if (type_name.equals( "timestamp" ))
return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
// variable length fields
typmod -= 4;
if (type_name.equals( "bpchar" )
|| type_name.equals( "varchar" ))
return typmod; // VARHDRSZ=sizeof(int32)=4
if (type_name.equals( "numeric" ))
return ( (typmod >> 16) & 0xffff )
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
// if we don't know better
return f.getLength();
}
/**
* 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 database access error occurs
*/
public String getColumnName(int column) throws SQLException
{
Field f = getField(column);
if (f != null)
return f.getName();
return "field" + column;
}
/**
* 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
{
return "";
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if (f != null)
return ((0xFFFF0000)&f.getMod()) >> 16;
else
return 0;
default:
return 0;
}
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if (f != null)
return (((0x0000FFFF)&f.getMod()) - 4);
else
return 0;
default:
return 0;
}
}
/**
* 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
{
return "";
}
/**
* 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 org.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).getPGType();
}
/**
* 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
{
return !isReadOnly(column);
}
/**
* 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 false;
}
// ********************************************************
// 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 PSQLException("postgresql.res.colrange");
return fields[columnIndex - 1];
}
// ** JDBC 2 Extensions **
// This can hook into our PG_Object mechanism
public String getColumnClassName(int column) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
// if we don't know better
return f.getLength();
}
/**
* 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 database access error occurs
*/
public String getColumnName(int column) throws SQLException
{
Field f = getField(column);
if(f!=null)
return f.getName();
return "field"+column;
}
/**
* 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
{
return "";
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if(f != null)
return ((0xFFFF0000)&f.getMod())>>16;
else
return 0;
default:
return 0;
}
}
/**
* 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;
case Types.VARCHAR:
return 0;
case Types.NUMERIC:
Field f = getField(column);
if(f != null)
return (((0x0000FFFF)&f.getMod())-4);
else
return 0;
default:
return 0;
}
}
/**
* 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
{
return "";
}
/**
* 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 org.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).getPGType();
}
/**
* 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
{
return !isReadOnly(column);
}
/**
* 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 false;
}
// ********************************************************
// 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 PSQLException("postgresql.res.colrange");
return fields[columnIndex - 1];
}
// ** JDBC 2 Extensions **
// This can hook into our PG_Object mechanism
public String getColumnClassName(int column) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}

View File

@ -16,7 +16,7 @@ import org.postgresql.util.*;
* <p>Only one ResultSet per Statement can be open at any point in time.
* Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different
* Statements. All statement execute methods implicitly close a
* Statements. All statement execute methods implicitly close a
* statement's current ResultSet if an open one exists.
*
* @see java.sql.Statement
@ -24,10 +24,10 @@ import org.postgresql.util.*;
*/
public class Statement extends org.postgresql.Statement implements java.sql.Statement
{
private Connection connection; // The connection who created us
private Vector batch=null;
private int resultsettype; // the resultset type to return
private int concurrency; // is it updateable or not?
private Connection connection; // The connection who created us
private Vector batch = null;
private int resultsettype; // the resultset type to return
private int concurrency; // is it updateable or not?
/**
* Constructor for a Statement. It simply sets the connection
@ -38,8 +38,8 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
public Statement (Connection c)
{
connection = c;
resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
concurrency = java.sql.ResultSet.CONCUR_READ_ONLY;
resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
concurrency = java.sql.ResultSet.CONCUR_READ_ONLY;
}
/**
@ -51,12 +51,12 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
*/
public java.sql.ResultSet executeQuery(String sql) throws SQLException
{
this.execute(sql);
while (result != null && !((org.postgresql.ResultSet)result).reallyResultSet())
result = ((org.postgresql.ResultSet)result).getNext();
if (result == null)
throw new PSQLException("postgresql.stat.noresult");
return result;
this.execute(sql);
while (result != null && !((org.postgresql.ResultSet)result).reallyResultSet())
result = ((org.postgresql.ResultSet)result).getNext();
if (result == null)
throw new PSQLException("postgresql.stat.noresult");
return result;
}
/**
@ -78,7 +78,7 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
/**
* setCursorName defines the SQL cursor name that will be used by
* subsequent execute methods. This name can then be used in SQL
* subsequent execute methods. This name can then be used in SQL
* positioned update/delete statements to identify the current row
* in the ResultSet generated by this statement. If a database
* doesn't support positioned update/delete, this method is a
@ -86,10 +86,10 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
*
* <p><B>Note:</B> By definition, positioned update/delete execution
* must be done by a different Statement than the one which
* generated the ResultSet being used for positioning. Also, cursor
* generated the ResultSet being used for positioning. Also, cursor
* names must be unique within a Connection.
*
* <p>We throw an additional constriction. There can only be one
* <p>We throw an additional constriction. There can only be one
* cursor active at any one time.
*
* @param name the new cursor name
@ -103,36 +103,37 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
/**
* Execute a SQL statement that may return multiple results. We
* don't have to worry about this since we do not support multiple
* ResultSets. You can use getResultSet or getUpdateCount to
* ResultSets. You can use getResultSet or getUpdateCount to
* retrieve the result.
*
* @param sql any SQL statement
* @return true if the next result is a ResulSet, false if it is
* an update count or there are no more results
* an update count or there are no more results
* @exception SQLException if a database access error occurs
*/
public boolean execute(String sql) throws SQLException
{
if (escapeProcessing)
sql = escapeSQL(sql);
public boolean execute(String sql) throws SQLException
{
if (escapeProcessing)
sql = escapeSQL(sql);
// New in 7.1, if we have a previous resultset then force it to close
// This brings us nearer to compliance, and helps memory management.
// Internal stuff will call ExecSQL directly, bypassing this.
if(result!=null) {
java.sql.ResultSet rs = getResultSet();
if(rs!=null)
rs.close();
}
// New in 7.1, if we have a previous resultset then force it to close
// This brings us nearer to compliance, and helps memory management.
// Internal stuff will call ExecSQL directly, bypassing this.
if (result != null)
{
java.sql.ResultSet rs = getResultSet();
if (rs != null)
rs.close();
}
// New in 7.1, pass Statement so that ExecSQL can customise to it
result = connection.ExecSQL(sql,this);
// New in 7.1, pass Statement so that ExecSQL can customise to it
result = connection.ExecSQL(sql, this);
// New in 7.1, required for ResultSet.getStatement() to work
((org.postgresql.jdbc2.ResultSet)result).setStatement(this);
// New in 7.1, required for ResultSet.getStatement() to work
((org.postgresql.jdbc2.ResultSet)result).setStatement(this);
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
}
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
}
/**
* getUpdateCount returns the current result as an update count,
@ -144,8 +145,10 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
*/
public int getUpdateCount() throws SQLException
{
if (result == null) return -1;
if (((org.postgresql.ResultSet)result).reallyResultSet()) return -1;
if (result == null)
return -1;
if (((org.postgresql.ResultSet)result).reallyResultSet())
return -1;
return ((org.postgresql.ResultSet)result).getResultCount();
}
@ -162,98 +165,103 @@ public class Statement extends org.postgresql.Statement implements java.sql.Stat
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
}
// ** JDBC 2 Extensions **
// ** JDBC 2 Extensions **
public void addBatch(String sql) throws SQLException
{
if(batch==null)
batch=new Vector();
batch.addElement(sql);
}
public void clearBatch() throws SQLException
{
if(batch!=null)
batch.removeAllElements();
}
public int[] executeBatch() throws SQLException
{
if(batch==null)
batch=new Vector();
int size=batch.size();
int[] result=new int[size];
int i=0;
try {
for(i=0;i<size;i++)
result[i]=this.executeUpdate((String)batch.elementAt(i));
} catch(SQLException e) {
int[] resultSucceeded = new int[i];
System.arraycopy(result,0,resultSucceeded,0,i);
PBatchUpdateException updex =
new PBatchUpdateException("postgresql.stat.batch.error",
new Integer(i), batch.elementAt(i), resultSucceeded);
updex.setNextException(e);
throw updex;
} finally {
batch.removeAllElements();
public void addBatch(String sql) throws SQLException
{
if (batch == null)
batch = new Vector();
batch.addElement(sql);
}
return result;
}
public java.sql.Connection getConnection() throws SQLException
{
return (java.sql.Connection)connection;
}
public void clearBatch() throws SQLException
{
if (batch != null)
batch.removeAllElements();
}
public int getFetchDirection() throws SQLException
{
throw new PSQLException("postgresql.psqlnotimp");
}
public int[] executeBatch() throws SQLException
{
if (batch == null)
batch = new Vector();
int size = batch.size();
int[] result = new int[size];
int i = 0;
try
{
for (i = 0;i < size;i++)
result[i] = this.executeUpdate((String)batch.elementAt(i));
}
catch (SQLException e)
{
int[] resultSucceeded = new int[i];
System.arraycopy(result, 0, resultSucceeded, 0, i);
public int getFetchSize() throws SQLException
{
// This one can only return a valid value when were a cursor?
throw org.postgresql.Driver.notImplemented();
}
PBatchUpdateException updex =
new PBatchUpdateException("postgresql.stat.batch.error",
new Integer(i), batch.elementAt(i), resultSucceeded);
updex.setNextException(e);
public int getResultSetConcurrency() throws SQLException
{
// new in 7.1
return concurrency;
}
throw updex;
}
finally
{
batch.removeAllElements();
}
return result;
}
public int getResultSetType() throws SQLException
{
// new in 7.1
return resultsettype;
}
public java.sql.Connection getConnection() throws SQLException
{
return (java.sql.Connection)connection;
}
public void setFetchDirection(int direction) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public int getFetchDirection() throws SQLException
{
throw new PSQLException("postgresql.psqlnotimp");
}
public void setFetchSize(int rows) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public int getFetchSize() throws SQLException
{
// This one can only return a valid value when were a cursor?
throw org.postgresql.Driver.notImplemented();
}
/**
* New in 7.1
*/
public void setResultSetConcurrency(int value) throws SQLException
{
concurrency=value;
}
public int getResultSetConcurrency() throws SQLException
{
// new in 7.1
return concurrency;
}
/**
* New in 7.1
*/
public void setResultSetType(int value) throws SQLException
{
resultsettype=value;
}
public int getResultSetType() throws SQLException
{
// new in 7.1
return resultsettype;
}
public void setFetchDirection(int direction) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
public void setFetchSize(int rows) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/**
* New in 7.1
*/
public void setResultSetConcurrency(int value) throws SQLException
{
concurrency = value;
}
/**
* New in 7.1
*/
public void setResultSetType(int value) throws SQLException
{
resultsettype = value;
}
}

View File

@ -29,226 +29,226 @@ import org.postgresql.util.*;
public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet
{
/**
* 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 UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount,int insertOID, boolean binaryCursor)
{
super(conn,fields,tuples,status,updateCount,insertOID,binaryCursor);
}
/**
* 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 UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount, int insertOID, boolean binaryCursor)
{
super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
}
/**
* 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 UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
// {
// super(conn,fields,tuples,status,updateCount,0,false);
//}
/**
* 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 UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
// {
// super(conn,fields,tuples,status,updateCount,0,false);
//}
public void cancelRowUpdates() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void cancelRowUpdates() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void deleteRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void deleteRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public int getConcurrency() throws SQLException
{
// New in 7.1 - The updateable ResultSet class will now return
// CONCUR_UPDATEABLE.
return CONCUR_UPDATABLE;
}
public int getConcurrency() throws SQLException
{
// New in 7.1 - The updateable ResultSet class will now return
// CONCUR_UPDATEABLE.
return CONCUR_UPDATABLE;
}
public void insertRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void insertRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void moveToCurrentRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void moveToCurrentRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void moveToInsertRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void moveToInsertRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public boolean rowDeleted() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value!
}
public boolean rowDeleted() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value!
}
public boolean rowInserted() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value!
}
public boolean rowInserted() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value!
}
public boolean rowUpdated() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value!
}
public boolean rowUpdated() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value!
}
public void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateAsciiStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBigDecimal(int columnIndex,
java.math.BigDecimal x
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBigDecimal(int columnIndex,
java.math.BigDecimal x
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBoolean(int columnIndex,boolean x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBoolean(int columnIndex, boolean x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateByte(int columnIndex,byte x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateByte(int columnIndex, byte x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBytes(int columnIndex,byte[] x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateBytes(int columnIndex, byte[] x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateCharacterStream(int columnIndex,
java.io.Reader x,
int length
) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateDate(int columnIndex,java.sql.Date x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateDate(int columnIndex, java.sql.Date x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateDouble(int columnIndex,double x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateDouble(int columnIndex, double x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateFloat(int columnIndex,float x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateFloat(int columnIndex, float x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateInt(int columnIndex,int x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateInt(int columnIndex, int x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateLong(int columnIndex,long x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateLong(int columnIndex, long x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateNull(int columnIndex) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateNull(int columnIndex) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateObject(int columnIndex,Object x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateObject(int columnIndex, Object x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateObject(int columnIndex,Object x,int scale) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateObject(int columnIndex, Object x, int scale) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateRow() throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateShort(int columnIndex,short x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateShort(int columnIndex, short x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateString(int columnIndex,String x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateString(int columnIndex, String x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateTime(int columnIndex,Time x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateTime(int columnIndex, Time x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateTimestamp(int columnIndex,Timestamp x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
{
// only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented();
}
}

View File

@ -9,155 +9,179 @@ import java.sql.SQLException;
* For now, the bare minimum is implemented. Later (after 7.1) we will overide
* the other read methods to optimise them.
*/
public class BlobInputStream extends InputStream {
/**
* The parent LargeObject
*/
private LargeObject lo;
public class BlobInputStream extends InputStream
{
/**
* The parent LargeObject
*/
private LargeObject lo;
/**
* Buffer used to improve performance
*/
private byte[] buffer;
/**
* Buffer used to improve performance
*/
private byte[] buffer;
/**
* Position within buffer
*/
private int bpos;
/**
* Position within buffer
*/
private int bpos;
/**
* The buffer size
*/
private int bsize;
/**
* The buffer size
*/
private int bsize;
/**
* The mark position
*/
private int mpos=0;
/**
* The mark position
*/
private int mpos = 0;
/**
* @param lo LargeObject to read from
*/
public BlobInputStream(LargeObject lo) {
this(lo,1024);
}
/**
* @param lo LargeObject to read from
*/
public BlobInputStream(LargeObject lo)
{
this(lo, 1024);
}
/**
* @param lo LargeObject to read from
* @param bsize buffer size
*/
public BlobInputStream(LargeObject lo,int bsize) {
this.lo=lo;
buffer=null;
bpos=0;
this.bsize=bsize;
}
/**
* @param lo LargeObject to read from
* @param bsize buffer size
*/
public BlobInputStream(LargeObject lo, int bsize)
{
this.lo = lo;
buffer = null;
bpos = 0;
this.bsize = bsize;
}
/**
* The minimum required to implement input stream
*/
public int read() throws java.io.IOException {
try {
if (buffer == null || bpos >= buffer.length) {
buffer=lo.read(bsize);
bpos=0;
}
/**
* The minimum required to implement input stream
*/
public int read() throws java.io.IOException
{
try
{
if (buffer == null || bpos >= buffer.length)
{
buffer = lo.read(bsize);
bpos = 0;
}
// Handle EOF
if(bpos >= buffer.length) {
return -1;
}
// Handle EOF
if (bpos >= buffer.length)
{
return -1;
}
int ret = (buffer[bpos] & 0x7F);
if ((buffer[bpos] &0x80) == 0x80) {
ret |= 0x80;
}
int ret = (buffer[bpos] & 0x7F);
if ((buffer[bpos] &0x80) == 0x80)
{
ret |= 0x80;
}
bpos++;
bpos++;
return ret;
} catch(SQLException se) {
throw new IOException(se.toString());
}
}
return ret;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
*
* <p> The <code>close</code> method of <code>InputStream</code> does
* nothing.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException {
try {
lo.close();
lo=null;
} catch(SQLException se) {
throw new IOException(se.toString());
}
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
*
* <p> The <code>close</code> method of <code>InputStream</code> does
* nothing.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException
{
try
{
lo.close();
lo = null;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Marks the current position in this input stream. A subsequent call to
* the <code>reset</code> method repositions this stream at the last marked
* position so that subsequent reads re-read the same bytes.
*
* <p> The <code>readlimit</code> arguments tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
*
* <p> The general contract of <code>mark</code> is that, if the method
* <code>markSupported</code> returns <code>true</code>, the stream somehow
* remembers all the bytes read after the call to <code>mark</code> and
* stands ready to supply those same bytes again if and whenever the method
* <code>reset</code> is called. However, the stream is not required to
* remember any data at all if more than <code>readlimit</code> bytes are
* read from the stream before <code>reset</code> is called.
*
* <p> The <code>mark</code> method of <code>InputStream</code> does
* nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.InputStream#reset()
*/
public synchronized void mark(int readlimit) {
try {
mpos=lo.tell();
} catch(SQLException se) {
//throw new IOException(se.toString());
}
}
/**
* Marks the current position in this input stream. A subsequent call to
* the <code>reset</code> method repositions this stream at the last marked
* position so that subsequent reads re-read the same bytes.
*
* <p> The <code>readlimit</code> arguments tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
*
* <p> The general contract of <code>mark</code> is that, if the method
* <code>markSupported</code> returns <code>true</code>, the stream somehow
* remembers all the bytes read after the call to <code>mark</code> and
* stands ready to supply those same bytes again if and whenever the method
* <code>reset</code> is called. However, the stream is not required to
* remember any data at all if more than <code>readlimit</code> bytes are
* read from the stream before <code>reset</code> is called.
*
* <p> The <code>mark</code> method of <code>InputStream</code> does
* nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.InputStream#reset()
*/
public synchronized void mark(int readlimit)
{
try
{
mpos = lo.tell();
}
catch (SQLException se)
{
//throw new IOException(se.toString());
}
}
/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
* NB: If mark is not called we move to the begining.
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
*/
public synchronized void reset() throws IOException {
try {
lo.seek(mpos);
} catch(SQLException se) {
throw new IOException(se.toString());
}
}
/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
* NB: If mark is not called we move to the begining.
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
*/
public synchronized void reset()
throws IOException
{
try
{
lo.seek(mpos);
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Tests if this input stream supports the <code>mark</code> and
* <code>reset</code> methods. The <code>markSupported</code> method of
* <code>InputStream</code> returns <code>false</code>.
*
* @return <code>true</code> if this true type supports the mark and reset
* method; <code>false</code> otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
public boolean markSupported() {
return true;
}
/**
* Tests if this input stream supports the <code>mark</code> and
* <code>reset</code> methods. The <code>markSupported</code> method of
* <code>InputStream</code> returns <code>false</code>.
*
* @return <code>true</code> if this true type supports the mark and reset
* method; <code>false</code> otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
public boolean markSupported()
{
return true;
}
}

View File

@ -7,97 +7,113 @@ import java.sql.SQLException;
/**
* This implements a basic output stream that writes to a LargeObject
*/
public class BlobOutputStream extends OutputStream {
/**
* The parent LargeObject
*/
private LargeObject lo;
public class BlobOutputStream extends OutputStream
{
/**
* The parent LargeObject
*/
private LargeObject lo;
/**
* Buffer
*/
private byte buf[];
/**
* Buffer
*/
private byte buf[];
/**
* Size of the buffer (default 1K)
*/
private int bsize;
/**
* Size of the buffer (default 1K)
*/
private int bsize;
/**
* Position within the buffer
*/
private int bpos;
/**
* Position within the buffer
*/
private int bpos;
/**
* Create an OutputStream to a large object
* @param lo LargeObject
*/
public BlobOutputStream(LargeObject lo) {
this(lo,1024);
}
/**
* Create an OutputStream to a large object
* @param lo LargeObject
*/
public BlobOutputStream(LargeObject lo)
{
this(lo, 1024);
}
/**
* Create an OutputStream to a large object
* @param lo LargeObject
* @param bsize The size of the buffer used to improve performance
*/
public BlobOutputStream(LargeObject lo,int bsize) {
this.lo=lo;
this.bsize=bsize;
buf=new byte[bsize];
bpos=0;
}
/**
* Create an OutputStream to a large object
* @param lo LargeObject
* @param bsize The size of the buffer used to improve performance
*/
public BlobOutputStream(LargeObject lo, int bsize)
{
this.lo = lo;
this.bsize = bsize;
buf = new byte[bsize];
bpos = 0;
}
public void write(int b) throws java.io.IOException {
try {
if(bpos>=bsize) {
lo.write(buf);
bpos=0;
}
buf[bpos++]=(byte)b;
} catch(SQLException se) {
throw new IOException(se.toString());
}
}
public void write(int b) throws java.io.IOException
{
try
{
if (bpos >= bsize)
{
lo.write(buf);
bpos = 0;
}
buf[bpos++] = (byte)b;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of <code>flush</code> is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
*
* @exception IOException if an I/O error occurs.
*/
public void flush() throws IOException {
try {
if(bpos>0)
lo.write(buf,0,bpos);
bpos=0;
} catch(SQLException se) {
throw new IOException(se.toString());
}
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of <code>flush</code> is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
*
* @exception IOException if an I/O error occurs.
*/
public void flush() throws IOException
{
try
{
if (bpos > 0)
lo.write(buf, 0, bpos);
bpos = 0;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Closes this output stream and releases any system resources
* associated with this stream. The general contract of <code>close</code>
* is that it closes the output stream. A closed stream cannot perform
* output operations and cannot be reopened.
* <p>
* The <code>close</code> method of <code>OutputStream</code> does nothing.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException {
try {
flush();
lo.close();
lo=null;
} catch(SQLException se) {
throw new IOException(se.toString());
}
}
/**
* Closes this output stream and releases any system resources
* associated with this stream. The general contract of <code>close</code>
* is that it closes the output stream. A closed stream cannot perform
* output operations and cannot be reopened.
* <p>
* The <code>close</code> method of <code>OutputStream</code> does nothing.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException
{
try
{
flush();
lo.close();
lo = null;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
}
}

View File

@ -43,271 +43,278 @@ import org.postgresql.fastpath.*;
*/
public class LargeObject
{
/**
* Indicates a seek from the begining of a file
*/
public static final int SEEK_SET = 0;
/**
* Indicates a seek from the begining of a file
*/
public static final int SEEK_SET = 0;
/**
* Indicates a seek from the current position
*/
public static final int SEEK_CUR = 1;
/**
* Indicates a seek from the current position
*/
public static final int SEEK_CUR = 1;
/**
* Indicates a seek from the end of a file
*/
public static final int SEEK_END = 2;
/**
* Indicates a seek from the end of a file
*/
public static final int SEEK_END = 2;
private Fastpath fp; // Fastpath API to use
private int oid; // OID of this object
private int fd; // the descriptor of the open large object
private Fastpath fp; // Fastpath API to use
private int oid; // OID of this object
private int fd; // the descriptor of the open large object
private BlobOutputStream os; // The current output stream
private BlobOutputStream os; // The current output stream
private boolean closed=false; // true when we are closed
private boolean closed = false; // true when we are closed
/**
* This opens a large object.
*
* <p>If the object does not exist, then an SQLException is thrown.
*
* @param fp FastPath API for the connection to use
* @param oid of the Large Object to open
* @param mode Mode of opening the large object
* (defined in LargeObjectManager)
* @exception SQLException if a database-access error occurs.
* @see org.postgresql.largeobject.LargeObjectManager
*/
protected LargeObject(Fastpath fp,int oid,int mode) throws SQLException
{
this.fp = fp;
this.oid = oid;
/**
* This opens a large object.
*
* <p>If the object does not exist, then an SQLException is thrown.
*
* @param fp FastPath API for the connection to use
* @param oid of the Large Object to open
* @param mode Mode of opening the large object
* (defined in LargeObjectManager)
* @exception SQLException if a database-access error occurs.
* @see org.postgresql.largeobject.LargeObjectManager
*/
protected LargeObject(Fastpath fp, int oid, int mode) throws SQLException
{
this.fp = fp;
this.oid = oid;
FastpathArg args[] = new FastpathArg[2];
args[0] = new FastpathArg(oid);
args[1] = new FastpathArg(mode);
this.fd = fp.getInteger("lo_open",args);
}
FastpathArg args[] = new FastpathArg[2];
args[0] = new FastpathArg(oid);
args[1] = new FastpathArg(mode);
this.fd = fp.getInteger("lo_open", args);
}
/* Release large object resources during garbage cleanup */
protected void finalize() throws SQLException
{
close();
}
/* Release large object resources during garbage cleanup */
protected void finalize() throws SQLException
{
close();
}
/**
* @return the OID of this LargeObject
*/
public int getOID()
{
return oid;
}
/**
* @return the OID of this LargeObject
*/
public int getOID()
{
return oid;
}
/**
* This method closes the object. You must not call methods in this
* object after this is called.
* @exception SQLException if a database-access error occurs.
*/
public void close() throws SQLException
{
if(!closed) {
// flush any open output streams
if(os!=null) {
try {
// we can't call os.close() otherwise we go into an infinite loop!
os.flush();
} catch(IOException ioe) {
throw new SQLException(ioe.getMessage());
} finally {
os=null;
}
}
/**
* This method closes the object. You must not call methods in this
* object after this is called.
* @exception SQLException if a database-access error occurs.
*/
public void close() throws SQLException
{
if (!closed)
{
// flush any open output streams
if (os != null)
{
try
{
// we can't call os.close() otherwise we go into an infinite loop!
os.flush();
}
catch (IOException ioe)
{
throw new SQLException(ioe.getMessage());
}
finally
{
os = null;
}
}
// finally close
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(fd);
fp.fastpath("lo_close",false,args); // true here as we dont care!!
closed=true;
}
}
// finally close
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(fd);
fp.fastpath("lo_close", false, args); // true here as we dont care!!
closed = true;
}
}
/**
* Reads some data from the object, and return as a byte[] array
*
* @param len number of bytes to read
* @return byte[] array containing data read
* @exception SQLException if a database-access error occurs.
*/
public byte[] read(int len) throws SQLException
{
// This is the original method, where the entire block (len bytes)
// is retrieved in one go.
FastpathArg args[] = new FastpathArg[2];
args[0] = new FastpathArg(fd);
args[1] = new FastpathArg(len);
return fp.getData("loread",args);
/**
* Reads some data from the object, and return as a byte[] array
*
* @param len number of bytes to read
* @return byte[] array containing data read
* @exception SQLException if a database-access error occurs.
*/
public byte[] read(int len) throws SQLException
{
// This is the original method, where the entire block (len bytes)
// is retrieved in one go.
FastpathArg args[] = new FastpathArg[2];
args[0] = new FastpathArg(fd);
args[1] = new FastpathArg(len);
return fp.getData("loread", args);
// This version allows us to break this down into 4k blocks
//if(len<=4048) {
//// handle as before, return the whole block in one go
//FastpathArg args[] = new FastpathArg[2];
//args[0] = new FastpathArg(fd);
//args[1] = new FastpathArg(len);
//return fp.getData("loread",args);
//} else {
//// return in 4k blocks
//byte[] buf=new byte[len];
//int off=0;
//while(len>0) {
//int bs=4048;
//len-=bs;
//if(len<0) {
//bs+=len;
//len=0;
//}
//read(buf,off,bs);
//off+=bs;
//}
//return buf;
//}
}
// This version allows us to break this down into 4k blocks
//if(len<=4048) {
//// handle as before, return the whole block in one go
//FastpathArg args[] = new FastpathArg[2];
//args[0] = new FastpathArg(fd);
//args[1] = new FastpathArg(len);
//return fp.getData("loread",args);
//} else {
//// return in 4k blocks
//byte[] buf=new byte[len];
//int off=0;
//while(len>0) {
//int bs=4048;
//len-=bs;
//if(len<0) {
//bs+=len;
//len=0;
//}
//read(buf,off,bs);
//off+=bs;
//}
//return buf;
//}
}
/**
* Reads some data from the object into an existing array
*
* @param buf destination array
* @param off offset within array
* @param len number of bytes to read
* @return the number of bytes actually read
* @exception SQLException if a database-access error occurs.
*/
public int read(byte buf[],int off,int len) throws SQLException
{
byte b[] = read(len);
if(b.length<len)
len=b.length;
System.arraycopy(b,0,buf,off,len);
return len;
}
/**
* Reads some data from the object into an existing array
*
* @param buf destination array
* @param off offset within array
* @param len number of bytes to read
* @return the number of bytes actually read
* @exception SQLException if a database-access error occurs.
*/
public int read(byte buf[], int off, int len) throws SQLException
{
byte b[] = read(len);
if (b.length < len)
len = b.length;
System.arraycopy(b, 0, buf, off, len);
return len;
}
/**
* Writes an array to the object
*
* @param buf array to write
* @exception SQLException if a database-access error occurs.
*/
public void write(byte buf[]) throws SQLException
{
FastpathArg args[] = new FastpathArg[2];
args[0] = new FastpathArg(fd);
args[1] = new FastpathArg(buf);
fp.fastpath("lowrite",false,args);
}
/**
* Writes an array to the object
*
* @param buf array to write
* @exception SQLException if a database-access error occurs.
*/
public void write(byte buf[]) throws SQLException
{
FastpathArg args[] = new FastpathArg[2];
args[0] = new FastpathArg(fd);
args[1] = new FastpathArg(buf);
fp.fastpath("lowrite", false, args);
}
/**
* Writes some data from an array to the object
*
* @param buf destination array
* @param off offset within array
* @param len number of bytes to write
* @exception SQLException if a database-access error occurs.
*/
public void write(byte buf[],int off,int len) throws SQLException
{
byte data[] = new byte[len];
System.arraycopy(buf,off,data,0,len);
write(data);
}
/**
* Writes some data from an array to the object
*
* @param buf destination array
* @param off offset within array
* @param len number of bytes to write
* @exception SQLException if a database-access error occurs.
*/
public void write(byte buf[], int off, int len) throws SQLException
{
byte data[] = new byte[len];
System.arraycopy(buf, off, data, 0, len);
write(data);
}
/**
* Sets the current position within the object.
*
* <p>This is similar to the fseek() call in the standard C library. It
* allows you to have random access to the large object.
*
* @param pos position within object
* @param ref Either SEEK_SET, SEEK_CUR or SEEK_END
* @exception SQLException if a database-access error occurs.
*/
public void seek(int pos,int ref) throws SQLException
{
FastpathArg args[] = new FastpathArg[3];
args[0] = new FastpathArg(fd);
args[1] = new FastpathArg(pos);
args[2] = new FastpathArg(ref);
fp.fastpath("lo_lseek",false,args);
}
/**
* Sets the current position within the object.
*
* <p>This is similar to the fseek() call in the standard C library. It
* allows you to have random access to the large object.
*
* @param pos position within object
* @param ref Either SEEK_SET, SEEK_CUR or SEEK_END
* @exception SQLException if a database-access error occurs.
*/
public void seek(int pos, int ref) throws SQLException
{
FastpathArg args[] = new FastpathArg[3];
args[0] = new FastpathArg(fd);
args[1] = new FastpathArg(pos);
args[2] = new FastpathArg(ref);
fp.fastpath("lo_lseek", false, args);
}
/**
* Sets the current position within the object.
*
* <p>This is similar to the fseek() call in the standard C library. It
* allows you to have random access to the large object.
*
* @param pos position within object from begining
* @exception SQLException if a database-access error occurs.
*/
public void seek(int pos) throws SQLException
{
seek(pos,SEEK_SET);
}
/**
* Sets the current position within the object.
*
* <p>This is similar to the fseek() call in the standard C library. It
* allows you to have random access to the large object.
*
* @param pos position within object from begining
* @exception SQLException if a database-access error occurs.
*/
public void seek(int pos) throws SQLException
{
seek(pos, SEEK_SET);
}
/**
* @return the current position within the object
* @exception SQLException if a database-access error occurs.
*/
public int tell() throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(fd);
return fp.getInteger("lo_tell",args);
}
/**
* @return the current position within the object
* @exception SQLException if a database-access error occurs.
*/
public int tell() throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(fd);
return fp.getInteger("lo_tell", args);
}
/**
* This method is inefficient, as the only way to find out the size of
* the object is to seek to the end, record the current position, then
* return to the original position.
*
* <p>A better method will be found in the future.
*
* @return the size of the large object
* @exception SQLException if a database-access error occurs.
*/
public int size() throws SQLException
{
int cp = tell();
seek(0,SEEK_END);
int sz = tell();
seek(cp,SEEK_SET);
return sz;
}
/**
* This method is inefficient, as the only way to find out the size of
* the object is to seek to the end, record the current position, then
* return to the original position.
*
* <p>A better method will be found in the future.
*
* @return the size of the large object
* @exception SQLException if a database-access error occurs.
*/
public int size() throws SQLException
{
int cp = tell();
seek(0, SEEK_END);
int sz = tell();
seek(cp, SEEK_SET);
return sz;
}
/**
* Returns an InputStream from this object.
*
* <p>This InputStream can then be used in any method that requires an
* InputStream.
*
* @exception SQLException if a database-access error occurs.
*/
public InputStream getInputStream() throws SQLException
{
return new BlobInputStream(this);
}
/**
* Returns an InputStream from this object.
*
* <p>This InputStream can then be used in any method that requires an
* InputStream.
*
* @exception SQLException if a database-access error occurs.
*/
public InputStream getInputStream() throws SQLException
{
return new BlobInputStream(this);
}
/**
* Returns an OutputStream to this object
*
* <p>This OutputStream can then be used in any method that requires an
* OutputStream.
*
* @exception SQLException if a database-access error occurs.
*/
public OutputStream getOutputStream() throws SQLException
{
if(os==null)
os = new BlobOutputStream(this);
return os;
}
/**
* Returns an OutputStream to this object
*
* <p>This OutputStream can then be used in any method that requires an
* OutputStream.
*
* @exception SQLException if a database-access error occurs.
*/
public OutputStream getOutputStream() throws SQLException
{
if (os == null)
os = new BlobOutputStream(this);
return os;
}
}

View File

@ -32,7 +32,7 @@ import org.postgresql.util.*;
* </pre>
*
* <p>Normally, client code would use the getAsciiStream, getBinaryStream,
* or getUnicodeStream methods in ResultSet, or setAsciiStream,
* or getUnicodeStream methods in ResultSet, or setAsciiStream,
* setBinaryStream, or setUnicodeStream methods in PreparedStatement to
* access Large Objects.
*
@ -58,149 +58,148 @@ import org.postgresql.util.*;
*/
public class LargeObjectManager
{
// the fastpath api for this connection
private Fastpath fp;
/**
* This mode indicates we want to write to an object
*/
public static final int WRITE = 0x00020000;
/**
* This mode indicates we want to read an object
*/
public static final int READ = 0x00040000;
/**
* This mode is the default. It indicates we want read and write access to
* a large object
*/
public static final int READWRITE = READ | WRITE;
/**
* This prevents us being created by mere mortals
*/
private LargeObjectManager()
{
}
/**
* Constructs the LargeObject API.
*
* <p><b>Important Notice</b>
* <br>This method should only be called by org.postgresql.Connection
*
* <p>There should only be one LargeObjectManager per Connection. The
* org.postgresql.Connection class keeps track of the various extension API's
* and it's advised you use those to gain access, and not going direct.
*/
public LargeObjectManager(org.postgresql.Connection conn) throws SQLException
{
// We need Fastpath to do anything
this.fp = conn.getFastpathAPI();
// Now get the function oid's for the api
//
// This is an example of Fastpath.addFunctions();
//
java.sql.ResultSet res = (java.sql.ResultSet)conn.createStatement().executeQuery("select proname, oid from pg_proc" +
" where proname = 'lo_open'" +
" or proname = 'lo_close'" +
" or proname = 'lo_creat'" +
" or proname = 'lo_unlink'" +
" or proname = 'lo_lseek'" +
" or proname = 'lo_tell'" +
" or proname = 'loread'" +
" or proname = 'lowrite'");
if(res==null)
throw new PSQLException("postgresql.lo.init");
fp.addFunctions(res);
res.close();
DriverManager.println("Large Object initialised");
}
// the fastpath api for this connection
private Fastpath fp;
/**
* This mode indicates we want to write to an object
*/
public static final int WRITE = 0x00020000;
/**
* This mode indicates we want to read an object
*/
public static final int READ = 0x00040000;
/**
* This mode is the default. It indicates we want read and write access to
* a large object
*/
public static final int READWRITE = READ | WRITE;
/**
* This prevents us being created by mere mortals
*/
private LargeObjectManager()
{}
/**
* Constructs the LargeObject API.
*
* <p><b>Important Notice</b>
* <br>This method should only be called by org.postgresql.Connection
*
* <p>There should only be one LargeObjectManager per Connection. The
* org.postgresql.Connection class keeps track of the various extension API's
* and it's advised you use those to gain access, and not going direct.
*/
public LargeObjectManager(org.postgresql.Connection conn) throws SQLException
{
// We need Fastpath to do anything
this.fp = conn.getFastpathAPI();
// Now get the function oid's for the api
//
// This is an example of Fastpath.addFunctions();
//
java.sql.ResultSet res = (java.sql.ResultSet)conn.createStatement().executeQuery("select proname, oid from pg_proc" +
" where proname = 'lo_open'" +
" or proname = 'lo_close'" +
" or proname = 'lo_creat'" +
" or proname = 'lo_unlink'" +
" or proname = 'lo_lseek'" +
" or proname = 'lo_tell'" +
" or proname = 'loread'" +
" or proname = 'lowrite'");
if (res == null)
throw new PSQLException("postgresql.lo.init");
fp.addFunctions(res);
res.close();
DriverManager.println("Large Object initialised");
}
/**
* This opens an existing large object, based on its OID. This method
* assumes that READ and WRITE access is required (the default).
*
* @param oid of large object
* @return LargeObject instance providing access to the object
* @exception SQLException on error
*/
public LargeObject open(int oid) throws SQLException
{
return new LargeObject(fp, oid, READWRITE);
}
/**
* This opens an existing large object, based on its OID
*
* @param oid of large object
* @param mode mode of open
* @return LargeObject instance providing access to the object
* @exception SQLException on error
*/
public LargeObject open(int oid, int mode) throws SQLException
{
return new LargeObject(fp, oid, mode);
}
/**
* This creates a large object, returning its OID.
*
* <p>It defaults to READWRITE for the new object's attributes.
*
* @return oid of new object
* @exception SQLException on error
*/
public int create() throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(READWRITE);
return fp.getInteger("lo_creat", args);
}
/**
* This creates a large object, returning its OID
*
* @param mode a bitmask describing different attributes of the new object
* @return oid of new object
* @exception SQLException on error
*/
public int create(int mode) throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(mode);
return fp.getInteger("lo_creat", args);
}
/**
* This deletes a large object.
*
* @param oid describing object to delete
* @exception SQLException on error
*/
public void delete(int oid) throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(oid);
fp.fastpath("lo_unlink", false, args);
}
/**
* This deletes a large object.
*
* <p>It is identical to the delete method, and is supplied as the C API uses
* unlink.
*
* @param oid describing object to delete
* @exception SQLException on error
*/
public void unlink(int oid) throws SQLException
{
delete(oid);
}
/**
* This opens an existing large object, based on its OID. This method
* assumes that READ and WRITE access is required (the default).
*
* @param oid of large object
* @return LargeObject instance providing access to the object
* @exception SQLException on error
*/
public LargeObject open(int oid) throws SQLException
{
return new LargeObject(fp,oid,READWRITE);
}
/**
* This opens an existing large object, based on its OID
*
* @param oid of large object
* @param mode mode of open
* @return LargeObject instance providing access to the object
* @exception SQLException on error
*/
public LargeObject open(int oid,int mode) throws SQLException
{
return new LargeObject(fp,oid,mode);
}
/**
* This creates a large object, returning its OID.
*
* <p>It defaults to READWRITE for the new object's attributes.
*
* @return oid of new object
* @exception SQLException on error
*/
public int create() throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(READWRITE);
return fp.getInteger("lo_creat",args);
}
/**
* This creates a large object, returning its OID
*
* @param mode a bitmask describing different attributes of the new object
* @return oid of new object
* @exception SQLException on error
*/
public int create(int mode) throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(mode);
return fp.getInteger("lo_creat",args);
}
/**
* This deletes a large object.
*
* @param oid describing object to delete
* @exception SQLException on error
*/
public void delete(int oid) throws SQLException
{
FastpathArg args[] = new FastpathArg[1];
args[0] = new FastpathArg(oid);
fp.fastpath("lo_unlink",false,args);
}
/**
* This deletes a large object.
*
* <p>It is identical to the delete method, and is supplied as the C API uses
* unlink.
*
* @param oid describing object to delete
* @exception SQLException on error
*/
public void unlink(int oid) throws SQLException
{
delete(oid);
}
}

View File

@ -20,47 +20,53 @@ import org.postgresql.largeobject.*;
* This implements the Blob interface, which is basically another way to
* access a LargeObject.
*
* $Id: PGblob.java,v 1.1 2000/04/17 20:07:52 peter Exp $
* $Id: PGblob.java,v 1.2 2001/10/25 05:59:59 momjian Exp $
*
*/
public class PGblob implements java.sql.Blob
{
private org.postgresql.Connection conn;
private int oid;
private LargeObject lo;
public PGblob(org.postgresql.Connection conn,int oid) throws SQLException {
this.conn=conn;
this.oid=oid;
LargeObjectManager lom = conn.getLargeObjectAPI();
this.lo = lom.open(oid);
}
public long length() throws SQLException {
return lo.size();
}
public InputStream getBinaryStream() throws SQLException {
return lo.getInputStream();
}
public byte[] getBytes(long pos,int length) throws SQLException {
lo.seek((int)pos,LargeObject.SEEK_SET);
return lo.read(length);
}
/*
* For now, this is not implemented.
*/
public long position(byte[] pattern,long start) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/*
* This should be simply passing the byte value of the pattern Blob
*/
public long position(Blob pattern,long start) throws SQLException {
return position(pattern.getBytes(0,(int)pattern.length()),start);
}
private org.postgresql.Connection conn;
private int oid;
private LargeObject lo;
public PGblob(org.postgresql.Connection conn, int oid) throws SQLException
{
this.conn = conn;
this.oid = oid;
LargeObjectManager lom = conn.getLargeObjectAPI();
this.lo = lom.open(oid);
}
public long length() throws SQLException
{
return lo.size();
}
public InputStream getBinaryStream() throws SQLException
{
return lo.getInputStream();
}
public byte[] getBytes(long pos, int length) throws SQLException
{
lo.seek((int)pos, LargeObject.SEEK_SET);
return lo.read(length);
}
/*
* For now, this is not implemented.
*/
public long position(byte[] pattern, long start) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/*
* This should be simply passing the byte value of the pattern Blob
*/
public long position(Blob pattern, long start) throws SQLException
{
return position(pattern.getBytes(0, (int)pattern.length()), start);
}
}

View File

@ -20,51 +20,58 @@ import org.postgresql.largeobject.*;
* This implements the Blob interface, which is basically another way to
* access a LargeObject.
*
* $Id: PGclob.java,v 1.1 2001/02/16 16:45:01 peter Exp $
* $Id: PGclob.java,v 1.2 2001/10/25 05:59:59 momjian Exp $
*
*/
public class PGclob implements java.sql.Clob
{
private org.postgresql.Connection conn;
private int oid;
private LargeObject lo;
private org.postgresql.Connection conn;
private int oid;
private LargeObject lo;
public PGclob(org.postgresql.Connection conn,int oid) throws SQLException {
this.conn=conn;
this.oid=oid;
LargeObjectManager lom = conn.getLargeObjectAPI();
this.lo = lom.open(oid);
}
public PGclob(org.postgresql.Connection conn, int oid) throws SQLException
{
this.conn = conn;
this.oid = oid;
LargeObjectManager lom = conn.getLargeObjectAPI();
this.lo = lom.open(oid);
}
public long length() throws SQLException {
return lo.size();
}
public long length() throws SQLException
{
return lo.size();
}
public InputStream getAsciiStream() throws SQLException {
return lo.getInputStream();
}
public InputStream getAsciiStream() throws SQLException
{
return lo.getInputStream();
}
public Reader getCharacterStream() throws SQLException {
return new InputStreamReader(lo.getInputStream());
}
public Reader getCharacterStream() throws SQLException
{
return new InputStreamReader(lo.getInputStream());
}
public String getSubString(long i,int j) throws SQLException {
lo.seek((int)i-1);
return new String(lo.read(j));
}
public String getSubString(long i, int j) throws SQLException
{
lo.seek((int)i - 1);
return new String(lo.read(j));
}
/*
* For now, this is not implemented.
*/
public long position(String pattern,long start) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/*
* For now, this is not implemented.
*/
public long position(String pattern, long start) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
/*
* This should be simply passing the byte value of the pattern Blob
*/
public long position(Clob pattern,long start) throws SQLException {
throw org.postgresql.Driver.notImplemented();
}
/*
* This should be simply passing the byte value of the pattern Blob
*/
public long position(Clob pattern, long start) throws SQLException
{
throw org.postgresql.Driver.notImplemented();
}
}

View File

@ -9,38 +9,48 @@ import java.sql.*;
/**
* Executes all known tests for JDBC2 and includes some utility methods.
*/
public class JDBC2Tests extends TestSuite {
public class JDBC2Tests extends TestSuite
{
/**
* Returns the Test database JDBC URL
*/
public static String getURL() {
public static String getURL()
{
return System.getProperty("database");
}
/**
* Returns the Postgresql username
*/
public static String getUser() {
public static String getUser()
{
return System.getProperty("username");
}
/**
* Returns the user's password
*/
public static String getPassword() {
public static String getPassword()
{
return System.getProperty("password");
}
/**
* Helper - opens a connection.
*/
public static java.sql.Connection openDB() {
try {
public static java.sql.Connection openDB()
{
try
{
Class.forName("org.postgresql.Driver");
return java.sql.DriverManager.getConnection(JDBC2Tests.getURL(),JDBC2Tests.getUser(),JDBC2Tests.getPassword());
} catch(ClassNotFoundException ex) {
return java.sql.DriverManager.getConnection(JDBC2Tests.getURL(), JDBC2Tests.getUser(), JDBC2Tests.getPassword());
}
catch (ClassNotFoundException ex)
{
TestCase.fail(ex.getMessage());
} catch(SQLException ex) {
}
catch (SQLException ex)
{
TestCase.fail(ex.getMessage());
}
return null;
@ -50,11 +60,15 @@ public class JDBC2Tests extends TestSuite {
* Helper - closes an open connection. This rewrites SQLException to a failed
* assertion. It's static so other classes can use it.
*/
public static void closeDB(Connection con) {
try {
public static void closeDB(Connection con)
{
try
{
if (con != null)
con.close();
} catch (SQLException ex) {
}
catch (SQLException ex)
{
TestCase.fail(ex.getMessage());
}
}
@ -64,19 +78,26 @@ public class JDBC2Tests extends TestSuite {
*/
public static void createTable(Connection con,
String table,
String columns) {
try {
String columns)
{
try
{
Statement st = con.createStatement();
try {
try
{
// Drop the table
dropTable(con, table);
// Now create the table
st.executeUpdate("create table " + table + " (" + columns + ")");
} finally {
}
finally
{
st.close();
}
} catch(SQLException ex) {
}
catch (SQLException ex)
{
TestCase.fail(ex.getMessage());
}
}
@ -84,15 +105,22 @@ public class JDBC2Tests extends TestSuite {
/**
* Helper - drops a table
*/
public static void dropTable(Connection con, String table) {
try {
public static void dropTable(Connection con, String table)
{
try
{
Statement stmt = con.createStatement();
try {
try
{
stmt.executeUpdate("DROP TABLE " + table);
} catch (SQLException ex) {
}
catch (SQLException ex)
{
// ignore
}
} catch (SQLException ex) {
}
catch (SQLException ex)
{
TestCase.fail(ex.getMessage());
}
}
@ -100,47 +128,53 @@ public class JDBC2Tests extends TestSuite {
/**
* Helper - generates INSERT SQL - very simple
*/
public static String insertSQL(String table, String values) {
public static String insertSQL(String table, String values)
{
return insertSQL(table, null, values);
}
public static String insertSQL(String table, String columns, String values) {
public static String insertSQL(String table, String columns, String values)
{
String s = "INSERT INTO " + table;
if (columns != null)
s = s + " (" + columns + ")";
return s + " VALUES (" + values + ")";
}
/**
* Helper - generates SELECT SQL - very simple
*/
public static String selectSQL(String table, String columns) {
public static String selectSQL(String table, String columns)
{
return selectSQL(table, columns, null, null);
}
public static String selectSQL(String table, String columns, String where) {
public static String selectSQL(String table, String columns, String where)
{
return selectSQL(table, columns, where, null);
}
public static String selectSQL(String table, String columns, String where, String other) {
public static String selectSQL(String table, String columns, String where, String other)
{
String s = "SELECT " + columns + " FROM " + table;
if (where != null)
s = s + " WHERE " + where;
if (other != null)
s = s + " " + other;
return s;
}
/**
* Helper to prefix a number with leading zeros - ugly but it works...
* @param v value to prefix
* @param l number of digits (0-10)
*/
public static String fix(int v, int l) {
public static String fix(int v, int l)
{
String s = "0000000000".substring(0, l) + Integer.toString(v);
return s.substring(s.length() - l);
}
@ -148,8 +182,9 @@ public class JDBC2Tests extends TestSuite {
/**
* The main entry point for JUnit
*/
public static TestSuite suite() {
TestSuite suite= new TestSuite();
public static TestSuite suite()
{
TestSuite suite = new TestSuite();
//
// Add one line per class in our test cases. These should be in order of

View File

@ -2,25 +2,28 @@ package org.postgresql.test.jdbc2;
import junit.framework.TestCase;
public class ANTTest extends TestCase {
public ANTTest(String name) {
super(name);
}
public class ANTTest extends TestCase
{
public ANTTest(String name)
{
super(name);
}
/**
* This tests the acceptsURL() method with a couple of good and badly formed
* jdbc urls
*/
public void testANT() {
String url=System.getProperty("database");
String usr=System.getProperty("username");
String psw=System.getProperty("password");
/**
* This tests the acceptsURL() method with a couple of good and badly formed
* jdbc urls
*/
public void testANT()
{
String url = System.getProperty("database");
String usr = System.getProperty("username");
String psw = System.getProperty("password");
assertNotNull(url);
assertNotNull(usr);
assertNotNull(psw);
assertNotNull(url);
assertNotNull(usr);
assertNotNull(psw);
assertTrue(! url.equals(""));
assertTrue(! usr.equals(""));
}
assertTrue(! url.equals(""));
assertTrue(! usr.equals(""));
}
}

View File

@ -12,24 +12,27 @@ import java.sql.*;
/**
* Test case for Statement.batchExecute()
*/
public class BatchExecuteTest extends TestCase {
public class BatchExecuteTest extends TestCase
{
private Connection con;
public BatchExecuteTest(String name) {
public BatchExecuteTest(String name)
{
super(name);
}
// Set up the fixture for this testcase: a connection to a database with
// a table for this test.
protected void setUp() throws Exception {
protected void setUp() throws Exception
{
con = JDBC2Tests.openDB();
Statement stmt = con.createStatement();
// Drop the test table if it already exists for some reason. It is
// not an error if it doesn't exist.
JDBC2Tests.createTable(con, "testbatch", "pk INTEGER, col1 INTEGER");
stmt.executeUpdate("INSERT INTO testbatch VALUES (1, 0)");
// Generally recommended with batch updates. By default we run all
@ -38,19 +41,22 @@ public class BatchExecuteTest extends TestCase {
}
// Tear down the fixture for this test case.
protected void tearDown() throws Exception {
protected void tearDown() throws Exception
{
con.setAutoCommit(true);
JDBC2Tests.dropTable(con, "testbatch");
JDBC2Tests.closeDB(con);
}
public void testSupportsBatchUpdates() throws Exception {
public void testSupportsBatchUpdates() throws Exception
{
DatabaseMetaData dbmd = con.getMetaData();
assertTrue(dbmd.supportsBatchUpdates());
}
private void assertCol1HasValue(int expected) throws Exception {
private void assertCol1HasValue(int expected) throws Exception
{
Statement getCol1 = con.createStatement();
ResultSet rs =
@ -67,21 +73,23 @@ public class BatchExecuteTest extends TestCase {
getCol1.close();
}
public void testExecuteEmptyBatch() throws Exception {
public void testExecuteEmptyBatch() throws Exception
{
Statement stmt = con.createStatement();
int[] updateCount = stmt.executeBatch();
assertEquals(0,updateCount.length);
assertEquals(0, updateCount.length);
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
stmt.clearBatch();
updateCount = stmt.executeBatch();
assertEquals(0,updateCount.length);
assertEquals(0, updateCount.length);
stmt.close();
}
public void testClearBatch() throws Exception {
public void testClearBatch() throws Exception
{
Statement stmt = con.createStatement();
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
assertCol1HasValue(0);
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
@ -98,44 +106,51 @@ public class BatchExecuteTest extends TestCase {
stmt.close();
}
public void testSelectThrowsException() throws Exception {
public void testSelectThrowsException() throws Exception
{
Statement stmt = con.createStatement();
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
stmt.addBatch("SELECT col1 FROM testbatch WHERE pk = 1");
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
try {
try
{
stmt.executeBatch();
fail("Should raise a BatchUpdateException because of the SELECT");
} catch (BatchUpdateException e) {
}
catch (BatchUpdateException e)
{
int [] updateCounts = e.getUpdateCounts();
assertEquals(1,updateCounts.length);
assertEquals(1,updateCounts[0]);
} catch (SQLException e) {
assertEquals(1, updateCounts.length);
assertEquals(1, updateCounts[0]);
}
catch (SQLException e)
{
fail( "Should throw a BatchUpdateException instead of " +
"a generic SQLException: " + e);
"a generic SQLException: " + e);
}
stmt.close();
}
public void testPreparedStatement() throws Exception {
public void testPreparedStatement() throws Exception
{
PreparedStatement pstmt = con.prepareStatement(
"UPDATE testbatch SET col1 = col1 + ? WHERE PK = ?" );
"UPDATE testbatch SET col1 = col1 + ? WHERE PK = ?" );
// Note that the first parameter changes for every statement in the
// batch, whereas the second parameter remains constant.
pstmt.setInt(1,1);
pstmt.setInt(2,1);
pstmt.setInt(1, 1);
pstmt.setInt(2, 1);
pstmt.addBatch();
assertCol1HasValue(0);
pstmt.setInt(1,2);
pstmt.setInt(1, 2);
pstmt.addBatch();
assertCol1HasValue(0);
pstmt.setInt(1,4);
pstmt.setInt(1, 4);
pstmt.addBatch();
assertCol1HasValue(0);
@ -153,9 +168,10 @@ public class BatchExecuteTest extends TestCase {
/**
*/
public void testTransactionalBehaviour() throws Exception {
public void testTransactionalBehaviour() throws Exception
{
Statement stmt = con.createStatement();
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
stmt.executeBatch();
@ -170,9 +186,9 @@ public class BatchExecuteTest extends TestCase {
assertCol1HasValue(0);
int[] updateCounts = stmt.executeBatch();
assertEquals(2,updateCounts.length);
assertEquals(1,updateCounts[0]);
assertEquals(1,updateCounts[1]);
assertEquals(2, updateCounts.length);
assertEquals(1, updateCounts[0]);
assertEquals(1, updateCounts[1]);
assertCol1HasValue(12);
con.commit();

View File

@ -8,39 +8,45 @@ import java.sql.*;
import org.postgresql.largeobject.*;
/**
* $Id: BlobTest.java,v 1.2 2001/09/23 04:11:14 momjian Exp $
* $Id: BlobTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*
* Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-)
*
*/
public class BlobTest extends TestCase {
public class BlobTest extends TestCase
{
private Connection con;
private Connection con;
private static final int LOOP = 0; // LargeObject API using loop
private static final int LOOP = 0; // LargeObject API using loop
private static final int NATIVE_STREAM = 1; // LargeObject API using OutputStream
private static final int JDBC_STREAM = 2; // JDBC API using OutputStream
private static final int JDBC_STREAM = 2; // JDBC API using OutputStream
public BlobTest(String name) {
public BlobTest(String name)
{
super(name);
}
}
protected void setUp() throws Exception {
protected void setUp() throws Exception
{
con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "testblob", "id name,lo oid");
}
protected void tearDown() throws Exception {
protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testblob");
JDBC2Tests.closeDB(con);
}
/**
* Tests one method of uploading a blob to the database
*/
public void testUploadBlob_LOOP() {
try {
public void testUploadBlob_LOOP()
{
try
{
con.setAutoCommit(false);
assertTrue(!con.getAutoCommit());
@ -51,7 +57,9 @@ public class BlobTest extends TestCase {
assertTrue(compareBlobs());
con.setAutoCommit(true);
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
@ -59,8 +67,10 @@ public class BlobTest extends TestCase {
/**
* Tests one method of uploading a blob to the database
*/
public void testUploadBlob_NATIVE() {
try {
public void testUploadBlob_NATIVE()
{
try
{
con.setAutoCommit(false);
assertTrue(!con.getAutoCommit());
@ -71,7 +81,9 @@ public class BlobTest extends TestCase {
assertTrue(compareBlobs());
con.setAutoCommit(true);
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
@ -81,7 +93,8 @@ public class BlobTest extends TestCase {
* because it always works, and we can use it as a base to test the new
* methods.
*/
private int uploadFile(String file, int method) throws Exception {
private int uploadFile(String file, int method) throws Exception
{
LargeObjectManager lom = ((org.postgresql.Connection)con).getLargeObjectAPI();
FileInputStream fis = new FileInputStream(file);
@ -89,40 +102,42 @@ public class BlobTest extends TestCase {
int oid = lom.create(LargeObjectManager.READWRITE);
LargeObject blob = lom.open(oid);
int s,t;
int s, t;
byte buf[];
OutputStream os;
switch(method)
switch (method)
{
case LOOP:
buf = new byte[2048];
t=0;
while((s=fis.read(buf,0,buf.length))>0) {
t+=s;
blob.write(buf,0,s);
}
break;
case LOOP:
buf = new byte[2048];
t = 0;
while ((s = fis.read(buf, 0, buf.length)) > 0)
{
t += s;
blob.write(buf, 0, s);
}
break;
case NATIVE_STREAM:
os = blob.getOutputStream();
s= fis.read();
while(s>-1) {
os.write(s);
s=fis.read();
}
os.close();
break;
case NATIVE_STREAM:
os = blob.getOutputStream();
s = fis.read();
while (s > -1)
{
os.write(s);
s = fis.read();
}
os.close();
break;
case JDBC_STREAM:
File f = new File(file);
PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testblob", "?"));
ps.setBinaryStream(1,fis,(int) f.length());
ps.execute();
break;
case JDBC_STREAM:
File f = new File(file);
PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testblob", "?"));
ps.setBinaryStream(1, fis, (int) f.length());
ps.execute();
break;
default:
assertTrue("Unknown method in uploadFile",false);
default:
assertTrue("Unknown method in uploadFile", false);
}
blob.close();
@ -130,7 +145,7 @@ public class BlobTest extends TestCase {
// Insert into the table
Statement st = con.createStatement();
st.executeUpdate(JDBC2Tests.insertSQL("testblob", "id,lo","'"+file+"',"+oid));
st.executeUpdate(JDBC2Tests.insertSQL("testblob", "id,lo", "'" + file + "'," + oid));
con.commit();
st.close();
@ -141,8 +156,9 @@ public class BlobTest extends TestCase {
* Helper - compares the blobs in a table with a local file. Note this alone
* tests the InputStream methods!
*/
private boolean compareBlobs() throws Exception {
boolean result=true;
private boolean compareBlobs() throws Exception
{
boolean result = true;
LargeObjectManager lom = ((org.postgresql.Connection)con).getLargeObjectAPI();
@ -150,7 +166,8 @@ public class BlobTest extends TestCase {
ResultSet rs = st.executeQuery(JDBC2Tests.selectSQL("testblob", "id,lo"));
assertNotNull(rs);
while(rs.next()) {
while (rs.next())
{
String file = rs.getString(1);
int oid = rs.getInt(2);
@ -158,19 +175,20 @@ public class BlobTest extends TestCase {
LargeObject blob = lom.open(oid);
InputStream bis = blob.getInputStream();
int f=fis.read();
int b=bis.read();
int c=0;
while(f>=0 && b>=0 & result) {
result=(f==b);
f=fis.read();
b=bis.read();
int f = fis.read();
int b = bis.read();
int c = 0;
while (f >= 0 && b >= 0 & result)
{
result = (f == b);
f = fis.read();
b = bis.read();
c++;
}
result=result && f==-1 && b==-1;
result = result && f == -1 && b == -1;
if(!result)
System.out.println("\nBlob compare failed at "+c+" of "+blob.size());
if (!result)
System.out.println("\nBlob compare failed at " + c + " of " + blob.size());
blob.close();
fis.close();

View File

@ -10,194 +10,219 @@ import java.sql.*;
*
* PS: Do you know how difficult it is to type on a train? ;-)
*
* $Id: ConnectionTest.java,v 1.5 2001/09/23 04:11:14 momjian Exp $
* $Id: ConnectionTest.java,v 1.6 2001/10/25 05:59:59 momjian Exp $
*/
public class ConnectionTest extends TestCase {
public class ConnectionTest extends TestCase
{
/**
* Constructor
*/
public ConnectionTest(String name) {
super(name);
}
/**
* Constructor
*/
public ConnectionTest(String name)
{
super(name);
}
// Set up the fixture for this testcase: the tables for this test.
protected void setUp() throws Exception {
Connection con = JDBC2Tests.openDB();
// Set up the fixture for this testcase: the tables for this test.
protected void setUp() throws Exception
{
Connection con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "test_a", "imagename name,image oid,id int4");
JDBC2Tests.createTable(con, "test_c", "source text,cost money,imageid int4");
JDBC2Tests.createTable(con, "test_a", "imagename name,image oid,id int4");
JDBC2Tests.createTable(con, "test_c", "source text,cost money,imageid int4");
JDBC2Tests.closeDB(con);
}
JDBC2Tests.closeDB(con);
}
// Tear down the fixture for this test case.
protected void tearDown() throws Exception {
Connection con = JDBC2Tests.openDB();
// Tear down the fixture for this test case.
protected void tearDown() throws Exception
{
Connection con = JDBC2Tests.openDB();
JDBC2Tests.dropTable(con, "test_a");
JDBC2Tests.dropTable(con, "test_c");
JDBC2Tests.closeDB(con);
}
JDBC2Tests.dropTable(con, "test_a");
JDBC2Tests.dropTable(con, "test_c");
/**
* Tests the two forms of createStatement()
*/
public void testCreateStatement() {
try {
java.sql.Connection conn = JDBC2Tests.openDB();
JDBC2Tests.closeDB(con);
}
// A standard Statement
java.sql.Statement stat = conn.createStatement();
assertNotNull(stat);
stat.close();
/**
* Tests the two forms of createStatement()
*/
public void testCreateStatement()
{
try
{
java.sql.Connection conn = JDBC2Tests.openDB();
// Ask for Updateable ResultSets
stat = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_UPDATABLE);
assertNotNull(stat);
stat.close();
// A standard Statement
java.sql.Statement stat = conn.createStatement();
assertNotNull(stat);
stat.close();
} catch(SQLException ex) {
assertTrue(ex.getMessage(),false);
}
}
// Ask for Updateable ResultSets
stat = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
assertNotNull(stat);
stat.close();
/**
* Tests the two forms of prepareStatement()
*/
public void testPrepareStatement() {
try {
java.sql.Connection conn = JDBC2Tests.openDB();
}
catch (SQLException ex)
{
assertTrue(ex.getMessage(), false);
}
}
String sql = "select source,cost,imageid from test_c";
/**
* Tests the two forms of prepareStatement()
*/
public void testPrepareStatement()
{
try
{
java.sql.Connection conn = JDBC2Tests.openDB();
// A standard Statement
java.sql.PreparedStatement stat = conn.prepareStatement(sql);
assertNotNull(stat);
stat.close();
String sql = "select source,cost,imageid from test_c";
// Ask for Updateable ResultSets
stat = conn.prepareStatement(sql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_UPDATABLE);
assertNotNull(stat);
stat.close();
// A standard Statement
java.sql.PreparedStatement stat = conn.prepareStatement(sql);
assertNotNull(stat);
stat.close();
} catch(SQLException ex) {
assertTrue(ex.getMessage(),false);
}
}
// Ask for Updateable ResultSets
stat = conn.prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
assertNotNull(stat);
stat.close();
/**
* Put the test for createPrepareCall here
*/
public void testPrepareCall() {
}
}
catch (SQLException ex)
{
assertTrue(ex.getMessage(), false);
}
}
/**
* Test nativeSQL
*/
public void testNativeSQL() {
// For now do nothing as it returns itself
}
/**
* Put the test for createPrepareCall here
*/
public void testPrepareCall()
{}
/**
* Test autoCommit (both get & set)
*/
public void testTransactions() {
try {
java.sql.Connection con = JDBC2Tests.openDB();
java.sql.Statement st;
java.sql.ResultSet rs;
/**
* Test nativeSQL
*/
public void testNativeSQL()
{
// For now do nothing as it returns itself
}
// Turn it off
con.setAutoCommit(false);
assertTrue(!con.getAutoCommit());
/**
* Test autoCommit (both get & set)
*/
public void testTransactions()
{
try
{
java.sql.Connection con = JDBC2Tests.openDB();
java.sql.Statement st;
java.sql.ResultSet rs;
// Turn it back on
con.setAutoCommit(true);
assertTrue(con.getAutoCommit());
// Turn it off
con.setAutoCommit(false);
assertTrue(!con.getAutoCommit());
// Now test commit
st = con.createStatement();
st.executeUpdate("insert into test_a (imagename,image,id) values ('comttest',1234,5678)");
// Turn it back on
con.setAutoCommit(true);
assertTrue(con.getAutoCommit());
con.setAutoCommit(false);
// Now test commit
st = con.createStatement();
st.executeUpdate("insert into test_a (imagename,image,id) values ('comttest',1234,5678)");
// Now update image to 9876 and commit
st.executeUpdate("update test_a set image=9876 where id=5678");
con.commit();
rs = st.executeQuery("select image from test_a where id=5678");
assertTrue(rs.next());
assertEquals(9876, rs.getInt(1));
rs.close();
con.setAutoCommit(false);
// Now try to change it but rollback
st.executeUpdate("update test_a set image=1111 where id=5678");
con.rollback();
rs = st.executeQuery("select image from test_a where id=5678");
assertTrue(rs.next());
assertEquals(9876, rs.getInt(1)); // Should not change!
rs.close();
// Now update image to 9876 and commit
st.executeUpdate("update test_a set image=9876 where id=5678");
con.commit();
rs = st.executeQuery("select image from test_a where id=5678");
assertTrue(rs.next());
assertEquals(9876, rs.getInt(1));
rs.close();
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
assertTrue(ex.getMessage(),false);
}
}
// Now try to change it but rollback
st.executeUpdate("update test_a set image=1111 where id=5678");
con.rollback();
rs = st.executeQuery("select image from test_a where id=5678");
assertTrue(rs.next());
assertEquals(9876, rs.getInt(1)); // Should not change!
rs.close();
/**
* Simple test to see if isClosed works.
*/
public void testIsClosed() {
try {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
assertTrue(ex.getMessage(), false);
}
}
// Should not say closed
assertTrue(!con.isClosed());
/**
* Simple test to see if isClosed works.
*/
public void testIsClosed()
{
try
{
Connection con = JDBC2Tests.openDB();
JDBC2Tests.closeDB(con);
// Should not say closed
assertTrue(!con.isClosed());
// Should now say closed
assertTrue(con.isClosed());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
assertTrue(ex.getMessage(),false);
}
}
// Should now say closed
assertTrue(con.isClosed());
/**
* Test the warnings system
*/
public void testWarnings() {
try {
Connection con = JDBC2Tests.openDB();
}
catch (SQLException ex)
{
assertTrue(ex.getMessage(), false);
}
}
String testStr = "This Is OuR TeSt message";
/**
* Test the warnings system
*/
public void testWarnings()
{
try
{
Connection con = JDBC2Tests.openDB();
// The connection must be ours!
assertTrue(con instanceof org.postgresql.Connection);
String testStr = "This Is OuR TeSt message";
// Clear any existing warnings
con.clearWarnings();
// The connection must be ours!
assertTrue(con instanceof org.postgresql.Connection);
// Set the test warning
((org.postgresql.Connection)con).addWarning(testStr);
// Clear any existing warnings
con.clearWarnings();
// Retrieve it
SQLWarning warning = con.getWarnings();
assertNotNull(warning);
assertEquals(testStr, warning.getMessage());
// Set the test warning
((org.postgresql.Connection)con).addWarning(testStr);
// Finally test clearWarnings() this time there must be something to delete
con.clearWarnings();
assertTrue(con.getWarnings()==null);
// Retrieve it
SQLWarning warning = con.getWarnings();
assertNotNull(warning);
assertEquals(testStr, warning.getMessage());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
assertTrue(ex.getMessage(),false);
}
}
// Finally test clearWarnings() this time there must be something to delete
con.clearWarnings();
assertTrue(con.getWarnings() == null);
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
assertTrue(ex.getMessage(), false);
}
}
/**
* Transaction Isolation Levels
@ -210,14 +235,14 @@ public class ConnectionTest extends TestCase {
// PostgreSQL defaults to READ COMMITTED
assertEquals(Connection.TRANSACTION_READ_COMMITTED,
con.getTransactionIsolation());
con.getTransactionIsolation());
// Begin a transaction
con.setAutoCommit(false);
// The isolation level should not have changed
assertEquals(Connection.TRANSACTION_READ_COMMITTED,
con.getTransactionIsolation());
con.getTransactionIsolation());
// Now change the default for future transactions
con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
@ -227,14 +252,14 @@ public class ConnectionTest extends TestCase {
// transaction did not change. It affects only future transactions.
// This behaviour is recommended by the JDBC spec.
assertEquals(Connection.TRANSACTION_READ_COMMITTED,
con.getTransactionIsolation());
con.getTransactionIsolation());
// Begin a new transaction
con.commit();
// Now we should see the new isolation level
assertEquals(Connection.TRANSACTION_SERIALIZABLE,
con.getTransactionIsolation());
con.getTransactionIsolation());
// Repeat the steps above with the transition back to
// READ COMMITTED.
@ -277,35 +302,39 @@ public class ConnectionTest extends TestCase {
con.getTransactionIsolation());
JDBC2Tests.closeDB(con);
}
catch ( SQLException ex )
}
catch ( SQLException ex )
{
fail( ex.getMessage() );
}
}
/**
* JDBC2 Type mappings
*/
public void testTypeMaps() {
try {
Connection con = JDBC2Tests.openDB();
/**
* JDBC2 Type mappings
*/
public void testTypeMaps()
{
try
{
Connection con = JDBC2Tests.openDB();
// preserve the current map
java.util.Map oldmap = con.getTypeMap();
// preserve the current map
java.util.Map oldmap = con.getTypeMap();
// now change it for an empty one
java.util.Map newmap = new java.util.HashMap();
con.setTypeMap(newmap);
assertEquals(newmap, con.getTypeMap());
// now change it for an empty one
java.util.Map newmap = new java.util.HashMap();
con.setTypeMap(newmap);
assertEquals(newmap, con.getTypeMap());
// restore the old one
con.setTypeMap(oldmap);
assertEquals(oldmap, con.getTypeMap());
// restore the old one
con.setTypeMap(oldmap);
assertEquals(oldmap, con.getTypeMap());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
assertTrue(ex.getMessage(),false);
}
}
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
assertTrue(ex.getMessage(), false);
}
}
}

View File

@ -9,273 +9,323 @@ import java.sql.*;
*
* PS: Do you know how difficult it is to type on a train? ;-)
*
* $Id: DatabaseMetaDataTest.java,v 1.2 2001/09/10 15:07:58 momjian Exp $
* $Id: DatabaseMetaDataTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*/
public class DatabaseMetaDataTest extends TestCase {
/**
* Constructor
*/
public DatabaseMetaDataTest(String name) {
super(name);
}
/**
* The spec says this may return null, but we always do!
*/
public void testGetMetaData() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
/**
* Test default capabilities
*/
public void testCapabilities() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.allProceduresAreCallable());
assertTrue(dbmd.allTablesAreSelectable()); // not true all the time
// This should always be false for postgresql (at least for 7.x)
assertTrue(!dbmd.isReadOnly());
// does the backend support this yet? The protocol does...
assertTrue(!dbmd.supportsMultipleResultSets());
// yes, as multiple backends can have transactions open
assertTrue(dbmd.supportsMultipleTransactions());
assertTrue(dbmd.supportsMinimumSQLGrammar());
assertTrue(!dbmd.supportsCoreSQLGrammar());
assertTrue(!dbmd.supportsExtendedSQLGrammar());
assertTrue(!dbmd.supportsANSI92EntryLevelSQL());
assertTrue(!dbmd.supportsANSI92IntermediateSQL());
assertTrue(!dbmd.supportsANSI92FullSQL());
assertTrue(!dbmd.supportsIntegrityEnhancementFacility());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testJoins() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.supportsOuterJoins());
assertTrue(dbmd.supportsFullOuterJoins());
assertTrue(dbmd.supportsLimitedOuterJoins());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testCursors() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!dbmd.supportsPositionedDelete());
assertTrue(!dbmd.supportsPositionedUpdate());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testNulls() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
// We need to type cast the connection to get access to the
// PostgreSQL-specific method haveMinimumServerVersion().
// This is not available through the java.sql.Connection interface.
assertTrue( con instanceof org.postgresql.Connection );
assertTrue(!dbmd.nullsAreSortedAtStart());
assertTrue( dbmd.nullsAreSortedAtEnd() !=
((org.postgresql.Connection)con).haveMinimumServerVersion("7.2"));
assertTrue( dbmd.nullsAreSortedHigh() ==
((org.postgresql.Connection)con).haveMinimumServerVersion("7.2"));
assertTrue(!dbmd.nullsAreSortedLow());
assertTrue(dbmd.nullPlusNonNullIsNull());
assertTrue(dbmd.supportsNonNullableColumns());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testLocalFiles() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!dbmd.usesLocalFilePerTable());
assertTrue(!dbmd.usesLocalFiles());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testIdentifiers() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!dbmd.supportsMixedCaseIdentifiers()); // always false
assertTrue(dbmd.supportsMixedCaseQuotedIdentifiers()); // always true
assertTrue(!dbmd.storesUpperCaseIdentifiers()); // always false
assertTrue(dbmd.storesLowerCaseIdentifiers()); // always true
assertTrue(!dbmd.storesUpperCaseQuotedIdentifiers()); // always false
assertTrue(!dbmd.storesLowerCaseQuotedIdentifiers()); // always false
assertTrue(!dbmd.storesMixedCaseQuotedIdentifiers()); // always false
assertTrue(dbmd.getIdentifierQuoteString().equals("\""));
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testTables() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
// we can add columns
assertTrue(dbmd.supportsAlterTableWithAddColumn());
// we can't drop columns (yet)
assertTrue(!dbmd.supportsAlterTableWithDropColumn());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testSelect() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
// yes we can?: SELECT col a FROM a;
assertTrue(dbmd.supportsColumnAliasing());
// yes we can have expressions in ORDERBY
assertTrue(dbmd.supportsExpressionsInOrderBy());
// Yes, an ORDER BY clause can contain columns that are not in the
// SELECT clause.
assertTrue(dbmd.supportsOrderByUnrelated());
assertTrue(dbmd.supportsGroupBy());
assertTrue(dbmd.supportsGroupByUnrelated());
assertTrue(dbmd.supportsGroupByBeyondSelect()); // needs checking
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testDBParams() {
try {
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getURL().equals(JDBC2Tests.getURL()));
assertTrue(dbmd.getUserName().equals(JDBC2Tests.getUser()));
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testDbProductDetails() {
try {
Connection con = JDBC2Tests.openDB();
assertTrue(con instanceof org.postgresql.Connection);
org.postgresql.Connection pc = (org.postgresql.Connection) con;
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getDatabaseProductName().equals("PostgreSQL"));
assertTrue(dbmd.getDatabaseProductVersion().startsWith(Integer.toString(pc.this_driver.getMajorVersion())+"."+Integer.toString(pc.this_driver.getMinorVersion())));
assertTrue(dbmd.getDriverName().equals("PostgreSQL Native Driver"));
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public void testDriverVersioning() {
try {
Connection con = JDBC2Tests.openDB();
assertTrue(con instanceof org.postgresql.Connection);
org.postgresql.Connection pc = (org.postgresql.Connection) con;
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getDriverVersion().equals(pc.this_driver.getVersion()));
assertTrue(dbmd.getDriverMajorVersion()==pc.this_driver.getMajorVersion());
assertTrue(dbmd.getDriverMinorVersion()==pc.this_driver.getMinorVersion());
JDBC2Tests.closeDB(con);
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
public class DatabaseMetaDataTest extends TestCase
{
/**
* Constructor
*/
public DatabaseMetaDataTest(String name)
{
super(name);
}
/**
* The spec says this may return null, but we always do!
*/
public void testGetMetaData()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
/**
* Test default capabilities
*/
public void testCapabilities()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.allProceduresAreCallable());
assertTrue(dbmd.allTablesAreSelectable()); // not true all the time
// This should always be false for postgresql (at least for 7.x)
assertTrue(!dbmd.isReadOnly());
// does the backend support this yet? The protocol does...
assertTrue(!dbmd.supportsMultipleResultSets());
// yes, as multiple backends can have transactions open
assertTrue(dbmd.supportsMultipleTransactions());
assertTrue(dbmd.supportsMinimumSQLGrammar());
assertTrue(!dbmd.supportsCoreSQLGrammar());
assertTrue(!dbmd.supportsExtendedSQLGrammar());
assertTrue(!dbmd.supportsANSI92EntryLevelSQL());
assertTrue(!dbmd.supportsANSI92IntermediateSQL());
assertTrue(!dbmd.supportsANSI92FullSQL());
assertTrue(!dbmd.supportsIntegrityEnhancementFacility());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testJoins()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.supportsOuterJoins());
assertTrue(dbmd.supportsFullOuterJoins());
assertTrue(dbmd.supportsLimitedOuterJoins());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testCursors()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!dbmd.supportsPositionedDelete());
assertTrue(!dbmd.supportsPositionedUpdate());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testNulls()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
// We need to type cast the connection to get access to the
// PostgreSQL-specific method haveMinimumServerVersion().
// This is not available through the java.sql.Connection interface.
assertTrue( con instanceof org.postgresql.Connection );
assertTrue(!dbmd.nullsAreSortedAtStart());
assertTrue( dbmd.nullsAreSortedAtEnd() !=
((org.postgresql.Connection)con).haveMinimumServerVersion("7.2"));
assertTrue( dbmd.nullsAreSortedHigh() ==
((org.postgresql.Connection)con).haveMinimumServerVersion("7.2"));
assertTrue(!dbmd.nullsAreSortedLow());
assertTrue(dbmd.nullPlusNonNullIsNull());
assertTrue(dbmd.supportsNonNullableColumns());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testLocalFiles()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!dbmd.usesLocalFilePerTable());
assertTrue(!dbmd.usesLocalFiles());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testIdentifiers()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!dbmd.supportsMixedCaseIdentifiers()); // always false
assertTrue(dbmd.supportsMixedCaseQuotedIdentifiers()); // always true
assertTrue(!dbmd.storesUpperCaseIdentifiers()); // always false
assertTrue(dbmd.storesLowerCaseIdentifiers()); // always true
assertTrue(!dbmd.storesUpperCaseQuotedIdentifiers()); // always false
assertTrue(!dbmd.storesLowerCaseQuotedIdentifiers()); // always false
assertTrue(!dbmd.storesMixedCaseQuotedIdentifiers()); // always false
assertTrue(dbmd.getIdentifierQuoteString().equals("\""));
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testTables()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
// we can add columns
assertTrue(dbmd.supportsAlterTableWithAddColumn());
// we can't drop columns (yet)
assertTrue(!dbmd.supportsAlterTableWithDropColumn());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testSelect()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
// yes we can?: SELECT col a FROM a;
assertTrue(dbmd.supportsColumnAliasing());
// yes we can have expressions in ORDERBY
assertTrue(dbmd.supportsExpressionsInOrderBy());
// Yes, an ORDER BY clause can contain columns that are not in the
// SELECT clause.
assertTrue(dbmd.supportsOrderByUnrelated());
assertTrue(dbmd.supportsGroupBy());
assertTrue(dbmd.supportsGroupByUnrelated());
assertTrue(dbmd.supportsGroupByBeyondSelect()); // needs checking
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testDBParams()
{
try
{
Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getURL().equals(JDBC2Tests.getURL()));
assertTrue(dbmd.getUserName().equals(JDBC2Tests.getUser()));
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testDbProductDetails()
{
try
{
Connection con = JDBC2Tests.openDB();
assertTrue(con instanceof org.postgresql.Connection);
org.postgresql.Connection pc = (org.postgresql.Connection) con;
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getDatabaseProductName().equals("PostgreSQL"));
assertTrue(dbmd.getDatabaseProductVersion().startsWith(Integer.toString(pc.this_driver.getMajorVersion()) + "." + Integer.toString(pc.this_driver.getMinorVersion())));
assertTrue(dbmd.getDriverName().equals("PostgreSQL Native Driver"));
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
public void testDriverVersioning()
{
try
{
Connection con = JDBC2Tests.openDB();
assertTrue(con instanceof org.postgresql.Connection);
org.postgresql.Connection pc = (org.postgresql.Connection) con;
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(dbmd.getDriverVersion().equals(pc.this_driver.getVersion()));
assertTrue(dbmd.getDriverMajorVersion() == pc.this_driver.getMajorVersion());
assertTrue(dbmd.getDriverMinorVersion() == pc.this_driver.getMinorVersion());
JDBC2Tests.closeDB(con);
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
}

View File

@ -5,37 +5,43 @@ import junit.framework.TestCase;
import java.sql.*;
/**
* $Id: DateTest.java,v 1.2 2001/09/23 04:11:14 momjian Exp $
* $Id: DateTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*
* Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-)
*
*/
public class DateTest extends TestCase {
public class DateTest extends TestCase
{
private Connection con;
public DateTest(String name) {
public DateTest(String name)
{
super(name);
}
protected void setUp() throws Exception {
protected void setUp() throws Exception
{
con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "testdate", "dt date");
}
protected void tearDown() throws Exception {
protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testdate");
JDBC2Tests.closeDB(con);
}
/**
* Tests the time methods in ResultSet
*/
public void testGetDate() {
try {
public void testGetDate()
{
try
{
Statement stmt = con.createStatement();
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testdate", "'1950-02-07'")));
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testdate", "'1970-06-02'")));
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testdate", "'1999-08-11'")));
@ -46,7 +52,9 @@ public class DateTest extends TestCase {
assertEquals(4, stmt.executeUpdate("DELETE FROM " + "testdate"));
stmt.close();
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
@ -54,8 +62,10 @@ public class DateTest extends TestCase {
/**
* Tests the time methods in PreparedStatement
*/
public void testSetDate() {
try {
public void testSetDate()
{
try
{
Statement stmt = con.createStatement();
PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testdate", "?"));
@ -78,7 +88,9 @@ public class DateTest extends TestCase {
assertEquals(4, stmt.executeUpdate("DELETE FROM testdate"));
stmt.close();
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
@ -86,7 +98,8 @@ public class DateTest extends TestCase {
/**
* Helper for the date tests. It tests what should be in the db
*/
private void dateTest() throws SQLException {
private void dateTest() throws SQLException
{
Statement st = con.createStatement();
ResultSet rs;
java.sql.Date d;
@ -97,7 +110,7 @@ public class DateTest extends TestCase {
assertTrue(rs.next());
d = rs.getDate(1);
assertNotNull(d);
assertEquals(d, makeDate(1950, 2, 7));
assertEquals(d, makeDate(1950, 2, 7));
assertTrue(rs.next());
d = rs.getDate(1);
@ -108,7 +121,7 @@ public class DateTest extends TestCase {
d = rs.getDate(1);
assertNotNull(d);
assertEquals(d, makeDate(1999, 8, 11));
assertTrue(rs.next());
d = rs.getDate(1);
assertNotNull(d);
@ -120,7 +133,8 @@ public class DateTest extends TestCase {
st.close();
}
private java.sql.Date makeDate(int y, int m, int d) {
private java.sql.Date makeDate(int y, int m, int d)
{
return java.sql.Date.valueOf(JDBC2Tests.fix(y, 4) + "-" +
JDBC2Tests.fix(m, 2) + "-" +
JDBC2Tests.fix(d, 2));

View File

@ -5,68 +5,80 @@ import junit.framework.TestCase;
import java.sql.*;
/**
* $Id: DriverTest.java,v 1.2 2001/09/23 04:11:14 momjian Exp $
* $Id: DriverTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*
* Tests the dynamically created class org.postgresql.Driver
*
*/
public class DriverTest extends TestCase {
public class DriverTest extends TestCase
{
public DriverTest(String name) {
super(name);
}
public DriverTest(String name)
{
super(name);
}
/**
* This tests the acceptsURL() method with a couple of good and badly formed
* jdbc urls
*/
public void testAcceptsURL() {
try {
/**
* This tests the acceptsURL() method with a couple of good and badly formed
* jdbc urls
*/
public void testAcceptsURL()
{
try
{
// Load the driver (note clients should never do it this way!)
org.postgresql.Driver drv = new org.postgresql.Driver();
assertNotNull(drv);
// Load the driver (note clients should never do it this way!)
org.postgresql.Driver drv = new org.postgresql.Driver();
assertNotNull(drv);
// These are always correct
assertTrue(drv.acceptsURL("jdbc:postgresql:test"));
assertTrue(drv.acceptsURL("jdbc:postgresql://localhost/test"));
assertTrue(drv.acceptsURL("jdbc:postgresql://localhost:5432/test"));
assertTrue(drv.acceptsURL("jdbc:postgresql://127.0.0.1/anydbname"));
assertTrue(drv.acceptsURL("jdbc:postgresql://127.0.0.1:5433/hidden"));
// These are always correct
assertTrue(drv.acceptsURL("jdbc:postgresql:test"));
assertTrue(drv.acceptsURL("jdbc:postgresql://localhost/test"));
assertTrue(drv.acceptsURL("jdbc:postgresql://localhost:5432/test"));
assertTrue(drv.acceptsURL("jdbc:postgresql://127.0.0.1/anydbname"));
assertTrue(drv.acceptsURL("jdbc:postgresql://127.0.0.1:5433/hidden"));
// Badly formatted url's
assertTrue(!drv.acceptsURL("jdbc:postgres:test"));
assertTrue(!drv.acceptsURL("postgresql:test"));
// Badly formatted url's
assertTrue(!drv.acceptsURL("jdbc:postgres:test"));
assertTrue(!drv.acceptsURL("postgresql:test"));
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
/**
* Tests parseURL (internal)
*/
/**
* Tests the connect method by connecting to the test database
*/
public void testConnect() {
Connection con=null;
try {
Class.forName("org.postgresql.Driver");
/**
* Tests parseURL (internal)
*/
/**
* Tests the connect method by connecting to the test database
*/
public void testConnect()
{
Connection con = null;
try
{
Class.forName("org.postgresql.Driver");
// Test with the url, username & password
con = DriverManager.getConnection(JDBC2Tests.getURL(),JDBC2Tests.getUser(),JDBC2Tests.getPassword());
assertNotNull(con);
con.close();
// Test with the url, username & password
con = DriverManager.getConnection(JDBC2Tests.getURL(), JDBC2Tests.getUser(), JDBC2Tests.getPassword());
assertNotNull(con);
con.close();
// Test with the username in the url
con = DriverManager.getConnection(JDBC2Tests.getURL()+"?user="+JDBC2Tests.getUser()+"&password="+JDBC2Tests.getPassword());
assertNotNull(con);
con.close();
} catch(ClassNotFoundException ex) {
fail(ex.getMessage());
} catch(SQLException ex) {
fail(ex.getMessage());
}
}
// Test with the username in the url
con = DriverManager.getConnection(JDBC2Tests.getURL() + "?user=" + JDBC2Tests.getUser() + "&password=" + JDBC2Tests.getPassword());
assertNotNull(con);
con.close();
}
catch (ClassNotFoundException ex)
{
fail(ex.getMessage());
}
catch (SQLException ex)
{
fail(ex.getMessage());
}
}
}

View File

@ -8,50 +8,55 @@ import java.io.*;
/**
* Tests for the Encoding class.
*
* $Id: EncodingTest.java,v 1.2 2001/09/23 04:11:14 momjian Exp $
* $Id: EncodingTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*/
public class EncodingTest extends TestCase {
public class EncodingTest extends TestCase
{
public EncodingTest(String name) {
super(name);
}
public EncodingTest(String name)
{
super(name);
}
public void testCreation() throws Exception {
Encoding encoding;
encoding = Encoding.getEncoding("UNICODE", null);
assertEquals("UTF", encoding.name().substring(0, 3).toUpperCase());
encoding = Encoding.getEncoding("SQL_ASCII", null);
assertTrue(encoding.name().toUpperCase().indexOf("ASCII") != -1);
assertEquals("When encoding is unknown the default encoding should be used",
Encoding.defaultEncoding(),
Encoding.getEncoding("UNKNOWN", null));
encoding = Encoding.getEncoding("SQL_ASCII", "utf-8");
assertTrue("Encoding passed in by the user should be preferred",
encoding.name().toUpperCase().indexOf("UTF") != -1);
}
public void testCreation() throws Exception
{
Encoding encoding;
encoding = Encoding.getEncoding("UNICODE", null);
assertEquals("UTF", encoding.name().substring(0, 3).toUpperCase());
encoding = Encoding.getEncoding("SQL_ASCII", null);
assertTrue(encoding.name().toUpperCase().indexOf("ASCII") != -1);
assertEquals("When encoding is unknown the default encoding should be used",
Encoding.defaultEncoding(),
Encoding.getEncoding("UNKNOWN", null));
encoding = Encoding.getEncoding("SQL_ASCII", "utf-8");
assertTrue("Encoding passed in by the user should be preferred",
encoding.name().toUpperCase().indexOf("UTF") != -1);
}
public void testTransformations() throws Exception {
Encoding encoding = Encoding.getEncoding("UNICODE", null);
assertEquals("ab", encoding.decode(new byte[] { 97, 98 }));
public void testTransformations() throws Exception
{
Encoding encoding = Encoding.getEncoding("UNICODE", null);
assertEquals("ab", encoding.decode(new byte[] { 97, 98 }));
assertEquals(2, encoding.encode("ab").length);
assertEquals(97, encoding.encode("a")[0]);
assertEquals(98, encoding.encode("b")[0]);
assertEquals(2, encoding.encode("ab").length);
assertEquals(97, encoding.encode("a")[0]);
assertEquals(98, encoding.encode("b")[0]);
encoding = Encoding.defaultEncoding();
assertEquals("a".getBytes()[0], encoding.encode("a")[0]);
assertEquals(new String(new byte[] { 97 }),
encoding.decode(new byte[] { 97 }));
}
encoding = Encoding.defaultEncoding();
assertEquals("a".getBytes()[0], encoding.encode("a")[0]);
assertEquals(new String(new byte[] { 97 }),
encoding.decode(new byte[] { 97 }));
}
public void testReader() throws Exception {
Encoding encoding = Encoding.getEncoding("SQL_ASCII", null);
InputStream stream = new ByteArrayInputStream(new byte[] { 97, 98 });
Reader reader = encoding.getDecodingReader(stream);
assertEquals(97, reader.read());
assertEquals(98, reader.read());
assertEquals(-1, reader.read());
}
public void testReader() throws Exception
{
Encoding encoding = Encoding.getEncoding("SQL_ASCII", null);
InputStream stream = new ByteArrayInputStream(new byte[] { 97, 98 });
Reader reader = encoding.getDecodingReader(stream);
assertEquals(97, reader.read());
assertEquals(98, reader.read());
assertEquals( -1, reader.read());
}
}

View File

@ -6,56 +6,65 @@ import java.sql.*;
import java.math.BigDecimal;
/**
* $Id: JBuilderTest.java,v 1.3 2001/09/23 04:11:14 momjian Exp $
* $Id: JBuilderTest.java,v 1.4 2001/10/25 05:59:59 momjian Exp $
*
* Some simple tests to check that the required components needed for JBuilder
* stay working
*
*/
public class JBuilderTest extends TestCase {
public class JBuilderTest extends TestCase
{
public JBuilderTest(String name) {
super(name);
}
public JBuilderTest(String name)
{
super(name);
}
// Set up the fixture for this testcase: the tables for this test.
protected void setUp() throws Exception {
Connection con = JDBC2Tests.openDB();
// Set up the fixture for this testcase: the tables for this test.
protected void setUp() throws Exception
{
Connection con = JDBC2Tests.openDB();
JDBC2Tests.createTable( con, "test_c",
"source text,cost money,imageid int4" );
JDBC2Tests.createTable( con, "test_c",
"source text,cost money,imageid int4" );
JDBC2Tests.closeDB(con);
}
JDBC2Tests.closeDB(con);
}
// Tear down the fixture for this test case.
protected void tearDown() throws Exception {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.dropTable(con, "test_c");
JDBC2Tests.closeDB(con);
}
// Tear down the fixture for this test case.
protected void tearDown() throws Exception
{
Connection con = JDBC2Tests.openDB();
JDBC2Tests.dropTable(con, "test_c");
JDBC2Tests.closeDB(con);
}
/**
* This tests that Money types work. JDBCExplorer barfs if this fails.
*/
public void testMoney() {
try {
Connection con = JDBC2Tests.openDB();
/**
* This tests that Money types work. JDBCExplorer barfs if this fails.
*/
public void testMoney()
{
try
{
Connection con = JDBC2Tests.openDB();
Statement st=con.createStatement();
ResultSet rs=st.executeQuery("select cost from test_c");
assertNotNull(rs);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select cost from test_c");
assertNotNull(rs);
while(rs.next()){
double bd = rs.getDouble(1);
}
while (rs.next())
{
double bd = rs.getDouble(1);
}
rs.close();
st.close();
rs.close();
st.close();
JDBC2Tests.closeDB(con);
} catch(Exception ex) {
fail(ex.getMessage());
}
}
JDBC2Tests.closeDB(con);
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
}

View File

@ -5,43 +5,50 @@ import junit.framework.TestCase;
import java.sql.*;
/**
* $Id: MiscTest.java,v 1.2 2001/09/23 04:11:14 momjian Exp $
* $Id: MiscTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*
* Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-)
*
*/
public class MiscTest extends TestCase {
public class MiscTest extends TestCase
{
public MiscTest(String name) {
super(name);
}
public MiscTest(String name)
{
super(name);
}
/**
* Some versions of the driver would return rs as a null?
*
* Sasha <ber0806@iperbole.bologna.it> was having this problem.
*
* Added Feb 13 2001
*/
public void testDatabaseSelectNullBug() {
try {
Connection con = JDBC2Tests.openDB();
/**
* Some versions of the driver would return rs as a null?
*
* Sasha <ber0806@iperbole.bologna.it> was having this problem.
*
* Added Feb 13 2001
*/
public void testDatabaseSelectNullBug()
{
try
{
Connection con = JDBC2Tests.openDB();
Statement st=con.createStatement();
ResultSet rs=st.executeQuery("select datname from pg_database");
assertNotNull(rs);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select datname from pg_database");
assertNotNull(rs);
while(rs.next()){
String s = rs.getString(1);
}
while (rs.next())
{
String s = rs.getString(1);
}
rs.close();
st.close();
rs.close();
st.close();
JDBC2Tests.closeDB(con);
} catch(Exception ex) {
fail(ex.getMessage());
}
}
JDBC2Tests.closeDB(con);
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
}

View File

@ -5,37 +5,43 @@ import junit.framework.TestCase;
import java.sql.*;
/**
* $Id: TimeTest.java,v 1.2 2001/09/23 04:11:14 momjian Exp $
* $Id: TimeTest.java,v 1.3 2001/10/25 05:59:59 momjian Exp $
*
* Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-)
*
*/
public class TimeTest extends TestCase {
public class TimeTest extends TestCase
{
private Connection con;
public TimeTest(String name) {
super(name);
}
protected void setUp() throws Exception {
public TimeTest(String name)
{
super(name);
}
protected void setUp() throws Exception
{
con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "testtime", "tm time");
}
}
protected void tearDown() throws Exception {
protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testtime");
JDBC2Tests.closeDB(con);
}
/**
* Tests the time methods in ResultSet
*/
public void testGetTime() {
try {
}
/**
* Tests the time methods in ResultSet
*/
public void testGetTime()
{
try
{
Statement stmt = con.createStatement();
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtime", "'01:02:03'")));
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtime", "'23:59:59'")));
@ -44,16 +50,20 @@ public class TimeTest extends TestCase {
assertEquals(2, stmt.executeUpdate("DELETE FROM testtime"));
stmt.close();
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
}
/**
* Tests the time methods in PreparedStatement
*/
public void testSetTime() {
try {
/**
* Tests the time methods in PreparedStatement
*/
public void testSetTime()
{
try
{
PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testtime", "?"));
Statement stmt = con.createStatement();
@ -69,15 +79,18 @@ public class TimeTest extends TestCase {
assertEquals(2, stmt.executeUpdate("DELETE FROM testtime"));
stmt.close();
ps.close();
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
}
/**
* Helper for the TimeTests. It tests what should be in the db
*/
private void timeTest() throws SQLException {
/**
* Helper for the TimeTests. It tests what should be in the db
*/
private void timeTest() throws SQLException
{
Statement st = con.createStatement();
ResultSet rs;
java.sql.Time t;
@ -98,11 +111,12 @@ public class TimeTest extends TestCase {
assertTrue(! rs.next());
rs.close();
}
}
private java.sql.Time makeTime(int h, int m, int s) {
private java.sql.Time makeTime(int h, int m, int s)
{
return java.sql.Time.valueOf(JDBC2Tests.fix(h, 2) + ":" +
JDBC2Tests.fix(m, 2) + ":" +
JDBC2Tests.fix(s, 2));
}
}
}

View File

@ -5,7 +5,7 @@ import junit.framework.TestCase;
import java.sql.*;
/**
* $Id: TimestampTest.java,v 1.4 2001/09/29 03:11:11 momjian Exp $
* $Id: TimestampTest.java,v 1.5 2001/10/25 05:59:59 momjian Exp $
*
* This has been the most controversial pair of methods since 6.5 was released!
*
@ -13,22 +13,26 @@ import java.sql.*;
* MUST PASS this TestCase!!!
*
*/
public class TimestampTest extends TestCase {
public class TimestampTest extends TestCase
{
private Connection con;
public TimestampTest(String name) {
public TimestampTest(String name)
{
super(name);
}
protected void setUp() throws Exception {
protected void setUp() throws Exception
{
con = JDBC2Tests.openDB();
Statement stmt = con.createStatement();
JDBC2Tests.createTable(con, "testtimestamp", "ts timestamp");
}
protected void tearDown() throws Exception {
protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testtimestamp");
JDBC2Tests.closeDB(con);
}
@ -36,19 +40,21 @@ public class TimestampTest extends TestCase {
/**
* Tests the time methods in ResultSet
*/
public void testGetTimestamp() {
try {
public void testGetTimestamp()
{
try
{
Statement stmt = con.createStatement();
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp",
"'1950-02-07 15:00:00'")));
"'1950-02-07 15:00:00'")));
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp", "'" +
getTimestamp(1970, 6, 2, 8, 13, 0, 0).toString() +
"'")));
getTimestamp(1970, 6, 2, 8, 13, 0, 0).toString() +
"'")));
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp",
"'1970-06-02 08:13:00'")));
"'1970-06-02 08:13:00'")));
// Fall through helper
timestampTest();
@ -56,7 +62,9 @@ public class TimestampTest extends TestCase {
assertEquals(3, stmt.executeUpdate("DELETE FROM testtimestamp"));
stmt.close();
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
@ -64,8 +72,10 @@ public class TimestampTest extends TestCase {
/**
* Tests the time methods in PreparedStatement
*/
public void testSetTimestamp() {
try {
public void testSetTimestamp()
{
try
{
Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement(JDBC2Tests.insertSQL("testtimestamp", "?"));
@ -85,7 +95,9 @@ public class TimestampTest extends TestCase {
pstmt.close();
stmt.close();
} catch(Exception ex) {
}
catch (Exception ex)
{
fail(ex.getMessage());
}
}
@ -93,7 +105,8 @@ public class TimestampTest extends TestCase {
/**
* Helper for the TimeTests. It tests what should be in the db
*/
private void timestampTest() throws SQLException {
private void timestampTest() throws SQLException
{
Statement stmt = con.createStatement();
ResultSet rs;
java.sql.Timestamp t;
@ -115,20 +128,21 @@ public class TimestampTest extends TestCase {
t = rs.getTimestamp(1);
assertNotNull(t);
assertTrue(t.equals(getTimestamp(1970, 6, 2, 8, 13, 0, 0)));
assertTrue(! rs.next()); // end of table. Fail if more entries exist.
rs.close();
stmt.close();
}
private java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int mn, int se, int f) {
return java.sql.Timestamp.valueOf(JDBC2Tests.fix(y, 4) + "-" +
JDBC2Tests.fix(m, 2) + "-" +
JDBC2Tests.fix(d, 2) + " " +
JDBC2Tests.fix(h, 2) + ":" +
private java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int mn, int se, int f)
{
return java.sql.Timestamp.valueOf(JDBC2Tests.fix(y, 4) + "-" +
JDBC2Tests.fix(m, 2) + "-" +
JDBC2Tests.fix(d, 2) + " " +
JDBC2Tests.fix(h, 2) + ":" +
JDBC2Tests.fix(mn, 2) + ":" +
JDBC2Tests.fix(se, 2) + "." +
JDBC2Tests.fix(f, 9));
JDBC2Tests.fix(f, 9));
}
}

View File

@ -6,58 +6,74 @@ import java.text.*;
/**
* A singleton class to translate JDBC driver messages in SQLException's.
*/
public class MessageTranslator {
public class MessageTranslator
{
// The singleton instance.
private static MessageTranslator instance = null;
private ResourceBundle bundle;
private MessageTranslator() {
try {
private MessageTranslator()
{
try
{
bundle = ResourceBundle.getBundle("org.postgresql.errors");
} catch(MissingResourceException e) {
}
catch (MissingResourceException e)
{
// translation files have not been installed.
bundle = null;
}
}
}
// Synchronized, otherwise multiple threads may perform the test and
// assign to the singleton instance simultaneously.
private synchronized final static MessageTranslator getInstance() {
if (instance == null) {
private synchronized final static MessageTranslator getInstance()
{
if (instance == null)
{
instance = new MessageTranslator();
}
return instance;
}
public final static String translate(String id, Object[] args) {
public final static String translate(String id, Object[] args)
{
MessageTranslator translator = MessageTranslator.getInstance();
return translator._translate(id, args);
}
private final String _translate(String id, Object[] args) {
private final String _translate(String id, Object[] args)
{
String message;
if (bundle != null && id != null) {
if (bundle != null && id != null)
{
// Now look up a localized message. If one is not found, then use
// the supplied message instead.
try {
try
{
message = bundle.getString(id);
} catch(MissingResourceException e) {
}
catch (MissingResourceException e)
{
message = id;
}
} else {
}
else
{
message = id;
}
// Expand any arguments
if (args != null && message != null) {
message = MessageFormat.format(message,args);
if (args != null && message != null)
{
message = MessageFormat.format(message, args);
}
return message;
}
}
}

View File

@ -5,82 +5,98 @@ import java.sql.*;
/**
* Converts to and from the postgresql bytea datatype used by the backend.
*
* $Id: PGbytea.java,v 1.1 2001/09/10 15:07:05 momjian Exp $
* $Id: PGbytea.java,v 1.2 2001/10/25 06:00:00 momjian Exp $
*/
public class PGbytea {
public class PGbytea
{
/**
* Converts a PG bytea string (i.e. the text representation
* of the bytea data type) into a java byte[]
*/
public static byte[] toBytes(String s) throws SQLException {
if(s==null)
return null;
int slength = s.length();
byte[] buf = new byte[slength];
int bufpos = 0;
int thebyte;
char nextchar;
char secondchar;
for (int i = 0; i < slength; i++) {
nextchar = s.charAt(i);
if (nextchar == '\\') {
secondchar = s.charAt(++i);
if (secondchar == '\\') {
//escaped \
buf[bufpos++] = (byte)'\\';
} else {
thebyte = (secondchar-48)*64 + (s.charAt(++i)-48)*8 + (s.charAt(++i)-48);
if (thebyte > 127)
thebyte -= 256;
buf[bufpos++] = (byte)thebyte;
}
} else {
buf[bufpos++] = (byte)nextchar;
}
}
byte[] l_return = new byte[bufpos];
System.arraycopy(buf,0,l_return,0,bufpos);
return l_return;
}
/**
* Converts a PG bytea string (i.e. the text representation
* of the bytea data type) into a java byte[]
*/
public static byte[] toBytes(String s) throws SQLException
{
if (s == null)
return null;
int slength = s.length();
byte[] buf = new byte[slength];
int bufpos = 0;
int thebyte;
char nextchar;
char secondchar;
for (int i = 0; i < slength; i++)
{
nextchar = s.charAt(i);
if (nextchar == '\\')
{
secondchar = s.charAt(++i);
if (secondchar == '\\')
{
//escaped \
buf[bufpos++] = (byte)'\\';
}
else
{
thebyte = (secondchar - 48) * 64 + (s.charAt(++i) - 48) * 8 + (s.charAt(++i) - 48);
if (thebyte > 127)
thebyte -= 256;
buf[bufpos++] = (byte)thebyte;
}
}
else
{
buf[bufpos++] = (byte)nextchar;
}
}
byte[] l_return = new byte[bufpos];
System.arraycopy(buf, 0, l_return, 0, bufpos);
return l_return;
}
/**
* Converts a java byte[] into a PG bytea string (i.e. the text
* representation of the bytea data type)
*/
public static String toPGString(byte[] p_buf) throws SQLException
{
if(p_buf==null)
return null;
StringBuffer l_strbuf = new StringBuffer();
for (int i = 0; i < p_buf.length; i++) {
int l_int = (int)p_buf[i];
if (l_int < 0) {
l_int = 256 + l_int;
}
//we escape the same non-printable characters as the backend
//we must escape all 8bit characters otherwise when convering
//from java unicode to the db character set we may end up with
//question marks if the character set is SQL_ASCII
if (l_int < 040 || l_int > 0176) {
//escape charcter with the form \000, but need two \\ because of
//the parser
l_strbuf.append("\\");
l_strbuf.append((char)(((l_int >> 6) & 0x3)+48));
l_strbuf.append((char)(((l_int >> 3) & 0x7)+48));
l_strbuf.append((char)((l_int & 0x07)+48));
} else if (p_buf[i] == (byte)'\\') {
//escape the backslash character as \\, but need four \\\\ because
//of the parser
l_strbuf.append("\\\\");
} else {
//other characters are left alone
l_strbuf.append((char)p_buf[i]);
}
}
return l_strbuf.toString();
}
/**
* Converts a java byte[] into a PG bytea string (i.e. the text
* representation of the bytea data type)
*/
public static String toPGString(byte[] p_buf) throws SQLException
{
if (p_buf == null)
return null;
StringBuffer l_strbuf = new StringBuffer();
for (int i = 0; i < p_buf.length; i++)
{
int l_int = (int)p_buf[i];
if (l_int < 0)
{
l_int = 256 + l_int;
}
//we escape the same non-printable characters as the backend
//we must escape all 8bit characters otherwise when convering
//from java unicode to the db character set we may end up with
//question marks if the character set is SQL_ASCII
if (l_int < 040 || l_int > 0176)
{
//escape charcter with the form \000, but need two \\ because of
//the parser
l_strbuf.append("\\");
l_strbuf.append((char)(((l_int >> 6) & 0x3) + 48));
l_strbuf.append((char)(((l_int >> 3) & 0x7) + 48));
l_strbuf.append((char)((l_int & 0x07) + 48));
}
else if (p_buf[i] == (byte)'\\')
{
//escape the backslash character as \\, but need four \\\\ because
//of the parser
l_strbuf.append("\\\\");
}
else
{
//other characters are left alone
l_strbuf.append((char)p_buf[i]);
}
}
return l_strbuf.toString();
}
}

View File

@ -6,102 +6,110 @@ import java.sql.*;
/**
* This implements a class that handles the PostgreSQL money and cash types
*/
public class PGmoney extends PGobject implements Serializable,Cloneable
public class PGmoney extends PGobject implements Serializable, Cloneable
{
/**
* The value of the field
*/
public double val;
/**
* The value of the field
*/
public double val;
/**
* @param value of field
*/
public PGmoney(double value) {
this();
val = value;
}
/**
* @param value of field
*/
public PGmoney(double value)
{
this();
val = value;
}
/**
* This is called mainly from the other geometric types, when a
* point is imbeded within their definition.
*
* @param value Definition of this point in PostgreSQL's syntax
*/
public PGmoney(String value) throws SQLException
{
this();
setValue(value);
}
/**
* This is called mainly from the other geometric types, when a
* point is imbeded within their definition.
*
* @param value Definition of this point in PostgreSQL's syntax
*/
public PGmoney(String value) throws SQLException
{
this();
setValue(value);
}
/**
* Required by the driver
*/
public PGmoney()
{
setType("money");
}
/**
* Required by the driver
*/
public PGmoney()
{
setType("money");
}
/**
* @param s Definition of this point in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
try {
String s1;
boolean negative;
/**
* @param s Definition of this point in PostgreSQL's syntax
* @exception SQLException on conversion failure
*/
public void setValue(String s) throws SQLException
{
try
{
String s1;
boolean negative;
negative = (s.charAt(0) == '(') ;
negative = (s.charAt(0) == '(') ;
// Remove any () (for negative) & currency symbol
s1 = PGtokenizer.removePara(s).substring(1);
// Remove any () (for negative) & currency symbol
s1 = PGtokenizer.removePara(s).substring(1);
// Strip out any , in currency
int pos = s1.indexOf(',');
while (pos != -1) {
s1 = s1.substring(0,pos) + s1.substring(pos +1);
pos = s1.indexOf(',');
}
// Strip out any , in currency
int pos = s1.indexOf(',');
while (pos != -1)
{
s1 = s1.substring(0, pos) + s1.substring(pos + 1);
pos = s1.indexOf(',');
}
val = Double.valueOf(s1).doubleValue();
val = negative ? -val : val;
val = Double.valueOf(s1).doubleValue();
val = negative ? -val : val;
} catch(NumberFormatException e) {
throw new PSQLException("postgresql.money",e);
}
}
}
catch (NumberFormatException e)
{
throw new PSQLException("postgresql.money", e);
}
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGmoney) {
PGmoney p = (PGmoney)obj;
return val == p.val;
}
return false;
}
/**
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGmoney)
{
PGmoney p = (PGmoney)obj;
return val == p.val;
}
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGmoney(val);
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
return new PGmoney(val);
}
/**
* @return the PGpoint in the syntax expected by org.postgresql
*/
public String getValue()
{
if (val < 0) {
return "-$" + (-val);
}
else {
return "$"+val;
}
}
/**
* @return the PGpoint in the syntax expected by org.postgresql
*/
public String getValue()
{
if (val < 0)
{
return "-$" + ( -val);
}
else
{
return "$" + val;
}
}
}

View File

@ -6,97 +6,96 @@ import java.sql.*;
import java.util.*;
/**
* org.postgresql.PG_Object is a class used to describe unknown types
* org.postgresql.PG_Object is a class used to describe unknown types
* An unknown type is any type that is unknown by JDBC Standards
*
* <p>As of PostgreSQL 6.3, this allows user code to add their own
* handlers via a call to org.postgresql.Connection. These handlers
* must extend this class.
*/
public class PGobject implements Serializable,Cloneable
public class PGobject implements Serializable, Cloneable
{
protected String type;
protected String value;
/**
* This is called by org.postgresql.Connection.getObject() to create the
* object.
*/
public PGobject()
{
}
/**
* This method sets the type of this object.
*
* <p>It should not be extended by subclasses, hence its final
*
* @param type a string describing the type of the object
*/
public final void setType(String type)
{
this.type = type;
}
/**
* This method sets the value of this object. It must be overidden.
*
* @param value a string representation of the value of the object
* @exception SQLException thrown if value is invalid for this type
*/
public void setValue(String value) throws SQLException
{
this.value = value;
}
/**
* As this cannot change during the life of the object, it's final.
* @return the type name of this object
*/
public final String getType()
{
return type;
}
/**
* This must be overidden, to return the value of the object, in the
* form required by org.postgresql.
* @return the value of this object
*/
public String getValue()
{
return value;
}
/**
* This must be overidden to allow comparisons of objects
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if(obj instanceof PGobject)
return ((PGobject)obj).getValue().equals(getValue());
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
PGobject obj = new PGobject();
obj.type=type;
obj.value=value;
return obj;
}
/**
* This is defined here, so user code need not overide it.
* @return the value of this object, in the syntax expected by org.postgresql
*/
public String toString()
{
return getValue();
}
protected String type;
protected String value;
/**
* This is called by org.postgresql.Connection.getObject() to create the
* object.
*/
public PGobject()
{}
/**
* This method sets the type of this object.
*
* <p>It should not be extended by subclasses, hence its final
*
* @param type a string describing the type of the object
*/
public final void setType(String type)
{
this.type = type;
}
/**
* This method sets the value of this object. It must be overidden.
*
* @param value a string representation of the value of the object
* @exception SQLException thrown if value is invalid for this type
*/
public void setValue(String value) throws SQLException
{
this.value = value;
}
/**
* As this cannot change during the life of the object, it's final.
* @return the type name of this object
*/
public final String getType()
{
return type;
}
/**
* This must be overidden, to return the value of the object, in the
* form required by org.postgresql.
* @return the value of this object
*/
public String getValue()
{
return value;
}
/**
* This must be overidden to allow comparisons of objects
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
public boolean equals(Object obj)
{
if (obj instanceof PGobject)
return ((PGobject)obj).getValue().equals(getValue());
return false;
}
/**
* This must be overidden to allow the object to be cloned
*/
public Object clone()
{
PGobject obj = new PGobject();
obj.type = type;
obj.value = value;
return obj;
}
/**
* This is defined here, so user code need not overide it.
* @return the value of this object, in the syntax expected by org.postgresql
*/
public String toString()
{
return getValue();
}
}

View File

@ -18,180 +18,186 @@ import java.util.*;
*/
public class PGtokenizer
{
// Our tokens
protected Vector tokens;
/**
* Create a tokeniser.
*
* <p>We could have used StringTokenizer to do this, however, we needed to
* handle nesting of '(' ')' '[' ']' '&lt;' and '&gt;' as these are used
* by the geometric data types.
*
* @param string containing tokens
* @param delim single character to split the tokens
*/
public PGtokenizer(String string,char delim)
{
tokenize(string,delim);
}
/**
* This resets this tokenizer with a new string and/or delimiter.
*
* @param string containing tokens
* @param delim single character to split the tokens
*/
public int tokenize(String string,char delim)
{
tokens = new Vector();
// nest holds how many levels we are in the current token.
// if this is > 0 then we don't split a token when delim is matched.
//
// The Geometric datatypes use this, because often a type may have others
// (usualls PGpoint) imbedded within a token.
//
// Peter 1998 Jan 6 - Added < and > to the nesting rules
int nest=0,p,s;
for(p=0,s=0;p<string.length();p++) {
char c = string.charAt(p);
// increase nesting if an open character is found
if(c == '(' || c == '[' || c == '<')
nest++;
// decrease nesting if a close character is found
if(c == ')' || c == ']' || c == '>')
nest--;
if(nest==0 && c==delim) {
tokens.addElement(string.substring(s,p));
s=p+1; // +1 to skip the delimiter
}
}
// Don't forget the last token ;-)
if(s<string.length())
tokens.addElement(string.substring(s));
return tokens.size();
}
/**
* @return the number of tokens available
*/
public int getSize()
{
return tokens.size();
}
/**
* @param n Token number ( 0 ... getSize()-1 )
* @return The token value
*/
public String getToken(int n)
{
return (String)tokens.elementAt(n);
}
/**
* This returns a new tokenizer based on one of our tokens.
*
* The geometric datatypes use this to process nested tokens (usually
* PGpoint).
*
* @param n Token number ( 0 ... getSize()-1 )
* @param delim The delimiter to use
* @return A new instance of PGtokenizer based on the token
*/
public PGtokenizer tokenizeToken(int n,char delim)
{
return new PGtokenizer(getToken(n),delim);
}
/**
* This removes the lead/trailing strings from a string
* @param s Source string
* @param l Leading string to remove
* @param t Trailing string to remove
* @return String without the lead/trailing strings
*/
public static String remove(String s,String l,String t)
{
if(s.startsWith(l)) s = s.substring(l.length());
if(s.endsWith(t)) s = s.substring(0,s.length()-t.length());
return s;
}
/**
* This removes the lead/trailing strings from all tokens
* @param l Leading string to remove
* @param t Trailing string to remove
*/
public void remove(String l,String t)
{
for(int i=0;i<tokens.size();i++) {
tokens.setElementAt(remove((String)tokens.elementAt(i),l,t),i);
}
}
/**
* Removes ( and ) from the beginning and end of a string
* @param s String to remove from
* @return String without the ( or )
*/
public static String removePara(String s)
{
return remove(s,"(",")");
}
/**
* Removes ( and ) from the beginning and end of all tokens
* @return String without the ( or )
*/
public void removePara()
{
remove("(",")");
}
/**
* Removes [ and ] from the beginning and end of a string
* @param s String to remove from
* @return String without the [ or ]
*/
public static String removeBox(String s)
{
return remove(s,"[","]");
}
/**
* Removes [ and ] from the beginning and end of all tokens
* @return String without the [ or ]
*/
public void removeBox()
{
remove("[","]");
}
/**
* Removes &lt; and &gt; from the beginning and end of a string
* @param s String to remove from
* @return String without the &lt; or &gt;
*/
public static String removeAngle(String s)
{
return remove(s,"<",">");
}
/**
* Removes &lt; and &gt; from the beginning and end of all tokens
* @return String without the &lt; or &gt;
*/
public void removeAngle()
{
remove("<",">");
}
// Our tokens
protected Vector tokens;
/**
* Create a tokeniser.
*
* <p>We could have used StringTokenizer to do this, however, we needed to
* handle nesting of '(' ')' '[' ']' '&lt;' and '&gt;' as these are used
* by the geometric data types.
*
* @param string containing tokens
* @param delim single character to split the tokens
*/
public PGtokenizer(String string, char delim)
{
tokenize(string, delim);
}
/**
* This resets this tokenizer with a new string and/or delimiter.
*
* @param string containing tokens
* @param delim single character to split the tokens
*/
public int tokenize(String string, char delim)
{
tokens = new Vector();
// nest holds how many levels we are in the current token.
// if this is > 0 then we don't split a token when delim is matched.
//
// The Geometric datatypes use this, because often a type may have others
// (usualls PGpoint) imbedded within a token.
//
// Peter 1998 Jan 6 - Added < and > to the nesting rules
int nest = 0, p, s;
for (p = 0, s = 0;p < string.length();p++)
{
char c = string.charAt(p);
// increase nesting if an open character is found
if (c == '(' || c == '[' || c == '<')
nest++;
// decrease nesting if a close character is found
if (c == ')' || c == ']' || c == '>')
nest--;
if (nest == 0 && c == delim)
{
tokens.addElement(string.substring(s, p));
s = p + 1; // +1 to skip the delimiter
}
}
// Don't forget the last token ;-)
if (s < string.length())
tokens.addElement(string.substring(s));
return tokens.size();
}
/**
* @return the number of tokens available
*/
public int getSize()
{
return tokens.size();
}
/**
* @param n Token number ( 0 ... getSize()-1 )
* @return The token value
*/
public String getToken(int n)
{
return (String)tokens.elementAt(n);
}
/**
* This returns a new tokenizer based on one of our tokens.
*
* The geometric datatypes use this to process nested tokens (usually
* PGpoint).
*
* @param n Token number ( 0 ... getSize()-1 )
* @param delim The delimiter to use
* @return A new instance of PGtokenizer based on the token
*/
public PGtokenizer tokenizeToken(int n, char delim)
{
return new PGtokenizer(getToken(n), delim);
}
/**
* This removes the lead/trailing strings from a string
* @param s Source string
* @param l Leading string to remove
* @param t Trailing string to remove
* @return String without the lead/trailing strings
*/
public static String remove(String s, String l, String t)
{
if (s.startsWith(l))
s = s.substring(l.length());
if (s.endsWith(t))
s = s.substring(0, s.length() - t.length());
return s;
}
/**
* This removes the lead/trailing strings from all tokens
* @param l Leading string to remove
* @param t Trailing string to remove
*/
public void remove(String l, String t)
{
for (int i = 0;i < tokens.size();i++)
{
tokens.setElementAt(remove((String)tokens.elementAt(i), l, t), i);
}
}
/**
* Removes ( and ) from the beginning and end of a string
* @param s String to remove from
* @return String without the ( or )
*/
public static String removePara(String s)
{
return remove(s, "(", ")");
}
/**
* Removes ( and ) from the beginning and end of all tokens
* @return String without the ( or )
*/
public void removePara()
{
remove("(", ")");
}
/**
* Removes [ and ] from the beginning and end of a string
* @param s String to remove from
* @return String without the [ or ]
*/
public static String removeBox(String s)
{
return remove(s, "[", "]");
}
/**
* Removes [ and ] from the beginning and end of all tokens
* @return String without the [ or ]
*/
public void removeBox()
{
remove("[", "]");
}
/**
* Removes &lt; and &gt; from the beginning and end of a string
* @param s String to remove from
* @return String without the &lt; or &gt;
*/
public static String removeAngle(String s)
{
return remove(s, "<", ">");
}
/**
* Removes &lt; and &gt; from the beginning and end of all tokens
* @return String without the &lt; or &gt;
*/
public void removeAngle()
{
remove("<", ">");
}
}

View File

@ -8,104 +8,109 @@ import java.sql.*;
*/
public class PSQLException extends SQLException
{
private String message;
private String message;
/**
* This provides the same functionality to SQLException
* @param error Error string
*/
public PSQLException(String error) {
super();
translate(error,null);
}
/**
* A more generic entry point.
* @param error Error string or standard message id
* @param args Array of arguments
*/
public PSQLException(String error,Object[] args)
{
//super();
translate(error,args);
}
/**
* Helper version for 1 arg
*/
public PSQLException(String error,Object arg)
{
super();
Object[] argv = new Object[1];
argv[0] = arg;
translate(error,argv);
}
/**
* Helper version for 1 arg. This is used for debug purposes only with
* some unusual Exception's. It allows the originiating Exceptions stack
* trace to be returned.
*/
public PSQLException(String error,Exception ex)
{
super();
Object[] argv = new Object[1];
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(baos);
pw.println("Exception: "+ex.toString()+"\nStack Trace:\n");
ex.printStackTrace(pw);
pw.println("End of Stack Trace");
pw.flush();
argv[0] = baos.toString();
pw.close();
baos.close();
} catch(Exception ioe) {
argv[0] = ex.toString()+"\nIO Error on stack trace generation! "+ioe.toString();
}
translate(error,argv);
}
/**
* Helper version for 2 args
*/
public PSQLException(String error,Object arg1,Object arg2)
{
super();
Object[] argv = new Object[2];
argv[0] = arg1;
argv[1] = arg2;
translate(error,argv);
}
private void translate(String error, Object[] args) {
message = MessageTranslator.translate(error,args);
/**
* This provides the same functionality to SQLException
* @param error Error string
*/
public PSQLException(String error)
{
super();
translate(error, null);
}
/**
* Overides Throwable
*/
public String getLocalizedMessage()
{
return message;
}
/**
* A more generic entry point.
* @param error Error string or standard message id
* @param args Array of arguments
*/
public PSQLException(String error, Object[] args)
{
//super();
translate(error, args);
}
/**
* Overides Throwable
*/
public String getMessage()
{
return message;
}
/**
* Helper version for 1 arg
*/
public PSQLException(String error, Object arg)
{
super();
Object[] argv = new Object[1];
argv[0] = arg;
translate(error, argv);
}
/**
* Overides Object
*/
public String toString()
{
return message;
}
/**
* Helper version for 1 arg. This is used for debug purposes only with
* some unusual Exception's. It allows the originiating Exceptions stack
* trace to be returned.
*/
public PSQLException(String error, Exception ex)
{
super();
Object[] argv = new Object[1];
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(baos);
pw.println("Exception: " + ex.toString() + "\nStack Trace:\n");
ex.printStackTrace(pw);
pw.println("End of Stack Trace");
pw.flush();
argv[0] = baos.toString();
pw.close();
baos.close();
}
catch (Exception ioe)
{
argv[0] = ex.toString() + "\nIO Error on stack trace generation! " + ioe.toString();
}
translate(error, argv);
}
/**
* Helper version for 2 args
*/
public PSQLException(String error, Object arg1, Object arg2)
{
super();
Object[] argv = new Object[2];
argv[0] = arg1;
argv[1] = arg2;
translate(error, argv);
}
private void translate(String error, Object[] args)
{
message = MessageTranslator.translate(error, args);
}
/**
* Overides Throwable
*/
public String getLocalizedMessage()
{
return message;
}
/**
* Overides Throwable
*/
public String getMessage()
{
return message;
}
/**
* Overides Object
*/
public String toString()
{
return message;
}
}

View File

@ -19,11 +19,11 @@ import java.sql.*;
* a table to be used as a data type. However, Postgres support of
* this feature is incomplete. The basic ability to create and use
* a table as a field type in another table exists:<br>
* CREATE TABLE myclass( var1 TEXT, var2 INTEGER );<br>
* CREATE TABLE othertable( field1 TEXT, field2 myclass );<br>
* INSERT INTO myclass VALUES ('Hello', 1);<br>
* INSERT INTO othertable VALUES ('World', xxxx::myclass);<br>
* where xxxx is the OID of a row in myclass<br>
* CREATE TABLE myclass( var1 TEXT, var2 INTEGER );<br>
* CREATE TABLE othertable( field1 TEXT, field2 myclass );<br>
* INSERT INTO myclass VALUES ('Hello', 1);<br>
* INSERT INTO othertable VALUES ('World', xxxx::myclass);<br>
* where xxxx is the OID of a row in myclass<br>
* This lets othertable reference a myclass instance but
* the support to actually make any use of the myclass data type
* is not there. For instance, you cannot compare the myclass field
@ -33,13 +33,13 @@ import java.sql.*;
* syntax appears to work.<p>
*
* Queries like:<br>
* SELECT othertable.field2.var1 FROM othertable;<br>
* SELECT othertable.field2.var1 FROM othertable;<br>
* will not work but were suggested in the original Postgres
* design documents.<p>
* Because support is incomplete for table data types, tables
* such as othertable that hold java instances should also
* hold an oid field for the same java instance:<br>
* CREATE othertable( field1 TEXT, field2 myclass, myclassOID oid);<br>
* CREATE othertable( field1 TEXT, field2 myclass, myclassOID oid);<br>
* This oid-type field would be set with setInt() immediately after
* setting the myclass-type field with setObject(). The order of these
* set calls matters since the oid is not available until after
@ -107,230 +107,271 @@ import java.sql.*;
*/
public class Serialize
{
// This is the connection that the instance refers to
protected org.postgresql.Connection conn;
// This is the connection that the instance refers to
protected org.postgresql.Connection conn;
// This is the table name
protected String tableName;
// This is the table name
protected String tableName;
// This is the class name
protected String className;
// This is the class name
protected String className;
// This is the Class for this serialzed object
protected Class ourClass;
// This is the Class for this serialzed object
protected Class ourClass;
/**
* This creates an instance that can be used to serialize or deserialize
* a Java object from a PostgreSQL table.
*/
public Serialize(org.postgresql.Connection c,String type) throws SQLException
{
try {
conn = c;
DriverManager.println("Serialize: initializing instance for type: " + type);
tableName = toPostgreSQL(type);
className = type;
ourClass = Class.forName(className);
} catch(ClassNotFoundException cnfe) {
DriverManager.println("Serialize: " + className + " java class not found");
throw new PSQLException("postgresql.serial.noclass",type);
}
// Second check, the type must be a table
boolean status = false;
ResultSet rs = conn.ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='" + tableName + "'");
if(rs!=null) {
if(rs.next()) {
status = true;
DriverManager.println("Serialize: " + tableName + " table found");
/**
* This creates an instance that can be used to serialize or deserialize
* a Java object from a PostgreSQL table.
*/
public Serialize(org.postgresql.Connection c, String type) throws SQLException
{
try
{
conn = c;
DriverManager.println("Serialize: initializing instance for type: " + type);
tableName = toPostgreSQL(type);
className = type;
ourClass = Class.forName(className);
}
rs.close();
catch (ClassNotFoundException cnfe)
{
DriverManager.println("Serialize: " + className + " java class not found");
throw new PSQLException("postgresql.serial.noclass", type);
}
// Second check, the type must be a table
boolean status = false;
ResultSet rs = conn.ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='" + tableName + "'");
if (rs != null)
{
if (rs.next())
{
status = true;
DriverManager.println("Serialize: " + tableName + " table found");
}
rs.close();
}
// This should never occur, as org.postgresql has it's own internal checks
if (!status)
{
DriverManager.println("Serialize: " + tableName + " table not found");
throw new PSQLException("postgresql.serial.table", type);
}
// Finally cache the fields within the table
}
// This should never occur, as org.postgresql has it's own internal checks
if(!status) {
DriverManager.println("Serialize: " + tableName + " table not found");
throw new PSQLException("postgresql.serial.table",type);
/**
* Constructor when Object is passed in
*/
public Serialize(org.postgresql.Connection c, Object o) throws SQLException
{
this(c, o.getClass().getName());
}
// Finally cache the fields within the table
}
/**
* Constructor when Object is passed in
*/
public Serialize(org.postgresql.Connection c,Object o) throws SQLException
{
this(c, o.getClass().getName());
}
/**
* Constructor when Class is passed in
*/
public Serialize(org.postgresql.Connection c, Class cls) throws SQLException
{
this(c, cls.getName());
}
/**
* Constructor when Class is passed in
*/
public Serialize(org.postgresql.Connection c, Class cls) throws SQLException
{
this(c, cls.getName());
}
/**
* This fetches an object from a table, given it's OID
* @param oid The oid of the object
* @return Object relating to oid
* @exception SQLException on error
*/
/**
* This fetches an object from a table, given it's OID
* @param oid The oid of the object
* @return Object relating to oid
* @exception SQLException on error
*/
public Object fetch(int oid) throws SQLException
{
try {
try
{
DriverManager.println("Serialize.fetch: " + "attempting to instantiate object of type: " + ourClass.getName() );
Object obj = ourClass.newInstance();
Object obj = ourClass.newInstance();
DriverManager.println("Serialize.fetch: " + "instantiated object of type: " + ourClass.getName() );
// NB: we use java.lang.reflect here to prevent confusion with
// the org.postgresql.Field
// NB: we use java.lang.reflect here to prevent confusion with
// the org.postgresql.Field
// used getFields to get only public fields. We have no way to set values
// for other declarations. Maybe look for setFieldName() methods?
java.lang.reflect.Field f[] = ourClass.getFields();
boolean hasOID=false;
int oidFIELD=-1;
// used getFields to get only public fields. We have no way to set values
// for other declarations. Maybe look for setFieldName() methods?
java.lang.reflect.Field f[] = ourClass.getFields();
boolean hasOID = false;
int oidFIELD = -1;
StringBuffer sb = new StringBuffer("select");
char sep=' ';
// build a select for the fields. Look for the oid field to use in the where
for(int i=0;i<f.length;i++) {
StringBuffer sb = new StringBuffer("select");
char sep = ' ';
// build a select for the fields. Look for the oid field to use in the where
for (int i = 0;i < f.length;i++)
{
String n = f[i].getName();
if(n.equals("oid")) {
hasOID=true;
oidFIELD=i;
if (n.equals("oid"))
{
hasOID = true;
oidFIELD = i;
}
sb.append(sep);
sb.append(n);
sep=',';
}
sb.append(" from ");
sb.append(tableName);
sb.append(" where oid=");
sb.append(oid);
sep = ',';
}
sb.append(" from ");
sb.append(tableName);
sb.append(" where oid=");
sb.append(oid);
DriverManager.println("Serialize.fetch: " + sb.toString());
ResultSet rs = conn.ExecSQL(sb.toString());
DriverManager.println("Serialize.fetch: " + sb.toString());
ResultSet rs = conn.ExecSQL(sb.toString());
if(rs!=null) {
if(rs.next()) {
for(int i=0;i<f.length;i++) {
if( !Modifier.isFinal(f[i].getModifiers()) ) {
if( f[i].getType().getName().equals("short") )
f[i].setShort(obj, rs.getShort(i+1));
else if( f[i].getType().getName().equals("char") )
f[i].setChar(obj, rs.getString(i+1).toCharArray()[0]);
else if( f[i].getType().getName().equals("byte"))
f[i].setByte(obj, rs.getByte(i+1));
else if( f[i].getType().getName().equals("boolean") ) {
if (rs != null)
{
if (rs.next())
{
for (int i = 0;i < f.length;i++)
{
if ( !Modifier.isFinal(f[i].getModifiers()) )
{
if ( f[i].getType().getName().equals("short") )
f[i].setShort(obj, rs.getShort(i + 1));
else if ( f[i].getType().getName().equals("char") )
f[i].setChar(obj, rs.getString(i + 1).toCharArray()[0]);
else if ( f[i].getType().getName().equals("byte"))
f[i].setByte(obj, rs.getByte(i + 1));
else if ( f[i].getType().getName().equals("boolean") )
{
// booleans come out of pgsql as a t or an f
if( rs.getString(i+1).equals("t") ) f[i].setBoolean(obj, true);
else f[i].setBoolean(obj, false);
} else f[i].set(obj,rs.getObject(i+1));
if ( rs.getString(i + 1).equals("t") )
f[i].setBoolean(obj, true);
else
f[i].setBoolean(obj, false);
}
else
f[i].set(obj, rs.getObject(i + 1));
}
}
}
rs.close();
} else throw new PSQLException("postgresql.unexpected");
}
else
throw new PSQLException("postgresql.unexpected");
return obj;
return obj;
} catch(IllegalAccessException iae) {
}
catch (IllegalAccessException iae)
{
throw new SQLException(iae.toString());
} catch(InstantiationException ie) {
}
catch (InstantiationException ie)
{
throw new SQLException(ie.toString());
}
}
/**
* This stores an object into a table, returning it's OID.<p>
*
* If the object has an int called OID, and it is > 0, then
* that value is used for the OID, and the table will be updated.
* If the value of OID is 0, then a new row will be created, and the
* value of OID will be set in the object. This enables an object's
* value in the database to be updateable.
*
* If the object has no int called OID, then the object is stored. However
* if the object is later retrieved, amended and stored again, it's new
* state will be appended to the table, and will not overwrite the old
* entries.
*
* @param o Object to store (must implement Serializable)
* @return oid of stored object
* @exception SQLException on error
*/
/**
* This stores an object into a table, returning it's OID.<p>
*
* If the object has an int called OID, and it is > 0, then
* that value is used for the OID, and the table will be updated.
* If the value of OID is 0, then a new row will be created, and the
* value of OID will be set in the object. This enables an object's
* value in the database to be updateable.
*
* If the object has no int called OID, then the object is stored. However
* if the object is later retrieved, amended and stored again, it's new
* state will be appended to the table, and will not overwrite the old
* entries.
*
* @param o Object to store (must implement Serializable)
* @return oid of stored object
* @exception SQLException on error
*/
public int store(Object o) throws SQLException
{
try {
// NB: we use java.lang.reflect here to prevent confusion with
try
{
// NB: we use java.lang.reflect here to prevent confusion with
// the org.postgresql.Field
// don't save private fields since we would not be able to fetch them
java.lang.reflect.Field f[] = ourClass.getFields();
boolean hasOID=false;
int oidFIELD=-1;
boolean update=false;
boolean hasOID = false;
int oidFIELD = -1;
boolean update = false;
// Find out if we have an oid value
for(int i=0;i<f.length;i++) {
for (int i = 0;i < f.length;i++)
{
String n = f[i].getName();
if(n.equals("oid")) {
hasOID=true;
oidFIELD=i;
if (n.equals("oid"))
{
hasOID = true;
oidFIELD = i;
// Do update if oid != 0
update = f[i].getInt(o) > 0;
}
}
StringBuffer sb = new StringBuffer(update?"update "+tableName+" set":"insert into "+tableName+" ");
char sep=update?' ':'(';
for(int i=0;i<f.length;i++) {
StringBuffer sb = new StringBuffer(update ? "update " + tableName + " set" : "insert into " + tableName + " ");
char sep = update ? ' ' : '(';
for (int i = 0;i < f.length;i++)
{
String n = f[i].getName();
// oid cannot be updated!
if( n.equals("oid") ) continue;
if ( n.equals("oid") )
continue;
sb.append(sep);
sep=',';
sep = ',';
sb.append(n);
if(update) {
if (update)
{
sb.append('=');
// handle unset values
if (f[i].get(o) == null)
sb.append("null");
else if(
f[i].getType().getName().equals("java.lang.String")
|| f[i].getType().getName().equals("char") ) {
else if (
f[i].getType().getName().equals("java.lang.String")
|| f[i].getType().getName().equals("char") )
{
sb.append('\'');
// don't allow single qoutes or newlines in the string
sb.append(fixString(f[i].get(o).toString()));
sb.append('\'');
} else sb.append(f[i].get(o).toString());
}
else
sb.append(f[i].get(o).toString());
}
}
if(update) sb.append(" where oid = " + f[oidFIELD].getInt(o) );
if (update)
sb.append(" where oid = " + f[oidFIELD].getInt(o) );
if(!update) {
if (!update)
{
sb.append(") values ");
sep='(';
for(int i=0;i<f.length;i++) {
sep = '(';
for (int i = 0;i < f.length;i++)
{
String n = f[i].getName();
// oid cannot be set!
if( n.equals("oid") ) continue;
if ( n.equals("oid") )
continue;
sb.append(sep);
sep=',';
sep = ',';
// handle unset values
if (f[i].get(o) == null) sb.append("null");
else if(
f[i].getType().getName().equals("java.lang.String")
|| f[i].getType().getName().equals("char")) {
if (f[i].get(o) == null)
sb.append("null");
else if (
f[i].getType().getName().equals("java.lang.String")
|| f[i].getType().getName().equals("char"))
{
sb.append('\'');
// don't allow single quotes or newlines in the string
sb.append(fixString(f[i].get(o).toString()));
sb.append('\'');
} else sb.append(f[i].get(o).toString());
}
else
sb.append(f[i].get(o).toString());
}
sb.append(')');
}
@ -339,23 +380,30 @@ public class Serialize
org.postgresql.ResultSet rs = (org.postgresql.ResultSet) conn.ExecSQL(sb.toString());
// fetch the OID for returning
if(update) {
if (update)
{
// object has oid already, so return it
if(rs!=null) rs.close();
if (rs != null)
rs.close();
return f[oidFIELD].getInt(o);
} else {
}
else
{
// new record inserted has new oid; rs should be not null
int newOID = ((org.postgresql.ResultSet)rs).getInsertedOID();
rs.close();
// update the java object's oid field if it has the oid field
if(hasOID) f[oidFIELD].setInt(o,newOID);
if (hasOID)
f[oidFIELD].setInt(o, newOID);
// new object stored, return newly inserted oid
return newOID;
}
} catch(IllegalAccessException iae) {
}
catch (IllegalAccessException iae)
{
throw new SQLException(iae.toString());
}
}
}
/**
@ -363,106 +411,121 @@ public class Serialize
* Otherwise, postgres will bomb on the single quote and remove the
* the backslashes.
*/
private String fixString(String s) {
private String fixString(String s)
{
int idx = -1;
// handle null
if (s == null)
return "";
if (s == null)
return "";
// if the string has single quotes in it escape them as ''
if ((idx = s.indexOf("'")) > -1) {
StringBuffer buf = new StringBuffer();
StringTokenizer tok = new StringTokenizer(s, "'");
// handle quote as 1St charater
if (idx > 0) buf.append(tok.nextToken());
// if the string has single quotes in it escape them as ''
if ((idx = s.indexOf("'")) > -1)
{
StringBuffer buf = new StringBuffer();
StringTokenizer tok = new StringTokenizer(s, "'");
// handle quote as 1St charater
if (idx > 0)
buf.append(tok.nextToken());
while(tok.hasMoreTokens())
buf.append("''").append(tok.nextToken());
while (tok.hasMoreTokens())
buf.append("''").append(tok.nextToken());
s = buf.toString();
}
s = buf.toString();
}
// if the string has backslashes in it escape them them as \\
if ((idx = s.indexOf("\\")) > -1) {
StringBuffer buf = new StringBuffer();
StringTokenizer tok = new StringTokenizer(s, "\\");
if (idx > 0) buf.append(tok.nextToken());
// if the string has backslashes in it escape them them as \\
if ((idx = s.indexOf("\\")) > -1)
{
StringBuffer buf = new StringBuffer();
StringTokenizer tok = new StringTokenizer(s, "\\");
if (idx > 0)
buf.append(tok.nextToken());
while(tok.hasMoreTokens())
buf.append("\\\\").append(tok.nextToken());
while (tok.hasMoreTokens())
buf.append("\\\\").append(tok.nextToken());
s = buf.toString();
}
s = buf.toString();
}
return s;
}
return s;
}
/**
* This method is not used by the driver, but it creates a table, given
* a Serializable Java Object. It should be used before serializing any
* objects.
* @param c Connection to database
* @param o Object to base table on
* @exception SQLException on error
*/
public static void create(org.postgresql.Connection con,Object o) throws SQLException
{
create(con,o.getClass());
}
/**
* This method is not used by the driver, but it creates a table, given
* a Serializable Java Object. It should be used before serializing any
* objects.
* @param c Connection to database
* @param o Class to base table on
* @exception SQLException on error
*/
public static void create(org.postgresql.Connection con,Class c) throws SQLException
/**
* This method is not used by the driver, but it creates a table, given
* a Serializable Java Object. It should be used before serializing any
* objects.
* @param c Connection to database
* @param o Object to base table on
* @exception SQLException on error
*/
public static void create(org.postgresql.Connection con, Object o) throws SQLException
{
if(c.isInterface()) throw new PSQLException("postgresql.serial.interface");
create(con, o.getClass());
}
/**
* This method is not used by the driver, but it creates a table, given
* a Serializable Java Object. It should be used before serializing any
* objects.
* @param c Connection to database
* @param o Class to base table on
* @exception SQLException on error
*/
public static void create(org.postgresql.Connection con, Class c) throws SQLException
{
if (c.isInterface())
throw new PSQLException("postgresql.serial.interface");
// See if the table exists
String tableName = toPostgreSQL(c.getName());
ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '"+tableName+"'");
if( rs.next() ) {
DriverManager.println("Serialize.create: table "+tableName+" exists, skipping");
ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '" + tableName + "'");
if ( rs.next() )
{
DriverManager.println("Serialize.create: table " + tableName + " exists, skipping");
rs.close();
return;
return ;
}
// else table not found, so create it
DriverManager.println("Serialize.create: table " + tableName + " not found, creating" );
// No entries returned, so the table doesn't exist
// No entries returned, so the table doesn't exist
StringBuffer sb = new StringBuffer("create table ");
sb.append(tableName);
char sep='(';
StringBuffer sb = new StringBuffer("create table ");
sb.append(tableName);
char sep = '(';
// java.lang.reflect.Field[] fields = c.getDeclaredFields();
// Only store public fields, another limitation!
java.lang.reflect.Field[] fields = c.getFields();
for(int i=0;i<fields.length;i++) {
java.lang.reflect.Field[] fields = c.getFields();
for (int i = 0;i < fields.length;i++)
{
Class type = fields[i].getType();
// oid is a special field
if(!fields[i].getName().equals("oid")) {
if (!fields[i].getName().equals("oid"))
{
sb.append(sep);
sb.append(fields[i].getName());
sb.append(' ');
sep=',';
sep = ',';
if(type.isArray()) {
if (type.isArray())
{
// array handling
} else {
}
else
{
// convert the java type to org.postgresql, recursing if a class
// is found
String n = type.getName();
int j=0;
for(;j<tp.length && !tp[j][0].equals(n);j++);
if(j<tp.length) sb.append(tp[j][1]);
else {
int j = 0;
for (;j < tp.length && !tp[j][0].equals(n);j++)
;
if (j < tp.length)
sb.append(tp[j][1]);
else
{
create(con, type);
sb.append(toPostgreSQL(n));
}
@ -476,71 +539,72 @@ public class Serialize
con.ExecSQL(sb.toString());
}
// This is used to translate between Java primitives and PostgreSQL types.
private static final String tp[][] = {
// {"boolean", "int1"},
{"boolean", "bool"},
{"double", "float8"},
{"float", "float4"},
{"int", "int4"},
// {"long", "int4"},
{"long", "int8"},
{"short", "int2"},
{"java.lang.String", "text"},
{"java.lang.Integer", "int4"},
{"java.lang.Float", "float4"},
{"java.lang.Double", "float8"},
{"java.lang.Short", "int2"},
{"char", "char"},
{"byte", "int2"}
};
// This is used to translate between Java primitives and PostgreSQL types.
private static final String tp[][] = {
// {"boolean", "int1"},
{"boolean", "bool"},
{"double", "float8"},
{"float", "float4"},
{"int", "int4"},
// {"long", "int4"},
{"long", "int8"},
{"short", "int2"},
{"java.lang.String", "text"},
{"java.lang.Integer", "int4"},
{"java.lang.Float", "float4"},
{"java.lang.Double", "float8"},
{"java.lang.Short", "int2"},
{"char", "char"},
{"byte", "int2"}
};
/**
* This converts a Java Class name to a org.postgresql table, by replacing . with
* _<p>
*
* Because of this, a Class name may not have _ in the name.<p>
* Another limitation, is that the entire class name (including packages)
* cannot be longer than 32 characters (a limit forced by PostgreSQL).
*
* @param name Class name
* @return PostgreSQL table name
* @exception SQLException on error
*/
public static String toPostgreSQL(String name) throws SQLException
{
name = name.toLowerCase();
/**
* This converts a Java Class name to a org.postgresql table, by replacing . with
* _<p>
*
* Because of this, a Class name may not have _ in the name.<p>
* Another limitation, is that the entire class name (including packages)
* cannot be longer than 32 characters (a limit forced by PostgreSQL).
*
* @param name Class name
* @return PostgreSQL table name
* @exception SQLException on error
*/
public static String toPostgreSQL(String name) throws SQLException
{
name = name.toLowerCase();
if(name.indexOf("_")>-1)
throw new PSQLException("postgresql.serial.underscore");
if (name.indexOf("_") > -1)
throw new PSQLException("postgresql.serial.underscore");
// Postgres table names can only be 32 character long.
// Reserve 1 char, so allow only up to 31 chars.
// If the full class name with package is too long
// then just use the class name. If the class name is
// too long throw an exception.
//
if( name.length() > 31 ) {
name = name.substring(name.lastIndexOf(".") + 1);
if( name.length() >31 )
throw new PSQLException("postgresql.serial.namelength",name,new Integer(name.length()));
}
return name.replace('.','_');
}
// Postgres table names can only be 32 character long.
// Reserve 1 char, so allow only up to 31 chars.
// If the full class name with package is too long
// then just use the class name. If the class name is
// too long throw an exception.
//
if ( name.length() > 31 )
{
name = name.substring(name.lastIndexOf(".") + 1);
if ( name.length() > 31 )
throw new PSQLException("postgresql.serial.namelength", name, new Integer(name.length()));
}
return name.replace('.', '_');
}
/**
* This converts a org.postgresql table to a Java Class name, by replacing _ with
* .<p>
*
* @param name PostgreSQL table name
* @return Class name
* @exception SQLException on error
*/
public static String toClassName(String name) throws SQLException
{
name = name.toLowerCase();
return name.replace('_','.');
}
/**
* This converts a org.postgresql table to a Java Class name, by replacing _ with
* .<p>
*
* @param name PostgreSQL table name
* @return Class name
* @exception SQLException on error
*/
public static String toClassName(String name) throws SQLException
{
name = name.toLowerCase();
return name.replace('_', '.');
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +1,47 @@
/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: ClientConnection.java,v 1.1 2000/04/17 20:07:55 peter Exp $
*/
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: ClientConnection.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/
package org.postgresql.xa;
@ -68,425 +68,497 @@ import java.sql.*;
* @see Connection
*/
final class ClientConnection
implements Connection
implements Connection
{
/**
* The pooled XA connection that created this client connection
* and should be used to report closure and fatal errors.
*/
private XAConnectionImpl _xaConn;
/**
* The pooled XA connection that created this client connection
* and should be used to report closure and fatal errors.
*/
private XAConnectionImpl _xaConn;
/**
* This identifier was handed on to use when we were created by
* {@link XAConnection}. If since then the XA connection was asked
* to create another connection or was closed, our identifier will
* no longer be valid and any call to {@link
* XAConnection#getUnderlying} will throw an exception. Previously,
* the XA connection would hold a reference to use and tell us to
* terminate, but that prevented ClientConnection from being
* finalized.
*/
private int _clientId;
/**
* This identifier was handed on to use when we were created by
* {@link XAConnection}. If since then the XA connection was asked
* to create another connection or was closed, our identifier will
* no longer be valid and any call to {@link
* XAConnection#getUnderlying} will throw an exception. Previously,
* the XA connection would hold a reference to use and tell us to
* terminate, but that prevented ClientConnection from being
* finalized.
*/
private int _clientId;
/**
* Construct a new client connection to provide access to the
* underlying JDBC connection (<tt>underlying</tt>) on behalf of
* an XA/pooled connection (<tt>xaConn<tt/>). The pooled connection
* is required to notify of connection closure and fatal errors.
*
* @param xaConn The XA/pooled connection that created this
* client connection
* @param clientId A unique identifier handed to us by
* {@link XAConnection}
* @param underlying The underlying JDBC connection
*/
ClientConnection( XAConnectionImpl xaConn, int clientId )
{
_xaConn = xaConn;
_clientId = clientId;
}
public Statement createStatement()
throws SQLException
{
try {
return getUnderlying().createStatement();
} catch ( SQLException except ) {
notifyError( except );
throw except;
/**
* Construct a new client connection to provide access to the
* underlying JDBC connection (<tt>underlying</tt>) on behalf of
* an XA/pooled connection (<tt>xaConn<tt/>). The pooled connection
* is required to notify of connection closure and fatal errors.
*
* @param xaConn The XA/pooled connection that created this
* client connection
* @param clientId A unique identifier handed to us by
* {@link XAConnection}
* @param underlying The underlying JDBC connection
*/
ClientConnection( XAConnectionImpl xaConn, int clientId )
{
_xaConn = xaConn;
_clientId = clientId;
}
}
public Statement createStatement( int resultSetType, int resultSetConcurrency )
throws SQLException
{
try {
return getUnderlying().createStatement( resultSetType, resultSetConcurrency );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public PreparedStatement prepareStatement( String sql )
throws SQLException
{
try {
return getUnderlying().prepareStatement( sql );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public PreparedStatement prepareStatement( String sql, int resultSetType, int resultSetConcurrency )
throws SQLException
{
try {
return getUnderlying().prepareStatement( sql, resultSetType, resultSetConcurrency );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public CallableStatement prepareCall( String sql )
throws SQLException
{
try {
return getUnderlying().prepareCall( sql );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public CallableStatement prepareCall( String sql, int resultSetType, int resultSetConcurrency )
throws SQLException
{
try {
return getUnderlying().prepareCall( sql, resultSetType, resultSetConcurrency );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public String nativeSQL( String sql )
throws SQLException
{
try {
return getUnderlying().nativeSQL( sql );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public DatabaseMetaData getMetaData()
throws SQLException
{
try {
return getUnderlying().getMetaData();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void setCatalog( String catalog )
throws SQLException
{
try {
getUnderlying().setCatalog( catalog );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public String getCatalog()
throws SQLException
{
try {
return getUnderlying().getCatalog();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public SQLWarning getWarnings()
throws SQLException
{
try {
return getUnderlying().getWarnings();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void clearWarnings()
throws SQLException
{
try {
getUnderlying().clearWarnings();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public Map getTypeMap()
throws SQLException
{
try {
return getUnderlying().getTypeMap();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void setTypeMap( Map map )
throws SQLException
{
try {
getUnderlying().setTypeMap( map );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void setAutoCommit( boolean autoCommit )
throws SQLException
{
// Cannot set auto-commit inside a transaction.
if ( _xaConn.insideGlobalTx() )
throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" );
try {
getUnderlying().setAutoCommit( autoCommit );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public boolean getAutoCommit()
throws SQLException
{
try {
return getUnderlying().getAutoCommit();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void commit()
throws SQLException
{
// Cannot commit directly if we're inside a global transaction.
if ( _xaConn.insideGlobalTx() )
throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" );
// Cannot commit a read-only transaction.
if ( isReadOnly() )
throw new SQLException( "Cannot commit/rollback a read-only transaction" );
// This only occurs if not inside a local transaction.
try {
getUnderlying().commit();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void rollback()
throws SQLException
{
// Cannot commit directly if we're inside a global transaction.
if ( _xaConn.insideGlobalTx() )
throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" );
// This only occurs if not inside a local transaction.
try {
getUnderlying().rollback();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void setReadOnly( boolean readOnly )
throws SQLException
{
try {
getUnderlying().setReadOnly( readOnly );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public boolean isReadOnly()
throws SQLException
{
try {
return getUnderlying().isReadOnly();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public void setTransactionIsolation( int level )
throws SQLException
{
try {
getUnderlying().setTransactionIsolation( level );
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public int getTransactionIsolation()
throws SQLException
{
try {
return getUnderlying().getTransactionIsolation();
} catch ( SQLException except ) {
notifyError( except );
throw except;
}
}
public synchronized void close()
public Statement createStatement()
throws SQLException
{
if ( _xaConn == null )
return;
{
try
{
return getUnderlying().createStatement();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
// Notify the XA connection that we are no longer going
// to be used. Whether the underlying connection is released,
// held until the transaction terminates, etc is not
// a concern of us.
_xaConn.notifyClose( _clientId );
public Statement createStatement( int resultSetType, int resultSetConcurrency )
throws SQLException
{
try
{
return getUnderlying().createStatement( resultSetType, resultSetConcurrency );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public PreparedStatement prepareStatement( String sql )
throws SQLException
{
try
{
return getUnderlying().prepareStatement( sql );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public PreparedStatement prepareStatement( String sql, int resultSetType, int resultSetConcurrency )
throws SQLException
{
try
{
return getUnderlying().prepareStatement( sql, resultSetType, resultSetConcurrency );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public CallableStatement prepareCall( String sql )
throws SQLException
{
try
{
return getUnderlying().prepareCall( sql );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public CallableStatement prepareCall( String sql, int resultSetType, int resultSetConcurrency )
throws SQLException
{
try
{
return getUnderlying().prepareCall( sql, resultSetType, resultSetConcurrency );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public String nativeSQL( String sql )
throws SQLException
{
try
{
return getUnderlying().nativeSQL( sql );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public DatabaseMetaData getMetaData()
throws SQLException
{
try
{
return getUnderlying().getMetaData();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void setCatalog( String catalog )
throws SQLException
{
try
{
getUnderlying().setCatalog( catalog );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public String getCatalog()
throws SQLException
{
try
{
return getUnderlying().getCatalog();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public SQLWarning getWarnings()
throws SQLException
{
try
{
return getUnderlying().getWarnings();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void clearWarnings()
throws SQLException
{
try
{
getUnderlying().clearWarnings();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public Map getTypeMap()
throws SQLException
{
try
{
return getUnderlying().getTypeMap();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void setTypeMap( Map map )
throws SQLException
{
try
{
getUnderlying().setTypeMap( map );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void setAutoCommit( boolean autoCommit )
throws SQLException
{
// Cannot set auto-commit inside a transaction.
if ( _xaConn.insideGlobalTx() )
throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" );
try
{
getUnderlying().setAutoCommit( autoCommit );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public boolean getAutoCommit()
throws SQLException
{
try
{
return getUnderlying().getAutoCommit();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void commit()
throws SQLException
{
// Cannot commit directly if we're inside a global transaction.
if ( _xaConn.insideGlobalTx() )
throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" );
// Cannot commit a read-only transaction.
if ( isReadOnly() )
throw new SQLException( "Cannot commit/rollback a read-only transaction" );
// This only occurs if not inside a local transaction.
try
{
getUnderlying().commit();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void rollback()
throws SQLException
{
// Cannot commit directly if we're inside a global transaction.
if ( _xaConn.insideGlobalTx() )
throw new SQLException( "Cannot commit/rollback a connection managed by the transaction manager" );
// This only occurs if not inside a local transaction.
try
{
getUnderlying().rollback();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void setReadOnly( boolean readOnly )
throws SQLException
{
try
{
getUnderlying().setReadOnly( readOnly );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public boolean isReadOnly()
throws SQLException
{
try
{
return getUnderlying().isReadOnly();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public void setTransactionIsolation( int level )
throws SQLException
{
try
{
getUnderlying().setTransactionIsolation( level );
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public int getTransactionIsolation()
throws SQLException
{
try
{
return getUnderlying().getTransactionIsolation();
}
catch ( SQLException except )
{
notifyError( except );
throw except;
}
}
public synchronized void close()
throws SQLException
{
if ( _xaConn == null )
return ;
// Notify the XA connection that we are no longer going
// to be used. Whether the underlying connection is released,
// held until the transaction terminates, etc is not
// a concern of us.
_xaConn.notifyClose( _clientId );
_xaConn = null;
}
public synchronized boolean isClosed()
{
// Simple way of determining if this connection is closed.
// The actual connection is never closed, it is pooled.
return ( _xaConn == null );
}
/**
* Called by {@link XAConnectionImpl} to terminate this connection
* by dissociating it from the underlying JDBC connection.
* The application would call {@link #close} but {@link
* XAConnectionImpl} cannot, since pooled connection requirements
* will cause an inifinite loop. This method should not attempt
* to notify either a closure or fatal error, but rather throw an
* exception if it fails.
*/
/* Deprecated: see XAConnection._clientId
void terminate()
{
_xaConn = null;
}
}
*/
public synchronized boolean isClosed()
{
// Simple way of determining if this connection is closed.
// The actual connection is never closed, it is pooled.
return ( _xaConn == null );
}
/**
* Called by {@link XAConnectionImpl} to terminate this connection
* by dissociating it from the underlying JDBC connection.
* The application would call {@link #close} but {@link
* XAConnectionImpl} cannot, since pooled connection requirements
* will cause an inifinite loop. This method should not attempt
* to notify either a closure or fatal error, but rather throw an
* exception if it fails.
*/
/* Deprecated: see XAConnection._clientId
void terminate()
{
_xaConn = null;
}
*/
protected void finalize()
protected void finalize()
throws Throwable
{
close();
}
public String toString()
{
try {
return getUnderlying().toString();
} catch ( SQLException except ) {
return "XAConnection: Connection closed";
{
close();
}
}
/**
* Called when an exception is thrown by the underlying connection
* to determine whether the exception is critical or not. If the
* exception is critical, notifies the XA connection to forget
* about this connection.
*
* @param except The exception thrown by the underlying
* connection
*/
void notifyError( SQLException except )
{
if ( _xaConn != null )
_xaConn.notifyError( _clientId, except );
}
/**
* Called to retrieve the underlying JDBC connection. Actual JDBC
* operations are performed against it. Throws an SQLException if
* this connection has been closed.
*/
Connection getUnderlying()
throws SQLException
{
if ( _xaConn == null )
throw new SQLException( "This connection has been closed" );
// Must pass the client identifier so XAConnection can determine
// whether we are still valid. If it tells us we're no longer
// valid, we have little to do.
try {
return _xaConn.getUnderlying( _clientId );
} catch ( SQLException except ) {
_xaConn = null;
throw except;
public String toString()
{
try
{
return getUnderlying().toString();
}
catch ( SQLException except )
{
return "XAConnection: Connection closed";
}
}
/**
* Called when an exception is thrown by the underlying connection
* to determine whether the exception is critical or not. If the
* exception is critical, notifies the XA connection to forget
* about this connection.
*
* @param except The exception thrown by the underlying
* connection
*/
void notifyError( SQLException except )
{
if ( _xaConn != null )
_xaConn.notifyError( _clientId, except );
}
/**
* Called to retrieve the underlying JDBC connection. Actual JDBC
* operations are performed against it. Throws an SQLException if
* this connection has been closed.
*/
Connection getUnderlying()
throws SQLException
{
if ( _xaConn == null )
throw new SQLException( "This connection has been closed" );
// Must pass the client identifier so XAConnection can determine
// whether we are still valid. If it tells us we're no longer
// valid, we have little to do.
try
{
return _xaConn.getUnderlying( _clientId );
}
catch ( SQLException except )
{
_xaConn = null;
throw except;
}
}
}
}

View File

@ -1,47 +1,47 @@
/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: TwoPhaseConnection.java,v 1.1 2000/04/17 20:07:55 peter Exp $
*/
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: TwoPhaseConnection.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/
package org.postgresql.xa;
@ -79,38 +79,38 @@ public interface TwoPhaseConnection
{
/**
* Enables or disables transaction demarcation through SQL commit
* and rollback. When the connection falls under control of
* {@link XAConnection}, SQL commit/rollback commands will be
* disabled to prevent direct transaction demarcation.
*
* @param flag True to enable SQL transactions (the default)
*/
public void enableSQLTransactions( boolean flag );
/**
* Enables or disables transaction demarcation through SQL commit
* and rollback. When the connection falls under control of
* {@link XAConnection}, SQL commit/rollback commands will be
* disabled to prevent direct transaction demarcation.
*
* @param flag True to enable SQL transactions (the default)
*/
public void enableSQLTransactions( boolean flag );
/**
* Called to prepare the transaction for commit. Returns true if
* the transaction is prepared, false if the transaction is
* read-only. If the transaction has been marked for rollback,
* throws a {@link RollbackException}.
*
* @return True if can commit, false if read-only
* @throws SQLException If transaction has been marked for
* rollback or cannot commit for any other reason
*/
public boolean prepare()
/**
* Called to prepare the transaction for commit. Returns true if
* the transaction is prepared, false if the transaction is
* read-only. If the transaction has been marked for rollback,
* throws a {@link RollbackException}.
*
* @return True if can commit, false if read-only
* @throws SQLException If transaction has been marked for
* rollback or cannot commit for any other reason
*/
public boolean prepare()
throws SQLException;
/**
* Returns true if the error issued by this connection is a
* critical error and the connection should be terminated.
*
* @param except The exception thrown by this connection
*/
public boolean isCriticalError( SQLException except );
/**
* Returns true if the error issued by this connection is a
* critical error and the connection should be terminated.
*
* @param except The exception thrown by this connection
*/
public boolean isCriticalError( SQLException except );
}

View File

@ -1,47 +1,47 @@
/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: TxConnection.java,v 1.1 2000/04/17 20:07:56 peter Exp $
*/
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: TxConnection.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/
package org.postgresql.xa;
@ -66,64 +66,64 @@ import javax.transaction.xa.Xid;
*/
final class TxConnection
{
/**
* The Xid of the transactions. Connections that are not
* associated with a transaction are not represented here.
*/
Xid xid;
/**
* Holds the underlying JDBC connection for as long as this
* connection is useable. If the connection has been rolled back,
* timed out or had any other error, this variable will null
* and the connection is considered failed.
*/
Connection conn;
/**
* Indicates the clock time (in ms) when the transaction should
* time out. The transaction times out when
* <tt>System.currentTimeMillis() > timeout</tt>.
*/
long timeout;
/**
* Indicates the clock time (in ms) when the transaction started.
*/
long started;
/**
* Reference counter indicates how many XA connections share this
* underlying connection and transaction. Always one or more.
*/
int count;
/**
* True if the transaction has failed due to time out.
*/
boolean timedOut;
/**
* The Xid of the transactions. Connections that are not
* associated with a transaction are not represented here.
*/
Xid xid;
/**
* True if the transaction has already been prepared.
*/
boolean prepared;
/**
* Holds the underlying JDBC connection for as long as this
* connection is useable. If the connection has been rolled back,
* timed out or had any other error, this variable will null
* and the connection is considered failed.
*/
Connection conn;
/**
* Indicates the clock time (in ms) when the transaction should
* time out. The transaction times out when
* <tt>System.currentTimeMillis() > timeout</tt>.
*/
long timeout;
/**
* Indicates the clock time (in ms) when the transaction started.
*/
long started;
/**
* Reference counter indicates how many XA connections share this
* underlying connection and transaction. Always one or more.
*/
int count;
/**
* True if the transaction has failed due to time out.
*/
boolean timedOut;
/**
* True if the transaction has already been prepared.
*/
boolean prepared;
/**
* True if the transaction has been prepared and found out to be
* read-only. Read-only transactions do not require commit/rollback.
*/
boolean readOnly;
/**
* True if the transaction has been prepared and found out to be
* read-only. Read-only transactions do not require commit/rollback.
*/
boolean readOnly;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +1,47 @@
/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: XADataSourceImpl.java,v 1.1 2000/04/17 20:07:56 peter Exp $
*/
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: XADataSourceImpl.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/
package org.postgresql.xa;
@ -77,383 +77,412 @@ import javax.transaction.xa.Xid;
* @version 1.0
*/
public abstract class XADataSourceImpl
implements DataSource, ConnectionPoolDataSource,
XADataSource, Serializable, Runnable
implements DataSource, ConnectionPoolDataSource,
XADataSource, Serializable, Runnable
{
/**
* Maps underlying JDBC connections into global transaction Xids.
*/
private transient Hashtable _txConnections = new Hashtable();
/**
* Maps underlying JDBC connections into global transaction Xids.
*/
private transient Hashtable _txConnections = new Hashtable();
/**
* This is a pool of free underlying JDBC connections. If two
* XA connections are used in the same transaction, the second
* one will make its underlying JDBC connection available to
* the pool. This is not a real connection pool, only a marginal
* efficiency solution for dealing with shared transactions.
*/
private transient Stack _pool = new Stack();
/**
* This is a pool of free underlying JDBC connections. If two
* XA connections are used in the same transaction, the second
* one will make its underlying JDBC connection available to
* the pool. This is not a real connection pool, only a marginal
* efficiency solution for dealing with shared transactions.
*/
private transient Stack _pool = new Stack();
/**
* A background deamon thread terminating connections that have
* timed out.
*/
private transient Thread _background;
/**
* A background deamon thread terminating connections that have
* timed out.
*/
private transient Thread _background;
/**
* The default timeout for all new transactions.
*/
private int _txTimeout = DEFAULT_TX_TIMEOUT;
/**
* The default timeout for all new transactions.
*/
private int _txTimeout = DEFAULT_TX_TIMEOUT;
/**
* The default timeout for all new transactions is 10 seconds.
*/
public final static int DEFAULT_TX_TIMEOUT = 10;
/**
* The default timeout for all new transactions is 10 seconds.
*/
public final static int DEFAULT_TX_TIMEOUT = 10;
/**
* Implementation details:
* If two XAConnections are associated with the same transaction
* (one with a start the other with a join) they must use the
* same underlying JDBC connection. They lookup the underlying
* JDBC connection based on the transaction's Xid in the
* originating XADataSource.
*
* Currently the XADataSource must be the exact same object,
* this should be changed so all XADataSources that are equal
* share a table of all enlisted connections
*
* To test is two connections should fall under the same
* transaction we match the resource managers by comparing the
* database/user they fall under using a comparison of the
* XADataSource properties.
*/
/**
* Implementation details:
* If two XAConnections are associated with the same transaction
* (one with a start the other with a join) they must use the
* same underlying JDBC connection. They lookup the underlying
* JDBC connection based on the transaction's Xid in the
* originating XADataSource.
*
* Currently the XADataSource must be the exact same object,
* this should be changed so all XADataSources that are equal
* share a table of all enlisted connections
*
* To test is two connections should fall under the same
* transaction we match the resource managers by comparing the
* database/user they fall under using a comparison of the
* XADataSource properties.
*/
public XADataSourceImpl()
{
super();
public XADataSourceImpl()
{
super();
// Create a background thread that will track transactions
// that timeout, abort them and release the underlying
// connections to the pool.
_background = new Thread( this, "XADataSource Timeout Daemon" );
_background.setPriority( Thread.MIN_PRIORITY );
_background.setDaemon( true );
_background.start();
}
// Create a background thread that will track transactions
// that timeout, abort them and release the underlying
// connections to the pool.
_background = new Thread( this, "XADataSource Timeout Daemon" );
_background.setPriority( Thread.MIN_PRIORITY );
_background.setDaemon( true );
_background.start();
}
public XAConnection getXAConnection()
throws SQLException
{
// Construct a new XAConnection with no underlying connection.
// When a JDBC method requires an underlying connection, one
// will be created. We don't create the underlying connection
// beforehand, as it might be coming from an existing
// transaction.
return new XAConnectionImpl( this, null );
}
public XAConnection getXAConnection( String user, String password )
throws SQLException
{
// Since we create the connection on-demand with newConnection
// or obtain it from a transaction, we cannot support XA
// connections with a caller specified user name.
throw new SQLException( "XAConnection does not support connections with caller specified user name" );
}
public PooledConnection getPooledConnection()
throws SQLException
{
// Construct a new pooled connection and an underlying JDBC
// connection to go along with it.
return new XAConnectionImpl( this, getConnection() );
}
public PooledConnection getPooledConnection( String user, String password )
throws SQLException
{
// Construct a new pooled connection and an underlying JDBC
// connection to go along with it.
return new XAConnectionImpl( this, getConnection( user, password ) );
}
/**
* Returns the default timeout for all transactions.
*/
public int getTransactionTimeout()
{
return _txTimeout;
}
/**
* This method is defined in the interface and implemented in the
* derived class, we re-define it just to make sure it does not
* throw an {@link SQLException} and that we do not need to
* catch one.
*/
public abstract java.io.PrintWriter getLogWriter();
/**
* Sets the default timeout for all transactions. The timeout is
* specified in seconds. Use zero for the default timeout. Calling
* this method does not affect transactions in progress.
*
* @param seconds The timeout in seconds
*/
public void setTransactionTimeout( int seconds )
{
if ( seconds <= 0 )
_txTimeout = DEFAULT_TX_TIMEOUT;
else
_txTimeout = seconds;
_background.interrupt();
}
/**
* Returns an underlying connection for the global transaction,
* if one has been associated before.
*
* @param xid The transaction Xid
* @return A connection associated with that transaction, or null
*/
TxConnection getTxConnection( Xid xid )
{
return (TxConnection) _txConnections.get( xid );
}
/**
* Associates the global transaction with an underlying connection,
* or dissociate it when null is passed.
*
* @param xid The transaction Xid
* @param conn The connection to associate, null to dissociate
*/
TxConnection setTxConnection( Xid xid, TxConnection txConn )
{
if ( txConn == null )
return (TxConnection) _txConnections.remove( xid );
else
return (TxConnection) _txConnections.put( xid, txConn );
}
/**
* Release an unused connection back to the pool. If an XA
* connection has been asked to join an existing transaction,
* it will no longer use it's own connection and make it available
* to newly created connections.
*
* @param conn An open connection that is no longer in use
*/
void releaseConnection( Connection conn )
{
_pool.push( conn );
}
/**
* Creates a new underlying connection. Used by XA connection
* that lost it's underlying connection when joining a
* transaction and is now asked to produce a new connection.
*
* @return An open connection ready for use
* @throws SQLException An error occured trying to open
* a connection
*/
Connection newConnection()
public XAConnection getXAConnection()
throws SQLException
{
Connection conn;
// Check in the pool first.
if ( ! _pool.empty() ) {
conn = (Connection) _pool.pop();
return conn;
{
// Construct a new XAConnection with no underlying connection.
// When a JDBC method requires an underlying connection, one
// will be created. We don't create the underlying connection
// beforehand, as it might be coming from an existing
// transaction.
return new XAConnectionImpl( this, null );
}
return getConnection();
}
/**
* XXX Not fully implemented yet and no code to really
* test it.
*/
Xid[] getTxRecover()
{
Vector list;
Enumeration enum;
TxConnection txConn;
list = new Vector();
enum = _txConnections.elements();
while ( enum.hasMoreElements() ) {
txConn = (TxConnection) enum.nextElement();
if ( txConn.conn != null && txConn.prepared )
list.add( txConn.xid );
public XAConnection getXAConnection( String user, String password )
throws SQLException
{
// Since we create the connection on-demand with newConnection
// or obtain it from a transaction, we cannot support XA
// connections with a caller specified user name.
throw new SQLException( "XAConnection does not support connections with caller specified user name" );
}
return (Xid[]) list.toArray();
}
/**
* Returns the transaction isolation level to use with all newly
* created transactions, or {@link Connection#TRANSACTION_NONE}
* if using the driver's default isolation level.
*/
public int isolationLevel()
{
return Connection.TRANSACTION_NONE;
}
public PooledConnection getPooledConnection()
throws SQLException
{
// Construct a new pooled connection and an underlying JDBC
// connection to go along with it.
return new XAConnectionImpl( this, getConnection() );
}
public void run()
{
Enumeration enum;
int reduce;
long timeout;
TxConnection txConn;
public PooledConnection getPooledConnection( String user, String password )
throws SQLException
{
// Construct a new pooled connection and an underlying JDBC
// connection to go along with it.
return new XAConnectionImpl( this, getConnection( user, password ) );
}
while ( true ) {
// Go to sleep for the duration of a transaction
// timeout. This mean transactions will timeout on average
// at _txTimeout * 1.5.
try {
Thread.sleep( _txTimeout * 1000 );
} catch ( InterruptedException except ) {
}
try {
// Check to see if there are any pooled connections
// we can release. We release 10% of the pooled
// connections each time, so in a heavy loaded
// environment we don't get to release that many, but
// as load goes down we do. These are not actually
// pooled connections, but connections that happen to
// get in and out of a transaction, not that many.
reduce = _pool.size() - ( _pool.size() / 10 ) - 1;
if ( reduce >= 0 && _pool.size() > reduce ) {
if ( getLogWriter() != null )
getLogWriter().println( "DataSource " + toString() +
": Reducing internal connection pool size from " +
_pool.size() + " to " + reduce );
while ( _pool.size() > reduce ) {
try {
( (Connection) _pool.pop() ).close();
} catch ( SQLException except ) { }
}
/**
* Returns the default timeout for all transactions.
*/
public int getTransactionTimeout()
{
return _txTimeout;
}
/**
* This method is defined in the interface and implemented in the
* derived class, we re-define it just to make sure it does not
* throw an {@link SQLException} and that we do not need to
* catch one.
*/
public abstract java.io.PrintWriter getLogWriter();
/**
* Sets the default timeout for all transactions. The timeout is
* specified in seconds. Use zero for the default timeout. Calling
* this method does not affect transactions in progress.
*
* @param seconds The timeout in seconds
*/
public void setTransactionTimeout( int seconds )
{
if ( seconds <= 0 )
_txTimeout = DEFAULT_TX_TIMEOUT;
else
_txTimeout = seconds;
_background.interrupt();
}
/**
* Returns an underlying connection for the global transaction,
* if one has been associated before.
*
* @param xid The transaction Xid
* @return A connection associated with that transaction, or null
*/
TxConnection getTxConnection( Xid xid )
{
return (TxConnection) _txConnections.get( xid );
}
/**
* Associates the global transaction with an underlying connection,
* or dissociate it when null is passed.
*
* @param xid The transaction Xid
* @param conn The connection to associate, null to dissociate
*/
TxConnection setTxConnection( Xid xid, TxConnection txConn )
{
if ( txConn == null )
return (TxConnection) _txConnections.remove( xid );
else
return (TxConnection) _txConnections.put( xid, txConn );
}
/**
* Release an unused connection back to the pool. If an XA
* connection has been asked to join an existing transaction,
* it will no longer use it's own connection and make it available
* to newly created connections.
*
* @param conn An open connection that is no longer in use
*/
void releaseConnection( Connection conn )
{
_pool.push( conn );
}
/**
* Creates a new underlying connection. Used by XA connection
* that lost it's underlying connection when joining a
* transaction and is now asked to produce a new connection.
*
* @return An open connection ready for use
* @throws SQLException An error occured trying to open
* a connection
*/
Connection newConnection()
throws SQLException
{
Connection conn;
// Check in the pool first.
if ( ! _pool.empty() )
{
conn = (Connection) _pool.pop();
return conn;
}
} catch ( Exception except ) { }
// Look for all connections inside a transaction that
// should have timed out by now.
timeout = System.currentTimeMillis();
enum = _txConnections.elements();
while ( enum.hasMoreElements() ) {
txConn = (TxConnection) enum.nextElement();
// If the transaction timed out, we roll it back and
// invalidate it, but do not remove it from the transaction
// list yet. We wait for the next iteration, minimizing the
// chance of a NOTA exception.
if ( txConn.conn == null ) {
_txConnections.remove( txConn.xid );
// Chose not to use an iterator so we must
// re-enumerate the list after removing
// an element from it.
enum = _txConnections.elements();
} else if ( txConn.timeout < timeout ) {
try {
Connection underlying;
synchronized ( txConn ) {
if ( txConn.conn == null )
continue;
if ( getLogWriter() != null )
getLogWriter().println( "DataSource " + toString() +
": Transaction timed out and being aborted: " +
txConn.xid );
// Remove the connection from the transaction
// association. XAConnection will now have
// no underlying connection and attempt to
// create a new one.
underlying = txConn.conn;
txConn.conn = null;
txConn.timedOut = true;
// Rollback the underlying connection to
// abort the transaction and release the
// underlying connection to the pool.
try {
underlying.rollback();
releaseConnection( underlying );
} catch ( SQLException except ) {
if ( getLogWriter() != null )
getLogWriter().println( "DataSource " + toString() +
": Error aborting timed out transaction: " + except );
try {
underlying.close();
} catch ( SQLException e2 ) { }
}
return getConnection();
}
/**
* XXX Not fully implemented yet and no code to really
* test it.
*/
Xid[] getTxRecover()
{
Vector list;
Enumeration enum;
TxConnection txConn;
list = new Vector();
enum = _txConnections.elements();
while ( enum.hasMoreElements() )
{
txConn = (TxConnection) enum.nextElement();
if ( txConn.conn != null && txConn.prepared )
list.add( txConn.xid );
}
return (Xid[]) list.toArray();
}
/**
* Returns the transaction isolation level to use with all newly
* created transactions, or {@link Connection#TRANSACTION_NONE}
* if using the driver's default isolation level.
*/
public int isolationLevel()
{
return Connection.TRANSACTION_NONE;
}
public void run()
{
Enumeration enum;
int reduce;
long timeout;
TxConnection txConn;
while ( true )
{
// Go to sleep for the duration of a transaction
// timeout. This mean transactions will timeout on average
// at _txTimeout * 1.5.
try
{
Thread.sleep( _txTimeout * 1000 );
}
catch ( InterruptedException except )
{}
try
{
// Check to see if there are any pooled connections
// we can release. We release 10% of the pooled
// connections each time, so in a heavy loaded
// environment we don't get to release that many, but
// as load goes down we do. These are not actually
// pooled connections, but connections that happen to
// get in and out of a transaction, not that many.
reduce = _pool.size() - ( _pool.size() / 10 ) - 1;
if ( reduce >= 0 && _pool.size() > reduce )
{
if ( getLogWriter() != null )
getLogWriter().println( "DataSource " + toString() +
": Reducing internal connection pool size from " +
_pool.size() + " to " + reduce );
while ( _pool.size() > reduce )
{
try
{
( (Connection) _pool.pop() ).close();
}
catch ( SQLException except )
{ }
}
}
}
catch ( Exception except )
{ }
// Look for all connections inside a transaction that
// should have timed out by now.
timeout = System.currentTimeMillis();
enum = _txConnections.elements();
while ( enum.hasMoreElements() )
{
txConn = (TxConnection) enum.nextElement();
// If the transaction timed out, we roll it back and
// invalidate it, but do not remove it from the transaction
// list yet. We wait for the next iteration, minimizing the
// chance of a NOTA exception.
if ( txConn.conn == null )
{
_txConnections.remove( txConn.xid );
// Chose not to use an iterator so we must
// re-enumerate the list after removing
// an element from it.
enum = _txConnections.elements();
}
else if ( txConn.timeout < timeout )
{
try
{
Connection underlying;
synchronized ( txConn )
{
if ( txConn.conn == null )
continue;
if ( getLogWriter() != null )
getLogWriter().println( "DataSource " + toString() +
": Transaction timed out and being aborted: " +
txConn.xid );
// Remove the connection from the transaction
// association. XAConnection will now have
// no underlying connection and attempt to
// create a new one.
underlying = txConn.conn;
txConn.conn = null;
txConn.timedOut = true;
// Rollback the underlying connection to
// abort the transaction and release the
// underlying connection to the pool.
try
{
underlying.rollback();
releaseConnection( underlying );
}
catch ( SQLException except )
{
if ( getLogWriter() != null )
getLogWriter().println( "DataSource " + toString() +
": Error aborting timed out transaction: " + except );
try
{
underlying.close();
}
catch ( SQLException e2 )
{ }
}
}
}
catch ( Exception except )
{ }
}
}
} catch ( Exception except ) { }
}
}
}
}
public void debug( PrintWriter writer )
{
Enumeration enum;
TxConnection txConn;
StringBuffer buffer;
public void debug( PrintWriter writer )
{
Enumeration enum;
TxConnection txConn;
StringBuffer buffer;
writer.println( "Debug info for XADataSource:" );
enum = _txConnections.elements();
if ( ! enum.hasMoreElements() )
writer.println( "Empty" );
while ( enum.hasMoreElements() ) {
buffer = new StringBuffer();
txConn = (TxConnection) enum.nextElement();
buffer.append( "TxConnection " );
if ( txConn.xid != null )
buffer.append( txConn.xid );
if ( txConn.conn != null )
buffer.append( ' ' ).append( txConn.conn );
buffer.append( " count: " ).append( txConn.count );
if ( txConn.prepared )
buffer.append( " prepared" );
if ( txConn.timedOut )
buffer.append( " timed-out" );
if ( txConn.readOnly )
buffer.append( " read-only" );
writer.println( buffer.toString() );
writer.println( "Debug info for XADataSource:" );
enum = _txConnections.elements();
if ( ! enum.hasMoreElements() )
writer.println( "Empty" );
while ( enum.hasMoreElements() )
{
buffer = new StringBuffer();
txConn = (TxConnection) enum.nextElement();
buffer.append( "TxConnection " );
if ( txConn.xid != null )
buffer.append( txConn.xid );
if ( txConn.conn != null )
buffer.append( ' ' ).append( txConn.conn );
buffer.append( " count: " ).append( txConn.count );
if ( txConn.prepared )
buffer.append( " prepared" );
if ( txConn.timedOut )
buffer.append( " timed-out" );
if ( txConn.readOnly )
buffer.append( " read-only" );
writer.println( buffer.toString() );
}
enum = _pool.elements();
while ( enum.hasMoreElements() )
writer.println( "Pooled underlying: " + enum.nextElement().toString() );
}
enum = _pool.elements();
while ( enum.hasMoreElements() )
writer.println( "Pooled underlying: " + enum.nextElement().toString() );
}
}

View File

@ -7,62 +7,68 @@ package utils;
*/
public class CheckVersion
{
/**
* Check for the existence of a class by attempting to load it
*/
public static boolean checkClass(String c) {
try {
Class.forName(c);
} catch(Exception e) {
return false;
/**
* Check for the existence of a class by attempting to load it
*/
public static boolean checkClass(String c)
{
try
{
Class.forName(c);
}
catch (Exception e)
{
return false;
}
return true;
}
return true;
}
/**
* This first checks java.vm.version for 1.1, 1.2 or 1.3.
*
* It writes jdbc1 to stdout for the 1.1.x VM.
*
* For 1.2 or 1.3, it checks for the existence of the javax.sql.DataSource
* interface, and if found writes enterprise to stdout. If the interface
* is not found, it writes jdbc2 to stdout.
*
* PS: It also looks for the existence of java.lang.Byte which appeared in
* JDK1.1.0 incase java.vm.version is not heeded by some JVM's.
*
* If it can't work it out, it writes huho to stdout.
*
* The make file uses the written results to determine which rule to run.
*
* Bugs: This needs thorough testing.
*/
public static void main(String args[])
{
String vmversion = System.getProperty("java.vm.version");
System.out.println("postgresql.jdbc="+System.getProperty("postgresql.jdbc"));
// We are running a 1.1 JVM
if(vmversion.startsWith("1.1")) {
System.out.println("jdbc1");
//System.exit(0);
/**
* This first checks java.vm.version for 1.1, 1.2 or 1.3.
*
* It writes jdbc1 to stdout for the 1.1.x VM.
*
* For 1.2 or 1.3, it checks for the existence of the javax.sql.DataSource
* interface, and if found writes enterprise to stdout. If the interface
* is not found, it writes jdbc2 to stdout.
*
* PS: It also looks for the existence of java.lang.Byte which appeared in
* JDK1.1.0 incase java.vm.version is not heeded by some JVM's.
*
* If it can't work it out, it writes huho to stdout.
*
* The make file uses the written results to determine which rule to run.
*
* Bugs: This needs thorough testing.
*/
public static void main(String args[])
{
String vmversion = System.getProperty("java.vm.version");
System.out.println("postgresql.jdbc=" + System.getProperty("postgresql.jdbc"));
// We are running a 1.1 JVM
if (vmversion.startsWith("1.1"))
{
System.out.println("jdbc1");
//System.exit(0);
}
else
// We are running a 1.2 or 1.3 JVM
if (vmversion.startsWith("1.2") ||
vmversion.startsWith("1.3") ||
checkClass("java.lang.Byte")
)
{
// Check to see if we have the standard extensions. If so, then
// we want the enterprise edition, otherwise the jdbc2 driver.
if (checkClass("javax.sql.DataSource"))
System.out.println("enterprise");
else
System.out.println("jdbc2");
//System.exit(0);
}
System.setProperty("postgresql.jdbc", "yoyo");
}
else
// We are running a 1.2 or 1.3 JVM
if(vmversion.startsWith("1.2") ||
vmversion.startsWith("1.3") ||
checkClass("java.lang.Byte")
) {
// Check to see if we have the standard extensions. If so, then
// we want the enterprise edition, otherwise the jdbc2 driver.
if(checkClass("javax.sql.DataSource"))
System.out.println("enterprise");
else
System.out.println("jdbc2");
//System.exit(0);
}
System.setProperty("postgresql.jdbc","yoyo");
}
}