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

javadocs

上级 cf963b69
...@@ -17,7 +17,7 @@ Change Log ...@@ -17,7 +17,7 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li> <li>RUNSCRIPT could throw a NullPointerException if the script name was an expression.
</li><li>Improved compatibility. New compatibility modes for Oracle and Derby. </li><li>Improved compatibility. New compatibility modes for Oracle and Derby.
New compatibility flag uniqueIndexNullDistinct to only allow one row with 'NULL' in a unique New compatibility flag uniqueIndexNullDistinct to only allow one row with 'NULL' in a unique
index. This flag is enabled for Derby, Oracle, MSSQLServer, and HSQLDB. index. This flag is enabled for Derby, Oracle, MSSQLServer, and HSQLDB.
......
...@@ -311,6 +311,20 @@ http://groups.google.com/group/h2-database/web/roadmap ...@@ -311,6 +311,20 @@ http://groups.google.com/group/h2-database/web/roadmap
<td class="compareY">Yes</td> <td class="compareY">Yes</td>
<td class="compareY">Yes</td> <td class="compareY">Yes</td>
</tr><tr> </tr><tr>
<td>Computed Columns</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
<td class="compareN">No</td>
<td class="compareY">Yes *6</td>
</tr><tr>
<td>Case Insensitive Columns</td>
<td class="compareY">Yes</td>
<td class="compareN">No</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes</td>
<td class="compareY">Yes *6</td>
</tr><tr>
<td>Custom Aggregate Functions</td> <td>Custom Aggregate Functions</td>
<td class="compareY">Yes</td> <td class="compareY">Yes</td>
<td class="compareN">No</td> <td class="compareN">No</td>
...@@ -331,7 +345,8 @@ http://groups.google.com/group/h2-database/web/roadmap ...@@ -331,7 +345,8 @@ http://groups.google.com/group/h2-database/web/roadmap
*2 MySQL supports linked MySQL tables under the name 'federated tables'.<br /> *2 MySQL supports linked MySQL tables under the name 'federated tables'.<br />
*3 Derby support for roles based security and password checking as an option.<br /> *3 Derby support for roles based security and password checking as an option.<br />
*4 Derby only supports global temporary tables.<br /> *4 Derby only supports global temporary tables.<br />
*5 The default H2 jar file contains debug information. *5 The default H2 jar file contains debug information, jar files for other databases do not.<br />
*6 PostgreSQL supports functional indexes.
</p> </p>
<h3>Derby and HSQLDB</h3> <h3>Derby and HSQLDB</h3>
...@@ -973,38 +988,81 @@ IGNORECASE=TRUE to the database URL (example: jdbc:h2:~/test;IGNORECASE=TRUE). ...@@ -973,38 +988,81 @@ IGNORECASE=TRUE to the database URL (example: jdbc:h2:~/test;IGNORECASE=TRUE).
<h3>Compatibility Modes</h3> <h3>Compatibility Modes</h3>
<p> <p>
For certain features, this database can emulate the behavior of specific databases. Not all features or differences of those For certain features, this database can emulate the behavior of specific databases.
databases are implemented. Currently, this feature is mainly used for randomized comparative testing Not all features or differences of those databases are implemented.
(where random statements are executed against multiple databases and the results are compared).
The mode can be changed by specifying the mode in the database URL, or using the SQL statement SET MODE.
To use the HSQLDB mode, you can use the database URL <code>jdbc:h2:~/test;MODE=HSQLDB</code>
or the SQL statement <code>SET MODE HSQLDB</code>.
Here is the list of currently supported modes and the difference to the regular mode: Here is the list of currently supported modes and the difference to the regular mode:
</p> </p>
<table>
<tr><th>Mode</th><th>Differences</th></tr> <h3>PostgreSQL Compatibility Mode</h3>
<tr><td> <p>
PostgreSQL To use the PostgreSQL mode, use the database URL <code>jdbc:h2:~/test;MODE=PostgreSQL</code>
</td><td> or the SQL statement <code>SET MODE PostgreSQL</code>.
Concatenation of a NULL with another value results in NULL. </p>
Usually, the NULL is treated as an empty string if only one of the operators is NULL, <ul><li>Concatenation of a NULL with another value results in NULL. Usually, the NULL is treated as an empty
and NULL is only returned if both values are NULL. string if only one of the operators is NULL, and NULL is only returned if both values are NULL.
</td></tr> </li><li>When converting a floating point number to a integer, the fractional
<tr><td> digits should not be truncated, but the value should be rounded.
MySQL </li><li>The system columns 'CTID' and 'OID' should be supported.
</td><td> </li></ul>
When inserting data, if a column is defined to be NOT NULL and NULL is inserted,
then a 0 (or empty string, or the current timestamp for timestamp columns) value is used. <h3>MySQL Compatibility Mode</h3>
Usually, this operation is not allowed and an exception is thrown. <p>
</td></tr> To use the MySQL mode, use the database URL <code>jdbc:h2:~/test;MODE=MySQL</code>
<tr><td> or the SQL statement <code>SET MODE MySQL</code>.
HSQLDB </p>
</td><td> <ul><li>When inserting data, if a column is defined to be NOT NULL and NULL is inserted,
When converting the scale of decimal data, the number is only converted if the new scale is then a 0 (or empty string, or the current timestamp for timestamp columns) value is used.
smaller then current scale. Usually, this operation is not allowed and an exception is thrown.
Usually, the scale is converted and 0s are added if required. </li><li>When converting a floating point number to a integer, the fractional
</td></tr> digits should not be truncated, but the value should be rounded.
</table> </li><li>The identifiers should be returned in lower case.
</li><li>Creating indexes in the CREATE TABLE statement should be supported.
</li></ul>
<h3>HSQLDB Compatibility Mode</h3>
<p>
To use the HSQLDB mode, use the database URL <code>jdbc:h2:~/test;MODE=HSQLDB</code>
or the SQL statement <code>SET MODE HSQLDB</code>.
</p>
<ul><li>Concatenation of a NULL with another value results in NULL. Usually, the NULL is treated as an empty
string if only one of the operators is NULL, and NULL is only returned if both values are NULL.
</li><li>When converting the scale of decimal data, the number is only converted if the new scale is
smaller then current scale. Usually, the scale is converted and 0s are added if required.
</li><li>When using unique indexes, multiple rows with NULL in one of the columns
are allowed by default. However many databases view NULL as distinct in
this regard and only allow one row with NULL.
</li></ul>
<h3>MS SQL Server Compatibility Mode</h3>
<p>
To use the MS SQL Server mode, use the database URL <code>jdbc:h2:~/test;MODE=MSSQLServer</code>
or the SQL statement <code>SET MODE MSSQLServer</code>.
</p>
<ul><li>Identifiers may be quoted using square brackets as in [Test].
</li><li>When using unique indexes, multiple rows with NULL in one of the columns
are allowed by default. However many databases view NULL as distinct in
this regard and only allow one row with NULL.
</li></ul>
<h3>Derby Compatibility Mode</h3>
<p>
To use the Derby mode, use the database URL <code>jdbc:h2:~/test;MODE=Derby</code>
or the SQL statement <code>SET MODE Derby</code>.
</p>
<ul><li>When using unique indexes, multiple rows with NULL in one of the columns
are allowed by default. However many databases view NULL as distinct in
this regard and only allow one row with NULL.
</li></ul>
<h3>Oracle Compatibility Mode</h3>
<p>
To use the Oracle mode, use the database URL <code>jdbc:h2:~/test;MODE=Oracle</code>
or the SQL statement <code>SET MODE Oracle</code>.
</p>
<ul><li>When using unique indexes, multiple rows with NULL in one of the columns
are allowed by default. However many databases view NULL as distinct in
this regard and only allow one row with NULL.
</li></ul>
<br /><a name="trace_options"></a> <br /><a name="trace_options"></a>
<h2>Using the Trace Options</h2> <h2>Using the Trace Options</h2>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -32,7 +32,6 @@ import org.h2.util.StringUtils; ...@@ -32,7 +32,6 @@ import org.h2.util.StringUtils;
public class Bnf { public class Bnf {
private static final String SEPARATORS = " [](){}|.,\r\n<>:-+*/=<\">!'$"; private static final String SEPARATORS = " [](){}|.,\r\n<>:-+*/=<\">!'$";
private static final long MAX_PARSE_TIME = 100;
private final Random random = new Random(); private final Random random = new Random();
private final HashMap ruleMap = new HashMap(); private final HashMap ruleMap = new HashMap();
...@@ -286,20 +285,17 @@ public class Bnf { ...@@ -286,20 +285,17 @@ public class Bnf {
* @return the map of possible token types / tokens * @return the map of possible token types / tokens
*/ */
public HashMap getNextTokenList(String query) { public HashMap getNextTokenList(String query) {
HashMap next = new HashMap();
Sentence sentence = new Sentence(); Sentence sentence = new Sentence();
sentence.next = next; sentence.setQuery(query);
sentence.text = query;
for (int i = 0; i < statements.size(); i++) { for (int i = 0; i < statements.size(); i++) {
RuleHead head = (RuleHead) statements.get(i); RuleHead head = (RuleHead) statements.get(i);
if (!head.section.startsWith("Commands")) { if (!head.section.startsWith("Commands")) {
continue; continue;
} }
sentence.max = System.currentTimeMillis() + MAX_PARSE_TIME; sentence.start();
sentence.setQuery(query);
head.getRule().addNextTokenList(sentence); head.getRule().addNextTokenList(sentence);
} }
return next; return sentence.getNext();
} }
/** /**
......
...@@ -78,15 +78,15 @@ public class RuleElement implements Rule { ...@@ -78,15 +78,15 @@ public class RuleElement implements Rule {
} }
public boolean matchRemove(Sentence sentence) { public boolean matchRemove(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.query; String query = sentence.getQuery();
if (query.length() == 0) { if (query.length() == 0) {
return false; return false;
} }
if (keyword) { if (keyword) {
String up = sentence.queryUpper; String up = sentence.getQueryUpper();
if (up.startsWith(name)) { if (up.startsWith(name)) {
query = query.substring(name.length()); query = query.substring(name.length());
while (!"_".equals(name) && query.length() > 0 && Character.isWhitespace(query.charAt(0))) { while (!"_".equals(name) && query.length() > 0 && Character.isWhitespace(query.charAt(0))) {
...@@ -101,7 +101,7 @@ public class RuleElement implements Rule { ...@@ -101,7 +101,7 @@ public class RuleElement implements Rule {
return false; return false;
} }
if (name != null && !name.startsWith("@") && (link.name() == null || !link.name().startsWith("@"))) { if (name != null && !name.startsWith("@") && (link.name() == null || !link.name().startsWith("@"))) {
query = sentence.query; query = sentence.getQuery();
while (query.length() > 0 && Character.isWhitespace(query.charAt(0))) { while (query.length() > 0 && Character.isWhitespace(query.charAt(0))) {
query = query.substring(1); query = query.substring(1);
} }
...@@ -111,13 +111,13 @@ public class RuleElement implements Rule { ...@@ -111,13 +111,13 @@ public class RuleElement implements Rule {
} }
public void addNextTokenList(Sentence sentence) { public void addNextTokenList(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return; return;
} }
if (keyword) { if (keyword) {
String query = sentence.query; String query = sentence.getQuery();
String q = query.trim(); String q = query.trim();
String up = sentence.queryUpper.trim(); String up = sentence.getQueryUpper().trim();
if (q.length() == 0 || name.startsWith(up)) { if (q.length() == 0 || name.startsWith(up)) {
if (q.length() < name.length()) { if (q.length() < name.length()) {
sentence.add(name, name.substring(q.length()), type); sentence.add(name, name.substring(q.length()), type);
......
...@@ -109,10 +109,10 @@ public class RuleFixed implements Rule { ...@@ -109,10 +109,10 @@ public class RuleFixed implements Rule {
} }
public boolean matchRemove(Sentence sentence) { public boolean matchRemove(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.query; String query = sentence.getQuery();
if (query.length() == 0) { if (query.length() == 0) {
return false; return false;
} }
...@@ -223,10 +223,10 @@ public class RuleFixed implements Rule { ...@@ -223,10 +223,10 @@ public class RuleFixed implements Rule {
} }
public void addNextTokenList(Sentence sentence) { public void addNextTokenList(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return; return;
} }
String query = sentence.query; String query = sentence.getQuery();
switch(type) { switch(type) {
case YMD: case YMD:
if (query.length() == 0) { if (query.length() == 0) {
......
...@@ -96,7 +96,7 @@ public class RuleList implements Rule { ...@@ -96,7 +96,7 @@ public class RuleList implements Rule {
} }
public boolean matchRemove(Sentence sentence) { public boolean matchRemove(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
if (query.length() == 0) { if (query.length() == 0) {
return false; return false;
} }
...@@ -118,7 +118,7 @@ public class RuleList implements Rule { ...@@ -118,7 +118,7 @@ public class RuleList implements Rule {
} }
public void addNextTokenList(Sentence sentence) { public void addNextTokenList(Sentence sentence) {
String old = sentence.query; String old = sentence.getQuery();
if (or) { if (or) {
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
sentence.setQuery(old); sentence.setQuery(old);
......
...@@ -46,10 +46,10 @@ public class RuleOptional implements Rule { ...@@ -46,10 +46,10 @@ public class RuleOptional implements Rule {
} }
public boolean matchRemove(Sentence sentence) { public boolean matchRemove(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.query; String query = sentence.getQuery();
if (query.length() == 0) { if (query.length() == 0) {
return true; return true;
} }
...@@ -60,7 +60,7 @@ public class RuleOptional implements Rule { ...@@ -60,7 +60,7 @@ public class RuleOptional implements Rule {
} }
public void addNextTokenList(Sentence sentence) { public void addNextTokenList(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return; return;
} }
rule.addNextTokenList(sentence); rule.addNextTokenList(sentence);
......
...@@ -40,10 +40,10 @@ public class RuleRepeat implements Rule { ...@@ -40,10 +40,10 @@ public class RuleRepeat implements Rule {
} }
public boolean matchRemove(Sentence sentence) { public boolean matchRemove(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.query; String query = sentence.getQuery();
if (query.length() == 0) { if (query.length() == 0) {
return false; return false;
} }
...@@ -51,20 +51,20 @@ public class RuleRepeat implements Rule { ...@@ -51,20 +51,20 @@ public class RuleRepeat implements Rule {
if (!rule.matchRemove(sentence)) { if (!rule.matchRemove(sentence)) {
return true; return true;
} }
if (sentence.query.length() == 0) { if (sentence.getQuery().length() == 0) {
return true; return true;
} }
} }
} }
public void addNextTokenList(Sentence sentence) { public void addNextTokenList(Sentence sentence) {
if (sentence.stop()) { if (sentence.shouldStop()) {
return; return;
} }
String old = sentence.query; String old = sentence.getQuery();
while (true) { while (true) {
rule.addNextTokenList(sentence); rule.addNextTokenList(sentence);
if (!rule.matchRemove(sentence) || old == sentence.query) { if (!rule.matchRemove(sentence) || old == sentence.getQuery()) {
break; break;
} }
} }
......
...@@ -20,25 +20,60 @@ import org.h2.util.StringUtils; ...@@ -20,25 +20,60 @@ import org.h2.util.StringUtils;
public class Sentence { public class Sentence {
/** /**
* The possible choices of the item depend on the context. * This token type means the possible choices of the item depend on the context.
* For example the item represents a table name of the current database. * For example the item represents a table name of the current database.
*/ */
public static final int CONTEXT = 0; public static final int CONTEXT = 0;
/**
* The token type for a keyword.
*/
static final int KEYWORD = 1; static final int KEYWORD = 1;
/**
* The token type for a function name.
*/
static final int FUNCTION = 2; static final int FUNCTION = 2;
public String text;
public String query; private static final long MAX_PROCESSING_TIME = 100;
public String queryUpper;
HashMap next; /**
long max; * The map of next tokens in the form type#tokenName token.
*/
private HashMap next = new HashMap();
/**
* The complete query string.
*/
private String query;
/**
* The uppercase version of the query string.
*/
private String queryUpper;
private long stopAt;
private DbSchema lastMatchedSchema; private DbSchema lastMatchedSchema;
private DbTableOrView lastMatchedTable; private DbTableOrView lastMatchedTable;
private DbTableOrView lastTable; private DbTableOrView lastTable;
private HashSet tables; private HashSet tables;
private HashMap aliases; private HashMap aliases;
/**
* Start the timer to make sure processing doesn't take too long.
*/
void start() {
stopAt = System.currentTimeMillis() + MAX_PROCESSING_TIME;
}
boolean stop() { /**
return System.currentTimeMillis() > max; * Check if it's time to stop processing.
* Processing auto-complete shouldn't take more than a few milliseconds.
*
* @return true if it's time to stop processing
*/
boolean shouldStop() {
return System.currentTimeMillis() > stopAt;
} }
/** /**
...@@ -46,7 +81,7 @@ public class Sentence { ...@@ -46,7 +81,7 @@ public class Sentence {
* *
* @param n the token name * @param n the token name
* @param string an example text * @param string an example text
* @param type the type * @param type the token type
*/ */
public void add(String n, String string, int type) { public void add(String n, String string, int type) {
next.put(type+"#"+n, string); next.put(type+"#"+n, string);
...@@ -142,6 +177,11 @@ public class Sentence { ...@@ -142,6 +177,11 @@ public class Sentence {
return lastMatchedTable; return lastMatchedTable;
} }
/**
* Set the query string.
*
* @param query the query string
*/
public void setQuery(String query) { public void setQuery(String query) {
if (this.query != query) { if (this.query != query) {
this.query = query; this.query = query;
...@@ -149,4 +189,31 @@ public class Sentence { ...@@ -149,4 +189,31 @@ public class Sentence {
} }
} }
/**
* Get the query string.
*
* @return the query
*/
public String getQuery() {
return query;
}
/**
* Get the uppercase version of the query string.
*
* @return the uppercase query
*/
public String getQueryUpper() {
return queryUpper;
}
/**
* Get the map of next tokens.
*
* @return the next token map
*/
public HashMap getNext() {
return next;
}
} }
...@@ -148,7 +148,7 @@ public abstract class Command implements CommandInterface { ...@@ -148,7 +148,7 @@ public abstract class Command implements CommandInterface {
} }
} }
protected void start() { void start() {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
} }
......
...@@ -143,6 +143,11 @@ public abstract class Prepared { ...@@ -143,6 +143,11 @@ public abstract class Prepared {
return parameters; return parameters;
} }
/**
* Check if all parameters have been set.
*
* @throws SQLException if any parameter has not been set
*/
protected void checkParameters() throws SQLException { protected void checkParameters() throws SQLException {
for (int i = 0; parameters != null && i < parameters.size(); i++) { for (int i = 0; parameters != null && i < parameters.size(); i++) {
Parameter param = (Parameter) parameters.get(i); Parameter param = (Parameter) parameters.get(i);
...@@ -214,10 +219,25 @@ public abstract class Prepared { ...@@ -214,10 +219,25 @@ public abstract class Prepared {
return sqlStatement; return sqlStatement;
} }
/**
* Get the object id to use for the database object that is created in this
* statement. This id is only set when the object is persistent.
* If not set, this method returns 0.
*
* @return the object id or 0 if not set
*/
protected int getCurrentObjectId() { protected int getCurrentObjectId() {
return objectId; return objectId;
} }
/**
* Get the current object id, or get a new id from the database. The object
* id is used when creating new database object (CREATE statement).
*
* @param needFresh if a fresh id is required
* @param dataFile if the object id is used for the
* @return the object id
*/
protected int getObjectId(boolean needFresh, boolean dataFile) { protected int getObjectId(boolean needFresh, boolean dataFile) {
Database db = session.getDatabase(); Database db = session.getDatabase();
int id = objectId; int id = objectId;
......
...@@ -242,7 +242,7 @@ public abstract class Query extends Prepared { ...@@ -242,7 +242,7 @@ public abstract class Query extends Prepared {
} }
} }
protected void initOrder(ObjectArray expressions, ObjectArray expressionSQL, ObjectArray orderList, int visible, void initOrder(ObjectArray expressions, ObjectArray expressionSQL, ObjectArray orderList, int visible,
boolean mustBeInResult) throws SQLException { boolean mustBeInResult) throws SQLException {
for (int i = 0; i < orderList.size(); i++) { for (int i = 0; i < orderList.size(); i++) {
SelectOrderBy o = (SelectOrderBy) orderList.get(i); SelectOrderBy o = (SelectOrderBy) orderList.get(i);
......
...@@ -66,7 +66,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler { ...@@ -66,7 +66,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
cipher = c; cipher = c;
} }
protected boolean isEncrypted() { private boolean isEncrypted() {
return cipher != null; return cipher != null;
} }
...@@ -94,7 +94,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler { ...@@ -94,7 +94,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
return false; return false;
} }
protected void deleteStore() throws SQLException { void deleteStore() throws SQLException {
String fileName = getFileName(); String fileName = getFileName();
if (fileName != null) { if (fileName != null) {
FileUtils.delete(fileName); FileUtils.delete(fileName);
...@@ -111,7 +111,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler { ...@@ -111,7 +111,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
store.init(); store.init();
} }
protected void openOutput() throws SQLException { void openOutput() throws SQLException {
String fileName = getFileName(); String fileName = getFileName();
if (fileName == null) { if (fileName == null) {
return; return;
...@@ -128,7 +128,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler { ...@@ -128,7 +128,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
} }
} }
protected void openInput() throws SQLException { void openInput() throws SQLException {
String fileName = getFileName(); String fileName = getFileName();
if (fileName == null) { if (fileName == null) {
return; return;
...@@ -151,7 +151,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler { ...@@ -151,7 +151,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
} }
} }
protected void closeIO() { void closeIO() {
IOUtils.closeSilently(out); IOUtils.closeSilently(out);
out = null; out = null;
IOUtils.closeSilently(in); IOUtils.closeSilently(in);
......
...@@ -9,12 +9,34 @@ package org.h2.command.dml; ...@@ -9,12 +9,34 @@ package org.h2.command.dml;
import org.h2.expression.Expression; import org.h2.expression.Expression;
/** /**
* Describes the ORDER BY clause of a query. * Describes one element of the ORDER BY clause of a query.
*/ */
public class SelectOrderBy { public class SelectOrderBy {
/**
* The order by expression.
*/
public Expression expression; public Expression expression;
/**
* The column index expression. This can be a column index number (1 meaning
* the first column of the select list) or a parameter (the parameter is a
* number representing the column index number).
*/
public Expression columnIndexExpr; public Expression columnIndexExpr;
/**
* If the column should be sorted descending.
*/
public boolean descending; public boolean descending;
/**
* If NULL should be appear first.
*/
public boolean nullsFirst; public boolean nullsFirst;
/**
* If NULL should be appear at the end.
*/
public boolean nullsLast; public boolean nullsLast;
} }
...@@ -54,9 +54,8 @@ public class ConstraintReferential extends Constraint { ...@@ -54,9 +54,8 @@ public class ConstraintReferential extends Constraint {
*/ */
public static final int SET_NULL = 3; public static final int SET_NULL = 3;
protected IndexColumn[] columns; private IndexColumn[] columns;
protected IndexColumn[] refColumns; private IndexColumn[] refColumns;
private int deleteAction; private int deleteAction;
private int updateAction; private int updateAction;
private Table refTable; private Table refTable;
......
...@@ -39,6 +39,14 @@ public abstract class DbObjectBase implements DbObject { ...@@ -39,6 +39,14 @@ public abstract class DbObjectBase implements DbObject {
private long modificationId; private long modificationId;
private boolean temporary; private boolean temporary;
/**
* Initialize some attributes of this object.
*
* @param database the database
* @param id the object id
* @param name the name
* @param traceModule the trace module name
*/
protected void initDbObjectBase(Database database, int id, String name, String traceModule) { protected void initDbObjectBase(Database database, int id, String name, String traceModule) {
this.database = database; this.database = database;
this.trace = database.getTrace(traceModule); this.trace = database.getTrace(traceModule);
...@@ -125,6 +133,10 @@ public abstract class DbObjectBase implements DbObject { ...@@ -125,6 +133,10 @@ public abstract class DbObjectBase implements DbObject {
return objectName; return objectName;
} }
/**
* Set the main attributes to null to make sure the object is no longer
* used.
*/
protected void invalidate() { protected void invalidate() {
setModified(); setModified();
id = -1; id = -1;
......
...@@ -23,13 +23,54 @@ public class Mode { ...@@ -23,13 +23,54 @@ public class Mode {
private static final HashMap MODES = new HashMap(); private static final HashMap MODES = new HashMap();
// Modes are also documented in the features section
/**
* Concatenation of a NULL with another value results in NULL. Usually, the
* NULL is treated as an empty string if only one of the operators is NULL,
* and NULL is only returned if both values are NULL.
*/
public boolean nullConcatIsNull; public boolean nullConcatIsNull;
/**
* When inserting data, if a column is defined to be NOT NULL and NULL is
* inserted, then a 0 (or empty string, or the current timestamp for
* timestamp columns) value is used. Usually, this operation is not allowed
* and an exception is thrown.
*/
public boolean convertInsertNullToZero; public boolean convertInsertNullToZero;
/**
* When converting the scale of decimal data, the number is only converted
* if the new scale is smaller then current scale. Usually, the scale is
* converted and 0s are added if required.
*/
public boolean convertOnlyToSmallerScale; public boolean convertOnlyToSmallerScale;
/**
* When converting a floating point number to a integer, the fractional
* digits should not be truncated, but the value should be rounded.
*/
public boolean roundWhenConvertToLong; public boolean roundWhenConvertToLong;
/**
* The identifiers should be returned in lower case.
*/
public boolean lowerCaseIdentifiers; public boolean lowerCaseIdentifiers;
/**
* Creating indexes in the CREATE TABLE statement should be supported.
*/
public boolean indexDefinitionInCreateTable; public boolean indexDefinitionInCreateTable;
/**
* The system columns 'CTID' and 'OID' should be supported.
*/
public boolean systemColumns; public boolean systemColumns;
/**
* Identifiers may be quoted using square brackets as in [Test].
*/
public boolean squareBracketQuotedNames; public boolean squareBracketQuotedNames;
/** /**
......
...@@ -59,7 +59,7 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -59,7 +59,7 @@ public abstract class RightOwner extends DbObjectBase {
return false; return false;
} }
protected boolean isRightGrantedRecursive(Table table, int rightMask) { boolean isRightGrantedRecursive(Table table, int rightMask) {
Right right; Right right;
if (grantedRights != null) { if (grantedRights != null) {
right = (Right) grantedRights.get(table); right = (Right) grantedRights.get(table);
......
...@@ -1450,6 +1450,12 @@ public class Function extends Expression implements FunctionCall { ...@@ -1450,6 +1450,12 @@ public class Function extends Expression implements FunctionCall {
} }
} }
/**
* Check if the parameter count is correct.
*
* @param len the number of parameters set
* @throws SQLException if the parameter count is incorrect
*/
protected void checkParameterCount(int len) throws SQLException { protected void checkParameterCount(int len) throws SQLException {
int min = 0, max = Integer.MAX_VALUE; int min = 0, max = Integer.MAX_VALUE;
switch (info.type) { switch (info.type) {
......
...@@ -633,7 +633,14 @@ public class FullText implements Trigger { ...@@ -633,7 +633,14 @@ public class FullText implements Trigger {
return search(conn, text, limit, offset, false); return search(conn, text, limit, offset, false);
} }
protected static SimpleResultSet createResultSet(boolean data) throws SQLException { /**
* Create an empty search result and initialize the columns.
*
* @param data true if the result set should contain the primary key data as
* an array.
* @return the empty result set
*/
static SimpleResultSet createResultSet(boolean data) throws SQLException {
SimpleResultSet result = new SimpleResultSet(); SimpleResultSet result = new SimpleResultSet();
if (data) { if (data) {
result.addColumn(FullText.FIELD_SCHEMA, Types.VARCHAR, 0, 0); result.addColumn(FullText.FIELD_SCHEMA, Types.VARCHAR, 0, 0);
...@@ -722,7 +729,14 @@ public class FullText implements Trigger { ...@@ -722,7 +729,14 @@ public class FullText implements Trigger {
return result; return result;
} }
protected static Object[][] parseKey(Connection conn, String key) throws SQLException { /**
* Parse a primary key condition into the primary key columns.
*
* @param conn the database connection
* @param key the primary key condition as a string
* @return an array containing the column name list and the data list
*/
static Object[][] parseKey(Connection conn, String key) throws SQLException {
ArrayList columns = new ArrayList(); ArrayList columns = new ArrayList();
ArrayList data = new ArrayList(); ArrayList data = new ArrayList();
JdbcConnection c = (JdbcConnection) conn; JdbcConnection c = (JdbcConnection) conn;
......
...@@ -22,17 +22,28 @@ import org.h2.value.Value; ...@@ -22,17 +22,28 @@ import org.h2.value.Value;
* An abstract b-tree page. * An abstract b-tree page.
*/ */
public abstract class BtreePage extends Record { public abstract class BtreePage extends Record {
// TODO btree: make sure the indexed data is at most half this size!
// (and find a solution to work around this problem!)
// TODO memory: the btree page needs a lot of memory (in the cache) -
// probably better not use ObjectArray but array;
// not Row but ValueList / Value (for single key index), int array for row
// pos
/**
* The maximum number of blocks occupied by a b-tree page.
*/
protected static final int BLOCKS_PER_PAGE = 1024 / DiskFile.BLOCK_SIZE; protected static final int BLOCKS_PER_PAGE = 1024 / DiskFile.BLOCK_SIZE;
/**
* The b-tree index object
*/
protected BtreeIndex index; protected BtreeIndex index;
// TODO memory: the btree page needs a lot of memory (in the cache) -
// probably better not use ObjectArray but array
/**
* The list of data pages.
*/
protected ObjectArray pageData; protected ObjectArray pageData;
/**
* If this is the root page of the index.
*/
protected boolean root; protected boolean root;
BtreePage(BtreeIndex index) { BtreePage(BtreeIndex index) {
......
...@@ -13,12 +13,38 @@ import org.h2.store.Storage; ...@@ -13,12 +13,38 @@ import org.h2.store.Storage;
* Such records are only used when recovering. * Such records are only used when recovering.
*/ */
public class RedoLogRecord { public class RedoLogRecord {
/**
* The storage object to where this log record belongs to.
*/
public Storage storage; public Storage storage;
/**
* The sequence id. This id is used to sort the records in the same order as
* they appear in the log file.
*/
public int sequenceId; public int sequenceId;
/**
* The position in the data file.
*/
public int recordId; public int recordId;
/**
* The offset in the data byte array.
*/
public int offset; public int offset;
/**
* The data.
*/
public byte[] data; public byte[] data;
/**
* Get the estimated memory size used by this object.
*
* @return the estimated memory size
*/
public int getSize() { public int getSize() {
// estimated memory size in bytes ((5 variables+myself) * 4 bytes each) // estimated memory size in bytes ((5 variables+myself) * 4 bytes each)
if (data == null) { if (data == null) {
...@@ -26,4 +52,5 @@ public class RedoLogRecord { ...@@ -26,4 +52,5 @@ public class RedoLogRecord {
} }
return 28 + data.length; return 28 + data.length;
} }
} }
...@@ -15,6 +15,14 @@ public abstract class SchemaObjectBase extends DbObjectBase implements SchemaObj ...@@ -15,6 +15,14 @@ public abstract class SchemaObjectBase extends DbObjectBase implements SchemaObj
private Schema schema; private Schema schema;
/**
* Initialize some attributes of this object.
*
* @param schema the schema
* @param id the object id
* @param name the name
* @param traceModule the trace module name
*/
protected void initSchemaObjectBase(Schema schema, int id, String name, String traceModule) { protected void initSchemaObjectBase(Schema schema, int id, String name, String traceModule) {
initDbObjectBase(schema.getDatabase(), id, name, traceModule); initDbObjectBase(schema.getDatabase(), id, name, traceModule);
this.schema = schema; this.schema = schema;
......
...@@ -14,7 +14,24 @@ import org.h2.util.StringUtils; ...@@ -14,7 +14,24 @@ import org.h2.util.StringUtils;
* This class is used by the H2 Console. * This class is used by the H2 Console.
*/ */
public class ConnectionInfo { public class ConnectionInfo {
public String driver, url, user; /**
* The driver class name.
*/
public String driver;
/**
* The database URL.
*/
public String url;
/**
* The user name.
*/
public String user;
/**
* The connection display name.
*/
String name; String name;
int lastAccess; int lastAccess;
......
...@@ -98,7 +98,7 @@ public class DbContextRule implements Rule { ...@@ -98,7 +98,7 @@ public class DbContextRule implements Rule {
} }
private void addTableAlias(Sentence sentence) { private void addTableAlias(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String q = StringUtils.toUpperEnglish(query.trim()); String q = StringUtils.toUpperEnglish(query.trim());
HashMap map = sentence.getAliases(); HashMap map = sentence.getAliases();
HashSet set = new HashSet(); HashSet set = new HashSet();
...@@ -136,7 +136,7 @@ public class DbContextRule implements Rule { ...@@ -136,7 +136,7 @@ public class DbContextRule implements Rule {
} }
private void addNewTableAlias(Sentence sentence) { private void addNewTableAlias(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
if (SUGGEST_TABLE_ALIAS) { if (SUGGEST_TABLE_ALIAS) {
// good when testing! // good when testing!
if (query.length() > 3) { if (query.length() > 3) {
...@@ -181,7 +181,7 @@ public class DbContextRule implements Rule { ...@@ -181,7 +181,7 @@ public class DbContextRule implements Rule {
// } // }
private void addSchema(Sentence sentence) { private void addSchema(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String q = StringUtils.toUpperEnglish(query); String q = StringUtils.toUpperEnglish(query);
if (q.trim().length() == 0) { if (q.trim().length() == 0) {
q = q.trim(); q = q.trim();
...@@ -201,7 +201,7 @@ public class DbContextRule implements Rule { ...@@ -201,7 +201,7 @@ public class DbContextRule implements Rule {
} }
private void addTable(Sentence sentence) { private void addTable(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
DbSchema schema = sentence.getLastMatchedSchema(); DbSchema schema = sentence.getLastMatchedSchema();
if (schema == null) { if (schema == null) {
schema = contents.defaultSchema; schema = contents.defaultSchema;
...@@ -222,14 +222,11 @@ public class DbContextRule implements Rule { ...@@ -222,14 +222,11 @@ public class DbContextRule implements Rule {
} }
private void addColumn(Sentence sentence) { private void addColumn(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String tableName = query; String tableName = query;
String columnPattern = ""; String columnPattern = "";
if (query.trim().length() == 0) { if (query.trim().length() == 0) {
tableName = null; tableName = null;
if (sentence.text.trim().endsWith(".")) {
return;
}
} else { } else {
tableName = StringUtils.toUpperEnglish(query.trim()); tableName = StringUtils.toUpperEnglish(query.trim());
if (tableName.endsWith(".")) { if (tableName.endsWith(".")) {
...@@ -286,7 +283,7 @@ public class DbContextRule implements Rule { ...@@ -286,7 +283,7 @@ public class DbContextRule implements Rule {
} }
public boolean matchRemove(Sentence sentence) { public boolean matchRemove(Sentence sentence) {
if (sentence.query.length() == 0) { if (sentence.getQuery().length() == 0) {
return false; return false;
} }
String s; String s;
...@@ -320,8 +317,8 @@ public class DbContextRule implements Rule { ...@@ -320,8 +317,8 @@ public class DbContextRule implements Rule {
} }
private String matchSchema(Sentence sentence) { private String matchSchema(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String up = sentence.queryUpper; String up = sentence.getQueryUpper();
DbSchema[] schemas = contents.schemas; DbSchema[] schemas = contents.schemas;
String best = null; String best = null;
DbSchema bestSchema = null; DbSchema bestSchema = null;
...@@ -347,8 +344,8 @@ public class DbContextRule implements Rule { ...@@ -347,8 +344,8 @@ public class DbContextRule implements Rule {
} }
private String matchTable(Sentence sentence) { private String matchTable(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String up = sentence.queryUpper; String up = sentence.getQueryUpper();
DbSchema schema = sentence.getLastMatchedSchema(); DbSchema schema = sentence.getLastMatchedSchema();
if (schema == null) { if (schema == null) {
schema = contents.defaultSchema; schema = contents.defaultSchema;
...@@ -378,8 +375,8 @@ public class DbContextRule implements Rule { ...@@ -378,8 +375,8 @@ public class DbContextRule implements Rule {
} }
private String matchColumnAlias(Sentence sentence) { private String matchColumnAlias(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String up = sentence.queryUpper; String up = sentence.getQueryUpper();
int i = 0; int i = 0;
if (query.indexOf(' ') < 0) { if (query.indexOf(' ') < 0) {
return null; return null;
...@@ -401,8 +398,8 @@ public class DbContextRule implements Rule { ...@@ -401,8 +398,8 @@ public class DbContextRule implements Rule {
} }
private String matchTableAlias(Sentence sentence, boolean add) { private String matchTableAlias(Sentence sentence, boolean add) {
String query = sentence.query; String query = sentence.getQuery();
String up = sentence.queryUpper; String up = sentence.getQueryUpper();
int i = 0; int i = 0;
if (query.indexOf(' ') < 0) { if (query.indexOf(' ') < 0) {
return null; return null;
...@@ -455,8 +452,8 @@ public class DbContextRule implements Rule { ...@@ -455,8 +452,8 @@ public class DbContextRule implements Rule {
} }
private String matchColumn(Sentence sentence) { private String matchColumn(Sentence sentence) {
String query = sentence.query; String query = sentence.getQuery();
String up = sentence.queryUpper; String up = sentence.getQueryUpper();
HashSet set = sentence.getTables(); HashSet set = sentence.getTables();
String best = null; String best = null;
DbTableOrView last = sentence.getLastMatchedTable(); DbTableOrView last = sentence.getLastMatchedTable();
......
...@@ -139,6 +139,11 @@ public class FileStore { ...@@ -139,6 +139,11 @@ public class FileStore {
return store; return store;
} }
/**
* Generate the random salt bytes if required.
*
* @return the random salt or the magic
*/
protected byte[] generateSalt() { protected byte[] generateSalt() {
return magic; return magic;
} }
......
...@@ -871,7 +871,7 @@ public class MetaTable extends Table { ...@@ -871,7 +871,7 @@ public class MetaTable extends Table {
// PARAMS // PARAMS
t.params, t.params,
// AUTO_INCREMENT // AUTO_INCREMENT
String.valueOf(t.autoInc), String.valueOf(t.autoIncrement),
// MINIMUM_SCALE // MINIMUM_SCALE
String.valueOf(t.minScale), String.valueOf(t.minScale),
// MAXIMUM_SCALE // MAXIMUM_SCALE
......
...@@ -17,13 +17,34 @@ import org.h2.store.DiskFile; ...@@ -17,13 +17,34 @@ import org.h2.store.DiskFile;
*/ */
public abstract class CacheObject { public abstract class CacheObject {
public CacheObject previous, next, chained; /**
* The previous element in the LRU linked list. If the previous element is
* the head, then this element is the most recently used object.
*/
public CacheObject previous;
/**
* The next element in the LRU linked list. If the next element is the head,
* then this element is the least recently used object.
*/
public CacheObject next;
/**
* The next element in the hash chain.
*/
public CacheObject chained;
/**
* The cache queue identifier. This field is only used for the 2Q cache
* algorithm.
*/
public int cacheQueue; public int cacheQueue;
/** /**
* The number of blocks occupied by this object. * The number of blocks occupied by this object.
*/ */
protected int blockCount; protected int blockCount;
private int pos; private int pos;
private boolean changed; private boolean changed;
......
...@@ -67,7 +67,11 @@ public abstract class HashBase { ...@@ -67,7 +67,11 @@ public abstract class HashBase {
return size + (zeroKey ? 1 : 0); return size + (zeroKey ? 1 : 0);
} }
protected void checkSizePut() throws SQLException { /**
* Check the size before adding an entry. This method resizes the map if
* required.
*/
void checkSizePut() throws SQLException {
if (deletedCount > size) { if (deletedCount > size) {
rehash(level); rehash(level);
} }
...@@ -76,6 +80,10 @@ public abstract class HashBase { ...@@ -76,6 +80,10 @@ public abstract class HashBase {
} }
} }
/**
* Check the size before removing an entry. This method resizes the map if
* required.
*/
protected void checkSizeRemove() throws SQLException { protected void checkSizeRemove() throws SQLException {
if (size < minSize && level > 0) { if (size < minSize && level > 0) {
rehash(level - 1); rehash(level - 1);
...@@ -84,6 +92,11 @@ public abstract class HashBase { ...@@ -84,6 +92,11 @@ public abstract class HashBase {
} }
} }
/**
* Clear the map and reset the level to the specified value.
*
* @param newLevel the new level
*/
protected void reset(int newLevel) { protected void reset(int newLevel) {
minSize = size * 3 / 4; minSize = size * 3 / 4;
size = 0; size = 0;
...@@ -95,6 +108,12 @@ public abstract class HashBase { ...@@ -95,6 +108,12 @@ public abstract class HashBase {
maxDeleted = 20 + len / 2; maxDeleted = 20 + len / 2;
} }
/**
* Calculate the index for this hash code.
*
* @param hash the hash code
* @return the index
*/
protected int getIndex(int hash) { protected int getIndex(int hash) {
return hash & mask; return hash & mask;
} }
......
...@@ -15,6 +15,9 @@ import java.sql.SQLException; ...@@ -15,6 +15,9 @@ import java.sql.SQLException;
*/ */
public abstract class Tool { public abstract class Tool {
/**
* The output stream where this tool writes to.
*/
protected PrintStream out = System.out; protected PrintStream out = System.out;
/** /**
......
...@@ -52,27 +52,111 @@ public class DataType { ...@@ -52,27 +52,111 @@ public class DataType {
private static ObjectArray types = new ObjectArray(); private static ObjectArray types = new ObjectArray();
private static HashMap typesByName = new HashMap(); private static HashMap typesByName = new HashMap();
private static DataType[] typesByValueType = new DataType[Value.TYPE_COUNT]; private static DataType[] typesByValueType = new DataType[Value.TYPE_COUNT];
/**
* The value type of this data type.
*/
public int type; public int type;
/**
* The data type name.
*/
public String name; public String name;
/**
* The SQL type.
*/
public int sqlType; public int sqlType;
/**
* The SQL type name.
*/
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 sqlTypePos; public int sqlTypePos;
/**
* The maximum supported precision.
*/
public int maxPrecision; public int maxPrecision;
public int minScale, maxScale;
/**
* The lowest possible scale.
*/
public int minScale;
/**
* The highest possible scale.
*/
public int maxScale;
/**
* If this is a numeric type.
*/
public boolean decimal; public boolean decimal;
public String prefix, suffix;
/**
* The prefix required for the SQL literal representation.
*/
public String prefix;
/**
* The suffix required for the SQL literal representation.
*/
public String suffix;
/**
* The list of parameters used in the column definition.
*/
public String params; public String params;
public boolean autoInc;
/**
* If this is an autoincrement type.
*/
public boolean autoIncrement;
/**
* If this data type is an autoincrement type.
*/
public boolean caseSensitive; public boolean caseSensitive;
public boolean supportsPrecision, supportsScale;
/**
* If the precision parameter is supported.
*/
public boolean supportsPrecision;
/**
* If the scale parameter is supported.
*/
public boolean supportsScale;
/**
* The default precision.
*/
public long defaultPrecision; public long defaultPrecision;
/**
* The default scale.
*/
public int defaultScale; public int defaultScale;
/**
* The default display size.
*/
public int defaultDisplaySize; public int defaultDisplaySize;
/**
* If this data type should not be listed in the database meta data.
*/
public boolean hidden; public boolean hidden;
/**
* The number of bytes required for an object.
*/
public int memory; public int memory;
static { static {
...@@ -250,7 +334,7 @@ public class DataType { ...@@ -250,7 +334,7 @@ public class DataType {
dt.sqlType = sqlType; dt.sqlType = sqlType;
dt.jdbc = jdbc; dt.jdbc = jdbc;
dt.name = names[i]; dt.name = names[i];
dt.autoInc = dataType.autoInc; dt.autoIncrement = dataType.autoIncrement;
dt.decimal = dataType.decimal; dt.decimal = dataType.decimal;
dt.maxPrecision = dataType.maxPrecision; dt.maxPrecision = dataType.maxPrecision;
dt.maxScale = dataType.maxScale; dt.maxScale = dataType.maxScale;
...@@ -292,7 +376,7 @@ public class DataType { ...@@ -292,7 +376,7 @@ public class DataType {
dataType.supportsScale = true; dataType.supportsScale = true;
} }
dataType.decimal = true; dataType.decimal = true;
dataType.autoInc = autoInc; dataType.autoIncrement = autoInc;
return dataType; return dataType;
} }
......
...@@ -144,14 +144,110 @@ java org.h2.test.TestAll timer ...@@ -144,14 +144,110 @@ java org.h2.test.TestAll timer
*/ */
public boolean smallLog, big, networked, memory, ssl, textStorage, diskUndo, diskResult, deleteIndex, traceSystemOut; /**
public boolean codeCoverage, mvcc, endless; * If the test should run with many rows.
public int logMode = 1, traceLevelFile, throttle; */
public boolean big;
/**
* If remote database connections should be used.
*/
public boolean networked;
/**
* If in-memory databases should be used.
*/
public boolean memory;
/**
* If index files should be deleted before re-opening the database.
*/
public boolean deleteIndex;
/**
* If code coverage is enabled.
*/
public boolean codeCoverage;
/**
* If the multi version concurrency control mode should be used.
*/
public boolean mvcc;
/**
* The log mode to use.
*/
public int logMode = 1;
/**
* The cipher to use (null for unencrypted).
*/
public String cipher; public String cipher;
public boolean traceTest, stopOnError; /**
* If only JDK 1.4 methods should be tested.
*/
public boolean jdk14 = true; public boolean jdk14 = true;
public boolean cache2Q;
/**
* If the transaction log files should be kept small (that is, log files should be switched early).
*/
boolean smallLog;
/**
* If SSL should be used for remote connections.
*/
boolean ssl;
/**
* If MAX_MEMORY_UNDO=3 should be used.
*/
boolean diskUndo;
/**
* If the text storage mechanism should be used.
*/
boolean textStorage;
/**
* If a small cache and a low number for MAX_MEMORY_ROWS should be used.
*/
boolean diskResult;
/**
* If TRACE_LEVEL_SYSTEM_OUT should be set to 2 (for debugging only).
*/
boolean traceSystemOut;
/**
* If the tests should run forever.
*/
boolean endless;
/**
* The file trace level value to use.
*/
int traceLevelFile;
/**
* The THROTTLE value to use.
*/
int throttle;
/**
* If test trace information should be written (for debugging only).
*/
boolean traceTest;
/**
* If the test should stop when the first error occurs.
*/
boolean stopOnError;
/**
* If the Two-Queue cache algorithm should be used.
*/
boolean cache2Q;
private Server server; private Server server;
...@@ -168,34 +264,17 @@ java org.h2.test.TestAll timer ...@@ -168,34 +264,17 @@ java org.h2.test.TestAll timer
System.setProperty("h2.maxMemoryRowsDistinct", "128"); System.setProperty("h2.maxMemoryRowsDistinct", "128");
/* /*
document bug
Caused by: java.lang.NullPointerException
at org.h2.expression.ExpressionColumn.getValue(ExpressionColumn.java:155)
at org.h2.expression.Operation.getValue(Operation.java:97)
at org.h2.command.dml.ScriptBase.getFileName(ScriptBase.java:84)
at org.h2.command.dml.ScriptBase.openInput(ScriptBase.java:132)
at org.h2.command.dml.RunScriptCommand.update(RunScriptCommand.java:38)
at org.h2.command.CommandContainer.update(CommandContainer.java:69)
at org.h2.command.Command.executeUpdate(Command.java:198)
at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:163)
... 6 more
add test case
> RUNSCRIPT FROM SCRIPT_DIRECTORY || 'Create_Users.sql';
> SCRIPT_DIRECTORY is a constant.
feature list:
computed columns: H2, HSQLDB (PostgreSQL: functional index)
case insensitive columns: H2, HSQLDB, MySQL (PostgreSQL: functional index)
jazoon
measure and improve performance of ObjectArray.toArray() measure and improve performance of ObjectArray.toArray()
H2 Console should support Java Queries
convert test.in.sql to RunScript syntax convert test.in.sql to RunScript syntax
C:\download\Data Concurrency and Consistency.pdf C:\download\Data Concurrency and Consistency.pdf
detect deadlock: alarm
not tested: not tested:
PreparedProcedure PREPARE <name>(column,...) AS ... PreparedProcedure PREPARE <name>(column,...) AS ...
Procedure Procedure
...@@ -208,8 +287,6 @@ deleted the same row when exactly does it occur in other databases ...@@ -208,8 +287,6 @@ deleted the same row when exactly does it occur in other databases
create an mbean for each database? server? (jconsole) create an mbean for each database? server? (jconsole)
jazoon
in help.csv, use complete examples for functions; add a test case in help.csv, use complete examples for functions; add a test case
improve javadocs improve javadocs
......
...@@ -43,12 +43,12 @@ public class TestBackup extends TestBase { ...@@ -43,12 +43,12 @@ public class TestBackup extends TestBase {
stat1.execute("backup to '" + baseDir + "/backup.zip'"); stat1.execute("backup to '" + baseDir + "/backup.zip'");
conn2.rollback(); conn2.rollback();
compareDatabases(stat1, stat2); assertEqualDatabases(stat1, stat2);
Restore.execute(baseDir + "/backup.zip", baseDir, "restored", true); Restore.execute(baseDir + "/backup.zip", baseDir, "restored", true);
conn3 = getConnection("restored"); conn3 = getConnection("restored");
stat3 = conn3.createStatement(); stat3 = conn3.createStatement();
compareDatabases(stat1, stat3); assertEqualDatabases(stat1, stat3);
conn1.close(); conn1.close();
conn2.close(); conn2.close();
......
...@@ -88,7 +88,7 @@ public class TestMemoryUsage extends TestBase { ...@@ -88,7 +88,7 @@ public class TestMemoryUsage extends TestBase {
System.gc(); System.gc();
System.gc(); System.gc();
int used = MemoryUtils.getMemoryUsed(); int used = MemoryUtils.getMemoryUsed();
if ((used - start) > 4000) { if ((used - start) > 5000) {
fail("Used: " + (used - start)); fail("Used: " + (used - start));
} }
stat.execute("drop table test"); stat.execute("drop table test");
......
...@@ -85,7 +85,7 @@ public class TestRunscript extends TestBase implements Trigger { ...@@ -85,7 +85,7 @@ public class TestRunscript extends TestBase implements Trigger {
stat2.execute(sql); stat2.execute(sql);
stat2.execute("script to '" + baseDir + "/backup.3.sql'"); stat2.execute("script to '" + baseDir + "/backup.3.sql'");
compareDatabases(stat1, stat2); assertEqualDatabases(stat1, stat2);
conn1.close(); conn1.close();
conn2.close(); conn2.close();
......
...@@ -621,7 +621,7 @@ public class TestPreparedStatement extends TestBase { ...@@ -621,7 +621,7 @@ public class TestPreparedStatement extends TestBase {
assertTrue(stat.execute("SELECT * FROM T_INT ORDER BY ID")); assertTrue(stat.execute("SELECT * FROM T_INT ORDER BY ID"));
rs = stat.getResultSet(); rs = stat.getResultSet();
testResultSetOrdered(rs, new String[][] { { "1", "0" }, { "2", "-1" }, { "3", "3" }, { "4", null }, assertResultSetOrdered(rs, new String[][] { { "1", "0" }, { "2", "-1" }, { "3", "3" }, { "4", null },
{ "5", "0" }, { "6", "-1" }, { "7", "3" }, { "8", null }, { "9", "-4" }, { "10", "5" }, { "11", null }, { "5", "0" }, { "6", "-1" }, { "7", "3" }, { "8", null }, { "9", "-4" }, { "10", "5" }, { "11", null },
{ "12", "1" }, { "13", "0" }, { "14", "-20" }, { "15", "100" }, { "16", "30000" }, { "17", "-30000" }, { "12", "1" }, { "13", "0" }, { "14", "-20" }, { "15", "100" }, { "16", "30000" }, { "17", "-30000" },
{ "18", "" + Integer.MAX_VALUE }, { "19", "" + Integer.MIN_VALUE }, }); { "18", "" + Integer.MAX_VALUE }, { "19", "" + Integer.MIN_VALUE }, });
......
...@@ -283,7 +283,7 @@ public class TestResultSet extends TestBase { ...@@ -283,7 +283,7 @@ public class TestResultSet extends TestBase {
assertEquals(meta.getColumnClassName(3), null); assertEquals(meta.getColumnClassName(3), null);
assertTrue(rs.getRow() == 0); assertTrue(rs.getRow() == 0);
testResultSetMeta(rs, 3, new String[] { "ID", "VALUE", "N" }, new int[] { Types.INTEGER, Types.INTEGER, assertResultSetMeta(rs, 3, new String[] { "ID", "VALUE", "N" }, new int[] { Types.INTEGER, Types.INTEGER,
Types.NULL }, new int[] { 10, 10, 1 }, new int[] { 0, 0, 0 }); Types.NULL }, new int[] { 10, 10, 1 }, new int[] { 0, 0, 0 });
rs.next(); rs.next();
assertEquals(rs.getConcurrency(), ResultSet.CONCUR_READ_ONLY); assertEquals(rs.getConcurrency(), ResultSet.CONCUR_READ_ONLY);
...@@ -408,7 +408,7 @@ public class TestResultSet extends TestBase { ...@@ -408,7 +408,7 @@ public class TestResultSet extends TestBase {
stat.execute("INSERT INTO TEST VALUES(10,'\\''')"); stat.execute("INSERT INTO TEST VALUES(10,'\\''')");
stat.execute("INSERT INTO TEST VALUES(11,'\\%')"); stat.execute("INSERT INTO TEST VALUES(11,'\\%')");
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.VARCHAR }, new int[] { assertResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.VARCHAR }, new int[] {
10, 255 }, new int[] { 0, 0 }); 10, 255 }, new int[] { 0, 0 });
String value; String value;
rs.next(); rs.next();
...@@ -488,7 +488,7 @@ public class TestResultSet extends TestBase { ...@@ -488,7 +488,7 @@ public class TestResultSet extends TestBase {
stat.execute("INSERT INTO TEST VALUES(7,-99999998.99)"); stat.execute("INSERT INTO TEST VALUES(7,-99999998.99)");
stat.execute("INSERT INTO TEST VALUES(8,NULL)"); stat.execute("INSERT INTO TEST VALUES(8,NULL)");
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.DECIMAL }, new int[] { assertResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.DECIMAL }, new int[] {
10, 10 }, new int[] { 0, 2 }); 10, 10 }, new int[] { 0, 2 });
BigDecimal bd; BigDecimal bd;
rs.next(); rs.next();
...@@ -539,7 +539,7 @@ public class TestResultSet extends TestBase { ...@@ -539,7 +539,7 @@ public class TestResultSet extends TestBase {
stat.execute("INSERT INTO TEST VALUES(7, -99999999.99, -99999999.99)"); stat.execute("INSERT INTO TEST VALUES(7, -99999999.99, -99999999.99)");
stat.execute("INSERT INTO TEST VALUES(8, NULL, NULL)"); stat.execute("INSERT INTO TEST VALUES(8, NULL, NULL)");
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 3, new String[] { "ID", "D", "R" }, assertResultSetMeta(rs, 3, new String[] { "ID", "D", "R" },
new int[] { Types.INTEGER, Types.DOUBLE, Types.REAL }, new int[] { 10, 17, 7 }, new int[] { 0, 0, 0 }); new int[] { Types.INTEGER, Types.DOUBLE, Types.REAL }, new int[] { 10, 17, 7 }, new int[] { 0, 0, 0 });
BigDecimal bd; BigDecimal bd;
rs.next(); rs.next();
...@@ -603,10 +603,10 @@ public class TestResultSet extends TestBase { ...@@ -603,10 +603,10 @@ public class TestResultSet extends TestBase {
stat.execute("INSERT INTO TEST VALUES(4,TIMESTAMP '9999-12-31 23:59:59')"); stat.execute("INSERT INTO TEST VALUES(4,TIMESTAMP '9999-12-31 23:59:59')");
stat.execute("INSERT INTO TEST VALUES(5,NULL)"); stat.execute("INSERT INTO TEST VALUES(5,NULL)");
rs = stat.executeQuery("SELECT 0 ID, TIMESTAMP '9999-12-31 23:59:59' VALUE FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT 0 ID, TIMESTAMP '9999-12-31 23:59:59' VALUE FROM TEST ORDER BY ID");
testResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.TIMESTAMP }, assertResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.TIMESTAMP },
new int[] { 10, 23 }, new int[] { 0, 10 }); new int[] { 10, 23 }, new int[] { 0, 10 });
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.TIMESTAMP }, assertResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.TIMESTAMP },
new int[] { 10, 23 }, new int[] { 0, 10 }); new int[] { 10, 23 }, new int[] { 0, 10 });
rs.next(); rs.next();
java.sql.Date date; java.sql.Date date;
...@@ -723,7 +723,7 @@ public class TestResultSet extends TestBase { ...@@ -723,7 +723,7 @@ public class TestResultSet extends TestBase {
prep.execute(); prep.execute();
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 4, new String[] { "ID", "D", "T", "TS" }, new int[] { Types.INTEGER, Types.DATE, assertResultSetMeta(rs, 4, new String[] { "ID", "D", "T", "TS" }, new int[] { Types.INTEGER, Types.DATE,
Types.TIME, Types.TIMESTAMP }, new int[] { 10, 8, 6, 23 }, new int[] { 0, 0, 0, 10 }); Types.TIME, Types.TIMESTAMP }, new int[] { 10, 8, 6, 23 }, new int[] { 0, 0, 0, 10 });
rs.next(); rs.next();
...@@ -777,7 +777,7 @@ public class TestResultSet extends TestBase { ...@@ -777,7 +777,7 @@ public class TestResultSet extends TestBase {
stat.execute("INSERT INTO TEST VALUES(5,X'0bcec1')"); stat.execute("INSERT INTO TEST VALUES(5,X'0bcec1')");
stat.execute("INSERT INTO TEST VALUES(6,NULL)"); stat.execute("INSERT INTO TEST VALUES(6,NULL)");
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.BLOB }, new int[] { assertResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.BLOB }, new int[] {
10, Integer.MAX_VALUE }, new int[] { 0, 0 }); 10, Integer.MAX_VALUE }, new int[] { 0, 0 });
rs.next(); rs.next();
checkBytes(rs.getBytes(2), new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 }); checkBytes(rs.getBytes(2), new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 });
...@@ -816,7 +816,7 @@ public class TestResultSet extends TestBase { ...@@ -816,7 +816,7 @@ public class TestResultSet extends TestBase {
stat.execute("INSERT INTO TEST VALUES(6,NULL)"); stat.execute("INSERT INTO TEST VALUES(6,NULL)");
stat.execute("INSERT INTO TEST VALUES(7,NULL)"); stat.execute("INSERT INTO TEST VALUES(7,NULL)");
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
testResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.CLOB }, new int[] { assertResultSetMeta(rs, 2, new String[] { "ID", "VALUE" }, new int[] { Types.INTEGER, Types.CLOB }, new int[] {
10, Integer.MAX_VALUE }, new int[] { 0, 0 }); 10, Integer.MAX_VALUE }, new int[] { 0, 0 });
rs.next(); rs.next();
string = rs.getString(2); string = rs.getString(2);
......
...@@ -105,6 +105,7 @@ public class TestWeb extends TestBase { ...@@ -105,6 +105,7 @@ public class TestWeb extends TestBase {
result = client.get(url, "logout.do"); result = client.get(url, "logout.do");
result = client.get(url, "settingRemove.do?name=_test_"); result = client.get(url, "settingRemove.do?name=_test_");
server.stop(); server.stop();
} }
......
...@@ -30,14 +30,67 @@ import org.h2.util.IOUtils; ...@@ -30,14 +30,67 @@ import org.h2.util.IOUtils;
*/ */
public abstract class TestHalt extends TestBase { public abstract class TestHalt extends TestBase {
protected static final int OP_INSERT = 1, OP_DELETE = 2, OP_UPDATE = 4, OP_SELECT = 8; /**
protected static final int FLAG_NO_DELAY = 1, FLAG_LOBS = 2; * This bit flag means insert operations should be performed.
*/
protected static final int OP_INSERT = 1;
/**
* This bit flag means delete operations should be performed.
*/
protected static final int OP_DELETE = 2;
/**
* This bit flag means update operations should be performed.
*/
protected static final int OP_UPDATE = 4;
/**
* This bit flag means select operations should be performed.
*/
protected static final int OP_SELECT = 8;
/**
* This bit flag means operations should be written to the log file immediately.
*/
protected static final int FLAG_NO_DELAY = 1;
/**
* This bit flag means the test should use LOB values.
*/
protected static final int FLAG_LOBS = 2;
/**
* The test directory.
*/
static final String DIR = TestBase.getTestDir("halt"); static final String DIR = TestBase.getTestDir("halt");
private static final String DATABASE_NAME = "halt"; private static final String DATABASE_NAME = "halt";
private static final String TRACE_FILE_NAME = "haltTrace.trace.db"; private static final String TRACE_FILE_NAME = "haltTrace.trace.db";
protected int operations, flags, value; /**
* The current operations bit mask.
*/
protected int operations;
/**
* The current flags bit mask.
*/
protected int flags;
/**
* The current test value, for example the number of rows.
*/
protected int value;
/**
* The database connection.
*/
protected Connection conn; protected Connection conn;
/**
* The pseudo random number generator used for this test.
*/
protected Random random = new Random(); protected Random random = new Random();
private SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss "); private SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss ");
...@@ -73,6 +126,11 @@ public abstract class TestHalt extends TestBase { ...@@ -73,6 +126,11 @@ public abstract class TestHalt extends TestBase {
return DriverManager.getConnection("jdbc:h2:" + baseDir + "/halt", "sa", "sa"); return DriverManager.getConnection("jdbc:h2:" + baseDir + "/halt", "sa", "sa");
} }
/**
* Start the program.
*
* @param args the command line arguments
*/
protected void start(String[] args) throws Exception { protected void start(String[] args) throws Exception {
if (args.length == 0) { if (args.length == 0) {
runTest(); runTest();
...@@ -111,10 +169,21 @@ public abstract class TestHalt extends TestBase { ...@@ -111,10 +169,21 @@ public abstract class TestHalt extends TestBase {
} }
} }
/**
* Print a trace message to the trace file.
*
* @param s the message
*/
protected void traceOperation(String s) { protected void traceOperation(String s) {
trace(s, null); trace(s, null);
} }
/**
* Print a trace message to the trace file.
*
* @param s the message
* @param e the exception or null
*/
protected void trace(String s, Exception e) { protected void trace(String s, Exception e) {
FileWriter writer = null; FileWriter writer = null;
try { try {
...@@ -191,6 +260,9 @@ public abstract class TestHalt extends TestBase { ...@@ -191,6 +260,9 @@ public abstract class TestHalt extends TestBase {
} }
} }
/**
* Close the database connection normally.
*/
protected void disconnect() { protected void disconnect() {
try { try {
traceOperation("disconnect"); traceOperation("disconnect");
...@@ -248,6 +320,12 @@ public abstract class TestHalt extends TestBase { ...@@ -248,6 +320,12 @@ public abstract class TestHalt extends TestBase {
} }
} }
/**
* Create a random string with the specified length.
*
* @param len the number of characters
* @return the random string
*/
protected String getRandomString(int len) { protected String getRandomString(int len) {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
......
...@@ -37,6 +37,9 @@ public class TestHaltApp extends TestHalt { ...@@ -37,6 +37,9 @@ public class TestHaltApp extends TestHalt {
stat.execute(sql); stat.execute(sql);
} }
/**
* Initialize the database.
*/
protected void testInit() throws SQLException { protected void testInit() throws SQLException {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
// stat.execute("CREATE TABLE TEST(ID IDENTITY, NAME VARCHAR(255))"); // stat.execute("CREATE TABLE TEST(ID IDENTITY, NAME VARCHAR(255))");
...@@ -51,6 +54,9 @@ public class TestHaltApp extends TestHalt { ...@@ -51,6 +54,9 @@ public class TestHaltApp extends TestHalt {
execute(stat, "CREATE TABLE TEST(ID BIGINT GENERATED BY DEFAULT AS IDENTITY, NAME VARCHAR(255), DATA CLOB)"); execute(stat, "CREATE TABLE TEST(ID BIGINT GENERATED BY DEFAULT AS IDENTITY, NAME VARCHAR(255), DATA CLOB)");
} }
/**
* Wait after the application has been started.
*/
protected void testWaitAfterAppStart() throws Exception { protected void testWaitAfterAppStart() throws Exception {
int sleep = 10 + random.nextInt(300); int sleep = 10 + random.nextInt(300);
if ((flags & FLAG_NO_DELAY) == 0) { if ((flags & FLAG_NO_DELAY) == 0) {
...@@ -59,6 +65,12 @@ public class TestHaltApp extends TestHalt { ...@@ -59,6 +65,12 @@ public class TestHaltApp extends TestHalt {
Thread.sleep(sleep); Thread.sleep(sleep);
} }
/**
* This method is called after a simulated crash. The method should check if
* the data is transactionally consistent and throw an exception if not.
*
* @throws Exception if the data is not consistent.
*/
protected void testCheckAfterCrash() throws Exception { protected void testCheckAfterCrash() throws Exception {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT COUNT(*) FROM TEST"); ResultSet rs = stat.executeQuery("SELECT COUNT(*) FROM TEST");
...@@ -71,6 +83,9 @@ public class TestHaltApp extends TestHalt { ...@@ -71,6 +83,9 @@ public class TestHaltApp extends TestHalt {
} }
} }
/**
* Initialize the application.
*/
protected void appStart() throws SQLException { protected void appStart() throws SQLException {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
if ((flags & FLAG_NO_DELAY) != 0) { if ((flags & FLAG_NO_DELAY) != 0) {
...@@ -83,6 +98,9 @@ public class TestHaltApp extends TestHalt { ...@@ -83,6 +98,9 @@ public class TestHaltApp extends TestHalt {
trace("rows: " + rowCount, null); trace("rows: " + rowCount, null);
} }
/**
* Run the application code.
*/
protected void appRun() throws Exception { protected void appRun() throws Exception {
conn.setAutoCommit(false); conn.setAutoCommit(false);
traceOperation("setAutoCommit false"); traceOperation("setAutoCommit false");
......
...@@ -17,6 +17,9 @@ import org.h2.test.TestBase; ...@@ -17,6 +17,9 @@ import org.h2.test.TestBase;
*/ */
public class TestMulti extends TestBase { public class TestMulti extends TestBase {
/**
* If set, the test should stop.
*/
public volatile boolean stop; public volatile boolean stop;
public void test() throws Exception { public void test() throws Exception {
......
...@@ -521,4 +521,5 @@ philosophers technologies modeling federation enterprise semantic deductive ...@@ -521,4 +521,5 @@ philosophers technologies modeling federation enterprise semantic deductive
fusion legacy decoded commented trimmed reaches indicating marks scaled tells fusion legacy decoded commented trimmed reaches indicating marks scaled tells
monitor benefit performing conditional significant arithmetic instrumented monitor benefit performing conditional significant arithmetic instrumented
doclets extremes instructions printable skips sava sources cms bytecode cfml doclets extremes instructions printable skips sava sources cms bytecode cfml
cold compiles markup spellchecker interleaved poormans programmed swt railo cold compiles markup spellchecker interleaved poormans programmed swt railo
\ No newline at end of file clobs resizes precisions scales
\ No newline at end of file
...@@ -334,7 +334,7 @@ public class Doclet { ...@@ -334,7 +334,7 @@ public class Doclet {
} }
private static boolean skipField(ClassDoc clazz, FieldDoc field) { private static boolean skipField(ClassDoc clazz, FieldDoc field) {
if (!field.isFinal() || !field.isStatic() || !field.isPublic() || field.containingClass() != clazz) { if (field.isPrivate() || field.containingClass() != clazz) {
return true; return true;
} }
return false; return false;
...@@ -347,7 +347,7 @@ public class Doclet { ...@@ -347,7 +347,7 @@ public class Doclet {
return true; return true;
} }
String name = method.name(); String name = method.name();
if (!method.isPublic() || name.equals("finalize")) { if ((method.isPrivate() && !method.isPackagePrivate()) || name.equals("finalize")) {
return true; return true;
} }
if (method.getRawCommentText().trim().startsWith("@deprecated INTERNAL")) { if (method.getRawCommentText().trim().startsWith("@deprecated INTERNAL")) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论