Commit 35a945f2 authored by Bruce Momjian's avatar Bruce Momjian

New stuff from Peter Mount for jdbc.

parent c37adac7
...@@ -123,7 +123,7 @@ public class psql ...@@ -123,7 +123,7 @@ public class psql
if(rs.wasNull()) if(rs.wasNull())
System.out.print("{null}"+(i<cols?"\t":"\n")); System.out.print("{null}"+(i<cols?"\t":"\n"));
else else
System.out.print(rs.getObject(i).toString()+(i<cols?"\t":"\n")); System.out.print(o.toString()+(i<cols?"\t":"\n"));
} }
} }
......
...@@ -34,6 +34,9 @@ public class Connection implements java.sql.Connection ...@@ -34,6 +34,9 @@ public class Connection implements java.sql.Connection
// This is set by postgresql.Statement.setMaxRows() // This is set by postgresql.Statement.setMaxRows()
protected int maxrows = 0; // maximum no. of rows; 0 = unlimited protected int maxrows = 0; // maximum no. of rows; 0 = unlimited
// This is a cache of the DatabaseMetaData instance for this connection
protected DatabaseMetaData metadata;
private String PG_HOST; private String PG_HOST;
private int PG_PORT; private int PG_PORT;
private String PG_USER; private String PG_USER;
...@@ -44,17 +47,6 @@ public class Connection implements java.sql.Connection ...@@ -44,17 +47,6 @@ public class Connection implements java.sql.Connection
public boolean CONNECTION_OK = true; public boolean CONNECTION_OK = true;
public boolean CONNECTION_BAD = false; public boolean CONNECTION_BAD = false;
//private static final int STARTUP_LEN = 288; // Length of a startup packet
// These are defined in src/include/libpq/pqcomm.h
//private int STARTUP_CODE = STARTUP_USER;
//private static final int STARTUP_USER = 7; // User auth
//private static final int STARTUP_KRB4 = 10; // Kerberos 4 (unused)
//private static final int STARTUP_KRB5 = 11; // Kerberos 5 (unused)
//private static final int STARTUP_HBA = 12; // Host Based
//private static final int STARTUP_NONE = 13; // Unauthenticated (unused)
//private static final int STARTUP_PASS = 14; // Password auth
private boolean autoCommit = true; private boolean autoCommit = true;
private boolean readOnly = false; private boolean readOnly = false;
...@@ -88,12 +80,6 @@ public class Connection implements java.sql.Connection ...@@ -88,12 +80,6 @@ public class Connection implements java.sql.Connection
// be across all connections, which could be to different backends. // be across all connections, which could be to different backends.
protected Hashtable fieldCache = new Hashtable(); protected Hashtable fieldCache = new Hashtable();
// This is used by Field to cache oid -> names.
// It's here, because it's shared across this connection only.
// Hence it cannot be static within the Field class, because it would then
// be across all connections, which could be to different backends.
protected Hashtable fieldCache = new Hashtable();
/** /**
* This is the current date style of the backend * This is the current date style of the backend
*/ */
...@@ -150,8 +136,6 @@ public class Connection implements java.sql.Connection ...@@ -150,8 +136,6 @@ public class Connection implements java.sql.Connection
*/ */
public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
{ {
//int len = STARTUP_LEN; // Length of a startup packet
// Throw an exception if the user or password properties are missing // Throw an exception if the user or password properties are missing
// This occasionally occurs when the client uses the properties version // This occasionally occurs when the client uses the properties version
// of getConnection(), and is a common question on the email lists // of getConnection(), and is a common question on the email lists
...@@ -169,30 +153,15 @@ public class Connection implements java.sql.Connection ...@@ -169,30 +153,15 @@ public class Connection implements java.sql.Connection
PG_HOST = new String(host); PG_HOST = new String(host);
PG_STATUS = CONNECTION_BAD; PG_STATUS = CONNECTION_BAD;
// Pre 6.3 code
// This handles the auth property. Any value begining with p enables
// password authentication, while anything begining with i enables
// ident (RFC 1413) authentication. Any other values default to trust.
//
// Also, the postgresql.auth system property can be used to change the
// local default, if the auth property is not present.
//
//String auth = info.getProperty("auth",System.getProperty("postgresql.auth","trust")).toLowerCase();
//if(auth.startsWith("p")) {
//// Password authentication
//STARTUP_CODE=STARTUP_PASS;
//} else if(auth.startsWith("i")) {
//// Ident (RFC 1413) authentication
//STARTUP_CODE=STARTUP_HBA;
//} else {
//// Anything else defaults to trust authentication
//STARTUP_CODE=STARTUP_USER;
//}
// Now make the initial connection // Now make the initial connection
try try
{ {
pg_stream = new PG_Stream(host, port); pg_stream = new PG_Stream(host, port);
} catch (ConnectException cex) {
// Added by Peter Mount <peter@retep.org.uk>
// ConnectException is thrown when the connection cannot be made.
// we trap this an return a more meaningful message for the end user
throw new SQLException ("Connection refused. Check that the hostname and port is correct, and that the postmaster is running with the -i flag, which enables TCP/IP networking.");
} catch (IOException e) { } catch (IOException e) {
throw new SQLException ("Connection failed: " + e.toString()); throw new SQLException ("Connection failed: " + e.toString());
} }
...@@ -200,30 +169,17 @@ public class Connection implements java.sql.Connection ...@@ -200,30 +169,17 @@ public class Connection implements java.sql.Connection
// Now we need to construct and send a startup packet // Now we need to construct and send a startup packet
try try
{ {
// Pre 6.3 code
//pg_stream.SendInteger(len, 4); len -= 4;
//pg_stream.SendInteger(STARTUP_CODE, 4); len -= 4;
//pg_stream.Send(database.getBytes(), 64); len -= 64;
//pg_stream.Send(PG_USER.getBytes(), len);
//
//// Send the password packet if required
//if(STARTUP_CODE == STARTUP_PASS) {
//len=STARTUP_LEN;
//pg_stream.SendInteger(len, 4); len -= 4;
//pg_stream.SendInteger(STARTUP_PASS, 4); len -= 4;
//pg_stream.Send(PG_USER.getBytes(), PG_USER.length());
//len-=PG_USER.length();
//pg_stream.SendInteger(0,1); len -= 1;
//pg_stream.Send(PG_PASSWORD.getBytes(), len);
//}
// Ver 6.3 code // Ver 6.3 code
pg_stream.SendInteger(4+4+SM_DATABASE+SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY,4); pg_stream.SendInteger(4+4+SM_DATABASE+SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY,4);
pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2); pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2);
pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2); pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2);
pg_stream.Send(database.getBytes(),SM_DATABASE); pg_stream.Send(database.getBytes(),SM_DATABASE);
// This last send includes the unused fields
pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY); pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY);
// The last send includes the unused fields
// now flush the startup packets to the backend
pg_stream.flush();
// Now get the response from the backend, either an error message // Now get the response from the backend, either an error message
// or an authentication request // or an authentication request
...@@ -233,6 +189,12 @@ public class Connection implements java.sql.Connection ...@@ -233,6 +189,12 @@ public class Connection implements java.sql.Connection
switch(beresp) switch(beresp)
{ {
case 'E': case 'E':
// An error occured, so pass the error message to the
// user.
//
// The most common one to be thrown here is:
// "User authentication failed"
//
throw new SQLException(pg_stream.ReceiveString(4096)); throw new SQLException(pg_stream.ReceiveString(4096));
case 'R': case 'R':
...@@ -267,7 +229,7 @@ public class Connection implements java.sql.Connection ...@@ -267,7 +229,7 @@ public class Connection implements java.sql.Connection
pg_stream.SendInteger(5+PG_PASSWORD.length(),4); pg_stream.SendInteger(5+PG_PASSWORD.length(),4);
pg_stream.Send(PG_PASSWORD.getBytes()); pg_stream.Send(PG_PASSWORD.getBytes());
pg_stream.SendInteger(0,1); pg_stream.SendInteger(0,1);
//pg_stream.SendPacket(PG_PASSWORD.getBytes()); pg_stream.flush();
break; break;
case AUTH_REQ_CRYPT: case AUTH_REQ_CRYPT:
...@@ -276,11 +238,11 @@ public class Connection implements java.sql.Connection ...@@ -276,11 +238,11 @@ public class Connection implements java.sql.Connection
pg_stream.SendInteger(5+crypted.length(),4); pg_stream.SendInteger(5+crypted.length(),4);
pg_stream.Send(crypted.getBytes()); pg_stream.Send(crypted.getBytes());
pg_stream.SendInteger(0,1); pg_stream.SendInteger(0,1);
//pg_stream.SendPacket(UnixCrypt.crypt(salt,PG_PASSWORD).getBytes()); pg_stream.flush();
break; break;
default: default:
throw new SQLException("Authentication type "+areq+" not supported"); throw new SQLException("Authentication type "+areq+" not supported. Check that you have configured the pg_hba.conf file to include the client's IP address or Subnet, and is using a supported authentication scheme.");
} }
break; break;
...@@ -511,7 +473,9 @@ public class Connection implements java.sql.Connection ...@@ -511,7 +473,9 @@ public class Connection implements java.sql.Connection
*/ */
public java.sql.DatabaseMetaData getMetaData() throws SQLException public java.sql.DatabaseMetaData getMetaData() throws SQLException
{ {
return new DatabaseMetaData(this); if(metadata==null)
metadata = new DatabaseMetaData(this);
return metadata;
} }
/** /**
...@@ -631,8 +595,6 @@ public class Connection implements java.sql.Connection ...@@ -631,8 +595,6 @@ public class Connection implements java.sql.Connection
*/ */
public void addWarning(String msg) public void addWarning(String msg)
{ {
//PrintStream log = DriverManager.getLogStream();
//if(log!=null)
DriverManager.println(msg); DriverManager.println(msg);
// Add the warning to the chain // Add the warning to the chain
...@@ -691,6 +653,7 @@ public class Connection implements java.sql.Connection ...@@ -691,6 +653,7 @@ public class Connection implements java.sql.Connection
buf = sql.getBytes(); buf = sql.getBytes();
pg_stream.Send(buf); pg_stream.Send(buf);
pg_stream.SendChar(0); pg_stream.SendChar(0);
pg_stream.flush();
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("I/O Error: " + e.toString()); throw new SQLException("I/O Error: " + e.toString());
} }
...@@ -726,6 +689,7 @@ public class Connection implements java.sql.Connection ...@@ -726,6 +689,7 @@ public class Connection implements java.sql.Connection
pg_stream.SendChar('Q'); pg_stream.SendChar('Q');
pg_stream.SendChar(' '); pg_stream.SendChar(' ');
pg_stream.SendChar(0); pg_stream.SendChar(0);
pg_stream.flush();
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("I/O Error: " + e.toString()); throw new SQLException("I/O Error: " + e.toString());
} }
...@@ -964,6 +928,8 @@ public class Connection implements java.sql.Connection ...@@ -964,6 +928,8 @@ public class Connection implements java.sql.Connection
return ((Serialize)o).fetch(Integer.parseInt(value)); return ((Serialize)o).fetch(Integer.parseInt(value));
} }
} catch(SQLException sx) { } catch(SQLException sx) {
// rethrow the exception. Done because we capture any others next
sx.fillInStackTrace();
throw sx; throw sx;
} catch(Exception ex) { } catch(Exception ex) {
throw new SQLException("Failed to create object for "+type+": "+ex); throw new SQLException("Failed to create object for "+type+": "+ex);
...@@ -999,14 +965,17 @@ public class Connection implements java.sql.Connection ...@@ -999,14 +965,17 @@ public class Connection implements java.sql.Connection
// If so, then call it's fetch method. // If so, then call it's fetch method.
if(x instanceof Serialize) if(x instanceof Serialize)
return ((Serialize)x).store(o); return ((Serialize)x).store(o);
// Thow an exception because the type is unknown
throw new SQLException("The object could not be stored. Check that any tables required have already been created in the database.");
} catch(SQLException sx) { } catch(SQLException sx) {
// rethrow the exception. Done because we capture any others next
sx.fillInStackTrace();
throw sx; throw sx;
} catch(Exception ex) { } catch(Exception ex) {
throw new SQLException("Failed to store object: "+ex); throw new SQLException("Failed to store object: "+ex);
} }
// should never be reached
return 0;
} }
/** /**
...@@ -1045,10 +1014,12 @@ public class Connection implements java.sql.Connection ...@@ -1045,10 +1014,12 @@ public class Connection implements java.sql.Connection
private static final String defaultObjectTypes[][] = { private static final String defaultObjectTypes[][] = {
{"box", "postgresql.geometric.PGbox"}, {"box", "postgresql.geometric.PGbox"},
{"circle", "postgresql.geometric.PGcircle"}, {"circle", "postgresql.geometric.PGcircle"},
{"line", "postgresql.geometric.PGline"},
{"lseg", "postgresql.geometric.PGlseg"}, {"lseg", "postgresql.geometric.PGlseg"},
{"path", "postgresql.geometric.PGpath"}, {"path", "postgresql.geometric.PGpath"},
{"point", "postgresql.geometric.PGpoint"}, {"point", "postgresql.geometric.PGpoint"},
{"polygon", "postgresql.geometric.PGpolygon"} {"polygon", "postgresql.geometric.PGpolygon"},
{"money", "postgresql.util.PGmoney"}
}; };
// This initialises the objectTypes hashtable // This initialises the objectTypes hashtable
......
...@@ -27,7 +27,7 @@ public class Driver implements java.sql.Driver ...@@ -27,7 +27,7 @@ public class Driver implements java.sql.Driver
// These should be in sync with the backend that the driver was // These should be in sync with the backend that the driver was
// distributed with // distributed with
static final int MAJORVERSION = 6; static final int MAJORVERSION = 6;
static final int MINORVERSION = 3; static final int MINORVERSION = 4;
static static
{ {
......
...@@ -20,7 +20,16 @@ public class PG_Stream ...@@ -20,7 +20,16 @@ public class PG_Stream
{ {
private Socket connection; private Socket connection;
private InputStream pg_input; private InputStream pg_input;
private OutputStream pg_output; private BufferedOutputStream pg_output;
// This is the error message returned when an EOF occurs
private static final String EOF_MSG = "The backend has broken the connection. Possibly the action you have attempted has caused it to close.";
// This is the error message returned when an IOException occurs
private static final String IOE_MSG = "IOError while reading from backend: ";
// This is the error message returned when flushing the stream.
private static final String FLUSH_MSG = "Error flushing output: ";
/** /**
* Constructor: Connect to the PostgreSQL back end and return * Constructor: Connect to the PostgreSQL back end and return
...@@ -33,8 +42,13 @@ public class PG_Stream ...@@ -33,8 +42,13 @@ public class PG_Stream
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
// improvement on FreeBSD machines (caused by a bug in their TCP Stack)
connection.setTcpNoDelay(true);
pg_input = connection.getInputStream(); pg_input = connection.getInputStream();
pg_output = connection.getOutputStream(); pg_output = new BufferedOutputStream(connection.getOutputStream());
} }
/** /**
...@@ -45,7 +59,6 @@ public class PG_Stream ...@@ -45,7 +59,6 @@ public class PG_Stream
*/ */
public void SendChar(int val) throws IOException public void SendChar(int val) throws IOException
{ {
//pg_output.write(val);
byte b[] = new byte[1]; byte b[] = new byte[1];
b[0] = (byte)val; b[0] = (byte)val;
pg_output.write(b); pg_output.write(b);
...@@ -165,9 +178,9 @@ public class PG_Stream ...@@ -165,9 +178,9 @@ public class PG_Stream
try try
{ {
c = pg_input.read(); c = pg_input.read();
if (c < 0) throw new IOException("EOF"); if (c < 0) throw new IOException(EOF_MSG);
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("Error reading from backend: " + e.toString()); throw new SQLException(IOE_MSG + e.toString());
} }
return c; return c;
} }
...@@ -190,11 +203,11 @@ public class PG_Stream ...@@ -190,11 +203,11 @@ public class PG_Stream
int b = pg_input.read(); int b = pg_input.read();
if (b < 0) if (b < 0)
throw new IOException("EOF"); throw new IOException(EOF_MSG);
n = n | (b << (8 * i)) ; n = n | (b << (8 * i)) ;
} }
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("Error reading from backend: " + e.toString()); throw new SQLException(IOE_MSG + e.toString());
} }
return n; return n;
} }
...@@ -217,11 +230,11 @@ public class PG_Stream ...@@ -217,11 +230,11 @@ public class PG_Stream
int b = pg_input.read(); int b = pg_input.read();
if (b < 0) if (b < 0)
throw new IOException("EOF"); throw new IOException(EOF_MSG);
n = b | (n << 8); n = b | (n << 8);
} }
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("Error reading from backend: " + e.toString()); throw new SQLException(IOE_MSG + e.toString());
} }
return n; return n;
} }
...@@ -246,7 +259,7 @@ public class PG_Stream ...@@ -246,7 +259,7 @@ public class PG_Stream
{ {
int c = pg_input.read(); int c = pg_input.read();
if (c < 0) if (c < 0)
throw new IOException("EOF"); throw new IOException(EOF_MSG);
else if (c == 0) else if (c == 0)
break; break;
else else
...@@ -255,7 +268,7 @@ public class PG_Stream ...@@ -255,7 +268,7 @@ public class PG_Stream
if (s >= maxsiz) if (s >= maxsiz)
throw new IOException("Too Much Data"); throw new IOException("Too Much Data");
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("Error reading from backend: " + e.toString()); throw new SQLException(IOE_MSG + e.toString());
} }
String v = new String(rst, 0, s); String v = new String(rst, 0, s);
return v; return v;
...@@ -314,21 +327,8 @@ public class PG_Stream ...@@ -314,21 +327,8 @@ public class PG_Stream
private byte[] Receive(int siz) throws SQLException private byte[] Receive(int siz) throws SQLException
{ {
byte[] answer = new byte[siz]; byte[] answer = new byte[siz];
int s = 0; Receive(answer,0,siz);
return answer;
try
{
while (s < siz)
{
int w = pg_input.read(answer, s, siz - s);
if (w < 0)
throw new IOException("EOF");
s += w;
}
} catch (IOException e) {
throw new SQLException("Error reading from backend: " + e.toString());
}
return answer;
} }
/** /**
...@@ -349,11 +349,11 @@ public class PG_Stream ...@@ -349,11 +349,11 @@ public class PG_Stream
{ {
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 IOException("EOF"); throw new IOException(EOF_MSG);
s += w; s += w;
} }
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("Error reading from backend: " + e.toString()); throw new SQLException(IOE_MSG + e.toString());
} }
} }
...@@ -367,7 +367,7 @@ public class PG_Stream ...@@ -367,7 +367,7 @@ public class PG_Stream
try { try {
pg_output.flush(); pg_output.flush();
} catch (IOException e) { } catch (IOException e) {
throw new SQLException("Error flushing output: " + e.toString()); throw new SQLException(FLUSH_MSG + e.toString());
} }
} }
......
...@@ -308,24 +308,21 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta ...@@ -308,24 +308,21 @@ 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
{ {
SimpleDateFormat df = new SimpleDateFormat("''"+connection.getDateStyle()+"''"); SimpleDateFormat df = new SimpleDateFormat("''"+connection.getDateStyle()+"''");
// Ideally the following should work: set(parameterIndex, df.format(x));
// The above is how the date should be handled.
// //
// 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
// to format a date to the previous day. So the fix is to add a day
// before formatting.
// //
// however, SimpleDateFormat seems to format a date to the previous // PS: 86400000 is one day
// day. So a fix (for now) is to add a day before formatting.
// This needs more people to confirm this is really happening, or
// possibly for us to implement our own formatting code.
// //
// I've tested this with the Linux jdk1.1.3 and the Win95 JRE1.1.5 //set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000)));
//
set(parameterIndex, df.format(new java.util.Date(x.getTime()+DAY)));
} }
// This equates to 1 day
private static final int DAY = 86400000;
/** /**
* Set a parameter to a java.sql.Time value. The driver converts * Set a parameter to a java.sql.Time value. The driver converts
* this to a SQL TIME value when it sends it to the database. * this to a SQL TIME value when it sends it to the database.
......
...@@ -714,6 +714,12 @@ public class ResultSet implements java.sql.ResultSet ...@@ -714,6 +714,12 @@ public class ResultSet implements java.sql.ResultSet
throw new SQLException("Column index out of range"); throw new SQLException("Column index out of range");
field = fields[columnIndex - 1]; field = fields[columnIndex - 1];
// some fields can be null, mainly from those returned by MetaData methods
if(field==null) {
wasNullFlag=true;
return null;
}
switch (field.getSQLType()) switch (field.getSQLType())
{ {
case Types.BIT: case Types.BIT:
......
...@@ -121,11 +121,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData ...@@ -121,11 +121,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
{ {
String type_name = getField(column).getTypeName(); String type_name = getField(column).getTypeName();
if (type_name.equals("cash")) return type_name.equals("cash") || type_name.equals("money");
return true;
if (type_name.equals("money"))
return true;
return false;
} }
/** /**
...@@ -214,11 +210,14 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData ...@@ -214,11 +210,14 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
* *
* @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 column name * @return the column name
* @exception SQLException if a databvase access error occurs * @exception SQLException if a database access error occurs
*/ */
public String getColumnName(int column) throws SQLException public String getColumnName(int column) throws SQLException
{ {
return getField(column).name; Field f = getField(column);
if(f!=null)
return f.name;
return "field"+column;
} }
/** /**
...@@ -233,13 +232,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData ...@@ -233,13 +232,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
*/ */
public String getSchemaName(int column) throws SQLException public String getSchemaName(int column) throws SQLException
{ {
String table_name = getTableName(column); return "";
// If the table name is invalid, so are we.
if (table_name.equals(""))
return "";
return ""; // Ok, so I don't know how to
// do this as yet.
} }
/** /**
...@@ -328,12 +321,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData ...@@ -328,12 +321,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
*/ */
public String getCatalogName(int column) throws SQLException public String getCatalogName(int column) throws SQLException
{ {
String table_name = getTableName(column); return "";
if (table_name.equals(""))
return "";
return ""; // As with getSchemaName(), this
// is just the start of it.
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment