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

--no commit message

--no commit message
上级 36e4a4ce
...@@ -15,9 +15,36 @@ Change Log ...@@ -15,9 +15,36 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>. <li>When a log file switch occured in the middle of a sequence flush
</li> (sequences are only flushed every 32 values by default), the sequence
</ul> was lost. Fixed.
</li><li>When a log file switch occured just after a truncate table or drop table
statement, the database could not be started normally (RECOVER=1
was required). Fixed.
</li><li>There was a bug in the recovery code that would stop recovery sometimes when
there are multiple log files to recover.
</li><li>A new Shell tools is now included (org.h2.tools.Shell) query a
database from the command line.
</li><li>Performance was very slow when using LOG=2 and deleting or
updating all rows of a table in a loop. Fixed.
</li><li>ALTER TABLE or CREATE TABLE now support parameters for the password field.
</li><li>The linear hash has been removed. It was always slower than the b-tree index,
and there were some bugs that would be hard to fix.
</li><li>TRACE_LEVEL_ settings are no longer persistent. This was a problem
when database initialization code caused a lot of logging.
</li><li>Fulltext search (native implementation): The words table is no longer
an in-memory table because this caused memory problems in some cases.
</li><li>It was possible to create a role with the name as an existing user
(but not vice versa). This is not allowed any more.
</li><li>The recovery tool didn't work correctly for tables without rows.
</li><li>For years below 1, the YEAR method didn't return the correct value,
and the conversion from date and timestamp to varchar was incorrect.
</li><li>CSVWRITE caused a NullPointerException when not specifying a nullString.
</li><li>New system property h2.sortNullsHigh to invert the default sorting behavior
for NULL. The default didn't change.
</li><li>Altering a sequence didn't unlock the system table
when autocommit switched off.
</li></ul>
<h2>Version 1.0.68 (2008-03-18)</h2> <h2>Version 1.0.68 (2008-03-18)</h2>
<ul> <ul>
...@@ -317,34 +344,4 @@ Change Log ...@@ -317,34 +344,4 @@ Change Log
</li><li>OpenOffice compatibility: support database name in column names. </li><li>OpenOffice compatibility: support database name in column names.
</li></ul> </li></ul>
<h2>Version 1.0.56 (2007-08-02)</h2>
<ul>
<li>A new tool to help translation has been implemented: src/tools/org/h2/tools/i18n/PrepareTranslation. This tool can detect delta changes in the original (English) and prepends '#' in translation if the original text was changed. It can also extract text from the user documentation (however, it is incomplete).
</li><li>The error messages (src/main/org/h2/res/_*.*) can now be translated.
</li><li>Part of the documentation has been translated to Japanese by Yusuke Fukushima.
</li><li>Some Unicode characters where not supported as identifier name. Thanks Yusuke Fukushima for reporting this problem.
</li><li>The default value DEFAULT_MAX_LENGTH_INPLACE_LOB has been changed from 128 to 1024.
</li><li>A server that implements the PostgreSQL protocol is now included and documented. That means, the PostgreSQL ODBC driver can be used to access a H2 database. See in the documentation for details.
</li><li>The experimental H2 ODBC driver has been removed.
</li><li>The default value for h2.defaultMaxMemoryUndo is now 50000. This avoids out of memory problems when using large transactions, however large transactions are slower because they are buffered to disk. To disable, use -Dh2.defaultMaxMemoryUndo=2000000000.
</li><li>Support for regular expression function REGEXP_REPLACE(expression, regex, replacement) and regular expression LIKE: expression REGEXP matchExpression. However, indexes are not yet used.
</li><li>The old view implementation has been removed.
</li><li>The SysTray tool has been removed, because JDK 1.6 has native support for system tray icons. Use the Console tool (org.h2.tools.Console) automatically installs a system tray icon if JDK 1.6 is used.
</li><li>H2 Console: In the last release, the shutdown button did not work. Fixed.
</li><li>Referential integrity can now be disabled using SET REFERENTIAL_INTEGRITY FALSE. It can also be disable only for one table using ALTER TABLE SET REFERENTIAL_INTEGRITY FALSE.
</li><li>The Backup and Restore tools, and the BACKUP command did not back up LOBs when h2.lobFilesInDirectories was enabled. Fixed.
</li><li>Calculation of cache memory usage has been improved.
</li><li>In some situations record were released too late from the cache. Fixed.
</li><li>The cache size is now measured in KB instead of blocks of 128 byte.
</li><li>CREATE TABLE ... AS SELECT now needs less memory. While inserting the rows, the undo log is temporarily disabled. This avoid out of memory problems when creating large tables.
</li><li>The per session undo log can now be disabled. This setting is useful for bulk operations that don't need to be atomic, like bulk delete or update.
</li><li>The database file could get corrupted when there was an OutOfMemoryException in the middle of inserting a row.
</li><li>Optimization for WHERE NOT(...) and WHERE [NOT] booleanFlagColumn. This can be disabled using the system property h2.optimizeNot.
</li><li>Optimization for conditions like WHERE A=B AND B=X (A=X is added). This often appears in joins. This can be disabled using the system property h2.optimizeTwoEquals.
</li><li>Documentation: the source code in 'Compacting a Database' was incorrect. Fixed.
</li><li>In the H2 Console, result sets could not be modified because the default result set type is now forward only. For H2, now uses scrollable result sets. Also for other databases, but only when the query starts with @EDIT.
</li><li>Views using UNION did not work correctly. Fixed.
</li><li>Function tables did not work with views and EXPLAIN. Fixed.
</li></ul>
</div></td></tr></table><!-- analytics --></body></html> </div></td></tr></table><!-- analytics --></body></html>
...@@ -394,6 +394,10 @@ Roadmap ...@@ -394,6 +394,10 @@ Roadmap
</li><li>Javadocs: for each tool, add a copy & paste sample in the class level. </li><li>Javadocs: for each tool, add a copy & paste sample in the class level.
</li><li>Add google site search to web page. </li><li>Add google site search to web page.
</li><li>Javadocs: add @author tags. </li><li>Javadocs: add @author tags.
</li><li>SET LOG_SYSTEM {NATIVE|LOG4J|COMMONS|DRIVER_MANAGER}
</li><li>Fluent API for tools: Server.createTcpServer().setPort(9081).setPassword(password).start();
</li><li>MySQL compatibility: SHOW TABLES, DESCRIBE TEST (then remove from Shell)
</li><li>Use a default delay of 1 second before closing a database.
</li></ul> </li></ul>
<h2>Not Planned</h2> <h2>Not Planned</h2>
......
...@@ -79,6 +79,12 @@ public class Constants { ...@@ -79,6 +79,12 @@ public class Constants {
public static final int BUILD_ID = 68; public static final int BUILD_ID = 68;
private static final String BUILD = "2008-03-15"; private static final String BUILD = "2008-03-15";
public static final boolean ALLOW_EMPTY_BTREE_PAGES = true;
public static final int ALLOW_LITERALS_NONE = 0;
public static final int ALLOW_LITERALS_NUMBERS = 1;
public static final int ALLOW_LITERALS_ALL = 2;
public static final boolean AUTO_CONVERT_LOB_TO_FILES = true;
public static final int VERSION_MAJOR = 1; public static final int VERSION_MAJOR = 1;
public static final int VERSION_MINOR = 0; public static final int VERSION_MINOR = 0;
...@@ -170,12 +176,7 @@ public class Constants { ...@@ -170,12 +176,7 @@ public class Constants {
public static final boolean SERIALIZE_JAVA_OBJECTS = true; public static final boolean SERIALIZE_JAVA_OBJECTS = true;
public static final long DEFAULT_MAX_LOG_SIZE = 32 * 1024 * 1024; public static final long DEFAULT_MAX_LOG_SIZE = 32 * 1024 * 1024;
public static final long LOG_SIZE_DIVIDER = 10; public static final long LOG_SIZE_DIVIDER = 10;
public static final int ALLOW_LITERALS_NONE = 0;
public static final int ALLOW_LITERALS_NUMBERS = 1;
public static final int ALLOW_LITERALS_ALL = 2;
public static final int DEFAULT_ALLOW_LITERALS = ALLOW_LITERALS_ALL; public static final int DEFAULT_ALLOW_LITERALS = ALLOW_LITERALS_ALL;
public static final boolean AUTO_CONVERT_LOB_TO_FILES = true;
public static final boolean ALLOW_EMPTY_BTREE_PAGES = true;
public static final String CONN_URL_INTERNAL = "jdbc:default:connection"; public static final String CONN_URL_INTERNAL = "jdbc:default:connection";
public static final String CONN_URL_COLUMNLIST = "jdbc:columnlist:connection"; public static final String CONN_URL_COLUMNLIST = "jdbc:columnlist:connection";
public static final int VIEW_INDEX_CACHE_SIZE = 64; public static final int VIEW_INDEX_CACHE_SIZE = 64;
......
...@@ -238,6 +238,15 @@ public class Database implements DataHandler { ...@@ -238,6 +238,15 @@ public class Database implements DataHandler {
return textStorage; return textStorage;
} }
/**
* Check if the storage mode of the given database file is 'text'.
*
* @param fileName the file name of the database file
* @param defaultValue the value to use if the file doesn't exist or is too
* small
* @return true if the storage mode is 'text'
* @throws SQLException if the database file version does not match
*/
public static boolean isTextStorage(String fileName, boolean defaultValue) throws SQLException { public static boolean isTextStorage(String fileName, boolean defaultValue) throws SQLException {
byte[] magicText = Constants.MAGIC_FILE_HEADER_TEXT.getBytes(); byte[] magicText = Constants.MAGIC_FILE_HEADER_TEXT.getBytes();
byte[] magicBinary = Constants.MAGIC_FILE_HEADER.getBytes(); byte[] magicBinary = Constants.MAGIC_FILE_HEADER.getBytes();
...@@ -1647,6 +1656,12 @@ public class Database implements DataHandler { ...@@ -1647,6 +1656,12 @@ public class Database implements DataHandler {
this.lobCompressionAlgorithm = stringValue; this.lobCompressionAlgorithm = stringValue;
} }
/**
* Called when the size if the data or index file has been changed. The log
* file size is at least 10% of the largest file.
*
* @param length the new file size
*/
public void notifyFileSize(long length) { public void notifyFileSize(long length) {
if (length > biggestFileSize) { if (length > biggestFileSize) {
biggestFileSize = length; biggestFileSize = length;
...@@ -1690,6 +1705,11 @@ public class Database implements DataHandler { ...@@ -1690,6 +1705,11 @@ public class Database implements DataHandler {
return cacheType; return cacheType;
} }
/**
* Called when the summary of the index in the log file has become invalid.
* This method is only called if index changes are not logged, and if an
* index has been changed.
*/
public void invalidateIndexSummary() throws SQLException { public void invalidateIndexSummary() throws SQLException {
if (indexSummaryValid) { if (indexSummaryValid) {
indexSummaryValid = false; indexSummaryValid = false;
...@@ -1717,14 +1737,29 @@ public class Database implements DataHandler { ...@@ -1717,14 +1737,29 @@ public class Database implements DataHandler {
return referentialIntegrity; return referentialIntegrity;
} }
/**
* Check if the database is currently opening. This is true until all stored
* SQL statements have been executed.
*
* @return true if the database is still starting
*/
public boolean isStarting() { public boolean isStarting() {
return starting; return starting;
} }
/**
* Check if multi version concurrency is enabled for this database.
*
* @return true if it is enabled
*/
public boolean isMultiVersion() { public boolean isMultiVersion() {
return multiVersion; return multiVersion;
} }
/**
* Called after the database has been opened and initialized. This method
* notifies the event listener if one has been set.
*/
public void opened() throws SQLException { public void opened() throws SQLException {
if (eventListener != null) { if (eventListener != null) {
eventListener.opened(); eventListener.opened();
......
...@@ -35,6 +35,11 @@ public class MetaRecord { ...@@ -35,6 +35,11 @@ public class MetaRecord {
sql = r.getValue(3).getString(); sql = r.getValue(3).getString();
} }
/**
* Sort the list of meta records by 'create order'.
*
* @param records the list of meta records
*/
public static void sort(ObjectArray records) { public static void sort(ObjectArray records) {
records.sort(new Comparator() { records.sort(new Comparator() {
public int compare(Object o1, Object o2) { public int compare(Object o1, Object o2) {
......
...@@ -15,6 +15,9 @@ import org.h2.util.StringUtils; ...@@ -15,6 +15,9 @@ import org.h2.util.StringUtils;
*/ */
public class Mode { public class Mode {
/**
* The name of the default mode.
*/
public static final String REGULAR = "REGULAR"; public static final String REGULAR = "REGULAR";
public boolean nullConcatIsNull; public boolean nullConcatIsNull;
...@@ -66,6 +69,12 @@ public class Mode { ...@@ -66,6 +69,12 @@ public class Mode {
this.name = name; this.name = name;
} }
/**
* Get the mode with the given name.
*
* @param name the name of the mode
* @return the mode object
*/
public static Mode getInstance(String name) { public static Mode getInstance(String name) {
return (Mode) MODES.get(StringUtils.toUpperEnglish(name)); return (Mode) MODES.get(StringUtils.toUpperEnglish(name));
} }
......
...@@ -17,7 +17,31 @@ import org.h2.table.Table; ...@@ -17,7 +17,31 @@ import org.h2.table.Table;
*/ */
public class Right extends DbObjectBase { public class Right extends DbObjectBase {
public static final int SELECT = 1, DELETE = 2, INSERT = 4, UPDATE = 8, ALL = 15; /**
* The right bit mask that means: selecting from a table is allowed.
*/
public static final int SELECT = 1;
/**
* The right bit mask that means: deleting rows from a table is allowed.
*/
public static final int DELETE = 2;
/**
* The right bit mask that means: inserting rows into a table is allowed.
*/
public static final int INSERT = 4;
/**
* The right bit mask that means: updating data is allowed.
*/
public static final int UPDATE = 8;
/**
* The right bit mask that means: select, insert, update, delete, and update
* for this object is allowed.
*/
public static final int ALL = SELECT | DELETE | INSERT | UPDATE;
private Role grantedRole; private Role grantedRole;
private int grantedRight; private int grantedRight;
......
...@@ -36,6 +36,12 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -36,6 +36,12 @@ public abstract class RightOwner extends DbObjectBase {
initDbObjectBase(database, id, name, traceModule); initDbObjectBase(database, id, name, traceModule);
} }
/**
* Check if a role has been granted for this right owner.
*
* @param grantedRole the role
* @return true if the role has been granted
*/
public boolean isRoleGranted(Role grantedRole) { public boolean isRoleGranted(Role grantedRole) {
if (grantedRole == this) { if (grantedRole == this) {
return true; return true;
...@@ -77,6 +83,13 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -77,6 +83,13 @@ public abstract class RightOwner extends DbObjectBase {
return false; return false;
} }
/**
* Grant a right for the given table. Only one right object per table is
* supported.
*
* @param table the table
* @param right the right
*/
public void grantRight(Table table, Right right) { public void grantRight(Table table, Right right) {
if (grantedRights == null) { if (grantedRights == null) {
grantedRights = new HashMap(); grantedRights = new HashMap();
...@@ -84,6 +97,11 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -84,6 +97,11 @@ public abstract class RightOwner extends DbObjectBase {
grantedRights.put(table, right); grantedRights.put(table, right);
} }
/**
* Revoke the right for the given table.
*
* @param table the table
*/
public void revokeRight(Table table) { public void revokeRight(Table table) {
if (grantedRights == null) { if (grantedRights == null) {
return; return;
...@@ -108,6 +126,13 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -108,6 +126,13 @@ public abstract class RightOwner extends DbObjectBase {
grantedRoles.put(role, right); grantedRoles.put(role, right);
} }
/**
* Remove the right for the given role.
*
* @param session the session
* @param role the role to revoke
* @throws SQLException if the right has not been granted
*/
public void revokeRole(Session session, Role role) throws SQLException { public void revokeRole(Session session, Role role) throws SQLException {
if (grantedRoles == null) { if (grantedRoles == null) {
throw Message.getSQLException(ErrorCode.RIGHT_NOT_FOUND); throw Message.getSQLException(ErrorCode.RIGHT_NOT_FOUND);
...@@ -122,6 +147,12 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -122,6 +147,12 @@ public abstract class RightOwner extends DbObjectBase {
} }
} }
/**
* Get the 'grant table' right of this object.
*
* @param table the granted table
* @return the right or null if the right has not been granted
*/
public Right getRightForTable(Table table) { public Right getRightForTable(Table table) {
if (grantedRights == null) { if (grantedRights == null) {
return null; return null;
...@@ -129,6 +160,12 @@ public abstract class RightOwner extends DbObjectBase { ...@@ -129,6 +160,12 @@ public abstract class RightOwner extends DbObjectBase {
return (Right) grantedRights.get(table); return (Right) grantedRights.get(table);
} }
/**
* Get the 'grant role' right of this object.
*
* @param role the granted role
* @return the right or null if the right has not been granted
*/
public Right getRightForRole(Role role) { public Right getRightForRole(Role role) {
if (grantedRoles == null) { if (grantedRoles == null) {
return null; return null;
......
...@@ -102,6 +102,12 @@ public class Session implements SessionInterface { ...@@ -102,6 +102,12 @@ public class Session implements SessionInterface {
} }
} }
/**
* Set the value of the given variable for this session.
*
* @param name the name of the variable (may not be null)
* @param value the new value (may not be null)
*/
public void setVariable(String name, Value value) throws SQLException { public void setVariable(String name, Value value) throws SQLException {
initVariables(); initVariables();
Value old; Value old;
...@@ -143,6 +149,12 @@ public class Session implements SessionInterface { ...@@ -143,6 +149,12 @@ public class Session implements SessionInterface {
return list; return list;
} }
/**
* Add a local temporary table to this session.
*
* @param table the table to add
* @throws SQLException if a table with this name already exists
*/
public void addLocalTempTable(Table table) throws SQLException { public void addLocalTempTable(Table table) throws SQLException {
if (localTempTables == null) { if (localTempTables == null) {
localTempTables = new HashMap(); localTempTables = new HashMap();
...@@ -364,6 +376,12 @@ public class Session implements SessionInterface { ...@@ -364,6 +376,12 @@ public class Session implements SessionInterface {
} }
} }
/**
* Add a lock for the given table. The object is unlocked on commit or
* rollback.
*
* @param table the table that is locked
*/
public void addLock(Table table) { public void addLock(Table table) {
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
if (locks.indexOf(table) >= 0) { if (locks.indexOf(table) >= 0) {
...@@ -474,6 +492,13 @@ public class Session implements SessionInterface { ...@@ -474,6 +492,13 @@ public class Session implements SessionInterface {
return lastIdentity; return lastIdentity;
} }
/**
* Called when a log entry for this session is added. The session keeps
* track of the first entry in the log file that is not yet committed.
*
* @param logId the log file id
* @param pos the position of the log entry in the log file
*/
public void addLogPos(int logId, int pos) { public void addLogPos(int logId, int pos) {
if (firstUncommittedLog == LogSystem.LOG_WRITTEN) { if (firstUncommittedLog == LogSystem.LOG_WRITTEN) {
firstUncommittedLog = logId; firstUncommittedLog = logId;
...@@ -651,6 +676,11 @@ public class Session implements SessionInterface { ...@@ -651,6 +676,11 @@ public class Session implements SessionInterface {
return "TEMP_VIEW_" + tempViewIndex++; return "TEMP_VIEW_" + tempViewIndex++;
} }
/**
* Add a procedure to this session.
*
* @param procedure the procedure to add
*/
public void addProcedure(Procedure procedure) { public void addProcedure(Procedure procedure) {
if (procedures == null) { if (procedures == null) {
procedures = new HashMap(); procedures = new HashMap();
...@@ -658,12 +688,24 @@ public class Session implements SessionInterface { ...@@ -658,12 +688,24 @@ public class Session implements SessionInterface {
procedures.put(procedure.getName(), procedure); procedures.put(procedure.getName(), procedure);
} }
/**
* Remove a procedure from this session.
*
* @param procedure the procedure to remove
*/
public void removeProcedure(String name) { public void removeProcedure(String name) {
if (procedures != null) { if (procedures != null) {
procedures.remove(name); procedures.remove(name);
} }
} }
/**
* Get the procedure with the given name, or null
* if none exists.
*
* @param name the procedure name
* @return the procedure or null
*/
public Procedure getProcedure(String name) { public Procedure getProcedure(String name) {
if (procedures == null) { if (procedures == null) {
return null; return null;
......
...@@ -45,10 +45,6 @@ public class Wildcard extends Expression { ...@@ -45,10 +45,6 @@ public class Wildcard extends Expression {
throw Message.getSQLException(ErrorCode.SYNTAX_ERROR_1, table); throw Message.getSQLException(ErrorCode.SYNTAX_ERROR_1, table);
} }
public void checkMapped() {
throw Message.getInternalError();
}
public Expression optimize(Session session) throws SQLException { public Expression optimize(Session session) throws SQLException {
throw Message.getSQLException(ErrorCode.SYNTAX_ERROR_1, table); throw Message.getSQLException(ErrorCode.SYNTAX_ERROR_1, table);
} }
......
...@@ -176,7 +176,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -176,7 +176,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
* Calculate the cost for the given mask as if this index was a typical * Calculate the cost for the given mask as if this index was a typical
* b-tree range index. * b-tree range index.
* *
* @param mask the search mask * @param masks the search mask
* @param rowCount the number of rows in the index * @param rowCount the number of rows in the index
* @return the calculated cost * @return the calculated cost
*/ */
......
...@@ -200,44 +200,9 @@ Can sometimes not delete log file? need test case ...@@ -200,44 +200,9 @@ Can sometimes not delete log file? need test case
Add where required // TODO: change in version 1.1 Add where required // TODO: change in version 1.1
History: History:
When a log file switch occured in the middle of a sequence flush
(sequences are only flushed every 32 values by default), the sequence
was lost. Fixed.
When a log file switch occured just after a truncate table or drop table
statement, the database could not be started normally (RECOVER=1
was required). Fixed.
There was a bug in the recovery code that would stop recovery sometimes when
there are multiple log files to recover.
A new Shell tools is now included (org.h2.tools.Shell) query a
database from the command line.
Performance was very slow when using LOG=2 and deleting or
updating all rows of a table in a loop. Fixed.
ALTER TABLE or CREATE TABLE now support parameters for the password field.
The linear hash has been removed. It was always slower than the b-tree index,
and there were some bugs that would be hard to fix.
TRACE_LEVEL_ settings are no longer persistent. This was a problem
when database initialization code caused a lot of logging.
Fulltext search (native implementation): The words table is no longer
an in-memory table because this caused memory problems in some cases.
It was possible to create a role with the name as an existing user
(but not vice versa). This is not allowed any more.
The recovery tool didn't work correctly for tables without rows.
For years below 1, the YEAR method didn't return the correct value,
and the conversion from date and timestamp to varchar was incorrect.
CSVWRITE caused a NullPointerException when not specifying a nullString.
New system property h2.sortNullsHigh to invert the default sorting behavior
for NULL. The default didn't change.
Altering a sequence didn't unlock the system table
when autocommit switched off.
Roadmap: Roadmap:
SET LOG_SYSTEM
{NATIVE|LOG4J|COMMONS|DRIVER_MANAGER}
Fluent API for tools: Server.createTcpServer().
setPort(9081).setPassword(password).start();
MySQL compatibility: SHOW TABLES, DESCRIBE TEST (then remove from Shell)
Use a default delay of 1 second before closing a database.
*/ */
......
...@@ -487,4 +487,5 @@ tmpdir mini owns accordingly snippets receiving rainbow pools groupware biz ...@@ -487,4 +487,5 @@ tmpdir mini owns accordingly snippets receiving rainbow pools groupware biz
greenwich sqli informix pointbase fbj pervasive jtds ifx syb mimer sybase greenwich sqli informix pointbase fbj pervasive jtds ifx syb mimer sybase
frontbase intersys maxwidth belonging learning mono typical toggle winexe frontbase intersys maxwidth belonging learning mono typical toggle winexe
hider ikvmc invert recycle filtering lesser recycled assertion runner teradata hider ikvmc invert recycle filtering lesser recycled assertion runner teradata
christian lgpl elapsed ncr disposed heureuse tera years retrieves christian lgpl elapsed ncr disposed heureuse tera years retrieves unlocked
\ No newline at end of file selecting
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论