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

--no commit message

--no commit message
上级 b504a2db
#Fri Feb 01 15:26:30 CET 2008
javac=javac
#Sun Feb 03 11:48:01 CET 2008
benchmark.drivers.dir=C\:/data/java
javac=javac
jdk=1.4
path.lucene.jar=C\:/data/classpath/lucene-core-2.2.0.jar
path.servlet.jar=C\:/data/classpath/servlet-api.jar
version.name.maven=1.0.66
path.lucene.jar=C\:/data/classpath/lucene-core-2.2.0.jar
jdk=1.4
......@@ -56,43 +56,38 @@
</target>
<target name="codeswitchAndroid" depends="codeswitchPrepare">
<propertyfile file="ant-build.properties">
<entry key="jdk" value="1.3" />
</propertyfile>
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin">
<arg line="+JDK13 -JDK14 -JDK16 -AWT src/main/org/h2"/>
<arg line="+JDK13 -JDK14 -JDK16 -AWT src/main/org/h2 -set ant-build.properties jdk 1.3"/>
</java>
</target>
<target name="codeswitchJdk13" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin">
<arg line="+JDK13 -JDK14 -JDK16 +AWT src/main/org/h2"/>
<arg line="+JDK13 -JDK14 -JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.3"/>
</java>
<propertyfile file="ant-build.properties">
<entry key="jdk" value="1.3" />
</propertyfile>
<property name="jdk" value="1.3"/>
</target>
<target name="codeswitchJdk14" depends="codeswitchPrepare" if="codeswitch.14">
<target name="codeswitchJdk14" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin">
<arg line="-JDK13 +JDK14 -JDK16 +AWT src/main/org/h2"/>
<arg line="-JDK13 +JDK14 -JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.4"/>
</java>
<propertyfile file="ant-build.properties">
<entry key="jdk" value="1.4" />
</propertyfile>
</target>
<target name="codeswitchJdk16" depends="codeswitchPrepare" if="codeswitch.16">
<target name="codeswitchJdk16" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin">
<arg line="-JDK13 +JDK14 +JDK16 +AWT src/main/org/h2"/>
<arg line="-JDK13 +JDK14 +JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.6"/>
</java>
<propertyfile file="ant-build.properties">
<entry key="jdk" value="1.6" />
</propertyfile>
</target>
<target name="compileResources" depends="clean, codeswitchJdk14, codeswitchJdk16">
<target name="codeswitchJdk14Auto" if="codeswitch.14">
<antcall target="codeswitchJdk14" />
</target>
<target name="codeswitchJdk16Auto" if="codeswitch.16">
<antcall target="codeswitchJdk16" />
</target>
<target name="compileResources" depends="clean, codeswitchJdk14Auto, codeswitchJdk16Auto">
<javac executable="${javac}" srcdir="src/main" destdir="bin" debug="true" includes="org/h2/util/Resources.java"/>
<java classname="org.h2.util.Resources" classpath="bin"/>
<delete>
......@@ -159,7 +154,7 @@
<javac executable="${javac}" srcdir="bin" destdir="bin" debug="true" includes="org/h2/**"/>
</target>
<target name="docs" depends="clean,javadoc,compile">
<target name="docs" depends="clean, javadoc, compile">
<copy todir="docs">
<fileset dir="src/docsrc" includes="index.html"/>
<fileset dir="src/docsrc" includes="html/**/*" excludes="**/*.jsp" />
......
......@@ -456,6 +456,11 @@ Also, there may be compatibility problems on the SQL level, with the catalog, or
Problems are fixed as they are found.
Currently, statements can not be cancelled when using the PG protocol.
</p>
<p>
PostgreSQL ODBC Driver Setup requires a database password, that means it
is not possible to connect to H2 databases without password. This is a limitation
of the ODBC driver.
</p>
<h3>Security Considerations</h3>
<p>
......
......@@ -108,7 +108,7 @@ via PayPal:
</li><li>Antonio Casqueiro, Portugal
</li><li>lumber-mill.co.jp, Japan
</li><li>Oliver Computing LLC, USA
</li><li>Harpal Grover, USA
</li><li>Harpal Grover Consulting Inc., USA
</li></ul>
</div></td></tr></table></body></html>
......@@ -295,9 +295,16 @@ public class Set extends Prepared {
session.setVariable(stringValue, expr.getValue(session));
break;
}
case SetTypes.QUERY_TIMEOUT: {
int value = getIntValue();
session.setQueryTimeout(value);
break;
}
default:
throw Message.getInternalError("type="+type);
}
// the meta data information has changed
database.getNextModificationDataId();
return 0;
}
......
......@@ -21,8 +21,7 @@ public class SetTypes {
public static final int COMPRESS_LOB = 23, ALLOW_LITERALS = 24, MULTI_THREADED = 25, SCHEMA = 26;
public static final int OPTIMIZE_REUSE_RESULTS = 27, SCHEMA_SEARCH_PATH = 28, UNDO_LOG = 29;
public static final int REFERENTIAL_INTEGRITY = 30, MVCC = 31, MAX_OPERATION_MEMORY = 32, EXCLUSIVE = 33;
public static final int CREATE_BUILD = 34;
public static final int VARIABLE = 35;
public static final int CREATE_BUILD = 34, VARIABLE = 35, QUERY_TIMEOUT = 36;
private static ObjectArray types = new ObjectArray();
......@@ -62,6 +61,7 @@ public class SetTypes {
setType(EXCLUSIVE, "EXCLUSIVE");
setType(CREATE_BUILD, "CREATE_BUILD");
setType(VARIABLE, "@");
setType(QUERY_TIMEOUT, "QUERY_TIMEOUT");
}
private static void setType(int type, String name) {
......
......@@ -21,6 +21,11 @@ import org.h2.message.TraceSystem;
*/
public class SysProperties {
/**
* INTERNAL
*/
public static final String H2_MAX_QUERY_TIMEOUT = "h2.maxQueryTimeout";
/**
* System property <code>file.encoding</code> (default: Cp1252).<br />
* It is usually set by the system and is the default encoding used for the RunScript and CSV tool.
......@@ -62,13 +67,13 @@ public class SysProperties {
* Comma separated list of class names or prefixes.
*/
public static final String BIND_ADDRESS = getStringSetting("h2.bindAddress", null);
/**
* System property <code>h2.cacheSizeDefault</code> (default: 16384).<br />
* The default cache size in KB.
*/
public static final int CACHE_SIZE_DEFAULT = getIntSetting("h2.cacheSizeDefault", 16 * 1024);
/**
* System property <code>h2.cacheSizeIndexShift</code> (default: 3).<br />
* How many time the cache size value is divided by two to get the index cache size.
......@@ -104,19 +109,19 @@ public class SysProperties {
* The default for the setting MAX_OPERATION_MEMORY.
*/
public static final int DEFAULT_MAX_OPERATION_MEMORY = getIntSetting("h2.defaultMaxOperationMemory", 100000);
/**
* System property <code>h2.dataSourceTraceLevel</code> (default: 1).<br />
* The trace level of the data source implementation. Default is 1 for error.
*/
public static final int DATASOURCE_TRACE_LEVEL = getIntSetting("h2.dataSourceTraceLevel", TraceSystem.ERROR);
/**
* System property <code>h2.defaultMaxMemoryUndo</code> (default: 100000).<br />
* The default value for the MAX_MEMORY_UNDO setting.
*/
public static final int DEFAULT_MAX_MEMORY_UNDO = getIntSetting("h2.defaultMaxMemoryUndo", 100000);
/**
* System property <code>h2.defaultLockMode</code> (default: 3).<br />
* The default value for the LOCK_MODE setting.
......@@ -171,14 +176,20 @@ public class SysProperties {
* Number of times to retry file delete and rename.
*/
public static final int MAX_FILE_RETRY = Math.max(1, getIntSetting("h2.maxFileRetry", 16));
/**
* System property <code>h2.maxQueryTimeout</code> (default: 0).<br />
* The maximum timeout of a query. The default is 0, meaning no limit.
*/
public static final int MAX_QUERY_TIMEOUT = getIntSetting(H2_MAX_QUERY_TIMEOUT, 0);
/**
* System property <code>h2.minColumnNameMap</code> (default: 3).<br />
* The minimum number of columns where a hash table is created when result set
* The minimum number of columns where a hash table is created when result set
* methods with column name (instead of column index) parameter are called.
*/
public static final int MIN_COLUMN_NAME_MAP = getIntSetting("h2.minColumnNameMap", 3);
/**
* System property <code>h2.minWriteDelay</code> (default: 5).<br />
* The minimum write delay that causes commits to be delayed.
......@@ -250,11 +261,11 @@ public class SysProperties {
* Optimize NOT conditions by removing the NOT and inverting the condition.
*/
public static final boolean OPTIMIZE_NOT = getBooleanSetting("h2.optimizeNot", true);
/**
* System property <code>h2.optimizeTwoEquals</code> (default: true).<br />
* Optimize expressions of the form A=B AND B=1. In this case, AND A=1 is added so an index on A can be used.
*/
*/
public static final boolean OPTIMIZE_TWO_EQUALS = getBooleanSetting("h2.optimizeTwoEquals", true);
/**
......@@ -335,7 +346,7 @@ public class SysProperties {
return s == null ? defaultValue : s;
}
private static int getIntSetting(String name, int defaultValue) {
public static int getIntSetting(String name, int defaultValue) {
String s = getProperty(name);
if (s != null) {
try {
......@@ -363,4 +374,11 @@ public class SysProperties {
return baseDir;
}
/**
* INTERNAL
*/
public static int getMaxQueryTimeout() {
return getIntSetting(H2_MAX_QUERY_TIMEOUT, 0);
}
}
......@@ -81,6 +81,7 @@ public class Session implements SessionInterface {
private long currentCommandStart;
private HashMap variables;
private HashSet temporaryResults;
private int queryTimeout = SysProperties.getMaxQueryTimeout();
public Session() {
}
......@@ -543,6 +544,9 @@ public class Session implements SessionInterface {
public void setCurrentCommand(Command command, long startTime) {
this.currentCommand = command;
this.currentCommandStart = startTime;
if (queryTimeout > 0) {
cancelAt = startTime + queryTimeout;
}
}
public void checkCancelled() throws SQLException {
......@@ -703,4 +707,17 @@ public class Session implements SessionInterface {
}
}
public void setQueryTimeout(int queryTimeout) {
int max = SysProperties.getMaxQueryTimeout();
if (max != 0 && (max < queryTimeout || queryTimeout == 0)) {
// the value must be at most max
queryTimeout = max;
}
this.queryTimeout = queryTimeout;
}
public int getQueryTimeout() {
return queryTimeout;
}
}
......@@ -39,6 +39,7 @@ import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueLob;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
//#ifdef JDK16
/*
......@@ -67,6 +68,7 @@ public class JdbcConnection extends TraceObject implements Connection {
private CommandInterface setAutoCommitTrue, setAutoCommitFalse, getAutoCommit;
private CommandInterface getReadOnly, getGeneratedKeys;
private CommandInterface setLockMode, getLockMode;
private CommandInterface setQueryTimeout, getQueryTimeout;
private Exception openStackTrace;
//#ifdef JDK14
private int savepointId;
......@@ -249,6 +251,8 @@ public class JdbcConnection extends TraceObject implements Connection {
getGeneratedKeys = closeAndSetNull(getGeneratedKeys);
getLockMode = closeAndSetNull(getLockMode);
setLockMode = closeAndSetNull(setLockMode);
getQueryTimeout = closeAndSetNull(getQueryTimeout);
setQueryTimeout = closeAndSetNull(setQueryTimeout);
} finally {
session.close();
}
......@@ -519,7 +523,7 @@ public class JdbcConnection extends TraceObject implements Connection {
/**
* Changes the current transaction isolation level. Calling this method will
* commit any open transactions, even if the new level is the same as the
* commit an open transaction, even if the new level is the same as the
* old one, except if the level is not supported.
*
* @param level the new transaction isolation level,
......@@ -556,6 +560,43 @@ public class JdbcConnection extends TraceObject implements Connection {
}
}
/**
* INTERNAL
*/
public void setQueryTimeout(int seconds) throws SQLException {
try {
commit();
setQueryTimeout = prepareCommand("SET QUERY_TIMEOUT ?", setQueryTimeout);
((ParameterInterface) setQueryTimeout.getParameters().get(0)).setValue(ValueInt.get(seconds * 1000));
setQueryTimeout.executeUpdate();
} catch (Throwable e) {
throw logAndConvert(e);
}
}
/**
* INTERNAL
*/
public int getQueryTimeout() throws SQLException {
try {
getQueryTimeout = prepareCommand("SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=?", getQueryTimeout);
((ParameterInterface) getQueryTimeout.getParameters().get(0)).setValue(ValueString.get("QUERY_TIMEOUT"));
ResultInterface result = getQueryTimeout.executeQuery(0, false);
result.next();
int queryTimeout = result.currentRow()[0].getInt();
result.close();
if (queryTimeout == 0) {
return 0;
} else {
// round to the next second, otherwise 999 millis would return 0 seconds
return (queryTimeout + 999) / 1000;
}
} catch (Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the current transaction isolation level.
*
......
......@@ -31,8 +31,6 @@ public class JdbcStatement extends TraceObject implements Statement {
protected JdbcResultSet resultSet;
protected int maxRows;
protected boolean escapeProcessing = true;
protected int queryTimeout;
protected boolean queryTimeoutSet;
protected int fetchSize = SysProperties.SERVER_RESULT_SET_FETCH_SIZE;
protected int updateCount;
private CommandInterface executingCommand;
......@@ -519,6 +517,8 @@ public class JdbcStatement extends TraceObject implements Statement {
/**
* Gets the current query timeout in seconds.
* This method will return 0 if no query timeout is set.
* The result is rounded to the next second.
*
* @return the timeout in seconds
* @throws SQLException if this object is closed
......@@ -527,7 +527,7 @@ public class JdbcStatement extends TraceObject implements Statement {
try {
debugCodeCall("getQueryTimeout");
checkClosed();
return queryTimeout;
return conn.getQueryTimeout();
} catch (Throwable e) {
throw logAndConvert(e);
}
......@@ -535,7 +535,8 @@ public class JdbcStatement extends TraceObject implements Statement {
/**
* Sets the current query timeout in seconds.
* This method will succeed, even if the functionality is not supported by the database.
* Calling this method will commit an open transaction, even if the value is the same as before.
* Changing the value will affect all statements of this connection.
*
* @param seconds the timeout in seconds -
* 0 means no timeout, values smaller 0 will throw an exception
......@@ -548,8 +549,7 @@ public class JdbcStatement extends TraceObject implements Statement {
if (seconds < 0) {
throw Message.getInvalidValueException("" + seconds, "seconds");
}
queryTimeout = seconds;
queryTimeoutSet = true;
conn.setQueryTimeout(seconds);
} catch (Throwable e) {
throw logAndConvert(e);
}
......
......@@ -1033,6 +1033,17 @@ This setting can be appended to the database URL: jdbc:h2:test;OPTIMIZE_REUSE_RE
SET OPTIMIZE_REUSE_RESULTS 0
"
"Commands (Other)","SET QUERY_TIMEOUT","
SET QUERY_TIMEOUT int
","
Set the query timeout of the current session to the given value.
The timeout is in milliseconds. All kinds of statements will
throw an exception if they take longer than the given value.
The default timeout is 0, meaning no timeout.
","
SET QUERY_TIMEOUT 10000
"
"Commands (Other)","SET PASSWORD","
SET PASSWORD string
","
......
......@@ -708,10 +708,11 @@ public class MetaTable extends Table {
add(rows, new String[] { "property." + s, SysProperties.getStringSetting(s, "") });
}
}
add(rows, new String[] { "MVCC", database.isMultiVersion() ? "TRUE" : "FALSE" });
add(rows, new String[] { "EXCLUSIVE", database.getExclusiveSession() == null ? "FALSE" : "TRUE" });
add(rows, new String[] { "MODE", database.getMode().getName() });
add(rows, new String[] { "MULTI_THREADED", database.getMultiThreaded() ? "1" : "0"});
add(rows, new String[] { "MVCC", database.isMultiVersion() ? "TRUE" : "FALSE" });
add(rows, new String[] { "QUERY_TIMEOUT", "" + session.getQueryTimeout() });
add(rows, new String[]{"h2.allowBigDecimalExtensions", "" + SysProperties.ALLOW_BIG_DECIMAL_EXTENSIONS});
add(rows, new String[]{"h2.baseDir", "" + SysProperties.getBaseDir()});
add(rows, new String[]{"h2.check", "" + SysProperties.CHECK});
......@@ -725,6 +726,7 @@ public class MetaTable extends Table {
add(rows, new String[]{"h2.logAllErrors", "" + SysProperties.LOG_ALL_ERRORS});
add(rows, new String[]{"h2.logAllErrorsFile", "" + SysProperties.LOG_ALL_ERRORS_FILE});
add(rows, new String[]{"h2.maxFileRetry", "" + SysProperties.MAX_FILE_RETRY});
add(rows, new String[]{SysProperties.H2_MAX_QUERY_TIMEOUT, "" + SysProperties.getMaxQueryTimeout()});
add(rows, new String[]{"h2.lobCloseBetweenReads", "" + SysProperties.lobCloseBetweenReads});
add(rows, new String[]{"h2.objectCache", "" + SysProperties.OBJECT_CACHE});
add(rows, new String[]{"h2.objectCacheSize", "" + SysProperties.OBJECT_CACHE_SIZE});
......
......@@ -167,7 +167,6 @@ timer test
// repeatable test with a very big database (making backups of the database files)
Test Recovery with MAX_LOG_FILE_SIZE=1; test with various log file sizes
ODBC must include a password; I cannot use the default 'sa' with no password for it.
Test with many columns (180), create index
add a 'kill process while altering tables' test case
......@@ -175,7 +174,7 @@ Roadmap:
History:
Statement.setQueryTimeout() is now supported. New session setting QUERY_TIMEOUT, and new system property h2.maxQueryTimeout.
*/
......
......@@ -10,6 +10,8 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.test.TestBase;
......@@ -41,6 +43,70 @@ public class TestCancel extends TestBase {
}
public void test() throws Exception {
testMaxQueryTimeout();
testQueryTimeout();
testJdbcQueryTimeout();
testCancelStatement();
}
private void testJdbcQueryTimeout() throws Exception {
deleteDb("cancel");
Connection conn = getConnection("cancel");
Statement stat = conn.createStatement();
check(0, stat.getQueryTimeout());
stat.setQueryTimeout(1);
check(1, stat.getQueryTimeout());
Statement s2 = conn.createStatement();
check(1, s2.getQueryTimeout());
ResultSet rs = s2.executeQuery("SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME = 'QUERY_TIMEOUT'");
rs.next();
check(1000, rs.getInt(1));
try {
stat.executeQuery("SELECT MAX(RAND()) FROM SYSTEM_RANGE(1, 100000000)");
error("unexpected success");
} catch (SQLException e) {
check(ErrorCode.STATEMENT_WAS_CANCELLED, e.getErrorCode());
}
stat.setQueryTimeout(0);
stat.execute("SET QUERY_TIMEOUT 1100");
check(2, stat.getQueryTimeout());
conn.close();
}
private void testQueryTimeout() throws Exception {
deleteDb("cancel");
Connection conn = getConnection("cancel");
Statement stat = conn.createStatement();
stat.execute("SET QUERY_TIMEOUT 10");
try {
stat.executeQuery("SELECT MAX(RAND()) FROM SYSTEM_RANGE(1, 100000000)");
error("unexpected success");
} catch (SQLException e) {
check(ErrorCode.STATEMENT_WAS_CANCELLED, e.getErrorCode());
}
conn.close();
}
private void testMaxQueryTimeout() throws Exception {
deleteDb("cancel");
int oldMax = SysProperties.getMaxQueryTimeout();
try {
System.setProperty(SysProperties.H2_MAX_QUERY_TIMEOUT, "" + 10);
Connection conn = getConnection("cancel");
Statement stat = conn.createStatement();
try {
stat.executeQuery("SELECT MAX(RAND()) FROM SYSTEM_RANGE(1, 100000000)");
error("unexpected success");
} catch (SQLException e) {
check(ErrorCode.STATEMENT_WAS_CANCELLED, e.getErrorCode());
}
conn.close();
} finally {
System.setProperty("h2.maxQueryTimeout", "" + oldMax);
}
}
private void testCancelStatement() throws Exception {
deleteDb("cancel");
Connection conn = getConnection("cancel");
Statement stat = conn.createStatement();
......
......@@ -27,6 +27,7 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import org.h2.constant.SysProperties;
import org.h2.jdbc.JdbcConnection;
import org.h2.test.TestAll;
import org.h2.test.TestBase;
......@@ -392,9 +393,15 @@ public class TestCrashAPI extends TestBase {
}
public void testCase(int i) throws Exception {
baseDir = "dataCrash";
testOne(i);
baseDir = "data";
int old = SysProperties.getMaxQueryTimeout();
try {
System.setProperty(SysProperties.H2_MAX_QUERY_TIMEOUT, "" + 10000);
baseDir = "dataCrash";
testOne(i);
} finally {
baseDir = "data";
System.setProperty(SysProperties.H2_MAX_QUERY_TIMEOUT, "" + old);
}
}
public void test() throws Exception {
......
......@@ -4,10 +4,21 @@
*/
package org.h2.tools.code;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
/**
* This application allows to switch source code to different 'modes', so that
......@@ -25,15 +36,16 @@ public class CodeSwitch {
private ArrayList lines;
private boolean changed;
public static void main(String[] argv) {
public static void main(String[] argv) throws Exception {
(new CodeSwitch()).run(argv);
}
private void run(String[] a) {
private void run(String[] a) throws Exception {
if (a.length == 0) {
showUsage();
return;
}
String propertiesFile = null, property = null, value = null;
boolean path = false;
recurse = true;
for (int i = 0; i < a.length; i++) {
......@@ -45,6 +57,10 @@ public class CodeSwitch {
recurse = true;
} else if (p.startsWith("-r-")) {
recurse = false;
} else if (p.startsWith("-set")) {
propertiesFile = a[++i];
property = a[++i];
value = a[++i];
} else if (p.startsWith("-")) {
switchOff.add(p.substring(1));
} else {
......@@ -60,15 +76,42 @@ public class CodeSwitch {
if (switchOff.size() == 0 && switchOn.size() == 0) {
printSwitches();
}
if (propertiesFile != null) {
setProperty(propertiesFile, property, value);
}
}
private static class SortedProperties extends Properties {
private static final long serialVersionUID = 3926204645298674434L;
public synchronized Enumeration keys() {
Vector v = new Vector(keySet());
Collections.sort(v);
return v.elements();
}
}
private void setProperty(String propertiesFile, String property, String value) throws IOException {
SortedProperties prop = new SortedProperties();
InputStream in = new BufferedInputStream(new FileInputStream(propertiesFile));
prop.load(in);
in.close();
prop.setProperty(property, value);
OutputStream out = new BufferedOutputStream(new FileOutputStream(propertiesFile));
prop.store(out, null);
out.close();
}
private void showUsage() {
String className = getClass().getName();
System.out.println("Usage: java " + className + " [-r+] [-r-] paths [+|-][labels]");
System.out.println("Usage: java " + className + " [-r+] [-r-] paths [+|-][labels] [-set file property value]");
System.out.println("If no labels are specified then all used");
System.out.println("labels in the source code are shown.");
System.out.println("-r+ recurse subdirectories (default)");
System.out.println("-r- do not recurse subdirectories");
System.out.println("-set will update a value in a properties file after switching");
System.out.println("Use +MODE to switch on code labeled MODE");
System.out.println("Use -MODE to switch off code labeled MODE");
System.out.println("Path: Any number of path or files may be specified.");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论