提交 528531e5 authored 作者: Thomas Mueller's avatar Thomas Mueller

javadocs

上级 2c2e30e7
......@@ -374,4 +374,10 @@ The SQL statement ANALYZE can be used to automatically estimate the selectivity
This command should be run from time to time to improve the query plans generated by the optimizer.
</p>
<h3>Optimization Examples</h3>
<p>
See <code>src/test/org/h2/samples/optimizations.sql</code> for a few examples of queries
that benefit from special optimizations built into the database.
</p>
</div></td></tr></table><!-- analytics --></body></html>
\ No newline at end of file
......@@ -6211,6 +6211,12 @@ If a table has multiple indexes, sometimes more than one index could be used. Ex
@performance_1400_p
The SQL statement ANALYZE can be used to automatically estimate the selectivity of the columns in the tables. This command should be run from time to time to improve the query plans generated by the optimizer.
@performance_1401_h3
Optimization Examples
@performance_1402_p
See <code>src/test/org/h2/samples/optimizations.sql</code> for a few examples of queries that benefit from special optimizations built into the database.
@quickstart_1000_h1
Quickstart
......
......@@ -6216,6 +6216,12 @@ MySQL
@performance_1400_p
#The SQL statement ANALYZE can be used to automatically estimate the selectivity of the columns in the tables. This command should be run from time to time to improve the query plans generated by the optimizer.
@performance_1401_h3
#Optimization Examples
@performance_1402_p
#See <code>src/test/org/h2/samples/optimizations.sql</code> for a few examples of queries that benefit from special optimizations built into the database.
@quickstart_1000_h1
クイックスタート
......
......@@ -2069,6 +2069,8 @@ performance_1397_h3=Updating Optimizer Statistics / Column Selectivity
performance_1398_p=When executing a query, at most one index per joined table can be used. If the same table is joined multiple times, for each join only one index is used. Example\: for the query SELECT * FROM TEST T1, TEST T2 WHERE T1.NAME\='A' AND T2.ID\=T1.ID, two index can be used, in this case the index on NAME for T1 and the index on ID for T2.
performance_1399_p=If a table has multiple indexes, sometimes more than one index could be used. Example\: if there is a table TEST(ID, NAME, FIRSTNAME) and an index on each column, then two indexes could be used for the query SELECT * FROM TEST WHERE NAME\='A' AND FIRSTNAME\='B', the index on NAME or the index on FIRSTNAME. It is not possible to use both indexes at the same time. Which index is used depends on the selectivity of the column. The selectivity describes the 'uniqueness' of values in a column. A selectivity of 100 means each value appears only once, and a selectivity of 1 means the same value appears in many or most rows. For the query above, the index on NAME should be used if the table contains more distinct names than first names.
performance_1400_p=The SQL statement ANALYZE can be used to automatically estimate the selectivity of the columns in the tables. This command should be run from time to time to improve the query plans generated by the optimizer.
performance_1401_h3=Optimization Examples
performance_1402_p=See <code>src/test/org/h2/samples/optimizations.sql</code> for a few examples of queries that benefit from special optimizations built into the database.
quickstart_1000_h1=Quickstart
quickstart_1001_a=Embedding H2 in an Application
quickstart_1002_a=The H2 Console Application
......
......@@ -81,7 +81,7 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
protected String getFileName() throws SQLException {
if (file != null && fileName == null) {
fileName = file.getValue(session).getString();
fileName = file.optimize(session).getValue(session).getString();
if (fileName == null || fileName.trim().length() == 0) {
fileName = "script.sql";
}
......
......@@ -444,7 +444,7 @@ public class ScriptCommand extends ScriptBase {
*/
public static Reader combineClob(Connection conn, int id) throws SQLException, IOException {
ResultSet rs = getLobStream(conn, "CDATA", id);
Writer out = FileUtils.openFileWriter(TEMP_LOB_FILENAME, false);
Writer out = IOUtils.getWriter(FileUtils.openFileOutputStream(TEMP_LOB_FILENAME, false));
while (rs.next()) {
Reader in = new BufferedReader(rs.getCharacterStream(1));
IOUtils.copyAndCloseInput(in, out);
......
......@@ -17,6 +17,7 @@ import org.h2.constant.SysProperties;
import org.h2.expression.ParameterInterface;
import org.h2.util.ByteUtils;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
......@@ -179,7 +180,7 @@ public class TraceObject {
synchronized (TraceObject.class) {
// e.printStackTrace();
try {
Writer writer = FileUtils.openFileWriter(SysProperties.LOG_ALL_ERRORS_FILE, true);
Writer writer = IOUtils.getWriter(FileUtils.openFileOutputStream(SysProperties.LOG_ALL_ERRORS_FILE, true));
PrintWriter p = new PrintWriter(writer);
e.printStackTrace(p);
p.close();
......
......@@ -19,6 +19,7 @@ import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.util.ClassUtils;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.SmallLRUCache;
/**
......@@ -302,7 +303,7 @@ public class TraceSystem implements TraceWriter {
// can't be opened
return false;
}
fileWriter = FileUtils.openFileWriter(fileName, true);
fileWriter = IOUtils.getWriter(FileUtils.openFileOutputStream(fileName, true));
printWriter = new PrintWriter(fileWriter, true);
} catch (Exception e) {
logWritingError(e);
......
......@@ -28,6 +28,7 @@ import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
import org.h2.util.SortedProperties;
/**
* Small FTP Server. Intended for ad-hoc networks in a secure environment.
......@@ -274,7 +275,7 @@ public class FtpServer implements Service {
new StreamRedirect(path, p.getInputStream(), null).start();
return;
}
Properties prop = FileUtils.loadProperties(path);
Properties prop = SortedProperties.loadProperties(path);
String command = prop.getProperty("command");
String outFile = path.substring(0, path.length() - TASK_SUFFIX.length());
String errorFile = root + "/" + prop.getProperty("error", outFile + ".err.txt");
......
......@@ -193,9 +193,9 @@ public class WebServer implements Service {
// TODO web: support using a different properties file
Properties prop = loadProperties();
driverList = prop.getProperty("drivers");
port = FileUtils.getIntProperty(prop, "webPort", Constants.DEFAULT_HTTP_PORT);
ssl = FileUtils.getBooleanProperty(prop, "webSSL", Constants.DEFAULT_HTTP_SSL);
allowOthers = FileUtils.getBooleanProperty(prop, "webAllowOthers", Constants.DEFAULT_HTTP_ALLOW_OTHERS);
port = SortedProperties.getIntProperty(prop, "webPort", Constants.DEFAULT_HTTP_PORT);
ssl = SortedProperties.getBooleanProperty(prop, "webSSL", Constants.DEFAULT_HTTP_SSL);
allowOthers = SortedProperties.getBooleanProperty(prop, "webAllowOthers", Constants.DEFAULT_HTTP_ALLOW_OTHERS);
for (int i = 0; args != null && i < args.length; i++) {
String a = args[i];
if ("-webPort".equals(a)) {
......@@ -437,7 +437,7 @@ public class WebServer implements Service {
private Properties loadProperties() {
String fileName = getPropertiesFileName();
try {
return FileUtils.loadProperties(fileName);
return SortedProperties.loadProperties(fileName);
} catch (IOException e) {
// TODO log exception
return new Properties();
......
......@@ -24,7 +24,6 @@ import org.h2.message.Trace;
import org.h2.message.TraceSystem;
import org.h2.store.fs.FileSystem;
import org.h2.util.ByteUtils;
import org.h2.util.FileUtils;
import org.h2.util.NetUtils;
import org.h2.util.RandomUtils;
import org.h2.util.SortedProperties;
......@@ -169,7 +168,7 @@ public class FileLock {
private Properties load() throws SQLException {
try {
Properties p2 = FileUtils.loadProperties(fileName);
Properties p2 = SortedProperties.loadProperties(fileName);
trace.debug("load " + p2);
return p2;
} catch (IOException e) {
......
......@@ -107,12 +107,14 @@ public abstract class FileSystem {
/**
* Create a new temporary file.
*
* @param prefix the file name prefix
* @param suffix the file name suffix
* @param deleteOnExit if the file should be deleted when the system exists
* @param inTempDir if the file should be stored in the temp file
* @return the file name
*
* @param prefix the prefix of the file name (including directory name if
* required)
* @param suffix the suffix
* @param deleteOnExit if the file should be deleted when the virtual
* machine exists
* @param inTempDir if the file should be stored in the temporary directory
* @return the name of the created file
*/
public abstract String createTempFile(String prefix, String suffix, boolean deleteOnExit, boolean inTempDir) throws IOException;
......
......@@ -118,8 +118,8 @@ public class ConvertTraceFile extends Tool {
*/
private void convertFile(String traceFileName, String javaClassName, String script) throws IOException, SQLException {
LineNumberReader reader = new LineNumberReader(IOUtils.getReader(FileUtils.openFileInputStream(traceFileName)));
PrintWriter javaWriter = new PrintWriter(FileUtils.openFileWriter(javaClassName + ".java", false));
PrintWriter scriptWriter = new PrintWriter(FileUtils.openFileWriter(script, false));
PrintWriter javaWriter = new PrintWriter(IOUtils.getWriter(FileUtils.openFileOutputStream(javaClassName + ".java", false)));
PrintWriter scriptWriter = new PrintWriter(IOUtils.getWriter(FileUtils.openFileOutputStream(script, false)));
javaWriter.println("import java.io.*;");
javaWriter.println("import java.sql.*;");
javaWriter.println("import java.math.*;");
......
......@@ -8,7 +8,6 @@ package org.h2.tools;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
......@@ -318,7 +317,7 @@ public class Recover extends Tool implements DataHandler {
fileName = fileName.substring(0, fileName.length() - 3);
String outputFile = fileName + suffix;
trace("Created file: " + outputFile);
return new PrintWriter(new BufferedWriter(FileUtils.openFileWriter(outputFile, false)));
return new PrintWriter(IOUtils.getWriter(FileUtils.openFileOutputStream(outputFile, false)));
}
private void writeDataError(PrintWriter writer, String error, byte[] data, int dumpBlocks) {
......
......@@ -249,8 +249,12 @@ public class RunScript extends Tool {
}
if (checkResults) {
String expected = r.readStatement() + ";";
expected = StringUtils.replaceAll(expected, "\r\n", "\n");
expected = StringUtils.replaceAll(expected, "\r", "\n");
if (!expected.equals(result)) {
throw new SQLException("Unexpected output, got:\n" + result + "\nExpected:\n" + expected);
expected = StringUtils.replaceAll(expected, " ", "+");
result = StringUtils.replaceAll(result, " ", "+");
throw new SQLException("Unexpected output for:\n" + sql.trim() + "\nGot:\n" + result + "\nExpected:\n" + expected);
}
}
......
......@@ -146,7 +146,7 @@ public class Script extends Tool {
org.h2.Driver.load();
conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement();
fileWriter = FileUtils.openFileWriter(fileName, false);
fileWriter = IOUtils.getWriter(FileUtils.openFileOutputStream(fileName, false));
PrintWriter writer = new PrintWriter(fileWriter);
ResultSet rs = stat.executeQuery("SCRIPT");
while (rs.next()) {
......
......@@ -27,6 +27,7 @@ import org.h2.util.ClassUtils;
import org.h2.util.FileUtils;
import org.h2.util.JdbcDriverUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.SortedProperties;
/**
* Interactive command line tool to access a database using JDBC.
......@@ -273,7 +274,7 @@ public class Shell {
String user = "sa";
String driver = null;
try {
Properties prop = FileUtils.loadProperties(propertiesFileName);
Properties prop = SortedProperties.loadProperties(propertiesFileName);
String data = null;
boolean found = false;
for (int i = 0;; i++) {
......
......@@ -22,14 +22,33 @@ public class ByteUtils {
// utility class
}
public static int readInt(byte[] buff, int pos) {
private static int readInt(byte[] buff, int pos) {
return (buff[pos++] << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos] & 0xff);
}
/**
* Read a long value from the byte array at the given position. The most
* significant byte is read first.
*
* @param buff the byte array
* @param pos the position
* @return the value
*/
public static long readLong(byte[] buff, int pos) {
return ((long) (readInt(buff, pos)) << 32) + (readInt(buff, pos + 4) & 0xffffffffL);
}
/**
* Calculate the index of the first occurrence of the pattern in the byte
* array, starting with the given index. This methods returns -1 if the
* pattern has not been found, and the start position if the pattern is
* empty.
*
* @param bytes the byte array
* @param pattern the pattern
* @param start the start index from where to search
* @return the index
*/
public static int indexOf(byte[] bytes, byte[] pattern, int start) {
if (pattern.length == 0) {
return start;
......@@ -49,6 +68,12 @@ public class ByteUtils {
return -1;
}
/**
* Convert a hex encoded string to a byte array.
*
* @param s the hex encoded string
* @return the byte array
*/
public static byte[] convertStringToBytes(String s) throws SQLException {
int len = s.length();
if (len % 2 != 0) {
......@@ -75,6 +100,12 @@ public class ByteUtils {
}
}
/**
* Calculate the hash code of the given byte array.
*
* @param value the byte array
* @return the hash code
*/
public static int getByteArrayHash(byte[] value) {
int h = 1;
for (int i = 0; i < value.length;) {
......@@ -83,10 +114,23 @@ public class ByteUtils {
return h;
}
/**
* Convert a byte array to a hex encoded string.
*
* @param value the byte array
* @return the hex encoded string
*/
public static String convertBytesToString(byte[] value) {
return convertBytesToString(value, value.length);
}
/**
* Convert a byte array to a hex encoded string.
*
* @param value the byte array
* @param len the number of bytes to encode
* @return the hex encoded string
*/
public static String convertBytesToString(byte[] value, int len) {
char[] buff = new char[len + len];
char[] hex = HEX;
......@@ -98,6 +142,15 @@ public class ByteUtils {
return new String(buff);
}
/**
* Compare two byte arrays. This method will always loop over all bytes and
* doesn't use conditional operations in the loop to make sure an attacker
* can not use a timing attack when trying out passwords.
*
* @param test the first array
* @param good the second array
* @return true if both byte arrays contain the same bytes
*/
public static boolean compareSecure(byte[] test, byte[] good) {
if ((test == null) || (good == null)) {
return (test == null) && (good == null);
......@@ -108,24 +161,36 @@ public class ByteUtils {
if (test.length == 0) {
return true;
}
// silly loop: this should help a little against timing attacks
boolean correct = true, correct2 = false;
// don't use conditional operations inside the loop
int bits = 0;
for (int i = 0; i < good.length; i++) {
if (test[i] != good[i]) {
correct = false;
} else {
correct2 = true;
}
// this will never reset any bits
bits |= test[i] ^ good[i];
}
return correct && correct2;
return bits == 0;
}
/**
* Set all elements of the array to zero.
*
* @param buff the byte array
*/
public static void clear(byte[] buff) {
for (int i = 0; i < buff.length; i++) {
buff[i] = 0;
}
}
/**
* Compare the contents of two byte arrays. If the content or length of the
* first array is smaller than the second array, -1 is returned. If the
* content or length of the second array is smaller than the first array, 1
* is returned. If the contents and lengths are the same, 0 is returned.
*
* @param data1 the first byte array (must not be null)
* @param data2 the second byte array (must not be null)
* @return the result of the comparison (-1, 1 or 0)
*/
public static int compareNotNull(byte[] data1, byte[] data2) {
int len = Math.min(data1.length, data2.length);
for (int i = 0; i < len; i++) {
......@@ -139,22 +204,14 @@ public class ByteUtils {
return c == 0 ? 0 : (c < 0 ? -1 : 1);
}
public static String convertToBinString(byte[] buff) {
char[] chars = new char[buff.length];
for (int i = 0; i < buff.length; i++) {
chars[i] = (char) (buff[i] & 0xff);
}
return new String(chars);
}
public static byte[] convertBinStringToBytes(String data) {
byte[] buff = new byte[data.length()];
for (int i = 0; i < data.length(); i++) {
buff[i] = (byte) (data.charAt(i) & 0xff);
}
return buff;
}
/**
* Copy the contents of the source array to the target array. If the size if
* the target array is too small, a larger array is created.
*
* @param source the source array
* @param target the target array
* @return the target array or a new one if the target array was too small
*/
public static byte[] copy(byte[] source, byte[] target) {
int len = source.length;
if (len > target.length) {
......@@ -164,6 +221,13 @@ public class ByteUtils {
return target;
}
/**
* Create a new byte array and copy all the data. If the size of the byte
* array is zero, the same array is returned.
*
* @param b the byte array (may not be null)
* @return a new byte array
*/
public static byte[] cloneByteArray(byte[] b) {
int len = b.length;
if (len == 0) {
......
......@@ -35,6 +35,11 @@ public abstract class CacheObject {
*/
public abstract boolean canRemove();
/**
* Order the given list of cache objects by position.
*
* @param recordList the list of cache objects
*/
public static void sort(ObjectArray recordList) {
recordList.sort(new Comparator() {
public int compare(Object a, Object b) {
......@@ -64,6 +69,12 @@ public abstract class CacheObject {
return pos;
}
/**
* Check if this cache object has been changed and thus needs to be written
* back to the storage.
*
* @return if it has been changed
*/
public boolean isChanged() {
return changed;
}
......@@ -72,6 +83,11 @@ public abstract class CacheObject {
changed = b;
}
/**
* Check if this cache object can be removed from the cache.
*
* @return if it can be removed
*/
public boolean isPinned() {
return false;
}
......
......@@ -48,10 +48,24 @@ public class ClassUtils {
// utility class
}
/**
* Load a class without performing access rights checking.
*
* @param className the name of the class
* @return the class object
*/
public static Class loadSystemClass(String className) throws ClassNotFoundException {
return Class.forName(className);
}
/**
* Load a class, but check if it is allowed to load this class first. To
* perform access rights checking, the system property h2.allowedClasses
* needs to be set to a list of class file name prefixes.
*
* @param className the name of the class
* @return the class object
*/
public static Class loadUserClass(String className) throws SQLException {
if (!ALLOW_ALL && !ALLOWED_CLASS_NAMES.contains(className)) {
boolean allowed = false;
......
......@@ -31,6 +31,13 @@ public class DateTimeUtils {
// utility class
}
/**
* Convert the timestamp to the specified time zone.
*
* @param x the timestamp
* @param calendar the calendar
* @return the timestamp using the correct time zone
*/
public static Timestamp convertTimestampToCalendar(Timestamp x, Calendar calendar) throws SQLException {
if (x != null) {
Timestamp y = new Timestamp(getLocalTime(x, calendar));
......@@ -41,6 +48,12 @@ public class DateTimeUtils {
return x;
}
/**
* Clone a time object and reset the day to 1970-01-01.
*
* @param value the time value
* @return the time value without the date component
*/
public static Time cloneAndNormalizeTime(Time value) {
Calendar cal = CALENDAR;
long time;
......@@ -52,6 +65,13 @@ public class DateTimeUtils {
return new Time(time);
}
/**
* Clone a date object and reset the hour, minutes, seconds, and
* milliseconds to zero.
*
* @param value the date value
* @return the date value at midnight
*/
public static Date cloneAndNormalizeDate(Date value) {
Calendar cal = CALENDAR;
long time;
......@@ -66,14 +86,35 @@ public class DateTimeUtils {
return new Date(time);
}
/**
* Convert the date from the specified time zone to UTC.
*
* @param x the date
* @param source the calendar
* @return the date in UTC
*/
public static Value convertDateToUniversal(Date x, Calendar source) throws SQLException {
return ValueDate.get(new Date(getUniversalTime(source, x)));
}
/**
* Convert the time from the specified time zone to UTC.
*
* @param x the time
* @param source the calendar
* @return the time in UTC
*/
public static Value convertTimeToUniversal(Time x, Calendar source) throws SQLException {
return ValueTime.get(new Time(getUniversalTime(source, x)));
}
/**
* Convert the timestamp from the specified time zone to UTC.
*
* @param x the time
* @param source the calendar
* @return the timestamp in UTC
*/
public static Value convertTimestampToUniversal(Timestamp x, Calendar source) throws SQLException {
Timestamp y = new Timestamp(getUniversalTime(source, x));
// fix the nano seconds
......@@ -113,14 +154,38 @@ public class DateTimeUtils {
to.set(Calendar.MILLISECOND, from.get(Calendar.MILLISECOND));
}
/**
* Convert the date to the specified time zone.
*
* @param x the date
* @param calendar the calendar
* @return the date using the correct time zone
*/
public static Date convertDateToCalendar(Date x, Calendar calendar) throws SQLException {
return x == null ? null : new Date(getLocalTime(x, calendar));
}
/**
* Convert the time to the specified time zone.
*
* @param x the time
* @param calendar the calendar
* @return the time using the correct time zone
*/
public static Time convertTimeToCalendar(Time x, Calendar calendar) throws SQLException {
return x == null ? null : new Time(getLocalTime(x, calendar));
}
/**
* Parse a date, time or timestamp value. This method supports the format
* +/-year-month-day hour:minute:seconds.fractional and an optional timezone
* part.
*
* @param original the original string
* @param type the value type (Value.TIME, TIMESTAMP, or DATE)
* @param errorCode the error code to use if an error occurs
* @return the date object
*/
public static java.util.Date parseDateTime(String original, int type, int errorCode) throws SQLException {
String s = original;
if (s == null) {
......@@ -251,6 +316,14 @@ public class DateTimeUtils {
return c.getTime().getTime();
}
/**
* Get the specified field of a date, however with years normalized to
* positive or negative, and month starting with 1.
*
* @param d the date
* @param field the field type
* @return the value
*/
public static int getDatePart(java.util.Date d, int field) {
Calendar c = Calendar.getInstance();
c.setTime(d);
......
......@@ -6,21 +6,14 @@
*/
package org.h2.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.SQLException;
import java.util.Properties;
import org.h2.constant.SysProperties;
import org.h2.message.Message;
import org.h2.message.TraceSystem;
import org.h2.store.fs.FileSystem;
/**
......@@ -32,6 +25,12 @@ public class FileUtils {
// utility class
}
/**
* Change the length of the file.
*
* @param file the random access file
* @param newLength the new length
*/
public static void setLength(RandomAccessFile file, long newLength) throws IOException {
try {
trace("setLength", null, file);
......@@ -56,39 +55,12 @@ public class FileUtils {
}
}
public static synchronized Properties loadProperties(String fileName) throws IOException {
Properties prop = new SortedProperties();
if (exists(fileName)) {
InputStream in = openFileInputStream(fileName);
try {
prop.load(in);
} finally {
in.close();
}
}
return prop;
}
public static boolean getBooleanProperty(Properties prop, String key, boolean def) {
String value = prop.getProperty(key, ""+def);
try {
return Boolean.valueOf(value).booleanValue();
} catch (Exception e) {
TraceSystem.traceThrowable(e);
return def;
}
}
public static int getIntProperty(Properties prop, String key, int def) {
String value = prop.getProperty(key, ""+def);
try {
return MathUtils.decodeInt(value);
} catch (Exception e) {
TraceSystem.traceThrowable(e);
return def;
}
}
/**
* Get the absolute file path of a file in the user home directory.
*
* @param fileName
* @return the absolute path
*/
public static String getFileInUserHome(String fileName) {
String userDir = SysProperties.USER_HOME;
if (userDir == null) {
......@@ -98,32 +70,68 @@ public class FileUtils {
return file.getAbsolutePath();
}
public static void trace(String method, String fileName, Object o) {
static void trace(String method, String fileName, Object o) {
if (SysProperties.TRACE_IO) {
System.out.println("FileUtils." + method + " " + fileName + " " + o);
}
}
/**
* Get the file name (without directory part).
*
* @param name the directory and file name
* @return just the file name
*/
public static String getFileName(String name) throws SQLException {
return FileSystem.getInstance(name).getFileName(name);
}
/**
* Normalize a file name.
*
* @param fileName the file name
* @return the normalized file name
*/
public static String normalize(String fileName) throws SQLException {
return FileSystem.getInstance(fileName).normalize(fileName);
}
/**
* Try to delete a file.
*
* @param fileName the file name
* @return true if it could be deleted
*/
public static void tryDelete(String fileName) {
FileSystem.getInstance(fileName).tryDelete(fileName);
}
/**
* Check if a file is read-only.
*
* @param fileName the file name
* @return if it is read only
*/
public static boolean isReadOnly(String fileName) {
return FileSystem.getInstance(fileName).isReadOnly(fileName);
}
/**
* Checks if a file exists.
*
* @param fileName the file name
* @return true if it exists
*/
public static boolean exists(String fileName) {
return FileSystem.getInstance(fileName).exists(fileName);
}
/**
* Get the length of a file.
*
* @param fileName the file name
* @return the length in bytes
*/
public static long length(String fileName) {
return FileSystem.getInstance(fileName).length(fileName);
}
......@@ -144,59 +152,124 @@ public class FileUtils {
return FileSystem.getInstance(prefix).createTempFile(prefix, suffix, deleteOnExit, inTempDir);
}
/**
* Get the parent directory of a file or directory.
*
* @param fileName the file or directory name
* @return the parent directory name
*/
public static String getParent(String fileName) {
return FileSystem.getInstance(fileName).getParent(fileName);
}
/**
* List the files in the given directory.
*
* @param path the directory
* @return the list of fully qualified file names
*/
public static String[] listFiles(String path) throws SQLException {
return FileSystem.getInstance(path).listFiles(path);
}
/**
* Check if it is a file or a directory.
*
* @param fileName the file or directory name
* @return true if it is a directory
*/
public static boolean isDirectory(String fileName) {
return FileSystem.getInstance(fileName).isDirectory(fileName);
}
/**
* Check if the file name includes a path.
*
* @param fileName the file name
* @return if the file name is absolute
*/
public static boolean isAbsolute(String fileName) {
return FileSystem.getInstance(fileName).isAbsolute(fileName);
}
/**
* Get the absolute file name.
*
* @param fileName the file name
* @return the absolute file name
*/
public static String getAbsolutePath(String fileName) {
return FileSystem.getInstance(fileName).getAbsolutePath(fileName);
}
public static Writer openFileWriter(String fileName, boolean append) throws SQLException {
OutputStream out = FileSystem.getInstance(fileName).openFileOutputStream(fileName, append);
try {
return new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw Message.convert(e);
}
}
/**
* Check if a file starts with a given prefix.
*
* @param fileName the complete file name
* @param prefix the prefix
* @return true if it starts with the prefix
*/
public static boolean fileStartsWith(String fileName, String prefix) {
return FileSystem.getInstance(fileName).fileStartsWith(fileName, prefix);
}
/**
* Create an input stream to read from the file.
*
* @param fileName the file name
* @return the input stream
*/
public static InputStream openFileInputStream(String fileName) throws IOException {
return FileSystem.getInstance(fileName).openFileInputStream(fileName);
}
/**
* Create an output stream to write into the file.
*
* @param fileName the file name
* @param append if true, the file will grow, if false, the file will be
* truncated first
* @return the output stream
*/
public static OutputStream openFileOutputStream(String fileName, boolean append) throws SQLException {
return FileSystem.getInstance(fileName).openFileOutputStream(fileName, append);
}
/**
* Rename a file if this is allowed.
*
* @param oldName the old fully qualified file name
* @param newName the new fully qualified file name
* @throws SQLException
*/
public static void rename(String oldName, String newName) throws SQLException {
FileSystem.getInstance(oldName).rename(oldName, newName);
}
/**
* Create all required directories that are required for this file.
*
* @param fileName the file name (not directory name)
*/
public static void createDirs(String fileName) throws SQLException {
FileSystem.getInstance(fileName).createDirs(fileName);
}
/**
* Delete a file.
*
* @param fileName the file name
*/
public static void delete(String fileName) throws SQLException {
FileSystem.getInstance(fileName).delete(fileName);
}
/**
* Get the last modified date of a file
*
* @param fileName the file name
* @return the last modified date
*/
public static long getLastModified(String fileName) {
return FileSystem.getInstance(fileName).getLastModified(fileName);
}
......
......@@ -7,6 +7,7 @@
package org.h2.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
......@@ -14,6 +15,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
......@@ -351,6 +353,21 @@ public class IOUtils {
throw Message.convert(e);
}
}
/**
* Create a writer to write to an output stream using the UTF-8 format. If
* the output stream is null, this method returns null.
*
* @param out the output stream or null
* @return the writer
*/
public static Writer getWriter(OutputStream out) throws SQLException {
try {
return out == null ? null : new BufferedWriter(new OutputStreamWriter(out, Constants.UTF8));
} catch (UnsupportedEncodingException e) {
throw Message.convert(e);
}
}
/**
* Create an input stream to read from a string. The string is converted to
......
......@@ -6,11 +6,15 @@
*/
package org.h2.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import org.h2.message.TraceSystem;
/**
* Sorted properties file.
* This implementation requires that store() internally calls keys().
......@@ -24,5 +28,60 @@ public class SortedProperties extends Properties {
Collections.sort(v);
return v.elements();
}
/**
* Get a boolean property value from a properties object.
*
* @param prop the properties object
* @param key the key
* @param def the default value
* @return the value if set, or the default value if not
*/
public static boolean getBooleanProperty(Properties prop, String key, boolean def) {
String value = prop.getProperty(key, ""+def);
try {
return Boolean.valueOf(value).booleanValue();
} catch (Exception e) {
TraceSystem.traceThrowable(e);
return def;
}
}
/**
* Get an int property value from a properties object.
*
* @param prop the properties object
* @param key the key
* @param def the default value
* @return the value if set, or the default value if not
*/
public static int getIntProperty(Properties prop, String key, int def) {
String value = prop.getProperty(key, ""+def);
try {
return MathUtils.decodeInt(value);
} catch (Exception e) {
TraceSystem.traceThrowable(e);
return def;
}
}
/**
* Load a properties object from a file.
*
* @param fileName the name of the properties file
* @return the properties object
*/
public static synchronized SortedProperties loadProperties(String fileName) throws IOException {
SortedProperties prop = new SortedProperties();
if (FileUtils.exists(fileName)) {
InputStream in = FileUtils.openFileInputStream(fileName);
try {
prop.load(in);
} finally {
in.close();
}
}
return prop;
}
}
......@@ -190,4 +190,4 @@ EXPLAIN SELECT VALUE FROM TEST ORDER BY VALUE DESC LIMIT 10;
--> LIMIT 10
;
DROP TABLE TEST;
\ No newline at end of file
DROP TABLE TEST;
......@@ -169,10 +169,27 @@ java org.h2.test.TestAll timer
/*
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)
measure and improve performance of ObjectArray.toArray()
test & document optimizations.sql
convert test.in.sql to RunScript syntax
C:\download\Data Concurrency and Consistency.pdf
......
......@@ -321,10 +321,10 @@ public abstract class TestBase {
int al = expected.length();
int bl = actual.length();
if (al > 100) {
expected = expected.substring(0, 100);
expected = expected.substring(0, 400);
}
if (bl > 100) {
actual = actual.substring(0, 100);
actual = actual.substring(0, 400);
}
fail("Expected: " + expected + " (" + al + ") actual: " + actual + " (" + bl + ")");
}
......
......@@ -8,6 +8,7 @@ package org.h2.test.unit;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.h2.test.TestBase;
......@@ -20,6 +21,11 @@ import org.h2.util.StringUtils;
public class TestSampleApps extends TestBase {
public void test() throws Exception {
deleteDb("optimizations");
String url = "jdbc:h2:" + baseDir + "/optimizations";
testApp(org.h2.tools.RunScript.class, new String[] { "-url", url, "-user", "sa", "-password", "sa", "-script",
"src/test/org/h2/samples/optimizations.sql", "-checkResults" }, "");
testApp(org.h2.samples.Compact.class, null, "Compacting...\nDone.");
testApp(org.h2.samples.CsvSample.class, null, "NAME: Bob Meier\n" + "EMAIL: bob.meier@abcde.abc\n"
+ "PHONE: +41123456789\n\n" + "NAME: John Jones\n" + "EMAIL: john.jones@abcde.abc\n"
......@@ -51,6 +57,8 @@ public class TestSampleApps extends TestBase {
System.setErr(out);
try {
m.invoke(null, new Object[] { args });
} catch (InvocationTargetException e) {
TestBase.logError("error", e.getTargetException());
} catch (Throwable e) {
TestBase.logError("error", e);
}
......
......@@ -519,4 +519,4 @@ indicate timezone unmounting beep ignoring gary tong extending respective
overloaded decide clash involve verification dining recursively originating
philosophers technologies modeling federation enterprise semantic deductive
fusion legacy decoded commented trimmed reaches indicating marks scaled tells
monitor
\ No newline at end of file
monitor benefit performing conditional significant
\ No newline at end of file
......@@ -30,7 +30,6 @@ import java.util.Map.Entry;
import org.h2.build.doc.XMLParser;
import org.h2.server.web.PageParser;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.SortedProperties;
import org.h2.util.StringUtils;
......@@ -94,12 +93,12 @@ public class PrepareTranslation {
new File(targetDir).mkdirs();
// load the main 'translation'
String propName = templateDir + "/_docs_" + MAIN_LANGUAGE + ".properties";
Properties prop = FileUtils.loadProperties(propName);
Properties prop = SortedProperties.loadProperties(propName);
propName = templateDir + "/_docs_" + language + ".properties";
if (!(new File(propName)).exists()) {
throw new IOException("Translation not found: " + propName);
}
Properties transProp = FileUtils.loadProperties(propName);
Properties transProp = SortedProperties.loadProperties(propName);
for (Iterator it = transProp.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
String t = transProp.getProperty(key);
......@@ -363,7 +362,7 @@ public class PrepareTranslation {
}
new File(target).mkdirs();
String propFileName = target + "/_docs_" + MAIN_LANGUAGE + ".properties";
Properties old = FileUtils.loadProperties(propFileName);
Properties old = SortedProperties.loadProperties(propFileName);
prop.putAll(old);
PropertiesToUTF8.storeProperties(prop, propFileName);
String t = template.toString();
......@@ -416,8 +415,8 @@ public class PrepareTranslation {
}
}
}
Properties p = FileUtils.loadProperties(main.getAbsolutePath());
Properties base = FileUtils.loadProperties(baseDir + "/" + main.getName());
Properties p = SortedProperties.loadProperties(main.getAbsolutePath());
Properties base = SortedProperties.loadProperties(baseDir + "/" + main.getName());
PropertiesToUTF8.storeProperties(p, main.getAbsolutePath());
for (int i = 0; i < translations.size(); i++) {
File trans = (File) translations.get(i);
......@@ -429,7 +428,7 @@ public class PrepareTranslation {
}
private void prepare(Properties main, Properties base, File trans, String language) throws IOException {
Properties p = FileUtils.loadProperties(trans.getAbsolutePath());
Properties p = SortedProperties.loadProperties(trans.getAbsolutePath());
Properties oldTranslations = new Properties();
for (Iterator it = base.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
......
......@@ -24,7 +24,6 @@ import java.util.Properties;
import org.h2.build.code.CheckTextFiles;
import org.h2.build.indexer.HtmlConverter;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.SortedProperties;
import org.h2.util.StringUtils;
......@@ -48,7 +47,7 @@ public class PropertiesToUTF8 {
if (!new File(source).exists()) {
return;
}
Properties prop = FileUtils.loadProperties(source);
Properties prop = SortedProperties.loadProperties(source);
FileOutputStream out = new FileOutputStream(target);
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
// keys is sorted
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论