提交 43214cca authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 2531186c
......@@ -37,13 +37,10 @@
<target name="clean" depends="init">
<mkdir dir="bin"/>
<mkdir dir="odbc"/>
<mkdir dir="docs"/>
<delete includeemptydirs="true">
<fileset dir="." includes="*.sql,*.txt,*.lock,**/*.db,node*"/>
<fileset dir="bin" includes="**/*" excludes="**/*.bat,**/*.sh"/>
<fileset dir="odbc" includes="*.a,*.def,"/>
<fileset dir="odbc" includes="*.def,h2odbcTest.exe"/>
<fileset dir="docs" includes="**/*"/>
</delete>
<delete file="src/tools/org/h2/tools/code/CodeSwitch.class"/>
......@@ -251,7 +248,7 @@
<fileset dir="src/main"/>
</copy>
<java classname="org.h2.test.coverage.Coverage" classpath="bin" dir="bin" fork="true">
<arg line="-e org/h2/web -e org/h2/server/Odbc -e org/h2/jdbcx -e org/h2/bnf -r org/h2"/>
<arg line="-e org/h2/web -e org/h2/jdbcx -e org/h2/bnf -r org/h2"/>
</java>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="bin" destdir="bin" debug="true" includes="org/h2/**"/>
<java classname="org.h2.test.TestAll" fork="true" classpath="bin" dir="bin">
......@@ -279,7 +276,6 @@
<fileset dir=".." includes="h2/ant-build.properties"/>
<fileset dir=".." includes="h2/bin/**/*"/>
<fileset dir=".." includes="h2/docs/**/*"/>
<fileset dir=".." includes="h2/odbc/**/*"/>
<fileset dir=".." includes="h2/service/**/*"/>
<fileset dir=".." includes="h2/src/**/*"/>
</zip>
......
......@@ -311,48 +311,86 @@ If successful, a command prompt window will pop up and disappear immediately. If
<br /><a name="odbc_driver"></a>
<h2>ODBC Driver</h2>
The ODBC driver of this database is currently not very stable and only tested superficially
with a few applications (OpenOffice 2.0, Microsoft Excel and Microsoft Access) and
data types (INT and VARCHAR), and should not be used for production applications.
Only a Windows version of the driver is available at this time.
This database does not come with its own ODBC driver at this time,
but it supports the PostgreSQL network protocol.
Therefore, the PostgreSQL ODBC driver can be used.
Support for the PostgreSQL network protocol is quite new and should be viewed
as experimental. It should not be used for production applications.
<h3>ODBC Installation</h3>
<p>
Before the ODBC driver can be used, it needs to be installed. To do this,
double click on h2odbcSetup.exe. If you do this the first time, it will ask you to locate the
driver dll (h2odbc.dll). If you already installed it, the ODBC administration dialog will open
where you can create new or modify existing data sources.
When you create a new H2 ODBC data source, a dialog window will appear
and ask for the database settings:
First, the ODBC driver must be installed.
Any recent PostgreSQL ODBC driver should work, however version 8.2.4 or newer is recommended.
The Windows version of the PostgreSQL ODBC driver is available at
<a href="http://www.postgresql.org/ftp/odbc/versions/msi">http://www.postgresql.org/ftp/odbc/versions/msi</a>.
</p>
<img src="odbcDataSource.png" alt="ODBC Configuration" />
<h3>Log Option</h3>
The driver is able to log operations to a file.
To enable logging, the log file name must be set in the registry under the key
CURRENT_USER/Software/H2/ODBC/LogFile. This key will only be read when the
driver starts, so you need to make sure all applications that may use the driver
are closed before changing this setting.
If this registry entry is not found when the driver starts, logging is disabled.
A sample registry key file may look like this:
<pre>
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\H2\ODBC]
"LogFile"="C:\\temp\\h2odbc.txt"
<h3>Starting the Server</h3>
<p>
After installing the ODBC driver, start the H2 Server using the command line:
<pre>
java -cp h2.jar org.h2.tools.Server
</pre>
The PG Server (PG for PostgreSQL protocol) is started as well.
By default, databases are stored in the current working directory where the server is started.
Use -baseDir to save databases in another directory, for example the user home directory:
<pre>
java -cp h2.jar org.h2.tools.Server -baseDir ~
</pre>
The PG server can be started and stopped from within a Java application as follows:
<pre>
Server server = Server.createPgServer(new String[]{"-baseDir", "~"});
server.start();
...
server.stop();
</pre>
By default, only connections from localhost are allowed. To allow remote connections, use
<code>-pgAllowOthers true</code> when starting the server.
</p>
<h3>ODBC Configuration</h3>
<p>
After installing the driver, a new Data Source must be added. In Windows,
run <code>odbcad32.exe</code> to open the Data Source Administrator. Then click on 'Add...'
and select the PostgreSQL Unicode driver. Then click 'Finish'.
You will be able to change the connection properties:
</p>
<table>
<tr><th>Property</th><th>Example</th><th>Remarks</th></th>
<tr><td>Data Source</td><td>H2 Test</td><td>The name of the ODBC Data Source</td></tr>
<tr><td>Database</td><td>test</td>
<td>
The database name. Only simple names are supported at this time; <br />
relative or absolute path are not supported in the database name. <br />
By default, the database is stored in the current working directory <br />
where the Server is started except when the -baseDir setting is used. <br />
The name must be at least 3 characters.
</td></tr>
<tr><td>Server</td><td>localhost</td><td>The server name or IP address.<br />By default, only remote connections are allowed</td></tr>
<tr><td>User Name</td><td>sa</td><td>The database user name.</td></tr>
<tr><td>SSL Mode</td><td>disabled</td><td>At this time, SSL is not supported.</td></tr>
<tr><td>Port</td><td>5435</td><td>The port where the PG Server is listening.</td></tr>
<tr><td>Password</td><td>sa</td><td>The database password.</td></tr>
</table>
<p>
Afterwards, you may use this data source.
</p>
<h3>PG Protocol Support Limitations</h3>
<p>
At this time, only a subset of the PostgreSQL network protocol is implemented.
Also, there may be compatibility problems on the SQL level, with the catalog, or with text encoding.
Problems are fixed as they are found.
Currently, statements can not be cancelled when using the PG protocol.
</p>
<h3>Security Considerations</h3>
Currently, the ODBC does not encrypt the password before sending it over TCP/IP to the server.
This may be a problem if an attacker can listen to the data transferred between the ODBC client
Currently, the PG Server does not support challenge response or encrypt passwords.
This may be a problem if an attacker can listen to the data transferred between the ODBC driver
and the server, because the password is readable to the attacker.
Also, it is currently not possible to use encrypted SSL connections.
The password for a data source is stored unencrypted in the registry.
Therefore the ODBC driver should not be used where security is important.
<h3>Uninstalling</h3>
To uninstall the ODBC driver, double click on h2odbcUninstall.exe. This will uninstall the driver.
<br /><a name="acid"></a>
<h2>ACID</h2>
In the database world, ACID stands for:
......
......@@ -39,7 +39,9 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / 2007-TODO</h3><ul>
<li>The default value for h2.defaultMaxMemoryUndo is now 50000.
<li>
</li><li>The experimental H2 ODBC driver has been removed.
</li><li>The default value for h2.defaultMaxMemoryUndo is now 50000.
This avoids out of memory problems when using very large transactions,
however large transactions are slower because they are buffered to disk.
To disable, use -Dh2.defaultMaxMemoryUndo=2000000000.
......
......@@ -119,8 +119,6 @@ Section "All"
File /r /x CVS /x .cvsignore ..\..\bin\*.*
SetOutPath "$INSTDIR\docs"
File /r /x CVS /x .cvsignore ..\..\docs\*.*
SetOutPath "$INSTDIR\odbc"
File /r /x CVS /x .cvsignore ..\..\odbc\*.*
SetOutPath "$INSTDIR\service"
File /r /x CVS /x .cvsignore /x .svn ..\..\service\*.*
SetOutPath "$INSTDIR"
......
......@@ -50,7 +50,6 @@ import org.h2.message.TraceSystem;
* - table of contents
* - Switch off auto-build
* - ant all
* - Make sure odbc files are the
* - Copy the pdf file to h2/docs
* - Make sure the build files are removed
* - ant zip
......
......@@ -58,7 +58,6 @@ import org.h2.value.ValueUuid;
*/
public class Function extends Expression implements FunctionCall {
// TODO functions: ODBC TIMESTAMPDIFF
// TODO functions: add function hashcode(value)
public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3, ATAN2 = 4,
......
......@@ -10,6 +10,14 @@ import org.h2.value.Value;
* @author Thomas
*/
public class LinearHashEntry {
// private LinearHashEntry(int home, int hash, Value key, int value) {
// this.home = home;
// this.hash = hash;
// this.key = key;
// this.value = value;
// }
public int home;
public int hash;
public Value key;
......
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.server;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import org.h2.message.TraceSystem;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
/**
* @author Thomas
*/
public class OdbcServer implements Service {
public static final int DEFAULT_PORT = 9083; // also in the docs
private int port = OdbcServer.DEFAULT_PORT;
private boolean stop;
private boolean log;
private ServerSocket serverSocket;
private HashSet running = new HashSet();
private String baseDir;
private String url;
private boolean allowOthers;
private boolean ifExists;
private Thread listenerThread;
boolean getLog() {
return log;
}
void log(String s) {
if (log) {
System.out.println(s);
}
}
synchronized void remove(OdbcServerThread t) {
running.remove(t);
}
void logError(Exception e) {
if (log) {
e.printStackTrace();
}
}
public void init(String[] args) throws Exception {
port = DEFAULT_PORT;
for (int i = 0; i < args.length; i++) {
String a = args[i];
if (a.equals("-log")) {
log = Boolean.valueOf(args[++i]).booleanValue();
} else if (a.equals("-odbcPort")) {
port = MathUtils.decodeInt(args[++i]);
} else if (a.equals("-baseDir")) {
baseDir = args[++i];
} else if (a.equals("-odbcAllowOthers")) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
} else if (a.equals("-ifExists")) {
ifExists = Boolean.valueOf(args[++i]).booleanValue();
}
}
org.h2.Driver.load();
url = "odbc://localhost:" + port;
}
public String getURL() {
return url;
}
boolean allow(Socket socket) {
if(allowOthers) {
return true;
}
return NetUtils.isLoopbackAddress(socket);
}
public void start() throws SQLException {
serverSocket = NetUtils.createServerSocket(port, false);
}
public void listen() {
listenerThread = Thread.currentThread();
String threadName = listenerThread.getName();
try {
while (!stop) {
Socket s = serverSocket.accept();
if(!allow(s)) {
log("Connection not allowed");
s.close();
} else {
OdbcServerThread c = new OdbcServerThread(s, this);
running.add(c);
Thread thread = new Thread(c);
thread.setName(threadName+" thread");
c.setThread(thread);
thread.start();
}
}
} catch (Exception e) {
if(!stop) {
e.printStackTrace();
}
}
}
public void stop() {
// TODO server: share code between web and tcp servers
if(!stop) {
stop = true;
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO log exception
e.printStackTrace();
}
serverSocket = null;
}
if(listenerThread != null) {
try {
listenerThread.join(1000);
} catch (InterruptedException e) {
TraceSystem.traceThrowable(e);
}
}
}
// TODO server: using a boolean 'now' argument? a timeout?
ArrayList list = new ArrayList(running);
for(int i=0; i<list.size(); i++) {
OdbcServerThread c = (OdbcServerThread) list.get(i);
c.close();
try {
c.getThread().join(100);
} catch(Exception e) {
// TODO log exception
e.printStackTrace();
}
}
}
public boolean isRunning() {
if(serverSocket == null) {
return false;
}
try {
Socket s = NetUtils.createSocket(InetAddress.getLocalHost(), serverSocket.getLocalPort(), false);
s.close();
return true;
} catch(Exception e) {
return false;
}
}
public String getBaseDir() {
return baseDir;
}
public boolean getAllowOthers() {
return allowOthers;
}
public String getType() {
return "ODBC";
}
public boolean getIfExists() {
return ifExists;
}
}
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.HashMap;
import org.h2.engine.ConnectionInfo;
import org.h2.message.Message;
import org.h2.util.ObjectUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
/**
* @author Thomas
*/
public class OdbcServerThread implements Runnable {
private OdbcServer server;
private Socket socket;
private Connection conn;
private DatabaseMetaData meta;
private boolean stop;
private int cacheId;
private Object cache;
private OdbcTransfer transfer;
private Thread thread;
private BufferedOutputStream outBuff;
private HashMap object = new HashMap();
private int nextId;
OdbcServerThread(Socket socket, OdbcServer server) {
this.server = server;
this.socket = socket;
}
private int addObject(Object o) {
int id = nextId++;
server.log("addObj "+id+" "+o);
object.put(ObjectUtils.getInteger(id), o);
cacheId = id;
cache = o;
return id;
}
private void freeObject(int id) {
if (cacheId == id) {
cacheId = -1;
cache = null;
}
object.remove(ObjectUtils.getInteger(id));
}
private Object getObject(int id) {
if (id == cacheId) {
server.log("getObj "+id+" "+cache);
return cache;
}
server.log("getObj "+id+" "+object.get(ObjectUtils.getInteger(id)));
return object.get(ObjectUtils.getInteger(id));
}
public void run() {
try {
server.log("Connect");
InputStream ins = socket.getInputStream();
OutputStream outs = socket.getOutputStream();
DataInputStream in;
in = new DataInputStream(new BufferedInputStream(ins,
OdbcTransfer.BUFFER_SIZE));
outBuff = new BufferedOutputStream(outs, OdbcTransfer.BUFFER_SIZE);
DataOutputStream out = new DataOutputStream(outBuff);
transfer = new OdbcTransfer(in, out);
outBuff.flush();
while (!stop) {
process();
outBuff.flush();
}
server.log("Disconnect");
} catch (Exception e) {
server.logError(e);
}
}
public void close() {
try {
stop = true;
conn.close();
socket.close();
server.log("Close");
} catch(Exception e) {
server.logError(e);
}
conn = null;
socket = null;
server.remove(this);
}
private void sendError(Throwable e) throws IOException {
SQLException s = Message.convert(e);
server.log("Exception "+s);
s.printStackTrace();
transfer.writeByte((byte)'E');
}
private void processResultSet(ResultSet rs) throws IOException, SQLException {
int id = addObject(rs);
transfer.writeInt(id);
ResultSetMetaData m = rs.getMetaData();
int columnCount = m.getColumnCount();
transfer.writeInt(columnCount);
for(int i=0; i<columnCount; i++) {
transfer.writeInt(mapType(m.getColumnType(i+1)));
transfer.writeString(m.getTableName(i+1));
transfer.writeString(m.getColumnLabel(i+1));
transfer.writeInt(m.getPrecision(i+1));
transfer.writeInt(m.getScale(i+1));
transfer.writeInt(m.getColumnDisplaySize(i+1));
}
}
private void setParameter(PreparedStatement prep, int index, int type) throws SQLException, IOException {
switch(type) {
case Types.NULL: {
// fake: use Integer data type for now
prep.setNull(index, Types.INTEGER);
break;
}
case Types.INTEGER: {
int value = transfer.readInt();
server.log(" index="+index+" int="+value);
prep.setInt(index, value);
break;
}
case Types.VARCHAR: {
String value = transfer.readString();
server.log(" index="+index+" string="+value);
prep.setString(index, value);
break;
}
default:
throw Message.getInternalError("unexpected data type "+type);
}
}
private void setParameters(PreparedStatement prep) throws SQLException, IOException {
while(true) {
int x = transfer.readByte();
if(x == '0') {
break;
} else if(x=='1') {
int index = transfer.readInt();
int type = transfer.readInt();
setParameter(prep, index+1, type);
} else {
throw Message.getInternalError("unexpected "+x);
}
}
}
private void processMeta() throws IOException {
int operation = transfer.readByte();
server.log("meta op="+(char)operation);
switch(operation) {
case 'B': {
String catalog = transfer.readString();
String schema = transfer.readString();
String table = transfer.readString();
if(table ==null || table.length()==0) {
table = "%";
}
int scope = transfer.readInt();
boolean nullable = transfer.readBoolean();
try {
ResultSet rs = meta.getBestRowIdentifier(catalog, schema, table, scope, nullable);
processResultSet(rs);
} catch(Throwable e) {
sendError(e);
}
break;
}
case 'C': {
// String catalog = transfer.readString();
String schemaPattern = transfer.readString();
String tableNamePattern = transfer.readString();
String columnNamePattern = transfer.readString();
if(tableNamePattern ==null || tableNamePattern.length()==0) {
tableNamePattern = "%";
}
if(columnNamePattern ==null || columnNamePattern.length()==0) {
columnNamePattern = "%";
}
PreparedStatement prep = null;
try {
prep = conn.prepareStatement("SELECT "
+ "TABLE_CATALOG TABLE_CAT, "
+ "TABLE_SCHEMA TABLE_SCHEM, "
+ "TABLE_NAME, "
+ "COLUMN_NAME, "
+ "DATA_TYPE, "
+ "TYPE_NAME, "
+ "CHARACTER_MAXIMUM_LENGTH COLUMN_SIZE, "
+ "CHARACTER_MAXIMUM_LENGTH BUFFER_LENGTH, "
+ "CAST(NUMERIC_SCALE AS SMALLINT) DECIMAL_DIGITS, " // different in JDBC
+ "CAST(10 AS SMALLINT) NUM_PREC_RADIX, " // different in JDBC
+ "CAST(NULLABLE AS SMALLINT) NULLABLE, " // different in JDBC
+ "'' REMARKS, "
+ "COLUMN_DEFAULT COLUMN_DEF, "
+ "CAST(DATA_TYPE AS SMALLINT) SQL_DATA_TYPE, " // different in JDBC
+ "CAST(0 AS SMALLINT) SQL_DATETIME_SUB, " // different in JDBC
+ "CHARACTER_OCTET_LENGTH CHAR_OCTET_LENGTH, "
+ "ORDINAL_POSITION ORDINAL_POSITION, "
+ "NULLABLE IS_NULLABLE "
+ "FROM INFORMATION_SCHEMA.COLUMNS "
+ "WHERE TABLE_SCHEMA LIKE ? "
+ "AND TABLE_NAME LIKE ? "
+ "AND COLUMN_NAME LIKE ? "
+ "ORDER BY TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION");
prep.setString(1, schemaPattern == null ? "%" : schemaPattern);
prep.setString(2, tableNamePattern == null ? "%" : tableNamePattern);
prep.setString(3, columnNamePattern == null ? "%" : columnNamePattern);
// ResultSet rs = meta.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
ResultSet rs = prep.executeQuery();
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(prep);
}
break;
}
case 'D': {
String where;
if(transfer.readByte()=='A') {
where= "";
} else {
int type = transfer.readInt();
where = " WHERE TYPE="+type+" ";
}
Statement stat = null;
try {
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT "
+ "TYPE_NAME, "
+ "DATA_TYPE, "
+ "PRECISION COLUMN_SIZE, "
+ "PREFIX LITERAL_PREFIX, "
+ "PREFIX LITERAL_SUFFIX, "
+ "PARAMS CREATE_PARAMS, "
+ "CAST(" +DatabaseMetaData.typeNullable + " AS SMALLINT) NULLABLE, "
+ "CAST(1 AS SMALLINT) CASE_SENSITIVE, " // TODO metadata: check if this is ok
+ "CAST(1 AS SMALLINT) SEARCHABLE, " // TODO metadata: check if this is ok
+ "CAST(0 AS SMALLINT) UNSIGNED_ATTRIBUTE, " // TODO metadata: check if this is ok
+ "CAST(0 AS SMALLINT) FIXED_PREC_SCALE, " // TODO metadata: check if this is ok
+ "CAST(0 AS SMALLINT) AUTO_UNIQUE_VALUE, " // TODO metadata: check if this is ok
+ "TYPE_NAME LOCAL_TYPE_NAME, "
+ "MINIMUM_SCALE, "
+ "MAXIMUM_SCALE, "
+ "DATA_TYPE SQL_DATA_TYPE, "
+ "CAST(1 AS SMALLINT) SQL_DATETIME_SUB, " // TODO metadata: check if this is ok
+ "RADIX NUM_PREC_RADIX, "
+ "CAST(0 AS SMALLINT) INTERVAL_PRECISION "
+ "FROM INFORMATION_SCHEMA.TYPE_INFO "
+ where
+ "ORDER BY DATA_TYPE, POS");
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(stat);
}
break;
}
case 'I': {
// String catalog = transfer.readString();
String schemaPattern = transfer.readString();
String tableNamePattern = transfer.readString();
if(tableNamePattern==null || tableNamePattern.length()==0) {
tableNamePattern = "%";
}
// boolean unique = transfer.readBoolean();
// boolean approximate = transfer.readBoolean();
PreparedStatement prep = null;
try {
//ResultSet rs = meta.getIndexInfo(catalog, schemaPattern, tableNamePattern, unique, approximate);
prep = conn.prepareStatement("SELECT "
+ "TABLE_CATALOG TABLE_CAT, "
+ "TABLE_SCHEMA TABLE_SCHEM, "
+ "TABLE_NAME, "
+ "CAST(NON_UNIQUE AS SMALLINT) NON_UNIQUE, "
+ "TABLE_CATALOG INDEX_QUALIFIER, "
+ "INDEX_NAME, "
+ "CAST("+DatabaseMetaData.tableIndexOther + " AS SMALLINT) TYPE, "
+ "ORDINAL_POSITION, "
+ "COLUMN_NAME, "
+ "'A' ASC_OR_DESC, "
+ "CARDINALITY, "
+ "0 PAGES, "
+ "'' FILTER_CONDITION "
+ "FROM INFORMATION_SCHEMA.INDEXES "
+ "WHERE CATALOG_NAME LIKE ? "
+ "AND TABLE_NAME LIKE ? "
+ "ORDER BY NON_UNIQUE, TYPE, TABLE_SCHEM, INDEX_NAME, ORDINAL_POSITION");
prep.setString(1, schemaPattern);
prep.setString(2, tableNamePattern);
ResultSet rs = prep.executeQuery();
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(prep);
}
break;
}
case 'N': {
String sql = transfer.readString();
try {
sql = conn.nativeSQL(sql);
} catch(SQLException e) {
sendError(e);
}
transfer.writeString(sql);
break;
}
case 'T': {
String catalog = transfer.readString();
String schema = transfer.readString();
String table = transfer.readString();
String tableTypes = transfer.readString();
server.log(" catalog="+catalog+" schema="+schema+" table="+table+" tableTypes="+tableTypes);
ResultSet rs;
String[] types = null;
PreparedStatement prep = null;
try {
if(catalog.equals("%") && schema.length()==0 && table.length()==0) {
server.log(" allCatalogs");
prep = conn.prepareStatement("SELECT "
+ "CATALOG_NAME TABLE_CAT, "
+ "NULL TABLE_SCHEM, "
+ "NULL TABLE_NAME, "
+ "NULL TABLE_TYPE, "
+ "'' REMARKS "
+ "FROM INFORMATION_SCHEMA.CATALOGS");
rs = prep.executeQuery();
} else if(catalog.length()==0 && schema.equals("%") && table.length()==0) {
server.log(" allSchemas");
prep = conn.prepareStatement("SELECT "
+ "CATALOG_NAME TABLE_CAT, "
+ "SCHEMA_NAME TABLE_SCHEM, "
+ "NULL TABLE_NAME, "
+ "NULL TABLE_TYPE, "
+ "'' REMARKS "
+ "FROM INFORMATION_SCHEMA.SCHEMATA");
rs = prep.executeQuery();
} else if(catalog.length()==0 && schema.length()==0 && table.length()==0 && tableTypes.equals("%")) {
server.log(" allTableTypes");
prep = conn.prepareStatement("SELECT "
+ "NULL TABLE_CAT, "
+ "NULL TABLE_SCHEM, "
+ "NULL TABLE_NAME, "
+ "TYPE TABLE_TYPE, "
+ "'' REMARKS "
+ "FROM INFORMATION_SCHEMA.TABLE_TYPES");
rs = prep.executeQuery();
} else {
server.log(" getTables");
if(tableTypes.equals("%") || tableTypes.length()==0) {
types = null;
} else {
types = StringUtils.arraySplit(tableTypes, ',', false);
for(int i=0; i<types.length; i++) {
String t = StringUtils.toUpperEnglish(types[i]);
if(t.startsWith("\'")) {
t = t.substring(1, t.length()-2);
}
types[i] = t;
}
}
server.log("getTables "+catalog+" "+schema+" "+table);
if(table.length() == 0) {
table = null;
}
rs = meta.getTables(catalog, schema, table, types);
}
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(prep);
}
break;
}
case 'V': {
String catalog = transfer.readString();
String schema = transfer.readString();
String table = transfer.readString();
if(table ==null || table.length()==0) {
table = "%";
}
try {
ResultSet rs = meta.getVersionColumns(catalog, schema, table);
// PreparedStatement prep = conn.prepareStatement("SELECT "
// + "CAST(NULL AS INT) SCOPE, "
// + "NULL COLUMN_NAME, "
// + "CAST(NULL AS INT) DATA_TYPE, "
// + "NULL TYPE_NAME, "
// + "CAST(NULL AS INT) COLUMN_SIZE, "
// + "CAST(NULL AS INT) BUFFER_LENGTH, "
// + "CAST(NULL AS INT) DECIMAL_DIGITS, "
// + "CAST(NULL AS INT) PSEUDO_COLUMN "
// + "FROM SYSTEM_TABLES "
// + "WHERE 1=0");
// ResultSet rs = prep.executeQuery();
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
}
break;
}
default:
server.log("meta operation? " + (char)operation);
}
}
private void process() throws IOException {
int operation = transfer.readByte();
if(operation == -1) {
stop = true;
return;
}
server.log("op="+(char)operation);
switch(operation) {
case 'A': {
try {
int op = transfer.readByte();
switch(op) {
case '0':
server.log("autoCommit false");
conn.setAutoCommit(false);
break;
case '1':
server.log("autoCommit true");
conn.setAutoCommit(true);
break;
case 'C':
server.log("commit");
conn.commit();
break;
case 'R':
server.log("rollback");
conn.rollback();
break;
default:
server.log("operation? " + (char)operation);
}
} catch(SQLException e) {
sendError(e);
}
break;
}
case 'C':
server.log("connect");
String db = transfer.readString();
server.log(" db="+db);
String user = transfer.readString();
server.log(" user="+user);
String password = transfer.readString();
server.log(" password="+password);
String baseDir = server.getBaseDir();
ConnectionInfo ci = new ConnectionInfo(db);
if(baseDir != null) {
ci.setBaseDir(baseDir);
}
if(server.getIfExists()) {
ci.setProperty("IFEXISTS", "TRUE");
}
String dbName = ci.getDatabaseName();
try {
conn = DriverManager.getConnection("jdbc:h2:" + dbName, user, password);
meta = conn.getMetaData();
transfer.writeByte((byte)'O');
} catch(SQLException e) {
sendError(e);
}
break;
case 'E': {
String sql = transfer.readString();
server.log("<"+sql+">");
try {
int params = getParametersCount(sql);
if(params > 0) {
// it is a prepared statement
PreparedStatement prep = conn.prepareStatement(sql);
int id = addObject(prep);
transfer.writeByte((byte)'O');
transfer.writeInt(id);
transfer.writeInt(params);
} else {
Statement stat = null;
try {
stat = conn.createStatement();
boolean isResultSet = stat.execute(sql);
if(isResultSet) {
transfer.writeByte((byte)'R');
ResultSet rs = stat.getResultSet();
processResultSet(rs);
} else {
transfer.writeByte((byte)'U');
transfer.writeInt(stat.getUpdateCount());
}
} finally {
JdbcUtils.closeSilently(stat);
}
}
} catch(SQLException e) {
sendError(e);
}
break;
}
case 'F': {
int id = transfer.readInt();
server.log("free "+id);
freeObject(id);
break;
}
case 'G': {
int objectId = transfer.readInt();
ResultSet rs = (ResultSet)getObject(objectId);
try {
boolean hasNext = rs.next();
if(hasNext) {
transfer.writeByte((byte)'1');
ResultSetMetaData m = rs.getMetaData();
int columnCount = m.getColumnCount();
for(int i=0; i<columnCount; i++) {
write(m, rs, i);
}
} else {
transfer.writeByte((byte)'0');
}
} catch(SQLException e) {
sendError(e);
}
break;
}
case 'M':
processMeta();
break;
case 'P': {
String sql = transfer.readString();
server.log("<"+sql+">");
try {
PreparedStatement prep = conn.prepareStatement(sql);
int id = addObject(prep);
transfer.writeByte((byte)'O');
transfer.writeInt(id);
int params = getParametersCount(sql);
transfer.writeInt(params);
} catch(SQLException e) {
sendError(e);
}
break;
}
case 'Q': {
// executePrepared
int id = transfer.readInt();
PreparedStatement prep = (PreparedStatement)getObject(id);
try {
setParameters(prep);
boolean isResultSet = prep.execute();
if(isResultSet) {
transfer.writeByte((byte)'R');
ResultSet rs = prep.getResultSet();
processResultSet(rs);
} else {
transfer.writeByte((byte)'U');
transfer.writeInt(prep.getUpdateCount());
}
} catch(SQLException e) {
sendError(e);
}
break;
}
case 'X':
stop = true;
break;
default:
server.log("operation? " + (char)operation);
}
}
private void write(ResultSetMetaData m, ResultSet rs, int i) throws IOException {
try {
int type = mapType(m.getColumnType(i+1));
switch(type) {
case Types.SMALLINT:
case Types.INTEGER: {
int value = rs.getInt(i+1);
if(rs.wasNull()) {
transfer.writeBoolean(true);
} else {
transfer.writeBoolean(false);
transfer.writeInt(value);
}
break;
}
case Types.NULL:
break;
case Types.VARCHAR:
transfer.writeString(rs.getString(i+1));
break;
default:
throw Message.getInternalError("unsupported data type "+type);
}
} catch(SQLException e) {
sendError(e);
}
}
int mapType(int sqlType) {
switch(sqlType) {
case Types.SMALLINT:
case Types.INTEGER:
case Types.NULL:
case Types.VARCHAR:
return sqlType;
case Types.TINYINT:
case Types.BIT:
case DataType.TYPE_BOOLEAN:
return Types.INTEGER;
case Types.BIGINT:
case Types.BINARY:
case Types.BLOB:
case Types.CHAR:
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.DECIMAL:
case Types.DOUBLE:
case Types.FLOAT:
case Types.JAVA_OBJECT:
case Types.LONGVARBINARY:
case Types.LONGVARCHAR:
case Types.NUMERIC:
case Types.OTHER:
case Types.REAL:
case Types.VARBINARY:
return Types.VARCHAR;
default:
throw Message.getInternalError("sqlType "+sqlType);
}
}
int getParametersCount(String sql) throws SQLException {
if (sql == null || sql.indexOf('?') < 0) {
return 0;
}
int len = sql.length();
int param = 0;
for (int i = 0; i < len; i++) {
try {
char c = sql.charAt(i);
switch (c) {
case '\'': {
int j = sql.indexOf('\'', i + 1);
if (j < 0) {
throw Message.getSyntaxError(sql, i);
}
i = j;
break;
}
case '"': {
int j = sql.indexOf('"', i + 1);
if (j < 0) {
throw Message.getSyntaxError(sql, i);
}
i = j;
break;
}
case '/': {
if (sql.charAt(i + 1) == '*') {
// block comment
int j = sql.indexOf("*/", i + 2);
if (j < 0) {
throw Message.getSyntaxError(sql, i);
}
i = j + 1;
} else if (sql.charAt(i + 1) == '/') {
// single line comment
i += 2;
while (i < len && (c = sql.charAt(i)) != '\r'
&& c != '\n') {
i++;
}
}
break;
}
case '-':
if (sql.charAt(i + 1) == '-') {
// single line comment
i += 2;
while (i < len && (c = sql.charAt(i)) != '\r'
&& c != '\n') {
i++;
}
}
break;
case '?':
param++;
break;
}
} catch (ArrayIndexOutOfBoundsException e) {
throw Message.getSyntaxError(sql, i);
}
}
return param;
}
public void setThread(Thread thread) {
this.thread = thread;
}
public Thread getThread() {
return thread;
}
}
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* @author Thomas
*/
public class OdbcTransfer {
static final int BUFFER_SIZE = 1024;
private DataInputStream in;
private DataOutputStream out;
OdbcTransfer(DataInputStream in, DataOutputStream out) {
this.in = in;
this.out = out;
}
OdbcTransfer writeBoolean(boolean x) throws IOException {
writeInt(x ? 1 : 0);
return this;
}
OdbcTransfer writeOk() throws IOException {
writeBoolean(true);
return this;
}
boolean readBoolean() throws IOException {
return readInt() == 1;
}
OdbcTransfer writeByte(byte x) throws IOException {
out.write(x);
return this;
}
int readByte() throws IOException {
return in.read();
}
OdbcTransfer writeShort(short x) throws IOException {
return writeInt(x);
}
short readShort() throws IOException {
return (short) readInt();
}
OdbcTransfer writeInt(int i) throws IOException {
out.writeInt(i);
return this;
}
int readInt() throws IOException {
return in.readInt();
}
OdbcTransfer writeLong(long i) throws IOException {
out.writeLong(i);
return this;
}
long readLong() throws IOException {
return in.readLong();
}
OdbcTransfer writeFloat(float i) throws IOException {
out.writeFloat(i);
return this;
}
float readFloat() throws IOException {
return in.readFloat();
}
OdbcTransfer writeDouble(double i) throws IOException {
out.writeDouble(i);
return this;
}
double readDouble() throws IOException {
return in.readDouble();
}
OdbcTransfer writeString(String s) throws IOException {
if (s == null) {
out.writeInt(-1);
} else {
out.writeInt(s.length());
for(int i=0; i<s.length(); i++) {
out.write(s.charAt(i));
}
}
return this;
}
String readString() throws IOException {
int len = in.readInt();
if (len == -1) {
return null;
}
char[] chars = new char[len];
for(int i=0; i<len; i++) {
chars[i] = (char)in.readByte();
}
return new String(chars);
}
OdbcTransfer writeDate(java.sql.Date x) throws IOException {
if (x == null) {
writeString(null);
} else {
writeString(x.toString());
}
return this;
}
OdbcTransfer writeTime(java.sql.Time x) throws IOException {
if (x == null) {
writeString(null);
} else {
writeString(x.toString());
}
return this;
}
OdbcTransfer writeTimestamp(java.sql.Timestamp x) throws IOException {
if (x == null) {
writeString(null);
} else {
writeString(x.toString());
}
return this;
}
java.sql.Date readDate() throws IOException {
String s = readString();
if (s == null) {
return null;
}
return java.sql.Date.valueOf(s);
}
java.sql.Time readTime() throws IOException {
String s = readString();
if (s == null) {
return null;
}
return java.sql.Time.valueOf(s);
}
java.sql.Timestamp readTimestamp() throws IOException {
String s = readString();
if (s == null) {
return null;
}
return java.sql.Timestamp.valueOf(s);
}
OdbcTransfer writeByteArray(byte[] data) throws IOException {
if (data == null) {
writeInt(-1);
} else {
writeInt(data.length);
}
out.write(data);
return this;
}
byte[] readByteArray() throws IOException {
int len = readInt();
if (len == -1) {
return null;
}
byte[] b = new byte[len];
in.readFully(b);
return b;
}
OdbcTransfer writeIntArray(int[] s) throws IOException {
if (s == null) {
writeInt(-1);
} else {
writeInt(s.length);
for (int i = 0; i < s.length; i++) {
writeInt(s[i]);
}
}
return this;
}
int[] readIntArray() throws IOException {
int len = readInt();
if (len == -1) {
return null;
}
int[] s = new int[len];
for (int i = 0; i < len; i++) {
s[i] = readInt();
}
return s;
}
OdbcTransfer writeStringArray(String[] s) throws IOException {
if (s == null) {
writeInt(-1);
} else {
writeInt(s.length);
for (int i = 0; i < s.length; i++) {
writeString(s[i]);
}
}
return this;
}
String[] readStringArray() throws IOException {
int len = readInt();
if (len == -1) {
return null;
}
String[] s = new String[len];
for (int i = 0; i < len; i++) {
s[i] = readString();
}
return s;
}
// buffer - cannot be null
OdbcTransfer writeBuffer(byte[] buffer) throws IOException {
out.write(buffer);
return this;
}
}
......@@ -38,11 +38,25 @@ public class PgServer implements Service {
private boolean allowOthers;
private boolean ifExists;
public static void main(String[] args) throws Exception {
PgServer app = new PgServer();
app.init(args);
app.start();
app.listen();
public void init(String[] args) throws Exception {
port = DEFAULT_PORT;
for (int i = 0; i < args.length; i++) {
String a = args[i];
if (a.equals("-log")) {
log = Boolean.valueOf(args[++i]).booleanValue();
} else if (a.equals("-pgPort")) {
port = MathUtils.decodeInt(args[++i]);
} else if (a.equals("-baseDir")) {
baseDir = args[++i];
} else if (a.equals("-pgAllowOthers")) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
} else if (a.equals("-ifExists")) {
ifExists = Boolean.valueOf(args[++i]).booleanValue();
}
}
org.h2.Driver.load();
url = "pg://localhost:" + port;
// log = true;
}
boolean getLog() {
......@@ -65,29 +79,6 @@ public class PgServer implements Service {
}
}
public void init(String[] args) throws Exception {
port = DEFAULT_PORT;
for (int i = 0; i < args.length; i++) {
String a = args[i];
if (a.equals("-log")) {
log = Boolean.valueOf(args[++i]).booleanValue();
} else if (a.equals("-pgPort")) {
port = MathUtils.decodeInt(args[++i]);
} else if (a.equals("-baseDir")) {
baseDir = args[++i];
} else if (a.equals("-pgAllowOthers")) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
} else if (a.equals("-ifExists")) {
ifExists = Boolean.valueOf(args[++i]).booleanValue();
}
}
org.h2.Driver.load();
url = "pg://localhost:" + port;
int testing;
log = true;
}
public String getURL() {
return url;
}
......@@ -129,7 +120,7 @@ public class PgServer implements Service {
}
public void stop() {
// TODO server: share code between web and tcp servers
// TODO server: combine with tcp server
if(!stop) {
stop = true;
if(serverSocket != null) {
......@@ -243,7 +234,7 @@ public class PgServer implements Service {
}
public static boolean hasDatabasePrivilege(int id, String privilege) {
return false;
return true;
}
public static boolean hasTablePrivilege(String table, String privilege) {
......
......@@ -26,7 +26,6 @@ import java.sql.Statement;
import java.sql.Types;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Properties;
import org.h2.Driver;
......@@ -37,7 +36,7 @@ import org.h2.util.ScriptReader;
* This class implements a subset of the PostgreSQL protocol as described here:
* http://developer.postgresql.org/pgdocs/postgres/protocol.html
* The PostgreSQL catalog is described here:
* http://www.postgresql.org/docs/7.4/static/view-pg-user.html
* http://www.postgresql.org/docs/7.4/static/catalogs.html
* @author Thomas
*/
......@@ -117,17 +116,6 @@ public class PgServerThread implements Runnable {
}
private void error(String message, Exception e) {
int todoDocumentLimitations;
/*
Limitations:
- The database name can not contains the path (~ or directory).
Workaround: use -baseDir when starting the server.
- SSL is not supported.
- Statements can not be cancelled.
- Metadata is static.
*/
if(e != null) {
server.logError(e);
}
......@@ -154,8 +142,7 @@ Limitations:
server.log("Init");
int version = readInt();
if(version == 80877102) {
int todoSupport;
server.log("CancelRequest");
server.log("CancelRequest (not supported)");
server.log(" pid: "+readInt());
server.log(" key: "+readInt());
error("CancelRequest", null);
......@@ -382,7 +369,6 @@ Limitations:
private String getSQL(String s) {
String lower = s.toLowerCase();
int todo;
if(lower.startsWith("show max_identifier_length")) {
s = "CALL 63";
} else if(lower.startsWith("set client_encoding to")) {
......@@ -458,8 +444,7 @@ Limitations:
if(text) {
s = new String(d2, getEncoding());
} else {
int testing;
System.out.println("binary format!");
server.logError(new SQLException("Binary format not supported"));
s = new String(d2, getEncoding());
}
} catch(Exception e) {
......@@ -483,6 +468,7 @@ Limitations:
writeString(e.getMessage());
write('D');
writeString(e.toString());
write(0);
sendMessage();
}
......@@ -534,7 +520,7 @@ Limitations:
writeString(names[i].toLowerCase());
writeInt(0); // object ID
writeShort(0); // attribute number of the column
writeInt(getType(types[i])); // data type
writeInt(types[i]); // data type
writeShort(getTypeSize(types[i])); // pg_type.typlen
writeInt(getModifier(types[i])); // pg_attribute.atttypmod
writeShort(0); // text
......@@ -546,15 +532,6 @@ Limitations:
}
}
private int getType(int type) {
int testing;
// switch(type) {
// case Types.VARCHAR:
// return 19;
// }
return type;
}
private int getTypeSize(int type) {
switch(type) {
case Types.VARCHAR:
......@@ -590,8 +567,18 @@ Limitations:
}
private void initDb() throws SQLException {
int todoUseVersionOnlyInitWhenRequired;
ResultSet rs = conn.getMetaData().getTables(null, "PG_CATALOG", "PG_VERSION", null);
boolean tableFound = rs.next();
Statement stat = conn.createStatement();
if(tableFound) {
rs = stat.executeQuery("SELECT VERION FROM PG_CATALOG.PG_VERSION");
if(rs.next()) {
if(rs.getInt(1) == 1) {
// already installed
return;
}
}
}
Reader r = new InputStreamReader(getClass().getResourceAsStream("pg_catalog.sql"));
r = new BufferedReader(r);
ScriptReader reader = new ScriptReader(r);
......@@ -604,52 +591,12 @@ Limitations:
}
reader.close();
ResultSet rs = stat.executeQuery("SELECT OID FROM PG_CATALOG.PG_TYPE");
rs = stat.executeQuery("SELECT OID FROM PG_CATALOG.PG_TYPE");
while(rs.next()) {
types.add(new Integer(rs.getInt(1)));
}
}
// private void sendResultSet(ResultSet rs) throws SQLException, IOException {
// ResultSetMetaData meta = rs.getMetaData();
// int columnCount = meta.getColumnCount();
// //
// startMessage('T');
// writeShort(columnCount);
// for(int i=0; i<columnCount; i++) {
// writeString(meta.getColumnName(i + 1));
// writeInt(0); // table id
// writeShort(0); // column id
// writeInt(0); // data type id
// writeShort(26); // data type size (see pg_type.typlen)
// writeInt(4); // type modifier (see pg_attribute.atttypmod)
// writeShort(0); // format code 0=text, 1=binary
// }
// sendMessage();
// while(rs.next()) {
// // DataRow
// startMessage('D');
// writeShort(columnCount);
// for(int i=0; i<columnCount; i++) {
// String v = rs.getString(i + 1);
// if(v == null) {
// writeInt(-1);
// } else {
// byte[] data = v.getBytes();
// writeInt(data.length);
// write(data);
// }
// }
// sendMessage();
// }
//
// // CommandComplete
// startMessage('C');
// writeString("SELECT");
// sendMessage();
// sendReadyForQuery('I');
// }
public void close() {
try {
stop = true;
......
......@@ -6,6 +6,8 @@
drop schema if exists pg_catalog;
create schema pg_catalog;
create table pg_version as select 1 as version;
set search_path = PUBLIC, pg_catalog;
create view pg_catalog.pg_roles -- (oid, rolname, rolcreaterole, rolcreatedb)
......@@ -87,7 +89,9 @@ from information_schema.indexes;
create table pg_catalog.pg_proc(
oid int,
proname varchar_ignorecase
proname varchar_ignorecase,
prorettype int,
pronamespace int
);
create table pg_catalog.pg_trigger(
......
......@@ -31,7 +31,7 @@ import org.h2.util.IOUtils;
import org.h2.util.StartBrowser;
/**
* This tool starts the H2 Console (web-) server, as well as the TCP and ODBC server.
* This tool starts the H2 Console (web-) server, as well as the TCP and PG server.
* For JDK 1.6, a system tray icon is created, for platforms that support it.
* Otherwise, a small window opens.
*
......
......@@ -12,7 +12,6 @@ import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.message.Message;
import org.h2.message.TraceSystem;
import org.h2.server.OdbcServer;
import org.h2.server.Service;
import org.h2.server.TcpServer;
import org.h2.server.ftp.FtpServer;
......@@ -52,10 +51,6 @@ public class Server implements Runnable {
System.out.println("-pgPort <port> (default: " + PgServer.DEFAULT_PORT+")");
System.out.println("-pgAllowOthers [true|false]");
System.out.println("-odbc (start the ODBC Server)");
System.out.println("-odbcPort <port> (default: " + OdbcServer.DEFAULT_PORT+")");
System.out.println("-odbcAllowOthers [true|false]");
System.out.println("-ftp (start the FTP Server)");
System.out.println("-ftpPort <port> (default: " + Constants.DEFAULT_FTP_PORT+")");
System.out.println("-ftpDir <directory> (default: " + FtpServer.DEFAULT_ROOT+", use jdbc:... to access a database)");
......@@ -74,7 +69,7 @@ public class Server implements Runnable {
/**
* The command line interface for this tool.
* The options must be split into strings like this: "-baseDir", "/temp/data",...
* By default, -tcp, -web, -browser and -odbc are started.
* By default, -tcp, -web, -browser and -pg are started.
* If there is a problem starting a service, the program terminates with an exit code of 1.
* The following options are supported:
* <ul>
......@@ -83,7 +78,6 @@ public class Server implements Runnable {
* </li><li>-tcp (start the TCP Server)
* </li><li>-tcpShutdown {url} (shutdown the running TCP Server, URL example: tcp://localhost:9094)
* </li><li>-pg (start the PG Server)
* </li><li>-odbc (start the ODBC Server)
* </li><li>-browser (start a browser and open a page to connect to the Web Server)
* </li><li>-log [true|false] (enable or disable logging)
* </li><li>-baseDir {directory} (sets the base directory for database files; not for H2 Console)
......@@ -102,8 +96,6 @@ public class Server implements Runnable {
* </li><li>-tcpShutdownForce [true|false] (don't wait for other connections to close)
* </li><li>-pgPort {port} (the port of PG Server, default: 5435)
* </li><li>-pgAllowOthers [true|false] (enable/disable remote connections)
* </li><li>-odbcPort {port} (the port of ODBC Server, default: 9083)
* </li><li>-odbcAllowOthers [true|false] (enable/disable remote connections)
* </li><li>-ftpPort {port}
* </li><li>-ftpDir {directory}
* </li><li>-ftpRead {readUserName}
......@@ -122,7 +114,7 @@ public class Server implements Runnable {
}
private int run(String[] args) throws SQLException {
boolean tcpStart = false, odbcStart = false, pgStart = false, webStart = false, ftpStart = false;
boolean tcpStart = false, pgStart = false, webStart = false, ftpStart = false;
boolean browserStart = false;
boolean tcpShutdown = false, tcpShutdownForce = false;
String tcpPassword = "";
......@@ -136,9 +128,6 @@ public class Server implements Runnable {
} else if(a.equals("-web")) {
startDefaultServers = false;
webStart = true;
} else if(a.equals("-odbc")) {
startDefaultServers = false;
odbcStart = true;
} else if(a.equals("-tcp")) {
startDefaultServers = false;
tcpStart = true;
......@@ -165,7 +154,6 @@ public class Server implements Runnable {
if(startDefaultServers) {
tcpStart = true;
pgStart = true;
odbcStart = false;
webStart = true;
browserStart = true;
}
......@@ -196,17 +184,6 @@ public class Server implements Runnable {
}
System.out.println(pg.getStatus());
}
if(odbcStart) {
Server odbc = createOdbcServer(args);
try {
odbc.start();
} catch(SQLException e) {
// ignore (status is displayed)
e.printStackTrace();
exitCode = EXIT_ERROR;
}
System.out.println(odbc.getStatus());
}
if(webStart) {
Server web = createWebServer(args);
try {
......@@ -341,15 +318,6 @@ public class Server implements Runnable {
return new Server("H2 TCP Server", new TcpServer(), args);
}
/**
* Create a new ODBC server, but does not start it yet.
* @param args
* @return the server
*/
public static Server createOdbcServer(String[] args) throws SQLException {
return new Server("H2 ODBC Server", new OdbcServer(), args);
}
/**
* Create a new PG server, but does not start it yet.
* @param args
......
......@@ -17,7 +17,7 @@ public class Cache2Q implements Cache {
public static final String TYPE_NAME = "TQ";
private static final int MAIN = 1, IN = 2, OUT = 3;
private final static int PERCENT_IN = 20, PERCENT_OUT = 50;
private static final int PERCENT_IN = 20, PERCENT_OUT = 50;
private final CacheWriter writer;
private int maxSize;
......@@ -160,12 +160,16 @@ public class Cache2Q implements Cache {
int i=0;
ObjectArray changed = new ObjectArray();
while (((sizeIn*4 > maxIn*3) || (sizeOut*4 > maxOut*3) || (sizeMain*4 > maxMain*3)) && recordCount > Constants.CACHE_MIN_RECORDS) {
if(i++ >= recordCount) {
i++;
if(i == recordCount) {
writer.flushLog();
}
if(i >= recordCount * 2) {
// can't remove any record, because the log is not written yet
// hopefully this does not happen too much, but it could happen theoretically
// TODO log this
break;
}
}
if (sizeIn > maxIn) {
CacheObject r = headIn.next;
if(!r.canRemove()) {
......
......@@ -90,23 +90,17 @@ public class CacheLRU implements Cache {
int i=0;
ObjectArray changed = new ObjectArray();
while (sizeMemory*4 > maxSize*3 && recordCount > Constants.CACHE_MIN_RECORDS) {
CacheObject last = head.next;
i++;
if(i == recordCount) {
int testing;
int todoCopyTo2Q;
System.out.println("flush log");
writer.flushLog();
}
if(i >= recordCount * 2) {
// can't remove any record, because the log is not written yet
// hopefully this does not happen too much, but it could happen theoretically
// TODO log this
System.out.println("can not shrink cache");
break;
}
CacheObject last = head.next;
if(Constants.CHECK && last == head) {
throw Message.getInternalError("try to remove head");
}
......
......@@ -230,7 +230,6 @@ public class DataType {
}
Value.getOrder(i);
}
// TODO data types: try to support other types as well (longvarchar for odbc/access,...) - maybe map them to regular types?
}
private static void add(int type, int sqlType, String jdbc, DataType dataType, String[] names, int memory) {
......
......@@ -201,7 +201,7 @@ CREATE TABLE TEST( ID BIGINT PRIMARY KEY, CREATED TIMESTAMP);
INSERT INTO TEST VALUES(1, '2007-01-01 00:00:00');
SELECT * FROM TEST;
Server: use one listener (detect if the request comes from an ODBC or TCP client).
Server: use one listener (detect if the request comes from an PG or TCP client).
PMD
......
db2 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;LOCK_MODE=3;CIPHER=XTEA, sa, sa 123
xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;LOCK_MODE=3;CIPHER=AES, sa, sa 123
xdb4 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3;write_mode_log=rws;write_delay=0, sa, sa
db1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
db1 = H2_PG, org.postgresql.Driver, jdbc:postgresql://localhost:5435/h2test, sa, sa
xdb2 = HSQLDB, org.hsqldb.jdbcDriver, jdbc:hsqldb:data/test;hsqldb.default_table_type=cached;sql.enforce_size=true, sa
#xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;LOCK_MODE=3;CIPHER=XTEA, sa, sa 123
#xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;LOCK_MODE=3;CIPHER=AES, sa, sa 123
#xdb4 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3;write_mode_log=rws;write_delay=0, sa, sa
#xdb5 = H2_PG, org.postgresql.Driver, jdbc:postgresql://localhost:5435/h2test, sa, sa
db2 = HSQLDB, org.hsqldb.jdbcDriver, jdbc:hsqldb:data/test;hsqldb.default_table_type=cached;sql.enforce_size=true, sa
db3 = Derby, org.apache.derby.jdbc.EmbeddedDriver, jdbc:derby:data/test;create=true, sa, sa
db4 = H2, org.h2.Driver, jdbc:h2:tcp://localhost/data/testServer;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
......@@ -30,5 +30,4 @@ oracle.datetime = TIMESTAMP
#test3 = org.h2.test.bench.BenchB
test1 = org.h2.test.bench.BenchC
#size = 400
size = 10
\ No newline at end of file
size = 400
......@@ -7,7 +7,6 @@ package org.h2.test.db;
import java.sql.Connection;
import java.sql.Statement;
import org.h2.engine.Constants;
import org.h2.test.TestBase;
import org.h2.tools.Restore;
......
call timestamp '2007-07-26 18:44:26.109000 +02:00';
> 1;
select timestamp '2007-07-26 18:44:26.109000 +02:00';
> 2007-07-26 18:44:26.109;
create table test(id int primary key);
begin;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论