提交 75648425 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 ebf9cd96
...@@ -11,7 +11,7 @@ import org.h2.value.Value; ...@@ -11,7 +11,7 @@ import org.h2.value.Value;
public interface DataHandler { public interface DataHandler {
boolean getTextStorage(); boolean getTextStorage();
String getDatabasePath(); String getDatabasePath();
FileStore openFile(String name, boolean mustExist) throws SQLException; FileStore openFile(String name, String mode, boolean mustExist) throws SQLException;
int getChecksum(byte[] data, int start, int end); int getChecksum(byte[] data, int start, int end);
void checkPowerOff() throws SQLException; void checkPowerOff() throws SQLException;
void checkWritingAllowed() throws SQLException; void checkWritingAllowed() throws SQLException;
......
...@@ -29,6 +29,7 @@ import org.h2.value.ValueLong; ...@@ -29,6 +29,7 @@ import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueShort; import org.h2.value.ValueShort;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueStringFixed;
import org.h2.value.ValueStringIgnoreCase; import org.h2.value.ValueStringIgnoreCase;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
...@@ -199,6 +200,7 @@ public abstract class DataPage { ...@@ -199,6 +200,7 @@ public abstract class DataPage {
} }
case Value.STRING: case Value.STRING:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
writeString(v.getString()); writeString(v.getString());
break; break;
case Value.DOUBLE: case Value.DOUBLE:
...@@ -261,6 +263,7 @@ public abstract class DataPage { ...@@ -261,6 +263,7 @@ public abstract class DataPage {
return 1 + getIntLen(); return 1 + getIntLen();
case Value.STRING: case Value.STRING:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
case Value.DECIMAL: case Value.DECIMAL:
return 1 + getStringLen(v.getString()); return 1 + getStringLen(v.getString());
case Value.JAVA_OBJECT: case Value.JAVA_OBJECT:
...@@ -353,6 +356,8 @@ public abstract class DataPage { ...@@ -353,6 +356,8 @@ public abstract class DataPage {
return ValueString.get(readString()); return ValueString.get(readString());
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
return ValueStringIgnoreCase.get(readString()); return ValueStringIgnoreCase.get(readString());
case Value.STRING_FIXED:
return ValueStringFixed.get(readString());
case Value.DOUBLE: case Value.DOUBLE:
return ValueDouble.get(Double.longBitsToDouble(readLong())); return ValueDouble.get(Double.longBitsToDouble(readLong()));
case Value.FLOAT: case Value.FLOAT:
......
...@@ -59,12 +59,14 @@ public class DiskFile implements CacheWriter { ...@@ -59,12 +59,14 @@ public class DiskFile implements CacheWriter {
private ObjectArray redoBuffer; private ObjectArray redoBuffer;
private int redoBufferSize; private int redoBufferSize;
private int readCount, writeCount; private int readCount, writeCount;
private String mode;
public DiskFile(Database database, String fileName, boolean dataFile, boolean logChanges, int cacheSize) throws SQLException { public DiskFile(Database database, String fileName, String mode, boolean dataFile, boolean logChanges, int cacheSize) throws SQLException {
reset(); reset();
this.database = database; this.database = database;
this.log = database.getLog(); this.log = database.getLog();
this.fileName = fileName; this.fileName = fileName;
this.mode = mode;
this.dataFile = dataFile; this.dataFile = dataFile;
this.logChanges = logChanges; this.logChanges = logChanges;
String cacheType = database.getCacheType(); String cacheType = database.getCacheType();
...@@ -81,7 +83,7 @@ public class DiskFile implements CacheWriter { ...@@ -81,7 +83,7 @@ public class DiskFile implements CacheWriter {
freeBlock.updateChecksum(); freeBlock.updateChecksum();
try { try {
if(FileUtils.exists(fileName)) { if(FileUtils.exists(fileName)) {
file = database.openFile(fileName, true); file = database.openFile(fileName, mode, true);
long length = file.length(); long length = file.length();
database.notifyFileSize(length); database.notifyFileSize(length);
int blocks = (int)((length - OFFSET) / BLOCK_SIZE); int blocks = (int)((length - OFFSET) / BLOCK_SIZE);
...@@ -118,7 +120,7 @@ public class DiskFile implements CacheWriter { ...@@ -118,7 +120,7 @@ public class DiskFile implements CacheWriter {
private void create() throws SQLException { private void create() throws SQLException {
try { try {
file = database.openFile(fileName, false); file = database.openFile(fileName, mode, false);
DataPage header = DataPage.create(database, OFFSET); DataPage header = DataPage.create(database, OFFSET);
file.seek(FileStore.HEADER_LENGTH); file.seek(FileStore.HEADER_LENGTH);
header.fill(OFFSET); header.fill(OFFSET);
......
...@@ -29,27 +29,27 @@ public class FileStore { ...@@ -29,27 +29,27 @@ public class FileStore {
private Reference autoDeleteReference; private Reference autoDeleteReference;
private boolean checkedWriting = true; private boolean checkedWriting = true;
public static FileStore open(DataHandler handler, String name, byte[] magic) throws SQLException { public static FileStore open(DataHandler handler, String name, String mode, byte[] magic) throws SQLException {
return open(handler, name, magic, null, null, 0); return open(handler, name, mode, magic, null, null, 0);
} }
public static FileStore open(DataHandler handler, String name, byte[] magic, String cipher, byte[] key) throws SQLException { public static FileStore open(DataHandler handler, String name, String mode, byte[] magic, String cipher, byte[] key) throws SQLException {
return open(handler, name, magic, cipher, key, Constants.ENCRYPTION_KEY_HASH_ITERATIONS); return open(handler, name, mode, magic, cipher, key, Constants.ENCRYPTION_KEY_HASH_ITERATIONS);
} }
public static FileStore open(DataHandler handler, String name, byte[] magic, String cipher, byte[] key, int keyIterations) throws SQLException { public static FileStore open(DataHandler handler, String name, String mode, byte[] magic, String cipher, byte[] key, int keyIterations) throws SQLException {
FileStore store; FileStore store;
if(FileUtils.isInMemory(name)) { if(FileUtils.isInMemory(name)) {
store = new MemoryFileStore(handler, name, magic); store = new MemoryFileStore(handler, name, magic);
} else if(cipher == null) { } else if(cipher == null) {
store = new FileStore(handler, name, magic); store = new FileStore(handler, name, mode, magic);
} else { } else {
store = new SecureFileStore(handler, name, magic, cipher, key, keyIterations); store = new SecureFileStore(handler, name, mode, magic, cipher, key, keyIterations);
} }
return store; return store;
} }
protected FileStore(DataHandler handler, String name, byte[] magic) throws SQLException { protected FileStore(DataHandler handler, String name, String mode, byte[] magic) throws SQLException {
this.handler = handler; this.handler = handler;
this.name = name; this.name = name;
this.magic = magic; this.magic = magic;
...@@ -59,8 +59,7 @@ public class FileStore { ...@@ -59,8 +59,7 @@ public class FileStore {
if(f.exists() && !f.canWrite()) { if(f.exists() && !f.canWrite()) {
file = FileUtils.openRandomAccessFile(name, "r"); file = FileUtils.openRandomAccessFile(name, "r");
} else { } else {
// file = new RandomAccessFile(name, "rws"); file = FileUtils.openRandomAccessFile(name, mode);
file = FileUtils.openRandomAccessFile(name, "rw");
} }
} catch(IOException e) { } catch(IOException e) {
throw Message.convert(e); throw Message.convert(e);
......
...@@ -59,7 +59,7 @@ public class LogFile { ...@@ -59,7 +59,7 @@ public class LogFile {
this.id = id; this.id = id;
this.fileNamePrefix = fileNamePrefix; this.fileNamePrefix = fileNamePrefix;
fileName = getFileName(); fileName = getFileName();
file = log.getDatabase().openFile(fileName, false); file = log.getDatabase().openFile(fileName, database.getWriteModeLog(), false);
rowBuff = log.getRowBuffer(); rowBuff = log.getRowBuffer();
buffer = new byte[BUFFER_SIZE]; buffer = new byte[BUFFER_SIZE];
unwritten = new ObjectArray(); unwritten = new ObjectArray();
...@@ -333,6 +333,8 @@ public class LogFile { ...@@ -333,6 +333,8 @@ public class LogFile {
if(file == null) { if(file == null) {
throw Message.getSQLException(Message.SIMULATED_POWER_OFF); throw Message.getSQLException(Message.SIMULATED_POWER_OFF);
} }
int testing ;
//System.out.println("flush " + file.length() + " pos:"+file.getFilePointer()+" len:"+bufferPos);
file.write(buffer, 0, bufferPos); file.write(buffer, 0, bufferPos);
for(int i=0; i<unwritten.size(); i++) { for(int i=0; i<unwritten.size(); i++) {
Record r = (Record) unwritten.get(i); Record r = (Record) unwritten.get(i);
......
...@@ -38,6 +38,7 @@ public class LogSystem { ...@@ -38,6 +38,7 @@ public class LogSystem {
private ObjectArray inDoubtTransactions; private ObjectArray inDoubtTransactions;
private boolean disabled; private boolean disabled;
private int keepFiles; private int keepFiles;
private boolean closed;
public LogSystem(Database database, String fileNamePrefix, boolean readOnly) throws SQLException { public LogSystem(Database database, String fileNamePrefix, boolean readOnly) throws SQLException {
this.database = database; this.database = database;
...@@ -110,10 +111,13 @@ public class LogSystem { ...@@ -110,10 +111,13 @@ public class LogSystem {
} }
public void close() throws SQLException { public void close() throws SQLException {
if (database == null || readOnly) { if(database == null || readOnly) {
return; return;
} }
synchronized (database) { synchronized (database) {
if(closed) {
return;
}
// TODO refactor flushing and closing files when we know what to do exactly // TODO refactor flushing and closing files when we know what to do exactly
SQLException closeException = null; SQLException closeException = null;
try { try {
...@@ -140,7 +144,7 @@ public class LogSystem { ...@@ -140,7 +144,7 @@ public class LogSystem {
} }
} }
} }
database = null; closed = true;
if (closeException != null) { if (closeException != null) {
throw closeException; throw closeException;
} }
...@@ -157,10 +161,13 @@ public class LogSystem { ...@@ -157,10 +161,13 @@ public class LogSystem {
} }
public boolean recover() throws SQLException { public boolean recover() throws SQLException {
if (database == null) { if(database == null) {
return false; return false;
} }
synchronized (database) { synchronized (database) {
if(closed) {
return false;
}
undo = new ObjectArray(); undo = new ObjectArray();
for (int i = 0; i < activeLogs.size(); i++) { for (int i = 0; i < activeLogs.size(); i++) {
LogFile log = (LogFile) activeLogs.get(i); LogFile log = (LogFile) activeLogs.get(i);
...@@ -290,10 +297,13 @@ public class LogSystem { ...@@ -290,10 +297,13 @@ public class LogSystem {
} }
public void prepareCommit(Session session, String transaction) throws SQLException { public void prepareCommit(Session session, String transaction) throws SQLException {
if (database == null || readOnly) { if(database == null || readOnly) {
return; return;
} }
synchronized (database) { synchronized (database) {
if(closed) {
return;
}
currentLog.prepareCommit(session, transaction); currentLog.prepareCommit(session, transaction);
} }
} }
...@@ -303,6 +313,9 @@ public class LogSystem { ...@@ -303,6 +313,9 @@ public class LogSystem {
return; return;
} }
synchronized (database) { synchronized (database) {
if(closed) {
return;
}
currentLog.commit(session); currentLog.commit(session);
session.setAllCommitted(); session.setAllCommitted();
} }
...@@ -313,15 +326,21 @@ public class LogSystem { ...@@ -313,15 +326,21 @@ public class LogSystem {
return; return;
} }
synchronized (database) { synchronized (database) {
if(closed) {
return;
}
currentLog.flush(); currentLog.flush();
} }
} }
public void addTruncate(Session session, DiskFile file, int storageId, int recordId, int blockCount) throws SQLException { public void addTruncate(Session session, DiskFile file, int storageId, int recordId, int blockCount) throws SQLException {
if (database == null || disabled) { if(database == null) {
return; return;
} }
synchronized (database) { synchronized (database) {
if(disabled || closed) {
return;
}
database.checkWritingAllowed(); database.checkWritingAllowed();
if (!file.isDataFile()) { if (!file.isDataFile()) {
storageId = -storageId; storageId = -storageId;
...@@ -334,10 +353,13 @@ public class LogSystem { ...@@ -334,10 +353,13 @@ public class LogSystem {
} }
public void add(Session session, DiskFile file, Record record) throws SQLException { public void add(Session session, DiskFile file, Record record) throws SQLException {
if (database == null || disabled) { if(database == null) {
return; return;
} }
synchronized (database) { synchronized (database) {
if(disabled || closed) {
return;
}
database.checkWritingAllowed(); database.checkWritingAllowed();
int storageId = record.getStorageId(); int storageId = record.getStorageId();
if (!file.isDataFile()) { if (!file.isDataFile()) {
...@@ -355,10 +377,13 @@ public class LogSystem { ...@@ -355,10 +377,13 @@ public class LogSystem {
} }
public void checkpoint() throws SQLException { public void checkpoint() throws SQLException {
if (database == null || readOnly || disabled) { if(readOnly || database == null) {
return; return;
} }
synchronized (database) { synchronized (database) {
if(closed || disabled) {
return;
}
flushAndCloseUnused(); flushAndCloseUnused();
currentLog = new LogFile(this, currentLog.getId() + 1, fileNamePrefix); currentLog = new LogFile(this, currentLog.getId() + 1, fileNamePrefix);
activeLogs.add(currentLog); activeLogs.add(currentLog);
...@@ -376,9 +401,6 @@ public class LogSystem { ...@@ -376,9 +401,6 @@ public class LogSystem {
} }
private void writeSummary() throws SQLException { private void writeSummary() throws SQLException {
if (database == null || readOnly || disabled) {
return;
}
byte[] summary; byte[] summary;
DiskFile file; DiskFile file;
file = database.getDataFile(); file = database.getDataFile();
...@@ -415,6 +437,9 @@ public class LogSystem { ...@@ -415,6 +437,9 @@ public class LogSystem {
} }
public void sync() throws SQLException { public void sync() throws SQLException {
if(database == null || readOnly) {
return;
}
synchronized (database) { synchronized (database) {
if (currentLog != null) { if (currentLog != null) {
currentLog.flush(); currentLog.flush();
......
...@@ -72,7 +72,7 @@ public class UndoLog { ...@@ -72,7 +72,7 @@ public class UndoLog {
if(memoryUndo > database.getMaxMemoryUndo() && database.isPersistent()) { if(memoryUndo > database.getMaxMemoryUndo() && database.isPersistent()) {
if(file == null) { if(file == null) {
String fileName = database.createTempFile(); String fileName = database.createTempFile();
file = database.openFile(fileName, false); file = database.openFile(fileName, "rw", false);
file.autoDelete(); file.autoDelete();
file.seek(FileStore.HEADER_LENGTH); file.seek(FileStore.HEADER_LENGTH);
rowBuff = DataPage.create(database, Constants.DEFAULT_DATA_PAGE_SIZE); rowBuff = DataPage.create(database, Constants.DEFAULT_DATA_PAGE_SIZE);
......
...@@ -276,6 +276,7 @@ public class Column { ...@@ -276,6 +276,7 @@ public class Column {
case Value.BYTES: case Value.BYTES:
case Value.STRING: case Value.STRING:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
buff.append("("); buff.append("(");
buff.append(precision); buff.append(precision);
buff.append(")"); buff.append(")");
......
...@@ -112,7 +112,7 @@ public class FunctionTable extends Table { ...@@ -112,7 +112,7 @@ public class FunctionTable extends Table {
return false; return false;
} }
public int getRowCount() throws SQLException { public long getRowCount() throws SQLException {
throw Message.getInternalError(); throw Message.getInternalError();
} }
......
...@@ -87,7 +87,8 @@ public class MetaTable extends Table { ...@@ -87,7 +87,8 @@ public class MetaTable extends Table {
// extensions // extensions
"STORAGE_TYPE", "STORAGE_TYPE",
"SQL", "SQL",
"REMARKS" "REMARKS",
"ID INT"
}); });
indexColumnName = "TABLE_NAME"; indexColumnName = "TABLE_NAME";
break; break;
...@@ -534,7 +535,8 @@ public class MetaTable extends Table { ...@@ -534,7 +535,8 @@ public class MetaTable extends Table {
table.getTableType(), // TABLE_TYPE table.getTableType(), // TABLE_TYPE
storageType, // STORAGE_TYPE storageType, // STORAGE_TYPE
table.getCreateSQL(), // SQL table.getCreateSQL(), // SQL
replaceNullWithEmpty(table.getComment()) // REMARKS replaceNullWithEmpty(table.getComment()), // REMARKS
"" + table.getId() // ID
}); });
} }
break; break;
...@@ -696,7 +698,7 @@ public class MetaTable extends Table { ...@@ -696,7 +698,7 @@ public class MetaTable extends Table {
String.valueOf(t.minScale), // MINIMUM_SCALE String.valueOf(t.minScale), // MINIMUM_SCALE
String.valueOf(t.maxScale), // MAXIMUM_SCALE String.valueOf(t.maxScale), // MAXIMUM_SCALE
t.decimal ? "10" : null, // RADIX t.decimal ? "10" : null, // RADIX
String.valueOf(t.order), // POS String.valueOf(t.sqlTypePos), // POS
String.valueOf(t.caseSensitive), // CASE_SENSITIVE String.valueOf(t.caseSensitive), // CASE_SENSITIVE
"" + DatabaseMetaData.typeNullable, // NULLABLE "" + DatabaseMetaData.typeNullable, // NULLABLE
"" + DatabaseMetaData.typeSearchable // SEARCHABLE "" + DatabaseMetaData.typeSearchable // SEARCHABLE
...@@ -1216,7 +1218,7 @@ public class MetaTable extends Table { ...@@ -1216,7 +1218,7 @@ public class MetaTable extends Table {
throw Message.getUnsupportedException(); throw Message.getUnsupportedException();
} }
public int getRowCount() { public long getRowCount() {
throw Message.getInternalError(); throw Message.getInternalError();
} }
......
...@@ -84,9 +84,8 @@ public class RangeTable extends Table { ...@@ -84,9 +84,8 @@ public class RangeTable extends Table {
return false; return false;
} }
public int getRowCount() throws SQLException { public long getRowCount() throws SQLException {
// TODO document system_range: count(*) for system_range could be wrong (long to int conversion) return max - min;
return (int)(max - min);
} }
public String getTableType() { public String getTableType() {
......
...@@ -250,7 +250,7 @@ public abstract class Table extends SchemaObject { ...@@ -250,7 +250,7 @@ public abstract class Table extends SchemaObject {
ObjectArray indexes = getIndexes(); ObjectArray indexes = getIndexes();
for (int i = 1; indexes != null && masks != null && i < indexes.size(); i++) { for (int i = 1; indexes != null && masks != null && i < indexes.size(); i++) {
Index index = (Index) indexes.get(i); Index index = (Index) indexes.get(i);
int cost = index.getCost(masks); long cost = index.getCost(masks);
if (cost < item.cost) { if (cost < item.cost) {
item.cost = cost; item.cost = cost;
item.setIndex(index); item.setIndex(index);
...@@ -432,7 +432,7 @@ public abstract class Table extends SchemaObject { ...@@ -432,7 +432,7 @@ public abstract class Table extends SchemaObject {
public abstract boolean canGetRowCount(); public abstract boolean canGetRowCount();
public abstract boolean canDrop(); public abstract boolean canDrop();
public abstract int getRowCount() throws SQLException; public abstract long getRowCount() throws SQLException;
public boolean getGlobalTemporary() { public boolean getGlobalTemporary() {
return false; return false;
......
...@@ -29,6 +29,7 @@ import org.h2.schema.Schema; ...@@ -29,6 +29,7 @@ import org.h2.schema.Schema;
import org.h2.store.DataPage; import org.h2.store.DataPage;
import org.h2.store.Record; import org.h2.store.Record;
import org.h2.store.RecordReader; import org.h2.store.RecordReader;
import org.h2.util.MathUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -38,7 +39,7 @@ import org.h2.value.Value; ...@@ -38,7 +39,7 @@ import org.h2.value.Value;
*/ */
public class TableData extends Table implements RecordReader { public class TableData extends Table implements RecordReader {
private ScanIndex scanIndex; private ScanIndex scanIndex;
private int rowCount; private long rowCount;
private Session lockExclusive; private Session lockExclusive;
private HashSet lockShared = new HashSet(); private HashSet lockShared = new HashSet();
private Trace traceLock; private Trace traceLock;
...@@ -76,7 +77,7 @@ public class TableData extends Table implements RecordReader { ...@@ -76,7 +77,7 @@ public class TableData extends Table implements RecordReader {
Index index = (Index) indexes.get(i); Index index = (Index) indexes.get(i);
index.add(session, row); index.add(session, row);
if(Constants.CHECK) { if(Constants.CHECK) {
int rc = index.getRowCount(); long rc = index.getRowCount();
if(rc != rowCount+1) { if(rc != rowCount+1) {
throw Message.getInternalError("rowCount expected "+(rowCount+1)+" got "+rc); throw Message.getInternalError("rowCount expected "+(rowCount+1)+" got "+rc);
} }
...@@ -89,7 +90,7 @@ public class TableData extends Table implements RecordReader { ...@@ -89,7 +90,7 @@ public class TableData extends Table implements RecordReader {
Index index = (Index) indexes.get(i); Index index = (Index) indexes.get(i);
index.remove(session, row); index.remove(session, row);
if(Constants.CHECK) { if(Constants.CHECK) {
int rc = index.getRowCount(); long rc = index.getRowCount();
if(rc != rowCount) { if(rc != rowCount) {
throw Message.getInternalError("rowCount expected "+(rowCount)+" got "+rc); throw Message.getInternalError("rowCount expected "+(rowCount)+" got "+rc);
} }
...@@ -152,14 +153,16 @@ public class TableData extends Table implements RecordReader { ...@@ -152,14 +153,16 @@ public class TableData extends Table implements RecordReader {
if(index.needRebuild()) { if(index.needRebuild()) {
try { try {
Index scan = getScanIndex(session); Index scan = getScanIndex(session);
int remaining = scan.getRowCount(); long remaining = scan.getRowCount();
int total = remaining; long total = remaining;
Cursor cursor = scan.find(session, null, null); Cursor cursor = scan.find(session, null, null);
int i = 0; long i = 0;
int bufferSize = Constants.DEFAULT_MAX_MEMORY_ROWS; int bufferSize = Constants.DEFAULT_MAX_MEMORY_ROWS;
ObjectArray buffer = new ObjectArray(bufferSize); ObjectArray buffer = new ObjectArray(bufferSize);
while (cursor.next()) { while (cursor.next()) {
database.setProgress(DatabaseEventListener.STATE_CREATE_INDEX, getName(), i++, total); database.setProgress(DatabaseEventListener.STATE_CREATE_INDEX, getName(),
MathUtils.convertLongToInt(i++),
MathUtils.convertLongToInt(total));
Row row = cursor.get(); Row row = cursor.get();
// index.add(session, row); // index.add(session, row);
buffer.add(row); buffer.add(row);
...@@ -234,7 +237,7 @@ public class TableData extends Table implements RecordReader { ...@@ -234,7 +237,7 @@ public class TableData extends Table implements RecordReader {
return true; return true;
} }
public int getRowCount() { public long getRowCount() {
return rowCount; return rowCount;
} }
...@@ -244,7 +247,7 @@ public class TableData extends Table implements RecordReader { ...@@ -244,7 +247,7 @@ public class TableData extends Table implements RecordReader {
Index index = (Index) indexes.get(i); Index index = (Index) indexes.get(i);
index.remove(session, row); index.remove(session, row);
if(Constants.CHECK) { if(Constants.CHECK) {
int rc = index.getRowCount(); long rc = index.getRowCount();
if(rc != rowCount-1) { if(rc != rowCount-1) {
throw Message.getInternalError("rowCount expected "+(rowCount-1)+" got "+rc); throw Message.getInternalError("rowCount expected "+(rowCount-1)+" got "+rc);
} }
...@@ -259,7 +262,7 @@ public class TableData extends Table implements RecordReader { ...@@ -259,7 +262,7 @@ public class TableData extends Table implements RecordReader {
Index index = (Index) indexes.get(i); Index index = (Index) indexes.get(i);
index.truncate(session); index.truncate(session);
if(Constants.CHECK) { if(Constants.CHECK) {
int rc = index.getRowCount(); long rc = index.getRowCount();
if(rc != 0) { if(rc != 0) {
throw Message.getInternalError("rowCount expected 0 got "+rc); throw Message.getInternalError("rowCount expected 0 got "+rc);
} }
......
...@@ -387,17 +387,21 @@ public class TableFilter implements ColumnResolver { ...@@ -387,17 +387,21 @@ public class TableFilter implements ColumnResolver {
buff.append(alias); buff.append(alias);
} }
buff.append(" /* "); buff.append(" /* ");
buff.append(index.getPlanSQL()); StringBuffer planBuff = new StringBuffer();
planBuff.append(index.getPlanSQL());
if(indexConditions.size() > 0) { if(indexConditions.size() > 0) {
buff.append(": "); planBuff.append(": ");
for (int i = 0; i < indexConditions.size(); i++) { for (int i = 0; i < indexConditions.size(); i++) {
IndexCondition condition = (IndexCondition) indexConditions.get(i); IndexCondition condition = (IndexCondition) indexConditions.get(i);
if(i>0) { if(i>0) {
buff.append(" AND "); planBuff.append(" AND ");
} }
buff.append(condition.getSQL()); planBuff.append(condition.getSQL());
} }
} }
String plan = planBuff.toString();
plan = StringUtils.quoteRemarkSQL(plan);
buff.append(plan);
buff.append(" */"); buff.append(" */");
if(joinCondition != null) { if(joinCondition != null) {
buff.append(" ON "); buff.append(" ON ");
...@@ -405,7 +409,9 @@ public class TableFilter implements ColumnResolver { ...@@ -405,7 +409,9 @@ public class TableFilter implements ColumnResolver {
} }
if(filterCondition != null) { if(filterCondition != null) {
buff.append(" /* WHERE "); buff.append(" /* WHERE ");
buff.append(StringUtils.unEnclose(filterCondition.getSQL())); String condition = StringUtils.unEnclose(filterCondition.getSQL());
condition = StringUtils.quoteRemarkSQL(condition);
buff.append(condition);
buff.append("*/"); buff.append("*/");
} }
return buff.toString(); return buff.toString();
......
...@@ -39,9 +39,10 @@ public class TableLink extends Table { ...@@ -39,9 +39,10 @@ public class TableLink extends Table {
private ObjectArray indexes = new ObjectArray(); private ObjectArray indexes = new ObjectArray();
private boolean emitUpdates; private boolean emitUpdates;
private LinkedIndex linkedIndex; private LinkedIndex linkedIndex;
private SQLException connectException;
public TableLink(Schema schema, int id, String name, String driver, String url, public TableLink(Schema schema, int id, String name, String driver, String url,
String user, String password, String originalTable, boolean emitUpdates) throws SQLException { String user, String password, String originalTable, boolean emitUpdates, boolean force) throws SQLException {
super(schema, id, name, false); super(schema, id, name, false);
this.driver = driver; this.driver = driver;
this.url = url; this.url = url;
...@@ -49,6 +50,21 @@ public class TableLink extends Table { ...@@ -49,6 +50,21 @@ public class TableLink extends Table {
this.password = password; this.password = password;
this.originalTable = originalTable; this.originalTable = originalTable;
this.emitUpdates = emitUpdates; this.emitUpdates = emitUpdates;
try {
connect();
} catch(SQLException e) {
connectException = e;
if(!force) {
throw e;
}
Column[] cols = new Column[0];
setColumns(cols);
linkedIndex = new LinkedIndex(this, id, cols, IndexType.createNonUnique(false));
indexes.add(linkedIndex);
}
}
private void connect() throws SQLException {
conn = JdbcUtils.getConnection(driver, url, user, password); conn = JdbcUtils.getConnection(driver, url, user, password);
DatabaseMetaData meta = conn.getMetaData(); DatabaseMetaData meta = conn.getMetaData();
boolean storesLowerCase = meta.storesLowerCaseIdentifiers(); boolean storesLowerCase = meta.storesLowerCaseIdentifiers();
...@@ -99,6 +115,7 @@ public class TableLink extends Table { ...@@ -99,6 +115,7 @@ public class TableLink extends Table {
Column[] cols = new Column[columnList.size()]; Column[] cols = new Column[columnList.size()];
columnList.toArray(cols); columnList.toArray(cols);
setColumns(cols); setColumns(cols);
int id = getId();
linkedIndex = new LinkedIndex(this, id, cols, IndexType.createNonUnique(false)); linkedIndex = new LinkedIndex(this, id, cols, IndexType.createNonUnique(false));
indexes.add(linkedIndex); indexes.add(linkedIndex);
rs = meta.getPrimaryKeys(null, null, originalTable); rs = meta.getPrimaryKeys(null, null, originalTable);
...@@ -167,7 +184,7 @@ public class TableLink extends Table { ...@@ -167,7 +184,7 @@ public class TableLink extends Table {
public String getCreateSQL() { public String getCreateSQL() {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
buff.append("CREATE LINKED TABLE "); buff.append("CREATE FORCE LINKED TABLE ");
buff.append(getSQL()); buff.append(getSQL());
if(comment != null) { if(comment != null) {
buff.append(" COMMENT "); buff.append(" COMMENT ");
...@@ -224,11 +241,11 @@ public class TableLink extends Table { ...@@ -224,11 +241,11 @@ public class TableLink extends Table {
} }
} }
public int getRowCount() throws SQLException { public long getRowCount() throws SQLException {
PreparedStatement prep = getPreparedStatement("SELECT COUNT(*) FROM "+originalTable); PreparedStatement prep = getPreparedStatement("SELECT COUNT(*) FROM "+originalTable);
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
rs.next(); rs.next();
int count = rs.getInt(1); long count = rs.getLong(1);
rs.close(); rs.close();
return count; return count;
} }
...@@ -238,6 +255,9 @@ public class TableLink extends Table { ...@@ -238,6 +255,9 @@ public class TableLink extends Table {
} }
public PreparedStatement getPreparedStatement(String sql) throws SQLException { public PreparedStatement getPreparedStatement(String sql) throws SQLException {
if(conn == null) {
throw connectException;
}
PreparedStatement prep = (PreparedStatement) prepared.get(sql); PreparedStatement prep = (PreparedStatement) prepared.get(sql);
if(prep==null) { if(prep==null) {
prep = conn.prepareStatement(sql); prep = conn.prepareStatement(sql);
......
...@@ -8,6 +8,7 @@ import java.sql.SQLException; ...@@ -8,6 +8,7 @@ import java.sql.SQLException;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.index.Index; import org.h2.index.Index;
...@@ -17,6 +18,7 @@ import org.h2.message.Message; ...@@ -17,6 +18,7 @@ import org.h2.message.Message;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.SmallLRUCache;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -103,7 +105,14 @@ public class TableView extends Table { ...@@ -103,7 +105,14 @@ public class TableView extends Table {
public PlanItem getBestPlanItem(Session session, int[] masks) throws SQLException { public PlanItem getBestPlanItem(Session session, int[] masks) throws SQLException {
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.cost = index.getCost(session, masks); item.cost = index.getCost(session, masks);
item.setIndex(index);
Index i2 = new ViewIndex(this, index, session, masks);
item.setIndex(i2);
int testing;
// item.setIndex(index);
return item; return item;
} }
...@@ -176,7 +185,7 @@ public class TableView extends Table { ...@@ -176,7 +185,7 @@ public class TableView extends Table {
throw Message.getUnsupportedException(); throw Message.getUnsupportedException();
} }
public int getRowCount() { public long getRowCount() {
throw Message.getInternalError(); throw Message.getInternalError();
} }
......
...@@ -138,9 +138,9 @@ public class ChangePassword { ...@@ -138,9 +138,9 @@ public class ChangePassword {
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
FileStore in; FileStore in;
if(decrypt == null) { if(decrypt == null) {
in = FileStore.open(null, fileName, magic); in = FileStore.open(null, fileName, "r", magic);
} else { } else {
in = FileStore.open(null, fileName, magic, cipher, decrypt); in = FileStore.open(null, fileName, "r", magic, cipher, decrypt);
} }
in.init(); in.init();
copy(fileName, textStorage, in, encrypt); copy(fileName, textStorage, in, encrypt);
...@@ -152,9 +152,9 @@ public class ChangePassword { ...@@ -152,9 +152,9 @@ public class ChangePassword {
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
FileStore out; FileStore out;
if(key == null) { if(key == null) {
out = FileStore.open(null, temp, magic); out = FileStore.open(null, temp, "rw", magic);
} else { } else {
out = FileStore.open(null, temp, magic, cipher, key); out = FileStore.open(null, temp, "rw", magic, cipher, key);
} }
out.init(); out.init();
byte[] buffer = new byte[4 * 1024]; byte[] buffer = new byte[4 * 1024];
......
...@@ -193,19 +193,6 @@ public class Csv implements SimpleRowSource { ...@@ -193,19 +193,6 @@ public class Csv implements SimpleRowSource {
throw e; throw e;
} }
} }
if(columnNames != null) {
writeHeader();
}
}
private void writeHeader() {
for(int i=0; i<columnNames.length; i++) {
if(i>0) {
writer.print(fieldSeparatorWrite);
}
writer.print(columnNames[i]);
}
writer.println();
} }
private void writeRow(String[] values) { private void writeRow(String[] values) {
...@@ -501,8 +488,7 @@ public class Csv implements SimpleRowSource { ...@@ -501,8 +488,7 @@ public class Csv implements SimpleRowSource {
} }
/** /**
* Reset the position (before the first row). * INTERNAL
* This is not supported at this time, and this methods throws a SQLException
*/ */
public void reset() throws SQLException { public void reset() throws SQLException {
throw new SQLException("Method is not supported", "CSV"); throw new SQLException("Method is not supported", "CSV");
......
...@@ -133,7 +133,7 @@ public class Recover implements DataHandler { ...@@ -133,7 +133,7 @@ public class Recover implements DataHandler {
databaseName = fileName.substring(fileName.length() - Constants.SUFFIX_DATA_FILE.length()); databaseName = fileName.substring(fileName.length() - Constants.SUFFIX_DATA_FILE.length());
textStorage = Database.isTextStorage(fileName, false); textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
FileStore store = FileStore.open(null, fileName, magic); FileStore store = FileStore.open(null, fileName, "rw", magic);
long length = store.length(); long length = store.length();
int offset = FileStore.HEADER_LENGTH; int offset = FileStore.HEADER_LENGTH;
int blockSize = DiskFile.BLOCK_SIZE; int blockSize = DiskFile.BLOCK_SIZE;
...@@ -311,7 +311,7 @@ public class Recover implements DataHandler { ...@@ -311,7 +311,7 @@ public class Recover implements DataHandler {
out = new FileOutputStream(n); out = new FileOutputStream(n);
textStorage = Database.isTextStorage(fileName, false); textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
store = FileStore.open(null, fileName, magic); store = FileStore.open(null, fileName, "r", magic);
store.init(); store.init();
in = new BufferedInputStream(new FileStoreInputStream(store, this, lobCompression)); in = new BufferedInputStream(new FileStoreInputStream(store, this, lobCompression));
byte[] buffer = new byte[Constants.IO_BUFFER_SIZE]; byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];
...@@ -393,7 +393,7 @@ public class Recover implements DataHandler { ...@@ -393,7 +393,7 @@ public class Recover implements DataHandler {
writer = getWriter(fileName, ".txt"); writer = getWriter(fileName, ".txt");
textStorage = Database.isTextStorage(fileName, false); textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
store = FileStore.open(null, fileName, magic); store = FileStore.open(null, fileName, "r", magic);
long length = store.length(); long length = store.length();
writer.println("// length: " + length); writer.println("// length: " + length);
int offset = FileStore.HEADER_LENGTH; int offset = FileStore.HEADER_LENGTH;
...@@ -549,7 +549,7 @@ public class Recover implements DataHandler { ...@@ -549,7 +549,7 @@ public class Recover implements DataHandler {
writer = getWriter(fileName, ".txt"); writer = getWriter(fileName, ".txt");
textStorage = Database.isTextStorage(fileName, false); textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
store = FileStore.open(null, fileName, magic); store = FileStore.open(null, fileName, "r", magic);
long length = store.length(); long length = store.length();
int offset = FileStore.HEADER_LENGTH; int offset = FileStore.HEADER_LENGTH;
int blockSize = DiskFile.BLOCK_SIZE; int blockSize = DiskFile.BLOCK_SIZE;
...@@ -627,7 +627,7 @@ public class Recover implements DataHandler { ...@@ -627,7 +627,7 @@ public class Recover implements DataHandler {
HashMap tableMap = new HashMap(); HashMap tableMap = new HashMap();
textStorage = Database.isTextStorage(fileName, false); textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage); byte[] magic = Database.getMagic(textStorage);
store = FileStore.open(null, fileName, magic); store = FileStore.open(null, fileName, "r", magic);
long length = store.length(); long length = store.length();
int offset = FileStore.HEADER_LENGTH; int offset = FileStore.HEADER_LENGTH;
int blockSize = DiskFile.BLOCK_SIZE; int blockSize = DiskFile.BLOCK_SIZE;
...@@ -812,7 +812,7 @@ public class Recover implements DataHandler { ...@@ -812,7 +812,7 @@ public class Recover implements DataHandler {
/** /**
* INTERNAL * INTERNAL
*/ */
public FileStore openFile(String name, boolean mustExist) throws SQLException { public FileStore openFile(String name, String mode, boolean mustExist) throws SQLException {
return null; return null;
} }
......
...@@ -200,7 +200,9 @@ public class RunScript { ...@@ -200,7 +200,9 @@ public class RunScript {
} }
} else { } else {
try { try {
if(sql.trim().length()>0) {
stat.execute(sql); stat.execute(sql);
}
} catch (SQLException e) { } catch (SQLException e) {
if (continueOnError) { if (continueOnError) {
e.printStackTrace(); e.printStackTrace();
......
...@@ -605,4 +605,22 @@ public class StringUtils { ...@@ -605,4 +605,22 @@ public class StringUtils {
return s == null || s.length() == 0; return s == null || s.length() == 0;
} }
public static String quoteRemarkSQL(String sql) {
while(true) {
int idx = sql.indexOf("*/");
if(idx < 0) {
break;
}
sql = sql.substring(0, idx) + "++/" + sql.substring(idx + 2);
}
while(true) {
int idx = sql.indexOf("/*");
if(idx < 0) {
break;
}
sql = sql.substring(0, idx) + "/++" + sql.substring(idx + 2);
}
return sql;
}
} }
...@@ -7,6 +7,7 @@ package org.h2.value; ...@@ -7,6 +7,7 @@ package org.h2.value;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Clob; import java.sql.Clob;
import java.sql.Date; import java.sql.Date;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -37,7 +38,7 @@ public class DataType { ...@@ -37,7 +38,7 @@ public class DataType {
public String jdbc; public String jdbc;
// how closely the data type maps to the corresponding JDBC SQL type (low is best) // how closely the data type maps to the corresponding JDBC SQL type (low is best)
public int order; public int sqlTypePos;
public int maxPrecision; public int maxPrecision;
public int minScale, maxScale; public int minScale, maxScale;
...@@ -51,8 +52,12 @@ public class DataType { ...@@ -51,8 +52,12 @@ public class DataType {
public int defaultScale; public int defaultScale;
public boolean hidden; public boolean hidden;
// for operations that include different types, convert both to the higher order
public int order;
// JDK 1.3 compatibility: Types.BOOLEAN // JDK 1.3 compatibility: Types.BOOLEAN
public static final int TYPE_BOOLEAN = 16; public static final int TYPE_BOOLEAN = 16;
// JDK 1.3 compatibility: Types.DATALINK // JDK 1.3 compatibility: Types.DATALINK
public static final int TYPE_DATALINK = 70; public static final int TYPE_DATALINK = 70;
...@@ -64,11 +69,28 @@ public class DataType { ...@@ -64,11 +69,28 @@ public class DataType {
if(TYPE_DATALINK != Types.DATALINK) { if(TYPE_DATALINK != Types.DATALINK) {
new Exception("Types.DATALINK: " + Types.DATALINK).printStackTrace(); new Exception("Types.DATALINK: " + Types.DATALINK).printStackTrace();
} }
//#endif //#endif
add(Value.NULL, Types.NULL, "Null", add(Value.NULL, Types.NULL, "Null",
new DataType(), new DataType(),
new String[]{"NULL"} new String[]{"NULL"}
); );
add(Value.STRING, Types.VARCHAR, "String",
createString(true),
new String[]{"VARCHAR", "VARCHAR2", "NVARCHAR", "NVARCHAR2", "VARCHAR_CASESENSITIVE", "CHARACTER VARYING"}
);
add(Value.STRING, Types.LONGVARCHAR, "String",
createString(true),
new String[]{"LONGVARCHAR"}
);
add(Value.STRING_FIXED, Types.CHAR, "String",
createString(true),
new String[]{"CHAR", "CHARACTER", "NCHAR"}
);
add(Value.STRING_IGNORECASE, Types.VARCHAR, "String",
createString(false),
new String[]{"VARCHAR_IGNORECASE"}
);
add(Value.BOOLEAN, DataType.TYPE_BOOLEAN, "Boolean", add(Value.BOOLEAN, DataType.TYPE_BOOLEAN, "Boolean",
createDecimal(ValueBoolean.PRECISION, ValueBoolean.PRECISION, 0, false, false), createDecimal(ValueBoolean.PRECISION, ValueBoolean.PRECISION, 0, false, false),
new String[]{"BOOLEAN", "BIT", "BOOL"} new String[]{"BOOLEAN", "BIT", "BOOL"}
...@@ -103,6 +125,10 @@ public class DataType { ...@@ -103,6 +125,10 @@ public class DataType {
new String[]{"NUMERIC", "NUMBER"} new String[]{"NUMERIC", "NUMBER"}
// TODO value: are NaN, Inf, -Inf,... supported as well? // TODO value: are NaN, Inf, -Inf,... supported as well?
); );
add(Value.FLOAT, Types.REAL, "Float",
createDecimal(ValueFloat.PRECISION, ValueFloat.PRECISION, 0, false, false),
new String[] {"REAL", "FLOAT4"}
);
add(Value.DOUBLE, Types.DOUBLE, "Double", add(Value.DOUBLE, Types.DOUBLE, "Double",
createDecimal(ValueDouble.PRECISION, ValueDouble.PRECISION, 0, false, false), createDecimal(ValueDouble.PRECISION, ValueDouble.PRECISION, 0, false, false),
new String[] { "DOUBLE", "DOUBLE PRECISION" } new String[] { "DOUBLE", "DOUBLE PRECISION" }
...@@ -112,10 +138,6 @@ public class DataType { ...@@ -112,10 +138,6 @@ public class DataType {
new String[] {"FLOAT", "FLOAT8" } new String[] {"FLOAT", "FLOAT8" }
// TODO value: show min and max values, E format if supported // TODO value: show min and max values, E format if supported
); );
add(Value.FLOAT, Types.REAL, "Float",
createDecimal(ValueFloat.PRECISION, ValueFloat.PRECISION, 0, false, false),
new String[] {"REAL", "FLOAT4"}
);
add(Value.TIME, Types.TIME, "Time", add(Value.TIME, Types.TIME, "Time",
createDate(ValueTime.PRECISION, "TIME", 0), createDate(ValueTime.PRECISION, "TIME", 0),
new String[]{"TIME"} new String[]{"TIME"}
...@@ -139,33 +161,17 @@ public class DataType { ...@@ -139,33 +161,17 @@ public class DataType {
createString(false), createString(false),
new String[]{"BINARY", "RAW", "BYTEA", "LONG RAW"} new String[]{"BINARY", "RAW", "BYTEA", "LONG RAW"}
); );
add(Value.UUID, Types.BINARY, "Bytes",
createString(false),
new String[]{"UUID"}
);
add(Value.BYTES, Types.LONGVARBINARY, "Bytes", add(Value.BYTES, Types.LONGVARBINARY, "Bytes",
createString(false), createString(false),
new String[]{"LONGVARBINARY"} new String[]{"LONGVARBINARY"}
); );
add(Value.JAVA_OBJECT, Types.OTHER, "Object", add(Value.UUID, Types.BINARY, "Bytes",
createString(false), createString(false),
new String[]{"OTHER", "OBJECT", "JAVA_OBJECT"} new String[]{"UUID"}
);
add(Value.STRING, Types.VARCHAR, "String",
createString(true),
new String[]{"VARCHAR", "VARCHAR2", "NVARCHAR", "NVARCHAR2", "VARCHAR_CASESENSITIVE"}
);
add(Value.STRING, Types.LONGVARCHAR, "String",
createString(true),
new String[]{"LONGVARCHAR"}
);
add(Value.STRING, Types.CHAR, "String",
createString(true),
new String[]{"CHAR", "CHARACTER", "NCHAR"}
); );
add(Value.STRING_IGNORECASE, Types.VARCHAR, "String", add(Value.JAVA_OBJECT, Types.OTHER, "Object",
createString(false), createString(false),
new String[]{"VARCHAR_IGNORECASE"} new String[]{"OTHER", "OBJECT", "JAVA_OBJECT"}
); );
add(Value.BLOB, Types.BLOB, "Bytes", add(Value.BLOB, Types.BLOB, "Bytes",
createString(false), createString(false),
...@@ -182,6 +188,18 @@ public class DataType { ...@@ -182,6 +188,18 @@ public class DataType {
dataType, dataType,
new String[]{"ARRAY"} new String[]{"ARRAY"}
); );
dataType = new DataType();
add(Value.RESULT_SET, 0, "ResultSet",
dataType,
new String[]{"RESULT_SET"}
);
for(int i=0; i<typesByValueType.length; i++) {
DataType dt = typesByValueType[i];
if(dt == null) {
throw Message.getInternalError("unmapped type " + i);
}
Value.getOrder(i);
}
// TODO data types: try to support other types as well (longvarchar for odbc/access,...) - maybe map them to regular types? // TODO data types: try to support other types as well (longvarchar for odbc/access,...) - maybe map them to regular types?
} }
...@@ -209,7 +227,7 @@ public class DataType { ...@@ -209,7 +227,7 @@ public class DataType {
for(int j=0; j<types.size(); j++) { for(int j=0; j<types.size(); j++) {
DataType t2 = (DataType) types.get(j); DataType t2 = (DataType) types.get(j);
if(t2.sqlType == dt.sqlType) { if(t2.sqlType == dt.sqlType) {
dt.order++; dt.sqlTypePos++;
} }
} }
typesByName.put(dt.name, dt); typesByName.put(dt.name, dt);
...@@ -338,7 +356,16 @@ public class DataType { ...@@ -338,7 +356,16 @@ public class DataType {
v = rs.wasNull() ? (Value)ValueNull.INSTANCE : ValueShort.get(value); v = rs.wasNull() ? (Value)ValueNull.INSTANCE : ValueShort.get(value);
break; break;
} }
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE: {
String s = rs.getString(columnIndex);
v = (s == null) ? (Value)ValueNull.INSTANCE : ValueStringIgnoreCase.get(s);
break;
}
case Value.STRING_FIXED: {
String s = rs.getString(columnIndex);
v = (s == null) ? (Value)ValueNull.INSTANCE : ValueStringFixed.get(s);
break;
}
case Value.STRING: { case Value.STRING: {
String s = rs.getString(columnIndex); String s = rs.getString(columnIndex);
v = (s == null) ? (Value)ValueNull.INSTANCE : ValueString.get(s); v = (s == null) ? (Value)ValueNull.INSTANCE : ValueString.get(s);
...@@ -367,6 +394,22 @@ public class DataType { ...@@ -367,6 +394,22 @@ public class DataType {
v = buff==null ? (Value)ValueNull.INSTANCE : ValueJavaObject.getNoCopy(buff); v = buff==null ? (Value)ValueNull.INSTANCE : ValueJavaObject.getNoCopy(buff);
break; break;
} }
case Value.ARRAY: {
Array array = rs.getArray(columnIndex);
if(array == null) {
return ValueNull.INSTANCE;
}
Object[] list = (Object[])array.getArray();
if(list == null) {
return ValueNull.INSTANCE;
}
Value[] values = new Value[list.length];
for(int i=0; i<list.length; i++) {
values[i] = DataType.convertToValue(session, list[i], Value.NULL);
}
v = array ==null ? (Value)ValueNull.INSTANCE : ValueArray.get(values);
break;
}
default: default:
throw Message.getInternalError("type="+type); throw Message.getInternalError("type="+type);
} }
...@@ -398,6 +441,7 @@ public class DataType { ...@@ -398,6 +441,7 @@ public class DataType {
return byte[].class.getName(); // "[B", not "byte[]"; return byte[].class.getName(); // "[B", not "byte[]";
case Value.STRING: case Value.STRING:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
return String.class.getName(); // "java.lang.String"; return String.class.getName(); // "java.lang.String";
case Value.BLOB: case Value.BLOB:
return java.sql.Blob.class.getName(); // "java.sql.Blob"; return java.sql.Blob.class.getName(); // "java.sql.Blob";
...@@ -430,8 +474,9 @@ public class DataType { ...@@ -430,8 +474,9 @@ public class DataType {
public static int convertSQLTypeToValueType(int sqlType) throws SQLException { public static int convertSQLTypeToValueType(int sqlType) throws SQLException {
switch(sqlType) { switch(sqlType) {
case Types.VARCHAR:
case Types.CHAR: case Types.CHAR:
return Value.STRING_FIXED;
case Types.VARCHAR:
case Types.LONGVARCHAR: case Types.LONGVARCHAR:
return Value.STRING; return Value.STRING;
case Types.NUMERIC: case Types.NUMERIC:
......
...@@ -239,6 +239,7 @@ public class Transfer { ...@@ -239,6 +239,7 @@ public class Transfer {
break; break;
case Value.STRING: case Value.STRING:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
writeString(v.getString()); writeString(v.getString());
break; break;
case Value.BLOB: { case Value.BLOB: {
...@@ -354,6 +355,8 @@ public class Transfer { ...@@ -354,6 +355,8 @@ public class Transfer {
return ValueString.get(readString()); return ValueString.get(readString());
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
return ValueStringIgnoreCase.get(readString()); return ValueStringIgnoreCase.get(readString());
case Value.STRING_FIXED:
return ValueStringFixed.get(readString());
case Value.BLOB: { case Value.BLOB: {
long length = readLong(); long length = readLong();
ValueLob v = ValueLob.createBlob(in, length, session.getDataHandler()); ValueLob v = ValueLob.createBlob(in, length, session.getDataHandler());
......
...@@ -38,9 +38,9 @@ public abstract class Value { ...@@ -38,9 +38,9 @@ public abstract class Value {
public static final int NULL = 0, BOOLEAN = 1, BYTE = 2, SHORT = 3, INT = 4, LONG = 5, DECIMAL = 6; public static final int NULL = 0, BOOLEAN = 1, BYTE = 2, SHORT = 3, INT = 4, LONG = 5, DECIMAL = 6;
public static final int DOUBLE = 7, FLOAT = 8, TIME = 9, DATE = 10, TIMESTAMP = 11, BYTES = 12; public static final int DOUBLE = 7, FLOAT = 8, TIME = 9, DATE = 10, TIMESTAMP = 11, BYTES = 12;
public static final int STRING = 13, STRING_IGNORECASE = 14, BLOB = 15, CLOB = 16; public static final int STRING = 13, STRING_IGNORECASE = 14, BLOB = 15, CLOB = 16;
public static final int ARRAY = 17, RESULT_SET = 18, JAVA_OBJECT = 19, UUID = 20; public static final int ARRAY = 17, RESULT_SET = 18, JAVA_OBJECT = 19, UUID = 20, STRING_FIXED = 21;
public static final int TYPE_COUNT = UUID + 1; public static final int TYPE_COUNT = STRING_FIXED + 1;
private static WeakReference weakCache = new WeakReference(null); private static WeakReference weakCache = new WeakReference(null);
// private static int cacheCleaner = 0; // private static int cacheCleaner = 0;
...@@ -49,9 +49,73 @@ public abstract class Value { ...@@ -49,9 +49,73 @@ public abstract class Value {
// private static Value[] cache = new Value[Constants.OBJECT_CACHE_SIZE]; // private static Value[] cache = new Value[Constants.OBJECT_CACHE_SIZE];
private static final BigDecimal MAX_LONG_DECIMAL = new BigDecimal("" + Long.MAX_VALUE); private static final BigDecimal MAX_LONG_DECIMAL = new BigDecimal("" + Long.MAX_VALUE);
private static final BigDecimal MIN_LONG_DECIMAL = new BigDecimal("" + Long.MIN_VALUE); private static final BigDecimal MIN_LONG_DECIMAL = new BigDecimal("" + Long.MIN_VALUE);
public static int getOrder(int type) {
switch(type) {
case UNKNOWN:
return 1;
case NULL:
return 2;
case STRING:
return 10;
case CLOB:
return 11;
case STRING_FIXED:
return 12;
case STRING_IGNORECASE:
return 13;
case BOOLEAN:
return 20;
case BYTE:
return 21;
case SHORT:
return 22;
case INT:
return 23;
case LONG:
return 24;
case DECIMAL:
return 25;
case FLOAT:
return 26;
case DOUBLE:
return 27;
case TIME:
return 30;
case DATE:
return 31;
case TIMESTAMP:
return 32;
case BYTES:
return 40;
case BLOB:
return 41;
case UUID:
return 42;
case JAVA_OBJECT:
return 43;
case ARRAY:
return 50;
case RESULT_SET:
return 51;
default:
throw Message.getInternalError("type:"+type);
}
}
public static int getHigherOrder(int t1, int t2) throws SQLException {
if(t1 == t2) {
if(t1 == Value.UNKNOWN) {
throw Message.getSQLException(Message.UNKNOWN_DATA_TYPE_1, "?, ?");
}
return t1;
}
int o1 = getOrder(t1);
int o2 = getOrder(t2);
return o1 > o2 ? t1 : t2;
}
static Value cache(Value v) { static Value cache(Value v) {
if (Constants.OBJECT_CACHE) { if (Constants.OBJECT_CACHE) {
Value[] cache = (Value[]) weakCache.get(); Value[] cache = (Value[]) weakCache.get();
...@@ -81,7 +145,6 @@ public abstract class Value { ...@@ -81,7 +145,6 @@ public abstract class Value {
public abstract long getPrecision(); public abstract long getPrecision();
public abstract int getDisplaySize(); public abstract int getDisplaySize();
public abstract String getString() throws SQLException; public abstract String getString() throws SQLException;
// public abstract String getJavaString();
protected abstract int compareSecure(Value v, CompareMode mode) throws SQLException; protected abstract int compareSecure(Value v, CompareMode mode) throws SQLException;
protected abstract boolean isEqual(Value v); protected abstract boolean isEqual(Value v);
public abstract Object getObject() throws SQLException; public abstract Object getObject() throws SQLException;
...@@ -183,33 +246,6 @@ public abstract class Value { ...@@ -183,33 +246,6 @@ public abstract class Value {
throw Message.getUnsupportedException(); throw Message.getUnsupportedException();
} }
public static int getHigherOrder(int t1, int t2) throws SQLException {
if(t1 == t2) {
if(t1 == Value.UNKNOWN) {
throw Message.getSQLException(Message.UNKNOWN_DATA_TYPE_1, "?, ?");
}
return t1;
}
int type = Math.max(t1, t2);
switch(type) {
case Value.STRING:
case Value.STRING_IGNORECASE: {
int b = Math.min(t1, t2);
switch(b) {
case Value.BLOB:
case Value.BYTES:
case Value.DATE:
case Value.JAVA_OBJECT:
case Value.TIME:
case Value.TIMESTAMP:
case Value.UUID:
return b;
}
}
}
return type;
}
public Value convertTo(int type) throws SQLException { public Value convertTo(int type) throws SQLException {
// converting NULL done in ValueNull // converting NULL done in ValueNull
// converting BLOB to CLOB and vice versa is done in ValueLob // converting BLOB to CLOB and vice versa is done in ValueLob
...@@ -482,6 +518,8 @@ public abstract class Value { ...@@ -482,6 +518,8 @@ public abstract class Value {
return ValueString.get(s); return ValueString.get(s);
case STRING_IGNORECASE: case STRING_IGNORECASE:
return ValueStringIgnoreCase.get(s); return ValueStringIgnoreCase.get(s);
case STRING_FIXED:
return ValueStringFixed.get(s);
case DOUBLE: case DOUBLE:
return ValueDouble.get(Double.parseDouble(s.trim())); return ValueDouble.get(Double.parseDouble(s.trim()));
case FLOAT: case FLOAT:
......
...@@ -288,7 +288,7 @@ public class ValueLob extends Value { ...@@ -288,7 +288,7 @@ public class ValueLob extends Value {
objectId = handler.allocateObjectId(false, true); objectId = handler.allocateObjectId(false, true);
fileName = handler.createTempFile(); fileName = handler.createTempFile();
} }
tempFile = handler.openFile(fileName, false); tempFile = handler.openFile(fileName, "rw", false);
tempFile.autoDelete(); tempFile.autoDelete();
} }
FileStoreOutputStream out = new FileStoreOutputStream(tempFile, handler, compressionAlgorithm); FileStoreOutputStream out = new FileStoreOutputStream(tempFile, handler, compressionAlgorithm);
...@@ -360,7 +360,7 @@ public class ValueLob extends Value { ...@@ -360,7 +360,7 @@ public class ValueLob extends Value {
} }
deleteFile(handler, temp); deleteFile(handler, temp);
renameFile(handler, fileName, temp); renameFile(handler, fileName, temp);
tempFile = FileStore.open(handler, temp, null); tempFile = FileStore.open(handler, temp, "rw", null);
tempFile.autoDelete(); tempFile.autoDelete();
tempFile.closeSilently(); tempFile.closeSilently();
fileName = temp; fileName = temp;
...@@ -491,7 +491,7 @@ public class ValueLob extends Value { ...@@ -491,7 +491,7 @@ public class ValueLob extends Value {
if (fileName == null) { if (fileName == null) {
return new ByteArrayInputStream(small); return new ByteArrayInputStream(small);
} }
FileStore store = handler.openFile(fileName, true); FileStore store = handler.openFile(fileName, "r", true);
return new BufferedInputStream(new FileStoreInputStream(store, handler, compression), Constants.IO_BUFFER_SIZE); return new BufferedInputStream(new FileStoreInputStream(store, handler, compression), Constants.IO_BUFFER_SIZE);
} }
......
...@@ -137,6 +137,15 @@ class Database { ...@@ -137,6 +137,15 @@ class Database {
} finally { } finally {
JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(stat);
} }
} else if(url.startsWith("jdbc:hsqldb:")) {
// HSQLDB: use a WRITE_DELAY of 1 second
Statement stat = null;
try {
stat = conn.createStatement();
stat.execute("SET WRITE_DELAY 1");
} finally {
JdbcUtils.closeSilently(stat);
}
} }
return conn; return conn;
} }
......
...@@ -2,7 +2,7 @@ db1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000, sa, sa ...@@ -2,7 +2,7 @@ db1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000, sa, sa
xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;CIPHER=XTEA, sa, sa 123 xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;CIPHER=XTEA, sa, sa 123
xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;CIPHER=AES, sa, sa 123 xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;CIPHER=AES, sa, sa 123
db2 = HSQLDB, org.hsqldb.jdbcDriver, jdbc:hsqldb:data/test;hsqldb.default_table_type=cached, 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 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, sa, sa db4 = H2, org.h2.Driver, jdbc:h2:tcp://localhost/data/testServer;LOCK_TIMEOUT=10000, sa, sa
...@@ -11,11 +11,11 @@ db6 = Derby, org.apache.derby.jdbc.ClientDriver, jdbc:derby://localhost/data/tes ...@@ -11,11 +11,11 @@ db6 = Derby, org.apache.derby.jdbc.ClientDriver, jdbc:derby://localhost/data/tes
db7 = PostgreSQL, org.postgresql.Driver, jdbc:postgresql:test, sa, sa db7 = PostgreSQL, org.postgresql.Driver, jdbc:postgresql:test, sa, sa
db8 = MySQL, com.mysql.jdbc.Driver, jdbc:mysql://localhost/test?jdbcCompliantTruncation=false, sa, sa db8 = MySQL, com.mysql.jdbc.Driver, jdbc:mysql://localhost/test?jdbcCompliantTruncation=false, sa, sa
#db2 = Firebird, org.firebirdsql.jdbc.FBDriver, jdbc:firebirdsql:localhost:c:/temp/firebird/test, sysdba, masterkey #db2 = MSSQLServer, com.microsoft.jdbc.sqlserver.SQLServerDriver, jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=test, test, test
#db2 = Oracle, oracle.jdbc.driver.OracleDriver, jdbc:oracle:thin:@localhost:1521:XE, client, client #db2 = Oracle, oracle.jdbc.driver.OracleDriver, jdbc:oracle:thin:@localhost:1521:XE, client, client
#db2 = OneDollarDB, in.co.daffodil.db.jdbc.DaffodilDBDriver, jdbc:daffodilDB_embedded:school;path=C:/temp;create=true, sa #db2 = Firebird, org.firebirdsql.jdbc.FBDriver, jdbc:firebirdsql:localhost:c:/temp/firebird/test, sysdba, masterkey
#db2 = DB2, COM.ibm.db2.jdbc.net.DB2Driver, jdbc:db2://localhost/test, test, test #db2 = DB2, COM.ibm.db2.jdbc.net.DB2Driver, jdbc:db2://localhost/test, test, test
#db2 = MSSQLServer, com.microsoft.jdbc.sqlserver.SQLServerDriver, jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=test, test, test #db2 = OneDollarDB, in.co.daffodil.db.jdbc.DaffodilDBDriver, jdbc:daffodilDB_embedded:school;path=C:/temp;create=true, sa
firebirdsql.datetime = TIMESTAMP firebirdsql.datetime = TIMESTAMP
postgresql.datetime = TIMESTAMP postgresql.datetime = TIMESTAMP
......
...@@ -7,6 +7,7 @@ package org.h2.test.db; ...@@ -7,6 +7,7 @@ package org.h2.test.db;
import java.io.File; import java.io.File;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.Statement; import java.sql.Statement;
...@@ -34,6 +35,14 @@ public class TestCsv extends TestBase { ...@@ -34,6 +35,14 @@ public class TestCsv extends TestBase {
check(rs.getString(2), "Hello"); check(rs.getString(2), "Hello");
checkFalse(rs.next()); checkFalse(rs.next());
new File(BASE_DIR+"/test.csv").delete(); new File(BASE_DIR+"/test.csv").delete();
int testing;
// PreparedStatement prep = conn.prepareStatement("select * from csvread(?, null, ?, ?)");
// prep.setString(1, BASE_DIR+"/test.csv");
// prep.setString(2, "utf-8");
// prep.setString(3, "|");
// rs = prep.executeQuery();
conn.close(); conn.close();
} }
......
...@@ -26,6 +26,8 @@ public class TestMemoryUsage extends TestBase { ...@@ -26,6 +26,8 @@ public class TestMemoryUsage extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
deleteDb("memoryUsage");
testReconnectOften();
deleteDb("memoryUsage"); deleteDb("memoryUsage");
reconnect(); reconnect();
insertUpdateSelectDelete(); insertUpdateSelectDelete();
...@@ -34,6 +36,22 @@ public class TestMemoryUsage extends TestBase { ...@@ -34,6 +36,22 @@ public class TestMemoryUsage extends TestBase {
conn.close(); conn.close();
} }
private void testReconnectOften() throws Exception {
int len = getSize(1, 2000);
Connection conn1 = getConnection("memoryUsage");
printTimeMemory("start", 0);
long time = System.currentTimeMillis();
for(int i=0; i<len; i++) {
Connection conn2 = getConnection("memoryUsage");
conn2.close();
if(i % 10000 == 0) {
printTimeMemory("connect", System.currentTimeMillis()-time);
}
}
printTimeMemory("connect", System.currentTimeMillis()-time);
conn1.close();
}
void insertUpdateSelectDelete() throws Exception { void insertUpdateSelectDelete() throws Exception {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
long time; long time;
......
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
create table d(d double, r real);
> ok
insert into d values(1.1234567890123456789, 1.1234567890123456789);
> update count: 1
select r+d, r+r, d+d from d;
> R + D R + R D + D
> ----------------- --------- ------------------
> 2.246913624759111 2.2469137 2.2469135780246914
> rows: 1
drop table d;
> ok
create table test(id int, c char(5), v varchar(5));
> ok
insert into test values(1, 'a', 'a');
> update count: 1
insert into test values(2, 'a ', 'a ');
> update count: 1
insert into test values(3, 'abcde ', 'abcde');
> update count: 1
select distinct length(c) from test order by length(c);
> LENGTH(C)
> ---------
> 1
> 5
> rows (ordered): 2
select id, c, v, length(c), length(v) from test order by id;
> ID C V LENGTH(C) LENGTH(V)
> -- ----- ----- --------- ---------
> 1 a a 1 1
> 2 a a 1 2
> 3 abcde abcde 5 5
> rows (ordered): 3
select id from test where c='a' order by id;
> ID
> --
> 1
> 2
> rows (ordered): 2
select id from test where c='a ' order by id;
> ID
> --
> 1
> 2
> rows (ordered): 2
select id from test where c=v order by id;
> ID
> --
> 1
> 2
> 3
> rows (ordered): 3
drop table test;
> ok
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), C INT); CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), C INT);
> ok > ok
...@@ -215,8 +282,8 @@ script nopasswords nosettings blocksize 10; ...@@ -215,8 +282,8 @@ script nopasswords nosettings blocksize 10;
> ------------------------------------------------------------------------------------------------------------------ > ------------------------------------------------------------------------------------------------------------------
> -- 1 = SELECT COUNT(*) FROM PUBLIC.TEST > -- 1 = SELECT COUNT(*) FROM PUBLIC.TEST
> CALL SYSTEM_COMBINE_BLOB(-1) > CALL SYSTEM_COMBINE_BLOB(-1)
> CREATE ALIAS IF NOT EXISTS SYSTEM_COMBINE_BLOB FOR "org.h2.command.dml.Script.combineBlob" > CREATE ALIAS IF NOT EXISTS SYSTEM_COMBINE_BLOB FOR "org.h2.command.dml.ScriptCommand.combineBlob"
> CREATE ALIAS IF NOT EXISTS SYSTEM_COMBINE_CLOB FOR "org.h2.command.dml.Script.combineClob" > CREATE ALIAS IF NOT EXISTS SYSTEM_COMBINE_CLOB FOR "org.h2.command.dml.ScriptCommand.combineClob"
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, DATA CLOB ) > CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, DATA CLOB )
> CREATE PRIMARY KEY ON PUBLIC.TEST(ID) > CREATE PRIMARY KEY ON PUBLIC.TEST(ID)
> CREATE TABLE IF NOT EXISTS SYSTEM_LOB_STREAM(ID INT, PART INT, CDATA VARCHAR, BDATA BINARY, PRIMARY KEY(ID, PART)) > CREATE TABLE IF NOT EXISTS SYSTEM_LOB_STREAM(ID INT, PART INT, CDATA VARCHAR, BDATA BINARY, PRIMARY KEY(ID, PART))
...@@ -4373,8 +4440,8 @@ SELECT * FROM V_UNION WHERE ID=1; ...@@ -4373,8 +4440,8 @@ SELECT * FROM V_UNION WHERE ID=1;
EXPLAIN SELECT * FROM V_UNION WHERE ID=1; EXPLAIN SELECT * FROM V_UNION WHERE ID=1;
> PLAN > PLAN
> ----------------------------------------------------------------------------------------------------------------------------------------------------- > -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT V_UNION.ID, V_UNION.NAME, V_UNION.CLASS FROM PUBLIC.V_UNION /* SELECT * FROM CHILDREN UNION ALL SELECT * FROM CHILDREN: ID = 1 */ WHERE ID = 1 > SELECT V_UNION.ID, V_UNION.NAME, V_UNION.CLASS FROM PUBLIC.V_UNION /* (SELECT CHILDREN.ID, CHILDREN.NAME, CHILDREN.CLASS FROM PUBLIC.CHILDREN /++ PUBLIC.PRIMARY_KEY_1: ID = CAST(?1 AS INTEGER) ++/ WHERE CHILDREN.ID = CAST(?1 AS INTEGER)) UNION ALL (SELECT CHILDREN.ID, CHILDREN.NAME, CHILDREN.CLASS FROM PUBLIC.CHILDREN /++ PUBLIC.PRIMARY_KEY_1: ID = CAST(?1 AS INTEGER) ++/ WHERE CHILDREN.ID = CAST(?1 AS INTEGER)): ID = 1 */ WHERE ID = 1
> rows: 1 > rows: 1
CREATE VIEW V_EXCEPT AS SELECT * FROM CHILDREN EXCEPT SELECT * FROM CHILDREN WHERE ID=2; CREATE VIEW V_EXCEPT AS SELECT * FROM CHILDREN EXCEPT SELECT * FROM CHILDREN WHERE ID=2;
...@@ -4388,8 +4455,8 @@ SELECT * FROM V_EXCEPT WHERE ID=1; ...@@ -4388,8 +4455,8 @@ SELECT * FROM V_EXCEPT WHERE ID=1;
EXPLAIN SELECT * FROM V_EXCEPT WHERE ID=1; EXPLAIN SELECT * FROM V_EXCEPT WHERE ID=1;
> PLAN > PLAN
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------- > -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT V_EXCEPT.ID, V_EXCEPT.NAME, V_EXCEPT.CLASS FROM PUBLIC.V_EXCEPT /* SELECT * FROM CHILDREN EXCEPT SELECT * FROM CHILDREN WHERE ID=2: ID = 1 */ WHERE ID = 1 > SELECT V_EXCEPT.ID, V_EXCEPT.NAME, V_EXCEPT.CLASS FROM PUBLIC.V_EXCEPT /* (SELECT CHILDREN.ID, CHILDREN.NAME, CHILDREN.CLASS FROM PUBLIC.CHILDREN /++ PUBLIC.PRIMARY_KEY_1: ID = CAST(?1 AS INTEGER) ++/ WHERE CHILDREN.ID = CAST(?1 AS INTEGER)) EXCEPT (SELECT CHILDREN.ID, CHILDREN.NAME, CHILDREN.CLASS FROM PUBLIC.CHILDREN /++ PUBLIC.PRIMARY_KEY_1: ID = 2 ++/ WHERE ID = 2): ID = 1 */ WHERE ID = 1
> rows: 1 > rows: 1
CREATE VIEW V_INTERSECT AS SELECT ID, NAME FROM CHILDREN INTERSECT SELECT * FROM CLASSES; CREATE VIEW V_INTERSECT AS SELECT ID, NAME FROM CHILDREN INTERSECT SELECT * FROM CLASSES;
...@@ -4402,8 +4469,8 @@ SELECT * FROM V_INTERSECT WHERE ID=1; ...@@ -4402,8 +4469,8 @@ SELECT * FROM V_INTERSECT WHERE ID=1;
EXPLAIN SELECT * FROM V_INTERSECT WHERE ID=1; EXPLAIN SELECT * FROM V_INTERSECT WHERE ID=1;
> PLAN > PLAN
> -------------------------------------------------------------------------------------------------------------------------------------------------------- > -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT V_INTERSECT.ID, V_INTERSECT.NAME FROM PUBLIC.V_INTERSECT /* SELECT ID, NAME FROM CHILDREN INTERSECT SELECT * FROM CLASSES: ID = 1 */ WHERE ID = 1 > SELECT V_INTERSECT.ID, V_INTERSECT.NAME FROM PUBLIC.V_INTERSECT /* (SELECT ID, NAME FROM PUBLIC.CHILDREN /++ PUBLIC.PRIMARY_KEY_1: ID = CAST(?1 AS INTEGER) ++/ WHERE ID = CAST(?1 AS INTEGER)) INTERSECT (SELECT CLASSES.ID, CLASSES.NAME FROM PUBLIC.CLASSES /++ PUBLIC.PRIMARY_KEY_2: ID = CAST(?1 AS INTEGER) ++/ WHERE CLASSES.ID = CAST(?1 AS INTEGER)): ID = 1 */ WHERE ID = 1
> rows: 1 > rows: 1
DROP VIEW V_UNION; DROP VIEW V_UNION;
...@@ -4510,10 +4577,10 @@ CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2; ...@@ -4510,10 +4577,10 @@ CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2;
> ok > ok
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW'; SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW';
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE STORAGE_TYPE SQL REMARKS > TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE STORAGE_TYPE SQL REMARKS ID
> ------------- ------------ ---------- ---------- ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ------- > ------------- ------------ ---------- ---------- ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ------- ---
> SCRIPT PUBLIC TEST_ALL VIEW MEMORY CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AID, A.NAME A_NAME, B.ID BID, B.NAME B_NAME FROM TEST_A A, TEST_B B WHERE A.ID = B.ID > SCRIPT PUBLIC TEST_ALL VIEW MEMORY CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AID, A.NAME A_NAME, B.ID BID, B.NAME B_NAME FROM TEST_A A, TEST_B B WHERE A.ID = B.ID 513
> SCRIPT PUBLIC TEST_A_SUB VIEW MEMORY CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT * FROM TEST_A WHERE ID < 2 > SCRIPT PUBLIC TEST_A_SUB VIEW MEMORY CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT * FROM TEST_A WHERE ID < 2 515
> rows: 2 > rows: 2
SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL; SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL;
......
...@@ -93,7 +93,7 @@ public class TestDataPage extends TestBase implements DataHandler { ...@@ -93,7 +93,7 @@ public class TestDataPage extends TestBase implements DataHandler {
return null; return null;
} }
public FileStore openFile(String name, boolean mustExist) throws SQLException { public FileStore openFile(String name, String mode, boolean mustExist) throws SQLException {
return null; return null;
} }
......
...@@ -88,7 +88,7 @@ public class TestValueHashMap extends TestBase implements DataHandler { ...@@ -88,7 +88,7 @@ public class TestValueHashMap extends TestBase implements DataHandler {
return null; return null;
} }
public FileStore openFile(String name, boolean mustExist) throws SQLException { public FileStore openFile(String name, String mode, boolean mustExist) throws SQLException {
return null; return null;
} }
......
...@@ -88,7 +88,7 @@ public class XMLChecker { ...@@ -88,7 +88,7 @@ public class XMLChecker {
} }
private static void checkXML(String xml, boolean html) throws Exception { private static void checkXML(String xml, boolean html) throws Exception {
String lastElement = null; // String lastElement = null;
// <li>: replace <li>([^\r]*[^<]*) with <li>$1</li> // <li>: replace <li>([^\r]*[^<]*) with <li>$1</li>
// use this for html file, for example if <li> is not closed // use this for html file, for example if <li> is not closed
String[] noClose = new String[]{}; String[] noClose = new String[]{};
...@@ -107,9 +107,6 @@ public class XMLChecker { ...@@ -107,9 +107,6 @@ public class XMLChecker {
rootElement = true; rootElement = true;
} }
String name = parser.getName(); String name = parser.getName();
if(html && name.equals("table") && lastElement.trim().length() > 0) {
throw new Exception("Test before table: " + lastElement);
}
for(int i=0; html && i<noClose.length; i++) { for(int i=0; html && i<noClose.length; i++) {
if(name.equals(noClose[i])) { if(name.equals(noClose[i])) {
name = null; name = null;
...@@ -134,7 +131,7 @@ public class XMLChecker { ...@@ -134,7 +131,7 @@ public class XMLChecker {
throw new Exception("Unclosed element " + pop + " at " + parser.getRemaining()); throw new Exception("Unclosed element " + pop + " at " + parser.getRemaining());
} }
} else if(event == XMLParser.CHARACTERS) { } else if(event == XMLParser.CHARACTERS) {
lastElement = parser.getText(); // lastElement = parser.getText();
} else if(event == XMLParser.DTD) { } else if(event == XMLParser.DTD) {
} else if(event == XMLParser.COMMENT) { } else if(event == XMLParser.COMMENT) {
} else { } else {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论