提交 2ab24ddf authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 6971da7a
...@@ -37,7 +37,10 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -37,7 +37,10 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / TODO (Build TODO)</h3><ul> <h3>Version 1.0 / TODO (Build TODO)</h3><ul>
<li>PostgreSQL compatibility: SET SEARCH_PATH, SERIAL, CURRENT_USER, E'text', $1. <li>Support for the system property baseDir. This works for embedded databases as well. The setting is supported
by the H2 Console using -Dh2.baseDir or -baseDir
</li><li>LIKE ESCAPE did not work correctly if the pattern was % or _, followed by an escape character, followed by %. Fixed.
</li><li>PostgreSQL compatibility: SET SEARCH_PATH, SERIAL, CURRENT_USER, E'text', $1.
</li><li>In some situations, when many tables with LOB columns were modified (ALTER TABLE), large objects were deleted. Fixed. </li><li>In some situations, when many tables with LOB columns were modified (ALTER TABLE), large objects were deleted. Fixed.
</li><li>CREATE TABLE AS SELECT .. UNION .. did not work. Fixed. </li><li>CREATE TABLE AS SELECT .. UNION .. did not work. Fixed.
</li><li>New column ID for INFORMATION_SCHEMA.INDEXES, SEQUENCES, USERS, ROLES, RIGHTS, </li><li>New column ID for INFORMATION_SCHEMA.INDEXES, SEQUENCES, USERS, ROLES, RIGHTS,
...@@ -783,13 +786,14 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -783,13 +786,14 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Priority 2</h3> <h3>Priority 2</h3>
<ul> <ul>
<li>Support OSGi: http://oscar-osgi.sourceforge.net, http://incubator.apache.org/felix/index.html <li>Support OSGi: http://oscar-osgi.sourceforge.net, http://incubator.apache.org/felix/index.html
</li><li>Set the database in an 'exclusive' mode (restrict to one user at a time)
</li><li>Clustering: recovery needs to becomes fully automatic. Global write lock feature. </li><li>Clustering: recovery needs to becomes fully automatic. Global write lock feature.
</li><li>System table / function: cache usage </li><li>System table / function: cache usage
</li><li>Connection pool manager </li><li>User defined aggregate functions
</li><li>Set the database in an 'exclusive' mode (restrict to one user at a time)
</li><li>Add a migration guide (list differences between databases) </li><li>Add a migration guide (list differences between databases)
</li><li>Optimization: automatic index creation suggestion using the trace file? </li><li>Optimization: automatic index creation suggestion using the trace file?
</li><li>Compression performance: don't allocate buffers, compress / expand in to out buffer </li><li>Compression performance: don't allocate buffers, compress / expand in to out buffer
</li><li>Connection pool manager
</li><li>Start / stop server with database URL </li><li>Start / stop server with database URL
</li><li>Rebuild index functionality (other than delete the index file) </li><li>Rebuild index functionality (other than delete the index file)
</li><li>Don't use deleteOnExit (bug 4513817: File.deleteOnExit consumes memory) </li><li>Don't use deleteOnExit (bug 4513817: File.deleteOnExit consumes memory)
...@@ -975,8 +979,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -975,8 +979,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Shrink the data file without closing the database (if the end of the file is empty) </li><li>Shrink the data file without closing the database (if the end of the file is empty)
</li><li>Delay reading the row if data is not required </li><li>Delay reading the row if data is not required
</li><li>Eliminate undo log records if stored on disk (just one pointer per block, not per record) </li><li>Eliminate undo log records if stored on disk (just one pointer per block, not per record)
</li><li>User defined aggregate functions
</li><li>System property for base directory (h2.baseDir) in embedded mode
</li><li>Feature matrix like here: http://www.inetsoftware.de/products/jdbc/mssql/features/default.asp. </li><li>Feature matrix like here: http://www.inetsoftware.de/products/jdbc/mssql/features/default.asp.
</li><li>Updatable result set on table without primary key or unique index </li><li>Updatable result set on table without primary key or unique index
</li><li>Use LinkedList instead of ArrayList where applicable </li><li>Use LinkedList instead of ArrayList where applicable
...@@ -1033,6 +1035,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -1033,6 +1035,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Support triggers with a string property or option: SpringTrigger, OSGITrigger </li><li>Support triggers with a string property or option: SpringTrigger, OSGITrigger
</li><li>Clustering: adding a node should be very fast and without interrupting clients (very short lock) </li><li>Clustering: adding a node should be very fast and without interrupting clients (very short lock)
</li><li>Updatable result sets: DatabaseMetaData.ownUpdatesAreVisible = true </li><li>Updatable result sets: DatabaseMetaData.ownUpdatesAreVisible = true
</li><li>Cache size should be in KB
</li></ul> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -24,8 +24,7 @@ import org.h2.message.TraceSystem; ...@@ -24,8 +24,7 @@ import org.h2.message.TraceSystem;
*/ */
public class Driver implements java.sql.Driver { public class Driver implements java.sql.Driver {
// TODO server: maybe start/stop a server using DriverManager.getConnection ? private static final Driver instance = new Driver();
private static Driver instance = new Driver();
static { static {
try { try {
......
...@@ -19,11 +19,11 @@ import org.h2.util.ObjectArray; ...@@ -19,11 +19,11 @@ import org.h2.util.ObjectArray;
* @author Thomas * @author Thomas
*/ */
public abstract class Command implements CommandInterface { public abstract class Command implements CommandInterface {
protected Session session; private final String sql;
protected final Session session;
protected final Trace trace;
protected long startTime; protected long startTime;
protected Trace trace;
private volatile boolean cancel; private volatile boolean cancel;
private final String sql;
public abstract boolean isTransactional(); public abstract boolean isTransactional();
public abstract boolean isQuery(); public abstract boolean isQuery();
......
...@@ -11,8 +11,8 @@ import org.h2.util.ObjectArray; ...@@ -11,8 +11,8 @@ import org.h2.util.ObjectArray;
public class CommandList extends Command { public class CommandList extends Command {
private Command command; private final Command command;
private String remaining; private final String remaining;
// TODO lock if possible! // TODO lock if possible!
......
...@@ -20,14 +20,14 @@ import org.h2.value.Transfer; ...@@ -20,14 +20,14 @@ import org.h2.value.Transfer;
public class CommandRemote implements CommandInterface { public class CommandRemote implements CommandInterface {
private final ObjectArray transferList;
private final ObjectArray parameters;
private final Trace trace;
private final String sql;
private SessionRemote session; private SessionRemote session;
private ObjectArray transferList;
private int id; private int id;
private boolean isQuery; private boolean isQuery;
private boolean readonly; private boolean readonly;
private ObjectArray parameters;
private Trace trace;
private String sql;
private int paramCount; private int paramCount;
public CommandRemote(SessionRemote session, ObjectArray transferList, String sql) throws SQLException { public CommandRemote(SessionRemote session, ObjectArray transferList, String sql) throws SQLException {
......
...@@ -147,6 +147,9 @@ public class Parser { ...@@ -147,6 +147,9 @@ public class Parser {
private static final int CURRENT_TIMESTAMP = 42, CURRENT_DATE = 43, CURRENT_TIME = 44, ROWNUM = 45; private static final int CURRENT_TIMESTAMP = 42, CURRENT_DATE = 43, CURRENT_TIME = 44, ROWNUM = 45;
private final Database database;
private final Session session;
private int[] characterTypes; private int[] characterTypes;
private int currentTokenType; private int currentTokenType;
private String currentToken; private String currentToken;
...@@ -159,8 +162,6 @@ public class Parser { ...@@ -159,8 +162,6 @@ public class Parser {
private Prepared prepared; private Prepared prepared;
private Prepared currentPrepared; private Prepared currentPrepared;
private Select currentSelect; private Select currentSelect;
private Session session;
private Database database;
private ObjectArray parameters; private ObjectArray parameters;
private String schemaName; private String schemaName;
private ObjectArray expected; private ObjectArray expected;
......
...@@ -17,9 +17,9 @@ import org.h2.util.ObjectArray; ...@@ -17,9 +17,9 @@ import org.h2.util.ObjectArray;
public abstract class Prepared { public abstract class Prepared {
protected Session session;
protected String sql; protected String sql;
protected int headPos = -1; protected int headPos = -1;
protected Session session;
protected ObjectArray parameters; protected ObjectArray parameters;
private long modificationId; private long modificationId;
private Command command; private Command command;
...@@ -27,6 +27,11 @@ public abstract class Prepared { ...@@ -27,6 +27,11 @@ public abstract class Prepared {
protected boolean prepareAlways; protected boolean prepareAlways;
private int currentRowNumber; private int currentRowNumber;
public Prepared(Session session) {
this.session = session;
modificationId = session.getDatabase().getModificationMetaId();
}
public boolean needRecompile() throws SQLException { public boolean needRecompile() throws SQLException {
Database db = session.getDatabase(); Database db = session.getDatabase();
if(db == null) { if(db == null) {
...@@ -42,11 +47,6 @@ public abstract class Prepared { ...@@ -42,11 +47,6 @@ public abstract class Prepared {
return false; return false;
} }
public Prepared(Session session) {
this.session = session;
modificationId = session.getDatabase().getModificationMetaId();
}
long getModificationId() { long getModificationId() {
return modificationId; return modificationId;
} }
......
...@@ -258,9 +258,21 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -258,9 +258,21 @@ public class AlterTableAlterColumn extends SchemaCommand {
newTable.addRow(newRow); newTable.addRow(newRow);
} }
*/ */
StringBuffer buff = new StringBuffer();
String sql = "INSERT INTO " + newTable.getSQL() + "(" + columnList+") " buff.append("INSERT INTO ");
+ "SELECT " + columnList + " FROM " + table.getSQL(); buff.append(newTable.getSQL());
buff.append("(");
buff.append(columnList);
buff.append(") SELECT ");
if (columnList.length() == 0) {
// special case insert into test select * from test
buff.append("*");
} else {
buff.append(columnList);
}
buff.append(" FROM ");
buff.append(table.getSQL());
String sql = buff.toString();
newTable.setCheckForeignKeyConstraints(false); newTable.setCheckForeignKeyConstraints(false);
try { try {
execute(sql); execute(sql);
......
...@@ -24,9 +24,7 @@ public class PrepareProcedure extends DefineCommand { ...@@ -24,9 +24,7 @@ public class PrepareProcedure extends DefineCommand {
} }
public int update() throws SQLException { public int update() throws SQLException {
Procedure proc = new Procedure(); Procedure proc = new Procedure(procedureName, prepared);
proc.setName(procedureName);
proc.setPrepared(prepared);
prepared.setParameterList(parameters); prepared.setParameterList(parameters);
prepared.setPrepareAlways(prepareAlways); prepared.setPrepareAlways(prepareAlways);
prepared.prepare(); prepared.prepare();
......
...@@ -11,7 +11,7 @@ import org.h2.schema.Schema; ...@@ -11,7 +11,7 @@ import org.h2.schema.Schema;
public abstract class SchemaCommand extends DefineCommand { public abstract class SchemaCommand extends DefineCommand {
private Schema schema; private final Schema schema;
public SchemaCommand(Session session, Schema schema) { public SchemaCommand(Session session, Schema schema) {
super(session); super(session);
......
...@@ -9,7 +9,7 @@ import java.io.InputStream; ...@@ -9,7 +9,7 @@ import java.io.InputStream;
public class LZFInputStream extends InputStream { public class LZFInputStream extends InputStream {
private InputStream in; private final InputStream in;
private CompressLZF decompress = new CompressLZF(); private CompressLZF decompress = new CompressLZF();
private int pos; private int pos;
private int bufferLength; private int bufferLength;
......
...@@ -12,11 +12,12 @@ import org.h2.engine.Constants; ...@@ -12,11 +12,12 @@ import org.h2.engine.Constants;
public class LZFOutputStream extends OutputStream { public class LZFOutputStream extends OutputStream {
static final int MAGIC = ('H' << 24) | ('2' << 16) | ('I' << 8) | 'S'; static final int MAGIC = ('H' << 24) | ('2' << 16) | ('I' << 8) | 'S';
private OutputStream out;
private byte[] buffer; private final OutputStream out;
private final CompressLZF compress = new CompressLZF();
private final byte[] buffer;
private int pos; private int pos;
private byte[] outBuffer; private byte[] outBuffer;
private CompressLZF compress = new CompressLZF();
public LZFOutputStream(OutputStream out) throws IOException { public LZFOutputStream(OutputStream out) throws IOException {
this.out = out; this.out = out;
......
...@@ -21,8 +21,8 @@ import org.h2.table.Table; ...@@ -21,8 +21,8 @@ import org.h2.table.Table;
*/ */
public abstract class Constraint extends SchemaObject { public abstract class Constraint extends SchemaObject {
protected Table table;
public static final String CHECK = "CHECK", REFERENTIAL = "REFERENTIAL", UNIQUE = "UNIQUE"; public static final String CHECK = "CHECK", REFERENTIAL = "REFERENTIAL", UNIQUE = "UNIQUE";
protected Table table;
public Constraint(Schema schema, int id, String name, Table table) { public Constraint(Schema schema, int id, String name, Table table) {
super(schema, id, name, Trace.CONSTRAINT); super(schema, id, name, Trace.CONSTRAINT);
......
...@@ -13,8 +13,8 @@ import org.h2.util.StringUtils; ...@@ -13,8 +13,8 @@ import org.h2.util.StringUtils;
public class Comment extends DbObject { public class Comment extends DbObject {
private int objectType; private final int objectType;
private String objectName; private final String objectName;
private String commentText; private String commentText;
public Comment(Database database, int id, DbObject obj) { public Comment(Database database, int id, DbObject obj) {
......
...@@ -19,16 +19,16 @@ import org.h2.util.StringUtils; ...@@ -19,16 +19,16 @@ import org.h2.util.StringUtils;
public class ConnectionInfo { public class ConnectionInfo {
private static final HashSet KNOWN_SETTINGS = new HashSet();
private final Properties prop = new Properties();
private String originalURL; private String originalURL;
private String url; private String url;
private Properties prop = new Properties();
private String user; private String user;
private byte[] filePasswordHash; private byte[] filePasswordHash;
private byte[] userPasswordHash; private byte[] userPasswordHash;
private String name; private String name;
private static HashSet KNOWN_SETTINGS = new HashSet();
private boolean remote; private boolean remote;
private boolean ssl; private boolean ssl;
private boolean persistent; private boolean persistent;
......
...@@ -251,7 +251,15 @@ public class Constants { ...@@ -251,7 +251,15 @@ public class Constants {
public static final int CACHE_SIZE_DEFAULT = getIntSetting("h2.cacheSizeDefault", (1 << 16)); public static final int CACHE_SIZE_DEFAULT = getIntSetting("h2.cacheSizeDefault", (1 << 16));
public static final int CACHE_SIZE_INDEX_SHIFT = getIntSetting("h2.cacheSizeIndexShift", 3); public static final int CACHE_SIZE_INDEX_SHIFT = getIntSetting("h2.cacheSizeIndexShift", 3);
public static final int CACHE_SIZE_INDEX_DEFAULT = CACHE_SIZE_DEFAULT >> CACHE_SIZE_INDEX_SHIFT; public static final int CACHE_SIZE_INDEX_DEFAULT = CACHE_SIZE_DEFAULT >> CACHE_SIZE_INDEX_SHIFT;
public static String BASE_DIR = getStringSetting("h2.baseDir", null);
public static void setBaseDir(String dir) {
if(!dir.endsWith("/")) {
dir += "/";
}
BASE_DIR = dir;
}
public static boolean getBooleanSetting(String name, boolean defaultValue) { public static boolean getBooleanSetting(String name, boolean defaultValue) {
String s = System.getProperty(name); String s = System.getProperty(name);
if(s != null) { if(s != null) {
......
...@@ -68,27 +68,33 @@ import org.h2.value.ValueInt; ...@@ -68,27 +68,33 @@ import org.h2.value.ValueInt;
*/ */
public class Database implements DataHandler { public class Database implements DataHandler {
private final boolean persistent;
private final String databaseName;
private final String databaseShortName;
private final String databaseURL;
private final String cipher;
private final byte[] filePasswordHash;
private final HashMap roles = new HashMap();
private final HashMap users = new HashMap();
private final HashMap settings = new HashMap();
private final HashMap schemas = new HashMap();
private final HashMap rights = new HashMap();
private final HashMap functionAliases = new HashMap();
private final HashMap userDataTypes = new HashMap();
private final HashMap comments = new HashMap();
private final HashSet sessions = new HashSet();
private final BitField objectIds = new BitField();
private final Object lobSyncObject = new Object();
private boolean textStorage; private boolean textStorage;
private String databaseName;
private String databaseShortName;
private String databaseURL;
private HashMap roles = new HashMap();
private HashMap users = new HashMap();
private HashMap settings = new HashMap();
private HashMap schemas = new HashMap();
private HashMap rights = new HashMap();
private HashMap functionAliases = new HashMap();
private HashMap userDataTypes = new HashMap();
private HashMap comments = new HashMap();
private Schema mainSchema; private Schema mainSchema;
private Schema infoSchema; private Schema infoSchema;
private int nextSessionId; private int nextSessionId;
private HashSet sessions = new HashSet();
private User systemUser; private User systemUser;
private Session systemSession; private Session systemSession;
private TableData meta; private TableData meta;
private Index metaIdIndex; private Index metaIdIndex;
private BitField objectIds = new BitField();
private FileLock lock; private FileLock lock;
private LogSystem log; private LogSystem log;
private WriterThread writer; private WriterThread writer;
...@@ -96,9 +102,6 @@ public class Database implements DataHandler { ...@@ -96,9 +102,6 @@ public class Database implements DataHandler {
private boolean starting; private boolean starting;
private DiskFile fileData, fileIndex; private DiskFile fileData, fileIndex;
private TraceSystem traceSystem; private TraceSystem traceSystem;
private boolean persistent;
private String cipher;
private byte[] filePasswordHash;
private DataPage dummy; private DataPage dummy;
private int fileLockMethod; private int fileLockMethod;
private Role publicRole; private Role publicRole;
...@@ -133,9 +136,68 @@ public class Database implements DataHandler { ...@@ -133,9 +136,68 @@ public class Database implements DataHandler {
private boolean optimizeReuseResults = true; private boolean optimizeReuseResults = true;
private String cacheType; private String cacheType;
private boolean indexSummaryValid = true; private boolean indexSummaryValid = true;
private Object lobSyncObject = new Object();
private String accessModeLog, accessModeData; private String accessModeLog, accessModeData;
public Database(String name, ConnectionInfo ci, String cipher) throws SQLException {
this.compareMode = new CompareMode(null, null);
this.persistent = ci.isPersistent();
this.filePasswordHash = ci.getFilePasswordHash();
this.databaseName = name;
this.databaseShortName = parseDatabaseShortName();
this.cipher = cipher;
String lockMethodName = ci.removeProperty("FILE_LOCK", null);
this.accessModeLog = ci.removeProperty("ACCESS_MODE_LOG", "rw").toLowerCase();
this.accessModeData = ci.removeProperty("ACCESS_MODE_DATA", "rw").toLowerCase();
this.fileLockMethod = FileLock.getFileLockMethod(lockMethodName);
this.textStorage = ci.getTextStorage();
this.databaseURL = ci.getURL();
String listener = ci.removeProperty("DATABASE_EVENT_LISTENER", null);
if(listener != null) {
if(listener.startsWith("'")) {
listener = listener.substring(1);
}
if(listener.endsWith("'")) {
listener = listener.substring(0, listener.length()-1);
}
setEventListener(listener);
}
String log = ci.getProperty(SetTypes.LOG, null);
if(log != null) {
this.logIndexChanges = log.equals("2");
}
String ignoreSummary = ci.getProperty("RECOVER", null);
if(ignoreSummary != null) {
this.recovery = true;
}
boolean closeAtVmShutdown = ci.removeProperty("DB_CLOSE_ON_EXIT", true);
int traceLevelFile = ci.getIntProperty(SetTypes.TRACE_LEVEL_FILE, TraceSystem.DEFAULT_TRACE_LEVEL_FILE);
int traceLevelSystemOut = ci.getIntProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT, TraceSystem.DEFAULT_TRACE_LEVEL_SYSTEM_OUT);
this.cacheType = StringUtils.toUpperEnglish(ci.removeProperty("CACHE_TYPE", CacheLRU.TYPE_NAME));
try {
synchronized(this) {
open(traceLevelFile, traceLevelSystemOut);
}
if(closeAtVmShutdown) {
DatabaseCloser closeOnExit = new DatabaseCloser(this, 0, true);
try {
Runtime.getRuntime().addShutdownHook(closeOnExit);
} catch(IllegalStateException e) {
// shutdown in progress - just don't register the handler
// (maybe an application wants to write something into a database at shutdown time)
}
}
} catch(Throwable e) {
if(traceSystem != null) {
traceSystem.getTrace(Trace.DATABASE).error("opening " + databaseName, e);
traceSystem.close();
}
synchronized(this) {
closeOpenFilesAndUnlock();
}
throw Message.convert(e);
}
}
public static void setInitialPowerOffCount(int count) { public static void setInitialPowerOffCount(int count) {
initialPowerOffCount = count; initialPowerOffCount = count;
} }
...@@ -340,66 +402,6 @@ public class Database implements DataHandler { ...@@ -340,66 +402,6 @@ public class Database implements DataHandler {
return StringUtils.toUpperEnglish(n); return StringUtils.toUpperEnglish(n);
} }
public Database(String name, ConnectionInfo ci, String cipher) throws SQLException {
this.compareMode = new CompareMode(null, null);
this.persistent = ci.isPersistent();
this.filePasswordHash = ci.getFilePasswordHash();
this.databaseName = name;
this.databaseShortName = parseDatabaseShortName();
this.cipher = cipher;
String lockMethodName = ci.removeProperty("FILE_LOCK", null);
this.accessModeLog = ci.removeProperty("ACCESS_MODE_LOG", "rw").toLowerCase();
this.accessModeData = ci.removeProperty("ACCESS_MODE_DATA", "rw").toLowerCase();
this.fileLockMethod = FileLock.getFileLockMethod(lockMethodName);
this.textStorage = ci.getTextStorage();
this.databaseURL = ci.getURL();
String listener = ci.removeProperty("DATABASE_EVENT_LISTENER", null);
if(listener != null) {
if(listener.startsWith("'")) {
listener = listener.substring(1);
}
if(listener.endsWith("'")) {
listener = listener.substring(0, listener.length()-1);
}
setEventListener(listener);
}
String log = ci.getProperty(SetTypes.LOG, null);
if(log != null) {
this.logIndexChanges = log.equals("2");
}
String ignoreSummary = ci.getProperty("RECOVER", null);
if(ignoreSummary != null) {
this.recovery = true;
}
boolean closeAtVmShutdown = ci.removeProperty("DB_CLOSE_ON_EXIT", true);
int traceLevelFile = ci.getIntProperty(SetTypes.TRACE_LEVEL_FILE, TraceSystem.DEFAULT_TRACE_LEVEL_FILE);
int traceLevelSystemOut = ci.getIntProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT, TraceSystem.DEFAULT_TRACE_LEVEL_SYSTEM_OUT);
this.cacheType = StringUtils.toUpperEnglish(ci.removeProperty("CACHE_TYPE", CacheLRU.TYPE_NAME));
try {
synchronized(this) {
open(traceLevelFile, traceLevelSystemOut);
}
if(closeAtVmShutdown) {
DatabaseCloser closeOnExit = new DatabaseCloser(this, 0, true);
try {
Runtime.getRuntime().addShutdownHook(closeOnExit);
} catch(IllegalStateException e) {
// shutdown in progress - just don't register the handler
// (maybe an application wants to write something into a database at shutdown time)
}
}
} catch(Throwable e) {
if(traceSystem != null) {
traceSystem.getTrace(Trace.DATABASE).error("opening " + databaseName, e);
traceSystem.close();
}
synchronized(this) {
closeOpenFilesAndUnlock();
}
throw Message.convert(e);
}
}
private void open(int traceLevelFile, int traceLevelSystemOut) throws SQLException { private void open(int traceLevelFile, int traceLevelSystemOut) throws SQLException {
if(persistent) { if(persistent) {
String dataFileName = databaseName + Constants.SUFFIX_DATA_FILE; String dataFileName = databaseName + Constants.SUFFIX_DATA_FILE;
......
...@@ -7,9 +7,10 @@ package org.h2.engine; ...@@ -7,9 +7,10 @@ package org.h2.engine;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
public class DatabaseCloser extends Thread { public class DatabaseCloser extends Thread {
private final boolean shutdownHook;
private WeakReference databaseRef; private WeakReference databaseRef;
private int delayInMillis; private int delayInMillis;
private boolean shutdownHook;
DatabaseCloser(Database db, int delayInMillis, boolean shutdownHook) { DatabaseCloser(Database db, int delayInMillis, boolean shutdownHook) {
this.databaseRef = new WeakReference(db); this.databaseRef = new WeakReference(db);
......
...@@ -17,54 +17,19 @@ import org.h2.util.ObjectArray; ...@@ -17,54 +17,19 @@ import org.h2.util.ObjectArray;
*/ */
public abstract class DbObject { public abstract class DbObject {
public static final int TABLE_OR_VIEW=0, INDEX=1, USER=2, SEQUENCE=3, TRIGGER=4; public static final int TABLE_OR_VIEW=0, INDEX=1, USER=2, SEQUENCE=3, TRIGGER=4;
public static final int CONSTRAINT = 5, SETTING = 6, ROLE = 7, RIGHT = 8, FUNCTION_ALIAS = 9; public static final int CONSTRAINT = 5, SETTING = 6, ROLE = 7, RIGHT = 8, FUNCTION_ALIAS = 9;
public static final int SCHEMA = 10, CONSTANT = 11; public static final int SCHEMA = 10, CONSTANT = 11;
public static final int USER_DATATYPE = 12, COMMENT = 13; public static final int USER_DATATYPE = 12, COMMENT = 13;
protected String comment;
static int getCreateOrder(int type) {
switch(type) {
case SETTING:
return 0;
case USER:
return 1;
case SCHEMA:
return 2;
case USER_DATATYPE:
return 3;
case SEQUENCE:
return 4;
case CONSTANT:
return 5;
case FUNCTION_ALIAS:
return 6;
case TABLE_OR_VIEW:
return 7;
case INDEX:
return 8;
case CONSTRAINT:
return 9;
case TRIGGER:
return 10;
case ROLE:
return 11;
case RIGHT:
return 12;
case COMMENT:
return 13;
default:
throw Message.getInternalError("type="+type);
}
}
private int id; private int id;
protected Database database; protected Database database;
protected Trace trace; protected Trace trace;
private String objectName; private String objectName;
private long modificationId; private long modificationId;
private boolean temporary; private boolean temporary;
protected String comment;
protected DbObject(Database database, int id, String name, String traceModule) { protected DbObject(Database database, int id, String name, String traceModule) {
this.database = database; this.database = database;
...@@ -148,4 +113,39 @@ public abstract class DbObject { ...@@ -148,4 +113,39 @@ public abstract class DbObject {
return comment; return comment;
} }
static int getCreateOrder(int type) {
switch(type) {
case SETTING:
return 0;
case USER:
return 1;
case SCHEMA:
return 2;
case USER_DATATYPE:
return 3;
case SEQUENCE:
return 4;
case CONSTANT:
return 5;
case FUNCTION_ALIAS:
return 6;
case TABLE_OR_VIEW:
return 7;
case INDEX:
return 8;
case CONSTRAINT:
return 9;
case TRIGGER:
return 10;
case ROLE:
return 11;
case RIGHT:
return 12;
case COMMENT:
return 13;
default:
throw Message.getInternalError("type="+type);
}
}
} }
...@@ -20,8 +20,8 @@ import org.h2.util.StringUtils; ...@@ -20,8 +20,8 @@ import org.h2.util.StringUtils;
public class Engine { public class Engine {
// TODO use a 'engine'/'master' database to allow shut down the server, view & kill sessions and so on // TODO use a 'engine'/'master' database to allow shut down the server, view & kill sessions and so on
private HashMap databases = new HashMap(); private static final Engine instance = new Engine();
private static Engine instance = new Engine(); private final HashMap databases = new HashMap();
private Engine() { private Engine() {
// don't allow others to instantiate // don't allow others to instantiate
......
...@@ -20,12 +20,12 @@ import org.h2.value.ValueNull; ...@@ -20,12 +20,12 @@ import org.h2.value.ValueNull;
public class FunctionAlias extends DbObject { public class FunctionAlias extends DbObject {
private boolean hasConnectionParam;
private String className; private String className;
private String methodName; private String methodName;
private Method javaMethod; private Method javaMethod;
private int paramCount; private int paramCount;
private boolean hasConnectionParam; private final int dataType;
private int dataType;
public FunctionAlias(Database db, int id, String name, String javaClassMethod) throws SQLException { public FunctionAlias(Database db, int id, String name, String javaClassMethod) throws SQLException {
super(db, id, name, Trace.FUNCTION); super(db, id, name, Trace.FUNCTION);
......
...@@ -17,6 +17,7 @@ import org.h2.value.ValueInt; ...@@ -17,6 +17,7 @@ import org.h2.value.ValueInt;
import org.h2.value.ValueString; import org.h2.value.ValueString;
public class MetaRecord { public class MetaRecord {
private int id; private int id;
private int objectType; private int objectType;
private int headPos; private int headPos;
......
...@@ -7,21 +7,19 @@ package org.h2.engine; ...@@ -7,21 +7,19 @@ package org.h2.engine;
import org.h2.command.Prepared; import org.h2.command.Prepared;
public class Procedure { public class Procedure {
private String name;
private Prepared prepared; private final String name;
private final Prepared prepared;
public void setName(String name) { public Procedure(String name, Prepared prepared) {
this.name = name; this.name = name;
this.prepared = prepared;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setPrepared(Prepared prepared) {
this.prepared = prepared;
}
public Prepared getPrepared() { public Prepared getPrepared() {
return prepared; return prepared;
} }
......
...@@ -13,7 +13,7 @@ import org.h2.util.ObjectArray; ...@@ -13,7 +13,7 @@ import org.h2.util.ObjectArray;
public class Role extends RightOwner { public class Role extends RightOwner {
private boolean system; private final boolean system;
public Role(Database database, int id, String roleName, boolean system) { public Role(Database database, int id, String roleName, boolean system) {
super(database, id, roleName, Trace.USER); super(database, id, roleName, Trace.USER);
......
...@@ -35,6 +35,7 @@ import org.h2.value.ValueLong; ...@@ -35,6 +35,7 @@ import org.h2.value.ValueLong;
* @author Thomas * @author Thomas
*/ */
public class Session implements SessionInterface { public class Session implements SessionInterface {
private User user; private User user;
private int id; private int id;
private Database database; private Database database;
......
...@@ -11,6 +11,7 @@ import org.h2.message.Trace; ...@@ -11,6 +11,7 @@ import org.h2.message.Trace;
import org.h2.table.Table; import org.h2.table.Table;
public class Setting extends DbObject { public class Setting extends DbObject {
private int intValue; private int intValue;
private String stringValue; private String stringValue;
......
...@@ -19,10 +19,10 @@ import org.h2.util.StringUtils; ...@@ -19,10 +19,10 @@ import org.h2.util.StringUtils;
public class User extends RightOwner { public class User extends RightOwner {
private final boolean systemUser;
private byte[] salt; private byte[] salt;
private byte[] passwordHash; private byte[] passwordHash;
private boolean admin; private boolean admin;
private boolean systemUser;
public User(Database database, int id, String userName, boolean systemUser) { public User(Database database, int id, String userName, boolean systemUser) {
super(database, id, userName, Trace.USER); super(database, id, userName, Trace.USER);
......
...@@ -42,18 +42,28 @@ public class Aggregate extends Expression { ...@@ -42,18 +42,28 @@ public class Aggregate extends Expression {
public static final int COUNT_ALL = 0, COUNT = 1, SUM = 2, MIN = 3, MAX = 4, AVG = 5; public static final int COUNT_ALL = 0, COUNT = 1, SUM = 2, MIN = 3, MAX = 4, AVG = 5;
public static final int GROUP_CONCAT = 6, STDDEV_POP = 7, STDDEV_SAMP = 8; public static final int GROUP_CONCAT = 6, STDDEV_POP = 7, STDDEV_SAMP = 8;
public static final int VAR_POP = 9, VAR_SAMP = 10, SOME = 11, EVERY = 12, SELECTIVITY = 13; public static final int VAR_POP = 9, VAR_SAMP = 10, SOME = 11, EVERY = 12, SELECTIVITY = 13;
private int type;
private final Database database;
private final int type;
private final Select select;
private final boolean distinct;
private Expression on; private Expression on;
private Expression separator; private Expression separator;
private ObjectArray orderList; private ObjectArray orderList;
private SortOrder sort; private SortOrder sort;
private int dataType, scale; private int dataType, scale;
private long precision; private long precision;
private Select select;
private Database database;
private boolean distinct;
private static HashMap aggregates = new HashMap(); private static final HashMap aggregates = new HashMap();
public Aggregate(Database database, int type, Expression on, Select select, boolean distinct) {
this.database = database;
this.type = type;
this.on = on;
this.select = select;
this.distinct = distinct;
}
static { static {
addAggregate("COUNT", COUNT); addAggregate("COUNT", COUNT);
...@@ -85,14 +95,6 @@ public class Aggregate extends Expression { ...@@ -85,14 +95,6 @@ public class Aggregate extends Expression {
return type == null ? -1 : type.intValue(); return type == null ? -1 : type.intValue();
} }
public Aggregate(Database database, int type, Expression on, Select select, boolean distinct) {
this.database = database;
this.type = type;
this.on = on;
this.select = select;
this.distinct = distinct;
}
public void setOrder(ObjectArray orderBy) { public void setOrder(ObjectArray orderBy) {
this.orderList = orderBy; this.orderList = orderBy;
} }
......
...@@ -19,7 +19,7 @@ import org.h2.value.ValueLong; ...@@ -19,7 +19,7 @@ import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
public class AggregateData { public class AggregateData {
private int aggregateType; private final int aggregateType;
private long count; private long count;
private ValueHashMap distinctValues; private ValueHashMap distinctValues;
private Value value; private Value value;
......
...@@ -18,8 +18,8 @@ import org.h2.value.Value; ...@@ -18,8 +18,8 @@ import org.h2.value.Value;
public class Alias extends Expression { public class Alias extends Expression {
private final String alias;
private Expression expr; private Expression expr;
private String alias;
public Alias(Expression expression, String alias) { public Alias(Expression expression, String alias) {
this.expr = expression; this.expr = expression;
......
...@@ -25,7 +25,7 @@ import org.h2.value.ValueString; ...@@ -25,7 +25,7 @@ import org.h2.value.ValueString;
public class CompareLike extends Condition { public class CompareLike extends Condition {
private CompareMode compareMode; private final CompareMode compareMode;
private Expression left; private Expression left;
private Expression right; private Expression right;
private Expression escape; private Expression escape;
...@@ -253,6 +253,7 @@ public class CompareLike extends Condition { ...@@ -253,6 +253,7 @@ public class CompareLike extends Condition {
throw Message.getSQLException(Message.LIKE_ESCAPE_ERROR_1, StringUtils.addAsterisk(p, i)); throw Message.getSQLException(Message.LIKE_ESCAPE_ERROR_1, StringUtils.addAsterisk(p, i));
} }
type = MATCH; type = MATCH;
lastAny = false;
} else if (c == '%') { } else if (c == '%') {
if(lastAny) { if(lastAny) {
continue; continue;
......
...@@ -21,15 +21,19 @@ import org.h2.value.ValueNull; ...@@ -21,15 +21,19 @@ import org.h2.value.ValueNull;
* @author Thomas * @author Thomas
*/ */
public class Comparison extends Condition { public class Comparison extends Condition {
public static final int EQUAL = 0, BIGGER_EQUAL = 1, BIGGER = 2, SMALLER_EQUAL = 3, public static final int EQUAL = 0, BIGGER_EQUAL = 1, BIGGER = 2, SMALLER_EQUAL = 3,
SMALLER = 4, NOT_EQUAL = 5, IS_NULL = 6, IS_NOT_NULL = 7; SMALLER = 4, NOT_EQUAL = 5, IS_NULL = 6, IS_NOT_NULL = 7;
// TODO refactor: comparison: there never is a comparison 'false', the constant is used only for index conditions
// TODO refactor: comparison: a comparison is never 'false'; the constant is used only for index conditions
public static final int FALSE = 8; public static final int FALSE = 8;
private final Database database;
private final int compareType;
private Expression left; private Expression left;
private Expression right; private Expression right;
private int compareType;
private int dataType = -1; private int dataType = -1;
private Database database;
public Comparison(Session session, int compareType, Expression left, Expression right) { public Comparison(Session session, int compareType, Expression left, Expression right) {
this.database = session.getDatabase(); this.database = session.getDatabase();
......
...@@ -19,9 +19,12 @@ import org.h2.value.ValueNull; ...@@ -19,9 +19,12 @@ import org.h2.value.ValueNull;
* @author Thomas * @author Thomas
*/ */
public class ConditionAndOr extends Condition { public class ConditionAndOr extends Condition {
// TODO optimization: we could extend (ID=1 AND ID=B) to (ID=1 AND ID=B AND B=1) // TODO optimization: we could extend (ID=1 AND ID=B) to (ID=1 AND ID=B AND B=1)
public static final int AND = 0, OR = 1; public static final int AND = 0, OR = 1;
private int andOrType;
private final int andOrType;
private Expression left, right; private Expression left, right;
public ConditionAndOr(int andOrType, Expression left, Expression right) { public ConditionAndOr(int andOrType, Expression left, Expression right) {
......
...@@ -20,7 +20,7 @@ import org.h2.value.ValueBoolean; ...@@ -20,7 +20,7 @@ import org.h2.value.ValueBoolean;
public class ConditionExists extends Condition { public class ConditionExists extends Condition {
private Query query; private final Query query;
public ConditionExists(Query query) { public ConditionExists(Query query) {
this.query = query; this.query = query;
......
...@@ -23,9 +23,10 @@ import org.h2.value.ValueNull; ...@@ -23,9 +23,10 @@ import org.h2.value.ValueNull;
*/ */
public class ConditionIn extends Condition { public class ConditionIn extends Condition {
private Database database;
private final Database database;
private Expression left; private Expression left;
private ObjectArray values; private final ObjectArray values;
private Value min, max; private Value min, max;
private int queryLevel; private int queryLevel;
......
...@@ -921,6 +921,10 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -921,6 +921,10 @@ public class JdbcConnection extends TraceObject implements Connection {
session = new SessionRemote().createSession(ci); session = new SessionRemote().createSession(ci);
} else { } else {
SessionInterface si = (SessionInterface) ClassUtils.loadClass("org.h2.engine.Session").newInstance(); SessionInterface si = (SessionInterface) ClassUtils.loadClass("org.h2.engine.Session").newInstance();
String baseDir = Constants.BASE_DIR;
if(baseDir != null) {
ci.setBaseDir(baseDir);
}
session = si.createSession(ci); session = si.createSession(ci);
} }
trace = session.getTrace(); trace = session.getTrace();
......
...@@ -58,6 +58,9 @@ public class TcpServerThread implements Runnable { ...@@ -58,6 +58,9 @@ public class TcpServerThread implements Runnable {
String db = transfer.readString(); String db = transfer.readString();
String originalURL = transfer.readString(); String originalURL = transfer.readString();
String baseDir = server.getBaseDir(); String baseDir = server.getBaseDir();
if(baseDir == null) {
baseDir = Constants.BASE_DIR;
}
ConnectionInfo ci = new ConnectionInfo(db); ConnectionInfo ci = new ConnectionInfo(db);
if(baseDir != null) { if(baseDir != null) {
ci.setBaseDir(baseDir); ci.setBaseDir(baseDir);
......
...@@ -167,8 +167,9 @@ public class WebServer implements Service { ...@@ -167,8 +167,9 @@ public class WebServer implements Service {
ssl = Boolean.valueOf(args[++i]).booleanValue(); ssl = Boolean.valueOf(args[++i]).booleanValue();
} else if("-webAllowOthers".equals(args[i])) { } else if("-webAllowOthers".equals(args[i])) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue(); allowOthers = Boolean.valueOf(args[++i]).booleanValue();
// } else if("-baseDir".equals(args[i])) { } else if("-baseDir".equals(args[i])) {
// String baseDir = args[++i]; String baseDir = args[++i];
Constants.setBaseDir(baseDir);
} }
} }
// if(driverList != null) { // if(driverList != null) {
......
...@@ -717,6 +717,7 @@ public class MetaTable extends Table { ...@@ -717,6 +717,7 @@ public class MetaTable extends Table {
add(rows, new String[]{"h2.maxFileRetry", "" + Constants.MAX_FILE_RETRY}); add(rows, new String[]{"h2.maxFileRetry", "" + Constants.MAX_FILE_RETRY});
add(rows, new String[]{"h2.lobCloseBetweenReads", "" + Constants.LOB_CLOSE_BETWEEN_READS}); add(rows, new String[]{"h2.lobCloseBetweenReads", "" + Constants.LOB_CLOSE_BETWEEN_READS});
add(rows, new String[]{"h2.allowBigDecimalExtensions", "" + Constants.ALLOW_BIG_DECIMAL_EXTENSIONS}); add(rows, new String[]{"h2.allowBigDecimalExtensions", "" + Constants.ALLOW_BIG_DECIMAL_EXTENSIONS});
add(rows, new String[]{"h2.baseDir", "" + Constants.BASE_DIR});
break; break;
} }
case TYPE_INFO: { case TYPE_INFO: {
......
...@@ -59,7 +59,7 @@ public class Server implements Runnable { ...@@ -59,7 +59,7 @@ public class Server implements Runnable {
System.out.println("-ftpWritePassword <password> (default: " + FtpServer.DEFAULT_WRITE_PASSWORD+")"); System.out.println("-ftpWritePassword <password> (default: " + FtpServer.DEFAULT_WRITE_PASSWORD+")");
System.out.println("-log [true|false]"); System.out.println("-log [true|false]");
System.out.println("-baseDir <directory>"); System.out.println("-baseDir <directory> (sets the base directory for H2 databases)");
System.out.println("-ifExists [true|false] (only existing databases may be opened)"); System.out.println("-ifExists [true|false] (only existing databases may be opened)");
} }
......
...@@ -94,26 +94,20 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -94,26 +94,20 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
/* /*
public static void Constants.setBaseDir(String baseDir) throws IOException. whats faster, stringBuffer.append.append.append or buff.append buff.append...
System property h2.baseDir (default: empty meaning current working directory). maybe replace StringBuffer with own class (StringCreator)
Can be set to ~ (meaning the user directory) or any directory (is created if it does not yet exist).
java -Dh2.baseDir=/tmp/data org.h2.tools.Server
System.setProperty would work as well, needs to be set before connecting to any database.
Test with newest Hibernate storages should be an inthashmap
SELECT * FROM DUAL WHERE 'a_z' LIKE '%=_%' ESCAPE '='; Test with newest Hibernate
SELECT * FROM DUAL WHERE 'a_z' LIKE '%\_%';
-- SET client_encoding = 'UTF8'; -- SET client_encoding = 'UTF8';
-- SET check_function_bodies = false; -- SET check_function_bodies = false;
-- SET client_min_messages = warning; -- SET client_min_messages = warning;
-- CREATE PROCEDURAL LANGUAGE plperl; -- CREATE PROCEDURAL LANGUAGE plperl;
-- CREATE PROCEDURAL LANGUAGE plpgsql; -- CREATE PROCEDURAL LANGUAGE plpgsql;
--SET search_path = public, pg_catalog;
--SET default_tablespace = ''; --SET default_tablespace = '';
--SET default_with_oids = false; --SET default_with_oids = false;
--id serial NOT NULL,
pg_catalog with views pg_catalog with views
...@@ -123,12 +117,10 @@ The unique object identifier of a row. PostgreSQL automatically adds this 4-byte ...@@ -123,12 +117,10 @@ The unique object identifier of a row. PostgreSQL automatically adds this 4-byte
ctid (tuple identifier) ctid (tuple identifier)
The identifier which describes the physical location of the tuple within the database. A pair of numbers are represented by the ctid: the block number, and tuple index within that block. The identifier which describes the physical location of the tuple within the database. A pair of numbers are represented by the ctid: the block number, and tuple index within that block.
make sure INDEX_LOOKUP_NEW = is true by default. make sure INDEX_LOOKUP_NEW = is true by default.
Test Console (batch, javaw, different platforms) Test Console (batch, javaw, different platforms)
test with openoffice (metadata changes) test with openoffice (metadata changes)
set read-committed as the default set read-committed as the default
testHalt testHalt
...@@ -200,8 +192,6 @@ CREATE TABLE TEST( ID BIGINT PRIMARY KEY, CREATED TIMESTAMP); ...@@ -200,8 +192,6 @@ CREATE TABLE TEST( ID BIGINT PRIMARY KEY, CREATED TIMESTAMP);
INSERT INTO TEST VALUES(1, '2007-01-01 00:00:00'); INSERT INTO TEST VALUES(1, '2007-01-01 00:00:00');
SELECT * FROM TEST; SELECT * FROM TEST;
Cache size in KB
*/ */
/* /*
......
create table test();
insert into test values();
ALTER TABLE TEST ADD ID INTEGER;
select count(*) from test;
> 1;
drop table test;
select * from dual where 'a_z' like '%=_%' escape '=';
> 1;
create table test as select 1 from dual union all select 2 from dual; create table test as select 1 from dual union all select 2 from dual;
drop table test; drop table test;
......
...@@ -19,8 +19,9 @@ public class TestPattern extends TestBase { ...@@ -19,8 +19,9 @@ public class TestPattern extends TestBase {
test(comp, "B", "%_"); test(comp, "B", "%_");
test(comp, "A", "A%"); test(comp, "A", "A%");
test(comp, "A", "A%%"); test(comp, "A", "A%%");
test(comp, "A_A", "%\\_%");
for(int i=0; i<10; i++) { for(int i=0; i<10000; i++) {
String pattern=getRandomPattern(); String pattern=getRandomPattern();
String value=getRandomValue(); String value=getRandomValue();
test(comp, value, pattern); test(comp, value, pattern);
...@@ -28,21 +29,18 @@ public class TestPattern extends TestBase { ...@@ -28,21 +29,18 @@ public class TestPattern extends TestBase {
} }
void test(CompareLike comp, String value, String pattern) throws Exception { void test(CompareLike comp, String value, String pattern) throws Exception {
// TODO test: need another regexp implementation (this one doesn't work for gcj) String regexp = initPatternRegexp(pattern, '\\');
// String regexp = initPatternRegexp(pattern); boolean resultRegexp = value.matches(regexp);
// boolean resultRegexp = value.matches(regexp); boolean result = comp.test(pattern, value, '\\');
// boolean result = if(result != resultRegexp) {
comp.test(pattern, value, 'X'); error("Error: >"+value+"< LIKE >"+pattern+"< result="+result+" resultReg="+resultRegexp);
}
// if(result != resultRegexp) {
// throw new Exception("Error: >"+value+"< LIKE >"+pattern+"< result="+result+" resultReg="+resultRegexp);
// }
} }
static String getRandomValue() { static String getRandomValue() {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
int len = (int)(Math.random() * 10); int len = (int)(Math.random() * 10);
String s = "ABCDEFGHIJKLMNOP"; String s = "AB_%\\";
for(int i=0; i<len; i++) { for(int i=0; i<len; i++) {
buff.append(s.charAt((int)(Math.random()*s.length()))); buff.append(s.charAt((int)(Math.random()*s.length())));
} }
...@@ -52,40 +50,45 @@ public class TestPattern extends TestBase { ...@@ -52,40 +50,45 @@ public class TestPattern extends TestBase {
static String getRandomPattern() { static String getRandomPattern() {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
int len = (int)(Math.random() * 4); int len = (int)(Math.random() * 4);
//String s = "ABC%_\\"; String s = "A%_\\";
String s = "AB_";
for(int i=0; i<len; i++) { for(int i=0; i<len; i++) {
buff.append(s.charAt((int)(Math.random()*s.length()))); char c = s.charAt((int)(Math.random()*s.length()));
if((c == '_' || c == '%') && Math.random() > 0.5) {
buff.append('\\');
} else if(c=='\\') {
buff.append(c);
}
buff.append(c);
} }
return buff.toString(); return buff.toString();
} }
// private String initPatternRegexp(String pattern) { private String initPatternRegexp(String pattern, char escape) throws Exception {
// int len = pattern.length(); int len = pattern.length();
// StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
// for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
// char c = pattern.charAt(i); char c = pattern.charAt(i);
// if (escape != null && escape.charValue() == c) { if (escape == c) {
// if (i >= len) { if (i >= len) {
// throw Message.internal("escape can't be last char"); error("escape can't be last char");
// } }
// c = pattern.charAt(++i); c = pattern.charAt(++i);
// buff.append('\\'); buff.append('\\');
// buff.append(c); buff.append(c);
// } else if (c == '%') { } else if (c == '%') {
// buff.append(".*"); buff.append(".*");
// } else if (c == '_') { } else if (c == '_') {
// buff.append('.'); buff.append('.');
// } else if(c=='\\'){ } else if(c=='\\'){
// buff.append("\\\\"); buff.append("\\\\");
// } else { } else {
// buff.append(c); buff.append(c);
// } }
// // TODO regexp: there are other chars that need escaping // TODO regexp: there are other chars that need escaping
// } }
// String regexp = buff.toString(); String regexp = buff.toString();
//// System.out.println("regexp = " + regexp); // System.out.println("regexp = " + regexp);
// return regexp; return regexp;
// } }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论