1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-06 18:42:54 +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 public class ImageViewer implements ItemListener
{ {
Connection db; Connection db;
Statement stat; Statement stat;
LargeObjectManager lom; LargeObjectManager lom;
Frame frame; Frame frame;
Label label; // Label used to display the current name Label label; // Label used to display the current name
List list; // The list of available images List list; // The list of available images
imageCanvas canvas; // Canvas used to display the image imageCanvas canvas; // Canvas used to display the image
String currentImage; // The current images name String currentImage; // The current images name
// This is a simple component to display our image // This is a simple component to display our image
public class imageCanvas extends Canvas public class imageCanvas extends Canvas
{ {
// holds the image // holds the image
private Image image; private Image image;
// holds the background buffer // holds the background buffer
private Image bkg; private Image bkg;
// the size of the buffer // the size of the buffer
private Dimension size; private Dimension size;
public imageCanvas() public imageCanvas()
{ {
image=null; image = null;
} }
public void setImage(Image img) public void setImage(Image img)
{ {
image=img; image = img;
repaint(); repaint();
} }
// This defines our minimum size // This defines our minimum size
public Dimension getMinimumSize() public Dimension getMinimumSize()
{ {
return new Dimension(400,400); return new Dimension(400, 400);
} }
public Dimension getPreferedSize() public Dimension getPreferedSize()
{ {
return getMinimumSize(); return getMinimumSize();
} }
public void update(Graphics g) public void update(Graphics g)
{ {
paint(g); paint(g);
} }
/** /**
* Paints the image, using double buffering to prevent screen flicker * Paints the image, using double buffering to prevent screen flicker
*/ */
public void paint(Graphics gr) public void paint(Graphics gr)
{ {
Dimension s = getSize(); Dimension s = getSize();
if(size==null || bkg==null || !s.equals(size)) { if (size == null || bkg == null || !s.equals(size))
size = s; {
bkg = createImage(size.width,size.height); size = s;
} bkg = createImage(size.width, size.height);
}
// now set the background // now set the background
Graphics g = bkg.getGraphics(); Graphics g = bkg.getGraphics();
g.setColor(Color.gray); g.setColor(Color.gray);
g.fillRect(0,0,s.width,s.height); g.fillRect(0, 0, s.width, s.height);
// now paint the image over the background // now paint the image over the background
if(image!=null) if (image != null)
g.drawImage(image,0,0,this); g.drawImage(image, 0, 0, this);
// dispose the graphics instance // dispose the graphics instance
g.dispose(); g.dispose();
// paint the image onto the component // paint the image onto the component
gr.drawImage(bkg,0,0,this); 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");
}
} }
}
}
}
/** public ImageViewer(Frame f, String url, String user, String password) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
* This refreshes the list of available images {
*/ frame = f;
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?");
}
}
/** MenuBar mb = new MenuBar();
* This removes an image from the database Menu m;
* MenuItem i;
* Note: With postgresql, this is the only way of deleting a large object
* using Java. f.setMenuBar(mb);
*/ mb.add(m = new Menu("PostgreSQL"));
public void removeImage() m.add(i = new MenuItem("Initialise"));
{ i.addActionListener(new ActionListener()
try { {
// public void actionPerformed(ActionEvent e)
// Delete any large objects for the current name {
// ImageViewer.this.init();
// 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+"'"); m.add(i = new MenuItem("Exit"));
if(rs!=null) { ActionListener exitListener = new ActionListener()
// Even though there should only be one image, we still have to {
// cycle through the ResultSet public void actionPerformed(ActionEvent e)
while(rs.next()) { {
lom.delete(rs.getInt(1)); 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; * This method initialises the database by creating a table that contains
refreshList(); * the image names, and Large Object OID's
} catch(SQLException ex) { */
label.setText(ex.toString()); 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
* This displays an image from the database. //try {
* //db.setAutoCommit(true);
* For images, this is the easiest method. //} catch(SQLException ex) {
*/ //label.setText(ex.toString());
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) { * This closes the connection, and ends the application
label.setText(ex.toString()); */
} finally { public void close()
try { {
db.setAutoCommit(true); try
} catch(SQLException ex2) { {
db.close();
}
catch (SQLException ex)
{
System.err.println(ex.toString());
}
System.exit(0);
} }
}
}
public void itemStateChanged(ItemEvent e) { /**
displayImage(list.getItem(((Integer)e.getItem()).intValue())); * 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
* This is the command line instructions Thread t = new importer(db, name, dir);
*/ //t.setPriority(Thread.MAX_PRIORITY);
public static void instructions() t.start();
{ }
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 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 is the application entry point {
*/ this.db = db;
public static void main(String args[]) this.name = name;
{ this.dir = dir;
if(args.length!=3) { }
instructions();
System.exit(1);
}
try { public void run()
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]); // Now the real import stuff
frame.pack(); if (name != null && dir != null)
frame.setLocation(0,50); {
frame.setVisible(true); Statement stat = null;
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex); try
ex.printStackTrace(); {
} // 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();
}
}
} }

View File

@@ -5,236 +5,274 @@ import java.sql.*;
import java.util.*; import java.util.*;
/** /**
* Test inserting and extracting Unicode-encoded strings. * Test inserting and extracting Unicode-encoded strings.
* *
* Synopsis: * Synopsis:
* example.Unicode <url> <user> <password> * example.Unicode <url> <user> <password>
* where <url> must specify an existing database to which <user> and * where <url> must specify an existing database to which <user> and
* <password> give access and which has UNICODE as its encoding. * <password> give access and which has UNICODE as its encoding.
* (To create a database with UNICODE encoding, you need to compile * (To create a database with UNICODE encoding, you need to compile
* postgres with "--enable-multibyte" and run createdb with the * postgres with "--enable-multibyte" and run createdb with the
* flag "-E UNICODE".) * 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 { public class Unicode
{
/** /**
* The url for the database to connect to. * The url for the database to connect to.
*/ */
private String url; private String url;
/** /**
* The user to connect as. * The user to connect as.
*/ */
private String user; private String user;
/** /**
* The password to connect with. * The password to connect with.
*/ */
private String password; private String password;
private static void usage() { private static void usage()
log("usage: example.Unicode <url> <user> <password>"); {
} log("usage: example.Unicode <url> <user> <password>");
}
private static void log(String message) { private static void log(String message)
System.err.println(message); {
} System.err.println(message);
}
private static void log(String message, Exception e) { private static void log(String message, Exception e)
System.err.println(message); {
e.printStackTrace(); System.err.println(message);
} e.printStackTrace();
}
public Unicode(String url, String user, String password) { public Unicode(String url, String user, String password)
this.url = url; {
this.user = user; this.url = url;
this.password = password; this.user = user;
} this.password = password;
}
/** /**
* Establish and return a connection to the database. * Establish and return a connection to the database.
*/ */
private Connection getConnection() throws SQLException, private Connection getConnection() throws SQLException,
ClassNotFoundException { ClassNotFoundException
Class.forName("org.postgresql.Driver"); {
Properties info = new Properties(); Class.forName("org.postgresql.Driver");
info.put("user", user); Properties info = new Properties();
info.put("password", password); info.put("user", user);
info.put("charSet", "utf-8"); info.put("password", password);
return DriverManager.getConnection(url, info); info.put("charSet", "utf-8");
} return DriverManager.getConnection(url, info);
}
/** /**
* Get string representing a block of 256 consecutive unicode characters. * Get string representing a block of 256 consecutive unicode characters.
* We exclude the null character, "'", and "\". * We exclude the null character, "'", and "\".
*/ */
private String getSqlSafeUnicodeBlock(int blockNum) { private String getSqlSafeUnicodeBlock(int blockNum)
if (blockNum < 0 || blockNum > 255) {
throw new IllegalArgumentException("blockNum must be from 0 to " if (blockNum < 0 || blockNum > 255)
+ "255: " + blockNum); throw new IllegalArgumentException("blockNum must be from 0 to "
StringBuffer sb = new StringBuffer(256); + "255: " + blockNum);
int blockFirst = blockNum * 256; StringBuffer sb = new StringBuffer(256);
int blockLast = blockFirst + 256; int blockFirst = blockNum * 256;
for (int i = blockFirst; i < blockLast; i++) { int blockLast = blockFirst + 256;
char c = (char) i; for (int i = blockFirst; i < blockLast; i++)
if (c == '\0' || c == '\'' || c == '\\') {
continue; char c = (char) i;
sb.append(c); if (c == '\0' || c == '\'' || c == '\\')
} continue;
return sb.toString(); sb.append(c);
} }
return sb.toString();
}
/** /**
* Is the block a block of valid unicode values. * Is the block a block of valid unicode values.
* d800 to db7f is the "unassigned high surrogate" range. * d800 to db7f is the "unassigned high surrogate" range.
* db80 to dbff is the "private use" range. * db80 to dbff is the "private use" range.
* These should not be used in actual Unicode strings; * These should not be used in actual Unicode strings;
* at least, jdk1.2 will not convert them to utf-8. * at least, jdk1.2 will not convert them to utf-8.
*/ */
private boolean isValidUnicodeBlock(int blockNum) { private boolean isValidUnicodeBlock(int blockNum)
if (blockNum >= 0xd8 && blockNum <= 0xdb) {
return false; if (blockNum >= 0xd8 && blockNum <= 0xdb)
else return false;
return true; else
} return true;
}
/** /**
* Report incorrect block retrieval. * Report incorrect block retrieval.
*/ */
private void reportRetrievalError(int blockNum, String block, private void reportRetrievalError(int blockNum, String block,
String retrieved) { String retrieved)
String message = "Block " + blockNum + " returned incorrectly: "; {
int i = 0; String message = "Block " + blockNum + " returned incorrectly: ";
for (i = 0; i < block.length(); i++) { int i = 0;
if (i >= retrieved.length()) { for (i = 0; i < block.length(); i++)
message += "too short"; {
break; if (i >= retrieved.length())
} else if (retrieved.charAt(i) != block.charAt(i)) { {
message += message += "too short";
"first changed character at position " + i + ", sent as 0x" break;
+ Integer.toHexString((int) block.charAt(i)) }
+ ", retrieved as 0x" else if (retrieved.charAt(i) != block.charAt(i))
+ Integer.toHexString ((int) retrieved.charAt(i)); {
break; message +=
} "first changed character at position " + i + ", sent as 0x"
} + Integer.toHexString((int) block.charAt(i))
if (i >= block.length()) + ", retrieved as 0x"
message += "too long"; + Integer.toHexString ((int) retrieved.charAt(i));
log(message); break;
} }
}
if (i >= block.length())
message += "too long";
log(message);
}
/** /**
* Do the testing. * Do the testing.
*/ */
public void runTest() { public void runTest()
Connection connection = null; {
Statement statement = null; Connection connection = null;
int blockNum = 0; Statement statement = null;
final int CREATE = 0; int blockNum = 0;
final int INSERT = 1; final int CREATE = 0;
final int SELECT = 2; final int INSERT = 1;
final int LIKE = 3; final int SELECT = 2;
int mode = CREATE; final int LIKE = 3;
try { int mode = CREATE;
connection = getConnection(); try
statement = connection.createStatement(); {
statement.executeUpdate("CREATE TABLE test_unicode " connection = getConnection();
+ "( blockNum INT PRIMARY KEY, " statement = connection.createStatement();
+ "block TEXT );"); statement.executeUpdate("CREATE TABLE test_unicode "
mode = INSERT; + "( blockNum INT PRIMARY KEY, "
for (blockNum = 0; blockNum < 256; blockNum++) { + "block TEXT );");
if (isValidUnicodeBlock(blockNum)) { mode = INSERT;
String block = getSqlSafeUnicodeBlock(blockNum); for (blockNum = 0; blockNum < 256; blockNum++)
statement.executeUpdate {
("INSERT INTO test_unicode VALUES ( " + blockNum if (isValidUnicodeBlock(blockNum))
+ ", '" + block + "');"); {
} String block = getSqlSafeUnicodeBlock(blockNum);
} statement.executeUpdate
mode = SELECT; ("INSERT INTO test_unicode VALUES ( " + blockNum
for (blockNum = 0; blockNum < 256; blockNum++) { + ", '" + block + "');");
if (isValidUnicodeBlock(blockNum)) { }
String block = getSqlSafeUnicodeBlock(blockNum); }
ResultSet rs = statement.executeQuery mode = SELECT;
("SELECT block FROM test_unicode WHERE blockNum = " for (blockNum = 0; blockNum < 256; blockNum++)
+ blockNum + ";"); {
if (!rs.next()) if (isValidUnicodeBlock(blockNum))
log("Could not retrieve block " + blockNum); {
else { String block = getSqlSafeUnicodeBlock(blockNum);
String retrieved = rs.getString(1); ResultSet rs = statement.executeQuery
if (!retrieved.equals(block)) { ("SELECT block FROM test_unicode WHERE blockNum = "
reportRetrievalError(blockNum, block, retrieved); + blockNum + ";");
} if (!rs.next())
} log("Could not retrieve block " + blockNum);
} else
} {
mode = LIKE; String retrieved = rs.getString(1);
for (blockNum = 0; blockNum < 256; blockNum++) { if (!retrieved.equals(block))
if (isValidUnicodeBlock(blockNum)) { {
String block = getSqlSafeUnicodeBlock(blockNum); reportRetrievalError(blockNum, block, retrieved);
String likeString = "%" + }
block.substring(2, block.length() - 3) + "%" ; }
ResultSet rs = statement.executeQuery }
("SELECT blockNum FROM test_unicode WHERE block LIKE '" }
+ likeString + "';"); mode = LIKE;
if (!rs.next()) for (blockNum = 0; blockNum < 256; blockNum++)
log("Could get block " + blockNum + " using LIKE"); {
} if (isValidUnicodeBlock(blockNum))
} {
} catch (SQLException sqle) { String block = getSqlSafeUnicodeBlock(blockNum);
switch (mode) { String likeString = "%" +
case CREATE: block.substring(2, block.length() - 3) + "%" ;
log("Exception creating database", sqle); ResultSet rs = statement.executeQuery
break; ("SELECT blockNum FROM test_unicode WHERE block LIKE '"
case INSERT: + likeString + "';");
log("Exception inserting block " + blockNum, sqle); if (!rs.next())
break; log("Could get block " + blockNum + " using LIKE");
case SELECT: }
log("Exception selecting block " + blockNum, sqle); }
break; }
case LIKE: catch (SQLException sqle)
log("Exception doing LIKE on block " + blockNum, sqle); {
break; switch (mode)
default: {
log("Exception", sqle); case CREATE:
break; log("Exception creating database", sqle);
} break;
} catch (ClassNotFoundException cnfe) { case INSERT:
log("Unable to load driver", cnfe); log("Exception inserting block " + blockNum, sqle);
return; break;
} case SELECT:
try { log("Exception selecting block " + blockNum, sqle);
if (statement != null) break;
statement.close(); case LIKE:
if (connection != null) log("Exception doing LIKE on block " + blockNum, sqle);
connection.close(); break;
} catch (SQLException sqle) { default:
log("Exception closing connections", sqle); log("Exception", sqle);
} break;
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 catch (ClassNotFoundException cnfe)
// a fresh connection to delete the table. {
try { log("Unable to load driver", cnfe);
connection = getConnection(); return ;
statement = connection.createStatement(); }
statement.executeUpdate("DROP TABLE test_unicode;"); try
} catch (Exception sqle) { {
log("*** ERROR: unable to delete test table " if (statement != null)
+ "test_unicode; must be deleted manually", sqle); 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) { public static void main(String [] args)
if (args.length != 3) { {
usage(); if (args.length != 3)
System.exit(1); {
} usage();
new Unicode(args[0], args[1], args[2]).runTest(); 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 * This example tests the basic components of the JDBC driver, and shows
* how even the simplest of queries can be implemented. * how even the simplest of queries can be implemented.
@@ -20,184 +20,198 @@ import java.text.*;
public class basic public class basic
{ {
Connection db; // The connection to the database Connection db; // The connection to the database
Statement st; // Our statement to run queries with Statement st; // Our statement to run queries with
public basic(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException public basic(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{ {
String url = args[0]; String url = args[0];
String usr = args[1]; String usr = args[1];
String pwd = args[2]; String pwd = args[2];
// Load the driver // Load the driver
Class.forName("org.postgresql.Driver"); Class.forName("org.postgresql.Driver");
// Connect to database // Connect to database
System.out.println("Connecting to Database URL = " + url); System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd); db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement"); System.out.println("Connected...Now creating a statement");
st = db.createStatement(); st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise // Clean up the database (in case we failed earlier) then initialise
cleanup(); cleanup();
// Now run tests using JDBC methods // Now run tests using JDBC methods
doexample(); doexample();
// Clean up the database // Clean up the database
cleanup(); cleanup();
// Finally close the database // Finally close the database
System.out.println("Now closing the connection"); System.out.println("Now closing the connection");
st.close(); st.close();
db.close(); db.close();
//throw postgresql.Driver.notImplemented(); //throw postgresql.Driver.notImplemented();
} }
/** /**
* This drops the table (if it existed). No errors are reported. * This drops the table (if it existed). No errors are reported.
*/ */
public void cleanup() public void cleanup()
{ {
try { try
st.executeUpdate("drop table basic"); {
} catch(Exception ex) { st.executeUpdate("drop table basic");
// We ignore any errors here }
} catch (Exception ex)
} {
// We ignore any errors here
}
}
/** /**
* This performs the example * This performs the example
*/ */
public void doexample() throws SQLException public void doexample() throws SQLException
{ {
System.out.println("\nRunning tests:"); System.out.println("\nRunning tests:");
// First we need a table to store data in // First we need a table to store data in
st.executeUpdate("create table basic (a int2, b int2)"); st.executeUpdate("create table basic (a int2, b int2)");
// Now insert some data, using the Statement // Now insert some data, using the Statement
st.executeUpdate("insert into basic values (1,1)"); st.executeUpdate("insert into basic values (1,1)");
st.executeUpdate("insert into basic values (2,1)"); st.executeUpdate("insert into basic values (2,1)");
st.executeUpdate("insert into basic values (3,1)"); st.executeUpdate("insert into basic values (3,1)");
// This shows how to get the oid of a just inserted row // This shows how to get the oid of a just inserted row
// updated for 7.1 // updated for 7.1
st.executeUpdate("insert into basic values (4,1)"); st.executeUpdate("insert into basic values (4,1)");
int insertedOID = ((org.postgresql.Statement)st).getInsertedOID(); int insertedOID = ((org.postgresql.Statement)st).getInsertedOID();
System.out.println("Inserted row with oid "+insertedOID); System.out.println("Inserted row with oid " + insertedOID);
// Now change the value of b from 1 to 8 // Now change the value of b from 1 to 8
st.executeUpdate("update basic set b=8"); st.executeUpdate("update basic set b=8");
System.out.println("Updated "+st.getUpdateCount()+" rows"); System.out.println("Updated " + st.getUpdateCount() + " rows");
// Now delete 2 rows // Now delete 2 rows
st.executeUpdate("delete from basic where a<3"); st.executeUpdate("delete from basic where a<3");
System.out.println("deleted "+st.getUpdateCount()+" rows"); System.out.println("deleted " + st.getUpdateCount() + " rows");
// For large inserts, a PreparedStatement is more efficient, because it // For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store // supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support // directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a // precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc). // Java object (like Date, String, etc).
// //
// Also, this is the only way of writing dates in a datestyle independent // Also, this is the only way of writing dates in a datestyle independent
// manner. (DateStyles are PostgreSQL's way of handling different methods // manner. (DateStyles are PostgreSQL's way of handling different methods
// of representing dates in the Date data type.) // of representing dates in the Date data type.)
PreparedStatement ps = db.prepareStatement("insert into basic values (?,?)"); PreparedStatement ps = db.prepareStatement("insert into basic values (?,?)");
for(int i=2;i<5;i++) { for (int i = 2;i < 5;i++)
ps.setInt(1,4); // "column a" = 5 {
ps.setInt(2,i); // "column b" = i ps.setInt(1, 4); // "column a" = 5
ps.executeUpdate(); // executeUpdate because insert returns no data 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 }
ps.close(); // Always close when we are done with it
// Finally perform a query on the table // Finally perform a query on the table
System.out.println("performing a query"); System.out.println("performing a query");
ResultSet rs = st.executeQuery("select a, b from basic"); ResultSet rs = st.executeQuery("select a, b from basic");
if(rs!=null) { 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 // Now we run through the result set, printing out the result.
while(rs.next()) { // Note, we must call .next() before attempting to read any results
int a = rs.getInt("a"); // This shows how to get the value by name while (rs.next())
int b = rs.getInt(2); // This shows how to get the value by column {
System.out.println(" a="+a+" b="+b); 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
rs.close(); // again, you must close the result when done 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 // 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 // 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 we run through the result set, printing out the result. System.out.println("performing another query");
// Again, we must call .next() before attempting to read any results rs = st.executeQuery("select * from basic where b>1");
while(rs.next()) { if (rs != null)
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 // First find out the column numbers.
System.out.println(" a="+a+" b="+b); //
} // It's best to do this here, as calling the methods with the column
rs.close(); // again, you must close the result when done // 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 // Now we run through the result set, printing out the result.
st.setMaxRows(3); // Again, we must call .next() before attempting to read any results
System.out.println("performing a query limited to "+st.getMaxRows()); while (rs.next())
rs = st.executeQuery("select a, b from basic"); {
while(rs.next()) { int a = rs.getInt(col_a); // This shows how to get the value by name
int a = rs.getInt("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
int b = rs.getInt(2); // This shows how to get the value by column System.out.println(" a=" + a + " b=" + b);
System.out.println(" a="+a+" b="+b); }
} rs.close(); // again, you must close the result when done
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 // Now test maxrows by setting it to 3 rows
// cleanup() method.
}
/** st.setMaxRows(3);
* Display some instructions on how to run the example System.out.println("performing a query limited to " + st.getMaxRows());
*/ rs = st.executeQuery("select a, b from basic");
public static void instructions() while (rs.next())
{ {
System.out.println("\nThis example tests the basic components of the JDBC driver, demonstrating\nhow to build simple queries in java.\n"); int a = rs.getInt("a"); // This shows how to get the value by name
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."); int b = rs.getInt(2); // This shows how to get the value by column
System.exit(1); 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
* This little lot starts the test // cleanup() method.
*/ }
public static void main(String args[])
{
System.out.println("PostgreSQL basic test v6.3 rev 1\n");
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 * This little lot starts the test
if(args.length>3) */
DriverManager.setLogStream(System.err); public static void main(String args[])
{
System.out.println("PostgreSQL basic test v6.3 rev 1\n");
// Now run the tests if (args.length < 3)
try { instructions();
basic test = new basic(args);
} catch(Exception ex) { // This line outputs debug information to stderr. To enable this, simply
System.err.println("Exception caught.\n"+ex); // add an extra parameter to the command line
ex.printStackTrace(); 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 public class blobtest
{ {
Connection db; Connection db;
Statement s; Statement s;
LargeObjectManager lobj; LargeObjectManager lobj;
public blobtest(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException public blobtest(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{ {
String url = args[0]; String url = args[0];
String usr = args[1]; String usr = args[1];
String pwd = args[2]; String pwd = args[2];
// Load the driver // Load the driver
Class.forName("org.postgresql.Driver"); Class.forName("org.postgresql.Driver");
// Connect to database // Connect to database
System.out.println("Connecting to Database URL = " + url); System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd); db = DriverManager.getConnection(url, usr, pwd);
// This is required for all LargeObject calls // This is required for all LargeObject calls
System.out.println("Connected... First turn off autoCommit()"); System.out.println("Connected... First turn off autoCommit()");
db.setAutoCommit(false); db.setAutoCommit(false);
System.out.println("Now creating a statement"); System.out.println("Now creating a statement");
s = db.createStatement(); s = db.createStatement();
// Now run tests using postgresql's own Large object api // Now run tests using postgresql's own Large object api
// NOTE: The methods shown in this example are _NOT_ JDBC, but are // NOTE: The methods shown in this example are _NOT_ JDBC, but are
// an implementation of the calls found in libpq. Unless you need to // 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. // use this functionality, look at the jdbc tests on how to access blobs.
ownapi(); ownapi();
// Now run tests using JDBC methods // Now run tests using JDBC methods
//jdbcapi(db,s); //jdbcapi(db,s);
// Finally close the database // Finally close the database
System.out.println("Now closing the connection"); System.out.println("Now closing the connection");
s.close(); s.close();
db.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();
} }
System.out.println("Cleaning up"); /**
jdbc2api_cleanup(); * 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");
private void jdbc2api_cleanup() throws SQLException // Internally, the driver provides JDBC compliant methods to access large
{ // objects, however the unique methods available to postgresql makes
db.setAutoCommit(true); // things a little easier.
try { System.out.println("Gaining access to large object api");
s.executeUpdate("drop table basic"); lobj = ((org.postgresql.Connection)db).getLargeObjectAPI();
} catch(Exception ex) {
// We ignore any errors here 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);
} }
db.setAutoCommit(false);
}
//======================================================================= private int ownapi_test1() throws FileNotFoundException, IOException, SQLException
{
System.out.println("Test 1 Creating a large object\n");
public static void instructions() // Ok, test 1 is to create a large object. To do this, we use the create
{ // method.
System.err.println("java example.blobtest jdbc-url user password [debug]"); System.out.println("Creating a large object");
System.err.println("\nExamples:\n"); int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
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"); DriverManager.println("got large object oid=" + oid);
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."); LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
} DriverManager.println("got large object obj=" + obj);
public static void main(String args[]) // Now open a test file - this class will do
{ System.out.println("Opening test source object");
System.out.println("PostgreSQL blobtest v7.0 rev 1\n"); FileInputStream fis = new FileInputStream("example/blobtest.java");
if(args.length<3) { // copy the data
instructions(); System.out.println("Copying file to large object");
System.exit(1); 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");
// This line outputs debug information to stderr. To enable this, simply // Close the object
// add an extra parameter to the command line System.out.println("Closing object");
if(args.length>3) obj.close();
DriverManager.setLogStream(System.err);
// Now run the tests return oid;
try { }
blobtest test = new blobtest(args);
} catch(Exception ex) { private void ownapi_test2(int oid) throws FileNotFoundException, IOException, SQLException
System.err.println("Exception caught.\n"+ex); {
ex.printStackTrace(); 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();
}
}
} }

View File

@@ -9,280 +9,340 @@ import org.omg.CosNaming.*;
* *
* It has no GUI, just a text frontend to keep it simple. * 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 public class StockClient
{ {
org.omg.CosNaming.NamingContext nameService; org.omg.CosNaming.NamingContext nameService;
stock.StockDispenser dispenser; stock.StockDispenser dispenser;
stock.StockItem item; stock.StockItem item;
BufferedReader in; BufferedReader in;
public StockClient(String[] args) { public StockClient(String[] args)
try { {
// We need this for our IO try
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)
{ {
case 0: // We need this for our IO
run=false; in = new BufferedReader(new InputStreamReader(System.in));
break;
case 1: // Initialize the orb
displayItem(); org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
break;
case 2: // Get a reference to the Naming Service
bookOut(); org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
break; if (nameServiceObj == null)
{
case 3: System.err.println("nameServiceObj == null");
bookIn(); return ;
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 nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
private void bookIn() { if (nameService == null)
try { {
int id = getMenu("\nStockID to book in",item.getLastID()); System.err.println("nameService == null");
item.fetchItem(id); return ;
System.out.println(item.getDescription()); }
if(item.getOrdered()>0) { // Resolve the dispenser
int am = getMenu("How many do you want to book in",item.getOrdered()); NameComponent[] dispName = {
if(am>0) new NameComponent("StockDispenser", "Stock")
item.addNewStock(am); };
} else dispenser = stock.StockDispenserHelper.narrow(nameService.resolve(dispName));
System.out.println("You don't have any of this item on ordered"); if (dispenser == null)
{
System.err.println("dispenser == null");
return ;
}
} catch(Exception e) { // Now run the front end.
System.out.println(e.toString()); run();
e.printStackTrace(); }
} catch (Exception e)
} {
System.out.println(e.toString());
// Order an item e.printStackTrace();
private void order(int id) { System.exit(1);
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) { public static void main(String[] args)
int v=-1; {
while(v<0 || v>max) { new StockClient(args);
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) { public void run()
try { {
while(true) { // First reserve a StockItem
System.out.print(title); try
System.out.flush(); {
String s = in.readLine(); item = dispenser.reserveItem();
if(s.startsWith("y") || s.startsWith("Y")) }
return true; catch (Exception e)
if(s.startsWith("n") || s.startsWith("N")) {
return false; System.out.println(e.toString());
} e.printStackTrace();
} catch(Exception nfe) { System.exit(1);
System.out.println(nfe.toString()); }
nfe.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 * that an object could be changed by another client, and we need to ensure that
* the returned data is live and accurate. * 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 public class StockDB
{ {
Connection con; Connection con;
Statement st; Statement st;
// the current stock number // the current stock number
int id = -1; int id = -1;
public void connect(String url,String usr,String pwd) throws Exception { public void connect(String url, String usr, String pwd) throws Exception
Class.forName("org.postgresql.Driver"); {
System.out.println("Connecting to "+url); Class.forName("org.postgresql.Driver");
con = DriverManager.getConnection(url,usr,pwd); System.out.println("Connecting to " + url);
st = con.createStatement(); 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;
} }
throw new SQLException("No ResultSet");
}
public int getAvailable() throws SQLException { public void closeConnection() throws Exception
ResultSet rs = st.executeQuery("select avail from stock where id="+id); {
if(rs!=null) { con.close();
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
} }
throw new SQLException("No ResultSet");
}
public int getOrdered() throws SQLException { public void fetchItem(int id) throws Exception
ResultSet rs = st.executeQuery("select ordered from stock where id="+id); {
if(rs!=null) { this.id = id;
rs.next();
int v = rs.getInt(1);
rs.close();
return v;
} }
throw new SQLException("No ResultSet");
}
public boolean isItemValid() throws SQLException { public int newItem() throws Exception
ResultSet rs = st.executeQuery("select valid from stock where id="+id); {
if(rs!=null) { // tba
rs.next(); return -1;
boolean b = rs.getBoolean(1);
rs.close();
return b;
} }
throw new SQLException("No ResultSet");
}
public void addNewStock(int amount) throws SQLException { public String getDescription() throws SQLException
st.executeUpdate("update stock set avail=avail+"+amount+ {
", ordered=ordered-"+amount+ ResultSet rs = st.executeQuery("select description from stock where id=" + id);
" where id="+id+" and ordered>="+amount); if (rs != null)
} {
rs.next();
public void removeStock(int amount) throws SQLException { String s = rs.getString(1);
st.executeUpdate("update stock set avail=avail-"+amount+ rs.close();
" where id="+id); return s;
} }
throw new SQLException("No ResultSet");
public void orderStock(int amount) throws SQLException { }
st.executeUpdate("update stock set ordered=ordered+"+amount+
" where id="+id); public int getAvailable() throws SQLException
} {
ResultSet rs = st.executeQuery("select avail from stock where id=" + id);
public int getLastID() throws SQLException { if (rs != null)
ResultSet rs = st.executeQuery("select max(id) from stock"); {
if(rs!=null) { rs.next();
rs.next(); int v = rs.getInt(1);
int v = rs.getInt(1); rs.close();
rs.close(); return v;
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");
} }
throw new SQLException("No ResultSet");
}
} }

View File

@@ -5,79 +5,88 @@ import org.omg.CosNaming.*;
/** /**
* This class implements the server side of the example. * 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 public class StockDispenserImpl extends stock._StockDispenserImplBase
{ {
private int maxObjects = 10; private int maxObjects = 10;
private int numObjects = 0; private int numObjects = 0;
private StockItemStatus[] stock = new StockItemStatus[maxObjects]; private StockItemStatus[] stock = new StockItemStatus[maxObjects];
public StockDispenserImpl(String[] args,String name,int num) public StockDispenserImpl(String[] args, String name, int num)
{ {
super(); super();
try { try
// get reference to orb {
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null); // get reference to orb
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
// prestart num objects // prestart num objects
if(num>=maxObjects) if (num >= maxObjects)
num=maxObjects; num = maxObjects;
numObjects = num; numObjects = num;
for(int i=0;i<numObjects;i++) { for (int i = 0;i < numObjects;i++)
stock[i] = new StockItemStatus(); {
stock[i].ref = new StockItemImpl(args,"StockItem"+(i+1)); stock[i] = new StockItemStatus();
orb.connect(stock[i].ref); stock[i].ref = new StockItemImpl(args, "StockItem" + (i + 1));
} orb.connect(stock[i].ref);
} catch(org.omg.CORBA.SystemException e) { }
e.printStackTrace(); }
catch (org.omg.CORBA.SystemException e)
{
e.printStackTrace();
}
} }
}
/** /**
* This method, defined in stock.idl, reserves a slot in the dispenser * This method, defined in stock.idl, reserves a slot in the dispenser
*/ */
public stock.StockItem reserveItem() throws stock.StockException public stock.StockItem reserveItem() throws stock.StockException
{ {
for(int i=0;i<numObjects;i++) { for (int i = 0;i < numObjects;i++)
if(!stock[i].inUse) { {
stock[i].inUse = true; if (!stock[i].inUse)
System.out.println("Reserving slot "+i); {
return stock[i].ref; 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 * This releases a slot from the dispenser
*/ */
public void releaseItem(stock.StockItem item) throws stock.StockException public void releaseItem(stock.StockItem item) throws stock.StockException
{ {
for(int i=0;i<numObjects;i++) { for (int i = 0;i < numObjects;i++)
if(stock[i].ref.getInstanceName().equals(item.getInstanceName())) { {
stock[i].inUse = false; if (stock[i].ref.getInstanceName().equals(item.getInstanceName()))
System.out.println("Releasing slot "+i); {
return; 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 * This class defines a slot in the dispenser
*/ */
class StockItemStatus class StockItemStatus
{ {
StockItemImpl ref; StockItemImpl ref;
boolean inUse; boolean inUse;
StockItemStatus() { StockItemStatus()
ref = null; {
inUse = false; ref = null;
inUse = false;
}
} }
}
} }

View File

@@ -5,159 +5,204 @@ import org.omg.CosNaming.*;
/** /**
* This class implements the server side of the example. * 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 public class StockItemImpl extends stock._StockItemImplBase
{ {
private StockDB db; private StockDB db;
private String instanceName; private String instanceName;
public StockItemImpl(String[] args,String iname) { public StockItemImpl(String[] args, String iname)
super(); {
try { super();
db =new StockDB(); try
db.connect(args[1],args[2],args[3]); {
System.out.println("StockDB object "+iname+" created"); db = new StockDB();
instanceName = iname; db.connect(args[1], args[2], args[3]);
} catch(Exception e) { System.out.println("StockDB object " + iname + " created");
e.printStackTrace(); instanceName = iname;
}
catch (Exception e)
{
e.printStackTrace();
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It sets the item to view * It sets the item to view
*/ */
public void fetchItem(int id) throws stock.StockException { public void fetchItem(int id) throws stock.StockException
try { {
db.fetchItem(id); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); db.fetchItem(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It sets the item to view * It sets the item to view
*/ */
public int newItem() throws stock.StockException { public int newItem() throws stock.StockException
try { {
return db.newItem(); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); return db.newItem();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public String getDescription() throws stock.StockException { public String getDescription() throws stock.StockException
try { {
return db.getDescription(); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); return db.getDescription();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public int getAvailable() throws stock.StockException { public int getAvailable() throws stock.StockException
try { {
return db.getAvailable(); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); return db.getAvailable();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public int getOrdered() throws stock.StockException { public int getOrdered() throws stock.StockException
try { {
return db.getOrdered(); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); return db.getOrdered();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public boolean isItemValid() throws stock.StockException { public boolean isItemValid() throws stock.StockException
try { {
return db.isItemValid(); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); return db.isItemValid();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public void addNewStock(int id) throws stock.StockException { public void addNewStock(int id) throws stock.StockException
try { {
db.addNewStock(id); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); db.addNewStock(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public void removeStock(int id) throws stock.StockException { public void removeStock(int id) throws stock.StockException
try { {
db.removeStock(id); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); db.removeStock(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is defined in stock.idl * This is defined in stock.idl
* *
* It returns the description of a Stock item * It returns the description of a Stock item
*/ */
public void orderStock(int id) throws stock.StockException { public void orderStock(int id) throws stock.StockException
try { {
db.orderStock(id); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); db.orderStock(id);
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This returns the highest id used, hence the number of items available * This returns the highest id used, hence the number of items available
*/ */
public int getLastID() throws stock.StockException { public int getLastID() throws stock.StockException
try { {
return db.getLastID(); try
} catch(Exception e) { {
throw new stock.StockException(e.toString()); return db.getLastID();
}
catch (Exception e)
{
throw new stock.StockException(e.toString());
}
} }
}
/** /**
* This is used by our Dispenser * This is used by our Dispenser
*/ */
public String getInstanceName() { public String getInstanceName()
return instanceName; {
} return instanceName;
}
} }

View File

@@ -5,49 +5,54 @@ import org.omg.CosNaming.*;
/** /**
* This class implements the server side of the example. * 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 class StockServer
{ {
public static void main(String[] args) public static void main(String[] args)
{ {
int numInstances = 3; int numInstances = 3;
try { try
// Initialise the ORB {
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null); // Initialise the ORB
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
// Create the StockDispenser object // Create the StockDispenser object
StockDispenserImpl dispenser = new StockDispenserImpl(args,"Stock Dispenser",numInstances); StockDispenserImpl dispenser = new StockDispenserImpl(args, "Stock Dispenser", numInstances);
// Export the new object // Export the new object
orb.connect(dispenser); orb.connect(dispenser);
// Get the naming service // Get the naming service
org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService"); org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
if(nameServiceObj == null) { if (nameServiceObj == null)
System.err.println("nameServiceObj = null"); {
return; System.err.println("nameServiceObj = null");
} return ;
}
org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj); org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
if(nameService == null) { if (nameService == null)
System.err.println("nameService = null"); {
return; System.err.println("nameService = null");
} return ;
}
// bind the dispenser into the naming service // bind the dispenser into the naming service
NameComponent[] dispenserName = { NameComponent[] dispenserName = {
new NameComponent("StockDispenser","Stock") new NameComponent("StockDispenser", "Stock")
}; };
nameService.rebind(dispenserName,dispenser); nameService.rebind(dispenserName, dispenser);
// Now wait forever for the current thread to die // Now wait forever for the current thread to die
Thread.currentThread().join(); Thread.currentThread().join();
} catch(Exception e) { }
e.printStackTrace(); catch (Exception e)
{
e.printStackTrace();
}
} }
}
} }

View File

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

View File

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

View File

@@ -12,202 +12,225 @@ import java.text.*;
public class psql public class psql
{ {
Connection db; // The connection to the database Connection db; // The connection to the database
Statement st; // Our statement to run queries with Statement st; // Our statement to run queries with
DatabaseMetaData dbmd; // This defines the structure of the database DatabaseMetaData dbmd; // This defines the structure of the database
boolean done = false; // Added by CWJ to permit \q command boolean done = false; // Added by CWJ to permit \q command
public psql(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException public psql(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{ {
String url = args[0]; String url = args[0];
String usr = args[1]; String usr = args[1];
String pwd = args[2]; String pwd = args[2];
// Load the driver // Load the driver
Class.forName("org.postgresql.Driver"); Class.forName("org.postgresql.Driver");
// Connect to database // Connect to database
System.out.println("Connecting to Database URL = " + url); System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd); db = DriverManager.getConnection(url, usr, pwd);
dbmd = db.getMetaData(); dbmd = db.getMetaData();
st = db.createStatement(); st = db.createStatement();
// This prints the backend's version // This prints the backend's version
System.out.println("Connected to "+dbmd.getDatabaseProductName()+" "+dbmd.getDatabaseProductVersion()); System.out.println("Connected to " + dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
System.out.println(); System.out.println();
// This provides us the means of reading from stdin // This provides us the means of reading from stdin
StreamTokenizer input = new StreamTokenizer(new InputStreamReader(System.in)); StreamTokenizer input = new StreamTokenizer(new InputStreamReader(System.in));
input.resetSyntax(); input.resetSyntax();
input.slashSlashComments(true); // allow // as a comment delimiter input.slashSlashComments(true); // allow // as a comment delimiter
input.eolIsSignificant(false); // treat eol's as spaces input.eolIsSignificant(false); // treat eol's as spaces
input.wordChars(32,126); input.wordChars(32, 126);
input.whitespaceChars(59,59); input.whitespaceChars(59, 59);
// input.quoteChar(39); *** CWJ: messes up literals in query string *** // input.quoteChar(39); *** CWJ: messes up literals in query string ***
// Now the main loop. // Now the main loop.
int tt=0,lineno=1; int tt = 0, lineno = 1;
while(tt!=StreamTokenizer.TT_EOF && ! done) { // done added by CWJ to permit \q command while (tt != StreamTokenizer.TT_EOF && ! done)
System.out.print("["+lineno+"] "); { // done added by CWJ to permit \q command
System.out.flush(); 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();
// 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(); * This processes a statement
db.close(); */
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 processes a statement {
*/ // This indicates nothing left
public void processLine(String line) throws SQLException loop = false;
{ }
if(line.startsWith("\\")) { else
processSlashCommand(line); {
return; // An update count was returned
} System.out.println("Updated " + st.getUpdateCount() + " rows");
}
}
boolean type = st.execute(line); if (loop)
boolean loop=true; type = st.getMoreResults();
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
* This displays a result set. int cols = rsmd.getColumnCount();
* Note: it closes the result once complete. for (int i = 1;i <= cols;i++)
*/ System.out.print(rsmd.getColumnLabel(i) + (i < cols ? "\t" : "\n"));
public void displayResult(ResultSet rs) throws SQLException
{
ResultSetMetaData rsmd = rs.getMetaData();
// Print the result column names // now the results
int cols = rsmd.getColumnCount(); while (rs.next())
for(int i=1;i<=cols;i++) {
System.out.print(rsmd.getColumnLabel(i)+(i<cols?"\t":"\n")); 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"));
}
}
// now the results // finally close the result set
while(rs.next()) { rs.close();
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 "))
* This process / commands (for now just /d) {
*/ // Display details about a table
public void processSlashCommand(String line) throws SQLException String table = line.substring(3);
{ displayResult(dbmd.getColumns(null, null, table, "%"));
if(line.startsWith("\\d")) { }
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);
if(line.startsWith("\\d ")) { // Display details about all system tables
// Display details about a table //
String table=line.substring(3); // Note: the first two arguments are ignored. To keep to the spec,
displayResult(dbmd.getColumns(null,null,table,"%")); // you must put null here
} else { //
String types[] = null; displayResult(dbmd.getTables(null, null, "%", types));
if(line.equals("\\d")) }
types=allUserTables; }
else if(line.equals("\\di")) else if (line.equals("\\q")) // Added by CWJ to permit \q command
types=usrIndices; done = true;
else if(line.equals("\\dt")) else
types=usrTables; throw new SQLException("Unsupported \\ command: " + line);
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 private static final String allUserTables[] = {"TABLE", "INDEX", "SEQUENCE"};
// private static final String usrIndices[] = {"INDEX"};
// Note: the first two arguments are ignored. To keep to the spec, private static final String usrTables[] = {"TABLE"};
// you must put null here private static final String usrSequences[] = {"SEQUENCE"};
// private static final String sysTables[] = {"SYSTEM TABLE", "SYSTEM INDEX"};
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"}; * Display some instructions on how to run the example
private static final String usrTables[] = {"TABLE"}; */
private static final String usrSequences[] = {"SEQUENCE"}; public static void instructions()
private static final String sysTables[] = {"SYSTEM TABLE","SYSTEM INDEX"}; {
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);
}
/** /**
* Display some instructions on how to run the example * This little lot starts the test
*/ */
public static void instructions() public static void main(String args[])
{ {
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("PostgreSQL psql example v6.3 rev 1\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);
}
/** if (args.length < 3)
* This little lot starts the test instructions();
*/
public static void main(String args[])
{
System.out.println("PostgreSQL psql example v6.3 rev 1\n");
if(args.length<3) // This line outputs debug information to stderr. To enable this, simply
instructions(); // add an extra parameter to the command line
if (args.length > 3)
DriverManager.setLogStream(System.err);
// This line outputs debug information to stderr. To enable this, simply // Now run the tests
// add an extra parameter to the command line try
if(args.length>3) {
DriverManager.setLogStream(System.err); psql test = new psql(args);
}
// Now run the tests catch (Exception ex)
try { {
psql test = new psql(args); System.err.println("Exception caught.\n" + ex);
} catch(Exception ex) { ex.printStackTrace();
System.err.println("Exception caught.\n"+ex); }
ex.printStackTrace(); }
}
}
} }

View File

@@ -18,350 +18,388 @@ import org.postgresql.largeobject.*;
public class threadsafe public class threadsafe
{ {
Connection db; // The connection to the database Connection db; // The connection to the database
Statement st; // Our statement to run queries with Statement st; // Our statement to run queries with
public threadsafe(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException public threadsafe(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{ {
String url = args[0]; String url = args[0];
String usr = args[1]; String usr = args[1];
String pwd = args[2]; String pwd = args[2];
// Load the driver // Load the driver
Class.forName("org.postgresql.Driver"); Class.forName("org.postgresql.Driver");
// Connect to database // Connect to database
System.out.println("Connecting to Database URL = " + url); System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd); db = DriverManager.getConnection(url, usr, pwd);
System.out.println("Connected...Now creating a statement"); System.out.println("Connected...Now creating a statement");
st = db.createStatement(); st = db.createStatement();
// Clean up the database (in case we failed earlier) then initialise // Clean up the database (in case we failed earlier) then initialise
cleanup(); cleanup();
// Because we use LargeObjects, we must use Transactions // Because we use LargeObjects, we must use Transactions
db.setAutoCommit(false); db.setAutoCommit(false);
// Now run tests using JDBC methods, then LargeObjects // Now run tests using JDBC methods, then LargeObjects
doexample(); doexample();
// Clean up the database // Clean up the database
cleanup(); cleanup();
// Finally close the database // Finally close the database
System.out.println("Now closing the connection"); System.out.println("Now closing the connection");
st.close(); st.close();
db.close(); db.close();
} }
/** /**
* This drops the table (if it existed). No errors are reported. * This drops the table (if it existed). No errors are reported.
*/ */
public void cleanup() public void cleanup()
{ {
try { try
st.executeUpdate("drop table basic1"); {
} catch(Exception ex) { st.executeUpdate("drop table basic1");
// We ignore any errors here }
} catch (Exception ex)
{
// We ignore any errors here
}
try { try
st.executeUpdate("drop table basic2"); {
} catch(Exception ex) { st.executeUpdate("drop table basic2");
// We ignore any errors here }
} catch (Exception ex)
} {
// We ignore any errors here
}
}
/** /**
* This performs the example * This performs the example
*/ */
public void doexample() throws SQLException 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"); 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; thread3 thread3 = null;
try { try
{
// create the two threads // create the two threads
Thread thread0 = Thread.currentThread(); Thread thread0 = Thread.currentThread();
Thread thread1 = new thread1(db); Thread thread1 = new thread1(db);
Thread thread2 = new thread2(db); Thread thread2 = new thread2(db);
thread3 = new thread3(db); thread3 = new thread3(db);
// now run, and wait for them // now run, and wait for them
thread1.start(); thread1.start();
thread2.start(); thread2.start();
thread3.start(); thread3.start();
// ok, I know this is bad, but it does the trick here as our main thread // 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 // will yield as long as either of the children are still running
System.out.println("Waiting for threads to run"); System.out.println("Waiting for threads to run");
while(thread1.isAlive() || thread2.isAlive() || thread3.isAlive()) while (thread1.isAlive() || thread2.isAlive() || thread3.isAlive())
thread0.yield(); thread0.yield();
} finally { }
// clean up after thread3 (the finally ensures this is run even finally
// if an exception is thrown inside the try { } construct) {
if(thread3 != null) // clean up after thread3 (the finally ensures this is run even
thread3.cleanup(); // 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."); 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 // This is the first thread. It's the same as the basic test
class thread1 extends Thread class thread1 extends Thread
{ {
Connection c; Connection c;
Statement st; Statement st;
public thread1(Connection c) throws SQLException { public thread1(Connection c) throws SQLException
this.c = c; {
st = c.createStatement(); this.c = c;
} st = c.createStatement();
}
public void run() { public void run()
try { {
System.out.println("Thread 1 running..."); try
{
System.out.println("Thread 1 running...");
// First we need a table to store data in // First we need a table to store data in
st.executeUpdate("create table basic1 (a int2, b int2)"); st.executeUpdate("create table basic1 (a int2, b int2)");
// Now insert some data, using the Statement // Now insert some data, using the Statement
st.executeUpdate("insert into basic1 values (1,1)"); st.executeUpdate("insert into basic1 values (1,1)");
st.executeUpdate("insert into basic1 values (2,1)"); st.executeUpdate("insert into basic1 values (2,1)");
st.executeUpdate("insert into basic1 values (3,1)"); st.executeUpdate("insert into basic1 values (3,1)");
// For large inserts, a PreparedStatement is more efficient, because it // For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store // supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support // directly, a Java object into any column. PostgreSQL doesnt support
// precompiling, but does support setting a column to the value of a // precompiling, but does support setting a column to the value of a
// Java object (like Date, String, etc). // 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 // The purpose of this is to test that FastPath will work in between normal
// manner. (DateStyles are PostgreSQL's way of handling different methods // JDBC queries.
// of representing dates in the Date data type.) class thread3 extends Thread
PreparedStatement ps = db.prepareStatement("insert into basic1 values (?,?)"); {
for(int i=2;i<2000;i++) { Connection c;
ps.setInt(1,4); // "column a" = 5 Statement st;
ps.setInt(2,i); // "column b" = i LargeObjectManager lom;
ps.executeUpdate(); // executeUpdate because insert returns no data LargeObject lo;
// c.commit(); int oid;
if((i%50)==0)
DriverManager.println("Thread 1 done "+i+" inserts"); 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"); * Display some instructions on how to run the example
ResultSet rs = st.executeQuery("select a, b from basic1"); */
int cnt=0; public static void instructions()
if(rs!=null) { {
// Now we run through the result set, printing out the result. 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");
// Note, we must call .next() before attempting to read any results 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.");
while(rs.next()) { System.exit(1);
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. * This little lot starts the test
System.out.println("Thread 1 finished"); */
} catch(SQLException se) { public static void main(String args[])
System.err.println("Thread 1: "+se.toString()); {
se.printStackTrace(); System.out.println("PostgreSQL Thread Safety test v6.4 rev 1\n");
System.exit(1);
}
}
}
// This is the second thread. It's the similar to the basic test, and thread1 if (args.length < 3)
// except it works on another table. instructions();
class thread2 extends Thread
{
Connection c;
Statement st;
public thread2(Connection c) throws SQLException { // This line outputs debug information to stderr. To enable this, simply
this.c = c; // add an extra parameter to the command line
st = c.createStatement(); if (args.length > 3)
} DriverManager.setLogStream(System.err);
public void run() { // Now run the tests
try { try
System.out.println("Thread 2 running..."); {
threadsafe test = new threadsafe(args);
// First we need a table to store data in }
st.executeUpdate("create table basic2 (a int2, b int2)"); catch (Exception ex)
{
// For large inserts, a PreparedStatement is more efficient, because it System.err.println("Exception caught.\n" + ex);
// supports the idea of precompiling the SQL statement, and to store ex.printStackTrace();
// 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.
//
// 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 public class Field
{ {
private int length; // Internal Length of this field private int length; // Internal Length of this field
private int oid; // OID of the type private int oid; // OID of the type
private int mod; // type modifier of this field private int mod; // type modifier of this field
private String name; // Name 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. * Construct a field based on the information fed to it.
* *
* @param conn the connection this field came from * @param conn the connection this field came from
* @param name the name of the field * @param name the name of the field
* @param oid the OID of the field * @param oid the OID of the field
* @param len the length of the field * @param len the length of the field
*/ */
public Field(Connection conn, String name, int oid, int length,int mod) public Field(Connection conn, String name, int oid, int length, int mod)
{ {
this.conn = conn; this.conn = conn;
this.name = name; this.name = name;
this.oid = oid; this.oid = oid;
this.length = length; this.length = length;
this.mod = mod; this.mod = mod;
} }
/** /**
* Constructor without mod parameter. * Constructor without mod parameter.
* *
* @param conn the connection this field came from * @param conn the connection this field came from
* @param name the name of the field * @param name the name of the field
* @param oid the OID of the field * @param oid the OID of the field
* @param len the length of the field * @param len the length of the field
*/ */
public Field(Connection conn, String name, int oid, int length) public Field(Connection conn, String name, int oid, int length)
{ {
this(conn,name,oid,length,0); this(conn, name, oid, length, 0);
} }
/** /**
* @return the oid of this Field's data type * @return the oid of this Field's data type
*/ */
public int getOID() public int getOID()
{ {
return oid; return oid;
} }
/** /**
* @return the mod of this Field's data type * @return the mod of this Field's data type
*/ */
public int getMod() public int getMod()
{ {
return mod; return mod;
} }
/** /**
* @return the name of this Field's data type * @return the name of this Field's data type
*/ */
public String getName() public String getName()
{ {
return name; return name;
} }
/** /**
* @return the length of this Field's data type * @return the length of this Field's data type
*/ */
public int getLength() public int getLength()
{ {
return length; return length;
} }
/** /**
* We also need to get the PG type name as returned by the back end. * 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 * @return the String representation of the PG type of this field
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public String getPGType() throws SQLException public String getPGType() throws SQLException
{ {
return conn.getPGType(oid); return conn.getPGType(oid);
} }
/** /**
* We also need to get the java.sql.types type. * We also need to get the java.sql.types type.
* *
* @return the int representation of the java.sql.types type of this field * @return the int representation of the java.sql.types type of this field
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public int getSQLType() throws SQLException public int getSQLType() throws SQLException
{ {
return conn.getSQLType(oid); return conn.getSQLType(oid);
} }
} }

View File

@@ -10,345 +10,366 @@ import org.postgresql.core.*;
import org.postgresql.util.*; 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 * This class is used by Connection & PGlobj for communicating with the
* backend. * backend.
* *
* @see java.sql.Connection * @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 public class PG_Stream
{ {
private Socket connection; private Socket connection;
private InputStream pg_input; private InputStream pg_input;
private BufferedOutputStream pg_output; private BufferedOutputStream pg_output;
private byte[] byte_buf = new byte[8*1024]; private byte[] byte_buf = new byte[8*1024];
BytePoolDim1 bytePoolDim1 = new BytePoolDim1(); BytePoolDim1 bytePoolDim1 = new BytePoolDim1();
BytePoolDim2 bytePoolDim2 = new BytePoolDim2(); BytePoolDim2 bytePoolDim2 = new BytePoolDim2();
/** /**
* Constructor: Connect to the PostgreSQL back end and return * Constructor: Connect to the PostgreSQL back end and return
* a stream connection. * a stream connection.
* *
* @param host the hostname to connect to * @param host the hostname to connect to
* @param port the port number that the postmaster is sitting on * @param port the port number that the postmaster is sitting on
* @exception IOException if an IOException occurs below it. * @exception IOException if an IOException occurs below it.
*/ */
public PG_Stream(String host, int port) throws IOException public PG_Stream(String host, int port) throws IOException
{ {
connection = new Socket(host, port); connection = new Socket(host, port);
// Submitted by Jason Venner <jason@idiom.com> adds a 10x speed // Submitted by Jason Venner <jason@idiom.com> adds a 10x speed
// improvement on FreeBSD machines (caused by a bug in their TCP Stack) // improvement on FreeBSD machines (caused by a bug in their TCP Stack)
connection.setTcpNoDelay(true); connection.setTcpNoDelay(true);
// Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no> // Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
pg_input = new BufferedInputStream(connection.getInputStream(), 8192); pg_input = new BufferedInputStream(connection.getInputStream(), 8192);
pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192); pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
} }
/** /**
* Sends a single character to the back end * Sends a single character to the back end
* *
* @param val the character to be sent * @param val the character to be sent
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
*/ */
public void SendChar(int val) throws IOException public void SendChar(int val) throws IOException
{ {
pg_output.write((byte)val); pg_output.write((byte)val);
} }
/** /**
* Sends an integer to the back end * Sends an integer to the back end
* *
* @param val the integer to be sent * @param val the integer to be sent
* @param siz the length of the integer in bytes (size of structure) * @param siz the length of the integer in bytes (size of structure)
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
*/ */
public void SendInteger(int val, int siz) throws IOException public void SendInteger(int val, int siz) throws IOException
{ {
byte[] buf = bytePoolDim1.allocByte(siz); byte[] buf = bytePoolDim1.allocByte(siz);
while (siz-- > 0) while (siz-- > 0)
{ {
buf[siz] = (byte)(val & 0xff); buf[siz] = (byte)(val & 0xff);
val >>= 8; val >>= 8;
} }
Send(buf); Send(buf);
} }
/** /**
* Send an array of bytes to the backend * Send an array of bytes to the backend
* *
* @param buf The array of bytes to be sent * @param buf The array of bytes to be sent
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
*/ */
public void Send(byte buf[]) throws IOException public void Send(byte buf[]) throws IOException
{ {
pg_output.write(buf); pg_output.write(buf);
} }
/** /**
* Send an exact array of bytes to the backend - if the length * Send an exact array of bytes to the backend - if the length
* has not been reached, send nulls until it has. * has not been reached, send nulls until it has.
* *
* @param buf the array of bytes to be sent * @param buf the array of bytes to be sent
* @param siz the number of bytes to be sent * @param siz the number of bytes to be sent
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
*/ */
public void Send(byte buf[], int siz) throws IOException public void Send(byte buf[], int siz) throws IOException
{ {
Send(buf,0,siz); Send(buf, 0, siz);
} }
/** /**
* Send an exact array of bytes to the backend - if the length * Send an exact array of bytes to the backend - if the length
* has not been reached, send nulls until it has. * has not been reached, send nulls until it has.
* *
* @param buf the array of bytes to be sent * @param buf the array of bytes to be sent
* @param off offset in the array to start sending from * @param off offset in the array to start sending from
* @param siz the number of bytes to be sent * @param siz the number of bytes to be sent
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
*/ */
public void Send(byte buf[], int off, int siz) throws IOException public void Send(byte buf[], int off, int siz) throws IOException
{ {
int i; int i;
pg_output.write(buf, off, ((buf.length-off) < siz ? (buf.length-off) : siz)); pg_output.write(buf, off, ((buf.length - off) < siz ? (buf.length - off) : siz));
if((buf.length-off) < siz) if ((buf.length - off) < siz)
{ {
for (i = buf.length-off ; i < siz ; ++i) for (i = buf.length - off ; i < siz ; ++i)
{ {
pg_output.write(0); pg_output.write(0);
} }
} }
} }
/** /**
* Receives a single character from the backend * Receives a single character from the backend
* *
* @return the character received * @return the character received
* @exception SQLException if an I/O Error returns * @exception SQLException if an I/O Error returns
*/ */
public int ReceiveChar() throws SQLException public int ReceiveChar() throws SQLException
{ {
int c = 0; int c = 0;
try try
{ {
c = pg_input.read(); c = pg_input.read();
if (c < 0) throw new PSQLException("postgresql.stream.eof"); if (c < 0)
} catch (IOException e) { throw new PSQLException("postgresql.stream.eof");
throw new PSQLException("postgresql.stream.ioerror",e); }
} catch (IOException e)
return c; {
} throw new PSQLException("postgresql.stream.ioerror", e);
}
return c;
}
/** /**
* Receives an integer from the backend * Receives an integer from the backend
* *
* @param siz length of the integer in bytes * @param siz length of the integer in bytes
* @return the integer received from the backend * @return the integer received from the backend
* @exception SQLException if an I/O error occurs * @exception SQLException if an I/O error occurs
*/ */
public int ReceiveInteger(int siz) throws SQLException public int ReceiveInteger(int siz) throws SQLException
{ {
int n = 0; int n = 0;
try try
{ {
for (int i = 0 ; i < siz ; i++) for (int i = 0 ; i < siz ; i++)
{ {
int b = pg_input.read(); int b = pg_input.read();
if (b < 0) if (b < 0)
throw new PSQLException("postgresql.stream.eof"); throw new PSQLException("postgresql.stream.eof");
n = n | (b << (8 * i)) ; n = n | (b << (8 * i)) ;
} }
} catch (IOException e) { }
throw new PSQLException("postgresql.stream.ioerror",e); catch (IOException e)
} {
return n; throw new PSQLException("postgresql.stream.ioerror", e);
} }
return n;
}
/** /**
* Receives an integer from the backend * Receives an integer from the backend
* *
* @param siz length of the integer in bytes * @param siz length of the integer in bytes
* @return the integer received from the backend * @return the integer received from the backend
* @exception SQLException if an I/O error occurs * @exception SQLException if an I/O error occurs
*/ */
public int ReceiveIntegerR(int siz) throws SQLException public int ReceiveIntegerR(int siz) throws SQLException
{ {
int n = 0; int n = 0;
try try
{ {
for (int i = 0 ; i < siz ; i++) for (int i = 0 ; i < siz ; i++)
{ {
int b = pg_input.read(); int b = pg_input.read();
if (b < 0) if (b < 0)
throw new PSQLException("postgresql.stream.eof"); throw new PSQLException("postgresql.stream.eof");
n = b | (n << 8); n = b | (n << 8);
} }
} catch (IOException e) { }
throw new PSQLException("postgresql.stream.ioerror",e); catch (IOException e)
} {
return n; throw new PSQLException("postgresql.stream.ioerror", e);
} }
return n;
}
/** /**
* Receives a null-terminated string from the backend. If we don't see a * Receives a null-terminated string from the backend. If we don't see a
* null, then we assume something has gone wrong. * null, then we assume something has gone wrong.
* *
* @param encoding the charset encoding to use. * @param encoding the charset encoding to use.
* @return string from back end * @return string from back end
* @exception SQLException if an I/O error occurs, or end of file * @exception SQLException if an I/O error occurs, or end of file
*/ */
public String ReceiveString(Encoding encoding) public String ReceiveString(Encoding encoding)
throws SQLException throws SQLException
{ {
int s = 0; int s = 0;
byte[] rst = byte_buf; byte[] rst = byte_buf;
try { try
int buflen = rst.length; {
boolean done = false; int buflen = rst.length;
while (!done) { boolean done = false;
while (s < buflen) { while (!done)
int c = pg_input.read(); {
if (c < 0) while (s < buflen)
throw new PSQLException("postgresql.stream.eof"); {
else if (c == 0) { int c = pg_input.read();
rst[s] = 0; if (c < 0)
done = true; throw new PSQLException("postgresql.stream.eof");
break; else if (c == 0)
} else { {
rst[s++] = (byte)c; rst[s] = 0;
} done = true;
if (s >= buflen) { // Grow the buffer break;
buflen = (int)(buflen*2); // 100% bigger }
byte[] newrst = new byte[buflen]; else
System.arraycopy(rst, 0, newrst, 0, s); {
rst = newrst; rst[s++] = (byte)c;
} }
} if (s >= buflen)
} { // Grow the buffer
} catch (IOException e) { buflen = (int)(buflen * 2); // 100% bigger
throw new PSQLException("postgresql.stream.ioerror",e); byte[] newrst = new byte[buflen];
} System.arraycopy(rst, 0, newrst, 0, s);
return encoding.decode(rst, 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 * Read a tuple from the back end. A tuple is a two dimensional
* array of bytes * array of bytes
* *
* @param nf the number of fields expected * @param nf the number of fields expected
* @param bin true if the tuple is a binary tuple * @param bin true if the tuple is a binary tuple
* @return null if the current response has no more tuples, otherwise * @return null if the current response has no more tuples, otherwise
* an array of strings * an array of strings
* @exception SQLException if a data I/O error occurs * @exception SQLException if a data I/O error occurs
*/ */
public byte[][] ReceiveTuple(int nf, boolean bin) throws SQLException public byte[][] ReceiveTuple(int nf, boolean bin) throws SQLException
{ {
int i, bim = (nf + 7)/8; int i, bim = (nf + 7) / 8;
byte[] bitmask = Receive(bim); byte[] bitmask = Receive(bim);
byte[][] answer = bytePoolDim2.allocByte(nf); byte[][] answer = bytePoolDim2.allocByte(nf);
int whichbit = 0x80; int whichbit = 0x80;
int whichbyte = 0; int whichbyte = 0;
for (i = 0 ; i < nf ; ++i) for (i = 0 ; i < nf ; ++i)
{ {
boolean isNull = ((bitmask[whichbyte] & whichbit) == 0); boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
whichbit >>= 1; whichbit >>= 1;
if (whichbit == 0) if (whichbit == 0)
{ {
++whichbyte; ++whichbyte;
whichbit = 0x80; whichbit = 0x80;
} }
if (isNull) if (isNull)
answer[i] = null; answer[i] = null;
else else
{ {
int len = ReceiveIntegerR(4); int len = ReceiveIntegerR(4);
if (!bin) if (!bin)
len -= 4; len -= 4;
if (len < 0) if (len < 0)
len = 0; len = 0;
answer[i] = Receive(len); answer[i] = Receive(len);
} }
} }
return answer; return answer;
} }
/** /**
* Reads in a given number of bytes from the backend * Reads in a given number of bytes from the backend
* *
* @param siz number of bytes to read * @param siz number of bytes to read
* @return array of bytes received * @return array of bytes received
* @exception SQLException if a data I/O error occurs * @exception SQLException if a data I/O error occurs
*/ */
private byte[] Receive(int siz) throws SQLException private byte[] Receive(int siz) throws SQLException
{ {
byte[] answer = bytePoolDim1.allocByte(siz); byte[] answer = bytePoolDim1.allocByte(siz);
Receive(answer,0,siz); Receive(answer, 0, siz);
return answer; return answer;
} }
/** /**
* Reads in a given number of bytes from the backend * Reads in a given number of bytes from the backend
* *
* @param buf buffer to store result * @param buf buffer to store result
* @param off offset in buffer * @param off offset in buffer
* @param siz number of bytes to read * @param siz number of bytes to read
* @exception SQLException if a data I/O error occurs * @exception SQLException if a data I/O error occurs
*/ */
public void Receive(byte[] b,int off,int siz) throws SQLException public void Receive(byte[] b, int off, int siz) throws SQLException
{ {
int s = 0; int s = 0;
try try
{ {
while (s < siz) while (s < siz)
{ {
int w = pg_input.read(b, off+s, siz - s); int w = pg_input.read(b, off + s, siz - s);
if (w < 0) if (w < 0)
throw new PSQLException("postgresql.stream.eof"); throw new PSQLException("postgresql.stream.eof");
s += w; s += w;
} }
} catch (IOException e) { }
throw new PSQLException("postgresql.stream.ioerror",e); catch (IOException e)
} {
} throw new PSQLException("postgresql.stream.ioerror", e);
}
}
/** /**
* This flushes any pending output to the backend. It is used primarily * This flushes any pending output to the backend. It is used primarily
* by the Fastpath code. * by the Fastpath code.
* @exception SQLException if an I/O error occurs * @exception SQLException if an I/O error occurs
*/ */
public void flush() throws SQLException public void flush() throws SQLException
{ {
try { try
pg_output.flush(); {
} catch (IOException e) { pg_output.flush();
throw new PSQLException("postgresql.stream.flush",e); }
} catch (IOException e)
} {
throw new PSQLException("postgresql.stream.flush", e);
}
}
/** /**
* Closes the connection * Closes the connection
* *
* @exception IOException if a IO Error occurs * @exception IOException if a IO Error occurs
*/ */
public void close() throws IOException public void close() throws IOException
{ {
pg_output.close(); pg_output.close();
pg_input.close(); pg_input.close();
connection.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 public abstract class ResultSet
{ {
protected Vector rows; // The results protected Vector rows; // The results
protected Field fields[]; // The field descriptions protected Field fields[]; // The field descriptions
protected String status; // Status of the result protected String status; // Status of the result
protected boolean binaryCursor = false; // is the data binary or Strings protected boolean binaryCursor = false; // is the data binary or Strings
protected int updateCount; // How many rows did we get back? protected int updateCount; // How many rows did we get back?
protected int insertOID; // The oid of an inserted row protected int insertOID; // The oid of an inserted row
protected int current_row; // Our pointer to where we are at protected int current_row; // Our pointer to where we are at
protected byte[][] this_row; // the current row result protected byte[][] this_row; // the current row result
protected Connection connection; // the connection which we returned from protected Connection connection; // the connection which we returned from
protected SQLWarning warnings = null; // The warning chain protected SQLWarning warnings = null; // The warning chain
protected boolean wasNullFlag = false; // the flag for wasNull() protected boolean wasNullFlag = false; // the flag for wasNull()
// We can chain multiple resultSets together - this points to // We can chain multiple resultSets together - this points to
// next resultSet in the chain. // next resultSet in the chain.
protected ResultSet next = null; protected ResultSet next = null;
/** /**
* Create a new ResultSet - Note that we create ResultSets to * Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything. * represent the results of everything.
* *
* @param fields an array of Field objects (basically, the * @param fields an array of Field objects (basically, the
* ResultSet MetaData) * ResultSet MetaData)
* @param tuples Vector of the actual data * @param tuples Vector of the actual data
* @param status the status string returned from the back end * @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation * @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name * @param cursor the positioned update/delete cursor name
*/ */
public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount,int insertOID, boolean binaryCursor) public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount, int insertOID, boolean binaryCursor)
{ {
this.connection = conn; this.connection = conn;
this.fields = fields; this.fields = fields;
this.rows = tuples; this.rows = tuples;
this.status = status; this.status = status;
this.updateCount = updateCount; this.updateCount = updateCount;
this.insertOID = insertOID; this.insertOID = insertOID;
this.this_row = null; this.this_row = null;
this.current_row = -1; this.current_row = -1;
this.binaryCursor = binaryCursor; this.binaryCursor = binaryCursor;
} }
/** /**
* Create a new ResultSet - Note that we create ResultSets to * Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything. * represent the results of everything.
* *
* @param fields an array of Field objects (basically, the * @param fields an array of Field objects (basically, the
* ResultSet MetaData) * ResultSet MetaData)
* @param tuples Vector of the actual data * @param tuples Vector of the actual data
* @param status the status string returned from the back end * @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation * @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name * @param cursor the positioned update/delete cursor name
*/ */
public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount) public ResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
{ {
this(conn,fields,tuples,status,updateCount,0,false); this(conn, fields, tuples, status, updateCount, 0, false);
} }
/** /**
* We at times need to know if the resultSet we are working * We at times need to know if the resultSet we are working
* with is the result of an UPDATE, DELETE or INSERT (in which * with is the result of an UPDATE, DELETE or INSERT (in which
* case, we only have a row count), or of a SELECT operation * case, we only have a row count), or of a SELECT operation
* (in which case, we have multiple fields) - this routine * (in which case, we have multiple fields) - this routine
* tells us. * tells us.
* *
* @return true if we have tuples available * @return true if we have tuples available
*/ */
public boolean reallyResultSet() public boolean reallyResultSet()
{ {
return (fields != null); return (fields != null);
} }
/** /**
* Since ResultSets can be chained, we need some method of * Since ResultSets can be chained, we need some method of
* finding the next one in the chain. The method getNext() * finding the next one in the chain. The method getNext()
* returns the next one in the chain. * returns the next one in the chain.
* *
* @return the next ResultSet, or null if there are none * @return the next ResultSet, or null if there are none
*/ */
public java.sql.ResultSet getNext() public java.sql.ResultSet getNext()
{ {
return (java.sql.ResultSet)next; return (java.sql.ResultSet)next;
} }
/** /**
* This following method allows us to add a ResultSet object * This following method allows us to add a ResultSet object
* to the end of the current chain. * to the end of the current chain.
* *
* @param r the resultset to add to the end of the chain. * @param r the resultset to add to the end of the chain.
*/ */
public void append(ResultSet r) public void append(ResultSet r)
{ {
if (next == null) if (next == null)
next = r; next = r;
else else
next.append(r); next.append(r);
} }
/** /**
* If we are just a place holder for results, we still need * If we are just a place holder for results, we still need
* to get an updateCount. This method returns it. * to get an updateCount. This method returns it.
* *
* @return the updateCount * @return the updateCount
*/ */
public int getResultCount() public int getResultCount()
{ {
return updateCount; return updateCount;
} }
/** /**
* We also need to provide a couple of auxiliary functions for * We also need to provide a couple of auxiliary functions for
* the implementation of the ResultMetaData functions. In * the implementation of the ResultMetaData functions. In
* particular, we need to know the number of rows and the * particular, we need to know the number of rows and the
* number of columns. Rows are also known as Tuples * number of columns. Rows are also known as Tuples
* *
* @return the number of rows * @return the number of rows
*/ */
public int getTupleCount() public int getTupleCount()
{ {
return rows.size(); return rows.size();
} }
/** /**
* getColumnCount returns the number of columns * getColumnCount returns the number of columns
* *
* @return the number of columns * @return the number of columns
*/ */
public int getColumnCount() public int getColumnCount()
{ {
return fields.length; return fields.length;
} }
/** /**
* Returns the status message from the backend.<p> * Returns the status message from the backend.<p>
* It is used internally by the driver. * It is used internally by the driver.
* *
* @return the status string from the backend * @return the status string from the backend
*/ */
public String getStatusString() public String getStatusString()
{ {
return status; return status;
} }
/** /**
* returns the OID of a field.<p> * returns the OID of a field.<p>
* It is used internally by the driver. * It is used internally by the driver.
* *
* @param field field id * @param field field id
* @return the oid of that field's type * @return the oid of that field's type
*/ */
public int getColumnOID(int field) public int getColumnOID(int field)
{ {
return fields[field-1].getOID(); return fields[field -1].getOID();
} }
/** /**
* returns the OID of the last inserted row * returns the OID of the last inserted row
*/ */
public int getInsertedOID() public int getInsertedOID()
{ {
return insertOID; return insertOID;
} }
/** /**
* This is part of the JDBC API, but is required by org.postgresql.Field * This is part of the JDBC API, but is required by org.postgresql.Field
*/ */
public abstract void close() throws SQLException; public abstract void close() throws SQLException;
public abstract boolean next() throws SQLException; public abstract boolean next() throws SQLException;
public abstract String getString(int i) throws SQLException; public abstract String getString(int i) throws SQLException;
/** /**
* This is used to fix get*() methods on Money fields. It should only be * This is used to fix get*() methods on Money fields. It should only be
* used by those methods! * used by those methods!
* *
* It converts ($##.##) to -##.## and $##.## to ##.## * It converts ($##.##) to -##.## and $##.## to ##.##
*/ */
public String getFixedString(int col) throws SQLException { public String getFixedString(int col) throws SQLException
String s = getString(col); {
String s = getString(col);
// Handle SQL Null // Handle SQL Null
wasNullFlag = (this_row[col - 1] == null); wasNullFlag = (this_row[col - 1] == null);
if(wasNullFlag) if (wasNullFlag)
return null; return null;
// Handle Money // Handle Money
if(s.charAt(0)=='(') { if (s.charAt(0) == '(')
s="-"+org.postgresql.util.PGtokenizer.removePara(s).substring(1); {
} s = "-" + org.postgresql.util.PGtokenizer.removePara(s).substring(1);
if(s.charAt(0)=='$') { }
s=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. * JDBC3.
*/ */
public abstract class Statement { public abstract class Statement
{
/** The warnings chain. */ /** The warnings chain. */
protected SQLWarning warnings = null; protected SQLWarning warnings = null;
/** The current results */ /** The current results */
protected java.sql.ResultSet result = null; protected java.sql.ResultSet result = null;
/** Maximum number of rows to return, 0 = unlimited */ /** Maximum number of rows to return, 0 = unlimited */
protected int maxrows = 0; protected int maxrows = 0;
/** Timeout (in seconds) for a query (not used) */ /** Timeout (in seconds) for a query (not used) */
protected int timeout = 0; protected int timeout = 0;
protected boolean escapeProcessing = true; protected boolean escapeProcessing = true;
// Static variables for parsing SQL when escapeProcessing is true. // Static variables for parsing SQL when escapeProcessing is true.
private static final short IN_SQLCODE = 0; private static final short IN_SQLCODE = 0;
private static final short IN_STRING = 1; private static final short IN_STRING = 1;
private static final short BACKSLASH =2; private static final short BACKSLASH = 2;
private static final short ESC_TIMEDATE = 3; private static final short ESC_TIMEDATE = 3;
public Statement() { public Statement()
} {}
/** /**
* Returns the status message from the current Result.<p> * Returns the status message from the current Result.<p>
* This is used internally by the driver. * This is used internally by the driver.
* *
* @return status message from backend * @return status message from backend
*/ */
public String getResultStatusString() { public String getResultStatusString()
if (result == null) {
return null; if (result == null)
return ((org.postgresql.ResultSet) result).getStatusString(); return null;
} return ((org.postgresql.ResultSet) result).getStatusString();
}
/** /**
* The maxRows limit is set to limit the number of rows that * The maxRows limit is set to limit the number of rows that
* any ResultSet can contain. If the limit is exceeded, the * any ResultSet can contain. If the limit is exceeded, the
* excess rows are silently dropped. * excess rows are silently dropped.
* *
* @return the current maximum row limit; zero means unlimited * @return the current maximum row limit; zero means unlimited
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public int getMaxRows() throws SQLException { public int getMaxRows() throws SQLException
return maxrows; {
} return maxrows;
}
/** /**
* Set the maximum number of rows * Set the maximum number of rows
* *
* @param max the new max rows limit; zero means unlimited * @param max the new max rows limit; zero means unlimited
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
* @see getMaxRows * @see getMaxRows
*/ */
public void setMaxRows(int max) throws SQLException { public void setMaxRows(int max) throws SQLException
maxrows = max; {
} maxrows = max;
}
/** /**
* If escape scanning is on (the default), the driver will do escape * If escape scanning is on (the default), the driver will do escape
* substitution before sending the SQL to the database. * substitution before sending the SQL to the database.
* *
* @param enable true to enable; false to disable * @param enable true to enable; false to disable
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public void setEscapeProcessing(boolean enable) throws SQLException { public void setEscapeProcessing(boolean enable) throws SQLException
escapeProcessing = enable; {
} escapeProcessing = enable;
}
/** /**
* The queryTimeout limit is the number of seconds the driver * The queryTimeout limit is the number of seconds the driver
* will wait for a Statement to execute. If the limit is * will wait for a Statement to execute. If the limit is
* exceeded, a SQLException is thrown. * exceeded, a SQLException is thrown.
* *
* @return the current query timeout limit in seconds; 0 = unlimited * @return the current query timeout limit in seconds; 0 = unlimited
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public int getQueryTimeout() throws SQLException { public int getQueryTimeout() throws SQLException
return timeout; {
} return timeout;
}
/** /**
* Sets the queryTimeout limit * Sets the queryTimeout limit
* *
* @param seconds - the new query timeout limit in seconds * @param seconds - the new query timeout limit in seconds
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public void setQueryTimeout(int seconds) throws SQLException { public void setQueryTimeout(int seconds) throws SQLException
timeout = seconds; {
} timeout = seconds;
}
/** /**
* The first warning reported by calls on this Statement is * The first warning reported by calls on this Statement is
* returned. A Statement's execute methods clear its SQLWarning * returned. A Statement's execute methods clear its SQLWarning
* chain. Subsequent Statement warnings will be chained to this * chain. Subsequent Statement warnings will be chained to this
* SQLWarning. * SQLWarning.
* *
* <p>The Warning chain is automatically cleared each time a statement * <p>The Warning chain is automatically cleared each time a statement
* is (re)executed. * is (re)executed.
* *
* <p><B>Note:</B> If you are processing a ResultSet then any warnings * <p><B>Note:</B> If you are processing a ResultSet then any warnings
* associated with ResultSet reads will be chained on the ResultSet * associated with ResultSet reads will be chained on the ResultSet
* object. * object.
* *
* @return the first SQLWarning on null * @return the first SQLWarning on null
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public SQLWarning getWarnings() throws SQLException { public SQLWarning getWarnings() throws SQLException
return warnings; {
} return warnings;
}
/** /**
* The maxFieldSize limit (in bytes) is the maximum amount of * The maxFieldSize limit (in bytes) is the maximum amount of
* data returned for any column value; it only applies to * data returned for any column value; it only applies to
* BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR * BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR
* columns. If the limit is exceeded, the excess data is silently * columns. If the limit is exceeded, the excess data is silently
* discarded. * discarded.
* *
* @return the current max column size limit; zero means unlimited * @return the current max column size limit; zero means unlimited
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public int getMaxFieldSize() throws SQLException { public int getMaxFieldSize() throws SQLException
return 8192; // We cannot change this {
} return 8192; // We cannot change this
}
/** /**
* Sets the maxFieldSize - NOT! - We throw an SQLException just * Sets the maxFieldSize - NOT! - We throw an SQLException just
* to inform them to stop doing this. * to inform them to stop doing this.
* *
* @param max the new max column size limit; zero means unlimited * @param max the new max column size limit; zero means unlimited
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public void setMaxFieldSize(int max) throws SQLException { public void setMaxFieldSize(int max) throws SQLException
throw new PSQLException("postgresql.stat.maxfieldsize"); {
} throw new PSQLException("postgresql.stat.maxfieldsize");
}
/** /**
* After this call, getWarnings returns null until a new warning * After this call, getWarnings returns null until a new warning
* is reported for this Statement. * is reported for this Statement.
* *
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public void clearWarnings() throws SQLException { public void clearWarnings() throws SQLException
warnings = null; {
} warnings = null;
}
/** /**
* Cancel can be used by one thread to cancel a statement that * Cancel can be used by one thread to cancel a statement that
* is being executed by another thread. * is being executed by another thread.
* <p> * <p>
* Not implemented, this method is a no-op. * Not implemented, this method is a no-op.
* *
* @exception SQLException only because thats the spec. * @exception SQLException only because thats the spec.
*/ */
public void cancel() throws SQLException { public void cancel() throws SQLException
// FIXME: Cancel feature has been available since 6.4. Implement it here! {
} // 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 * New in 7.1: Returns the Last inserted oid. This should be used, rather
* than the old method using getResultSet, which for executeUpdate returns * than the old method using getResultSet, which for executeUpdate returns
* null. * null.
* @return OID of last insert * @return OID of last insert
*/ */
public int getInsertedOID() throws SQLException { public int getInsertedOID() throws SQLException
if (result == null) {
return 0; if (result == null)
return ((org.postgresql.ResultSet) result).getInsertedOID(); return 0;
} return ((org.postgresql.ResultSet) result).getInsertedOID();
}
/** /**
* getResultSet returns the current result as a ResultSet. It * getResultSet returns the current result as a ResultSet. It
* should only be called once per result. * should only be called once per result.
* *
* @return the current result set; null if there are no more * @return the current result set; null if there are no more
* @exception SQLException if a database access error occurs (why?) * @exception SQLException if a database access error occurs (why?)
*/ */
public java.sql.ResultSet getResultSet() throws SQLException { public java.sql.ResultSet getResultSet() throws SQLException
if (result != null && ((org.postgresql.ResultSet) result).reallyResultSet()) {
return result; if (result != null && ((org.postgresql.ResultSet) result).reallyResultSet())
return null; return result;
} return null;
}
/** /**
* In many cases, it is desirable to immediately release a * In many cases, it is desirable to immediately release a
* Statement's database and JDBC resources instead of waiting * Statement's database and JDBC resources instead of waiting
* for this to happen when it is automatically closed. The * for this to happen when it is automatically closed. The
* close method provides this immediate release. * close method provides this immediate release.
* *
* <p><B>Note:</B> A Statement is automatically closed when it is * <p><B>Note:</B> A Statement is automatically closed when it is
* garbage collected. When a Statement is closed, its current * garbage collected. When a Statement is closed, its current
* ResultSet, if one exists, is also closed. * ResultSet, if one exists, is also closed.
* *
* @exception SQLException if a database access error occurs (why?) * @exception SQLException if a database access error occurs (why?)
*/ */
public void close() throws SQLException { public void close() throws SQLException
// Force the ResultSet to close {
java.sql.ResultSet rs = getResultSet(); // Force the ResultSet to close
if(rs!=null) java.sql.ResultSet rs = getResultSet();
rs.close(); if (rs != null)
rs.close();
// Disasociate it from us (For Garbage Collection) // Disasociate it from us (For Garbage Collection)
result = null; result = null;
} }
/** /**
* Filter the SQL string of Java SQL Escape clauses. * Filter the SQL string of Java SQL Escape clauses.
* *
* Currently implemented Escape clauses are those mentioned in 11.3 * Currently implemented Escape clauses are those mentioned in 11.3
* in the specification. Basically we look through the sql string for * 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 * {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. * 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 * So, something like "select * from x where d={d '2001-10-09'}" would
* return "select * from x where d= '2001-10-09'". * return "select * from x where d= '2001-10-09'".
*/ */
protected static String escapeSQL(String sql) protected static String escapeSQL(String sql)
{ {
// Since escape codes can only appear in SQL CODE, we keep track // Since escape codes can only appear in SQL CODE, we keep track
// of if we enter a string or not. // of if we enter a string or not.
StringBuffer newsql = new StringBuffer(); StringBuffer newsql = new StringBuffer();
short state = IN_SQLCODE; short state = IN_SQLCODE;
int i = -1; int i = -1;
int len = sql.length(); int len = sql.length();
while(++i < len) while (++i < len)
{ {
char c = sql.charAt(i); char c = sql.charAt(i);
switch(state) switch (state)
{ {
case IN_SQLCODE: case IN_SQLCODE:
if(c == '\'') // start of a string? if (c == '\'') // start of a string?
state = IN_STRING; state = IN_STRING;
else if(c == '{') // start of an escape code? else if (c == '{') // start of an escape code?
if(i+1 < len) if (i + 1 < len)
{ {
char next = sql.charAt(i+1); char next = sql.charAt(i + 1);
if(next == 'd') if (next == 'd')
{ {
state = ESC_TIMEDATE; state = ESC_TIMEDATE;
i++; i++;
break; break;
} }
else if(next == 't') else if (next == 't')
{ {
state = ESC_TIMEDATE; state = ESC_TIMEDATE;
i += (i+2 < len && sql.charAt(i+2) == 's') ? 2 : 1; i += (i + 2 < len && sql.charAt(i + 2) == 's') ? 2 : 1;
break; break;
} }
} }
newsql.append(c); newsql.append(c);
break; break;
case IN_STRING: case IN_STRING:
if(c == '\'') // end of string? if (c == '\'') // end of string?
state = IN_SQLCODE; state = IN_SQLCODE;
else if(c == '\\') // a backslash? else if (c == '\\') // a backslash?
state = BACKSLASH; state = BACKSLASH;
newsql.append(c); newsql.append(c);
break; break;
case BACKSLASH: case BACKSLASH:
state = IN_STRING; state = IN_STRING;
newsql.append(c); newsql.append(c);
break; break;
case ESC_TIMEDATE: case ESC_TIMEDATE:
if(c == '}') if (c == '}')
state = IN_SQLCODE; // end of escape code. state = IN_SQLCODE; // end of escape code.
else else
newsql.append(c); newsql.append(c);
break; break;
} // end switch } // 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 * A simple and efficient class to pool one dimensional byte arrays
* of different sizes. * of different sizes.
*/ */
public class BytePoolDim1 { public class BytePoolDim1
{
/** /**
* The maximum size of the array we manage. * The maximum size of the array we manage.
*/ */
int maxsize = 256; int maxsize = 256;
/** /**
* The pools not currently in use * The pools not currently in use
*/ */
ObjectPool notusemap[] = new ObjectPool[maxsize+1]; ObjectPool notusemap[] = new ObjectPool[maxsize + 1];
/** /**
* The pools currently in use * The pools currently in use
*/ */
ObjectPool inusemap[] = new ObjectPool[maxsize+1]; ObjectPool inusemap[] = new ObjectPool[maxsize + 1];
/** /**
* *
*/ */
byte binit[][] = new byte[maxsize+1][0]; byte binit[][] = new byte[maxsize + 1][0];
/** /**
* Construct a new pool * Construct a new pool
*/ */
public BytePoolDim1(){ public BytePoolDim1()
for(int i = 0; i <= maxsize; i++){ {
binit[i] = new byte[i]; for (int i = 0; i <= maxsize; i++)
inusemap[i] = new SimpleObjectPool(); {
notusemap[i] = new SimpleObjectPool(); 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];
} }
ObjectPool not_usel = notusemap[size]; /**
ObjectPool in_usel = inusemap[size]; * Allocate a byte[] of a specified size and put it in the pool. If it's
byte b[] = null; * 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 ObjectPool not_usel = notusemap[size];
// now array ObjectPool in_usel = inusemap[size];
if(!not_usel.isEmpty()) { byte b[] = null;
Object o = not_usel.remove();
b = (byte[]) o; // 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 } else
b = new byte[size]; b = new byte[size];
in_usel.add(b); in_usel.add(b);
return b; return b;
*/ */
} }
/** /**
* Release an array * Release an array
* @param b byte[] to release * @param b byte[] to release
*/ */
public void release(byte[] b) { public void release(byte[] b)
// If it's larger than maxsize then we don't touch it {
if(b.length>maxsize) // If it's larger than maxsize then we don't touch it
return; if (b.length > maxsize)
return ;
ObjectPool not_usel = notusemap[b.length]; ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length]; ObjectPool in_usel = inusemap[b.length];
in_usel.remove(b); in_usel.remove(b);
not_usel.add(b); not_usel.add(b);
} }
/** /**
* Deallocate all * Deallocate all
* @deprecated Real bad things happen if this is called! * @deprecated Real bad things happen if this is called!
*/ */
public void deallocate() { public void deallocate()
//for(int i = 0; i <= maxsize; i++){ {
// notusemap[i].addAll(inusemap[i]); //for(int i = 0; i <= maxsize; i++){
// inusemap[i].clear(); // notusemap[i].addAll(inusemap[i]);
//} // inusemap[i].clear();
} //}
}
} }

View File

@@ -1,62 +1,69 @@
package org.postgresql.core; package org.postgresql.core;
public class BytePoolDim2 { public class BytePoolDim2
int maxsize = 32; {
ObjectPool notusemap[] = new ObjectPool[maxsize+1]; int maxsize = 32;
ObjectPool inusemap[] = new ObjectPool[maxsize+1]; ObjectPool notusemap[] = new ObjectPool[maxsize + 1];
ObjectPool inusemap[] = new ObjectPool[maxsize + 1];
public BytePoolDim2(){ public BytePoolDim2()
for(int i = 0; i <= maxsize; i++){ {
inusemap[i] = new SimpleObjectPool(); for (int i = 0; i <= maxsize; i++)
notusemap[i] = new SimpleObjectPool(); {
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
}
} }
}
public byte[][] allocByte(int size){ public byte[][] allocByte(int size)
// For now until the bug can be removed {
return new byte[size][0]; // For now until the bug can be removed
/* return new byte[size][0];
if(size > maxsize){ /*
return new byte[size][0]; if(size > maxsize){
return new byte[size][0];
} }
ObjectPool not_usel = notusemap[size]; ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size]; ObjectPool in_usel = inusemap[size];
byte b[][] = null; byte b[][] = null;
if(!not_usel.isEmpty()) { if(!not_usel.isEmpty()) {
Object o = not_usel.remove(); Object o = not_usel.remove();
b = (byte[][]) o; b = (byte[][]) o;
} else } else
b = new byte[size][0]; b = new byte[size][0];
in_usel.add(b); in_usel.add(b);
return b; return b;
*/ */
}
public void release(byte[][] b){
if(b.length > maxsize){
return;
} }
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
in_usel.remove(b); public void release(byte[][] b)
not_usel.add(b); {
} if (b.length > maxsize)
{
return ;
}
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
/** in_usel.remove(b);
* Deallocate the object cache. not_usel.add(b);
* 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. * Deallocate the object cache.
*/ * PM 17/01/01: Commented out this code as it blows away any hope of
public void deallocate(){ * multiple queries on the same connection. I'll redesign the allocation
//for(int i = 0; i <= maxsize; i++){ * code to use some form of Statement context, so the buffers are per
// notusemap[i].addAll(inusemap[i]); * Statement and not per Connection/PG_Stream as it is now.
// inusemap[i].clear(); */
//} 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. * 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. * Preferred JVM encodings for backend encodings.
*/ */
private static final Hashtable encodings = new Hashtable(); private static final Hashtable encodings = new Hashtable();
static { static {
//Note: this list should match the set of supported server //Note: this list should match the set of supported server
// encodings found in backend/util/mb/encnames.c // encodings found in backend/util/mb/encnames.c
encodings.put("SQL_ASCII", new String[] { "ASCII", "us-ascii" }); encodings.put("SQL_ASCII", new String[] { "ASCII", "us-ascii" });
encodings.put("UNICODE", new String[] { "UTF-8", "UTF8" }); encodings.put("UNICODE", new String[] { "UTF-8", "UTF8" });
encodings.put("LATIN1", new String[] { "ISO8859_1" }); encodings.put("LATIN1", new String[] { "ISO8859_1" });
encodings.put("LATIN2", new String[] { "ISO8859_2" }); encodings.put("LATIN2", new String[] { "ISO8859_2" });
encodings.put("LATIN3", new String[] { "ISO8859_3" }); encodings.put("LATIN3", new String[] { "ISO8859_3" });
encodings.put("LATIN4", new String[] { "ISO8859_4" }); encodings.put("LATIN4", new String[] { "ISO8859_4" });
encodings.put("ISO_8859_5", new String[] { "ISO8859_5" }); encodings.put("ISO_8859_5", new String[] { "ISO8859_5" });
encodings.put("ISO_8859_6", new String[] { "ISO8859_6" }); encodings.put("ISO_8859_6", new String[] { "ISO8859_6" });
encodings.put("ISO_8859_7", new String[] { "ISO8859_7" }); encodings.put("ISO_8859_7", new String[] { "ISO8859_7" });
encodings.put("ISO_8859_8", new String[] { "ISO8859_8" }); encodings.put("ISO_8859_8", new String[] { "ISO8859_8" });
encodings.put("LATIN5", new String[] { "ISO8859_9" }); encodings.put("LATIN5", new String[] { "ISO8859_9" });
encodings.put("LATIN7", new String[] { "ISO8859_13" }); encodings.put("LATIN7", new String[] { "ISO8859_13" });
encodings.put("LATIN9", new String[] { "ISO8859_15_FDIS" }); encodings.put("LATIN9", new String[] { "ISO8859_15_FDIS" });
encodings.put("EUC_JP", new String[] { "EUC_JP" }); encodings.put("EUC_JP", new String[] { "EUC_JP" });
encodings.put("EUC_CN", new String[] { "EUC_CN" }); encodings.put("EUC_CN", new String[] { "EUC_CN" });
encodings.put("EUC_KR", new String[] { "EUC_KR" }); encodings.put("EUC_KR", new String[] { "EUC_KR" });
encodings.put("EUC_TW", new String[] { "EUC_TW" }); encodings.put("EUC_TW", new String[] { "EUC_TW" });
encodings.put("SJIS", new String[] { "SJIS" }); encodings.put("SJIS", new String[] { "SJIS" });
encodings.put("BIG5", new String[] { "Big5" }); encodings.put("BIG5", new String[] { "Big5" });
encodings.put("WIN1250", new String[] { "Cp1250" }); encodings.put("WIN1250", new String[] { "Cp1250" });
encodings.put("WIN", new String[] { "Cp1251" }); encodings.put("WIN", new String[] { "Cp1251" });
encodings.put("ALT", new String[] { "Cp866" }); encodings.put("ALT", new String[] { "Cp866" });
// We prefer KOI8-U, since it is a superset of KOI8-R. // We prefer KOI8-U, since it is a superset of KOI8-R.
encodings.put("KOI8", new String[] { "KOI8_U", "KOI8_R" }); encodings.put("KOI8", new String[] { "KOI8_U", "KOI8_R" });
// If the database isn't encoding-aware then we can't have // If the database isn't encoding-aware then we can't have
// any preferred encodings. // any preferred encodings.
encodings.put("UNKNOWN", new String[0]); encodings.put("UNKNOWN", new String[0]);
// The following encodings do not have a java equivalent // The following encodings do not have a java equivalent
encodings.put("MULE_INTERNAL", new String[0]); encodings.put("MULE_INTERNAL", new String[0]);
encodings.put("LATIN6", new String[0]); encodings.put("LATIN6", new String[0]);
encodings.put("LATIN8", new String[0]); encodings.put("LATIN8", new String[0]);
encodings.put("LATIN10", 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);
} }
}
/** private final String 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.
if (encodings.containsKey(databaseEncoding)) { private Encoding(String encoding)
String[] candidates = (String[]) encodings.get(databaseEncoding); {
for (int i = 0; i < candidates.length; i++) { this.encoding = encoding;
if (isAvailable(candidates[i])) { }
return new Encoding(candidates[i]);
/**
* 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. * Get an Encoding matching the given database encoding.
*/ */
public String name() { private static Encoding encodingForDatabaseEncoding(String databaseEncoding)
return encoding; {
} // 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.
/** if (encodings.containsKey(databaseEncoding))
* Encode a string to an array of bytes. {
*/ String[] candidates = (String[]) encodings.get(databaseEncoding);
public byte[] encode(String s) throws SQLException { for (int i = 0; i < candidates.length; i++)
try { {
if (encoding == null) { if (isAvailable(candidates[i]))
return s.getBytes(); {
} else { return new Encoding(candidates[i]);
return s.getBytes(encoding); }
} }
} catch (UnsupportedEncodingException e) { }
throw new PSQLException("postgresql.stream.encoding", e); return defaultEncoding();
} }
}
/** /**
* Decode an array of bytes into a string. * Name of the (JVM) encoding used.
*/ */
public String decode(byte[] encodedString, int offset, int length) throws SQLException { public String name()
try { {
if (encoding == null) { return encoding;
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. * Encode a string to an array of bytes.
*/ */
public String decode(byte[] encodedString) throws SQLException { public byte[] encode(String s) throws SQLException
return decode(encodedString, 0, encodedString.length); {
} try
{
/** if (encoding == null)
* Get a Reader that decodes the given InputStream. {
*/ return s.getBytes();
public Reader getDecodingReader(InputStream in) throws SQLException { }
try { else
if (encoding == null) { {
return new InputStreamReader(in); return s.getBytes(encoding);
} else { }
return new InputStreamReader(in, encoding); }
} catch (UnsupportedEncodingException e)
} catch (UnsupportedEncodingException e) { {
throw new PSQLException("postgresql.res.encoding", e); throw new PSQLException("postgresql.stream.encoding", e);
}
} }
}
/** /**
* Get an Encoding using the default encoding for the JVM. * Decode an array of bytes into a string.
*/ */
public static Encoding defaultEncoding() { public String decode(byte[] encodedString, int offset, int length) throws SQLException
return DEFAULT_ENCODING; {
} try
{
/** if (encoding == null)
* Test if an encoding is available in the JVM. {
*/ return new String(encodedString, offset, length);
private static boolean isAvailable(String encodingName) { }
try { else
"DUMMY".getBytes(encodingName); {
return true; return new String(encodedString, offset, length, encoding);
} catch (UnsupportedEncodingException e) { }
return false; }
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. * This interface defines the methods to access the memory pool classes.
*/ */
public interface MemoryPool { public interface MemoryPool
/** {
* Allocate an array from the pool /**
* @return byte[] allocated * Allocate an array from the pool
*/ * @return byte[] allocated
public byte[] allocByte(int size); */
public byte[] allocByte(int size);
/** /**
* Frees an object back to the pool * Frees an object back to the pool
* @param o Object to release * @param o Object to release
*/ */
public void release(Object o); public void release(Object o);
} }

View File

@@ -6,43 +6,44 @@ package org.postgresql.core;
* other for jdk1.2+ * other for jdk1.2+
*/ */
public interface ObjectPool { public interface ObjectPool
/** {
* Adds an object to the pool /**
* @param o Object to add * Adds an object to the pool
*/ * @param o Object to add
public void add(Object o); */
public void add(Object o);
/** /**
* Removes an object from the pool * Removes an object from the pool
* @param o Object to remove * @param o Object to remove
*/ */
public void remove(Object o); public void remove(Object o);
/** /**
* Removes the top object from the pool * Removes the top object from the pool
* @return Object from the top. * @return Object from the top.
*/ */
public Object remove(); public Object remove();
/** /**
* @return true if the pool is empty * @return true if the pool is empty
*/ */
public boolean isEmpty(); public boolean isEmpty();
/** /**
* @return the number of objects in the pool * @return the number of objects in the pool
*/ */
public int size(); public int size();
/** /**
* Adds all objects in one pool to this one * Adds all objects in one pool to this one
* @param pool The pool to take the objects from * @param pool The pool to take the objects from
*/ */
public void addAll(ObjectPool pool); public void addAll(ObjectPool pool);
/** /**
* Clears the pool of all objects * Clears the pool of all objects
*/ */
public void clear(); 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 * <p>The lifetime of a QueryExecutor object is from sending the query
* until the response has been received from the backend. * 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 String sql;
private final java.sql.Statement statement; private final java.sql.Statement statement;
private final PG_Stream pg_stream; private final PG_Stream pg_stream;
private final org.postgresql.Connection connection; private final org.postgresql.Connection connection;
public QueryExecutor(String sql, public QueryExecutor(String sql,
java.sql.Statement statement, java.sql.Statement statement,
PG_Stream pg_stream, PG_Stream pg_stream,
org.postgresql.Connection connection) org.postgresql.Connection connection)
throws SQLException throws SQLException
{ {
this.sql = sql; this.sql = sql;
this.statement = statement; this.statement = statement;
this.pg_stream = pg_stream; this.pg_stream = pg_stream;
this.connection = connection; this.connection = connection;
if (statement != null) if (statement != null)
maxRows = statement.getMaxRows(); maxRows = statement.getMaxRows();
else else
maxRows = 0; maxRows = 0;
} }
private Field[] fields = null; private Field[] fields = null;
private Vector tuples = new Vector(); private Vector tuples = new Vector();
private boolean binaryCursor = false; private boolean binaryCursor = false;
private String status = null; private String status = null;
private int update_count = 1; private int update_count = 1;
private int insert_oid = 0; private int insert_oid = 0;
private int maxRows; private int maxRows;
/** /**
* Execute a query on the backend. * Execute a query on the backend.
*/ */
public java.sql.ResultSet execute() throws SQLException { public java.sql.ResultSet execute() throws SQLException
{
int fqp = 0; int fqp = 0;
boolean hfr = false; boolean hfr = false;
synchronized(pg_stream) { synchronized (pg_stream)
{
sendQuery(sql); sendQuery(sql);
while (!hfr || fqp > 0) { while (!hfr || fqp > 0)
int c = pg_stream.ReceiveChar(); {
int c = pg_stream.ReceiveChar();
switch (c) switch (c)
{ {
case 'A': // Asynchronous Notify case 'A': // Asynchronous Notify
int pid = pg_stream.ReceiveInteger(4); int pid = pg_stream.ReceiveInteger(4);
String msg = pg_stream.ReceiveString(connection.getEncoding()); String msg = pg_stream.ReceiveString(connection.getEncoding());
break; break;
case 'B': // Binary Data Transfer case 'B': // Binary Data Transfer
receiveTuple(true); receiveTuple(true);
break; break;
case 'C': // Command Status case 'C': // Command Status
receiveCommandStatus(); receiveCommandStatus();
if (fields != null) if (fields != null)
hfr = true; hfr = true;
else { else
sendQuery(" "); {
fqp++; sendQuery(" ");
} fqp++;
break; }
case 'D': // Text Data Transfer break;
receiveTuple(false); case 'D': // Text Data Transfer
break; receiveTuple(false);
case 'E': // Error Message break;
throw new SQLException(pg_stream.ReceiveString(connection.getEncoding())); case 'E': // Error Message
case 'I': // Empty Query throw new SQLException(pg_stream.ReceiveString(connection.getEncoding()));
int t = pg_stream.ReceiveChar(); case 'I': // Empty Query
if (t != 0) int t = pg_stream.ReceiveChar();
throw new PSQLException("postgresql.con.garbled"); if (t != 0)
throw new PSQLException("postgresql.con.garbled");
if (fqp > 0) if (fqp > 0)
fqp--; fqp--;
if (fqp == 0) if (fqp == 0)
hfr = true; hfr = true;
break; break;
case 'N': // Error Notification case 'N': // Error Notification
connection.addWarning(pg_stream.ReceiveString(connection.getEncoding())); connection.addWarning(pg_stream.ReceiveString(connection.getEncoding()));
break; break;
case 'P': // Portal Name case 'P': // Portal Name
String pname = pg_stream.ReceiveString(connection.getEncoding()); String pname = pg_stream.ReceiveString(connection.getEncoding());
break; break;
case 'T': // MetaData Field Description case 'T': // MetaData Field Description
receiveFields(); receiveFields();
break; break;
case 'Z': // backend ready for query, ignore for now :-) case 'Z': // backend ready for query, ignore for now :-)
break; break;
default: default:
throw new PSQLException("postgresql.con.type", throw new PSQLException("postgresql.con.type",
new Character((char) c)); new Character((char) c));
} }
} }
return connection.getResultSet(connection, statement, fields, tuples, status, update_count, insert_oid, binaryCursor); return connection.getResultSet(connection, statement, fields, tuples, status, update_count, insert_oid, binaryCursor);
} }
} }
/** /**
* Send a query to the backend. * Send a query to the backend.
*/ */
private void sendQuery(String query) throws SQLException { private void sendQuery(String query) throws SQLException
try { {
pg_stream.SendChar('Q'); try
pg_stream.Send(connection.getEncoding().encode(query)); {
pg_stream.SendChar(0); pg_stream.SendChar('Q');
pg_stream.flush(); 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. * Receive a tuple from the backend.
* *
* @param isBinary set if the tuple should be treated as binary data * @param isBinary set if the tuple should be treated as binary data
*/ */
private void receiveTuple(boolean isBinary) throws SQLException { private void receiveTuple(boolean isBinary) throws SQLException
if (fields == null) {
throw new PSQLException("postgresql.con.tuple"); if (fields == null)
Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary); throw new PSQLException("postgresql.con.tuple");
if (isBinary) binaryCursor = true; Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary);
if (maxRows == 0 || tuples.size() < maxRows) if (isBinary)
tuples.addElement(tuple); binaryCursor = true;
} if (maxRows == 0 || tuples.size() < maxRows)
tuples.addElement(tuple);
}
/** /**
* Receive command status from the backend. * Receive command status from the backend.
*/ */
private void receiveCommandStatus() throws SQLException { private void receiveCommandStatus() throws SQLException
{
status = pg_stream.ReceiveString(connection.getEncoding()); status = pg_stream.ReceiveString(connection.getEncoding());
try { try
// Now handle the update count correctly. {
if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE")) { // Now handle the update count correctly.
update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' '))); if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE"))
} {
if (status.startsWith("INSERT")) { update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' ')));
insert_oid = Integer.parseInt(status.substring(1 + status.indexOf(' '), }
status.lastIndexOf(' '))); if (status.startsWith("INSERT"))
} {
} catch (NumberFormatException nfe) { insert_oid = Integer.parseInt(status.substring(1 + status.indexOf(' '),
throw new PSQLException("postgresql.con.fathom", status); status.lastIndexOf(' ')));
} }
} }
catch (NumberFormatException nfe)
{
throw new PSQLException("postgresql.con.fathom", status);
}
}
/** /**
* Receive the field descriptions from the back end. * Receive the field descriptions from the back end.
*/ */
private void receiveFields() throws SQLException { private void receiveFields() throws SQLException
if (fields != null) {
throw new PSQLException("postgresql.con.multres"); if (fields != null)
throw new PSQLException("postgresql.con.multres");
int size = pg_stream.ReceiveIntegerR(2); int size = pg_stream.ReceiveIntegerR(2);
fields = new Field[size]; fields = new Field[size];
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++)
String typeName = pg_stream.ReceiveString(connection.getEncoding()); {
int typeOid = pg_stream.ReceiveIntegerR(4); String typeName = pg_stream.ReceiveString(connection.getEncoding());
int typeLength = pg_stream.ReceiveIntegerR(2); int typeOid = pg_stream.ReceiveIntegerR(4);
int typeModifier = pg_stream.ReceiveIntegerR(4); int typeLength = pg_stream.ReceiveIntegerR(2);
fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier); 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 public class SimpleObjectPool implements ObjectPool
{ {
// This was originally in PG_Stream but moved out to fix the major problem // 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 // where more than one query (usually all the time) overwrote the results
// of another query. // of another query.
int cursize = 0; int cursize = 0;
int maxsize = 16; int maxsize = 16;
Object arr[] = new Object[maxsize]; Object arr[] = new Object[maxsize];
/** /**
* Adds an object to the pool * Adds an object to the pool
* @param o Object to add * @param o Object to add
*/ */
public void add(Object o) public void add(Object o)
{ {
if(cursize >= maxsize){ if (cursize >= maxsize)
Object newarr[] = new Object[maxsize*2]; {
System.arraycopy(arr, 0, newarr, 0, maxsize); Object newarr[] = new Object[maxsize * 2];
maxsize = maxsize * 2; System.arraycopy(arr, 0, newarr, 0, maxsize);
arr = newarr; maxsize = maxsize * 2;
arr = newarr;
}
arr[cursize++] = o;
} }
arr[cursize++] = o;
}
/** /**
* Removes the top object from the pool * Removes the top object from the pool
* @return Object from the top. * @return Object from the top.
*/ */
public Object remove(){ public Object remove()
return arr[--cursize]; {
} 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;
} }
System.arraycopy(pool.arr, 0, arr, cursize, srcsize);
cursize = totalsize;
}
/** /**
* Clears the pool of all objects * Removes the given object from the pool
*/ * @param o Object to remove
public void clear(){ */
cursize = 0; 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 public class Fastpath
{ {
// This maps the functions names to their id's (possible unique just // This maps the functions names to their id's (possible unique just
// to a connection). // to a connection).
protected Hashtable func = new Hashtable(); protected Hashtable func = new Hashtable();
protected org.postgresql.Connection conn; // our connection protected org.postgresql.Connection conn; // our connection
protected org.postgresql.PG_Stream stream; // the network stream protected org.postgresql.PG_Stream stream; // the network stream
/** /**
* Initialises the fastpath system * Initialises the fastpath system
* *
* <p><b>Important Notice</b> * <p><b>Important Notice</b>
* <br>This is called from org.postgresql.Connection, and should not be called * <br>This is called from org.postgresql.Connection, and should not be called
* from client code. * from client code.
* *
* @param conn org.postgresql.Connection to attach to * @param conn org.postgresql.Connection to attach to
* @param stream The network stream to the backend * @param stream The network stream to the backend
*/ */
public Fastpath(org.postgresql.Connection conn,org.postgresql.PG_Stream stream) 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);
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': this.conn = conn;
break; this.stream = stream;
//DriverManager.println("Fastpath initialised");
//------------------------------
// 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. * Send a function call to the PostgreSQL backend
* *
* Note: the mapping for the procedure name to function id needs to exist, * @param fnid Function id
* usually to an earlier call to addfunction(). * @param resulttype True if the result is an integer, false for other results
* * @param args FastpathArguments to pass to fastpath
* This is the prefered method to call, as function id's can/may change * @return null if no data, Integer if an integer result, or byte[] otherwise
* between versions of the backend. * @exception SQLException if a database-access error occurs.
* */
* For an example of how this works, refer to org.postgresql.LargeObject public Object fastpath(int fnid, boolean resulttype, FastpathArg[] args) throws SQLException
* {
* @param name Function name // added Oct 7 1998 to give us thread safety
* @param resulttype True if the result is an integer, false for other synchronized (stream)
* 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);
}
/** // send the function call
* This convenience method assumes that the return value is an Integer try
* @param name Function name {
* @param args Function arguments // 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
* @return integer result // that confuses the backend. The 0 terminates the command line.
* @exception SQLException if a database-access error occurs or no result stream.SendInteger(70, 1);
*/ stream.SendInteger(0, 1);
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();
}
/** stream.SendInteger(fnid, 4);
* This convenience method assumes that the return value is an Integer stream.SendInteger(args.length, 4);
* @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);
}
/** for (int i = 0;i < args.length;i++)
* This adds a function to our lookup table. args[i].send(stream);
*
* <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 is needed, otherwise data can be lost
* This takes a ResultSet containing two columns. Column 1 contains the stream.flush();
* 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 catch (IOException ioe)
* {
* <p>If addFunction() or addFunctions() have not been called for this name, throw new PSQLException("postgresql.fp.send", new Integer(fnid), ioe);
* 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 // Now handle 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(); // 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();
}
} }

View File

@@ -22,85 +22,88 @@ import org.postgresql.util.*;
*/ */
public class FastpathArg public class FastpathArg
{ {
/** /**
* Type of argument, true=integer, false=byte[] * Type of argument, true=integer, false=byte[]
*/ */
public boolean type; public boolean type;
/** /**
* Integer value if type=true * Integer value if type=true
*/ */
public int value; public int value;
/** /**
* Byte value if type=false; * Byte value if type=false;
*/ */
public byte[] bytes; public byte[] bytes;
/** /**
* Constructs an argument that consists of an integer value * Constructs an argument that consists of an integer value
* @param value int value to set * @param value int value to set
*/ */
public FastpathArg(int value) public FastpathArg(int value)
{ {
type=true; type = true;
this.value=value; this.value = value;
} }
/** /**
* Constructs an argument that consists of an array of bytes * Constructs an argument that consists of an array of bytes
* @param bytes array to store * @param bytes array to store
*/ */
public FastpathArg(byte bytes[]) public FastpathArg(byte bytes[])
{ {
type=false; type = false;
this.bytes=bytes; this.bytes = bytes;
} }
/** /**
* Constructs an argument that consists of part of a byte array * Constructs an argument that consists of part of a byte array
* @param buf source array * @param buf source array
* @param off offset within array * @param off offset within array
* @param len length of data to include * @param len length of data to include
*/ */
public FastpathArg(byte buf[],int off,int len) public FastpathArg(byte buf[], int off, int len)
{ {
type=false; type = false;
bytes = new byte[len]; bytes = new byte[len];
System.arraycopy(buf,off,bytes,0,len); System.arraycopy(buf, off, bytes, 0, len);
} }
/** /**
* Constructs an argument that consists of a String. * Constructs an argument that consists of a String.
* @param s String to store * @param s String to store
*/ */
public FastpathArg(String s) public FastpathArg(String s)
{ {
this(s.getBytes()); this(s.getBytes());
} }
/** /**
* This sends this argument down the network stream. * This sends this argument down the network stream.
* *
* <p>The stream sent consists of the length.int4 then the contents. * <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 * <p><b>Note:</b> This is called from Fastpath, and cannot be called from
* client code. * client code.
* *
* @param s output stream * @param s output stream
* @exception IOException if something failed on the network stream * @exception IOException if something failed on the network stream
*/ */
protected void send(org.postgresql.PG_Stream s) throws IOException protected void send(org.postgresql.PG_Stream s) throws IOException
{ {
if(type) { if (type)
// argument is an integer {
s.SendInteger(4,4); // size of an integer // argument is an integer
s.SendInteger(value,4); // integer value of argument s.SendInteger(4, 4); // size of an integer
} else { s.SendInteger(value, 4); // integer value of argument
// argument is a byte array }
s.SendInteger(bytes.length,4); // size of array else
s.Send(bytes); {
} // 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. * 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. * These are the two points.
*/ */
public PGpoint point[] = new PGpoint[2]; public PGpoint point[] = new PGpoint[2];
/** /**
* @param x1 first x coordinate * @param x1 first x coordinate
* @param y1 first y coordinate * @param y1 first y coordinate
* @param x2 second x coordinate * @param x2 second x coordinate
* @param y2 second y coordinate * @param y2 second y coordinate
*/ */
public PGbox(double x1,double y1,double x2,double y2) public PGbox(double x1, double y1, double x2, double y2)
{ {
this(); this();
this.point[0] = new PGpoint(x1,y1); this.point[0] = new PGpoint(x1, y1);
this.point[1] = new PGpoint(x2,y2); this.point[1] = new PGpoint(x2, y2);
} }
/** /**
* @param p1 first point * @param p1 first point
* @param p2 second point * @param p2 second point
*/ */
public PGbox(PGpoint p1,PGpoint p2) public PGbox(PGpoint p1, PGpoint p2)
{ {
this(); this();
this.point[0] = p1; this.point[0] = p1;
this.point[1] = p2; this.point[1] = p2;
} }
/** /**
* @param s Box definition in PostgreSQL syntax * @param s Box definition in PostgreSQL syntax
* @exception SQLException if definition is invalid * @exception SQLException if definition is invalid
*/ */
public PGbox(String s) throws SQLException public PGbox(String s) throws SQLException
{ {
this(); this();
setValue(s); setValue(s);
} }
/** /**
* Required constructor * Required constructor
*/ */
public PGbox() public PGbox()
{ {
setType("box"); setType("box");
} }
/** /**
* This method sets the value of this object. It should be overidden, * This method sets the value of this object. It should be overidden,
* but still called by subclasses. * but still called by subclasses.
* *
* @param value a string representation of the value of the object * @param value a string representation of the value of the object
* @exception SQLException thrown if value is invalid for this type * @exception SQLException thrown if value is invalid for this type
*/ */
public void setValue(String value) throws SQLException public void setValue(String value) throws SQLException
{ {
PGtokenizer t = new PGtokenizer(value,','); PGtokenizer t = new PGtokenizer(value, ',');
if(t.getSize() != 2) if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.box",value); throw new PSQLException("postgresql.geo.box", value);
point[0] = new PGpoint(t.getToken(0)); point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1)); point[1] = new PGpoint(t.getToken(1));
} }
/** /**
* @param obj Object to compare with * @param obj Object to compare with
* @return true if the two boxes are identical * @return true if the two boxes are identical
*/ */
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if(obj instanceof PGbox) { if (obj instanceof PGbox)
PGbox p = (PGbox)obj; {
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) || PGbox p = (PGbox)obj;
(p.point[0].equals(point[1]) && p.point[1].equals(point[0])); 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; }
} return false;
}
/** /**
* This must be overidden to allow the object to be cloned * This must be overidden to allow the object to be cloned
*/ */
public Object clone() public Object clone()
{ {
return new PGbox((PGpoint)point[0].clone(),(PGpoint)point[1].clone()); return new PGbox((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
} }
/** /**
* @return the PGbox in the syntax expected by org.postgresql * @return the PGbox in the syntax expected by org.postgresql
*/ */
public String getValue() public String getValue()
{ {
return point[0].toString()+","+point[1].toString(); 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 * This represents org.postgresql's circle datatype, consisting of a point and
* a radius * a radius
*/ */
public class PGcircle extends PGobject implements Serializable,Cloneable public class PGcircle extends PGobject implements Serializable, Cloneable
{ {
/** /**
* This is the centre point * This is the centre point
*/ */
public PGpoint center; public PGpoint center;
/** /**
* This is the radius * This is the radius
*/ */
double radius; double radius;
/** /**
* @param x coordinate of centre * @param x coordinate of centre
* @param y coordinate of centre * @param y coordinate of centre
* @param r radius of circle * @param r radius of circle
*/ */
public PGcircle(double x,double y,double r) public PGcircle(double x, double y, double r)
{ {
this(new PGpoint(x,y),r); this(new PGpoint(x, y), r);
} }
/** /**
* @param c PGpoint describing the circle's centre * @param c PGpoint describing the circle's centre
* @param r radius of circle * @param r radius of circle
*/ */
public PGcircle(PGpoint c,double r) public PGcircle(PGpoint c, double r)
{ {
this(); this();
this.center = c; this.center = c;
this.radius = r; this.radius = r;
} }
/** /**
* @param s definition of the circle in PostgreSQL's syntax. * @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public PGcircle(String s) throws SQLException public PGcircle(String s) throws SQLException
{ {
this(); this();
setValue(s); setValue(s);
} }
/** /**
* This constructor is used by the driver. * This constructor is used by the driver.
*/ */
public PGcircle() public PGcircle()
{ {
setType("circle"); setType("circle");
} }
/** /**
* @param s definition of the circle in PostgreSQL's syntax. * @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public void setValue(String s) throws SQLException public void setValue(String s) throws SQLException
{ {
PGtokenizer t = new PGtokenizer(PGtokenizer.removeAngle(s),','); PGtokenizer t = new PGtokenizer(PGtokenizer.removeAngle(s), ',');
if(t.getSize() != 2) if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.circle",s); throw new PSQLException("postgresql.geo.circle", s);
try { try
center = new PGpoint(t.getToken(0)); {
radius = Double.valueOf(t.getToken(1)).doubleValue(); center = new PGpoint(t.getToken(0));
} catch(NumberFormatException e) { radius = Double.valueOf(t.getToken(1)).doubleValue();
throw new PSQLException("postgresql.geo.circle",e); }
} catch (NumberFormatException e)
} {
throw new PSQLException("postgresql.geo.circle", e);
}
}
/** /**
* @param obj Object to compare with * @param obj Object to compare with
* @return true if the two boxes are identical * @return true if the two boxes are identical
*/ */
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if(obj instanceof PGcircle) { if (obj instanceof PGcircle)
PGcircle p = (PGcircle)obj; {
return p.center.equals(center) && p.radius==radius; PGcircle p = (PGcircle)obj;
} return p.center.equals(center) && p.radius == radius;
return false; }
} return false;
}
/** /**
* This must be overidden to allow the object to be cloned * This must be overidden to allow the object to be cloned
*/ */
public Object clone() public Object clone()
{ {
return new PGcircle((PGpoint)center.clone(),radius); return new PGcircle((PGpoint)center.clone(), radius);
} }
/** /**
* @return the PGcircle in the syntax expected by org.postgresql * @return the PGcircle in the syntax expected by org.postgresql
*/ */
public String getValue() public String getValue()
{ {
return "<"+center+","+radius+">"; 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 * Currently line is not yet implemented in the backend, but this class
* ensures that when it's done were ready for it. * 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. * These are the two points.
*/ */
public PGpoint point[] = new PGpoint[2]; public PGpoint point[] = new PGpoint[2];
/** /**
* @param x1 coordinate for first point * @param x1 coordinate for first point
* @param y1 coordinate for first point * @param y1 coordinate for first point
* @param x2 coordinate for second point * @param x2 coordinate for second point
* @param y2 coordinate for second point * @param y2 coordinate for second point
*/ */
public PGline(double x1,double y1,double x2,double y2) public PGline(double x1, double y1, double x2, double y2)
{ {
this(new PGpoint(x1,y1),new PGpoint(x2,y2)); this(new PGpoint(x1, y1), new PGpoint(x2, y2));
} }
/** /**
* @param p1 first point * @param p1 first point
* @param p2 second point * @param p2 second point
*/ */
public PGline(PGpoint p1,PGpoint p2) public PGline(PGpoint p1, PGpoint p2)
{ {
this(); this();
this.point[0] = p1; this.point[0] = p1;
this.point[1] = p2; this.point[1] = p2;
} }
/** /**
* @param s definition of the circle in PostgreSQL's syntax. * @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public PGline(String s) throws SQLException public PGline(String s) throws SQLException
{ {
this(); this();
setValue(s); setValue(s);
} }
/** /**
* reuired by the driver * reuired by the driver
*/ */
public PGline() public PGline()
{ {
setType("line"); setType("line");
} }
/** /**
* @param s Definition of the line segment in PostgreSQL's syntax * @param s Definition of the line segment in PostgreSQL's syntax
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public void setValue(String s) throws SQLException public void setValue(String s) throws SQLException
{ {
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s),','); PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s), ',');
if(t.getSize() != 2) if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.line",s); throw new PSQLException("postgresql.geo.line", s);
point[0] = new PGpoint(t.getToken(0)); point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1)); point[1] = new PGpoint(t.getToken(1));
} }
/** /**
* @param obj Object to compare with * @param obj Object to compare with
* @return true if the two boxes are identical * @return true if the two boxes are identical
*/ */
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if(obj instanceof PGline) { if (obj instanceof PGline)
PGline p = (PGline)obj; {
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) || PGline p = (PGline)obj;
(p.point[0].equals(point[1]) && p.point[1].equals(point[0])); 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; }
} return false;
}
/** /**
* This must be overidden to allow the object to be cloned * This must be overidden to allow the object to be cloned
*/ */
public Object clone() public Object clone()
{ {
return new PGline((PGpoint)point[0].clone(),(PGpoint)point[1].clone()); return new PGline((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
} }
/** /**
* @return the PGline in the syntax expected by org.postgresql * @return the PGline in the syntax expected by org.postgresql
*/ */
public String getValue() public String getValue()
{ {
return "["+point[0]+","+point[1]+"]"; 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 * 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. * These are the two points.
*/ */
public PGpoint point[] = new PGpoint[2]; public PGpoint point[] = new PGpoint[2];
/** /**
* @param x1 coordinate for first point * @param x1 coordinate for first point
* @param y1 coordinate for first point * @param y1 coordinate for first point
* @param x2 coordinate for second point * @param x2 coordinate for second point
* @param y2 coordinate for second point * @param y2 coordinate for second point
*/ */
public PGlseg(double x1,double y1,double x2,double y2) public PGlseg(double x1, double y1, double x2, double y2)
{ {
this(new PGpoint(x1,y1),new PGpoint(x2,y2)); this(new PGpoint(x1, y1), new PGpoint(x2, y2));
} }
/** /**
* @param p1 first point * @param p1 first point
* @param p2 second point * @param p2 second point
*/ */
public PGlseg(PGpoint p1,PGpoint p2) public PGlseg(PGpoint p1, PGpoint p2)
{ {
this(); this();
this.point[0] = p1; this.point[0] = p1;
this.point[1] = p2; this.point[1] = p2;
} }
/** /**
* @param s definition of the circle in PostgreSQL's syntax. * @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public PGlseg(String s) throws SQLException public PGlseg(String s) throws SQLException
{ {
this(); this();
setValue(s); setValue(s);
} }
/** /**
* reuired by the driver * reuired by the driver
*/ */
public PGlseg() public PGlseg()
{ {
setType("lseg"); setType("lseg");
} }
/** /**
* @param s Definition of the line segment in PostgreSQL's syntax * @param s Definition of the line segment in PostgreSQL's syntax
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public void setValue(String s) throws SQLException public void setValue(String s) throws SQLException
{ {
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s),','); PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s), ',');
if(t.getSize() != 2) if (t.getSize() != 2)
throw new PSQLException("postgresql.geo.lseg"); throw new PSQLException("postgresql.geo.lseg");
point[0] = new PGpoint(t.getToken(0)); point[0] = new PGpoint(t.getToken(0));
point[1] = new PGpoint(t.getToken(1)); point[1] = new PGpoint(t.getToken(1));
} }
/** /**
* @param obj Object to compare with * @param obj Object to compare with
* @return true if the two boxes are identical * @return true if the two boxes are identical
*/ */
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if(obj instanceof PGlseg) { if (obj instanceof PGlseg)
PGlseg p = (PGlseg)obj; {
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) || PGlseg p = (PGlseg)obj;
(p.point[0].equals(point[1]) && p.point[1].equals(point[0])); 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; }
} return false;
}
/** /**
* This must be overidden to allow the object to be cloned * This must be overidden to allow the object to be cloned
*/ */
public Object clone() public Object clone()
{ {
return new PGlseg((PGpoint)point[0].clone(),(PGpoint)point[1].clone()); return new PGlseg((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
} }
/** /**
* @return the PGlseg in the syntax expected by org.postgresql * @return the PGlseg in the syntax expected by org.postgresql
*/ */
public String getValue() public String getValue()
{ {
return "["+point[0]+","+point[1]+"]"; 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) * 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 * True if the path is open, false if closed
*/ */
public boolean open; public boolean open;
/** /**
* The points defining this path * The points defining this path
*/ */
public PGpoint points[]; public PGpoint points[];
/** /**
* @param points the PGpoints that define the path * @param points the PGpoints that define the path
* @param open True if the path is open, false if closed * @param open True if the path is open, false if closed
*/ */
public PGpath(PGpoint[] points,boolean open) public PGpath(PGpoint[] points, boolean open)
{ {
this(); this();
this.points = points; this.points = points;
this.open = open; this.open = open;
} }
/** /**
* Required by the driver * Required by the driver
*/ */
public PGpath() public PGpath()
{ {
setType("path"); setType("path");
} }
/** /**
* @param s definition of the circle in PostgreSQL's syntax. * @param s definition of the circle in PostgreSQL's syntax.
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public PGpath(String s) throws SQLException public PGpath(String s) throws SQLException
{ {
this(); this();
setValue(s); setValue(s);
} }
/** /**
* @param s Definition of the path in PostgreSQL's syntax * @param s Definition of the path in PostgreSQL's syntax
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public void setValue(String s) throws SQLException public void setValue(String s) throws SQLException
{ {
// First test to see if were open // First test to see if were open
if(s.startsWith("[") && s.endsWith("]")) { if (s.startsWith("[") && s.endsWith("]"))
open = true; {
s = PGtokenizer.removeBox(s); open = true;
} else if(s.startsWith("(") && s.endsWith(")")) { s = PGtokenizer.removeBox(s);
open = false; }
s = PGtokenizer.removePara(s); else if (s.startsWith("(") && s.endsWith(")"))
} else {
throw new PSQLException("postgresql.geo.path"); open = false;
s = PGtokenizer.removePara(s);
}
else
throw new PSQLException("postgresql.geo.path");
PGtokenizer t = new PGtokenizer(s,','); PGtokenizer t = new PGtokenizer(s, ',');
int npoints = t.getSize(); int npoints = t.getSize();
points = new PGpoint[npoints]; points = new PGpoint[npoints];
for(int p=0;p<npoints;p++) for (int p = 0;p < npoints;p++)
points[p] = new PGpoint(t.getToken(p)); points[p] = new PGpoint(t.getToken(p));
} }
/** /**
* @param obj Object to compare with * @param obj Object to compare with
* @return true if the two boxes are identical * @return true if the two boxes are identical
*/ */
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if(obj instanceof PGpath) { if (obj instanceof PGpath)
PGpath p = (PGpath)obj; {
PGpath p = (PGpath)obj;
if(p.points.length != points.length) if (p.points.length != points.length)
return false; return false;
if(p.open != open) if (p.open != open)
return false; return false;
for(int i=0;i<points.length;i++) for (int i = 0;i < points.length;i++)
if(!points[i].equals(p.points[i])) if (!points[i].equals(p.points[i]))
return false; return false;
return true; return true;
} }
return false; return false;
} }
/** /**
* This must be overidden to allow the object to be cloned * This must be overidden to allow the object to be cloned
*/ */
public Object clone() public Object clone()
{ {
PGpoint ary[] = new PGpoint[points.length]; PGpoint ary[] = new PGpoint[points.length];
for(int i=0;i<points.length;i++) for (int i = 0;i < points.length;i++)
ary[i]=(PGpoint)points[i].clone(); ary[i] = (PGpoint)points[i].clone();
return new PGpath(ary,open); return new PGpath(ary, open);
} }
/** /**
* This returns the polygon in the syntax expected by org.postgresql * This returns the polygon in the syntax expected by org.postgresql
*/ */
public String getValue() public String getValue()
{ {
StringBuffer b = new StringBuffer(open?"[":"("); StringBuffer b = new StringBuffer(open ? "[" : "(");
for(int p=0;p<points.length;p++) { for (int p = 0;p < points.length;p++)
if(p>0) b.append(","); {
b.append(points[p].toString()); if (p > 0)
} b.append(",");
b.append(open?"]":")"); b.append(points[p].toString());
}
b.append(open ? "]" : ")");
return b.toString(); return b.toString();
} }
public boolean isOpen() public boolean isOpen()
{ {
return open; return open;
} }
public boolean isClosed() public boolean isClosed()
{ {
return !open; return !open;
} }
public void closePath() public void closePath()
{ {
open = false; open = false;
} }
public void openPath() public void openPath()
{ {
open = true; open = true;
} }
} }

View File

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

View File

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

View File

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

View File

@@ -17,9 +17,9 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*; 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 * context of a Connection, SQL statements are executed and results are
* returned. * returned.
* *
@@ -29,181 +29,183 @@ import org.postgresql.util.*;
* with the getMetaData method. * with the getMetaData method.
* *
* <p><B>Note:</B> By default, the Connection automatically commits changes * <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. * explicit commit must be done or database changes will not be saved.
* *
* @see java.sql.Connection * @see java.sql.Connection
*/ */
public class Connection extends org.postgresql.Connection implements 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 // This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata; protected DatabaseMetaData metadata;
/** /**
* SQL statements without parameters are normally executed using * SQL statements without parameters are normally executed using
* Statement objects. If the same SQL statement is executed many * Statement objects. If the same SQL statement is executed many
* times, it is more efficient to use a PreparedStatement * times, it is more efficient to use a PreparedStatement
* *
* @return a new Statement object * @return a new Statement object
* @exception SQLException passed through from the constructor * @exception SQLException passed through from the constructor
*/ */
public java.sql.Statement createStatement() throws SQLException public java.sql.Statement createStatement() throws SQLException
{ {
return new Statement(this); return new Statement(this);
} }
/** /**
* A SQL statement with or without IN parameters can be pre-compiled * A SQL statement with or without IN parameters can be pre-compiled
* and stored in a PreparedStatement object. This object can then * and stored in a PreparedStatement object. This object can then
* be used to efficiently execute this statement multiple times. * be used to efficiently execute this statement multiple times.
* *
* <B>Note:</B> This method is optimized for handling parametric * <B>Note:</B> This method is optimized for handling parametric
* SQL statements that benefit from precompilation if the drivers * SQL statements that benefit from precompilation if the drivers
* supports precompilation. PostgreSQL does not support precompilation. * supports precompilation. PostgreSQL does not support precompilation.
* In this case, the statement is not sent to the database until the * In this case, the statement is not sent to the database until the
* PreparedStatement is executed. This has no direct effect on users; * PreparedStatement is executed. This has no direct effect on users;
* however it does affect which method throws certain SQLExceptions * however it does affect which method throws certain SQLExceptions
* *
* @param sql a SQL statement that may contain one or more '?' IN * @param sql a SQL statement that may contain one or more '?' IN
* parameter placeholders * parameter placeholders
* @return a new PreparedStatement object containing the pre-compiled * @return a new PreparedStatement object containing the pre-compiled
* statement. * statement.
* @exception SQLException if a database access error occurs. * @exception SQLException if a database access error occurs.
*/ */
public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
{ {
return new PreparedStatement(this, sql); return new PreparedStatement(this, sql);
} }
/** /**
* A SQL stored procedure call statement is handled by creating a * A SQL stored procedure call statement is handled by creating a
* CallableStatement for it. The CallableStatement provides methods * CallableStatement for it. The CallableStatement provides methods
* for setting up its IN and OUT parameters and methods for executing * for setting up its IN and OUT parameters and methods for executing
* it. * it.
* *
* <B>Note:</B> This method is optimised for handling stored procedure * <B>Note:</B> This method is optimised for handling stored procedure
* call statements. Some drivers may send the call statement to the * call statements. Some drivers may send the call statement to the
* database when the prepareCall is done; others may wait until the * database when the prepareCall is done; others may wait until the
* CallableStatement is executed. This has no direct effect on users; * CallableStatement is executed. This has no direct effect on users;
* however, it does affect which method throws certain SQLExceptions * however, it does affect which method throws certain SQLExceptions
* *
* @param sql a SQL statement that may contain one or more '?' parameter * @param sql a SQL statement that may contain one or more '?' parameter
* placeholders. Typically this statement is a JDBC function call * placeholders. Typically this statement is a JDBC function call
* escape string. * escape string.
* @return a new CallableStatement object containing the pre-compiled * @return a new CallableStatement object containing the pre-compiled
* SQL statement * SQL statement
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public java.sql.CallableStatement prepareCall(String sql) throws SQLException public java.sql.CallableStatement prepareCall(String sql) throws SQLException
{ {
throw new PSQLException("postgresql.con.call"); throw new PSQLException("postgresql.con.call");
// return new CallableStatement(this, sql); // return new CallableStatement(this, sql);
} }
/** /**
* Tests to see if a Connection is closed * Tests to see if a Connection is closed
* *
* @return the status of the connection * @return the status of the connection
* @exception SQLException (why?) * @exception SQLException (why?)
*/ */
public boolean isClosed() throws SQLException public boolean isClosed() throws SQLException
{ {
return (pg_stream == null); return (pg_stream == null);
} }
/** /**
* A connection's database is able to provide information describing * A connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the * its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is made * capabilities of this connection, etc. This information is made
* available through a DatabaseMetaData object. * available through a DatabaseMetaData object.
* *
* @return a DatabaseMetaData object for this connection * @return a DatabaseMetaData object for this connection
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public java.sql.DatabaseMetaData getMetaData() throws SQLException public java.sql.DatabaseMetaData getMetaData() throws SQLException
{ {
if(metadata==null) if (metadata == null)
metadata = new DatabaseMetaData(this); metadata = new DatabaseMetaData(this);
return metadata; return metadata;
} }
/** /**
* This overides the method in org.postgresql.Connection and returns a * This overides the method in org.postgresql.Connection and returns a
* ResultSet. * 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 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. // in jdbc1 stat is ignored.
return new org.postgresql.jdbc1.ResultSet((org.postgresql.jdbc1.Connection)conn,fields,tuples,status,updateCount,insertOID,binaryCursor); 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. /* An implementation of the abstract method in the parent class.
* This implemetation uses the jdbc1Types array to support the jdbc1 * This implemetation uses the jdbc1Types array to support the jdbc1
* datatypes. Basically jdbc1 and jdbc2 are the same, except that * datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types. * jdbc2 adds the Array types.
*/ */
public int getSQLType(String pgTypeName) public int getSQLType(String pgTypeName)
{ {
int sqlType = Types.OTHER; // default value int sqlType = Types.OTHER; // default value
for(int i=0;i<jdbc1Types.length;i++) { for (int i = 0;i < jdbc1Types.length;i++)
if(pgTypeName.equals(jdbc1Types[i])) { {
sqlType=jdbc1Typei[i]; if (pgTypeName.equals(jdbc1Types[i]))
break; {
} sqlType = jdbc1Typei[i];
} break;
return sqlType; }
} }
return sqlType;
}
/** /**
* This table holds the org.postgresql names for the types supported. * 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. * Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER * They default automatically to Types.OTHER
* *
* Note: This must be in the same order as below. * Note: This must be in the same order as below.
* *
* Tip: keep these grouped together by the Types. value * Tip: keep these grouped together by the Types. value
*/ */
private static final String jdbc1Types[] = { private static final String jdbc1Types[] = {
"int2", "int2",
"int4","oid", "int4", "oid",
"int8", "int8",
"cash","money", "cash", "money",
"numeric", "numeric",
"float4", "float4",
"float8", "float8",
"bpchar","char","char2","char4","char8","char16", "bpchar", "char", "char2", "char4", "char8", "char16",
"varchar","text","name","filename", "varchar", "text", "name", "filename",
"bytea", "bytea",
"bool", "bool",
"date", "date",
"time", "time",
"abstime","timestamp" "abstime", "timestamp"
}; };
/** /**
* This table holds the JDBC type for each entry above. * This table holds the JDBC type for each entry above.
* *
* Note: This must be in the same order as above * Note: This must be in the same order as above
* *
* Tip: keep these grouped together by the Types. value * Tip: keep these grouped together by the Types. value
*/ */
private static final int jdbc1Typei[] = { private static final int jdbc1Typei[] = {
Types.SMALLINT, Types.SMALLINT,
Types.INTEGER,Types.INTEGER, Types.INTEGER, Types.INTEGER,
Types.BIGINT, Types.BIGINT,
Types.DOUBLE,Types.DOUBLE, Types.DOUBLE, Types.DOUBLE,
Types.NUMERIC, Types.NUMERIC,
Types.REAL, Types.REAL,
Types.DOUBLE, Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.BINARY, Types.BINARY,
Types.BIT, Types.BIT,
Types.DATE, Types.DATE,
Types.TIME, Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP Types.TIMESTAMP, Types.TIMESTAMP
}; };
} }

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -24,440 +24,453 @@ import java.sql.Types;
*/ */
public class ResultSetMetaData implements java.sql.ResultSetMetaData public class ResultSetMetaData implements java.sql.ResultSetMetaData
{ {
Vector rows; Vector rows;
Field[] fields; Field[] fields;
/** /**
* Initialise for a result with a tuple set and * Initialise for a result with a tuple set and
* a field descriptor set * a field descriptor set
* *
* @param rows the Vector of rows returned by the ResultSet * @param rows the Vector of rows returned by the ResultSet
* @param fields the array of field descriptors * @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.
*/ */
return columnNullableUnknown; public ResultSetMetaData(Vector rows, Field[] fields)
} {
this.rows = rows;
this.fields = fields;
}
/** /**
* Is the column a signed number? In PostgreSQL, all numbers * Whats the number of columns in the ResultSet?
* are signed, so this is trivial. However, strings are not *
* signed (duh!) * @return the number
* * @exception SQLException if a database access error occurs
* @param column the first column is 1, the second is 2... */
* @return true if so public int getColumnCount() throws SQLException
* @exception SQLException if a database access error occurs {
*/ return fields.length;
public boolean isSigned(int column) throws SQLException }
{
int sql_type = getField(column).getSQLType();
switch (sql_type) /**
{ * Is the column automatically numbered (and thus read-only)
case Types.SMALLINT: * I believe that PostgreSQL does not support this feature.
case Types.INTEGER: *
case Types.FLOAT: * @param column the first column is 1, the second is 2...
case Types.REAL: * @return true if so
case Types.DOUBLE: * @exception SQLException if a database access error occurs
return true; */
case Types.DATE: public boolean isAutoIncrement(int column) throws SQLException
case Types.TIME: {
case Types.TIMESTAMP: return false;
return false; // I don't know about these? }
default:
return false;
}
}
/** /**
* What is the column's normal maximum width in characters? * 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, etc. *
* @return the maximum width * @param column the first column is 1, the second is 2...
* @exception SQLException if a database access error occurs * @return true if so
*/ * @exception SQLException if a database access error occurs
public int getColumnDisplaySize(int column) throws SQLException */
{ public boolean isCaseSensitive(int column) throws SQLException
Field f = getField(column); {
String type_name = f.getPGType(); int sql_type = getField(column).getSQLType();
int sql_type = f.getSQLType();
int typmod = f.getMod();
// I looked at other JDBC implementations and couldn't find a consistent switch (sql_type)
// 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 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;
}
}
// fixed length data types /**
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign) * Can the column be used in a WHERE clause? Basically for
if (type_name.equals( "int4" ) * this, I split the functions into two types: recognised
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647 * types (which are always useable), and OTHER types (which
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807 * may or may not be useable). The OTHER types, for now, I
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2) * will assume they are useable. We should really query the
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits * catalog to see if they are useable.
if (type_name.equals( "float8" )) return 20; // dito, 20 *
if (type_name.equals( "char" )) return 1; * @param column the first column is 1, the second is 2...
if (type_name.equals( "bool" )) return 1; * @return true if they can be used in a WHERE clause
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD" * @exception SQLException if a database access error occurs
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 public boolean isSearchable(int column) throws SQLException
{
int sql_type = getField(column).getSQLType();
// variable length fields // This switch is pointless, I know - but it is a set-up
typmod -= 4; // for further expansion.
if (type_name.equals( "bpchar" ) switch (sql_type)
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4 {
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff ) case Types.OTHER:
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits) return true;
default:
return true;
}
}
// if we don't know better /**
return f.getLength(); * 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");
* 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? * Indicates the nullability of values in the designated column.
* *
* @param column the first column is 1, the second is 2, etc. * @param column the first column is 1, the second is 2...
* @return the column name * @return one of the columnNullable values
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public String getColumnName(int column) throws SQLException public int isNullable(int column) throws SQLException
{ {
Field f = getField(column); /*
if(f!=null) * TODO This needs a real implementation, taking into account columns
return f.getName(); * defined with NOT NULL or PRIMARY KEY, CHECK constraints, views,
return "field"+column; * functions etc.
} */
return columnNullableUnknown;
}
/** /**
* What is a column's table's schema? This relies on us knowing * Is the column a signed number? In PostgreSQL, all numbers
* the table name....which I don't know how to do as yet. The * are signed, so this is trivial. However, strings are not
* JDBC specification allows us to return "" if this is not * signed (duh!)
* applicable. *
* * @param column the first column is 1, the second is 2...
* @param column the first column is 1, the second is 2... * @return true if so
* @return the Schema * @exception SQLException if a database access error occurs
* @exception SQLException if a database access error occurs */
*/ public boolean isSigned(int column) throws SQLException
public String getSchemaName(int column) throws SQLException {
{ int sql_type = getField(column).getSQLType();
return "";
}
/** switch (sql_type)
* What is a column's number of decimal digits. {
* case Types.SMALLINT:
* @param column the first column is 1, the second is 2... case Types.INTEGER:
* @return the precision case Types.FLOAT:
* @exception SQLException if a database access error occurs case Types.REAL:
*/ case Types.DOUBLE:
public int getPrecision(int column) throws SQLException return true;
{ case Types.DATE:
int sql_type = getField(column).getSQLType(); case Types.TIME:
case Types.TIMESTAMP:
return false; // I don't know about these?
default:
return false;
}
}
switch (sql_type) /**
{ * What is the column's normal maximum width in characters?
case Types.SMALLINT: *
return 5; * @param column the first column is 1, the second is 2, etc.
case Types.INTEGER: * @return the maximum width
return 10; * @exception SQLException if a database access error occurs
case Types.REAL: */
return 8; public int getColumnDisplaySize(int column) throws SQLException
case Types.FLOAT: {
return 16; Field f = getField(column);
case Types.DOUBLE: String type_name = f.getPGType();
return 16; int sql_type = f.getSQLType();
case Types.VARCHAR: int typmod = f.getMod();
return 0;
case Types.NUMERIC:
Field f = getField(column);
if(f != null)
return ((0xFFFF0000)&f.getMod())>>16;
else
return 0;
default:
return 0;
}
}
/** // I looked at other JDBC implementations and couldn't find a consistent
* What is a column's number of digits to the right of the // interpretation of the "display size" for numeric values, so this is our's
* decimal point? // FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
*
* @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) // fixed length data types
{ if (type_name.equals( "int2" ))
case Types.SMALLINT: return 6; // -32768 to +32768 (5 digits and a sign)
return 0; if (type_name.equals( "int4" )
case Types.INTEGER: || type_name.equals( "oid" ))
return 0; return 11; // -2147483648 to +2147483647
case Types.REAL: if (type_name.equals( "int8" ))
return 8; return 20; // -9223372036854775808 to +9223372036854775807
case Types.FLOAT: if (type_name.equals( "money" ))
return 16; return 12; // MONEY = DECIMAL(9,2)
case Types.DOUBLE: if (type_name.equals( "float4" ))
return 16; return 11; // i checked it out ans wasn't able to produce more than 11 digits
case Types.VARCHAR: if (type_name.equals( "float8" ))
return 0; return 20; // dito, 20
case Types.NUMERIC: if (type_name.equals( "char" ))
Field f = getField(column); return 1;
if(f != null) if (type_name.equals( "bool" ))
return (((0x0000FFFF)&f.getMod())-4); return 1;
else if (type_name.equals( "date" ))
return 0; return 14; // "01/01/4713 BC" - "31/12/32767 AD"
default: if (type_name.equals( "time" ))
return 0; 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
* Whats a column's table's name? How do I find this out? Both typmod -= 4;
* getSchemaName() and getCatalogName() rely on knowing the table if (type_name.equals( "bpchar" )
* Name, so we need this before we can work on them. || type_name.equals( "varchar" ))
* return typmod; // VARHDRSZ=sizeof(int32)=4
* @param column the first column is 1, the second is 2... if (type_name.equals( "numeric" ))
* @return column name, or "" if not applicable return ( (typmod >> 16) & 0xffff )
* @exception SQLException if a database access error occurs + 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
*/
public String getTableName(int column) throws SQLException
{
return "";
}
/** // if we don't know better
* What's a column's table's catalog name? As with getSchemaName(), return f.getLength();
* 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) * 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 java.sql.Type value * @param column the first column is 1, the second is 2, etc.
* @exception SQLException if a database access error occurs * @return the column label
* @see org.postgresql.Field#getSQLType * @exception SQLException if a database access error occurs
* @see java.sql.Types */
*/ public String getColumnLabel(int column) throws SQLException
public int getColumnType(int column) throws SQLException {
{ return getColumnName(column);
return getField(column).getSQLType(); }
}
/** /**
* Whats is the column's data source specific type name? * What's a column's name?
* *
* @param column the first column is 1, the second is 2, etc. * @param column the first column is 1, the second is 2, etc.
* @return the type name * @return the column name
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public String getColumnTypeName(int column) throws SQLException public String getColumnName(int column) throws SQLException
{ {
return getField(column).getPGType(); Field f = getField(column);
} if (f != null)
return f.getName();
return "field" + column;
}
/** /**
* Is the column definitely not writable? In reality, we would * What is a column's table's schema? This relies on us knowing
* have to check the GRANT/REVOKE stuff for this to be effective, * the table name....which I don't know how to do as yet. The
* and I haven't really looked into that yet, so this will get * JDBC specification allows us to return "" if this is not
* re-visited. * applicable.
* *
* @param column the first column is 1, the second is 2, etc. * @param column the first column is 1, the second is 2...
* @return true if so * @return the Schema
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public boolean isReadOnly(int column) throws SQLException public String getSchemaName(int column) throws SQLException
{ {
return false; return "";
} }
/** /**
* Is it possible for a write on the column to succeed? Again, we * What is a column's number of decimal digits.
* 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 * @param column the first column is 1, the second is 2...
* it is obviously writable. * @return the precision
* * @exception SQLException if a database access error occurs
* @param column the first column is 1, the second is 2, etc. */
* @return true if so public int getPrecision(int column) throws SQLException
* @exception SQLException if a database access error occurs {
*/ int sql_type = getField(column).getSQLType();
public boolean isWritable(int column) throws SQLException
{
return !isReadOnly(column);
}
/** switch (sql_type)
* Will a write on this column definately succeed? Hmmm...this {
* is a bad one, since the two preceding functions have not been case Types.SMALLINT:
* really defined. I cannot tell is the short answer. I thus return 5;
* return isWritable() just to give us an idea. case Types.INTEGER:
* return 10;
* @param column the first column is 1, the second is 2, etc.. case Types.REAL:
* @return true if so return 8;
* @exception SQLException if a database access error occurs case Types.FLOAT:
*/ return 16;
public boolean isDefinitelyWritable(int column) throws SQLException case Types.DOUBLE:
{ return 16;
return false; 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;
}
}
// ******************************************************** /**
// END OF PUBLIC INTERFACE * 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)
* For several routines in this package, we need to convert {
* a columnIndex into a Field[] descriptor. Rather than do case Types.SMALLINT:
* the same code several times, here it is. return 0;
* case Types.INTEGER:
* @param columnIndex the first column is 1, the second is 2... return 0;
* @return the Field description case Types.REAL:
* @exception SQLException if a database access error occurs return 8;
*/ case Types.FLOAT:
private Field getField(int columnIndex) throws SQLException return 16;
{ case Types.DOUBLE:
if (columnIndex < 1 || columnIndex > fields.length) return 16;
throw new PSQLException("postgresql.res.colrange"); case Types.VARCHAR:
return fields[columnIndex - 1]; 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. * <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 * Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different * 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. * statement's current ResultSet if an open one exists.
* *
* @see java.sql.Statement * @see java.sql.Statement
@@ -24,7 +24,7 @@ import org.postgresql.util.PSQLException;
*/ */
public class Statement extends org.postgresql.Statement implements java.sql.Statement 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 * 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 * 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 * positioned update/delete statements to identify the current row
* in the ResultSet generated by this statement. If a database * in the ResultSet generated by this statement. If a database
* doesn't support positioned update/delete, this method is a * 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 * <p><B>Note:</B> By definition, positioned update/delete execution
* must be done by a different Statement than the one which * 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. * 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. * cursor active at any one time.
* *
* @param name the new cursor name * @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 * Execute a SQL statement that may return multiple results. We
* don't have to worry about this since we do not support multiple * 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. * retrieve the result.
* *
* @param sql any SQL statement * @param sql any SQL statement
* @return true if the next result is a ResulSet, false if it is * @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 * @exception SQLException if a database access error occurs
*/ */
public boolean execute(String sql) throws SQLException public boolean execute(String sql) throws SQLException
{ {
if (escapeProcessing) if (escapeProcessing)
sql = escapeSQL(sql); sql = escapeSQL(sql);
result = connection.ExecSQL(sql); result = connection.ExecSQL(sql);
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet()); 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 public int getUpdateCount() throws SQLException
{ {
if (result == null) return -1; if (result == null)
if (((org.postgresql.ResultSet)result).reallyResultSet()) return -1; return -1;
if (((org.postgresql.ResultSet)result).reallyResultSet())
return -1;
return ((org.postgresql.ResultSet)result).getResultCount(); return ((org.postgresql.ResultSet)result).getResultCount();
} }

View File

@@ -25,22 +25,22 @@ import org.postgresql.util.*;
public class Array implements java.sql.Array public class Array implements java.sql.Array
{ {
private org.postgresql.Connection conn = null; private org.postgresql.Connection conn = null;
private org.postgresql.Field field = null; private org.postgresql.Field field = null;
private org.postgresql.jdbc2.ResultSet rs = null; private org.postgresql.jdbc2.ResultSet rs = null;
private int idx = 0; private int idx = 0;
private String rawString = null; private String rawString = null;
/** /**
* Create a new Array * Create a new Array
* *
* @param conn a database connection * @param conn a database connection
* @param idx 1-based index of the query field to load into this Array * @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 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 * @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 ) public Array( org.postgresql.Connection conn, int idx, Field field, org.postgresql.jdbc2.ResultSet rs )
throws SQLException throws SQLException
{ {
this.conn = conn; this.conn = conn;
this.field = field; this.field = field;
@@ -49,45 +49,54 @@ public class Array implements java.sql.Array
this.rawString = rs.getFixedString(idx); this.rawString = rs.getFixedString(idx);
} }
public Object getArray() throws SQLException { public Object getArray() throws SQLException
{
return getArray( 1, 0, null ); 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 ); return getArray( index, count, null );
} }
public Object getArray(Map map) throws SQLException { public Object getArray(Map map) throws SQLException
{
return getArray( 1, 0, map ); return getArray( 1, 0, map );
} }
public Object getArray(long index, int count, Map map) throws SQLException { 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 ( map != null ) // For now maps aren't supported.
throw org.postgresql.Driver.notImplemented();
if (index < 1) if (index < 1)
throw new PSQLException("postgresql.arr.range"); throw new PSQLException("postgresql.arr.range");
Object retVal = null; Object retVal = null;
ArrayList array = new ArrayList(); ArrayList array = new ArrayList();
if( rawString != null ) { if ( rawString != null )
{
char[] chars = rawString.toCharArray(); char[] chars = rawString.toCharArray();
StringBuffer sbuf = new StringBuffer(); StringBuffer sbuf = new StringBuffer();
boolean foundOpen = false; boolean foundOpen = false;
boolean insideString = false; boolean insideString = false;
for( int i=0; i<chars.length; i++ ) { for ( int i = 0; i < chars.length; i++ )
if( chars[i] == '{' ) { {
if( foundOpen ) // Only supports 1-D arrays for now if ( chars[i] == '{' )
{
if ( foundOpen ) // Only supports 1-D arrays for now
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
foundOpen = true; foundOpen = true;
continue; continue;
} }
if( chars[i] == '"' ) { if ( chars[i] == '"' )
{
insideString = !insideString; insideString = !insideString;
continue; continue;
} }
if( (!insideString && chars[i] == ',') || chars[i] == '}' || i == chars.length-1) { if ( (!insideString && chars[i] == ',') || chars[i] == '}' || i == chars.length - 1)
if( chars[i] != '"' && chars[i] != '}' && chars[i] != ',' ) {
if ( chars[i] != '"' && chars[i] != '}' && chars[i] != ',' )
sbuf.append(chars[i]); sbuf.append(chars[i]);
array.add( sbuf.toString() ); array.add( sbuf.toString() );
sbuf = new StringBuffer(); sbuf = new StringBuffer();
@@ -97,221 +106,240 @@ public class Array implements java.sql.Array
} }
} }
String[] arrayContents = (String[]) array.toArray( new String[array.size()] ); String[] arrayContents = (String[]) array.toArray( new String[array.size()] );
if( count == 0 ) if ( count == 0 )
count = arrayContents.length; count = arrayContents.length;
index--; index--;
if( index+count > arrayContents.length ) if ( index + count > arrayContents.length )
throw new PSQLException("postgresql.arr.range"); throw new PSQLException("postgresql.arr.range");
int i = 0; int i = 0;
switch ( getBaseType() ) switch ( getBaseType() )
{ {
case Types.BIT: case Types.BIT:
retVal = new boolean[ count ]; retVal = new boolean[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((boolean[])retVal)[i++] = ResultSet.toBoolean( arrayContents[(int)index++] ); ((boolean[])retVal)[i++] = ResultSet.toBoolean( arrayContents[(int)index++] );
break; break;
case Types.SMALLINT: case Types.SMALLINT:
case Types.INTEGER: case Types.INTEGER:
retVal = new int[ count ]; retVal = new int[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((int[])retVal)[i++] = ResultSet.toInt( arrayContents[(int)index++] ); ((int[])retVal)[i++] = ResultSet.toInt( arrayContents[(int)index++] );
break; break;
case Types.BIGINT: case Types.BIGINT:
retVal = new long[ count ]; retVal = new long[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((long[])retVal)[i++] = ResultSet.toLong( arrayContents[(int)index++] ); ((long[])retVal)[i++] = ResultSet.toLong( arrayContents[(int)index++] );
break; break;
case Types.NUMERIC: case Types.NUMERIC:
retVal = new BigDecimal[ count ]; retVal = new BigDecimal[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((BigDecimal[])retVal)[i] = ResultSet.toBigDecimal( arrayContents[(int)index++], 0 ); ((BigDecimal[])retVal)[i] = ResultSet.toBigDecimal( arrayContents[(int)index++], 0 );
break; break;
case Types.REAL: case Types.REAL:
retVal = new float[ count ]; retVal = new float[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((float[])retVal)[i++] = ResultSet.toFloat( arrayContents[(int)index++] ); ((float[])retVal)[i++] = ResultSet.toFloat( arrayContents[(int)index++] );
break; break;
case Types.DOUBLE: case Types.DOUBLE:
retVal = new double[ count ]; retVal = new double[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((double[])retVal)[i++] = ResultSet.toDouble( arrayContents[(int)index++] ); ((double[])retVal)[i++] = ResultSet.toDouble( arrayContents[(int)index++] );
break; break;
case Types.CHAR: case Types.CHAR:
case Types.VARCHAR: case Types.VARCHAR:
retVal = new String[ count ]; retVal = new String[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((String[])retVal)[i++] = arrayContents[(int)index++]; ((String[])retVal)[i++] = arrayContents[(int)index++];
break; break;
case Types.DATE: case Types.DATE:
retVal = new java.sql.Date[ count ]; retVal = new java.sql.Date[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((java.sql.Date[])retVal)[i++] = ResultSet.toDate( arrayContents[(int)index++] ); ((java.sql.Date[])retVal)[i++] = ResultSet.toDate( arrayContents[(int)index++] );
break; break;
case Types.TIME: case Types.TIME:
retVal = new java.sql.Time[ count ]; retVal = new java.sql.Time[ count ];
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((java.sql.Time[])retVal)[i++] = ResultSet.toTime( arrayContents[(int)index++] ); ((java.sql.Time[])retVal)[i++] = ResultSet.toTime( arrayContents[(int)index++] );
break; break;
case Types.TIMESTAMP: case Types.TIMESTAMP:
retVal = new Timestamp[ count ]; retVal = new Timestamp[ count ];
StringBuffer sbuf = null; StringBuffer sbuf = null;
for( ; count > 0; count-- ) for ( ; count > 0; count-- )
((java.sql.Timestamp[])retVal)[i++] = ResultSet.toTimestamp( arrayContents[(int)index], rs ); ((java.sql.Timestamp[])retVal)[i++] = ResultSet.toTimestamp( arrayContents[(int)index], rs );
break; break;
// Other datatypes not currently supported. If you are really using other types ask // 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. // yourself if an array of non-trivial data types is really good database design.
default: default:
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
return retVal; return retVal;
} }
public int getBaseType() throws SQLException { public int getBaseType() throws SQLException
return conn.getSQLType(getBaseTypeName()); {
return conn.getSQLType(getBaseTypeName());
} }
public String getBaseTypeName() throws SQLException { public String getBaseTypeName() throws SQLException
String fType = field.getPGType(); {
if( fType.charAt(0) == '_' ) String fType = field.getPGType();
if ( fType.charAt(0) == '_' )
fType = fType.substring(1); fType = fType.substring(1);
return fType; return fType;
} }
public java.sql.ResultSet getResultSet() throws SQLException { public java.sql.ResultSet getResultSet() throws SQLException
{
return getResultSet( 1, 0, null ); 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 ); 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 ); 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 ); Object array = getArray( index, count, map );
Vector rows = new Vector(); Vector rows = new Vector();
Field[] fields = new Field[2]; 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() ) switch ( getBaseType() )
{ {
case Types.BIT: case Types.BIT:
boolean[] booleanArray = (boolean[]) array; boolean[] booleanArray = (boolean[]) array;
fields[1] = new Field(conn, "VALUE", conn.getOID("bool"), 1); fields[1] = new Field(conn, "VALUE", conn.getOID("bool"), 1);
for( int i=0; i<booleanArray.length; i++ ) { 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 byte[][] tuple = new byte[2][0];
tuple[1] = conn.getEncoding().encode( (booleanArray[i]?"YES":"NO") ); // Value tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
rows.addElement(tuple); 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.SMALLINT:
case Types.INTEGER: fields[1] = new Field(conn, "VALUE", conn.getOID("int2"), 2);
int[] intArray = (int[]) array; case Types.INTEGER:
if( fields[1] == null ) int[] intArray = (int[]) array;
fields[1] = new Field(conn, "VALUE", conn.getOID("int4"), 4); if ( fields[1] == null )
for( int i=0; i<intArray.length; i++ ) { fields[1] = new Field(conn, "VALUE", conn.getOID("int4"), 4);
byte[][] tuple = new byte[2][0]; for ( int i = 0; i < intArray.length; i++ )
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index {
tuple[1] = conn.getEncoding().encode( Integer.toString(intArray[i]) ); // Value byte[][] tuple = new byte[2][0];
rows.addElement(tuple); tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
} tuple[1] = conn.getEncoding().encode( Integer.toString(intArray[i]) ); // Value
break; rows.addElement(tuple);
case Types.BIGINT: }
long[] longArray = (long[]) array; break;
fields[1] = new Field(conn, "VALUE", conn.getOID("int8"), 8); case Types.BIGINT:
for( int i=0; i<longArray.length; i++ ) { long[] longArray = (long[]) array;
byte[][] tuple = new byte[2][0]; fields[1] = new Field(conn, "VALUE", conn.getOID("int8"), 8);
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index for ( int i = 0; i < longArray.length; i++ )
tuple[1] = conn.getEncoding().encode( Long.toString(longArray[i]) ); // Value {
rows.addElement(tuple); byte[][] tuple = new byte[2][0];
} tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
break; tuple[1] = conn.getEncoding().encode( Long.toString(longArray[i]) ); // Value
case Types.NUMERIC: rows.addElement(tuple);
BigDecimal[] bdArray = (BigDecimal[]) array; }
fields[1] = new Field(conn, "VALUE", conn.getOID("numeric"), -1); break;
for( int i=0; i<bdArray.length; i++ ) { case Types.NUMERIC:
byte[][] tuple = new byte[2][0]; BigDecimal[] bdArray = (BigDecimal[]) array;
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index fields[1] = new Field(conn, "VALUE", conn.getOID("numeric"), -1);
tuple[1] = conn.getEncoding().encode( bdArray[i].toString() ); // Value for ( int i = 0; i < bdArray.length; i++ )
rows.addElement(tuple); {
} byte[][] tuple = new byte[2][0];
break; tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
case Types.REAL: tuple[1] = conn.getEncoding().encode( bdArray[i].toString() ); // Value
float[] floatArray = (float[]) array; rows.addElement(tuple);
fields[1] = new Field(conn, "VALUE", conn.getOID("float4"), 4); }
for( int i=0; i<floatArray.length; i++ ) { break;
byte[][] tuple = new byte[2][0]; case Types.REAL:
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index float[] floatArray = (float[]) array;
tuple[1] = conn.getEncoding().encode( Float.toString(floatArray[i]) ); // Value fields[1] = new Field(conn, "VALUE", conn.getOID("float4"), 4);
rows.addElement(tuple); for ( int i = 0; i < floatArray.length; i++ )
} {
break; byte[][] tuple = new byte[2][0];
case Types.DOUBLE: tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
double[] doubleArray = (double[]) array; tuple[1] = conn.getEncoding().encode( Float.toString(floatArray[i]) ); // Value
fields[1] = new Field(conn, "VALUE", conn.getOID("float8"), 8); rows.addElement(tuple);
for( int i=0; i<doubleArray.length; i++ ) { }
byte[][] tuple = new byte[2][0]; break;
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index case Types.DOUBLE:
tuple[1] = conn.getEncoding().encode( Double.toString(doubleArray[i]) ); // Value double[] doubleArray = (double[]) array;
rows.addElement(tuple); fields[1] = new Field(conn, "VALUE", conn.getOID("float8"), 8);
} for ( int i = 0; i < doubleArray.length; i++ )
break; {
case Types.CHAR: byte[][] tuple = new byte[2][0];
fields[1] = new Field(conn, "VALUE", conn.getOID("char"), 1); tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
case Types.VARCHAR: tuple[1] = conn.getEncoding().encode( Double.toString(doubleArray[i]) ); // Value
String[] strArray = (String[]) array; rows.addElement(tuple);
if( fields[1] == null ) }
fields[1] = new Field(conn, "VALUE", conn.getOID("varchar"), -1); break;
for( int i=0; i<strArray.length; i++ ) { case Types.CHAR:
byte[][] tuple = new byte[2][0]; fields[1] = new Field(conn, "VALUE", conn.getOID("char"), 1);
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index case Types.VARCHAR:
tuple[1] = conn.getEncoding().encode( strArray[i] ); // Value String[] strArray = (String[]) array;
rows.addElement(tuple); if ( fields[1] == null )
} fields[1] = new Field(conn, "VALUE", conn.getOID("varchar"), -1);
break; for ( int i = 0; i < strArray.length; i++ )
case Types.DATE: {
java.sql.Date[] dateArray = (java.sql.Date[]) array; byte[][] tuple = new byte[2][0];
fields[1] = new Field(conn, "VALUE", conn.getOID("date"), 4); tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
for( int i=0; i<dateArray.length; i++ ) { tuple[1] = conn.getEncoding().encode( strArray[i] ); // Value
byte[][] tuple = new byte[2][0]; rows.addElement(tuple);
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index }
tuple[1] = conn.getEncoding().encode( dateArray[i].toString() ); // Value break;
rows.addElement(tuple); case Types.DATE:
} java.sql.Date[] dateArray = (java.sql.Date[]) array;
break; fields[1] = new Field(conn, "VALUE", conn.getOID("date"), 4);
case Types.TIME: for ( int i = 0; i < dateArray.length; i++ )
java.sql.Time[] timeArray = (java.sql.Time[]) array; {
fields[1] = new Field(conn, "VALUE", conn.getOID("time"), 8); byte[][] tuple = new byte[2][0];
for( int i=0; i<timeArray.length; i++ ) { tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
byte[][] tuple = new byte[2][0]; tuple[1] = conn.getEncoding().encode( dateArray[i].toString() ); // Value
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index rows.addElement(tuple);
tuple[1] = conn.getEncoding().encode( timeArray[i].toString() ); // Value }
rows.addElement(tuple); break;
} case Types.TIME:
break; java.sql.Time[] timeArray = (java.sql.Time[]) array;
case Types.TIMESTAMP: fields[1] = new Field(conn, "VALUE", conn.getOID("time"), 8);
java.sql.Timestamp[] timestampArray = (java.sql.Timestamp[]) array; for ( int i = 0; i < timeArray.length; i++ )
fields[1] = new Field(conn, "VALUE", conn.getOID("timestamp"), 8); {
for( int i=0; i<timestampArray.length; i++ ) { byte[][] tuple = new byte[2][0];
byte[][] tuple = new byte[2][0]; tuple[0] = conn.getEncoding().encode( Integer.toString((int)index + i) ); // Index
tuple[0] = conn.getEncoding().encode( Integer.toString((int)index+i) ); // Index tuple[1] = conn.getEncoding().encode( timeArray[i].toString() ); // Value
tuple[1] = conn.getEncoding().encode( timestampArray[i].toString() ); // Value rows.addElement(tuple);
rows.addElement(tuple); }
} break;
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 // 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. // yourself if an array of non-trivial data types is really good database design.
default: default:
throw org.postgresql.Driver.notImplemented(); 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 public class CallableStatement extends org.postgresql.jdbc2.PreparedStatement implements java.sql.CallableStatement
{ {
/** /**
* @exception SQLException on failure * @exception SQLException on failure
*/ */
public CallableStatement(Connection c,String q) throws SQLException public CallableStatement(Connection c, String q) throws SQLException
{ {
super(c,q); super(c, q);
} }
/** /**
* Before executing a stored procedure call you must explicitly * Before executing a stored procedure call you must explicitly
* call registerOutParameter to register the java.sql.Type of each * call registerOutParameter to register the java.sql.Type of each
* out parameter. * out parameter.
* *
* <p>Note: When reading the value of an out parameter, you must use * <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the * the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type. * parameter's registered SQL type.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for * @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of * parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value * registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException { public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
} {}
/** /**
* You must also specify the scale for numeric/decimal types: * You must also specify the scale for numeric/decimal types:
* *
* <p>Note: When reading the value of an out parameter, you must use * <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the * the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type. * parameter's registered SQL type.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the * @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point * desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public void registerOutParameter(int parameterIndex, int sqlType, public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException int scale) throws SQLException
{ {}
}
// Old api? // Old api?
//public boolean isNull(int parameterIndex) throws SQLException { //public boolean isNull(int parameterIndex) throws SQLException {
//return true; //return true;
//} //}
/** /**
* An OUT parameter may have the value of SQL NULL; wasNull * An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value. * reports whether the last value read has this special value.
* *
* <p>Note: You must first call getXXX on a parameter to read its * <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. * value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL * @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public boolean wasNull() throws SQLException { public boolean wasNull() throws SQLException
// check to see if the last access threw an exception {
return false; // fake it for now // check to see if the last access threw an exception
} return false; // fake it for now
}
// Old api? // Old api?
//public String getChar(int parameterIndex) throws SQLException { //public String getChar(int parameterIndex) throws SQLException {
//return null; //return null;
//} //}
/** /**
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a * Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String. * Java String.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public String getString(int parameterIndex) throws SQLException { public String getString(int parameterIndex) throws SQLException
return null; {
} return null;
//public String getVarChar(int parameterIndex) throws SQLException { }
// return null; //public String getVarChar(int parameterIndex) throws SQLException {
//} // return null;
//}
//public String getLongVarChar(int parameterIndex) throws SQLException { //public String getLongVarChar(int parameterIndex) throws SQLException {
//return null; //return null;
//} //}
/** /**
* Get the value of a BIT parameter as a Java boolean. * Get the value of a BIT parameter as a Java boolean.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public boolean getBoolean(int parameterIndex) throws SQLException { public boolean getBoolean(int parameterIndex) throws SQLException
return false; {
} return false;
}
/** /**
* Get the value of a TINYINT parameter as a Java byte. * Get the value of a TINYINT parameter as a Java byte.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public byte getByte(int parameterIndex) throws SQLException { public byte getByte(int parameterIndex) throws SQLException
return 0; {
} return 0;
}
/** /**
* Get the value of a SMALLINT parameter as a Java short. * Get the value of a SMALLINT parameter as a Java short.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public short getShort(int parameterIndex) throws SQLException { public short getShort(int parameterIndex) throws SQLException
return 0; {
} return 0;
}
/** /**
* Get the value of an INTEGER parameter as a Java int. * Get the value of an INTEGER parameter as a Java int.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public int getInt(int parameterIndex) throws SQLException { public int getInt(int parameterIndex) throws SQLException
return 0; {
} return 0;
}
/** /**
* Get the value of a BIGINT parameter as a Java long. * Get the value of a BIGINT parameter as a Java long.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public long getLong(int parameterIndex) throws SQLException { public long getLong(int parameterIndex) throws SQLException
return 0; {
} return 0;
}
/** /**
* Get the value of a FLOAT parameter as a Java float. * Get the value of a FLOAT parameter as a Java float.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public float getFloat(int parameterIndex) throws SQLException { public float getFloat(int parameterIndex) throws SQLException
return (float) 0.0; {
} return (float) 0.0;
}
/** /**
* Get the value of a DOUBLE parameter as a Java double. * Get the value of a DOUBLE parameter as a Java double.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public double getDouble(int parameterIndex) throws SQLException { public double getDouble(int parameterIndex) throws SQLException
return 0.0; {
} return 0.0;
}
/** /**
* Get the value of a NUMERIC parameter as a java.math.BigDecimal * Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object. * object.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the * @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point * 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 * @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
* @deprecated in Java2.0 * @deprecated in Java2.0
*/ */
public BigDecimal getBigDecimal(int parameterIndex, int scale) public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException { throws SQLException
return null; {
} return null;
}
/** /**
* Get the value of a SQL BINARY or VARBINARY parameter as a Java * Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[] * byte[]
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @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 * @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public byte[] getBytes(int parameterIndex) throws SQLException { public byte[] getBytes(int parameterIndex) throws SQLException
return null; {
} return null;
}
// New API (JPM) (getLongVarBinary) // New API (JPM) (getLongVarBinary)
//public byte[] getBinaryStream(int parameterIndex) throws SQLException { //public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null; //return null;
//} //}
/** /**
* Get the value of a SQL DATE parameter as a java.sql.Date object * 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,... * @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 * @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public java.sql.Date getDate(int parameterIndex) throws SQLException { public java.sql.Date getDate(int parameterIndex) throws SQLException
return null; {
} return null;
}
/** /**
* Get the value of a SQL TIME parameter as a java.sql.Time object. * 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,... * @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 * @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public java.sql.Time getTime(int parameterIndex) throws SQLException { public java.sql.Time getTime(int parameterIndex) throws SQLException
return null; {
} return null;
}
/** /**
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object. * 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,... * @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 * @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public java.sql.Timestamp getTimestamp(int parameterIndex) public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException { throws SQLException
return null; {
} return null;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Advanced features: // Advanced features:
// You can obtain a ParameterMetaData object to get information // You can obtain a ParameterMetaData object to get information
// about the parameters to this CallableStatement. // about the parameters to this CallableStatement.
//public DatabaseMetaData getMetaData() { //public DatabaseMetaData getMetaData() {
//return null; //return null;
//} //}
// getObject returns a Java object for the parameter. // getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details. // See the JDBC spec's "Dynamic Programming" chapter for details.
/** /**
* Get the value of a parameter as a Java object. * Get the value of a parameter as a Java object.
* *
* <p>This method returns a Java object whose type coresponds to the * <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using * SQL type that was registered for this parameter using
* registerOutParameter. * registerOutParameter.
* *
* <P>Note that this method may be used to read datatabase-specific, * <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType * abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a * of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type. * database-specific Java type.
* *
* <p>See the JDBC spec's "Dynamic Programming" chapter for details. * <p>See the JDBC spec's "Dynamic Programming" chapter for details.
* *
* @param parameterIndex the first parameter is 1, the second is 2,... * @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value. * @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs. * @exception SQLException if a database-access error occurs.
*/ */
public Object getObject(int parameterIndex) public Object getObject(int parameterIndex)
throws SQLException { throws SQLException
return null; {
} return null;
}
// ** JDBC 2 Extensions ** // ** JDBC 2 Extensions **
public java.sql.Array getArray(int i) throws SQLException public java.sql.Array getArray(int i) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public java.math.BigDecimal getBigDecimal(int i) throws SQLException public java.math.BigDecimal getBigDecimal(int i) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public Blob getBlob(int i) throws SQLException public Blob getBlob(int i) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public Clob getClob(int i) throws SQLException public Clob getClob(int i) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public Object getObject(int i,java.util.Map map) throws SQLException public Object getObject(int i, java.util.Map map) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public Ref getRef(int i) throws SQLException public Ref getRef(int i) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public java.sql.Date getDate(int i,java.util.Calendar cal) throws SQLException public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public Time getTime(int i,java.util.Calendar cal) throws SQLException public Time getTime(int i, java.util.Calendar cal) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public Timestamp getTimestamp(int i,java.util.Calendar cal) throws SQLException public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void registerOutParameter(int parameterIndex, int sqlType,String typeName) throws SQLException public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
} }

View File

@@ -17,9 +17,9 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*; 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 * context of a Connection, SQL statements are executed and results are
* returned. * returned.
* *
@@ -29,306 +29,314 @@ import org.postgresql.util.*;
* with the getMetaData method. * with the getMetaData method.
* *
* <p><B>Note:</B> By default, the Connection automatically commits changes * <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. * explicit commit must be done or database changes will not be saved.
* *
* @see java.sql.Connection * @see java.sql.Connection
*/ */
public class Connection extends org.postgresql.Connection implements 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 // This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata; protected DatabaseMetaData metadata;
/** /**
* The current type mappings * The current type mappings
*/ */
protected java.util.Map typemap; protected java.util.Map typemap;
/** /**
* SQL statements without parameters are normally executed using * SQL statements without parameters are normally executed using
* Statement objects. If the same SQL statement is executed many * Statement objects. If the same SQL statement is executed many
* times, it is more efficient to use a PreparedStatement * times, it is more efficient to use a PreparedStatement
* *
* @return a new Statement object * @return a new Statement object
* @exception SQLException passed through from the constructor * @exception SQLException passed through from the constructor
*/ */
public java.sql.Statement createStatement() throws SQLException public java.sql.Statement createStatement() throws SQLException
{ {
// The spec says default of TYPE_FORWARD_ONLY but everyone is used to // The spec says default of TYPE_FORWARD_ONLY but everyone is used to
// using TYPE_SCROLL_INSENSITIVE // using TYPE_SCROLL_INSENSITIVE
return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY); return createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
} }
/** /**
* SQL statements without parameters are normally executed using * SQL statements without parameters are normally executed using
* Statement objects. If the same SQL statement is executed many * Statement objects. If the same SQL statement is executed many
* times, it is more efficient to use a PreparedStatement * times, it is more efficient to use a PreparedStatement
* *
* @param resultSetType to use * @param resultSetType to use
* @param resultSetCuncurrency to use * @param resultSetCuncurrency to use
* @return a new Statement object * @return a new Statement object
* @exception SQLException passed through from the constructor * @exception SQLException passed through from the constructor
*/ */
public java.sql.Statement createStatement(int resultSetType,int resultSetConcurrency) throws SQLException public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{ {
Statement s = new Statement(this); Statement s = new Statement(this);
s.setResultSetType(resultSetType); s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency); s.setResultSetConcurrency(resultSetConcurrency);
return s; return s;
} }
/** /**
* A SQL statement with or without IN parameters can be pre-compiled * A SQL statement with or without IN parameters can be pre-compiled
* and stored in a PreparedStatement object. This object can then * and stored in a PreparedStatement object. This object can then
* be used to efficiently execute this statement multiple times. * be used to efficiently execute this statement multiple times.
* *
* <B>Note:</B> This method is optimized for handling parametric * <B>Note:</B> This method is optimized for handling parametric
* SQL statements that benefit from precompilation if the drivers * SQL statements that benefit from precompilation if the drivers
* supports precompilation. PostgreSQL does not support precompilation. * supports precompilation. PostgreSQL does not support precompilation.
* In this case, the statement is not sent to the database until the * In this case, the statement is not sent to the database until the
* PreparedStatement is executed. This has no direct effect on users; * PreparedStatement is executed. This has no direct effect on users;
* however it does affect which method throws certain SQLExceptions * however it does affect which method throws certain SQLExceptions
* *
* @param sql a SQL statement that may contain one or more '?' IN * @param sql a SQL statement that may contain one or more '?' IN
* parameter placeholders * parameter placeholders
* @return a new PreparedStatement object containing the pre-compiled * @return a new PreparedStatement object containing the pre-compiled
* statement. * statement.
* @exception SQLException if a database access error occurs. * @exception SQLException if a database access error occurs.
*/ */
public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
{ {
return prepareStatement(sql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY); 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 public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{ {
PreparedStatement s = new PreparedStatement(this,sql); PreparedStatement s = new PreparedStatement(this, sql);
s.setResultSetType(resultSetType); s.setResultSetType(resultSetType);
s.setResultSetConcurrency(resultSetConcurrency); s.setResultSetConcurrency(resultSetConcurrency);
return s; return s;
} }
/** /**
* A SQL stored procedure call statement is handled by creating a * A SQL stored procedure call statement is handled by creating a
* CallableStatement for it. The CallableStatement provides methods * CallableStatement for it. The CallableStatement provides methods
* for setting up its IN and OUT parameters and methods for executing * for setting up its IN and OUT parameters and methods for executing
* it. * it.
* *
* <B>Note:</B> This method is optimised for handling stored procedure * <B>Note:</B> This method is optimised for handling stored procedure
* call statements. Some drivers may send the call statement to the * call statements. Some drivers may send the call statement to the
* database when the prepareCall is done; others may wait until the * database when the prepareCall is done; others may wait until the
* CallableStatement is executed. This has no direct effect on users; * CallableStatement is executed. This has no direct effect on users;
* however, it does affect which method throws certain SQLExceptions * however, it does affect which method throws certain SQLExceptions
* *
* @param sql a SQL statement that may contain one or more '?' parameter * @param sql a SQL statement that may contain one or more '?' parameter
* placeholders. Typically this statement is a JDBC function call * placeholders. Typically this statement is a JDBC function call
* escape string. * escape string.
* @return a new CallableStatement object containing the pre-compiled * @return a new CallableStatement object containing the pre-compiled
* SQL statement * SQL statement
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public java.sql.CallableStatement prepareCall(String sql) throws SQLException public java.sql.CallableStatement prepareCall(String sql) throws SQLException
{ {
return prepareCall(sql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY); 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 public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{ {
throw new PSQLException("postgresql.con.call"); throw new PSQLException("postgresql.con.call");
//CallableStatement s = new CallableStatement(this,sql); //CallableStatement s = new CallableStatement(this,sql);
//s.setResultSetType(resultSetType); //s.setResultSetType(resultSetType);
//s.setResultSetConcurrency(resultSetConcurrency); //s.setResultSetConcurrency(resultSetConcurrency);
//return s; //return s;
} }
/** /**
* Tests to see if a Connection is closed. * Tests to see if a Connection is closed.
* *
* Peter Feb 7 2000: Now I've discovered that this doesn't actually obey the * 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() * 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 * 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 * 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 * that the client should monitor the SQLExceptions thrown when their queries
* fail because the connection is dead. * fail because the connection is dead.
* *
* I don't like this definition. As it doesn't hurt breaking it here, our * 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 * isClosed() implementation does test the connection, so for PostgreSQL, you
* can rely on isClosed() returning a valid result. * can rely on isClosed() returning a valid result.
* *
* @return the status of the connection * @return the status of the connection
* @exception SQLException (why?) * @exception SQLException (why?)
*/ */
public boolean isClosed() throws SQLException public boolean isClosed() throws SQLException
{ {
// If the stream is gone, then close() was called // If the stream is gone, then close() was called
if(pg_stream == null) if (pg_stream == null)
return true; return true;
// ok, test the connection // ok, test the connection
try { try
// by sending an empty query. If we are dead, then an SQLException should {
// be thrown // by sending an empty query. If we are dead, then an SQLException should
java.sql.ResultSet rs = ExecSQL(" "); // be thrown
if(rs!=null) java.sql.ResultSet rs = ExecSQL(" ");
rs.close(); if (rs != null)
rs.close();
// By now, we must be alive // By now, we must be alive
return false; return false;
} catch(SQLException se) { }
// Why throw an SQLException as this may fail without throwing one, catch (SQLException se)
// 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 // Why throw an SQLException as this may fail without throwing one,
// most likely why it was thrown in the first place. // ie isClosed() is called incase the connection has died, and we don't
return true; // 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 * A connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the * its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is made * capabilities of this connection, etc. This information is made
* available through a DatabaseMetaData object. * available through a DatabaseMetaData object.
* *
* @return a DatabaseMetaData object for this connection * @return a DatabaseMetaData object for this connection
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public java.sql.DatabaseMetaData getMetaData() throws SQLException public java.sql.DatabaseMetaData getMetaData() throws SQLException
{ {
if(metadata==null) if (metadata == null)
metadata = new DatabaseMetaData(this); metadata = new DatabaseMetaData(this);
return metadata; return metadata;
} }
/** /**
* This overides the method in org.postgresql.Connection and returns a * This overides the method in org.postgresql.Connection and returns a
* ResultSet. * 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 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 // 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. // Statement then default to a normal ResultSet object.
if(stat!=null) { 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); 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 public java.util.Map getTypeMap() throws SQLException
{ {
// new in 7.1 // new in 7.1
return typemap; return typemap;
} }
public void setTypeMap(java.util.Map map) throws SQLException public void setTypeMap(java.util.Map map) throws SQLException
{ {
// new in 7.1 // new in 7.1
typemap=map; typemap = map;
} }
/** /**
* This overides the standard internal getObject method so that we can * This overides the standard internal getObject method so that we can
* check the jdbc2 type map first * check the jdbc2 type map first
* *
* @return PGobject for this type, and set to value * @return PGobject for this type, and set to value
* @exception SQLException if value is not correct for this type * @exception SQLException if value is not correct for this type
* @see org.postgresql.util.Serialize * @see org.postgresql.util.Serialize
*/ */
public Object getObject(String type,String value) throws SQLException public Object getObject(String type, String value) throws SQLException
{ {
if(typemap!=null) { if (typemap != null)
SQLData d = (SQLData) typemap.get(type); {
if(d!=null) { SQLData d = (SQLData) typemap.get(type);
// Handle the type (requires SQLInput & SQLOutput classes to be implemented) if (d != null)
throw org.postgresql.Driver.notImplemented(); {
} // Handle the type (requires SQLInput & SQLOutput classes to be implemented)
} throw org.postgresql.Driver.notImplemented();
}
}
// Default to the original method // Default to the original method
return super.getObject(type,value); return super.getObject(type, value);
} }
/* An implementation of the abstract method in the parent class. /* An implementation of the abstract method in the parent class.
* This implemetation uses the jdbc2Types array to support the jdbc2 * This implemetation uses the jdbc2Types array to support the jdbc2
* datatypes. Basically jdbc1 and jdbc2 are the same, except that * datatypes. Basically jdbc1 and jdbc2 are the same, except that
* jdbc2 adds the Array types. * jdbc2 adds the Array types.
*/ */
public int getSQLType(String pgTypeName) public int getSQLType(String pgTypeName)
{ {
int sqlType = Types.OTHER; // default value int sqlType = Types.OTHER; // default value
for(int i=0;i<jdbc2Types.length;i++) { for (int i = 0;i < jdbc2Types.length;i++)
if(pgTypeName.equals(jdbc2Types[i])) { {
sqlType=jdbc2Typei[i]; if (pgTypeName.equals(jdbc2Types[i]))
break; {
} sqlType = jdbc2Typei[i];
} break;
return sqlType; }
} }
return sqlType;
}
/** /**
* This table holds the org.postgresql names for the types supported. * 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. * Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER * They default automatically to Types.OTHER
* *
* Note: This must be in the same order as below. * Note: This must be in the same order as below.
* *
* Tip: keep these grouped together by the Types. value * Tip: keep these grouped together by the Types. value
*/ */
private static final String jdbc2Types[] = { private static final String jdbc2Types[] = {
"int2", "int2",
"int4","oid", "int4", "oid",
"int8", "int8",
"cash","money", "cash", "money",
"numeric", "numeric",
"float4", "float4",
"float8", "float8",
"bpchar","char","char2","char4","char8","char16", "bpchar", "char", "char2", "char4", "char8", "char16",
"varchar","text","name","filename", "varchar", "text", "name", "filename",
"bytea", "bytea",
"bool", "bool",
"date", "date",
"time", "time",
"abstime","timestamp", "abstime", "timestamp",
"_bool", "_char", "_int2", "_int4", "_text", "_bool", "_char", "_int2", "_int4", "_text",
"_oid", "_varchar", "_int8", "_float4", "_float8", "_oid", "_varchar", "_int8", "_float4", "_float8",
"_abstime", "_date", "_time", "_timestamp", "_numeric", "_abstime", "_date", "_time", "_timestamp", "_numeric",
"_bytea" "_bytea"
}; };
/** /**
* This table holds the JDBC type for each entry above. * This table holds the JDBC type for each entry above.
* *
* Note: This must be in the same order as above * Note: This must be in the same order as above
* *
* Tip: keep these grouped together by the Types. value * Tip: keep these grouped together by the Types. value
*/ */
private static final int jdbc2Typei[] = { private static final int jdbc2Typei[] = {
Types.SMALLINT, Types.SMALLINT,
Types.INTEGER,Types.INTEGER, Types.INTEGER, Types.INTEGER,
Types.BIGINT, Types.BIGINT,
Types.DOUBLE,Types.DOUBLE, Types.DOUBLE, Types.DOUBLE,
Types.NUMERIC, Types.NUMERIC,
Types.REAL, Types.REAL,
Types.DOUBLE, Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
Types.BINARY, Types.BINARY,
Types.BIT, Types.BIT,
Types.DATE, Types.DATE,
Types.TIME, Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP, 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, 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

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

@@ -19,449 +19,462 @@ import org.postgresql.util.*;
*/ */
public class ResultSetMetaData implements java.sql.ResultSetMetaData public class ResultSetMetaData implements java.sql.ResultSetMetaData
{ {
Vector rows; Vector rows;
Field[] fields; Field[] fields;
/** /**
* Initialise for a result with a tuple set and * Initialise for a result with a tuple set and
* a field descriptor set * a field descriptor set
* *
* @param rows the Vector of rows returned by the ResultSet * @param rows the Vector of rows returned by the ResultSet
* @param fields the array of field descriptors * @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.
*/ */
return columnNullableUnknown; public ResultSetMetaData(Vector rows, Field[] fields)
} {
this.rows = rows;
this.fields = fields;
}
/** /**
* Is the column a signed number? In PostgreSQL, all numbers * Whats the number of columns in the ResultSet?
* are signed, so this is trivial. However, strings are not *
* signed (duh!) * @return the number
* * @exception SQLException if a database access error occurs
* @param column the first column is 1, the second is 2... */
* @return true if so public int getColumnCount() throws SQLException
* @exception SQLException if a database access error occurs {
*/ return fields.length;
public boolean isSigned(int column) throws SQLException }
{
int sql_type = getField(column).getSQLType();
switch (sql_type) /**
{ * Is the column automatically numbered (and thus read-only)
case Types.SMALLINT: * I believe that PostgreSQL does not support this feature.
case Types.INTEGER: *
case Types.FLOAT: * @param column the first column is 1, the second is 2...
case Types.REAL: * @return true if so
case Types.DOUBLE: * @exception SQLException if a database access error occurs
return true; */
case Types.DATE: public boolean isAutoIncrement(int column) throws SQLException
case Types.TIME: {
case Types.TIMESTAMP: return false;
return false; // I don't know about these? }
default:
return false;
}
}
/** /**
* What is the column's normal maximum width in characters? * 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, etc. *
* @return the maximum width * @param column the first column is 1, the second is 2...
* @exception SQLException if a database access error occurs * @return true if so
*/ * @exception SQLException if a database access error occurs
public int getColumnDisplaySize(int column) throws SQLException */
{ public boolean isCaseSensitive(int column) throws SQLException
Field f = getField(column); {
String type_name = f.getPGType(); int sql_type = getField(column).getSQLType();
int sql_type = f.getSQLType();
int typmod = f.getMod();
// I looked at other JDBC implementations and couldn't find a consistent switch (sql_type)
// 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 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;
}
}
// fixed length data types /**
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign) * Can the column be used in a WHERE clause? Basically for
if (type_name.equals( "int4" ) * this, I split the functions into two types: recognised
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647 * types (which are always useable), and OTHER types (which
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807 * may or may not be useable). The OTHER types, for now, I
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2) * will assume they are useable. We should really query the
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits * catalog to see if they are useable.
if (type_name.equals( "float8" )) return 20; // dito, 20 *
if (type_name.equals( "char" )) return 1; * @param column the first column is 1, the second is 2...
if (type_name.equals( "bool" )) return 1; * @return true if they can be used in a WHERE clause
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD" * @exception SQLException if a database access error occurs
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 public boolean isSearchable(int column) throws SQLException
{
int sql_type = getField(column).getSQLType();
// variable length fields // This switch is pointless, I know - but it is a set-up
typmod -= 4; // for further expansion.
if (type_name.equals( "bpchar" ) switch (sql_type)
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4 {
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff ) case Types.OTHER:
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits) return true;
default:
return true;
}
}
// if we don't know better /**
return f.getLength(); * 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");
* 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? * Indicates the nullability of values in the designated column.
* *
* @param column the first column is 1, the second is 2, etc. * @param column the first column is 1, the second is 2...
* @return the column name * @return one of the columnNullable values
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public String getColumnName(int column) throws SQLException public int isNullable(int column) throws SQLException
{ {
Field f = getField(column); /*
if(f!=null) * TODO This needs a real implementation, taking into account columns
return f.getName(); * defined with NOT NULL or PRIMARY KEY, CHECK constraints, views,
return "field"+column; * functions etc.
} */
return columnNullableUnknown;
}
/** /**
* What is a column's table's schema? This relies on us knowing * Is the column a signed number? In PostgreSQL, all numbers
* the table name....which I don't know how to do as yet. The * are signed, so this is trivial. However, strings are not
* JDBC specification allows us to return "" if this is not * signed (duh!)
* applicable. *
* * @param column the first column is 1, the second is 2...
* @param column the first column is 1, the second is 2... * @return true if so
* @return the Schema * @exception SQLException if a database access error occurs
* @exception SQLException if a database access error occurs */
*/ public boolean isSigned(int column) throws SQLException
public String getSchemaName(int column) throws SQLException {
{ int sql_type = getField(column).getSQLType();
return "";
}
/** switch (sql_type)
* What is a column's number of decimal digits. {
* case Types.SMALLINT:
* @param column the first column is 1, the second is 2... case Types.INTEGER:
* @return the precision case Types.FLOAT:
* @exception SQLException if a database access error occurs case Types.REAL:
*/ case Types.DOUBLE:
public int getPrecision(int column) throws SQLException return true;
{ case Types.DATE:
int sql_type = getField(column).getSQLType(); case Types.TIME:
case Types.TIMESTAMP:
return false; // I don't know about these?
default:
return false;
}
}
switch (sql_type) /**
{ * What is the column's normal maximum width in characters?
case Types.SMALLINT: *
return 5; * @param column the first column is 1, the second is 2, etc.
case Types.INTEGER: * @return the maximum width
return 10; * @exception SQLException if a database access error occurs
case Types.REAL: */
return 8; public int getColumnDisplaySize(int column) throws SQLException
case Types.FLOAT: {
return 16; Field f = getField(column);
case Types.DOUBLE: String type_name = f.getPGType();
return 16; int sql_type = f.getSQLType();
case Types.VARCHAR: int typmod = f.getMod();
return 0;
case Types.NUMERIC:
Field f = getField(column);
if(f != null)
return ((0xFFFF0000)&f.getMod())>>16;
else
return 0;
default:
return 0;
}
}
/** // I looked at other JDBC implementations and couldn't find a consistent
* What is a column's number of digits to the right of the // interpretation of the "display size" for numeric values, so this is our's
* decimal point? // FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
*
* @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) // fixed length data types
{ if (type_name.equals( "int2" ))
case Types.SMALLINT: return 6; // -32768 to +32768 (5 digits and a sign)
return 0; if (type_name.equals( "int4" )
case Types.INTEGER: || type_name.equals( "oid" ))
return 0; return 11; // -2147483648 to +2147483647
case Types.REAL: if (type_name.equals( "int8" ))
return 8; return 20; // -9223372036854775808 to +9223372036854775807
case Types.FLOAT: if (type_name.equals( "money" ))
return 16; return 12; // MONEY = DECIMAL(9,2)
case Types.DOUBLE: if (type_name.equals( "float4" ))
return 16; return 11; // i checked it out ans wasn't able to produce more than 11 digits
case Types.VARCHAR: if (type_name.equals( "float8" ))
return 0; return 20; // dito, 20
case Types.NUMERIC: if (type_name.equals( "char" ))
Field f = getField(column); return 1;
if(f != null) if (type_name.equals( "bool" ))
return (((0x0000FFFF)&f.getMod())-4); return 1;
else if (type_name.equals( "date" ))
return 0; return 14; // "01/01/4713 BC" - "31/12/32767 AD"
default: if (type_name.equals( "time" ))
return 0; 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
* Whats a column's table's name? How do I find this out? Both typmod -= 4;
* getSchemaName() and getCatalogName() rely on knowing the table if (type_name.equals( "bpchar" )
* Name, so we need this before we can work on them. || type_name.equals( "varchar" ))
* return typmod; // VARHDRSZ=sizeof(int32)=4
* @param column the first column is 1, the second is 2... if (type_name.equals( "numeric" ))
* @return column name, or "" if not applicable return ( (typmod >> 16) & 0xffff )
* @exception SQLException if a database access error occurs + 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
*/
public String getTableName(int column) throws SQLException
{
return "";
}
/** // if we don't know better
* What's a column's table's catalog name? As with getSchemaName(), return f.getLength();
* 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) * 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 java.sql.Type value * @param column the first column is 1, the second is 2, etc.
* @exception SQLException if a database access error occurs * @return the column label
* @see org.postgresql.Field#getSQLType * @exception SQLException if a database access error occurs
* @see java.sql.Types */
*/ public String getColumnLabel(int column) throws SQLException
public int getColumnType(int column) throws SQLException {
{ return getColumnName(column);
return getField(column).getSQLType(); }
}
/** /**
* Whats is the column's data source specific type name? * What's a column's name?
* *
* @param column the first column is 1, the second is 2, etc. * @param column the first column is 1, the second is 2, etc.
* @return the type name * @return the column name
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public String getColumnTypeName(int column) throws SQLException public String getColumnName(int column) throws SQLException
{ {
return getField(column).getPGType(); Field f = getField(column);
} if (f != null)
return f.getName();
return "field" + column;
}
/** /**
* Is the column definitely not writable? In reality, we would * What is a column's table's schema? This relies on us knowing
* have to check the GRANT/REVOKE stuff for this to be effective, * the table name....which I don't know how to do as yet. The
* and I haven't really looked into that yet, so this will get * JDBC specification allows us to return "" if this is not
* re-visited. * applicable.
* *
* @param column the first column is 1, the second is 2, etc. * @param column the first column is 1, the second is 2...
* @return true if so * @return the Schema
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
*/ */
public boolean isReadOnly(int column) throws SQLException public String getSchemaName(int column) throws SQLException
{ {
return false; return "";
} }
/** /**
* Is it possible for a write on the column to succeed? Again, we * What is a column's number of decimal digits.
* 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 * @param column the first column is 1, the second is 2...
* it is obviously writable. * @return the precision
* * @exception SQLException if a database access error occurs
* @param column the first column is 1, the second is 2, etc. */
* @return true if so public int getPrecision(int column) throws SQLException
* @exception SQLException if a database access error occurs {
*/ int sql_type = getField(column).getSQLType();
public boolean isWritable(int column) throws SQLException
{
return !isReadOnly(column);
}
/** switch (sql_type)
* Will a write on this column definately succeed? Hmmm...this {
* is a bad one, since the two preceding functions have not been case Types.SMALLINT:
* really defined. I cannot tell is the short answer. I thus return 5;
* return isWritable() just to give us an idea. case Types.INTEGER:
* return 10;
* @param column the first column is 1, the second is 2, etc.. case Types.REAL:
* @return true if so return 8;
* @exception SQLException if a database access error occurs case Types.FLOAT:
*/ return 16;
public boolean isDefinitelyWritable(int column) throws SQLException case Types.DOUBLE:
{ return 16;
return false; 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;
}
}
// ******************************************************** /**
// END OF PUBLIC INTERFACE * 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)
* For several routines in this package, we need to convert {
* a columnIndex into a Field[] descriptor. Rather than do case Types.SMALLINT:
* the same code several times, here it is. return 0;
* case Types.INTEGER:
* @param columnIndex the first column is 1, the second is 2... return 0;
* @return the Field description case Types.REAL:
* @exception SQLException if a database access error occurs return 8;
*/ case Types.FLOAT:
private Field getField(int columnIndex) throws SQLException return 16;
{ case Types.DOUBLE:
if (columnIndex < 1 || columnIndex > fields.length) return 16;
throw new PSQLException("postgresql.res.colrange"); case Types.VARCHAR:
return fields[columnIndex - 1]; return 0;
} case Types.NUMERIC:
Field f = getField(column);
if (f != null)
return (((0x0000FFFF)&f.getMod()) - 4);
else
return 0;
default:
return 0;
}
}
// ** JDBC 2 Extensions ** /**
* 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 "";
}
// This can hook into our PG_Object mechanism /**
public String getColumnClassName(int column) throws SQLException * 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 -
throw org.postgresql.Driver.notImplemented(); * 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. * <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 * Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different * 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. * statement's current ResultSet if an open one exists.
* *
* @see java.sql.Statement * @see java.sql.Statement
@@ -24,10 +24,10 @@ import org.postgresql.util.*;
*/ */
public class Statement extends org.postgresql.Statement implements java.sql.Statement 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
private Vector batch=null; private Vector batch = null;
private int resultsettype; // the resultset type to return private int resultsettype; // the resultset type to return
private int concurrency; // is it updateable or not? private int concurrency; // is it updateable or not?
/** /**
* Constructor for a Statement. It simply sets the connection * 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) public Statement (Connection c)
{ {
connection = c; connection = c;
resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; resultsettype = java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
concurrency = java.sql.ResultSet.CONCUR_READ_ONLY; 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 public java.sql.ResultSet executeQuery(String sql) throws SQLException
{ {
this.execute(sql); this.execute(sql);
while (result != null && !((org.postgresql.ResultSet)result).reallyResultSet()) while (result != null && !((org.postgresql.ResultSet)result).reallyResultSet())
result = ((org.postgresql.ResultSet)result).getNext(); result = ((org.postgresql.ResultSet)result).getNext();
if (result == null) if (result == null)
throw new PSQLException("postgresql.stat.noresult"); throw new PSQLException("postgresql.stat.noresult");
return result; 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 * 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 * positioned update/delete statements to identify the current row
* in the ResultSet generated by this statement. If a database * in the ResultSet generated by this statement. If a database
* doesn't support positioned update/delete, this method is a * 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 * <p><B>Note:</B> By definition, positioned update/delete execution
* must be done by a different Statement than the one which * 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. * 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. * cursor active at any one time.
* *
* @param name the new cursor name * @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 * Execute a SQL statement that may return multiple results. We
* don't have to worry about this since we do not support multiple * 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. * retrieve the result.
* *
* @param sql any SQL statement * @param sql any SQL statement
* @return true if the next result is a ResulSet, false if it is * @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 * @exception SQLException if a database access error occurs
*/ */
public boolean execute(String sql) throws SQLException public boolean execute(String sql) throws SQLException
{ {
if (escapeProcessing) if (escapeProcessing)
sql = escapeSQL(sql); sql = escapeSQL(sql);
// New in 7.1, if we have a previous resultset then force it to 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. // This brings us nearer to compliance, and helps memory management.
// Internal stuff will call ExecSQL directly, bypassing this. // Internal stuff will call ExecSQL directly, bypassing this.
if(result!=null) { if (result != null)
java.sql.ResultSet rs = getResultSet(); {
if(rs!=null) java.sql.ResultSet rs = getResultSet();
rs.close(); if (rs != null)
} rs.close();
}
// New in 7.1, pass Statement so that ExecSQL can customise to it // New in 7.1, pass Statement so that ExecSQL can customise to it
result = connection.ExecSQL(sql,this); result = connection.ExecSQL(sql, this);
// New in 7.1, required for ResultSet.getStatement() to work // New in 7.1, required for ResultSet.getStatement() to work
((org.postgresql.jdbc2.ResultSet)result).setStatement(this); ((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, * 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 public int getUpdateCount() throws SQLException
{ {
if (result == null) return -1; if (result == null)
if (((org.postgresql.ResultSet)result).reallyResultSet()) return -1; return -1;
if (((org.postgresql.ResultSet)result).reallyResultSet())
return -1;
return ((org.postgresql.ResultSet)result).getResultCount(); 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()); return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
} }
// ** JDBC 2 Extensions ** // ** JDBC 2 Extensions **
public void addBatch(String sql) throws SQLException public void addBatch(String sql) throws SQLException
{ {
if(batch==null) if (batch == null)
batch=new Vector(); batch = new Vector();
batch.addElement(sql); 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();
} }
return result;
}
public java.sql.Connection getConnection() throws SQLException public void clearBatch() throws SQLException
{ {
return (java.sql.Connection)connection; if (batch != null)
} batch.removeAllElements();
}
public int getFetchDirection() throws SQLException public int[] executeBatch() throws SQLException
{ {
throw new PSQLException("postgresql.psqlnotimp"); 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 PBatchUpdateException updex =
{ new PBatchUpdateException("postgresql.stat.batch.error",
// This one can only return a valid value when were a cursor? new Integer(i), batch.elementAt(i), resultSucceeded);
throw org.postgresql.Driver.notImplemented(); updex.setNextException(e);
}
public int getResultSetConcurrency() throws SQLException throw updex;
{ }
// new in 7.1 finally
return concurrency; {
} batch.removeAllElements();
}
return result;
}
public int getResultSetType() throws SQLException public java.sql.Connection getConnection() throws SQLException
{ {
// new in 7.1 return (java.sql.Connection)connection;
return resultsettype; }
}
public void setFetchDirection(int direction) throws SQLException public int getFetchDirection() throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); throw new PSQLException("postgresql.psqlnotimp");
} }
public void setFetchSize(int rows) throws SQLException public int getFetchSize() throws SQLException
{ {
throw org.postgresql.Driver.notImplemented(); // This one can only return a valid value when were a cursor?
} throw org.postgresql.Driver.notImplemented();
}
/** public int getResultSetConcurrency() throws SQLException
* New in 7.1 {
*/ // new in 7.1
public void setResultSetConcurrency(int value) throws SQLException return concurrency;
{ }
concurrency=value;
}
/** public int getResultSetType() throws SQLException
* New in 7.1 {
*/ // new in 7.1
public void setResultSetType(int value) throws SQLException return resultsettype;
{ }
resultsettype=value;
} 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 public class UpdateableResultSet extends org.postgresql.jdbc2.ResultSet
{ {
/** /**
* Create a new ResultSet - Note that we create ResultSets to * Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything. * represent the results of everything.
* *
* @param fields an array of Field objects (basically, the * @param fields an array of Field objects (basically, the
* ResultSet MetaData) * ResultSet MetaData)
* @param tuples Vector of the actual data * @param tuples Vector of the actual data
* @param status the status string returned from the back end * @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation * @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name * @param cursor the positioned update/delete cursor name
*/ */
public UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount,int insertOID, boolean binaryCursor) public UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount, int insertOID, boolean binaryCursor)
{ {
super(conn,fields,tuples,status,updateCount,insertOID,binaryCursor); super(conn, fields, tuples, status, updateCount, insertOID, binaryCursor);
} }
/** /**
* Create a new ResultSet - Note that we create ResultSets to * Create a new ResultSet - Note that we create ResultSets to
* represent the results of everything. * represent the results of everything.
* *
* @param fields an array of Field objects (basically, the * @param fields an array of Field objects (basically, the
* ResultSet MetaData) * ResultSet MetaData)
* @param tuples Vector of the actual data * @param tuples Vector of the actual data
* @param status the status string returned from the back end * @param status the status string returned from the back end
* @param updateCount the number of rows affected by the operation * @param updateCount the number of rows affected by the operation
* @param cursor the positioned update/delete cursor name * @param cursor the positioned update/delete cursor name
*/ */
// public UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount) // public UpdateableResultSet(Connection conn, Field[] fields, Vector tuples, String status, int updateCount)
// { // {
// super(conn,fields,tuples,status,updateCount,0,false); // super(conn,fields,tuples,status,updateCount,0,false);
//} //}
public void cancelRowUpdates() throws SQLException public void cancelRowUpdates() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void deleteRow() throws SQLException public void deleteRow() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public int getConcurrency() throws SQLException public int getConcurrency() throws SQLException
{ {
// New in 7.1 - The updateable ResultSet class will now return // New in 7.1 - The updateable ResultSet class will now return
// CONCUR_UPDATEABLE. // CONCUR_UPDATEABLE.
return CONCUR_UPDATABLE; return CONCUR_UPDATABLE;
} }
public void insertRow() throws SQLException public void insertRow() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void moveToCurrentRow() throws SQLException public void moveToCurrentRow() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void moveToInsertRow() throws SQLException public void moveToInsertRow() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public boolean rowDeleted() throws SQLException public boolean rowDeleted() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value! //return false; // javac complains about not returning a value!
} }
public boolean rowInserted() throws SQLException public boolean rowInserted() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value! //return false; // javac complains about not returning a value!
} }
public boolean rowUpdated() throws SQLException public boolean rowUpdated() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
//return false; // javac complains about not returning a value! //return false; // javac complains about not returning a value!
} }
public void updateAsciiStream(int columnIndex, public void updateAsciiStream(int columnIndex,
java.io.InputStream x, java.io.InputStream x,
int length int length
) throws SQLException ) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateBigDecimal(int columnIndex, public void updateBigDecimal(int columnIndex,
java.math.BigDecimal x java.math.BigDecimal x
) throws SQLException ) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateBinaryStream(int columnIndex, public void updateBinaryStream(int columnIndex,
java.io.InputStream x, java.io.InputStream x,
int length int length
) throws SQLException ) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateBoolean(int columnIndex,boolean x) throws SQLException public void updateBoolean(int columnIndex, boolean x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateByte(int columnIndex,byte x) throws SQLException public void updateByte(int columnIndex, byte x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateBytes(int columnIndex,byte[] x) throws SQLException public void updateBytes(int columnIndex, byte[] x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateCharacterStream(int columnIndex, public void updateCharacterStream(int columnIndex,
java.io.Reader x, java.io.Reader x,
int length int length
) throws SQLException ) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateDate(int columnIndex,java.sql.Date x) throws SQLException public void updateDate(int columnIndex, java.sql.Date x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateDouble(int columnIndex,double x) throws SQLException public void updateDouble(int columnIndex, double x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateFloat(int columnIndex,float x) throws SQLException public void updateFloat(int columnIndex, float x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateInt(int columnIndex,int x) throws SQLException public void updateInt(int columnIndex, int x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateLong(int columnIndex,long x) throws SQLException public void updateLong(int columnIndex, long x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateNull(int columnIndex) throws SQLException public void updateNull(int columnIndex) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateObject(int columnIndex,Object x) throws SQLException public void updateObject(int columnIndex, Object x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateObject(int columnIndex,Object x,int scale) throws SQLException public void updateObject(int columnIndex, Object x, int scale) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateRow() throws SQLException public void updateRow() throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateShort(int columnIndex,short x) throws SQLException public void updateShort(int columnIndex, short x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateString(int columnIndex,String x) throws SQLException public void updateString(int columnIndex, String x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateTime(int columnIndex,Time x) throws SQLException public void updateTime(int columnIndex, Time x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); throw org.postgresql.Driver.notImplemented();
} }
public void updateTimestamp(int columnIndex,Timestamp x) throws SQLException public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
{ {
// only sub-classes implement CONCUR_UPDATEABLE // only sub-classes implement CONCUR_UPDATEABLE
throw org.postgresql.Driver.notImplemented(); 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 * For now, the bare minimum is implemented. Later (after 7.1) we will overide
* the other read methods to optimise them. * the other read methods to optimise them.
*/ */
public class BlobInputStream extends InputStream { public class BlobInputStream extends InputStream
/** {
* The parent LargeObject /**
*/ * The parent LargeObject
private LargeObject lo; */
private LargeObject lo;
/** /**
* Buffer used to improve performance * Buffer used to improve performance
*/ */
private byte[] buffer; private byte[] buffer;
/** /**
* Position within buffer * Position within buffer
*/ */
private int bpos; private int bpos;
/** /**
* The buffer size * The buffer size
*/ */
private int bsize; private int bsize;
/** /**
* The mark position * The mark position
*/ */
private int mpos=0; private int mpos = 0;
/** /**
* @param lo LargeObject to read from * @param lo LargeObject to read from
*/ */
public BlobInputStream(LargeObject lo) { public BlobInputStream(LargeObject lo)
this(lo,1024); {
} this(lo, 1024);
}
/** /**
* @param lo LargeObject to read from * @param lo LargeObject to read from
* @param bsize buffer size * @param bsize buffer size
*/ */
public BlobInputStream(LargeObject lo,int bsize) { public BlobInputStream(LargeObject lo, int bsize)
this.lo=lo; {
buffer=null; this.lo = lo;
bpos=0; buffer = null;
this.bsize=bsize; bpos = 0;
} this.bsize = bsize;
}
/** /**
* The minimum required to implement input stream * The minimum required to implement input stream
*/ */
public int read() throws java.io.IOException { public int read() throws java.io.IOException
try { {
if (buffer == null || bpos >= buffer.length) { try
buffer=lo.read(bsize); {
bpos=0; if (buffer == null || bpos >= buffer.length)
} {
buffer = lo.read(bsize);
bpos = 0;
}
// Handle EOF // Handle EOF
if(bpos >= buffer.length) { if (bpos >= buffer.length)
return -1; {
} return -1;
}
int ret = (buffer[bpos] & 0x7F); int ret = (buffer[bpos] & 0x7F);
if ((buffer[bpos] &0x80) == 0x80) { if ((buffer[bpos] &0x80) == 0x80)
ret |= 0x80; {
} ret |= 0x80;
}
bpos++; bpos++;
return ret; return ret;
} catch(SQLException se) { }
throw new IOException(se.toString()); catch (SQLException se)
} {
} throw new IOException(se.toString());
}
}
/** /**
* Closes this input stream and releases any system resources associated * Closes this input stream and releases any system resources associated
* with the stream. * with the stream.
* *
* <p> The <code>close</code> method of <code>InputStream</code> does * <p> The <code>close</code> method of <code>InputStream</code> does
* nothing. * nothing.
* *
* @exception IOException if an I/O error occurs. * @exception IOException if an I/O error occurs.
*/ */
public void close() throws IOException { public void close() throws IOException
try { {
lo.close(); try
lo=null; {
} catch(SQLException se) { lo.close();
throw new IOException(se.toString()); lo = null;
} }
} catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/** /**
* Marks the current position in this input stream. A subsequent call to * Marks the current position in this input stream. A subsequent call to
* the <code>reset</code> method repositions this stream at the last marked * the <code>reset</code> method repositions this stream at the last marked
* position so that subsequent reads re-read the same bytes. * position so that subsequent reads re-read the same bytes.
* *
* <p> The <code>readlimit</code> arguments tells this input stream to * <p> The <code>readlimit</code> arguments tells this input stream to
* allow that many bytes to be read before the mark position gets * allow that many bytes to be read before the mark position gets
* invalidated. * invalidated.
* *
* <p> The general contract of <code>mark</code> is that, if the method * <p> The general contract of <code>mark</code> is that, if the method
* <code>markSupported</code> returns <code>true</code>, the stream somehow * <code>markSupported</code> returns <code>true</code>, the stream somehow
* remembers all the bytes read after the call to <code>mark</code> and * 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 * 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 * <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 * remember any data at all if more than <code>readlimit</code> bytes are
* read from the stream before <code>reset</code> is called. * read from the stream before <code>reset</code> is called.
* *
* <p> The <code>mark</code> method of <code>InputStream</code> does * <p> The <code>mark</code> method of <code>InputStream</code> does
* nothing. * nothing.
* *
* @param readlimit the maximum limit of bytes that can be read before * @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid. * the mark position becomes invalid.
* @see java.io.InputStream#reset() * @see java.io.InputStream#reset()
*/ */
public synchronized void mark(int readlimit) { public synchronized void mark(int readlimit)
try { {
mpos=lo.tell(); try
} catch(SQLException se) { {
//throw new IOException(se.toString()); mpos = lo.tell();
} }
} catch (SQLException se)
{
//throw new IOException(se.toString());
}
}
/** /**
* Repositions this stream to the position at the time the * Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream. * <code>mark</code> method was last called on this input stream.
* NB: If mark is not called we move to the begining. * NB: If mark is not called we move to the begining.
* @see java.io.InputStream#mark(int) * @see java.io.InputStream#mark(int)
* @see java.io.IOException * @see java.io.IOException
*/ */
public synchronized void reset() throws IOException { public synchronized void reset()
try { throws IOException
lo.seek(mpos); {
} catch(SQLException se) { try
throw new IOException(se.toString()); {
} lo.seek(mpos);
} }
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/** /**
* Tests if this input stream supports the <code>mark</code> and * Tests if this input stream supports the <code>mark</code> and
* <code>reset</code> methods. The <code>markSupported</code> method of * <code>reset</code> methods. The <code>markSupported</code> method of
* <code>InputStream</code> returns <code>false</code>. * <code>InputStream</code> returns <code>false</code>.
* *
* @return <code>true</code> if this true type supports the mark and reset * @return <code>true</code> if this true type supports the mark and reset
* method; <code>false</code> otherwise. * method; <code>false</code> otherwise.
* @see java.io.InputStream#mark(int) * @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset() * @see java.io.InputStream#reset()
*/ */
public boolean markSupported() { public boolean markSupported()
return true; {
} return true;
}
} }

View File

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

View File

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

View File

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

View File

@@ -20,47 +20,53 @@ import org.postgresql.largeobject.*;
* This implements the Blob interface, which is basically another way to * This implements the Blob interface, which is basically another way to
* access a LargeObject. * 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 public class PGblob implements java.sql.Blob
{ {
private org.postgresql.Connection conn; private org.postgresql.Connection conn;
private int oid; private int oid;
private LargeObject lo; private LargeObject lo;
public PGblob(org.postgresql.Connection conn,int oid) throws SQLException { public PGblob(org.postgresql.Connection conn, int oid) throws SQLException
this.conn=conn; {
this.oid=oid; this.conn = conn;
LargeObjectManager lom = conn.getLargeObjectAPI(); this.oid = oid;
this.lo = lom.open(oid); LargeObjectManager lom = conn.getLargeObjectAPI();
} this.lo = lom.open(oid);
}
public long length() throws SQLException { public long length() throws SQLException
return lo.size(); {
} return lo.size();
}
public InputStream getBinaryStream() throws SQLException { public InputStream getBinaryStream() throws SQLException
return lo.getInputStream(); {
} return lo.getInputStream();
}
public byte[] getBytes(long pos,int length) throws SQLException { public byte[] getBytes(long pos, int length) throws SQLException
lo.seek((int)pos,LargeObject.SEEK_SET); {
return lo.read(length); lo.seek((int)pos, LargeObject.SEEK_SET);
} return lo.read(length);
}
/* /*
* For now, this is not implemented. * For now, this is not implemented.
*/ */
public long position(byte[] pattern,long start) throws SQLException { public long position(byte[] pattern, long start) throws SQLException
throw org.postgresql.Driver.notImplemented(); {
} throw org.postgresql.Driver.notImplemented();
}
/* /*
* This should be simply passing the byte value of the pattern Blob * This should be simply passing the byte value of the pattern Blob
*/ */
public long position(Blob pattern,long start) throws SQLException { public long position(Blob pattern, long start) throws SQLException
return position(pattern.getBytes(0,(int)pattern.length()),start); {
} 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 * This implements the Blob interface, which is basically another way to
* access a LargeObject. * 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 public class PGclob implements java.sql.Clob
{ {
private org.postgresql.Connection conn; private org.postgresql.Connection conn;
private int oid; private int oid;
private LargeObject lo; private LargeObject lo;
public PGclob(org.postgresql.Connection conn,int oid) throws SQLException { public PGclob(org.postgresql.Connection conn, int oid) throws SQLException
this.conn=conn; {
this.oid=oid; this.conn = conn;
LargeObjectManager lom = conn.getLargeObjectAPI(); this.oid = oid;
this.lo = lom.open(oid); LargeObjectManager lom = conn.getLargeObjectAPI();
} this.lo = lom.open(oid);
}
public long length() throws SQLException { public long length() throws SQLException
return lo.size(); {
} return lo.size();
}
public InputStream getAsciiStream() throws SQLException { public InputStream getAsciiStream() throws SQLException
return lo.getInputStream(); {
} return lo.getInputStream();
}
public Reader getCharacterStream() throws SQLException { public Reader getCharacterStream() throws SQLException
return new InputStreamReader(lo.getInputStream()); {
} return new InputStreamReader(lo.getInputStream());
}
public String getSubString(long i,int j) throws SQLException { public String getSubString(long i, int j) throws SQLException
lo.seek((int)i-1); {
return new String(lo.read(j)); lo.seek((int)i - 1);
} return new String(lo.read(j));
}
/* /*
* For now, this is not implemented. * For now, this is not implemented.
*/ */
public long position(String pattern,long start) throws SQLException { public long position(String pattern, long start) throws SQLException
throw org.postgresql.Driver.notImplemented(); {
} throw org.postgresql.Driver.notImplemented();
}
/* /*
* This should be simply passing the byte value of the pattern Blob * This should be simply passing the byte value of the pattern Blob
*/ */
public long position(Clob pattern,long start) throws SQLException { public long position(Clob pattern, long start) throws SQLException
throw org.postgresql.Driver.notImplemented(); {
} 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. * 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 * Returns the Test database JDBC URL
*/ */
public static String getURL() { public static String getURL()
{
return System.getProperty("database"); return System.getProperty("database");
} }
/** /**
* Returns the Postgresql username * Returns the Postgresql username
*/ */
public static String getUser() { public static String getUser()
{
return System.getProperty("username"); return System.getProperty("username");
} }
/** /**
* Returns the user's password * Returns the user's password
*/ */
public static String getPassword() { public static String getPassword()
{
return System.getProperty("password"); return System.getProperty("password");
} }
/** /**
* Helper - opens a connection. * Helper - opens a connection.
*/ */
public static java.sql.Connection openDB() { public static java.sql.Connection openDB()
try { {
try
{
Class.forName("org.postgresql.Driver"); Class.forName("org.postgresql.Driver");
return java.sql.DriverManager.getConnection(JDBC2Tests.getURL(),JDBC2Tests.getUser(),JDBC2Tests.getPassword()); return java.sql.DriverManager.getConnection(JDBC2Tests.getURL(), JDBC2Tests.getUser(), JDBC2Tests.getPassword());
} catch(ClassNotFoundException ex) { }
catch (ClassNotFoundException ex)
{
TestCase.fail(ex.getMessage()); TestCase.fail(ex.getMessage());
} catch(SQLException ex) { }
catch (SQLException ex)
{
TestCase.fail(ex.getMessage()); TestCase.fail(ex.getMessage());
} }
return null; return null;
@@ -50,11 +60,15 @@ public class JDBC2Tests extends TestSuite {
* Helper - closes an open connection. This rewrites SQLException to a failed * Helper - closes an open connection. This rewrites SQLException to a failed
* assertion. It's static so other classes can use it. * assertion. It's static so other classes can use it.
*/ */
public static void closeDB(Connection con) { public static void closeDB(Connection con)
try { {
try
{
if (con != null) if (con != null)
con.close(); con.close();
} catch (SQLException ex) { }
catch (SQLException ex)
{
TestCase.fail(ex.getMessage()); TestCase.fail(ex.getMessage());
} }
} }
@@ -64,19 +78,26 @@ public class JDBC2Tests extends TestSuite {
*/ */
public static void createTable(Connection con, public static void createTable(Connection con,
String table, String table,
String columns) { String columns)
try { {
try
{
Statement st = con.createStatement(); Statement st = con.createStatement();
try { try
{
// Drop the table // Drop the table
dropTable(con, table); dropTable(con, table);
// Now create the table // Now create the table
st.executeUpdate("create table " + table + " (" + columns + ")"); st.executeUpdate("create table " + table + " (" + columns + ")");
} finally { }
finally
{
st.close(); st.close();
} }
} catch(SQLException ex) { }
catch (SQLException ex)
{
TestCase.fail(ex.getMessage()); TestCase.fail(ex.getMessage());
} }
} }
@@ -84,15 +105,22 @@ public class JDBC2Tests extends TestSuite {
/** /**
* Helper - drops a table * Helper - drops a table
*/ */
public static void dropTable(Connection con, String table) { public static void dropTable(Connection con, String table)
try { {
try
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
try { try
{
stmt.executeUpdate("DROP TABLE " + table); stmt.executeUpdate("DROP TABLE " + table);
} catch (SQLException ex) { }
catch (SQLException ex)
{
// ignore // ignore
} }
} catch (SQLException ex) { }
catch (SQLException ex)
{
TestCase.fail(ex.getMessage()); TestCase.fail(ex.getMessage());
} }
} }
@@ -100,11 +128,13 @@ public class JDBC2Tests extends TestSuite {
/** /**
* Helper - generates INSERT SQL - very simple * 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); 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; String s = "INSERT INTO " + table;
if (columns != null) if (columns != null)
@@ -116,15 +146,18 @@ public class JDBC2Tests extends TestSuite {
/** /**
* Helper - generates SELECT SQL - very simple * 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); 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); 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; String s = "SELECT " + columns + " FROM " + table;
if (where != null) if (where != null)
@@ -140,7 +173,8 @@ public class JDBC2Tests extends TestSuite {
* @param v value to prefix * @param v value to prefix
* @param l number of digits (0-10) * @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); String s = "0000000000".substring(0, l) + Integer.toString(v);
return s.substring(s.length() - l); return s.substring(s.length() - l);
} }
@@ -148,8 +182,9 @@ public class JDBC2Tests extends TestSuite {
/** /**
* The main entry point for JUnit * The main entry point for JUnit
*/ */
public static TestSuite suite() { public static TestSuite suite()
TestSuite suite= new TestSuite(); {
TestSuite suite = new TestSuite();
// //
// Add one line per class in our test cases. These should be in order of // 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; import junit.framework.TestCase;
public class ANTTest extends TestCase { public class ANTTest extends TestCase
public ANTTest(String name) { {
super(name); public ANTTest(String name)
} {
super(name);
}
/** /**
* This tests the acceptsURL() method with a couple of good and badly formed * This tests the acceptsURL() method with a couple of good and badly formed
* jdbc urls * jdbc urls
*/ */
public void testANT() { public void testANT()
String url=System.getProperty("database"); {
String usr=System.getProperty("username"); String url = System.getProperty("database");
String psw=System.getProperty("password"); String usr = System.getProperty("username");
String psw = System.getProperty("password");
assertNotNull(url); assertNotNull(url);
assertNotNull(usr); assertNotNull(usr);
assertNotNull(psw); assertNotNull(psw);
assertTrue(! url.equals("")); assertTrue(! url.equals(""));
assertTrue(! usr.equals("")); assertTrue(! usr.equals(""));
} }
} }

View File

@@ -12,17 +12,20 @@ import java.sql.*;
/** /**
* Test case for Statement.batchExecute() * Test case for Statement.batchExecute()
*/ */
public class BatchExecuteTest extends TestCase { public class BatchExecuteTest extends TestCase
{
private Connection con; private Connection con;
public BatchExecuteTest(String name) { public BatchExecuteTest(String name)
{
super(name); super(name);
} }
// Set up the fixture for this testcase: a connection to a database with // Set up the fixture for this testcase: a connection to a database with
// a table for this test. // a table for this test.
protected void setUp() throws Exception { protected void setUp() throws Exception
{
con = JDBC2Tests.openDB(); con = JDBC2Tests.openDB();
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
@@ -38,19 +41,22 @@ public class BatchExecuteTest extends TestCase {
} }
// Tear down the fixture for this test case. // Tear down the fixture for this test case.
protected void tearDown() throws Exception { protected void tearDown() throws Exception
{
con.setAutoCommit(true); con.setAutoCommit(true);
JDBC2Tests.dropTable(con, "testbatch"); JDBC2Tests.dropTable(con, "testbatch");
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} }
public void testSupportsBatchUpdates() throws Exception { public void testSupportsBatchUpdates() throws Exception
{
DatabaseMetaData dbmd = con.getMetaData(); DatabaseMetaData dbmd = con.getMetaData();
assertTrue(dbmd.supportsBatchUpdates()); assertTrue(dbmd.supportsBatchUpdates());
} }
private void assertCol1HasValue(int expected) throws Exception { private void assertCol1HasValue(int expected) throws Exception
{
Statement getCol1 = con.createStatement(); Statement getCol1 = con.createStatement();
ResultSet rs = ResultSet rs =
@@ -67,19 +73,21 @@ public class BatchExecuteTest extends TestCase {
getCol1.close(); getCol1.close();
} }
public void testExecuteEmptyBatch() throws Exception { public void testExecuteEmptyBatch() throws Exception
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
int[] updateCount = stmt.executeBatch(); int[] updateCount = stmt.executeBatch();
assertEquals(0,updateCount.length); assertEquals(0, updateCount.length);
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1"); stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
stmt.clearBatch(); stmt.clearBatch();
updateCount = stmt.executeBatch(); updateCount = stmt.executeBatch();
assertEquals(0,updateCount.length); assertEquals(0, updateCount.length);
stmt.close(); stmt.close();
} }
public void testClearBatch() throws Exception { public void testClearBatch() throws Exception
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1"); stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
@@ -98,44 +106,51 @@ public class BatchExecuteTest extends TestCase {
stmt.close(); stmt.close();
} }
public void testSelectThrowsException() throws Exception { public void testSelectThrowsException() throws Exception
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1"); stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
stmt.addBatch("SELECT col1 FROM testbatch WHERE pk = 1"); stmt.addBatch("SELECT col1 FROM testbatch WHERE pk = 1");
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1"); stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
try { try
{
stmt.executeBatch(); stmt.executeBatch();
fail("Should raise a BatchUpdateException because of the SELECT"); fail("Should raise a BatchUpdateException because of the SELECT");
} catch (BatchUpdateException e) { }
catch (BatchUpdateException e)
{
int [] updateCounts = e.getUpdateCounts(); int [] updateCounts = e.getUpdateCounts();
assertEquals(1,updateCounts.length); assertEquals(1, updateCounts.length);
assertEquals(1,updateCounts[0]); assertEquals(1, updateCounts[0]);
} catch (SQLException e) { }
catch (SQLException e)
{
fail( "Should throw a BatchUpdateException instead of " + fail( "Should throw a BatchUpdateException instead of " +
"a generic SQLException: " + e); "a generic SQLException: " + e);
} }
stmt.close(); stmt.close();
} }
public void testPreparedStatement() throws Exception { public void testPreparedStatement() throws Exception
{
PreparedStatement pstmt = con.prepareStatement( 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 // Note that the first parameter changes for every statement in the
// batch, whereas the second parameter remains constant. // batch, whereas the second parameter remains constant.
pstmt.setInt(1,1); pstmt.setInt(1, 1);
pstmt.setInt(2,1); pstmt.setInt(2, 1);
pstmt.addBatch(); pstmt.addBatch();
assertCol1HasValue(0); assertCol1HasValue(0);
pstmt.setInt(1,2); pstmt.setInt(1, 2);
pstmt.addBatch(); pstmt.addBatch();
assertCol1HasValue(0); assertCol1HasValue(0);
pstmt.setInt(1,4); pstmt.setInt(1, 4);
pstmt.addBatch(); pstmt.addBatch();
assertCol1HasValue(0); assertCol1HasValue(0);
@@ -153,7 +168,8 @@ public class BatchExecuteTest extends TestCase {
/** /**
*/ */
public void testTransactionalBehaviour() throws Exception { public void testTransactionalBehaviour() throws Exception
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1"); stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
@@ -170,9 +186,9 @@ public class BatchExecuteTest extends TestCase {
assertCol1HasValue(0); assertCol1HasValue(0);
int[] updateCounts = stmt.executeBatch(); int[] updateCounts = stmt.executeBatch();
assertEquals(2,updateCounts.length); assertEquals(2, updateCounts.length);
assertEquals(1,updateCounts[0]); assertEquals(1, updateCounts[0]);
assertEquals(1,updateCounts[1]); assertEquals(1, updateCounts[1]);
assertCol1HasValue(12); assertCol1HasValue(12);
con.commit(); con.commit();

View File

@@ -8,30 +8,34 @@ import java.sql.*;
import org.postgresql.largeobject.*; 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 * Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-) * 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 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); super(name);
} }
protected void setUp() throws Exception { protected void setUp() throws Exception
{
con = JDBC2Tests.openDB(); con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "testblob", "id name,lo oid"); JDBC2Tests.createTable(con, "testblob", "id name,lo oid");
} }
protected void tearDown() throws Exception { protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testblob"); JDBC2Tests.dropTable(con, "testblob");
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} }
@@ -39,8 +43,10 @@ public class BlobTest extends TestCase {
/** /**
* Tests one method of uploading a blob to the database * Tests one method of uploading a blob to the database
*/ */
public void testUploadBlob_LOOP() { public void testUploadBlob_LOOP()
try { {
try
{
con.setAutoCommit(false); con.setAutoCommit(false);
assertTrue(!con.getAutoCommit()); assertTrue(!con.getAutoCommit());
@@ -51,7 +57,9 @@ public class BlobTest extends TestCase {
assertTrue(compareBlobs()); assertTrue(compareBlobs());
con.setAutoCommit(true); con.setAutoCommit(true);
} catch(Exception ex) { }
catch (Exception ex)
{
fail(ex.getMessage()); fail(ex.getMessage());
} }
} }
@@ -59,8 +67,10 @@ public class BlobTest extends TestCase {
/** /**
* Tests one method of uploading a blob to the database * Tests one method of uploading a blob to the database
*/ */
public void testUploadBlob_NATIVE() { public void testUploadBlob_NATIVE()
try { {
try
{
con.setAutoCommit(false); con.setAutoCommit(false);
assertTrue(!con.getAutoCommit()); assertTrue(!con.getAutoCommit());
@@ -71,7 +81,9 @@ public class BlobTest extends TestCase {
assertTrue(compareBlobs()); assertTrue(compareBlobs());
con.setAutoCommit(true); con.setAutoCommit(true);
} catch(Exception ex) { }
catch (Exception ex)
{
fail(ex.getMessage()); 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 * because it always works, and we can use it as a base to test the new
* methods. * 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(); LargeObjectManager lom = ((org.postgresql.Connection)con).getLargeObjectAPI();
FileInputStream fis = new FileInputStream(file); FileInputStream fis = new FileInputStream(file);
@@ -89,40 +102,42 @@ public class BlobTest extends TestCase {
int oid = lom.create(LargeObjectManager.READWRITE); int oid = lom.create(LargeObjectManager.READWRITE);
LargeObject blob = lom.open(oid); LargeObject blob = lom.open(oid);
int s,t; int s, t;
byte buf[]; byte buf[];
OutputStream os; OutputStream os;
switch(method) switch (method)
{ {
case LOOP: case LOOP:
buf = new byte[2048]; buf = new byte[2048];
t=0; t = 0;
while((s=fis.read(buf,0,buf.length))>0) { while ((s = fis.read(buf, 0, buf.length)) > 0)
t+=s; {
blob.write(buf,0,s); t += s;
} blob.write(buf, 0, s);
break; }
break;
case NATIVE_STREAM: case NATIVE_STREAM:
os = blob.getOutputStream(); os = blob.getOutputStream();
s= fis.read(); s = fis.read();
while(s>-1) { while (s > -1)
os.write(s); {
s=fis.read(); os.write(s);
} s = fis.read();
os.close(); }
break; os.close();
break;
case JDBC_STREAM: case JDBC_STREAM:
File f = new File(file); File f = new File(file);
PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testblob", "?")); PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testblob", "?"));
ps.setBinaryStream(1,fis,(int) f.length()); ps.setBinaryStream(1, fis, (int) f.length());
ps.execute(); ps.execute();
break; break;
default: default:
assertTrue("Unknown method in uploadFile",false); assertTrue("Unknown method in uploadFile", false);
} }
blob.close(); blob.close();
@@ -130,7 +145,7 @@ public class BlobTest extends TestCase {
// Insert into the table // Insert into the table
Statement st = con.createStatement(); Statement st = con.createStatement();
st.executeUpdate(JDBC2Tests.insertSQL("testblob", "id,lo","'"+file+"',"+oid)); st.executeUpdate(JDBC2Tests.insertSQL("testblob", "id,lo", "'" + file + "'," + oid));
con.commit(); con.commit();
st.close(); 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 * Helper - compares the blobs in a table with a local file. Note this alone
* tests the InputStream methods! * tests the InputStream methods!
*/ */
private boolean compareBlobs() throws Exception { private boolean compareBlobs() throws Exception
boolean result=true; {
boolean result = true;
LargeObjectManager lom = ((org.postgresql.Connection)con).getLargeObjectAPI(); 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")); ResultSet rs = st.executeQuery(JDBC2Tests.selectSQL("testblob", "id,lo"));
assertNotNull(rs); assertNotNull(rs);
while(rs.next()) { while (rs.next())
{
String file = rs.getString(1); String file = rs.getString(1);
int oid = rs.getInt(2); int oid = rs.getInt(2);
@@ -158,19 +175,20 @@ public class BlobTest extends TestCase {
LargeObject blob = lom.open(oid); LargeObject blob = lom.open(oid);
InputStream bis = blob.getInputStream(); InputStream bis = blob.getInputStream();
int f=fis.read(); int f = fis.read();
int b=bis.read(); int b = bis.read();
int c=0; int c = 0;
while(f>=0 && b>=0 & result) { while (f >= 0 && b >= 0 & result)
result=(f==b); {
f=fis.read(); result = (f == b);
b=bis.read(); f = fis.read();
b = bis.read();
c++; c++;
} }
result=result && f==-1 && b==-1; result = result && f == -1 && b == -1;
if(!result) if (!result)
System.out.println("\nBlob compare failed at "+c+" of "+blob.size()); System.out.println("\nBlob compare failed at " + c + " of " + blob.size());
blob.close(); blob.close();
fis.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? ;-) * 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 * Constructor
*/ */
public ConnectionTest(String name) { public ConnectionTest(String name)
super(name); {
} super(name);
}
// Set up the fixture for this testcase: the tables for this test. // Set up the fixture for this testcase: the tables for this test.
protected void setUp() throws Exception { protected void setUp() throws Exception
Connection con = JDBC2Tests.openDB(); {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "test_a", "imagename name,image oid,id int4"); 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_c", "source text,cost money,imageid int4");
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} }
// Tear down the fixture for this test case. // Tear down the fixture for this test case.
protected void tearDown() throws Exception { protected void tearDown() throws Exception
Connection con = JDBC2Tests.openDB(); {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.dropTable(con, "test_a"); JDBC2Tests.dropTable(con, "test_a");
JDBC2Tests.dropTable(con, "test_c"); JDBC2Tests.dropTable(con, "test_c");
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} }
/** /**
* Tests the two forms of createStatement() * Tests the two forms of createStatement()
*/ */
public void testCreateStatement() { public void testCreateStatement()
try { {
java.sql.Connection conn = JDBC2Tests.openDB(); try
{
java.sql.Connection conn = JDBC2Tests.openDB();
// A standard Statement // A standard Statement
java.sql.Statement stat = conn.createStatement(); java.sql.Statement stat = conn.createStatement();
assertNotNull(stat); assertNotNull(stat);
stat.close(); stat.close();
// Ask for Updateable ResultSets // Ask for Updateable ResultSets
stat = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_UPDATABLE); stat = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
assertNotNull(stat); assertNotNull(stat);
stat.close(); stat.close();
} catch(SQLException ex) { }
assertTrue(ex.getMessage(),false); catch (SQLException ex)
} {
} assertTrue(ex.getMessage(), false);
}
}
/** /**
* Tests the two forms of prepareStatement() * Tests the two forms of prepareStatement()
*/ */
public void testPrepareStatement() { public void testPrepareStatement()
try { {
java.sql.Connection conn = JDBC2Tests.openDB(); try
{
java.sql.Connection conn = JDBC2Tests.openDB();
String sql = "select source,cost,imageid from test_c"; String sql = "select source,cost,imageid from test_c";
// A standard Statement // A standard Statement
java.sql.PreparedStatement stat = conn.prepareStatement(sql); java.sql.PreparedStatement stat = conn.prepareStatement(sql);
assertNotNull(stat); assertNotNull(stat);
stat.close(); stat.close();
// Ask for Updateable ResultSets // Ask for Updateable ResultSets
stat = conn.prepareStatement(sql,java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_UPDATABLE); stat = conn.prepareStatement(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
assertNotNull(stat); assertNotNull(stat);
stat.close(); stat.close();
} catch(SQLException ex) { }
assertTrue(ex.getMessage(),false); catch (SQLException ex)
} {
} assertTrue(ex.getMessage(), false);
}
}
/** /**
* Put the test for createPrepareCall here * Put the test for createPrepareCall here
*/ */
public void testPrepareCall() { public void testPrepareCall()
} {}
/** /**
* Test nativeSQL * Test nativeSQL
*/ */
public void testNativeSQL() { public void testNativeSQL()
// For now do nothing as it returns itself {
} // For now do nothing as it returns itself
}
/** /**
* Test autoCommit (both get & set) * Test autoCommit (both get & set)
*/ */
public void testTransactions() { public void testTransactions()
try { {
java.sql.Connection con = JDBC2Tests.openDB(); try
java.sql.Statement st; {
java.sql.ResultSet rs; java.sql.Connection con = JDBC2Tests.openDB();
java.sql.Statement st;
java.sql.ResultSet rs;
// Turn it off // Turn it off
con.setAutoCommit(false); con.setAutoCommit(false);
assertTrue(!con.getAutoCommit()); assertTrue(!con.getAutoCommit());
// Turn it back on // Turn it back on
con.setAutoCommit(true); con.setAutoCommit(true);
assertTrue(con.getAutoCommit()); assertTrue(con.getAutoCommit());
// Now test commit // Now test commit
st = con.createStatement(); st = con.createStatement();
st.executeUpdate("insert into test_a (imagename,image,id) values ('comttest',1234,5678)"); st.executeUpdate("insert into test_a (imagename,image,id) values ('comttest',1234,5678)");
con.setAutoCommit(false); con.setAutoCommit(false);
// Now update image to 9876 and commit // Now update image to 9876 and commit
st.executeUpdate("update test_a set image=9876 where id=5678"); st.executeUpdate("update test_a set image=9876 where id=5678");
con.commit(); con.commit();
rs = st.executeQuery("select image from test_a where id=5678"); rs = st.executeQuery("select image from test_a where id=5678");
assertTrue(rs.next()); assertTrue(rs.next());
assertEquals(9876, rs.getInt(1)); assertEquals(9876, rs.getInt(1));
rs.close(); rs.close();
// Now try to change it but rollback // Now try to change it but rollback
st.executeUpdate("update test_a set image=1111 where id=5678"); st.executeUpdate("update test_a set image=1111 where id=5678");
con.rollback(); con.rollback();
rs = st.executeQuery("select image from test_a where id=5678"); rs = st.executeQuery("select image from test_a where id=5678");
assertTrue(rs.next()); assertTrue(rs.next());
assertEquals(9876, rs.getInt(1)); // Should not change! assertEquals(9876, rs.getInt(1)); // Should not change!
rs.close(); rs.close();
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} catch(SQLException ex) { }
assertTrue(ex.getMessage(),false); catch (SQLException ex)
} {
} assertTrue(ex.getMessage(), false);
}
}
/** /**
* Simple test to see if isClosed works. * Simple test to see if isClosed works.
*/ */
public void testIsClosed() { public void testIsClosed()
try { {
Connection con = JDBC2Tests.openDB(); try
{
Connection con = JDBC2Tests.openDB();
// Should not say closed // Should not say closed
assertTrue(!con.isClosed()); assertTrue(!con.isClosed());
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
// Should now say closed // Should now say closed
assertTrue(con.isClosed()); assertTrue(con.isClosed());
} catch(SQLException ex) { }
assertTrue(ex.getMessage(),false); catch (SQLException ex)
} {
} assertTrue(ex.getMessage(), false);
}
}
/** /**
* Test the warnings system * Test the warnings system
*/ */
public void testWarnings() { public void testWarnings()
try { {
Connection con = JDBC2Tests.openDB(); try
{
Connection con = JDBC2Tests.openDB();
String testStr = "This Is OuR TeSt message"; String testStr = "This Is OuR TeSt message";
// The connection must be ours! // The connection must be ours!
assertTrue(con instanceof org.postgresql.Connection); assertTrue(con instanceof org.postgresql.Connection);
// Clear any existing warnings // Clear any existing warnings
con.clearWarnings(); con.clearWarnings();
// Set the test warning // Set the test warning
((org.postgresql.Connection)con).addWarning(testStr); ((org.postgresql.Connection)con).addWarning(testStr);
// Retrieve it // Retrieve it
SQLWarning warning = con.getWarnings(); SQLWarning warning = con.getWarnings();
assertNotNull(warning); assertNotNull(warning);
assertEquals(testStr, warning.getMessage()); assertEquals(testStr, warning.getMessage());
// Finally test clearWarnings() this time there must be something to delete // Finally test clearWarnings() this time there must be something to delete
con.clearWarnings(); con.clearWarnings();
assertTrue(con.getWarnings()==null); assertTrue(con.getWarnings() == null);
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} catch(SQLException ex) { }
assertTrue(ex.getMessage(),false); catch (SQLException ex)
} {
} assertTrue(ex.getMessage(), false);
}
}
/** /**
* Transaction Isolation Levels * Transaction Isolation Levels
@@ -210,14 +235,14 @@ public class ConnectionTest extends TestCase {
// PostgreSQL defaults to READ COMMITTED // PostgreSQL defaults to READ COMMITTED
assertEquals(Connection.TRANSACTION_READ_COMMITTED, assertEquals(Connection.TRANSACTION_READ_COMMITTED,
con.getTransactionIsolation()); con.getTransactionIsolation());
// Begin a transaction // Begin a transaction
con.setAutoCommit(false); con.setAutoCommit(false);
// The isolation level should not have changed // The isolation level should not have changed
assertEquals(Connection.TRANSACTION_READ_COMMITTED, assertEquals(Connection.TRANSACTION_READ_COMMITTED,
con.getTransactionIsolation()); con.getTransactionIsolation());
// Now change the default for future transactions // Now change the default for future transactions
con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
@@ -227,14 +252,14 @@ public class ConnectionTest extends TestCase {
// transaction did not change. It affects only future transactions. // transaction did not change. It affects only future transactions.
// This behaviour is recommended by the JDBC spec. // This behaviour is recommended by the JDBC spec.
assertEquals(Connection.TRANSACTION_READ_COMMITTED, assertEquals(Connection.TRANSACTION_READ_COMMITTED,
con.getTransactionIsolation()); con.getTransactionIsolation());
// Begin a new transaction // Begin a new transaction
con.commit(); con.commit();
// Now we should see the new isolation level // Now we should see the new isolation level
assertEquals(Connection.TRANSACTION_SERIALIZABLE, assertEquals(Connection.TRANSACTION_SERIALIZABLE,
con.getTransactionIsolation()); con.getTransactionIsolation());
// Repeat the steps above with the transition back to // Repeat the steps above with the transition back to
// READ COMMITTED. // READ COMMITTED.
@@ -284,28 +309,32 @@ public class ConnectionTest extends TestCase {
} }
} }
/** /**
* JDBC2 Type mappings * JDBC2 Type mappings
*/ */
public void testTypeMaps() { public void testTypeMaps()
try { {
Connection con = JDBC2Tests.openDB(); try
{
Connection con = JDBC2Tests.openDB();
// preserve the current map // preserve the current map
java.util.Map oldmap = con.getTypeMap(); java.util.Map oldmap = con.getTypeMap();
// now change it for an empty one // now change it for an empty one
java.util.Map newmap = new java.util.HashMap(); java.util.Map newmap = new java.util.HashMap();
con.setTypeMap(newmap); con.setTypeMap(newmap);
assertEquals(newmap, con.getTypeMap()); assertEquals(newmap, con.getTypeMap());
// restore the old one // restore the old one
con.setTypeMap(oldmap); con.setTypeMap(oldmap);
assertEquals(oldmap, con.getTypeMap()); assertEquals(oldmap, con.getTypeMap());
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} catch(SQLException ex) { }
assertTrue(ex.getMessage(),false); 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? ;-) * 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 { public class DatabaseMetaDataTest extends TestCase
{
/**
* Constructor /**
*/ * Constructor
public DatabaseMetaDataTest(String name) { */
super(name); public DatabaseMetaDataTest(String name)
} {
super(name);
/** }
* The spec says this may return null, but we always do!
*/ /**
public void testGetMetaData() { * The spec says this may return null, but we always do!
try { */
Connection con = JDBC2Tests.openDB(); public void testGetMetaData()
{
DatabaseMetaData dbmd = con.getMetaData(); try
assertNotNull(dbmd); {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.closeDB(con);
} catch(SQLException ex) { DatabaseMetaData dbmd = con.getMetaData();
fail(ex.getMessage()); assertNotNull(dbmd);
}
} JDBC2Tests.closeDB(con);
}
/** catch (SQLException ex)
* Test default capabilities {
*/ fail(ex.getMessage());
public void testCapabilities() { }
try { }
Connection con = JDBC2Tests.openDB();
/**
DatabaseMetaData dbmd = con.getMetaData(); * Test default capabilities
assertNotNull(dbmd); */
public void testCapabilities()
assertTrue(dbmd.allProceduresAreCallable()); {
assertTrue(dbmd.allTablesAreSelectable()); // not true all the time try
{
// This should always be false for postgresql (at least for 7.x) Connection con = JDBC2Tests.openDB();
assertTrue(!dbmd.isReadOnly());
DatabaseMetaData dbmd = con.getMetaData();
// does the backend support this yet? The protocol does... assertNotNull(dbmd);
assertTrue(!dbmd.supportsMultipleResultSets());
assertTrue(dbmd.allProceduresAreCallable());
// yes, as multiple backends can have transactions open assertTrue(dbmd.allTablesAreSelectable()); // not true all the time
assertTrue(dbmd.supportsMultipleTransactions());
// This should always be false for postgresql (at least for 7.x)
assertTrue(dbmd.supportsMinimumSQLGrammar()); assertTrue(!dbmd.isReadOnly());
assertTrue(!dbmd.supportsCoreSQLGrammar());
assertTrue(!dbmd.supportsExtendedSQLGrammar()); // does the backend support this yet? The protocol does...
assertTrue(!dbmd.supportsANSI92EntryLevelSQL()); assertTrue(!dbmd.supportsMultipleResultSets());
assertTrue(!dbmd.supportsANSI92IntermediateSQL());
assertTrue(!dbmd.supportsANSI92FullSQL()); // yes, as multiple backends can have transactions open
assertTrue(dbmd.supportsMultipleTransactions());
assertTrue(!dbmd.supportsIntegrityEnhancementFacility());
assertTrue(dbmd.supportsMinimumSQLGrammar());
JDBC2Tests.closeDB(con); assertTrue(!dbmd.supportsCoreSQLGrammar());
} catch(SQLException ex) { assertTrue(!dbmd.supportsExtendedSQLGrammar());
fail(ex.getMessage()); assertTrue(!dbmd.supportsANSI92EntryLevelSQL());
} assertTrue(!dbmd.supportsANSI92IntermediateSQL());
} assertTrue(!dbmd.supportsANSI92FullSQL());
assertTrue(!dbmd.supportsIntegrityEnhancementFacility());
public void testJoins() {
try { JDBC2Tests.closeDB(con);
Connection con = JDBC2Tests.openDB(); }
catch (SQLException ex)
DatabaseMetaData dbmd = con.getMetaData(); {
assertNotNull(dbmd); fail(ex.getMessage());
}
assertTrue(dbmd.supportsOuterJoins()); }
assertTrue(dbmd.supportsFullOuterJoins());
assertTrue(dbmd.supportsLimitedOuterJoins());
public void testJoins()
JDBC2Tests.closeDB(con); {
} catch(SQLException ex) { try
fail(ex.getMessage()); {
} Connection con = JDBC2Tests.openDB();
}
DatabaseMetaData dbmd = con.getMetaData();
public void testCursors() { assertNotNull(dbmd);
try {
Connection con = JDBC2Tests.openDB(); assertTrue(dbmd.supportsOuterJoins());
assertTrue(dbmd.supportsFullOuterJoins());
DatabaseMetaData dbmd = con.getMetaData(); assertTrue(dbmd.supportsLimitedOuterJoins());
assertNotNull(dbmd);
JDBC2Tests.closeDB(con);
assertTrue(!dbmd.supportsPositionedDelete()); }
assertTrue(!dbmd.supportsPositionedUpdate()); catch (SQLException ex)
{
JDBC2Tests.closeDB(con); fail(ex.getMessage());
} catch(SQLException ex) { }
fail(ex.getMessage()); }
}
} public void testCursors()
{
public void testNulls() { try
try { {
Connection con = JDBC2Tests.openDB(); Connection con = JDBC2Tests.openDB();
DatabaseMetaData dbmd = con.getMetaData(); DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd); assertNotNull(dbmd);
// We need to type cast the connection to get access to the assertTrue(!dbmd.supportsPositionedDelete());
// PostgreSQL-specific method haveMinimumServerVersion(). assertTrue(!dbmd.supportsPositionedUpdate());
// This is not available through the java.sql.Connection interface.
assertTrue( con instanceof org.postgresql.Connection ); JDBC2Tests.closeDB(con);
}
assertTrue(!dbmd.nullsAreSortedAtStart()); catch (SQLException ex)
assertTrue( dbmd.nullsAreSortedAtEnd() != {
((org.postgresql.Connection)con).haveMinimumServerVersion("7.2")); fail(ex.getMessage());
assertTrue( dbmd.nullsAreSortedHigh() == }
((org.postgresql.Connection)con).haveMinimumServerVersion("7.2")); }
assertTrue(!dbmd.nullsAreSortedLow());
public void testNulls()
assertTrue(dbmd.nullPlusNonNullIsNull()); {
try
assertTrue(dbmd.supportsNonNullableColumns()); {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.closeDB(con);
} catch(SQLException ex) { DatabaseMetaData dbmd = con.getMetaData();
fail(ex.getMessage()); assertNotNull(dbmd);
}
} // We need to type cast the connection to get access to the
// PostgreSQL-specific method haveMinimumServerVersion().
public void testLocalFiles() { // This is not available through the java.sql.Connection interface.
try { assertTrue( con instanceof org.postgresql.Connection );
Connection con = JDBC2Tests.openDB();
assertTrue(!dbmd.nullsAreSortedAtStart());
DatabaseMetaData dbmd = con.getMetaData(); assertTrue( dbmd.nullsAreSortedAtEnd() !=
assertNotNull(dbmd); ((org.postgresql.Connection)con).haveMinimumServerVersion("7.2"));
assertTrue( dbmd.nullsAreSortedHigh() ==
assertTrue(!dbmd.usesLocalFilePerTable()); ((org.postgresql.Connection)con).haveMinimumServerVersion("7.2"));
assertTrue(!dbmd.usesLocalFiles()); assertTrue(!dbmd.nullsAreSortedLow());
JDBC2Tests.closeDB(con); assertTrue(dbmd.nullPlusNonNullIsNull());
} catch(SQLException ex) {
fail(ex.getMessage()); assertTrue(dbmd.supportsNonNullableColumns());
}
} JDBC2Tests.closeDB(con);
}
public void testIdentifiers() { catch (SQLException ex)
try { {
Connection con = JDBC2Tests.openDB(); fail(ex.getMessage());
}
DatabaseMetaData dbmd = con.getMetaData(); }
assertNotNull(dbmd);
public void testLocalFiles()
assertTrue(!dbmd.supportsMixedCaseIdentifiers()); // always false {
assertTrue(dbmd.supportsMixedCaseQuotedIdentifiers()); // always true try
{
assertTrue(!dbmd.storesUpperCaseIdentifiers()); // always false Connection con = JDBC2Tests.openDB();
assertTrue(dbmd.storesLowerCaseIdentifiers()); // always true
assertTrue(!dbmd.storesUpperCaseQuotedIdentifiers()); // always false DatabaseMetaData dbmd = con.getMetaData();
assertTrue(!dbmd.storesLowerCaseQuotedIdentifiers()); // always false assertNotNull(dbmd);
assertTrue(!dbmd.storesMixedCaseQuotedIdentifiers()); // always false
assertTrue(!dbmd.usesLocalFilePerTable());
assertTrue(dbmd.getIdentifierQuoteString().equals("\"")); assertTrue(!dbmd.usesLocalFiles());
JDBC2Tests.closeDB(con);
JDBC2Tests.closeDB(con); }
} catch(SQLException ex) { catch (SQLException ex)
fail(ex.getMessage()); {
} fail(ex.getMessage());
} }
}
public void testTables() {
try { public void testIdentifiers()
Connection con = JDBC2Tests.openDB(); {
try
DatabaseMetaData dbmd = con.getMetaData(); {
assertNotNull(dbmd); Connection con = JDBC2Tests.openDB();
// we can add columns DatabaseMetaData dbmd = con.getMetaData();
assertTrue(dbmd.supportsAlterTableWithAddColumn()); assertNotNull(dbmd);
// we can't drop columns (yet) assertTrue(!dbmd.supportsMixedCaseIdentifiers()); // always false
assertTrue(!dbmd.supportsAlterTableWithDropColumn()); assertTrue(dbmd.supportsMixedCaseQuotedIdentifiers()); // always true
JDBC2Tests.closeDB(con); assertTrue(!dbmd.storesUpperCaseIdentifiers()); // always false
} catch(SQLException ex) { assertTrue(dbmd.storesLowerCaseIdentifiers()); // always true
fail(ex.getMessage()); assertTrue(!dbmd.storesUpperCaseQuotedIdentifiers()); // always false
} assertTrue(!dbmd.storesLowerCaseQuotedIdentifiers()); // always false
} assertTrue(!dbmd.storesMixedCaseQuotedIdentifiers()); // always false
public void testSelect() { assertTrue(dbmd.getIdentifierQuoteString().equals("\""));
try {
Connection con = JDBC2Tests.openDB();
JDBC2Tests.closeDB(con);
DatabaseMetaData dbmd = con.getMetaData(); }
assertNotNull(dbmd); catch (SQLException ex)
{
// yes we can?: SELECT col a FROM a; fail(ex.getMessage());
assertTrue(dbmd.supportsColumnAliasing()); }
}
// yes we can have expressions in ORDERBY
assertTrue(dbmd.supportsExpressionsInOrderBy()); public void testTables()
{
// Yes, an ORDER BY clause can contain columns that are not in the try
// SELECT clause. {
assertTrue(dbmd.supportsOrderByUnrelated()); Connection con = JDBC2Tests.openDB();
assertTrue(dbmd.supportsGroupBy()); DatabaseMetaData dbmd = con.getMetaData();
assertTrue(dbmd.supportsGroupByUnrelated()); assertNotNull(dbmd);
assertTrue(dbmd.supportsGroupByBeyondSelect()); // needs checking
// we can add columns
JDBC2Tests.closeDB(con); assertTrue(dbmd.supportsAlterTableWithAddColumn());
} catch(SQLException ex) {
fail(ex.getMessage()); // we can't drop columns (yet)
} assertTrue(!dbmd.supportsAlterTableWithDropColumn());
}
JDBC2Tests.closeDB(con);
public void testDBParams() { }
try { catch (SQLException ex)
Connection con = JDBC2Tests.openDB(); {
fail(ex.getMessage());
DatabaseMetaData dbmd = con.getMetaData(); }
assertNotNull(dbmd); }
assertTrue(dbmd.getURL().equals(JDBC2Tests.getURL())); public void testSelect()
assertTrue(dbmd.getUserName().equals(JDBC2Tests.getUser())); {
try
JDBC2Tests.closeDB(con); {
} catch(SQLException ex) { Connection con = JDBC2Tests.openDB();
fail(ex.getMessage());
} DatabaseMetaData dbmd = con.getMetaData();
} assertNotNull(dbmd);
public void testDbProductDetails() { // yes we can?: SELECT col a FROM a;
try { assertTrue(dbmd.supportsColumnAliasing());
Connection con = JDBC2Tests.openDB();
assertTrue(con instanceof org.postgresql.Connection); // yes we can have expressions in ORDERBY
org.postgresql.Connection pc = (org.postgresql.Connection) con; assertTrue(dbmd.supportsExpressionsInOrderBy());
DatabaseMetaData dbmd = con.getMetaData(); // Yes, an ORDER BY clause can contain columns that are not in the
assertNotNull(dbmd); // SELECT clause.
assertTrue(dbmd.supportsOrderByUnrelated());
assertTrue(dbmd.getDatabaseProductName().equals("PostgreSQL"));
assertTrue(dbmd.getDatabaseProductVersion().startsWith(Integer.toString(pc.this_driver.getMajorVersion())+"."+Integer.toString(pc.this_driver.getMinorVersion()))); assertTrue(dbmd.supportsGroupBy());
assertTrue(dbmd.getDriverName().equals("PostgreSQL Native Driver")); assertTrue(dbmd.supportsGroupByUnrelated());
assertTrue(dbmd.supportsGroupByBeyondSelect()); // needs checking
JDBC2Tests.closeDB(con);
} catch(SQLException ex) { JDBC2Tests.closeDB(con);
fail(ex.getMessage()); }
} catch (SQLException ex)
} {
fail(ex.getMessage());
public void testDriverVersioning() { }
try { }
Connection con = JDBC2Tests.openDB();
assertTrue(con instanceof org.postgresql.Connection); public void testDBParams()
org.postgresql.Connection pc = (org.postgresql.Connection) con; {
try
DatabaseMetaData dbmd = con.getMetaData(); {
assertNotNull(dbmd); Connection con = JDBC2Tests.openDB();
assertTrue(dbmd.getDriverVersion().equals(pc.this_driver.getVersion())); DatabaseMetaData dbmd = con.getMetaData();
assertTrue(dbmd.getDriverMajorVersion()==pc.this_driver.getMajorVersion()); assertNotNull(dbmd);
assertTrue(dbmd.getDriverMinorVersion()==pc.this_driver.getMinorVersion());
assertTrue(dbmd.getURL().equals(JDBC2Tests.getURL()));
assertTrue(dbmd.getUserName().equals(JDBC2Tests.getUser()));
JDBC2Tests.closeDB(con);
} catch(SQLException ex) { JDBC2Tests.closeDB(con);
fail(ex.getMessage()); }
} 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,26 +5,30 @@ import junit.framework.TestCase;
import java.sql.*; 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 * Some simple tests based on problems reported by users. Hopefully these will
* help prevent previous problems from re-occuring ;-) * help prevent previous problems from re-occuring ;-)
* *
*/ */
public class DateTest extends TestCase { public class DateTest extends TestCase
{
private Connection con; private Connection con;
public DateTest(String name) { public DateTest(String name)
{
super(name); super(name);
} }
protected void setUp() throws Exception { protected void setUp() throws Exception
{
con = JDBC2Tests.openDB(); con = JDBC2Tests.openDB();
JDBC2Tests.createTable(con, "testdate", "dt date"); JDBC2Tests.createTable(con, "testdate", "dt date");
} }
protected void tearDown() throws Exception { protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testdate"); JDBC2Tests.dropTable(con, "testdate");
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} }
@@ -32,8 +36,10 @@ public class DateTest extends TestCase {
/** /**
* Tests the time methods in ResultSet * Tests the time methods in ResultSet
*/ */
public void testGetDate() { public void testGetDate()
try { {
try
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testdate", "'1950-02-07'"))); assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testdate", "'1950-02-07'")));
@@ -46,7 +52,9 @@ public class DateTest extends TestCase {
assertEquals(4, stmt.executeUpdate("DELETE FROM " + "testdate")); assertEquals(4, stmt.executeUpdate("DELETE FROM " + "testdate"));
stmt.close(); stmt.close();
} catch(Exception ex) { }
catch (Exception ex)
{
fail(ex.getMessage()); fail(ex.getMessage());
} }
} }
@@ -54,8 +62,10 @@ public class DateTest extends TestCase {
/** /**
* Tests the time methods in PreparedStatement * Tests the time methods in PreparedStatement
*/ */
public void testSetDate() { public void testSetDate()
try { {
try
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testdate", "?")); PreparedStatement ps = con.prepareStatement(JDBC2Tests.insertSQL("testdate", "?"));
@@ -78,7 +88,9 @@ public class DateTest extends TestCase {
assertEquals(4, stmt.executeUpdate("DELETE FROM testdate")); assertEquals(4, stmt.executeUpdate("DELETE FROM testdate"));
stmt.close(); stmt.close();
} catch(Exception ex) { }
catch (Exception ex)
{
fail(ex.getMessage()); 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 * 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(); Statement st = con.createStatement();
ResultSet rs; ResultSet rs;
java.sql.Date d; java.sql.Date d;
@@ -97,7 +110,7 @@ public class DateTest extends TestCase {
assertTrue(rs.next()); assertTrue(rs.next());
d = rs.getDate(1); d = rs.getDate(1);
assertNotNull(d); assertNotNull(d);
assertEquals(d, makeDate(1950, 2, 7)); assertEquals(d, makeDate(1950, 2, 7));
assertTrue(rs.next()); assertTrue(rs.next());
d = rs.getDate(1); d = rs.getDate(1);
@@ -120,7 +133,8 @@ public class DateTest extends TestCase {
st.close(); 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) + "-" + return java.sql.Date.valueOf(JDBC2Tests.fix(y, 4) + "-" +
JDBC2Tests.fix(m, 2) + "-" + JDBC2Tests.fix(m, 2) + "-" +
JDBC2Tests.fix(d, 2)); JDBC2Tests.fix(d, 2));

View File

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

View File

@@ -8,50 +8,55 @@ import java.io.*;
/** /**
* Tests for the Encoding class. * 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) { public EncodingTest(String name)
super(name); {
} super(name);
}
public void testCreation() throws Exception { public void testCreation() throws Exception
Encoding encoding; {
encoding = Encoding.getEncoding("UNICODE", null); Encoding encoding;
assertEquals("UTF", encoding.name().substring(0, 3).toUpperCase()); encoding = Encoding.getEncoding("UNICODE", null);
encoding = Encoding.getEncoding("SQL_ASCII", null); assertEquals("UTF", encoding.name().substring(0, 3).toUpperCase());
assertTrue(encoding.name().toUpperCase().indexOf("ASCII") != -1); encoding = Encoding.getEncoding("SQL_ASCII", null);
assertEquals("When encoding is unknown the default encoding should be used", assertTrue(encoding.name().toUpperCase().indexOf("ASCII") != -1);
Encoding.defaultEncoding(), assertEquals("When encoding is unknown the default encoding should be used",
Encoding.getEncoding("UNKNOWN", null)); Encoding.defaultEncoding(),
encoding = Encoding.getEncoding("SQL_ASCII", "utf-8"); Encoding.getEncoding("UNKNOWN", null));
assertTrue("Encoding passed in by the user should be preferred", encoding = Encoding.getEncoding("SQL_ASCII", "utf-8");
encoding.name().toUpperCase().indexOf("UTF") != -1); assertTrue("Encoding passed in by the user should be preferred",
} encoding.name().toUpperCase().indexOf("UTF") != -1);
}
public void testTransformations() throws Exception { public void testTransformations() throws Exception
Encoding encoding = Encoding.getEncoding("UNICODE", null); {
assertEquals("ab", encoding.decode(new byte[] { 97, 98 })); Encoding encoding = Encoding.getEncoding("UNICODE", null);
assertEquals("ab", encoding.decode(new byte[] { 97, 98 }));
assertEquals(2, encoding.encode("ab").length); assertEquals(2, encoding.encode("ab").length);
assertEquals(97, encoding.encode("a")[0]); assertEquals(97, encoding.encode("a")[0]);
assertEquals(98, encoding.encode("b")[0]); assertEquals(98, encoding.encode("b")[0]);
encoding = Encoding.defaultEncoding(); encoding = Encoding.defaultEncoding();
assertEquals("a".getBytes()[0], encoding.encode("a")[0]); assertEquals("a".getBytes()[0], encoding.encode("a")[0]);
assertEquals(new String(new byte[] { 97 }), assertEquals(new String(new byte[] { 97 }),
encoding.decode(new byte[] { 97 })); encoding.decode(new byte[] { 97 }));
} }
public void testReader() throws Exception { public void testReader() throws Exception
Encoding encoding = Encoding.getEncoding("SQL_ASCII", null); {
InputStream stream = new ByteArrayInputStream(new byte[] { 97, 98 }); Encoding encoding = Encoding.getEncoding("SQL_ASCII", null);
Reader reader = encoding.getDecodingReader(stream); InputStream stream = new ByteArrayInputStream(new byte[] { 97, 98 });
assertEquals(97, reader.read()); Reader reader = encoding.getDecodingReader(stream);
assertEquals(98, reader.read()); assertEquals(97, reader.read());
assertEquals(-1, reader.read()); assertEquals(98, reader.read());
} assertEquals( -1, reader.read());
}
} }

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,7 @@ import junit.framework.TestCase;
import java.sql.*; 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! * 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!!! * MUST PASS this TestCase!!!
* *
*/ */
public class TimestampTest extends TestCase { public class TimestampTest extends TestCase
{
private Connection con; private Connection con;
public TimestampTest(String name) { public TimestampTest(String name)
{
super(name); super(name);
} }
protected void setUp() throws Exception { protected void setUp() throws Exception
{
con = JDBC2Tests.openDB(); con = JDBC2Tests.openDB();
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
JDBC2Tests.createTable(con, "testtimestamp", "ts timestamp"); JDBC2Tests.createTable(con, "testtimestamp", "ts timestamp");
} }
protected void tearDown() throws Exception { protected void tearDown() throws Exception
{
JDBC2Tests.dropTable(con, "testtimestamp"); JDBC2Tests.dropTable(con, "testtimestamp");
JDBC2Tests.closeDB(con); JDBC2Tests.closeDB(con);
} }
@@ -36,19 +40,21 @@ public class TimestampTest extends TestCase {
/** /**
* Tests the time methods in ResultSet * Tests the time methods in ResultSet
*/ */
public void testGetTimestamp() { public void testGetTimestamp()
try { {
try
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp", 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", "'" + 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", assertEquals(1, stmt.executeUpdate(JDBC2Tests.insertSQL("testtimestamp",
"'1970-06-02 08:13:00'"))); "'1970-06-02 08:13:00'")));
// Fall through helper // Fall through helper
timestampTest(); timestampTest();
@@ -56,7 +62,9 @@ public class TimestampTest extends TestCase {
assertEquals(3, stmt.executeUpdate("DELETE FROM testtimestamp")); assertEquals(3, stmt.executeUpdate("DELETE FROM testtimestamp"));
stmt.close(); stmt.close();
} catch(Exception ex) { }
catch (Exception ex)
{
fail(ex.getMessage()); fail(ex.getMessage());
} }
} }
@@ -64,8 +72,10 @@ public class TimestampTest extends TestCase {
/** /**
* Tests the time methods in PreparedStatement * Tests the time methods in PreparedStatement
*/ */
public void testSetTimestamp() { public void testSetTimestamp()
try { {
try
{
Statement stmt = con.createStatement(); Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement(JDBC2Tests.insertSQL("testtimestamp", "?")); PreparedStatement pstmt = con.prepareStatement(JDBC2Tests.insertSQL("testtimestamp", "?"));
@@ -85,7 +95,9 @@ public class TimestampTest extends TestCase {
pstmt.close(); pstmt.close();
stmt.close(); stmt.close();
} catch(Exception ex) { }
catch (Exception ex)
{
fail(ex.getMessage()); fail(ex.getMessage());
} }
} }
@@ -93,7 +105,8 @@ public class TimestampTest extends TestCase {
/** /**
* Helper for the TimeTests. It tests what should be in the db * 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(); Statement stmt = con.createStatement();
ResultSet rs; ResultSet rs;
java.sql.Timestamp t; java.sql.Timestamp t;
@@ -122,13 +135,14 @@ public class TimestampTest extends TestCase {
stmt.close(); stmt.close();
} }
private java.sql.Timestamp getTimestamp(int y, int m, int d, int h, int mn, int se, int f) { 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) + "-" + return java.sql.Timestamp.valueOf(JDBC2Tests.fix(y, 4) + "-" +
JDBC2Tests.fix(d, 2) + " " + JDBC2Tests.fix(m, 2) + "-" +
JDBC2Tests.fix(h, 2) + ":" + JDBC2Tests.fix(d, 2) + " " +
JDBC2Tests.fix(h, 2) + ":" +
JDBC2Tests.fix(mn, 2) + ":" + JDBC2Tests.fix(mn, 2) + ":" +
JDBC2Tests.fix(se, 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. * A singleton class to translate JDBC driver messages in SQLException's.
*/ */
public class MessageTranslator { public class MessageTranslator
{
// The singleton instance. // The singleton instance.
private static MessageTranslator instance = null; private static MessageTranslator instance = null;
private ResourceBundle bundle; private ResourceBundle bundle;
private MessageTranslator() { private MessageTranslator()
try { {
try
{
bundle = ResourceBundle.getBundle("org.postgresql.errors"); bundle = ResourceBundle.getBundle("org.postgresql.errors");
} catch(MissingResourceException e) { }
catch (MissingResourceException e)
{
// translation files have not been installed. // translation files have not been installed.
bundle = null; bundle = null;
} }
} }
// Synchronized, otherwise multiple threads may perform the test and // Synchronized, otherwise multiple threads may perform the test and
// assign to the singleton instance simultaneously. // assign to the singleton instance simultaneously.
private synchronized final static MessageTranslator getInstance() { private synchronized final static MessageTranslator getInstance()
if (instance == null) { {
if (instance == null)
{
instance = new MessageTranslator(); instance = new MessageTranslator();
} }
return instance; return instance;
} }
public final static String translate(String id, Object[] args) { public final static String translate(String id, Object[] args)
{
MessageTranslator translator = MessageTranslator.getInstance(); MessageTranslator translator = MessageTranslator.getInstance();
return translator._translate(id, args); return translator._translate(id, args);
} }
private final String _translate(String id, Object[] args) { private final String _translate(String id, Object[] args)
{
String message; 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 // Now look up a localized message. If one is not found, then use
// the supplied message instead. // the supplied message instead.
try { try
{
message = bundle.getString(id); message = bundle.getString(id);
} catch(MissingResourceException e) { }
catch (MissingResourceException e)
{
message = id; message = id;
} }
} else { }
else
{
message = id; message = id;
} }
// Expand any arguments // Expand any arguments
if (args != null && message != null) { if (args != null && message != null)
message = MessageFormat.format(message,args); {
message = MessageFormat.format(message, args);
} }
return message; return message;
} }
} }

View File

@@ -5,82 +5,98 @@ import java.sql.*;
/** /**
* Converts to and from the postgresql bytea datatype used by the backend. * 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 * Converts a PG bytea string (i.e. the text representation
* of the bytea data type) into a java byte[] * of the bytea data type) into a java byte[]
*/ */
public static byte[] toBytes(String s) throws SQLException { public static byte[] toBytes(String s) throws SQLException
if(s==null) {
return null; if (s == null)
int slength = s.length(); return null;
byte[] buf = new byte[slength]; int slength = s.length();
int bufpos = 0; byte[] buf = new byte[slength];
int thebyte; int bufpos = 0;
char nextchar; int thebyte;
char secondchar; char nextchar;
for (int i = 0; i < slength; i++) { char secondchar;
nextchar = s.charAt(i); for (int i = 0; i < slength; i++)
if (nextchar == '\\') { {
secondchar = s.charAt(++i); nextchar = s.charAt(i);
if (secondchar == '\\') { if (nextchar == '\\')
//escaped \ {
buf[bufpos++] = (byte)'\\'; secondchar = s.charAt(++i);
} else { if (secondchar == '\\')
thebyte = (secondchar-48)*64 + (s.charAt(++i)-48)*8 + (s.charAt(++i)-48); {
if (thebyte > 127) //escaped \
thebyte -= 256; buf[bufpos++] = (byte)'\\';
buf[bufpos++] = (byte)thebyte; }
} else
} else { {
buf[bufpos++] = (byte)nextchar; thebyte = (secondchar - 48) * 64 + (s.charAt(++i) - 48) * 8 + (s.charAt(++i) - 48);
} if (thebyte > 127)
} thebyte -= 256;
byte[] l_return = new byte[bufpos]; buf[bufpos++] = (byte)thebyte;
System.arraycopy(buf,0,l_return,0,bufpos); }
return l_return; }
} 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 * Converts a java byte[] into a PG bytea string (i.e. the text
* representation of the bytea data type) * representation of the bytea data type)
*/ */
public static String toPGString(byte[] p_buf) throws SQLException public static String toPGString(byte[] p_buf) throws SQLException
{ {
if(p_buf==null) if (p_buf == null)
return null; return null;
StringBuffer l_strbuf = new StringBuffer(); StringBuffer l_strbuf = new StringBuffer();
for (int i = 0; i < p_buf.length; i++) { for (int i = 0; i < p_buf.length; i++)
int l_int = (int)p_buf[i]; {
if (l_int < 0) { int l_int = (int)p_buf[i];
l_int = 256 + l_int; if (l_int < 0)
} {
//we escape the same non-printable characters as the backend l_int = 256 + l_int;
//we must escape all 8bit characters otherwise when convering }
//from java unicode to the db character set we may end up with //we escape the same non-printable characters as the backend
//question marks if the character set is SQL_ASCII //we must escape all 8bit characters otherwise when convering
if (l_int < 040 || l_int > 0176) { //from java unicode to the db character set we may end up with
//escape charcter with the form \000, but need two \\ because of //question marks if the character set is SQL_ASCII
//the parser if (l_int < 040 || l_int > 0176)
l_strbuf.append("\\"); {
l_strbuf.append((char)(((l_int >> 6) & 0x3)+48)); //escape charcter with the form \000, but need two \\ because of
l_strbuf.append((char)(((l_int >> 3) & 0x7)+48)); //the parser
l_strbuf.append((char)((l_int & 0x07)+48)); l_strbuf.append("\\");
} else if (p_buf[i] == (byte)'\\') { l_strbuf.append((char)(((l_int >> 6) & 0x3) + 48));
//escape the backslash character as \\, but need four \\\\ because l_strbuf.append((char)(((l_int >> 3) & 0x7) + 48));
//of the parser l_strbuf.append((char)((l_int & 0x07) + 48));
l_strbuf.append("\\\\"); }
} else { else if (p_buf[i] == (byte)'\\')
//other characters are left alone {
l_strbuf.append((char)p_buf[i]); //escape the backslash character as \\, but need four \\\\ because
} //of the parser
} l_strbuf.append("\\\\");
return l_strbuf.toString(); }
} 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 * 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 * The value of the field
*/ */
public double val; public double val;
/** /**
* @param value of field * @param value of field
*/ */
public PGmoney(double value) { public PGmoney(double value)
this(); {
val = value; this();
} val = value;
}
/** /**
* This is called mainly from the other geometric types, when a * This is called mainly from the other geometric types, when a
* point is imbeded within their definition. * point is imbeded within their definition.
* *
* @param value Definition of this point in PostgreSQL's syntax * @param value Definition of this point in PostgreSQL's syntax
*/ */
public PGmoney(String value) throws SQLException public PGmoney(String value) throws SQLException
{ {
this(); this();
setValue(value); setValue(value);
} }
/** /**
* Required by the driver * Required by the driver
*/ */
public PGmoney() public PGmoney()
{ {
setType("money"); setType("money");
} }
/** /**
* @param s Definition of this point in PostgreSQL's syntax * @param s Definition of this point in PostgreSQL's syntax
* @exception SQLException on conversion failure * @exception SQLException on conversion failure
*/ */
public void setValue(String s) throws SQLException public void setValue(String s) throws SQLException
{ {
try { try
String s1; {
boolean negative; String s1;
boolean negative;
negative = (s.charAt(0) == '(') ; negative = (s.charAt(0) == '(') ;
// Remove any () (for negative) & currency symbol // Remove any () (for negative) & currency symbol
s1 = PGtokenizer.removePara(s).substring(1); s1 = PGtokenizer.removePara(s).substring(1);
// Strip out any , in currency // Strip out any , in currency
int pos = s1.indexOf(','); int pos = s1.indexOf(',');
while (pos != -1) { while (pos != -1)
s1 = s1.substring(0,pos) + s1.substring(pos +1); {
pos = s1.indexOf(','); s1 = s1.substring(0, pos) + s1.substring(pos + 1);
} pos = s1.indexOf(',');
}
val = Double.valueOf(s1).doubleValue(); val = Double.valueOf(s1).doubleValue();
val = negative ? -val : val; 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 * @param obj Object to compare with
* @return true if the two boxes are identical * @return true if the two boxes are identical
*/ */
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if(obj instanceof PGmoney) { if (obj instanceof PGmoney)
PGmoney p = (PGmoney)obj; {
return val == p.val; PGmoney p = (PGmoney)obj;
} return val == p.val;
return false; }
} return false;
}
/** /**
* This must be overidden to allow the object to be cloned * This must be overidden to allow the object to be cloned
*/ */
public Object clone() public Object clone()
{ {
return new PGmoney(val); return new PGmoney(val);
} }
/** /**
* @return the PGpoint in the syntax expected by org.postgresql * @return the PGpoint in the syntax expected by org.postgresql
*/ */
public String getValue() public String getValue()
{ {
if (val < 0) { if (val < 0)
return "-$" + (-val); {
} return "-$" + ( -val);
else { }
return "$"+val; else
} {
} return "$" + val;
}
}
} }

View File

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

View File

@@ -18,180 +18,186 @@ import java.util.*;
*/ */
public class PGtokenizer public class PGtokenizer
{ {
// Our tokens // Our tokens
protected Vector tokens; protected Vector tokens;
/** /**
* Create a tokeniser. * Create a tokeniser.
* *
* <p>We could have used StringTokenizer to do this, however, we needed to * <p>We could have used StringTokenizer to do this, however, we needed to
* handle nesting of '(' ')' '[' ']' '&lt;' and '&gt;' as these are used * handle nesting of '(' ')' '[' ']' '&lt;' and '&gt;' as these are used
* by the geometric data types. * by the geometric data types.
* *
* @param string containing tokens * @param string containing tokens
* @param delim single character to split the tokens * @param delim single character to split the tokens
*/ */
public PGtokenizer(String string,char delim) public PGtokenizer(String string, char delim)
{ {
tokenize(string,delim); tokenize(string, delim);
} }
/** /**
* This resets this tokenizer with a new string and/or delimiter. * This resets this tokenizer with a new string and/or delimiter.
* *
* @param string containing tokens * @param string containing tokens
* @param delim single character to split the tokens * @param delim single character to split the tokens
*/ */
public int tokenize(String string,char delim) public int tokenize(String string, char delim)
{ {
tokens = new Vector(); tokens = new Vector();
// nest holds how many levels we are in the current token. // 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. // 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 // The Geometric datatypes use this, because often a type may have others
// (usualls PGpoint) imbedded within a token. // (usualls PGpoint) imbedded within a token.
// //
// Peter 1998 Jan 6 - Added < and > to the nesting rules // Peter 1998 Jan 6 - Added < and > to the nesting rules
int nest=0,p,s; int nest = 0, p, s;
for(p=0,s=0;p<string.length();p++) { for (p = 0, s = 0;p < string.length();p++)
char c = string.charAt(p); {
char c = string.charAt(p);
// increase nesting if an open character is found // increase nesting if an open character is found
if(c == '(' || c == '[' || c == '<') if (c == '(' || c == '[' || c == '<')
nest++; nest++;
// decrease nesting if a close character is found // decrease nesting if a close character is found
if(c == ')' || c == ']' || c == '>') if (c == ')' || c == ']' || c == '>')
nest--; nest--;
if(nest==0 && c==delim) { if (nest == 0 && c == delim)
tokens.addElement(string.substring(s,p)); {
s=p+1; // +1 to skip the delimiter tokens.addElement(string.substring(s, p));
} s = p + 1; // +1 to skip the delimiter
}
} }
// Don't forget the last token ;-) // Don't forget the last token ;-)
if(s<string.length())
tokens.addElement(string.substring(s));
return tokens.size(); 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 number of tokens available
* @return The token value */
*/ public int getSize()
public String getToken(int n) {
{ return tokens.size();
return (String)tokens.elementAt(n); }
}
/** /**
* This returns a new tokenizer based on one of our tokens. * @param n Token number ( 0 ... getSize()-1 )
* * @return The token value
* The geometric datatypes use this to process nested tokens (usually */
* PGpoint). public String getToken(int n)
* {
* @param n Token number ( 0 ... getSize()-1 ) return (String)tokens.elementAt(n);
* @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 * This returns a new tokenizer based on one of our tokens.
* @param s Source string *
* @param l Leading string to remove * The geometric datatypes use this to process nested tokens (usually
* @param t Trailing string to remove * PGpoint).
* @return String without the lead/trailing strings *
*/ * @param n Token number ( 0 ... getSize()-1 )
public static String remove(String s,String l,String t) * @param delim The delimiter to use
{ * @return A new instance of PGtokenizer based on the token
if(s.startsWith(l)) s = s.substring(l.length()); */
if(s.endsWith(t)) s = s.substring(0,s.length()-t.length()); public PGtokenizer tokenizeToken(int n, char delim)
return s; {
} return new PGtokenizer(getToken(n), delim);
}
/** /**
* This removes the lead/trailing strings from all tokens * This removes the lead/trailing strings from a string
* @param l Leading string to remove * @param s Source string
* @param t Trailing string to remove * @param l Leading string to remove
*/ * @param t Trailing string to remove
public void remove(String l,String t) * @return String without the lead/trailing strings
{ */
for(int i=0;i<tokens.size();i++) { public static String remove(String s, String l, String t)
tokens.setElementAt(remove((String)tokens.elementAt(i),l,t),i); {
} if (s.startsWith(l))
} s = s.substring(l.length());
if (s.endsWith(t))
s = s.substring(0, s.length() - t.length());
return s;
}
/** /**
* Removes ( and ) from the beginning and end of a string * This removes the lead/trailing strings from all tokens
* @param s String to remove from * @param l Leading string to remove
* @return String without the ( or ) * @param t Trailing string to remove
*/ */
public static String removePara(String s) public void remove(String l, String t)
{ {
return remove(s,"(",")"); 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 all tokens * Removes ( and ) from the beginning and end of a string
* @return String without the ( or ) * @param s String to remove from
*/ * @return String without the ( or )
public void removePara() */
{ public static String removePara(String s)
remove("(",")"); {
} return remove(s, "(", ")");
}
/** /**
* Removes [ and ] from the beginning and end of a string * Removes ( and ) from the beginning and end of all tokens
* @param s String to remove from * @return String without the ( or )
* @return String without the [ or ] */
*/ public void removePara()
public static String removeBox(String s) {
{ remove("(", ")");
return remove(s,"[","]"); }
}
/** /**
* Removes [ and ] from the beginning and end of all tokens * Removes [ and ] from the beginning and end of a string
* @return String without the [ or ] * @param s String to remove from
*/ * @return String without the [ or ]
public void removeBox() */
{ public static String removeBox(String s)
remove("[","]"); {
} return remove(s, "[", "]");
}
/** /**
* Removes &lt; and &gt; from the beginning and end of a string * Removes [ and ] from the beginning and end of all tokens
* @param s String to remove from * @return String without the [ or ]
* @return String without the &lt; or &gt; */
*/ public void removeBox()
public static String removeAngle(String s) {
{ remove("[", "]");
return remove(s,"<",">"); }
}
/** /**
* Removes &lt; and &gt; from the beginning and end of all tokens * Removes &lt; and &gt; from the beginning and end of a string
* @return String without the &lt; or &gt; * @param s String to remove from
*/ * @return String without the &lt; or &gt;
public void removeAngle() */
{ public static String removeAngle(String s)
remove("<",">"); {
} 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 public class PSQLException extends SQLException
{ {
private String message; private String message;
/** /**
* This provides the same functionality to SQLException * This provides the same functionality to SQLException
* @param error Error string * @param error Error string
*/ */
public PSQLException(String error) { public PSQLException(String error)
super(); {
translate(error,null); 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);
} }
/** /**
* Overides Throwable * A more generic entry point.
*/ * @param error Error string or standard message id
public String getLocalizedMessage() * @param args Array of arguments
{ */
return message; public PSQLException(String error, Object[] args)
} {
//super();
translate(error, args);
}
/** /**
* Overides Throwable * Helper version for 1 arg
*/ */
public String getMessage() public PSQLException(String error, Object arg)
{ {
return message; super();
} Object[] argv = new Object[1];
argv[0] = arg;
translate(error, argv);
}
/** /**
* Overides Object * Helper version for 1 arg. This is used for debug purposes only with
*/ * some unusual Exception's. It allows the originiating Exceptions stack
public String toString() * trace to be returned.
{ */
return message; 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 * a table to be used as a data type. However, Postgres support of
* this feature is incomplete. The basic ability to create and use * this feature is incomplete. The basic ability to create and use
* a table as a field type in another table exists:<br> * a table as a field type in another table exists:<br>
* CREATE TABLE myclass( var1 TEXT, var2 INTEGER );<br> * CREATE TABLE myclass( var1 TEXT, var2 INTEGER );<br>
* CREATE TABLE othertable( field1 TEXT, field2 myclass );<br> * CREATE TABLE othertable( field1 TEXT, field2 myclass );<br>
* INSERT INTO myclass VALUES ('Hello', 1);<br> * INSERT INTO myclass VALUES ('Hello', 1);<br>
* INSERT INTO othertable VALUES ('World', xxxx::myclass);<br> * INSERT INTO othertable VALUES ('World', xxxx::myclass);<br>
* where xxxx is the OID of a row in myclass<br> * where xxxx is the OID of a row in myclass<br>
* This lets othertable reference a myclass instance but * This lets othertable reference a myclass instance but
* the support to actually make any use of the myclass data type * the support to actually make any use of the myclass data type
* is not there. For instance, you cannot compare the myclass field * is not there. For instance, you cannot compare the myclass field
@@ -33,13 +33,13 @@ import java.sql.*;
* syntax appears to work.<p> * syntax appears to work.<p>
* *
* Queries like:<br> * 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 * will not work but were suggested in the original Postgres
* design documents.<p> * design documents.<p>
* Because support is incomplete for table data types, tables * Because support is incomplete for table data types, tables
* such as othertable that hold java instances should also * such as othertable that hold java instances should also
* hold an oid field for the same java instance:<br> * 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 * This oid-type field would be set with setInt() immediately after
* setting the myclass-type field with setObject(). The order of these * setting the myclass-type field with setObject(). The order of these
* set calls matters since the oid is not available until after * set calls matters since the oid is not available until after
@@ -107,230 +107,271 @@ import java.sql.*;
*/ */
public class Serialize public class Serialize
{ {
// This is the connection that the instance refers to // This is the connection that the instance refers to
protected org.postgresql.Connection conn; protected org.postgresql.Connection conn;
// This is the table name // This is the table name
protected String tableName; protected String tableName;
// This is the class name // This is the class name
protected String className; protected String className;
// This is the Class for this serialzed object // This is the Class for this serialzed object
protected Class ourClass; protected Class ourClass;
/** /**
* This creates an instance that can be used to serialize or deserialize * This creates an instance that can be used to serialize or deserialize
* a Java object from a PostgreSQL table. * a Java object from a PostgreSQL table.
*/ */
public Serialize(org.postgresql.Connection c,String type) throws SQLException public Serialize(org.postgresql.Connection c, String type) throws SQLException
{ {
try { try
conn = c; {
DriverManager.println("Serialize: initializing instance for type: " + type); conn = c;
tableName = toPostgreSQL(type); DriverManager.println("Serialize: initializing instance for type: " + type);
className = type; tableName = toPostgreSQL(type);
ourClass = Class.forName(className); className = type;
} catch(ClassNotFoundException cnfe) { ourClass = Class.forName(className);
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(); 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"); * Constructor when Object is passed in
throw new PSQLException("postgresql.serial.table",type); */
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 * Constructor when Class is passed in
*/ */
public Serialize(org.postgresql.Connection c,Object o) throws SQLException public Serialize(org.postgresql.Connection c, Class cls) throws SQLException
{ {
this(c, o.getClass().getName()); this(c, cls.getName());
} }
/** /**
* Constructor when Class is passed in * This fetches an object from a table, given it's OID
*/ * @param oid The oid of the object
public Serialize(org.postgresql.Connection c, Class cls) throws SQLException * @return Object relating to oid
{ * @exception SQLException on error
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
*/
public Object fetch(int oid) throws SQLException public Object fetch(int oid) throws SQLException
{ {
try { try
{
DriverManager.println("Serialize.fetch: " + "attempting to instantiate object of type: " + ourClass.getName() ); 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() ); DriverManager.println("Serialize.fetch: " + "instantiated object of type: " + ourClass.getName() );
// NB: we use java.lang.reflect here to prevent confusion with // NB: we use java.lang.reflect here to prevent confusion with
// the org.postgresql.Field // the org.postgresql.Field
// used getFields to get only public fields. We have no way to set values // used getFields to get only public fields. We have no way to set values
// for other declarations. Maybe look for setFieldName() methods? // for other declarations. Maybe look for setFieldName() methods?
java.lang.reflect.Field f[] = ourClass.getFields(); java.lang.reflect.Field f[] = ourClass.getFields();
boolean hasOID=false; boolean hasOID = false;
int oidFIELD=-1; int oidFIELD = -1;
StringBuffer sb = new StringBuffer("select"); StringBuffer sb = new StringBuffer("select");
char sep=' '; char sep = ' ';
// build a select for the fields. Look for the oid field to use in the where // build a select for the fields. Look for the oid field to use in the where
for(int i=0;i<f.length;i++) { for (int i = 0;i < f.length;i++)
{
String n = f[i].getName(); String n = f[i].getName();
if(n.equals("oid")) { if (n.equals("oid"))
hasOID=true; {
oidFIELD=i; hasOID = true;
oidFIELD = i;
} }
sb.append(sep); sb.append(sep);
sb.append(n); sb.append(n);
sep=','; sep = ',';
} }
sb.append(" from "); sb.append(" from ");
sb.append(tableName); sb.append(tableName);
sb.append(" where oid="); sb.append(" where oid=");
sb.append(oid); sb.append(oid);
DriverManager.println("Serialize.fetch: " + sb.toString()); DriverManager.println("Serialize.fetch: " + sb.toString());
ResultSet rs = conn.ExecSQL(sb.toString()); ResultSet rs = conn.ExecSQL(sb.toString());
if(rs!=null) { if (rs != null)
if(rs.next()) { {
for(int i=0;i<f.length;i++) { if (rs.next())
if( !Modifier.isFinal(f[i].getModifiers()) ) { {
if( f[i].getType().getName().equals("short") ) for (int i = 0;i < f.length;i++)
f[i].setShort(obj, rs.getShort(i+1)); {
else if( f[i].getType().getName().equals("char") ) if ( !Modifier.isFinal(f[i].getModifiers()) )
f[i].setChar(obj, rs.getString(i+1).toCharArray()[0]); {
else if( f[i].getType().getName().equals("byte")) if ( f[i].getType().getName().equals("short") )
f[i].setByte(obj, rs.getByte(i+1)); f[i].setShort(obj, rs.getShort(i + 1));
else if( f[i].getType().getName().equals("boolean") ) { 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 // booleans come out of pgsql as a t or an f
if( rs.getString(i+1).equals("t") ) f[i].setBoolean(obj, true); if ( rs.getString(i + 1).equals("t") )
else f[i].setBoolean(obj, false); f[i].setBoolean(obj, true);
} else f[i].set(obj,rs.getObject(i+1)); else
f[i].setBoolean(obj, false);
}
else
f[i].set(obj, rs.getObject(i + 1));
} }
} }
} }
rs.close(); 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()); throw new SQLException(iae.toString());
} catch(InstantiationException ie) { }
catch (InstantiationException ie)
{
throw new SQLException(ie.toString()); throw new SQLException(ie.toString());
} }
} }
/** /**
* This stores an object into a table, returning it's OID.<p> * 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 * 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. * 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 * 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 of OID will be set in the object. This enables an object's
* value in the database to be updateable. * value in the database to be updateable.
* *
* If the object has no int called OID, then the object is stored. However * 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 * 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 * state will be appended to the table, and will not overwrite the old
* entries. * entries.
* *
* @param o Object to store (must implement Serializable) * @param o Object to store (must implement Serializable)
* @return oid of stored object * @return oid of stored object
* @exception SQLException on error * @exception SQLException on error
*/ */
public int store(Object o) throws SQLException public int store(Object o) throws SQLException
{ {
try { try
// NB: we use java.lang.reflect here to prevent confusion with {
// NB: we use java.lang.reflect here to prevent confusion with
// the org.postgresql.Field // the org.postgresql.Field
// don't save private fields since we would not be able to fetch them // don't save private fields since we would not be able to fetch them
java.lang.reflect.Field f[] = ourClass.getFields(); java.lang.reflect.Field f[] = ourClass.getFields();
boolean hasOID=false; boolean hasOID = false;
int oidFIELD=-1; int oidFIELD = -1;
boolean update=false; boolean update = false;
// Find out if we have an oid value // 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(); String n = f[i].getName();
if(n.equals("oid")) { if (n.equals("oid"))
hasOID=true; {
oidFIELD=i; hasOID = true;
oidFIELD = i;
// Do update if oid != 0 // Do update if oid != 0
update = f[i].getInt(o) > 0; update = f[i].getInt(o) > 0;
} }
} }
StringBuffer sb = new StringBuffer(update?"update "+tableName+" set":"insert into "+tableName+" "); StringBuffer sb = new StringBuffer(update ? "update " + tableName + " set" : "insert into " + tableName + " ");
char sep=update?' ':'('; char sep = update ? ' ' : '(';
for(int i=0;i<f.length;i++) { for (int i = 0;i < f.length;i++)
{
String n = f[i].getName(); String n = f[i].getName();
// oid cannot be updated! // oid cannot be updated!
if( n.equals("oid") ) continue; if ( n.equals("oid") )
continue;
sb.append(sep); sb.append(sep);
sep=','; sep = ',';
sb.append(n); sb.append(n);
if(update) { if (update)
{
sb.append('='); sb.append('=');
// handle unset values // handle unset values
if (f[i].get(o) == null) if (f[i].get(o) == null)
sb.append("null"); sb.append("null");
else if( else if (
f[i].getType().getName().equals("java.lang.String") f[i].getType().getName().equals("java.lang.String")
|| f[i].getType().getName().equals("char") ) { || f[i].getType().getName().equals("char") )
{
sb.append('\''); sb.append('\'');
// don't allow single qoutes or newlines in the string // don't allow single qoutes or newlines in the string
sb.append(fixString(f[i].get(o).toString())); sb.append(fixString(f[i].get(o).toString()));
sb.append('\''); 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 "); sb.append(") values ");
sep='('; sep = '(';
for(int i=0;i<f.length;i++) { for (int i = 0;i < f.length;i++)
{
String n = f[i].getName(); String n = f[i].getName();
// oid cannot be set! // oid cannot be set!
if( n.equals("oid") ) continue; if ( n.equals("oid") )
continue;
sb.append(sep); sb.append(sep);
sep=','; sep = ',';
// handle unset values // handle unset values
if (f[i].get(o) == null) sb.append("null"); if (f[i].get(o) == null)
else if( sb.append("null");
f[i].getType().getName().equals("java.lang.String") else if (
|| f[i].getType().getName().equals("char")) { f[i].getType().getName().equals("java.lang.String")
|| f[i].getType().getName().equals("char"))
{
sb.append('\''); sb.append('\'');
// don't allow single quotes or newlines in the string // don't allow single quotes or newlines in the string
sb.append(fixString(f[i].get(o).toString())); sb.append(fixString(f[i].get(o).toString()));
sb.append('\''); sb.append('\'');
} else sb.append(f[i].get(o).toString()); }
else
sb.append(f[i].get(o).toString());
} }
sb.append(')'); sb.append(')');
} }
@@ -339,23 +380,30 @@ public class Serialize
org.postgresql.ResultSet rs = (org.postgresql.ResultSet) conn.ExecSQL(sb.toString()); org.postgresql.ResultSet rs = (org.postgresql.ResultSet) conn.ExecSQL(sb.toString());
// fetch the OID for returning // fetch the OID for returning
if(update) { if (update)
{
// object has oid already, so return it // object has oid already, so return it
if(rs!=null) rs.close(); if (rs != null)
rs.close();
return f[oidFIELD].getInt(o); return f[oidFIELD].getInt(o);
} else { }
else
{
// new record inserted has new oid; rs should be not null // new record inserted has new oid; rs should be not null
int newOID = ((org.postgresql.ResultSet)rs).getInsertedOID(); int newOID = ((org.postgresql.ResultSet)rs).getInsertedOID();
rs.close(); rs.close();
// update the java object's oid field if it has the oid field // 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 // new object stored, return newly inserted oid
return newOID; return newOID;
} }
} catch(IllegalAccessException iae) { }
catch (IllegalAccessException iae)
{
throw new SQLException(iae.toString()); throw new SQLException(iae.toString());
} }
} }
/** /**
@@ -363,106 +411,121 @@ public class Serialize
* Otherwise, postgres will bomb on the single quote and remove the * Otherwise, postgres will bomb on the single quote and remove the
* the backslashes. * the backslashes.
*/ */
private String fixString(String s) { private String fixString(String s)
{
int idx = -1; int idx = -1;
// handle null // handle null
if (s == null) if (s == null)
return ""; return "";
// if the string has single quotes in it escape them as '' // if the string has single quotes in it escape them as ''
if ((idx = s.indexOf("'")) > -1) { if ((idx = s.indexOf("'")) > -1)
StringBuffer buf = new StringBuffer(); {
StringTokenizer tok = new StringTokenizer(s, "'"); StringBuffer buf = new StringBuffer();
// handle quote as 1St charater StringTokenizer tok = new StringTokenizer(s, "'");
if (idx > 0) buf.append(tok.nextToken()); // handle quote as 1St charater
if (idx > 0)
buf.append(tok.nextToken());
while(tok.hasMoreTokens()) while (tok.hasMoreTokens())
buf.append("''").append(tok.nextToken()); buf.append("''").append(tok.nextToken());
s = buf.toString(); s = buf.toString();
} }
// if the string has backslashes in it escape them them as \\ // if the string has backslashes in it escape them them as \\
if ((idx = s.indexOf("\\")) > -1) { if ((idx = s.indexOf("\\")) > -1)
StringBuffer buf = new StringBuffer(); {
StringTokenizer tok = new StringTokenizer(s, "\\"); StringBuffer buf = new StringBuffer();
if (idx > 0) buf.append(tok.nextToken()); StringTokenizer tok = new StringTokenizer(s, "\\");
if (idx > 0)
buf.append(tok.nextToken());
while(tok.hasMoreTokens()) while (tok.hasMoreTokens())
buf.append("\\\\").append(tok.nextToken()); 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 * 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 * a Serializable Java Object. It should be used before serializing any
* objects. * objects.
* @param c Connection to database * @param c Connection to database
* @param o Object to base table on * @param o Object to base table on
* @exception SQLException on error * @exception SQLException on error
*/ */
public static void create(org.postgresql.Connection con,Object o) throws SQLException 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
{ {
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 // See if the table exists
String tableName = toPostgreSQL(c.getName()); String tableName = toPostgreSQL(c.getName());
ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '"+tableName+"'"); ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '" + tableName + "'");
if( rs.next() ) { if ( rs.next() )
DriverManager.println("Serialize.create: table "+tableName+" exists, skipping"); {
DriverManager.println("Serialize.create: table " + tableName + " exists, skipping");
rs.close(); rs.close();
return; return ;
} }
// else table not found, so create it // else table not found, so create it
DriverManager.println("Serialize.create: table " + tableName + " not found, creating" ); 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 "); StringBuffer sb = new StringBuffer("create table ");
sb.append(tableName); sb.append(tableName);
char sep='('; char sep = '(';
// java.lang.reflect.Field[] fields = c.getDeclaredFields(); // java.lang.reflect.Field[] fields = c.getDeclaredFields();
// Only store public fields, another limitation! // Only store public fields, another limitation!
java.lang.reflect.Field[] fields = c.getFields(); java.lang.reflect.Field[] fields = c.getFields();
for(int i=0;i<fields.length;i++) { for (int i = 0;i < fields.length;i++)
{
Class type = fields[i].getType(); Class type = fields[i].getType();
// oid is a special field // oid is a special field
if(!fields[i].getName().equals("oid")) { if (!fields[i].getName().equals("oid"))
{
sb.append(sep); sb.append(sep);
sb.append(fields[i].getName()); sb.append(fields[i].getName());
sb.append(' '); sb.append(' ');
sep=','; sep = ',';
if(type.isArray()) { if (type.isArray())
{
// array handling // array handling
} else { }
else
{
// convert the java type to org.postgresql, recursing if a class // convert the java type to org.postgresql, recursing if a class
// is found // is found
String n = type.getName(); String n = type.getName();
int j=0; int j = 0;
for(;j<tp.length && !tp[j][0].equals(n);j++); for (;j < tp.length && !tp[j][0].equals(n);j++)
if(j<tp.length) sb.append(tp[j][1]); ;
else { if (j < tp.length)
sb.append(tp[j][1]);
else
{
create(con, type); create(con, type);
sb.append(toPostgreSQL(n)); sb.append(toPostgreSQL(n));
} }
@@ -476,71 +539,72 @@ public class Serialize
con.ExecSQL(sb.toString()); con.ExecSQL(sb.toString());
} }
// This is used to translate between Java primitives and PostgreSQL types. // This is used to translate between Java primitives and PostgreSQL types.
private static final String tp[][] = { private static final String tp[][] = {
// {"boolean", "int1"}, // {"boolean", "int1"},
{"boolean", "bool"}, {"boolean", "bool"},
{"double", "float8"}, {"double", "float8"},
{"float", "float4"}, {"float", "float4"},
{"int", "int4"}, {"int", "int4"},
// {"long", "int4"}, // {"long", "int4"},
{"long", "int8"}, {"long", "int8"},
{"short", "int2"}, {"short", "int2"},
{"java.lang.String", "text"}, {"java.lang.String", "text"},
{"java.lang.Integer", "int4"}, {"java.lang.Integer", "int4"},
{"java.lang.Float", "float4"}, {"java.lang.Float", "float4"},
{"java.lang.Double", "float8"}, {"java.lang.Double", "float8"},
{"java.lang.Short", "int2"}, {"java.lang.Short", "int2"},
{"char", "char"}, {"char", "char"},
{"byte", "int2"} {"byte", "int2"}
}; };
/** /**
* This converts a Java Class name to a org.postgresql table, by replacing . with * This converts a Java Class name to a org.postgresql table, by replacing . with
* _<p> * _<p>
* *
* Because of this, a Class name may not have _ in the name.<p> * Because of this, a Class name may not have _ in the name.<p>
* Another limitation, is that the entire class name (including packages) * Another limitation, is that the entire class name (including packages)
* cannot be longer than 32 characters (a limit forced by PostgreSQL). * cannot be longer than 32 characters (a limit forced by PostgreSQL).
* *
* @param name Class name * @param name Class name
* @return PostgreSQL table name * @return PostgreSQL table name
* @exception SQLException on error * @exception SQLException on error
*/ */
public static String toPostgreSQL(String name) throws SQLException public static String toPostgreSQL(String name) throws SQLException
{ {
name = name.toLowerCase(); name = name.toLowerCase();
if(name.indexOf("_")>-1) if (name.indexOf("_") > -1)
throw new PSQLException("postgresql.serial.underscore"); throw new PSQLException("postgresql.serial.underscore");
// Postgres table names can only be 32 character long. // Postgres table names can only be 32 character long.
// Reserve 1 char, so allow only up to 31 chars. // Reserve 1 char, so allow only up to 31 chars.
// If the full class name with package is too long // If the full class name with package is too long
// then just use the class name. If the class name is // then just use the class name. If the class name is
// too long throw an exception. // too long throw an exception.
// //
if( name.length() > 31 ) { if ( name.length() > 31 )
name = name.substring(name.lastIndexOf(".") + 1); {
if( name.length() >31 ) name = name.substring(name.lastIndexOf(".") + 1);
throw new PSQLException("postgresql.serial.namelength",name,new Integer(name.length())); if ( name.length() > 31 )
} throw new PSQLException("postgresql.serial.namelength", name, new Integer(name.length()));
return name.replace('.','_'); }
} return name.replace('.', '_');
}
/** /**
* This converts a org.postgresql table to a Java Class name, by replacing _ with * This converts a org.postgresql table to a Java Class name, by replacing _ with
* .<p> * .<p>
* *
* @param name PostgreSQL table name * @param name PostgreSQL table name
* @return Class name * @return Class name
* @exception SQLException on error * @exception SQLException on error
*/ */
public static String toClassName(String name) throws SQLException public static String toClassName(String name) throws SQLException
{ {
name = name.toLowerCase(); name = name.toLowerCase();
return name.replace('_','.'); 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 * Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided * ("Software"), with or without modification, are permitted provided
* that the following conditions are met: * that the following conditions are met:
* *
* 1. Redistributions of source code must retain copyright * 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a * statements and notices. Redistributions must also contain a
* copy of this document. * copy of this document.
* *
* 2. Redistributions in binary form must reproduce the * 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the * above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other * following disclaimer in the documentation and/or other
* materials provided with the distribution. * materials provided with the distribution.
* *
* 3. The name "Exolab" must not be used to endorse or promote * 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written * products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission, * permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org. * please contact info@exolab.org.
* *
* 4. Products derived from this Software may not be called "Exolab" * 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written * nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered * permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies. * trademark of Exoffice Technologies.
* *
* 5. Due credit should be given to the Exolab Project * 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/). * (http://www.exolab.org/).
* *
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved. * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
* *
* $Id: ClientConnection.java,v 1.1 2000/04/17 20:07:55 peter Exp $ * $Id: ClientConnection.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/ */
package org.postgresql.xa; package org.postgresql.xa;
@@ -68,425 +68,497 @@ import java.sql.*;
* @see Connection * @see Connection
*/ */
final class ClientConnection final class ClientConnection
implements Connection implements Connection
{ {
/** /**
* The pooled XA connection that created this client connection * The pooled XA connection that created this client connection
* and should be used to report closure and fatal errors. * and should be used to report closure and fatal errors.
*/ */
private XAConnectionImpl _xaConn; private XAConnectionImpl _xaConn;
/** /**
* This identifier was handed on to use when we were created by * This identifier was handed on to use when we were created by
* {@link XAConnection}. If since then the XA connection was asked * {@link XAConnection}. If since then the XA connection was asked
* to create another connection or was closed, our identifier will * to create another connection or was closed, our identifier will
* no longer be valid and any call to {@link * no longer be valid and any call to {@link
* XAConnection#getUnderlying} will throw an exception. Previously, * XAConnection#getUnderlying} will throw an exception. Previously,
* the XA connection would hold a reference to use and tell us to * the XA connection would hold a reference to use and tell us to
* terminate, but that prevented ClientConnection from being * terminate, but that prevented ClientConnection from being
* finalized. * finalized.
*/ */
private int _clientId; private int _clientId;
/** /**
* Construct a new client connection to provide access to the * Construct a new client connection to provide access to the
* underlying JDBC connection (<tt>underlying</tt>) on behalf of * underlying JDBC connection (<tt>underlying</tt>) on behalf of
* an XA/pooled connection (<tt>xaConn<tt/>). The pooled connection * an XA/pooled connection (<tt>xaConn<tt/>). The pooled connection
* is required to notify of connection closure and fatal errors. * is required to notify of connection closure and fatal errors.
* *
* @param xaConn The XA/pooled connection that created this * @param xaConn The XA/pooled connection that created this
* client connection * client connection
* @param clientId A unique identifier handed to us by * @param clientId A unique identifier handed to us by
* {@link XAConnection} * {@link XAConnection}
* @param underlying The underlying JDBC connection * @param underlying The underlying JDBC connection
*/ */
ClientConnection( XAConnectionImpl xaConn, int clientId ) ClientConnection( XAConnectionImpl xaConn, int clientId )
{ {
_xaConn = xaConn; _xaConn = xaConn;
_clientId = clientId; _clientId = clientId;
}
public Statement createStatement()
throws SQLException
{
try {
return getUnderlying().createStatement();
} catch ( SQLException except ) {
notifyError( except );
throw except;
} }
}
public Statement createStatement( int resultSetType, int resultSetConcurrency ) public Statement createStatement()
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 throws SQLException
{ {
if ( _xaConn == null ) try
return; {
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, public Statement createStatement( int resultSetType, int resultSetConcurrency )
// held until the transaction terminates, etc is not throws SQLException
// a concern of us. {
_xaConn.notifyClose( _clientId ); 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; _xaConn = null;
} }
*/
public synchronized boolean isClosed() protected void finalize()
{
// 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()
throws Throwable throws Throwable
{ {
close(); close();
}
public String toString()
{
try {
return getUnderlying().toString();
} catch ( SQLException except ) {
return "XAConnection: Connection closed";
} }
}
/** public String toString()
* Called when an exception is thrown by the underlying connection {
* to determine whether the exception is critical or not. If the try
* exception is critical, notifies the XA connection to forget {
* about this connection. return getUnderlying().toString();
* }
* @param except The exception thrown by the underlying catch ( SQLException except )
* connection {
*/ return "XAConnection: Connection closed";
void notifyError( SQLException except ) }
{ }
if ( _xaConn != null )
_xaConn.notifyError( _clientId, except );
} /**
* 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
* Called to retrieve the underlying JDBC connection. Actual JDBC * about this connection.
* operations are performed against it. Throws an SQLException if *
* this connection has been closed. * @param except The exception thrown by the underlying
*/ * connection
Connection getUnderlying() */
throws SQLException void notifyError( SQLException except )
{ {
if ( _xaConn == null ) if ( _xaConn != null )
throw new SQLException( "This connection has been closed" ); _xaConn.notifyError( _clientId, except );
// 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 ); * Called to retrieve the underlying JDBC connection. Actual JDBC
} catch ( SQLException except ) { * operations are performed against it. Throws an SQLException if
_xaConn = null; * this connection has been closed.
throw except; */
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 * Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided * ("Software"), with or without modification, are permitted provided
* that the following conditions are met: * that the following conditions are met:
* *
* 1. Redistributions of source code must retain copyright * 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a * statements and notices. Redistributions must also contain a
* copy of this document. * copy of this document.
* *
* 2. Redistributions in binary form must reproduce the * 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the * above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other * following disclaimer in the documentation and/or other
* materials provided with the distribution. * materials provided with the distribution.
* *
* 3. The name "Exolab" must not be used to endorse or promote * 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written * products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission, * permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org. * please contact info@exolab.org.
* *
* 4. Products derived from this Software may not be called "Exolab" * 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written * nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered * permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies. * trademark of Exoffice Technologies.
* *
* 5. Due credit should be given to the Exolab Project * 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/). * (http://www.exolab.org/).
* *
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved. * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
* *
* $Id: TwoPhaseConnection.java,v 1.1 2000/04/17 20:07:55 peter Exp $ * $Id: TwoPhaseConnection.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/ */
package org.postgresql.xa; package org.postgresql.xa;
@@ -79,38 +79,38 @@ public interface TwoPhaseConnection
{ {
/** /**
* Enables or disables transaction demarcation through SQL commit * Enables or disables transaction demarcation through SQL commit
* and rollback. When the connection falls under control of * and rollback. When the connection falls under control of
* {@link XAConnection}, SQL commit/rollback commands will be * {@link XAConnection}, SQL commit/rollback commands will be
* disabled to prevent direct transaction demarcation. * disabled to prevent direct transaction demarcation.
* *
* @param flag True to enable SQL transactions (the default) * @param flag True to enable SQL transactions (the default)
*/ */
public void enableSQLTransactions( boolean flag ); public void enableSQLTransactions( boolean flag );
/** /**
* Called to prepare the transaction for commit. Returns true if * Called to prepare the transaction for commit. Returns true if
* the transaction is prepared, false if the transaction is * the transaction is prepared, false if the transaction is
* read-only. If the transaction has been marked for rollback, * read-only. If the transaction has been marked for rollback,
* throws a {@link RollbackException}. * throws a {@link RollbackException}.
* *
* @return True if can commit, false if read-only * @return True if can commit, false if read-only
* @throws SQLException If transaction has been marked for * @throws SQLException If transaction has been marked for
* rollback or cannot commit for any other reason * rollback or cannot commit for any other reason
*/ */
public boolean prepare() public boolean prepare()
throws SQLException; throws SQLException;
/** /**
* Returns true if the error issued by this connection is a * Returns true if the error issued by this connection is a
* critical error and the connection should be terminated. * critical error and the connection should be terminated.
* *
* @param except The exception thrown by this connection * @param except The exception thrown by this connection
*/ */
public boolean isCriticalError( SQLException except ); public boolean isCriticalError( SQLException except );
} }

View File

@@ -1,47 +1,47 @@
/** /**
* Redistribution and use of this software and associated documentation * Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided * ("Software"), with or without modification, are permitted provided
* that the following conditions are met: * that the following conditions are met:
* *
* 1. Redistributions of source code must retain copyright * 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a * statements and notices. Redistributions must also contain a
* copy of this document. * copy of this document.
* *
* 2. Redistributions in binary form must reproduce the * 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the * above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other * following disclaimer in the documentation and/or other
* materials provided with the distribution. * materials provided with the distribution.
* *
* 3. The name "Exolab" must not be used to endorse or promote * 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written * products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission, * permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org. * please contact info@exolab.org.
* *
* 4. Products derived from this Software may not be called "Exolab" * 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written * nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered * permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies. * trademark of Exoffice Technologies.
* *
* 5. Due credit should be given to the Exolab Project * 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/). * (http://www.exolab.org/).
* *
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved. * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
* *
* $Id: TxConnection.java,v 1.1 2000/04/17 20:07:56 peter Exp $ * $Id: TxConnection.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/ */
package org.postgresql.xa; package org.postgresql.xa;
@@ -68,61 +68,61 @@ final class TxConnection
{ {
/** /**
* The Xid of the transactions. Connections that are not * The Xid of the transactions. Connections that are not
* associated with a transaction are not represented here. * associated with a transaction are not represented here.
*/ */
Xid xid; Xid xid;
/** /**
* Holds the underlying JDBC connection for as long as this * Holds the underlying JDBC connection for as long as this
* connection is useable. If the connection has been rolled back, * connection is useable. If the connection has been rolled back,
* timed out or had any other error, this variable will null * timed out or had any other error, this variable will null
* and the connection is considered failed. * and the connection is considered failed.
*/ */
Connection conn; Connection conn;
/** /**
* Indicates the clock time (in ms) when the transaction should * Indicates the clock time (in ms) when the transaction should
* time out. The transaction times out when * time out. The transaction times out when
* <tt>System.currentTimeMillis() > timeout</tt>. * <tt>System.currentTimeMillis() > timeout</tt>.
*/ */
long timeout; long timeout;
/** /**
* Indicates the clock time (in ms) when the transaction started. * Indicates the clock time (in ms) when the transaction started.
*/ */
long started; long started;
/** /**
* Reference counter indicates how many XA connections share this * Reference counter indicates how many XA connections share this
* underlying connection and transaction. Always one or more. * underlying connection and transaction. Always one or more.
*/ */
int count; int count;
/** /**
* True if the transaction has failed due to time out. * True if the transaction has failed due to time out.
*/ */
boolean timedOut; boolean timedOut;
/** /**
* True if the transaction has already been prepared. * True if the transaction has already been prepared.
*/ */
boolean prepared; boolean prepared;
/** /**
* True if the transaction has been prepared and found out to be * True if the transaction has been prepared and found out to be
* read-only. Read-only transactions do not require commit/rollback. * read-only. Read-only transactions do not require commit/rollback.
*/ */
boolean readOnly; 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 * Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided * ("Software"), with or without modification, are permitted provided
* that the following conditions are met: * that the following conditions are met:
* *
* 1. Redistributions of source code must retain copyright * 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a * statements and notices. Redistributions must also contain a
* copy of this document. * copy of this document.
* *
* 2. Redistributions in binary form must reproduce the * 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the * above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other * following disclaimer in the documentation and/or other
* materials provided with the distribution. * materials provided with the distribution.
* *
* 3. The name "Exolab" must not be used to endorse or promote * 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written * products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission, * permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org. * please contact info@exolab.org.
* *
* 4. Products derived from this Software may not be called "Exolab" * 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written * nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered * permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies. * trademark of Exoffice Technologies.
* *
* 5. Due credit should be given to the Exolab Project * 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/). * (http://www.exolab.org/).
* *
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved. * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
* *
* $Id: XADataSourceImpl.java,v 1.1 2000/04/17 20:07:56 peter Exp $ * $Id: XADataSourceImpl.java,v 1.2 2001/10/25 06:00:05 momjian Exp $
*/ */
package org.postgresql.xa; package org.postgresql.xa;
@@ -77,383 +77,412 @@ import javax.transaction.xa.Xid;
* @version 1.0 * @version 1.0
*/ */
public abstract class XADataSourceImpl public abstract class XADataSourceImpl
implements DataSource, ConnectionPoolDataSource, implements DataSource, ConnectionPoolDataSource,
XADataSource, Serializable, Runnable XADataSource, Serializable, Runnable
{ {
/** /**
* Maps underlying JDBC connections into global transaction Xids. * Maps underlying JDBC connections into global transaction Xids.
*/ */
private transient Hashtable _txConnections = new Hashtable(); private transient Hashtable _txConnections = new Hashtable();
/** /**
* This is a pool of free underlying JDBC connections. If two * This is a pool of free underlying JDBC connections. If two
* XA connections are used in the same transaction, the second * XA connections are used in the same transaction, the second
* one will make its underlying JDBC connection available to * one will make its underlying JDBC connection available to
* the pool. This is not a real connection pool, only a marginal * the pool. This is not a real connection pool, only a marginal
* efficiency solution for dealing with shared transactions. * efficiency solution for dealing with shared transactions.
*/ */
private transient Stack _pool = new Stack(); private transient Stack _pool = new Stack();
/** /**
* A background deamon thread terminating connections that have * A background deamon thread terminating connections that have
* timed out. * timed out.
*/ */
private transient Thread _background; private transient Thread _background;
/** /**
* The default timeout for all new transactions. * The default timeout for all new transactions.
*/ */
private int _txTimeout = DEFAULT_TX_TIMEOUT; private int _txTimeout = DEFAULT_TX_TIMEOUT;
/** /**
* The default timeout for all new transactions is 10 seconds. * The default timeout for all new transactions is 10 seconds.
*/ */
public final static int DEFAULT_TX_TIMEOUT = 10; public final static int DEFAULT_TX_TIMEOUT = 10;
/** /**
* Implementation details: * Implementation details:
* If two XAConnections are associated with the same transaction * If two XAConnections are associated with the same transaction
* (one with a start the other with a join) they must use the * (one with a start the other with a join) they must use the
* same underlying JDBC connection. They lookup the underlying * same underlying JDBC connection. They lookup the underlying
* JDBC connection based on the transaction's Xid in the * JDBC connection based on the transaction's Xid in the
* originating XADataSource. * originating XADataSource.
* *
* Currently the XADataSource must be the exact same object, * Currently the XADataSource must be the exact same object,
* this should be changed so all XADataSources that are equal * this should be changed so all XADataSources that are equal
* share a table of all enlisted connections * share a table of all enlisted connections
* *
* To test is two connections should fall under the same * To test is two connections should fall under the same
* transaction we match the resource managers by comparing the * transaction we match the resource managers by comparing the
* database/user they fall under using a comparison of the * database/user they fall under using a comparison of the
* XADataSource properties. * XADataSource properties.
*/ */
public XADataSourceImpl() public XADataSourceImpl()
{ {
super(); super();
// Create a background thread that will track transactions // Create a background thread that will track transactions
// that timeout, abort them and release the underlying // that timeout, abort them and release the underlying
// connections to the pool. // connections to the pool.
_background = new Thread( this, "XADataSource Timeout Daemon" ); _background = new Thread( this, "XADataSource Timeout Daemon" );
_background.setPriority( Thread.MIN_PRIORITY ); _background.setPriority( Thread.MIN_PRIORITY );
_background.setDaemon( true ); _background.setDaemon( true );
_background.start(); _background.start();
} }
public XAConnection getXAConnection() 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()
throws SQLException throws SQLException
{ {
Connection conn; // Construct a new XAConnection with no underlying connection.
// When a JDBC method requires an underlying connection, one
// Check in the pool first. // will be created. We don't create the underlying connection
if ( ! _pool.empty() ) { // beforehand, as it might be coming from an existing
conn = (Connection) _pool.pop(); // transaction.
return conn; return new XAConnectionImpl( this, null );
} }
return getConnection();
}
/** public XAConnection getXAConnection( String user, String password )
* XXX Not fully implemented yet and no code to really throws SQLException
* test it. {
*/ // Since we create the connection on-demand with newConnection
Xid[] getTxRecover() // or obtain it from a transaction, we cannot support XA
{ // connections with a caller specified user name.
Vector list; throw new SQLException( "XAConnection does not support connections with caller specified user name" );
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();
}
/** public PooledConnection getPooledConnection()
* Returns the transaction isolation level to use with all newly throws SQLException
* created transactions, or {@link Connection#TRANSACTION_NONE} {
* if using the driver's default isolation level. // Construct a new pooled connection and an underlying JDBC
*/ // connection to go along with it.
public int isolationLevel() return new XAConnectionImpl( this, getConnection() );
{ }
return Connection.TRANSACTION_NONE;
}
public void run() public PooledConnection getPooledConnection( String user, String password )
{ throws SQLException
Enumeration enum; {
int reduce; // Construct a new pooled connection and an underlying JDBC
long timeout; // connection to go along with it.
TxConnection txConn; 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 * Returns the default timeout for all transactions.
// we can release. We release 10% of the pooled */
// connections each time, so in a heavy loaded public int getTransactionTimeout()
// environment we don't get to release that many, but {
// as load goes down we do. These are not actually return _txTimeout;
// 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 ) * This method is defined in the interface and implemented in the
getLogWriter().println( "DataSource " + toString() + * derived class, we re-define it just to make sure it does not
": Reducing internal connection pool size from " + * throw an {@link SQLException} and that we do not need to
_pool.size() + " to " + reduce ); * catch one.
while ( _pool.size() > reduce ) { */
try { public abstract java.io.PrintWriter getLogWriter();
( (Connection) _pool.pop() ).close();
} catch ( SQLException except ) { }
} /**
* 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 ) { } return getConnection();
}
// 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; * XXX Not fully implemented yet and no code to really
* test it.
*/
Xid[] getTxRecover()
{
Vector list;
Enumeration enum;
TxConnection txConn;
synchronized ( txConn ) { list = new Vector();
if ( txConn.conn == null ) enum = _txConnections.elements();
continue; while ( enum.hasMoreElements() )
if ( getLogWriter() != null ) {
getLogWriter().println( "DataSource " + toString() + txConn = (TxConnection) enum.nextElement();
": Transaction timed out and being aborted: " + if ( txConn.conn != null && txConn.prepared )
txConn.xid ); list.add( txConn.xid );
// Remove the connection from the transaction }
// association. XAConnection will now have return (Xid[]) list.toArray();
// 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. * Returns the transaction isolation level to use with all newly
try { * created transactions, or {@link Connection#TRANSACTION_NONE}
underlying.rollback(); * if using the driver's default isolation level.
releaseConnection( underlying ); */
} catch ( SQLException except ) { public int isolationLevel()
if ( getLogWriter() != null ) {
getLogWriter().println( "DataSource " + toString() + return Connection.TRANSACTION_NONE;
": Error aborting timed out transaction: " + except ); }
try {
underlying.close();
} catch ( SQLException e2 ) { } 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 ( Exception except ) { } 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 )
{ }
}
}
} }
}
} }
}
public void debug( PrintWriter writer ) public void debug( PrintWriter writer )
{ {
Enumeration enum; Enumeration enum;
TxConnection txConn; TxConnection txConn;
StringBuffer buffer; StringBuffer buffer;
writer.println( "Debug info for XADataSource:" ); writer.println( "Debug info for XADataSource:" );
enum = _txConnections.elements(); enum = _txConnections.elements();
if ( ! enum.hasMoreElements() ) if ( ! enum.hasMoreElements() )
writer.println( "Empty" ); writer.println( "Empty" );
while ( enum.hasMoreElements() ) { while ( enum.hasMoreElements() )
buffer = new StringBuffer(); {
txConn = (TxConnection) enum.nextElement(); buffer = new StringBuffer();
buffer.append( "TxConnection " ); txConn = (TxConnection) enum.nextElement();
if ( txConn.xid != null ) buffer.append( "TxConnection " );
buffer.append( txConn.xid ); if ( txConn.xid != null )
if ( txConn.conn != null ) buffer.append( txConn.xid );
buffer.append( ' ' ).append( txConn.conn ); if ( txConn.conn != null )
buffer.append( " count: " ).append( txConn.count ); buffer.append( ' ' ).append( txConn.conn );
if ( txConn.prepared ) buffer.append( " count: " ).append( txConn.count );
buffer.append( " prepared" ); if ( txConn.prepared )
if ( txConn.timedOut ) buffer.append( " prepared" );
buffer.append( " timed-out" ); if ( txConn.timedOut )
if ( txConn.readOnly ) buffer.append( " timed-out" );
buffer.append( " read-only" ); if ( txConn.readOnly )
writer.println( buffer.toString() ); 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 public class CheckVersion
{ {
/** /**
* Check for the existence of a class by attempting to load it * Check for the existence of a class by attempting to load it
*/ */
public static boolean checkClass(String c) { public static boolean checkClass(String c)
try { {
Class.forName(c); try
} catch(Exception e) { {
return false; 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. * 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. * 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 * 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 * interface, and if found writes enterprise to stdout. If the interface
* is not found, it writes jdbc2 to stdout. * is not found, it writes jdbc2 to stdout.
* *
* PS: It also looks for the existence of java.lang.Byte which appeared in * 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. * 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. * 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. * The make file uses the written results to determine which rule to run.
* *
* Bugs: This needs thorough testing. * Bugs: This needs thorough testing.
*/ */
public static void main(String args[]) public static void main(String args[])
{ {
String vmversion = System.getProperty("java.vm.version"); String vmversion = System.getProperty("java.vm.version");
System.out.println("postgresql.jdbc="+System.getProperty("postgresql.jdbc")); System.out.println("postgresql.jdbc=" + System.getProperty("postgresql.jdbc"));
// We are running a 1.1 JVM // We are running a 1.1 JVM
if(vmversion.startsWith("1.1")) { if (vmversion.startsWith("1.1"))
System.out.println("jdbc1"); {
//System.exit(0); 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");
}
} }