提交 4830b307 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 faecae21
......@@ -111,9 +111,10 @@
</target>
<target name="compileServlet" depends="compileServletTest, compile" if="servlet.jar.present">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/tools" destdir="bin" debug="true">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/main" destdir="bin" debug="true">
<classpath location="${path.servlet.jar}" />
<include name="org/h2/server/web/*.*"/>
<include name="org/h2/server/web/WebServlet.java"/>
<include name="org/h2/server/web/DbStarter.java"/>
</javac>
</target>
......@@ -125,11 +126,11 @@
<target name="compile" depends="compileResources, compileTest">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/main" destdir="bin" debug="true">
<exclude name="org/h2/fulltext/FullTextLucene.java"/>
<exclude name="org/h2/server/web/WebServlet.java"/>
<exclude name="org/h2/server/web/DbStarter.java"/>
</javac>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/test" destdir="bin" debug="true"/>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/tools" destdir="bin" debug="true">
<exclude name="org/h2/server/web/*.*"/>
</javac>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/tools" destdir="bin" debug="true"/>
<copy todir="bin" overwrite="true">
<fileset dir="src/main" includes="META-INF/**/*"/>
<fileset dir="src/main" includes="**/*.png"/>
......
......@@ -42,6 +42,8 @@ Advanced Topics
File Locking Protocols</a><br />
<a href="#sql_injection">
Protection against SQL Injection</a><br />
<a href="#restricting_classes">
Restricting Class Loading and Usage</a><br />
<a href="#security_protocols">
Security Protocols</a><br />
<a href="#uuid">
......@@ -760,6 +762,29 @@ It is not required to create a constant for the number 0 as there is already a b
SELECT * FROM USERS WHERE LENGTH(PASSWORD)=ZERO();
</pre>
<br /><a name="restricting_classes"></a>
<h2>Restricting Class Loading and Usage</h2>
<p>
By default there is no restriction on loading classes and executing Java code for admins.
That means an admin may call system functions such as System.setProperty by executing:
<pre>
CREATE ALIAS SET_PROPERTY FOR "java.lang.System.setProperty";
CALL SET_PROPERTY('abc', '1');
CREATE ALIAS GET_PROPERTY FOR "java.lang.System.getProperty";
CALL GET_PROPERTY('abc');
</pre>
To restrict users (including admins) from loading classes and executing code,
the list of allowed classes can be set in the system property h2.allowedClasses
in the form of a comma separated list of classes or patterns (items ending with '*').
By default all classes are allowed. Example:
<pre>
java -Dh2.allowedClasses=java.lang.Math,com.acme.*
</pre>
This mechanism is used for all user classes, including database event listeners,
trigger classes, user defined functions, user defined aggregate functions, and JDBC
driver classes (with the exception of the H2 driver) when using the H2 Console.
</p>
<br /><a name="security_protocols"></a>
<h2>Security Protocols</h2>
<p>
......@@ -908,6 +933,7 @@ INFORMATION_SCHEMA.SETTINGS
<th>Setting</th>
<th>Default</th>
<th>Description</th></tr>
<tr><td>h2.allowedClasses</td><td>*</td><td>Comma separated list of class names or prefixes</td></tr>
<tr><td>h2.check</td><td>true</td><td>Assertions in the database engine</td></tr>
<tr><td>h2.check2</td><td>false</td><td>Additional assertions</td></tr>
<tr><td>h2.clientTraceDirectory</td><td>trace.db/</td><td>Directory where the trace files of the JDBC client are stored (only for client / server)</td></tr>
......
......@@ -21,7 +21,7 @@ H2 Database Engine
<a href="http://www.h2database.com/h2-2007-12-02.zip">Platform-Independent Zip</a><br />
</p>
<h3>Download Mirror</h3>
<h3>Download Mirror and Older Versions</h3>
<p>
<a href="http://code.google.com/p/h2database/downloads/list">Platform-Independent Zip</a><br />
</p>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -154,6 +154,7 @@
90131=Concurrent update in table {0}\: another transaction has updated or deleted the same row
90132=Aggregate {0} not found
90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied
HY000=General error\: {0}
HY004=Unknown data type\: {0}
HYC00=Feature not supported
......
......@@ -22,7 +22,7 @@ import org.h2.util.StringCache;
import org.h2.util.StringUtils;
/**
* This class can read a file that is similar to BNF (BackusNaur form).
* This class can read a file that is similar to BNF (Backus-Naur form).
* It is made specially to support SQL grammar.
*/
public class Bnf {
......
......@@ -314,6 +314,7 @@ public class ErrorCode {
public static final int CONCURRENT_UPDATE_1 = 90131;
public static final int AGGREGATE_NOT_FOUND_1 = 90132;
public static final int CANNOT_CHANGE_SETTING_WHEN_OPEN_1 = 90133;
public static final int ACCESS_DENIED_TO_CLASS_1 = 90134;
/**
* INTERNAL
......
......@@ -71,6 +71,7 @@ public class SysProperties {
public static final int LOB_FILES_PER_DIRECTORY = getIntSetting("h2.lobFilesPerDirectory", 256);
public static final boolean NEW_DISPLAY_SIZE = getBooleanSetting("h2.newDisplaySize", true);
public static final int DEFAULT_MAX_OPERATION_MEMORY = getIntSetting("h2.defaultMaxOperationMemory", 100000);
public static final String ALLOWED_CLASSES = getStringSetting("h2.allowedClasses", "*");
private static boolean getBooleanSetting(String name, boolean defaultValue) {
String s = getProperty(name);
......
......@@ -17,7 +17,7 @@ import org.h2.table.Column;
import org.h2.table.Table;
/**
* The base calss for constraint checking.
* The base class for constraint checking.
*/
public abstract class Constraint extends SchemaObjectBase {
......
......@@ -20,7 +20,7 @@ import org.h2.table.TableFilter;
import org.h2.util.StringUtils;
/**
* A check contraint.
* A check constraint.
*/
public class ConstraintCheck extends Constraint {
......
......@@ -27,7 +27,7 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* A referential contraint.
* A referential constraint.
*/
public class ConstraintReferential extends Constraint {
public static final int RESTRICT = 0, CASCADE = 1, SET_DEFAULT = 2, SET_NULL = 3;
......
......@@ -15,7 +15,7 @@ import org.h2.table.Table;
import org.h2.util.StringUtils;
/**
* A unique contraint. This object always backed by a unique index.
* A unique constraint. This object always backed by a unique index.
*/
public class ConstraintUnique extends Constraint {
......
......@@ -1295,9 +1295,9 @@ public class Database implements DataHandler {
}
}
public Class loadClass(String className) throws SQLException {
public Class loadUserClass(String className) throws SQLException {
try {
return ClassUtils.loadClass(className);
return ClassUtils.loadUserClass(className);
} catch (ClassNotFoundException e) {
throw Message.getSQLException(ErrorCode.CLASS_NOT_FOUND_1, new String[] { className }, e);
}
......@@ -1308,7 +1308,7 @@ public class Database implements DataHandler {
eventListener = null;
} else {
try {
eventListener = (DatabaseEventListener) loadClass(className).newInstance();
eventListener = (DatabaseEventListener) loadUserClass(className).newInstance();
String url = databaseURL;
if (cipher != null) {
url += ";CIPHER=" + cipher;
......
......@@ -55,7 +55,7 @@ public class FunctionAlias extends DbObjectBase {
if (javaMethod != null) {
return;
}
Class javaClass = database.loadClass(className);
Class javaClass = database.loadUserClass(className);
Method[] methods = javaClass.getMethods();
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
......
......@@ -30,7 +30,7 @@ public class UserAggregate extends DbObjectBase {
public AggregateFunction getInstance() throws SQLException {
if (javaClass == null) {
javaClass = database.loadClass(className);
javaClass = database.loadUserClass(className);
}
Object obj;
try {
......
......@@ -22,7 +22,7 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* This class wrapps a user defined aggregate.
* This class wraps a user defined aggregate.
*/
public class JavaAggregate extends Expression {
......
......@@ -16,7 +16,7 @@ import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
/**
* This class wrapps a user defined function.
* This class wraps a user defined function.
*/
public class JavaFunction extends Expression implements FunctionCall {
......
......@@ -909,7 +909,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if (ci.isRemote()) {
session = new SessionRemote().createSession(ci);
} else {
SessionInterface si = (SessionInterface) ClassUtils.loadClass("org.h2.engine.Session").newInstance();
SessionInterface si = (SessionInterface) ClassUtils.loadSystemClass("org.h2.engine.Session").newInstance();
String baseDir = SysProperties.getBaseDir();
if (baseDir != null) {
ci.setBaseDir(baseDir);
......
......@@ -153,7 +153,8 @@
90130=Diese Methode ist nicht erlaubt f\u00FCr ein PreparedStatement; ben\u00FCtzen Sie ein Statement.
90131=Gleichzeitige \u00C4nderung in Tabelle {0}\: eine andere Transaktion hat den gleichen Datensatz ge\u00E4ndert oder gel\u00F6scht
90132=Aggregat-Funktion {0} nicht gefunden
90133=\#Cannot change the setting {0} when the database is already open
90133=Kann das Setting {0} nicht \u00E4ndern wenn die Datenbank bereits ge\u00F6ffnet ist
90134=Der Zugriff auf die Klasse {0} ist nicht erlaubt
HY000=Allgemeiner Fehler\: {0}
HY004=Unbekannter Datentyp\: {0}
HYC00=Dieses Feature wird unterst\u00FCtzt
......
......@@ -154,6 +154,7 @@
90131=Concurrent update in table {0}\: another transaction has updated or deleted the same row
90132=Aggregate {0} not found
90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied
HY000=General error\: {0}
HY004=Unknown data type\: {0}
HYC00=Feature not supported
......
......@@ -154,6 +154,7 @@
90131=\u30C6\u30FC\u30D6\u30EB {0} \u306B\u4E26\u884C\u3057\u3066\u66F4\u65B0\u304C\u884C\u308F\u308C\u307E\u3057\u305F\: \u5225\u306E\u30C8\u30E9\u30F3\u30B6\u30AF\u30B7\u30E7\u30F3\u304C\u3001\u540C\u3058\u884C\u306B\u66F4\u65B0\u304B\u524A\u9664\u3092\u884C\u3044\u307E\u3057\u305F
90132=\#Aggregate {0} not found
90133=\#Cannot change the setting {0} when the database is already open
90134=\#Access to the class {0} is denied
HY000=\u4E00\u822C\u30A8\u30E9\u30FC\: {0}
HY004=\u4E0D\u660E\u306A\u30C7\u30FC\u30BF\u578B\: {0}
HYC00=\u6A5F\u80FD\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093
......
......@@ -154,6 +154,7 @@
90131=\#Concurrent update in table {0}\: another transaction has updated or deleted the same row
90132=\#Aggregate {0} not found
90133=\#Cannot change the setting {0} when the database is already open
90134=\#Access to the class {0} is denied
HY000=Blad ogolny\: {0}
HY004=Nieznany typ danyche\: {0}
HYC00=Cecha nie jest wspierana
......
......@@ -154,6 +154,7 @@
90131=Atualiza\u00E7\u00E3o concorrente na tabela {0}\: outra transa\u00E7\u00E3o atualizou ou deletou a mesma linha
90132=Agrega\u00E7\u00E3o {0} n\u00E3o encontrada
90133=\#Cannot change the setting {0} when the database is already open
90134=\#Access to the class {0} is denied
HY000=Erro geral\: {0}
HY004=Tipo de dados desconhecido\: {0}
HYC00=Recurso n\u00E3o suportado
......
......@@ -52,7 +52,7 @@ public class TriggerObject extends SchemaObjectBase {
this.triggerClassName = triggerClassName;
try {
Connection c2 = session.createConnection(false);
Object obj = session.getDatabase().loadClass(triggerClassName).newInstance();
Object obj = session.getDatabase().loadUserClass(triggerClassName).newInstance();
triggerCallback = (Trigger) obj;
triggerCallback.init(c2, getSchema().getName(), getName(), table.getName());
} catch (Throwable e) {
......
......@@ -55,6 +55,7 @@ public class WebServer implements Service {
{ "pt_BR", "Portugu\u00eas (Brasil)"},
{ "pt_PT", "Portugu\u00eas (Europeu)"},
{ "ru", "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"},
{ "tr", "T\u00fcrk\u00e7e"},
{ "uk", "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
{ "zh_CN", "\u4E2D\u6587"},
};
......
.translator=R&\#305;dvan A&\#287;ar
a.help=Yard&\#305;m
a.language=T&\#252;rk&\#231;e
a.lynxNotSupported=Web taray&\#305;c&\#305;n&\#305;z HTML Frames'i desteklemiyor. Frames (ve Javascript) deste&\#287;i gerekli.
a.password=&\#350;ifre
a.remoteConnectionsDisabled=Ba&\#351;ka bilgisayarlardan, veri taban&\#305;na ba&\#287;lanma izni hen&\#252;z ayarlanmam&\#305;&\#351; ('webAllowOthers').
a.title=H2 Konsolu
a.user=Kullan&\#305;c&\#305; ad&\#305;
admin.executing=Aktif
admin.ip=IP
admin.lastAccess=Son ba&\#287;lant&\#305;
admin.lastQuery=Son komut
admin.url=URL
adminAllow=&\#304;zin verilen ba&\#287;lant&\#305;lar
adminConnection=Ba&\#287;lant&\#305; g&\#252;venli&\#287;i
adminHttp=&\#350;ifrelenmemi&\#351; HTTP ba&\#287;lant&\#305;lar&\#305;
adminHttps=&\#350;ifrelenmi&\#351; HTTP ba&\#287;lant&\#305;lar&\#305;
adminLocal=Sadece yerel ba&\#287;lant&\#305;lara izin ver
adminLogin=Y&\#246;netim giri&\#351;i
adminLoginCancel=&\#304;ptal et
adminLoginOk=Tamam
adminLogout=Bitir
adminOthers=Ba&\#351;ka bilgisayarlardan, veri taban&\#305;na ba&\#287;lanma izni ver
adminPort=Port
adminPortWeb=Web-Server Port
adminRestart=De&\#287;i&\#351;iklikler veri taban&\#305; hizmet&\#231;isinin yeniden ba&\#351;lat&\#305;lmas&\#305;yla etkinlik kazanacak.
adminSave=Kaydet
adminSessions=Aktif ba&\#287;lant&\#305;lar
adminShutdown=Kapat
adminTitle=H2 Konsol ayarlar&\#305;
helpAction=Aksiyon
helpAddAnotherRow=Yeni bir sat&\#305;r ekle
helpAddDrivers=Veritaban&\#305; s&\#252;r&\#252;c&\#252;s&\#252; ekle
helpAddDriversOnlyJava=Ek s&\#252;r&\#252;c&\#252;ler sadece Java s&\#252;r&\#252;m&\#252; ile kullan&\#305;labilir.
helpAddDriversText=Yeni veri taban&\#305; s&\#252;r&\#252;c&\#252;leri eklemek i&\#231;in, s&\#252;r&\#252;c&\#252; dosyalar&\#305;n&\#305;n yerini H2DRIVERS yada CLASSPATH &\#231;evre de&\#287;i&\#351;kenlerine ekleyebilirsiniz. &\#214;rnek (Windows)\: S&\#252;r&\#252;c&\#252; dosyas&\#305; C\:\\Programs\\hsqldb\\lib\\hsqldb.jar ise H2DRIVERS de&\#287;i&\#351;kenini C\:\\Programs\\hsqldb\\lib\\hsqldb.jar olarak girin.
helpAddRow=Veri taban&\#305;na yeni bir sat&\#305;r ekler
helpCommandHistory=Komut tarih&\#231;esini g&\#246;sterir
helpCreateTable=Veri taban&\#305;na yeni bir tabela ekler
helpDeleteRow=Tabeladan sat&\#305;r&\#305; siler
helpDisconnect=Veri taban&\#305; ba&\#287;lant&\#305;s&\#305;n&\#305; keser
helpDisplayThis=Bu yard&\#305;m sayfas&\#305;n&\#305; g&\#246;sterir
helpDropTable=Var ise, istenen tabelay&\#305; siler
helpExecuteCurrent=Girilen SQL komutunu icra eder
helpIcon=&\#350;alter
helpImportantCommands=&\#214;nemli komutlar
helpOperations=&\#304;&\#351;lemler
helpQuery=Tabela i&\#231;eri&\#287;ini g&\#246;sterir
helpSampleSQL=&\#214;rnek SQL
helpStatements=SQL komutlar&\#305;
helpUpdate=Bir tabeladaki belli bir sat&\#305;r i&\#231;eri&\#287;ini de&\#287;i&\#351;tirir
helpWithColumnsIdName=Colon isimleriyle birlikte
login.connect=Ba&\#287;lan
login.driverClass=Veri taban&\#305; s&\#252;r&\#252;c&\#252; s&\#305;n&\#305;f&\#305;
login.driverNotFound=&\#304;stenilen veri taban&\#305; s&\#252;r&\#252;c&\#252;s&\#252; bulunamad&\#305;<br />S&\#252;r&\#252;c&\#252; ekleme konusunda bilgi i&\#231;in Yard&\#305;m'a ba&\#351;vurunuz
login.goAdmin=Se&\#231;enekler
login.jdbcUrl=JDBC URL
login.language=Dil
login.login=Gir
login.remove=Sil
login.save=Kaydet
login.savedSetting=Kay&\#305;tl&\#305; ayarlar
login.settingName=Ayar ad&\#305;
login.testConnection=Ba&\#287;lant&\#305;y&\#305; test et
login.testSuccessful=Test ba&\#351;ar&\#305;l&\#305;
login.welcome=H2 Konsolu
result.1row=1 dizi
result.autoCommitOff=Auto-Commit kapat&\#305;ld&\#305;
result.autoCommitOn=Auto-Commit a&\#231;&\#305;ld&\#305;
result.maxrowsSet=Maximum dizi say&\#305;s&\#305; ayar&\#305; yap&\#305;ld&\#305;
result.noRows=Hi&\#231; bir bilgi yok
result.noRunningStatement=&\#350;u an bir komut icra ediliyor
result.rows=Dizi
result.statementWasCancelled=Komut iptal edildi
result.updateCount=G&\#252;ncelle&\#351;terilen dizi say&\#305;s&\#305;
resultEdit.add=Ekle
resultEdit.cancel=&\#304;ptal
resultEdit.delete=Sil
resultEdit.edit=De&\#287;i&\#351;tir
resultEdit.editResult=De&\#287;i&\#351;tir
resultEdit.save=Kaydet
toolbar.all=Hepsi
toolbar.autoCommit=Auto-Commit
toolbar.autoComplete=Auto-Complete
toolbar.autoComplete.full=Hepsi
toolbar.autoComplete.normal=Normal
toolbar.autoComplete.off=Kapal&\#305;
toolbar.cancelStatement=Y&\#252;r&\#252;t&\#252;len i&\#351;lemi iptal et
toolbar.clear=Temizle
toolbar.commit=Degi&\#351;iklikleri kaydet
toolbar.disconnect=Ba&\#287;lant&\#305;y&\#305; kes
toolbar.history=Verilmi&\#351; olan komutlar
toolbar.maxRows=Maximum dizi say&\#305;s&\#305;
toolbar.refresh=G&\#252;ncelle&\#351;tir
toolbar.rollback=De&\#287;i&\#351;iklikleri geri al
toolbar.run=&\#304;&\#351;lemi y&\#252;r&\#252;t
toolbar.sqlStatement=SQL komutu
tree.admin=Y&\#246;netici
tree.current=G&\#252;ncel de&\#287;er
tree.hashed=Hash tabanl&\#305;
tree.increment=Art&\#305;r
tree.indexes=Indexler
tree.nonUnique=e&\#351;siz de&\#287;il
tree.sequences=Dizinler
tree.unique=E&\#351;siz
tree.users=Kullan&\#305;c&\#305;
......@@ -1172,7 +1172,7 @@ public class MetaTable extends Table {
"" + trigger.getQueueSize(), // QUEUE_SIZE INT
"" + trigger.getNoWait(), // NO_WAIT BIT
replaceNullWithEmpty(trigger.getComment()), // REMARKS
trigger.getSQL(), // SQL
trigger.getCreateSQL(), // SQL
"" + trigger.getId() // ID
});
}
......
......@@ -88,7 +88,7 @@ public class RunScript {
} else if (args[i].equals("-driver")) {
String driver = args[++i];
try {
ClassUtils.loadClass(driver);
ClassUtils.loadUserClass(driver);
} catch (ClassNotFoundException e) {
throw Message.convert(e);
}
......
......@@ -4,10 +4,57 @@
*/
package org.h2.util;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.message.Message;
public class ClassUtils {
public static Class loadClass(String className) throws ClassNotFoundException {
// TODO support special syntax to load classes using another classloader
private static final boolean ALLOW_ALL;
private static final HashSet ALLOWED_CLASS_NAMES = new HashSet();
private static final String[] ALLOWED_CLASS_NAME_PREFIXES;
static {
String s = SysProperties.ALLOWED_CLASSES;
String[] list = StringUtils.arraySplit(s, ',', true);
ArrayList prefixes = new ArrayList();
boolean allowAll = false;
for (int i = 0; i < list.length; i++) {
String p = list[i];
if (p.equals("*")) {
allowAll = true;
} else if (p.endsWith("*")) {
prefixes.add(p.substring(0, p.length() - 1));
} else {
ALLOWED_CLASS_NAMES.add(p);
}
}
ALLOW_ALL = allowAll;
ALLOWED_CLASS_NAME_PREFIXES = new String[prefixes.size()];
prefixes.toArray(ALLOWED_CLASS_NAME_PREFIXES);
}
public static Class loadSystemClass(String className) throws ClassNotFoundException {
return Class.forName(className);
}
public static Class loadUserClass(String className) throws ClassNotFoundException, SQLException {
if (!ALLOW_ALL && !ALLOWED_CLASS_NAMES.contains(className)) {
boolean allowed = false;
for (int i = 0; i < ALLOWED_CLASS_NAME_PREFIXES.length; i++) {
String s = ALLOWED_CLASS_NAME_PREFIXES[i];
if (className.startsWith(s)) {
allowed = true;
}
}
if (!allowed) {
throw Message.getSQLException(ErrorCode.ACCESS_DENIED_TO_CLASS_1, className);
}
}
return Class.forName(className);
}
......
......@@ -83,7 +83,7 @@ public class JdbcUtils {
public static Connection getConnection(String driver, String url, Properties prop) throws SQLException {
if (!StringUtils.isNullOrEmpty(driver)) {
try {
Class d = ClassUtils.loadClass(driver);
Class d = ClassUtils.loadUserClass(driver);
if (java.sql.Driver.class.isAssignableFrom(d)) {
return DriverManager.getConnection(url, prop);
//#ifdef JDK14
......
......@@ -156,22 +156,6 @@ C:\temp\test\db
No more
@author
SQL column in INFORMATION_SCHEMA.TRIGGERS
build.xml
org/h2/server/web/*.*
They are currently in the tools folder, I will move them to the main folder.
Add unit tests.
History:
The classes DbStarter and WebServlet have been moved to src/main.
Improved debugging support: toString methods of most object now return a meaningful text.
This database could not be used in applets. Fixed
A stack trace was thrown if the system did not provide a quick secure
random source and if there is no network or the network settings are not configured. Fixed.
toString: > the parameters for the prepared statements.
autocomplete only just after meaningful key (ctrl+space, space, bs, ...)
write more tests for the command line tools
......
......@@ -515,4 +515,5 @@ uklinux credential crypt kerberos redferni routine reopen tmp configured replica
webtest einstellung redirects endless ran gives replication lxabcdef asf packages replayed jspa
russian backward alexahin vlad ffffffffffff bfff ffffffff webapp undeploy initializer brasil uncached slowing translating uploaded
llc computing oliver road inaccessible android velasques duplicates eduardo chunk brazilian near langpair xrmd xmkd
\ No newline at end of file
encapsulates negating igor midnight fulfill prefixes communicates nesting convenience negated resides optimizing principal applets dobrovolskyi
involves ukrainian chile machines restricting summer aliased backus naur
\ No newline at end of file
......@@ -36,7 +36,7 @@ import org.h2.util.StringUtils;
public class PrepareTranslation {
private static final String MAIN_LANGUAGE = "en";
private static final String DELETED_PREFIX = "~";
private static final boolean AUTO_TRANSLATE = true;
private static final boolean AUTO_TRANSLATE = false;
public static void main(String[] args) throws Exception {
new PrepareTranslation().run(args);
......@@ -431,7 +431,13 @@ public class PrepareTranslation {
if (!p.containsKey(key)) {
String t = oldTranslations.getProperty(now);
if (t == null) {
if (AUTO_TRANSLATE) {
toTranslate.add(key);
} else {
System.out.println(trans.getName() + ": key " + key + " not found in translation file; added dummy # 'translation'");
t = "#" + now;
p.put(key, t);
}
} else {
p.put(key, t);
}
......@@ -451,8 +457,13 @@ public class PrepareTranslation {
// main data changed since the last run: review translation
System.out.println(trans.getName() + ": key " + key + " changed, please review; last=" + last
+ " now=" + now);
// String old = p.getProperty(key);
if (AUTO_TRANSLATE) {
toTranslate.add(key);
} else {
String old = p.getProperty(key);
t = "#" + now + " #" + old;
p.put(key, t);
}
} else {
p.put(key, t);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论