提交 b2e546f3 authored 作者: Owner's avatar Owner

Merge from master, plus minor refactoring

...@@ -21,6 +21,12 @@ Change Log ...@@ -21,6 +21,12 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Fix removal of LOB when rolling back transaction on a table containing more than one LOB column.
</li>
<li>Issue #654: List ENUM type values in INFORMATION_SCHEMA.COLUMNS
</li>
<li>Issue #650: Simple nested SELECT causes error for table with TIMESTAMP WITH TIMEZONE column
</li>
<li>Issue #654: List ENUM type values in INFORMATION_SCHEMA.COLUMNS <li>Issue #654: List ENUM type values in INFORMATION_SCHEMA.COLUMNS
</li> </li>
<li>Issue #668: Fail of an update command on large table with ENUM column <li>Issue #668: Fail of an update command on large table with ENUM column
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
08000=Error opening database: {0} 08000=Error opening database: {0}
21S02=Column count does not match 21S02=Column count does not match
22001=Value too long for column {0}: {1} 22001=Value too long for column {0}: {1}
22003=Numeric value out of range: {0} {1} 22003=Numeric value out of range: {0}
22004=Numeric value out of range: {0} in column {1}
22007=Cannot parse {0} constant {1} 22007=Cannot parse {0} constant {1}
22012=Division by zero: {0} 22012=Division by zero: {0}
22018=Data conversion error converting {0} 22018=Data conversion error converting {0}
......
...@@ -162,6 +162,7 @@ import org.h2.value.ValueNull; ...@@ -162,6 +162,7 @@ import org.h2.value.ValueNull;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
/** /**
* The parser is used to convert a SQL statement string to an command object. * The parser is used to convert a SQL statement string to an command object.
...@@ -3120,6 +3121,17 @@ public class Parser { ...@@ -3120,6 +3121,17 @@ public class Parser {
read("FOR"); read("FOR");
Sequence sequence = readSequence(); Sequence sequence = readSequence();
r = new SequenceValue(sequence); r = new SequenceValue(sequence);
} else if (equalsToken("TIMESTAMP", name) && readIf("WITH")) {
read("TIME");
read("ZONE");
if (currentTokenType != VALUE
|| currentValue.getType() != Value.STRING) {
throw getSyntaxError();
}
String timestamp = currentValue.getString();
read();
r = ValueExpression
.get(ValueTimestampTimeZone.parse(timestamp));
} else if (currentTokenType == VALUE && } else if (currentTokenType == VALUE &&
currentValue.getType() == Value.STRING) { currentValue.getType() == Value.STRING) {
if (equalsToken("DATE", name) || if (equalsToken("DATE", name) ||
......
...@@ -333,25 +333,19 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -333,25 +333,19 @@ public class AlterTableAddConstraint extends SchemaCommand {
// all cols must be in the index key, the order doesn't matter and there // all cols must be in the index key, the order doesn't matter and there
// must be no other fields in the index key // must be no other fields in the index key
private static boolean canUseUniqueIndex(Index idx, Table table, private static boolean canUseUniqueIndex(Index idx, Table table, IndexColumn[] cols) {
IndexColumn[] cols) {
if (idx.getTable() != table || !idx.getIndexType().isUnique()) { if (idx.getTable() != table || !idx.getIndexType().isUnique()) {
return false; return false;
} }
Column[] indexCols = idx.getColumns(); Column[] indexCols = idx.getColumns();
HashSet<Column> indexColsSet = New.hashSet(); HashSet<Column> indexColsSet = New.hashSet();
for (Column c : indexCols) { for (Column c : indexCols) {
indexColsSet.add(c); indexColsSet.add(c);
} }
HashSet<Column> colsSet = New.hashSet(); HashSet<Column> colsSet = New.hashSet();
for (IndexColumn c : cols) { for (IndexColumn c : cols) {
colsSet.add(c.column); colsSet.add(c.column);
} }
return colsSet.equals(indexColsSet); return colsSet.equals(indexColsSet);
} }
......
...@@ -535,13 +535,11 @@ public class Set extends Prepared { ...@@ -535,13 +535,11 @@ public class Set extends Prepared {
database.setAllowBuiltinAliasOverride(value == 1); database.setAllowBuiltinAliasOverride(value == 1);
break; break;
} }
case SetTypes.COLUMN_NAME_RULES: { case SetTypes.COLUMN_NAME_RULES: {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
session.getColumnNamerConfiguration().configure(expression.getColumnName()); session.getColumnNamerConfiguration().configure(expression.getColumnName());
break; break;
} }
default: default:
DbException.throwInternalError("type="+type); DbException.throwInternalError("type="+type);
} }
......
...@@ -1330,8 +1330,8 @@ public class Session extends SessionWithState { ...@@ -1330,8 +1330,8 @@ public class Session extends SessionWithState {
} }
if (removeLobMap == null) { if (removeLobMap == null) {
removeLobMap = New.hashMap(); removeLobMap = New.hashMap();
removeLobMap.put(v.toString(), v);
} }
removeLobMap.put(v.toString(), v);
} }
/** /**
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=Počet sloupců nesouhlasí 21S02=Počet sloupců nesouhlasí
22001=Příliš dlouhá hodnota pro sloupec {0}: {1} 22001=Příliš dlouhá hodnota pro sloupec {0}: {1}
22003=Číselná hodnota je mimo rozsah: {0} 22003=Číselná hodnota je mimo rozsah: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#Číselná hodnota je mimo rozsah: {0} in column {1}
22007=Nelze zpracovat konstantu {0} {1} 22007=Nelze zpracovat konstantu {0} {1}
22012=Dělení nulou: {0} 22012=Dělení nulou: {0}
22018=Chyba při převodu dat {0} 22018=Chyba při převodu dat {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=Vrácený výsledek je pouze pro čtení. Možná budete muset použít conn.createStatement(..., ResultSet.CONCUR_UPDATABLE). 90140=Vrácený výsledek je pouze pro čtení. Možná budete muset použít conn.createStatement(..., ResultSet.CONCUR_UPDATABLE).
90141=#Serializer cannot be changed because there is a data table: {0} 90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero 90142=#Step size must not be zero
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=Obecná chyba: {0} HY000=Obecná chyba: {0}
HY004=Neznámý datový typ: {0} HY004=Neznámý datový typ: {0}
HYC00=Vlastnost není podporována: {0} HYC00=Vlastnost není podporována: {0}
......
...@@ -4,16 +4,16 @@ ...@@ -4,16 +4,16 @@
08000=Fehler beim Öffnen der Datenbank: {0} 08000=Fehler beim Öffnen der Datenbank: {0}
21S02=Anzahl der Felder stimmt nicht überein 21S02=Anzahl der Felder stimmt nicht überein
22001=Wert zu gross / lang für Feld {0}: {1} 22001=Wert zu gross / lang für Feld {0}: {1}
22003=Zahlenwert ausserhalb des Bereichs: {0} 22003=Numerischer Wert ausserhalb des Bereichs: {0}
22004=Numeric value out of range: {0} in column {1} 22004=Numerischer Wert ausserhalb des Bereichs: {0} in Feld {1}
22007=Kann {0} {1} nicht umwandeln 22007=Kann {0} {1} nicht umwandeln
22012=Division durch 0: {0} 22012=Division durch 0: {0}
22018=Datenumwandlungsfehler beim Umwandeln von {0} 22018=Datenumwandlungsfehler beim Umwandeln von {0}
22025=Fehler in LIKE ESCAPE: {0} 22025=Fehler in LIKE ESCAPE: {0}
22030=#Value not permitted for column {0}: {1} 22030=Wert nicht erlaubt für Feld {0}: {1}
22031=#Value not a member of enumerators {0}: {1} 22031=Wert nicht Teil der Aufzählung {0}: {1}
22032=#Empty enums are not allowed 22032=Leere Aufzählungen sind nicht erlaubt
22033=#Duplicate enumerators are not allowed for enum types: {0} 22033=Doppelte Nennungen sind nicht erlaubt für Aufzählungstypen: {0}
23502=NULL nicht zulässig für Feld {0} 23502=NULL nicht zulässig für Feld {0}
23503=Referentielle Integrität verletzt: {0} 23503=Referentielle Integrität verletzt: {0}
23505=Eindeutiger Index oder Primärschlüssel verletzt: {0} 23505=Eindeutiger Index oder Primärschlüssel verletzt: {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=Die Resultat-Zeilen können nicht verändert werden. Mögliche Lösung: conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=Die Resultat-Zeilen können nicht verändert werden. Mögliche Lösung: conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serialisierer kann nicht geändert werden wenn eine Daten-Tabelle existiert: {0} 90141=Serialisierer kann nicht geändert werden wenn eine Daten-Tabelle existiert: {0}
90142=Schrittgrösse darf nicht 0 sein 90142=Schrittgrösse darf nicht 0 sein
90143=##Row {1} not found in primary index {0} 90143=Zeile {1} nicht gefunden im Primär-Index {0}
HY000=Allgemeiner Fehler: {0} HY000=Allgemeiner Fehler: {0}
HY004=Unbekannter Datentyp: {0} HY004=Unbekannter Datentyp: {0}
HYC00=Dieses Feature wird nicht unterstützt: {0} HYC00=Dieses Feature wird nicht unterstützt: {0}
......
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serializer cannot be changed because there is a data table: {0} 90141=Serializer cannot be changed because there is a data table: {0}
90142=Step size must not be zero 90142=Step size must not be zero
90143=#Row {1} not found in primary index {0} 90143=Row {1} not found in primary index {0}
HY000=General error: {0} HY000=General error: {0}
HY004=Unknown data type: {0} HY004=Unknown data type: {0}
HYC00=Feature not supported: {0} HYC00=Feature not supported: {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=La cantidad de columnas no coincide 21S02=La cantidad de columnas no coincide
22001=Valor demasiado largo para la columna {0}: {1} 22001=Valor demasiado largo para la columna {0}: {1}
22003=Valor numerico fuera de rango: {0} 22003=Valor numerico fuera de rango: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#Valor numerico fuera de rango: {0} in column {1}
22007=Imposible interpretar la constante {0} {1} 22007=Imposible interpretar la constante {0} {1}
22012=División por cero: {0} 22012=División por cero: {0}
22018=Conversión de datos fallida, convirtiendo {0} 22018=Conversión de datos fallida, convirtiendo {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=El conjunto de resultados es de solo lectura. Puede ser necesario usar conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=El conjunto de resultados es de solo lectura. Puede ser necesario usar conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=#Serializer cannot be changed because there is a data table: {0} 90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero 90142=#Step size must not be zero
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=Error General : {0} HY000=Error General : {0}
HY004=Tipo de dato desconocido : {0} HY004=Tipo de dato desconocido : {0}
HYC00=Caracteristica no soportada: {0} HYC00=Caracteristica no soportada: {0}
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
21S02=Le nombre de colonnes ne correspond pas 21S02=Le nombre de colonnes ne correspond pas
22001=Valeur trop longue pour la colonne {0}: {1} 22001=Valeur trop longue pour la colonne {0}: {1}
22003=Valeur numérique hors de portée: {0} 22003=Valeur numérique hors de portée: {0}
22004=#Valeur numérique hors de portée: {0} in column {1}
22007=Impossible d'analyser {0} constante {1} 22007=Impossible d'analyser {0} constante {1}
22012=Division par zéro: {0} 22012=Division par zéro: {0}
22018=Erreur lors de la conversion de données {0} 22018=Erreur lors de la conversion de données {0}
...@@ -100,7 +101,7 @@ ...@@ -100,7 +101,7 @@
90066=Propriété dupliquée {0} 90066=Propriété dupliquée {0}
90067=La connexion est cassée: {0} 90067=La connexion est cassée: {0}
90068=L'expression Order by {0} doit être dans ce cas dans la liste des résultats 90068=L'expression Order by {0} doit être dans ce cas dans la liste des résultats
90069Le rôle {0} existe déjà 90069=Le rôle {0} existe déjà
90070=Rôle {0} non trouvé 90070=Rôle {0} non trouvé
90071=Utilisateur ou rôle {0} non trouvé 90071=Utilisateur ou rôle {0} non trouvé
90072=Les rôles et les droits ne peuvent être mélangés 90072=Les rôles et les droits ne peuvent être mélangés
...@@ -171,7 +172,7 @@ ...@@ -171,7 +172,7 @@
90140='ensemble des résultats est en lecture seule. Vous pouvez avoir besoin d'utiliser conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140='ensemble des résultats est en lecture seule. Vous pouvez avoir besoin d'utiliser conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Le sérialiseur ne peut être changé parce que il y a des données dans la table: {0} 90141=Le sérialiseur ne peut être changé parce que il y a des données dans la table: {0}
90142=La taille de l'étape ne doit pas être de 0 90142=La taille de l'étape ne doit pas être de 0
90143=#Ligne {1} non trouvée dans l'index principal {0} 90143=Ligne {1} non trouvée dans l'index principal {0}
HY000=Erreur générale: {0} HY000=Erreur générale: {0}
HY004=Type de données inconnu: {0} HY004=Type de données inconnu: {0}
HYC00=Fonctionnalité non supportée: {0} HYC00=Fonctionnalité non supportée: {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=列番号が一致しません 21S02=列番号が一致しません
22001=列 {0} の値が長過ぎます: {1} 22001=列 {0} の値が長過ぎます: {1}
22003=範囲外の数値です: {0} 22003=範囲外の数値です: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#範囲外の数値です: {0} in column {1}
22007={0} 定数 {1} を解析できません 22007={0} 定数 {1} を解析できません
22012=ゼロで除算しました: {0} 22012=ゼロで除算しました: {0}
22018=データ変換中にエラーが発生しました {0} 22018=データ変換中にエラーが発生しました {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=リザルトセットは読み込み専用です。conn.createStatement(.., ResultSet.CONCUR_UPDATABLE) を使う必要があるかもしれません 90140=リザルトセットは読み込み専用です。conn.createStatement(.., ResultSet.CONCUR_UPDATABLE) を使う必要があるかもしれません
90141=データテーブル {0} があるため、シリアライザを変更することはできません 90141=データテーブル {0} があるため、シリアライザを変更することはできません
90142=ステップサイズに0は指定できません 90142=ステップサイズに0は指定できません
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=一般エラー: {0} HY000=一般エラー: {0}
HY004=不明なデータ型: {0} HY004=不明なデータ型: {0}
HYC00=機能はサポートされていません: {0} HYC00=機能はサポートされていません: {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=Niezgodna ilość kolumn 21S02=Niezgodna ilość kolumn
22001=Wartość za długa dla kolumny {0}: {1} 22001=Wartość za długa dla kolumny {0}: {1}
22003=Wartość numeryczna poza zakresem: {0} 22003=Wartość numeryczna poza zakresem: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#Wartość numeryczna poza zakresem: {0} in column {1}
22007=Nie można odczytać {0} jako {1} 22007=Nie można odczytać {0} jako {1}
22012=Dzielenie przez zero: {0} 22012=Dzielenie przez zero: {0}
22018=Błąd konwersji danych {0} 22018=Błąd konwersji danych {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=Wyniki są tylko do odczytu. Być może potrzebujesz użyć conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=Wyniki są tylko do odczytu. Być może potrzebujesz użyć conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serializator nie może być zmieniony ponieważ istnieje tabela z danymi: {0} 90141=Serializator nie może być zmieniony ponieważ istnieje tabela z danymi: {0}
90142=#Step size must not be zero 90142=#Step size must not be zero
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=Błąd ogólny: {0} HY000=Błąd ogólny: {0}
HY004=Nieznany typ danych: {0} HY004=Nieznany typ danych: {0}
HYC00=Cecha nie jest wspierana: {0} HYC00=Cecha nie jest wspierana: {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=A quantidade de colunas não corresponde 21S02=A quantidade de colunas não corresponde
22001=Valor muito longo para a coluna {0}: {1} 22001=Valor muito longo para a coluna {0}: {1}
22003=Valor númerico não esta dentro do limite: {0} 22003=Valor númerico não esta dentro do limite: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#Valor númerico não esta dentro do limite: {0} in column {1}
22007=Não é possível converter {1} para {0} 22007=Não é possível converter {1} para {0}
22012=Divisão por zero: {0} 22012=Divisão por zero: {0}
22018=Erro na conversão de dado, convertendo {0} 22018=Erro na conversão de dado, convertendo {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=Неверное количество столбцов 21S02=Неверное количество столбцов
22001=Значение слишком длинное для поля {0}: {1} 22001=Значение слишком длинное для поля {0}: {1}
22003=Численное значение вне допустимого диапазона: {0} 22003=Численное значение вне допустимого диапазона: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#Численное значение вне допустимого диапазона: {0} in column {1}
22007=Невозможно преобразование строки {1} в тип {0} 22007=Невозможно преобразование строки {1} в тип {0}
22012=Деление на ноль: {0} 22012=Деление на ноль: {0}
22018=Ошибка преобразования данных при конвертации {0} 22018=Ошибка преобразования данных при конвертации {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=Набор записей не является обновляемым. Возможно необходимо использовать conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=Набор записей не является обновляемым. Возможно необходимо использовать conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serializer не может быть изменен, потому что есть таблица данных: {0} 90141=Serializer не может быть изменен, потому что есть таблица данных: {0}
90142=Размер шага не должен быть равен нулю 90142=Размер шага не должен быть равен нулю
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=Внутренняя ошибка: {0} HY000=Внутренняя ошибка: {0}
HY004=Неизвестный тип данных: {0} HY004=Неизвестный тип данных: {0}
HYC00=Данная функция не поддерживается: {0} HYC00=Данная функция не поддерживается: {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=Počet stĺpcov sa nezhoduje 21S02=Počet stĺpcov sa nezhoduje
22001=Hodnota je príliš dlhá pre stĺpec {0}: {1} 22001=Hodnota je príliš dlhá pre stĺpec {0}: {1}
22003=Číselná hodnota mimo rozsah: {0} 22003=Číselná hodnota mimo rozsah: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#Číselná hodnota mimo rozsah: {0} in column {1}
22007=Nemožem rozobrať {0} konštantu {1} 22007=Nemožem rozobrať {0} konštantu {1}
22012=Delenie nulou: {0} 22012=Delenie nulou: {0}
22018=Chyba konverzie dát pre {0} 22018=Chyba konverzie dát pre {0}
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=Výsledok (result set) je iba na čítanie. Je potrebné použiť conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=Výsledok (result set) je iba na čítanie. Je potrebné použiť conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=#Serializer cannot be changed because there is a data table: {0} 90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero 90142=#Step size must not be zero
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=Všeobecná chyba: {0} HY000=Všeobecná chyba: {0}
HY004=Neznámy dátový typ: {0} HY004=Neznámy dátový typ: {0}
HYC00=Vlastnosť nie je podporovaná: {0} HYC00=Vlastnosť nie je podporovaná: {0}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
21S02=字段数目不匹配 21S02=字段数目不匹配
22001=字段 {0}数值太大: {1} 22001=字段 {0}数值太大: {1}
22003=数值超出范围: {0} 22003=数值超出范围: {0}
22004=Numeric value out of range: {0} in column {1} 22004=#数值超出范围: {0} in column {1}
22007=不能解析字段 {0} 的数值 :{1} 22007=不能解析字段 {0} 的数值 :{1}
22012=除数为零: {0} 22012=除数为零: {0}
22018=转换数据{0}期间出现转换错误 22018=转换数据{0}期间出现转换错误
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
90140=结果集是只读的. 你可以使用 conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=结果集是只读的. 你可以使用 conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=#Serializer cannot be changed because there is a data table: {0} 90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero 90142=#Step size must not be zero
90143=##Row {1} not found in primary index {0} 90143=#Row {1} not found in primary index {0}
HY000=常规错误: {0} HY000=常规错误: {0}
HY004=位置数据类型: {0} HY004=位置数据类型: {0}
HYC00=不支持的特性: {0} HYC00=不支持的特性: {0}
......
...@@ -103,16 +103,13 @@ public class CreateCluster extends Tool { ...@@ -103,16 +103,13 @@ public class CreateCluster extends Tool {
String user, String password, String serverList) throws SQLException { String user, String password, String serverList) throws SQLException {
org.h2.Driver.load(); org.h2.Driver.load();
try (Connection connSource = DriverManager.getConnection(
// use cluster='' so connecting is possible // use cluster='' so connecting is possible
// even if the cluster is enabled // even if the cluster is enabled
urlSource + ";CLUSTER=''", user, password); try (Connection connSource = DriverManager.getConnection(urlSource + ";CLUSTER=''", user, password);
Statement statSource = connSource.createStatement()) Statement statSource = connSource.createStatement()) {
{
// enable the exclusive mode and close other connections, // enable the exclusive mode and close other connections,
// so that data can't change while restoring the second database // so that data can't change while restoring the second database
statSource.execute("SET EXCLUSIVE 2"); statSource.execute("SET EXCLUSIVE 2");
try { try {
performTransfer(statSource, urlTarget, user, password, serverList); performTransfer(statSource, urlTarget, user, password, serverList);
} finally { } finally {
...@@ -122,14 +119,12 @@ public class CreateCluster extends Tool { ...@@ -122,14 +119,12 @@ public class CreateCluster extends Tool {
} }
} }
private static void performTransfer(Statement statSource, String urlTarget, private static void performTransfer(Statement statSource, String urlTarget, String user, String password,
String user, String password, String serverList) throws SQLException { String serverList) throws SQLException {
// Delete the target database first. // Delete the target database first.
try (Connection connTarget = DriverManager.getConnection( try (Connection connTarget = DriverManager.getConnection(urlTarget + ";CLUSTER=''", user, password);
urlTarget + ";CLUSTER=''", user, password); Statement statTarget = connTarget.createStatement()) {
Statement statTarget = connTarget.createStatement())
{
statTarget.execute("DROP ALL OBJECTS DELETE FILES"); statTarget.execute("DROP ALL OBJECTS DELETE FILES");
} }
...@@ -137,10 +132,8 @@ public class CreateCluster extends Tool { ...@@ -137,10 +132,8 @@ public class CreateCluster extends Tool {
Future<?> threadFuture = startWriter(pipeReader, statSource); Future<?> threadFuture = startWriter(pipeReader, statSource);
// Read data from pipe reader, restore on target. // Read data from pipe reader, restore on target.
try (Connection connTarget = DriverManager.getConnection( try (Connection connTarget = DriverManager.getConnection(urlTarget, user, password);
urlTarget, user, password); Statement statTarget = connTarget.createStatement()) {
Statement statTarget = connTarget.createStatement())
{
RunScript.execute(connTarget, pipeReader); RunScript.execute(connTarget, pipeReader);
// Check if the writer encountered any exception // Check if the writer encountered any exception
...@@ -170,17 +163,13 @@ public class CreateCluster extends Tool { ...@@ -170,17 +163,13 @@ public class CreateCluster extends Tool {
Future<?> threadFuture = thread.submit(new Runnable() { Future<?> threadFuture = thread.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
/* // If the creation of the piped writer fails, the reader will
* If the creation of the piped writer fails, the reader will // throw an IOException as soon as read() is called: IOException
* throw an IOException as soon as read() is called: // - if the pipe is broken, unconnected, closed, or an I/O error
* IOException - if the pipe is broken, unconnected, closed, // occurs. The reader's IOException will then trigger the
* or an I/O error occurs. // finally{} that releases exclusive mode on the source DB.
* The reader's IOException will then trigger the finally{} that
* releases exclusive mode on the source DB.
*/
try (final PipedWriter pipeWriter = new PipedWriter(pipeReader); try (final PipedWriter pipeWriter = new PipedWriter(pipeReader);
final ResultSet rs = statSource.executeQuery("SCRIPT")) final ResultSet rs = statSource.executeQuery("SCRIPT")) {
{
while (rs.next()) { while (rs.next()) {
pipeWriter.write(rs.getString(1) + "\n"); pipeWriter.write(rs.getString(1) + "\n");
} }
......
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
*/
package org.h2.util; package org.h2.util;
import java.util.HashSet; import java.util.HashSet;
...@@ -6,7 +10,9 @@ import java.util.regex.Matcher; ...@@ -6,7 +10,9 @@ import java.util.regex.Matcher;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
/**
* A factory for column names.
*/
public class ColumnNamer { public class ColumnNamer {
private static final String DEFAULT_COLUMN_NAME = "DEFAULT"; private static final String DEFAULT_COLUMN_NAME = "DEFAULT";
...@@ -17,14 +23,13 @@ public class ColumnNamer { ...@@ -17,14 +23,13 @@ public class ColumnNamer {
public ColumnNamer(Session session) { public ColumnNamer(Session session) {
this.session = session; this.session = session;
if(this.session!=null && this.session.getColumnNamerConfiguration()!=null){ if (this.session != null && this.session.getColumnNamerConfiguration() != null) {
// use original from session // use original from session
this.configuration = this.session.getColumnNamerConfiguration(); this.configuration = this.session.getColumnNamerConfiguration();
} } else {
else{
// detached namer, create new // detached namer, create new
this.configuration = ColumnNamerConfiguration.getDefault(); this.configuration = ColumnNamerConfiguration.getDefault();
if(session!=null){ if (session != null) {
session.setColumnNamerConfiguration(this.configuration); session.setColumnNamerConfiguration(this.configuration);
} }
} }
...@@ -36,7 +41,7 @@ public class ColumnNamer { ...@@ -36,7 +41,7 @@ public class ColumnNamer {
* @param indexOfColumn index of column in below array * @param indexOfColumn index of column in below array
*/ */
public String getColumnName(Expression expr, int indexOfColumn) { public String getColumnName(Expression expr, int indexOfColumn) {
return getColumnName(expr,indexOfColumn,(String) null); return getColumnName(expr, indexOfColumn, (String) null);
} }
/** /**
...@@ -64,18 +69,17 @@ public class ColumnNamer { ...@@ -64,18 +69,17 @@ public class ColumnNamer {
public String getColumnName(Expression columnExp, int indexOfColumn, String columnNameOverride) { public String getColumnName(Expression columnExp, int indexOfColumn, String columnNameOverride) {
// try a name from the column name override // try a name from the column name override
String columnName = null; String columnName = null;
if (columnNameOverride != null){ if (columnNameOverride != null) {
columnName = columnNameOverride; columnName = columnNameOverride;
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
} }
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = null; columnName = null;
} }
} }
// try a name from the column alias // try a name from the column alias
if (columnName==null && columnExp.getAlias()!=null && if (columnName == null && columnExp.getAlias() != null && !DEFAULT_COLUMN_NAME.equals(columnExp.getAlias())) {
!DEFAULT_COLUMN_NAME.equals(columnExp.getAlias())) {
columnName = columnExp.getAlias(); columnName = columnExp.getAlias();
if (!isAllowableColumnName(columnName)) { if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
...@@ -85,8 +89,8 @@ public class ColumnNamer { ...@@ -85,8 +89,8 @@ public class ColumnNamer {
} }
} }
// try a name derived from the column expression SQL // try a name derived from the column expression SQL
if (columnName == null && columnExp.getColumnName() != null && if (columnName == null && columnExp.getColumnName() != null
!DEFAULT_COLUMN_NAME.equals(columnExp.getColumnName())) { && !DEFAULT_COLUMN_NAME.equals(columnExp.getColumnName())) {
columnName = columnExp.getColumnName(); columnName = columnExp.getColumnName();
if (!isAllowableColumnName(columnName)) { if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
...@@ -96,8 +100,7 @@ public class ColumnNamer { ...@@ -96,8 +100,7 @@ public class ColumnNamer {
} }
} }
// try a name derived from the column expression plan SQL // try a name derived from the column expression plan SQL
if (columnName == null && columnExp.getSQL() != null && if (columnName == null && columnExp.getSQL() != null && !DEFAULT_COLUMN_NAME.equals(columnExp.getSQL())) {
!DEFAULT_COLUMN_NAME.equals(columnExp.getSQL())) {
columnName = columnExp.getSQL(); columnName = columnExp.getSQL();
if (!isAllowableColumnName(columnName)) { if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
...@@ -121,7 +124,7 @@ public class ColumnNamer { ...@@ -121,7 +124,7 @@ public class ColumnNamer {
String newColumnName = columnName; String newColumnName = columnName;
int loopCount = 2; int loopCount = 2;
while (existingColumnNames.contains(newColumnName)) { while (existingColumnNames.contains(newColumnName)) {
String loopCountString = "_"+loopCount; String loopCountString = "_" + loopCount;
newColumnName = columnName.substring(0, newColumnName = columnName.substring(0,
Math.min(columnName.length(), configuration.getMaxIdentiferLength() - loopCountString.length())) Math.min(columnName.length(), configuration.getMaxIdentiferLength() - loopCountString.length()))
+ loopCountString; + loopCountString;
...@@ -130,10 +133,10 @@ public class ColumnNamer { ...@@ -130,10 +133,10 @@ public class ColumnNamer {
return newColumnName; return newColumnName;
} }
public boolean isAllowableColumnName(String proposedName){ public boolean isAllowableColumnName(String proposedName) {
// check null // check null
if (proposedName == null){ if (proposedName == null) {
return false; return false;
} }
// check size limits // check size limits
...@@ -152,8 +155,8 @@ public class ColumnNamer { ...@@ -152,8 +155,8 @@ public class ColumnNamer {
proposedName = match.replaceAll(""); proposedName = match.replaceAll("");
// check size limits - then truncate // check size limits - then truncate
if (proposedName.length() > configuration.getMaxIdentiferLength()){ if (proposedName.length() > configuration.getMaxIdentiferLength()) {
proposedName=proposedName.substring(0, configuration.getMaxIdentiferLength()); proposedName = proposedName.substring(0, configuration.getMaxIdentiferLength());
} }
return proposedName; return proposedName;
......
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
*/
package org.h2.util; package org.h2.util;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -5,7 +9,11 @@ import org.h2.engine.Mode.ModeEnum; ...@@ -5,7 +9,11 @@ import org.h2.engine.Mode.ModeEnum;
import static org.h2.engine.Mode.ModeEnum.*; import static org.h2.engine.Mode.ModeEnum.*;
import org.h2.message.DbException; import org.h2.message.DbException;
/**
* The configuration for the allowed column names.
*/
public class ColumnNamerConfiguration { public class ColumnNamerConfiguration {
private static final String DEFAULT_COMMAND = "DEFAULT"; private static final String DEFAULT_COMMAND = "DEFAULT";
private static final String REGULAR_EXPRESSION_MATCH_DISALLOWED = "REGULAR_EXPRESSION_MATCH_DISALLOWED = "; private static final String REGULAR_EXPRESSION_MATCH_DISALLOWED = "REGULAR_EXPRESSION_MATCH_DISALLOWED = ";
private static final String REGULAR_EXPRESSION_MATCH_ALLOWED = "REGULAR_EXPRESSION_MATCH_ALLOWED = "; private static final String REGULAR_EXPRESSION_MATCH_ALLOWED = "REGULAR_EXPRESSION_MATCH_ALLOWED = ";
...@@ -41,7 +49,7 @@ public class ColumnNamerConfiguration { ...@@ -41,7 +49,7 @@ public class ColumnNamerConfiguration {
} }
public void setMaxIdentiferLength(int maxIdentiferLength) { public void setMaxIdentiferLength(int maxIdentiferLength) {
this.maxIdentiferLength = Math.max(30,maxIdentiferLength); this.maxIdentiferLength = Math.max(30, maxIdentiferLength);
if (maxIdentiferLength != getMaxIdentiferLength()) { if (maxIdentiferLength != getMaxIdentiferLength()) {
throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES", throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES",
"MAX_IDENTIFIER_LENGTH=" + maxIdentiferLength); "MAX_IDENTIFIER_LENGTH=" + maxIdentiferLength);
...@@ -89,12 +97,11 @@ public class ColumnNamerConfiguration { ...@@ -89,12 +97,11 @@ public class ColumnNamerConfiguration {
} }
public void configure(String stringValue) { public void configure(String stringValue) {
try{ try {
if (stringValue.equalsIgnoreCase(DEFAULT_COMMAND)) { if (stringValue.equalsIgnoreCase(DEFAULT_COMMAND)) {
configure(REGULAR); configure(REGULAR);
} else if (stringValue.startsWith(EMULATE_COMMAND)) { } else if (stringValue.startsWith(EMULATE_COMMAND)) {
configure(ModeEnum.valueOf( configure(ModeEnum.valueOf(unquoteString(stringValue.substring(EMULATE_COMMAND.length()))));
unquoteString(stringValue.substring(EMULATE_COMMAND.length()))));
} else if (stringValue.startsWith(MAX_IDENTIFIER_LENGTH)) { } else if (stringValue.startsWith(MAX_IDENTIFIER_LENGTH)) {
int maxLength = Integer.parseInt(stringValue.substring(MAX_IDENTIFIER_LENGTH.length())); int maxLength = Integer.parseInt(stringValue.substring(MAX_IDENTIFIER_LENGTH.length()));
setMaxIdentiferLength(maxLength); setMaxIdentiferLength(maxLength);
...@@ -113,38 +120,34 @@ public class ColumnNamerConfiguration { ...@@ -113,38 +120,34 @@ public class ColumnNamerConfiguration {
} else { } else {
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:" + stringValue, throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:" + stringValue,
stringValue); stringValue);
} }
recompilePatterns(); recompilePatterns();
} }
//Including NumberFormatException|PatternSyntaxException // Including NumberFormatException|PatternSyntaxException
catch(RuntimeException e){ catch (RuntimeException e) {
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES:"+e.getMessage(), throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES:" + e.getMessage(), stringValue);
stringValue);
} }
} }
private void recompilePatterns() { private void recompilePatterns() {
try{ try {
// recompile RE patterns // recompile RE patterns
setCompiledRegularExpressionMatchAllowed(Pattern.compile(getRegularExpressionMatchAllowed())); setCompiledRegularExpressionMatchAllowed(Pattern.compile(getRegularExpressionMatchAllowed()));
setCompiledRegularExpressionMatchDisallowed(Pattern.compile(getRegularExpressionMatchDisallowed())); setCompiledRegularExpressionMatchDisallowed(Pattern.compile(getRegularExpressionMatchDisallowed()));
} } catch (Exception e) {
catch(Exception e){
configure(REGULAR); configure(REGULAR);
throw e; throw e;
} }
} }
public static ColumnNamerConfiguration getDefault(){ public static ColumnNamerConfiguration getDefault() {
return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$",false); return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$", false);
} }
private static String unquoteString(String s){ private static String unquoteString(String s) {
if(s.startsWith("'") && s.endsWith("'")){ if (s.startsWith("'") && s.endsWith("'")) {
s = s.substring(1, s.length()-1); s = s.substring(1, s.length() - 1);
return s; return s;
} }
return s; return s;
...@@ -159,7 +162,7 @@ public class ColumnNamerConfiguration { ...@@ -159,7 +162,7 @@ public class ColumnNamerConfiguration {
} }
public void configure(ModeEnum modeEnum) { public void configure(ModeEnum modeEnum) {
switch(modeEnum){ switch (modeEnum) {
case Oracle: case Oracle:
// Nonquoted identifiers can contain only alphanumeric characters // Nonquoted identifiers can contain only alphanumeric characters
// from your database character set and the underscore (_), dollar // from your database character set and the underscore (_), dollar
...@@ -174,14 +177,16 @@ public class ColumnNamerConfiguration { ...@@ -174,14 +177,16 @@ public class ColumnNamerConfiguration {
case MSSQLServer: case MSSQLServer:
// https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server // https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
setMaxIdentiferLength(128); setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\[\\]]+");// allows [] around names // allows [] around names
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\[\\]]+");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\[\\]]"); setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\[\\]]");
setDefaultColumnNamePattern("_UNNAMED_$$"); setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false); setGenerateUniqueColumnNames(false);
break; break;
case PostgreSQL: case PostgreSQL:
setMaxIdentiferLength(63);// this default can be changed to 128 by postgres config // this default can be changed to 128 by postgres config
setMaxIdentiferLength(63);
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\$]+"); setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\$]+");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\$]"); setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\$]");
setDefaultColumnNamePattern("_UNNAMED_$$"); setDefaultColumnNamePattern("_UNNAMED_$$");
...@@ -189,7 +194,7 @@ public class ColumnNamerConfiguration { ...@@ -189,7 +194,7 @@ public class ColumnNamerConfiguration {
break; break;
case MySQL: case MySQL:
//https://dev.mysql.com/doc/refman/5.7/en/identifiers.html // https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
setMaxIdentiferLength(64); setMaxIdentiferLength(64);
setRegularExpressionMatchAllowed("(?m)(?s)`?[A-Za-z0-9_`\\$]+`?"); setRegularExpressionMatchAllowed("(?m)(?s)`?[A-Za-z0-9_`\\$]+`?");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_`\\$]"); setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_`\\$]");
......
...@@ -228,10 +228,10 @@ import org.h2.test.unit.TestValueHashMap; ...@@ -228,10 +228,10 @@ import org.h2.test.unit.TestValueHashMap;
import org.h2.test.unit.TestValueMemory; import org.h2.test.unit.TestValueMemory;
import org.h2.test.utils.OutputCatcher; import org.h2.test.utils.OutputCatcher;
import org.h2.test.utils.SelfDestructor; import org.h2.test.utils.SelfDestructor;
import org.h2.test.utils.TestColumnNamer;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Server; import org.h2.tools.Server;
import org.h2.util.AbbaLockingDetector; import org.h2.util.AbbaLockingDetector;
import org.h2.util.TestColumnNamer;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.Profiler; import org.h2.util.Profiler;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
......
...@@ -133,6 +133,12 @@ public class BenchB implements Bench, Runnable { ...@@ -133,6 +133,12 @@ public class BenchB implements Bench, Runnable {
// db.end(); // db.end();
} }
/**
* Get the number of transactions per client.
*
* @param size test size
* @return the transactions per client
*/
protected int getTransactionsPerClient(int size) { protected int getTransactionsPerClient(int size) {
return size / 8; return size / 8;
} }
......
package org.h2.test.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.test.TestBase;
public abstract class AbstractBaseForCommonTableExpressions extends TestBase {
protected void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames, int expectedNumbeOfRows, String SETUP_SQL,
String WITH_QUERY, int closeAndReopenDatabaseConnectionOnIteration) throws SQLException {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep;
ResultSet rs;
for(int queryRunTries=1;queryRunTries<=maxRetries;queryRunTries++){
Statement stat = conn.createStatement();
stat.execute(SETUP_SQL);
stat.close();
// close and re-open connection for one iteration to make sure the query work between connections
if(queryRunTries==closeAndReopenDatabaseConnectionOnIteration){
conn.close();
conn = getConnection("commonTableExpressionQueries");
}
prep = conn.prepareStatement(WITH_QUERY);
rs = prep.executeQuery();
for(int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++){
assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null);
assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex));
}
int rowNdx=0;
while (rs.next()) {
StringBuffer buf = new StringBuffer();
for(int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++){
buf.append("|"+rs.getString(columnIndex));
}
assertEquals(expectedRowData[rowNdx], buf.toString());
rowNdx++;
}
assertEquals(expectedNumbeOfRows,rowNdx);
rs.close();
prep.close();
}
conn.close();
deleteDb("commonTableExpressionQueries");
}
}
...@@ -1417,13 +1417,9 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1417,13 +1417,9 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertEquals(date, ToDateParser.toDate("113029", "J")); assertEquals(date, ToDateParser.toDate("113029", "J"));
if (Locale.getDefault() == Locale.ENGLISH) { if (Locale.getDefault() == Locale.ENGLISH) {
date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss") date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse("9999-12-31T23:59:59");
.parse("9999-12-31T23:59:59"); assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59", "DD-MON-YYYY HH24:MI:SS"));
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59", assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59", "DD-MON-RRRR HH24:MI:SS"));
"DD-MON-YYYY HH24:MI:SS"));
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59",
"DD-MON-RRRR HH24:MI:SS"));
SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");
assertEquals(ymd.parse("0001-03-01"), ToDateParser.toDate("1-MAR-0001", "DD-MON-RRRR")); assertEquals(ymd.parse("0001-03-01"), ToDateParser.toDate("1-MAR-0001", "DD-MON-RRRR"));
assertEquals(ymd.parse("9999-03-01"), ToDateParser.toDate("1-MAR-9999", "DD-MON-RRRR")); assertEquals(ymd.parse("9999-03-01"), ToDateParser.toDate("1-MAR-9999", "DD-MON-RRRR"));
......
...@@ -15,7 +15,7 @@ import org.h2.test.TestBase; ...@@ -15,7 +15,7 @@ import org.h2.test.TestBase;
/** /**
* Test non-recursive queries using WITH, but more than one common table defined. * Test non-recursive queries using WITH, but more than one common table defined.
*/ */
public class TestGeneralCommonTableQueries extends TestBase { public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExpressions {
/** /**
* Run just this test. * Run just this test.
...@@ -41,6 +41,7 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -41,6 +41,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
testMerge(); testMerge();
testCreateTable(); testCreateTable();
testNestedSQL(); testNestedSQL();
testRecursiveTable();
} }
private void testSimpleSelect() throws Exception { private void testSimpleSelect() throws Exception {
...@@ -468,4 +469,66 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -468,4 +469,66 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
private void testRecursiveTable() throws Exception {
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n" +
" X\n" +
"FROM PUBLIC.\"\" BB\n" +
" /* SELECT\n" +
" SUM(1) AS X,\n" +
" A\n" +
" FROM PUBLIC.B\n" +
" /++ PUBLIC.B.tableScan ++/\n" +
" /++ WHERE A IS ?1\n" +
" ++/\n" +
" /++ scanCount: 4 ++/\n" +
" INNER JOIN PUBLIC.C\n" +
" /++ PUBLIC.C.tableScan ++/\n" +
" ON 1=1\n" +
" WHERE (A IS ?1)\n" +
" AND (B.VAL = C.B)\n" +
" GROUP BY A: A IS A.VAL\n" +
" */\n" +
" /* scanCount: 1 */\n" +
"WHERE BB.A IS A.VAL)"};
String SETUP_SQL =
"DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; "
+"CREATE TABLE A(VAL VARCHAR(255)); "
+"CREATE TABLE B(A VARCHAR(255), VAL VARCHAR(255)); "
+"CREATE TABLE C(B VARCHAR(255), VAL VARCHAR(255)); "
+" "
+"INSERT INTO A VALUES('fruit'); "
+"INSERT INTO B VALUES('fruit','apple'); "
+"INSERT INTO B VALUES('fruit','banana'); "
+"INSERT INTO C VALUES('apple', 'golden delicious');"
+"INSERT INTO C VALUES('apple', 'granny smith'); "
+"INSERT INTO C VALUES('apple', 'pippin'); "
+"INSERT INTO A VALUES('veg'); "
+"INSERT INTO B VALUES('veg', 'carrot'); "
+"INSERT INTO C VALUES('carrot', 'nantes'); "
+"INSERT INTO C VALUES('carrot', 'imperator'); "
+"INSERT INTO C VALUES(null, 'banapple'); "
+"INSERT INTO A VALUES('meat'); "
;
String WITH_QUERY = "WITH BB as (SELECT \n" +
"sum(1) as X, \n" +
"a \n" +
"FROM B \n" +
"JOIN C ON B.val=C.b \n" +
"GROUP BY a) \n" +
"SELECT \n" +
"A.val, \n" +
"sum(SELECT X FROM BB WHERE BB.a IS A.val)\n" +
"FROM A \n" + "GROUP BY A.val";
int maxRetries = 3;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
}
} }
...@@ -5,17 +5,12 @@ ...@@ -5,17 +5,12 @@
*/ */
package org.h2.test.db; package org.h2.test.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
* Test persistent common table expressions queries using WITH. * Test persistent common table expressions queries using WITH.
*/ */
public class TestPersistentCommonTableExpressions extends TestBase { public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonTableExpressions {
/** /**
* Run just this test. * Run just this test.
...@@ -167,55 +162,4 @@ public class TestPersistentCommonTableExpressions extends TestBase { ...@@ -167,55 +162,4 @@ public class TestPersistentCommonTableExpressions extends TestBase {
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL, testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1); WITH_QUERY, maxRetries-1);
} }
private void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames,
int expectedNumbeOfRows, String SETUP_SQL, String WITH_QUERY, int closeAndReopenDatabaseConnectionOnIteration) throws SQLException {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep;
ResultSet rs;
for(int queryRunTries=1;queryRunTries<=maxRetries;queryRunTries++){
Statement stat = conn.createStatement();
stat.execute(SETUP_SQL);
stat.close();
// close and re-open connection for one iteration to make sure the query work between connections
if(queryRunTries==closeAndReopenDatabaseConnectionOnIteration){
conn.close();
conn = getConnection("commonTableExpressionQueries");
}
prep = conn.prepareStatement(WITH_QUERY);
rs = prep.executeQuery();
for(int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++){
assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null);
assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex));
}
int rowNdx=0;
while (rs.next()) {
StringBuffer buf = new StringBuffer();
for(int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++){
buf.append("|"+rs.getString(columnIndex));
}
assertEquals(expectedRowData[rowNdx], buf.toString());
rowNdx++;
}
assertEquals(expectedNumbeOfRows,rowNdx);
rs.close();
prep.close();
}
conn.close();
deleteDb("commonTableExpressionQueries");
}
} }
...@@ -61,25 +61,17 @@ public class TestConnection extends TestBase { ...@@ -61,25 +61,17 @@ public class TestConnection extends TestBase {
// Use MySQL-mode since this allows all property names // Use MySQL-mode since this allows all property names
// (apart from h2 internal names). // (apart from h2 internal names).
Connection conn = getConnection("clientInfoMySQL;MODE=MySQL"); Connection conn = getConnection("clientInfoMySQL;MODE=MySQL");
String numServersPropertyName = "numServers"; String numServersPropertyName = "numServers";
String numServers = conn.getClientInfo(numServersPropertyName); String numServers = conn.getClientInfo(numServersPropertyName);
conn.setClientInfo(numServersPropertyName, numServers); conn.setClientInfo(numServersPropertyName, numServers);
assertEquals(conn.getClientInfo(numServersPropertyName), numServers); assertEquals(conn.getClientInfo(numServersPropertyName), numServers);
conn.close(); conn.close();
} }
private void testSetUnsupportedClientInfoProperties() throws SQLException { private void testSetUnsupportedClientInfoProperties() throws SQLException {
Connection conn = getConnection("clientInfo"); Connection conn = getConnection("clientInfo");
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("ClientUser", "someUser"); properties.put("ClientUser", "someUser");
assertThrows(SQLClientInfoException.class, conn).setClientInfo(properties); assertThrows(SQLClientInfoException.class, conn).setClientInfo(properties);
conn.close(); conn.close();
} }
......
...@@ -2,3 +2,15 @@ ...@@ -2,3 +2,15 @@
-- and the EPL 1.0 (http://h2database.com/html/license.html). -- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group -- Initial Developer: H2 Group
-- --
CREATE TABLE tab_with_timezone(x TIMESTAMP WITH TIME ZONE);
> ok
INSERT INTO tab_with_timezone(x) VALUES ('2017-01-01');
> update count: 1
SELECT "Query".* FROM (select * from tab_with_timezone where x > '2016-01-01') AS "Query";
> X
> ------------------------
> 2017-01-01 00:00:00.0+00
package org.h2.util; /*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
*/
package org.h2.test.utils;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ValueExpression; import org.h2.expression.ValueExpression;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.ColumnNamer;
/**
* Tests the column name factory.
*/
public class TestColumnNamer extends TestBase { public class TestColumnNamer extends TestBase {
private String[] ids = new String[]{ private String[] ids = new String[] { "ABC", "123", "a\n2", "a$c%d#e@f!.", null,
"ABC" "VERYVERYVERYVERYVERYVERYLONGVERYVERYVERYVERYVERYVERYLONGVERYVERYVERYVERYVERYVERYLONG", "'!!!'", "'!!!!'",
,"123" "3.1415", "\r", "col1", "col1", "col1",
,"a\n2" "col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2",
,"a$c%d#e@f!." "col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2" };
,null
,"VERYVERYVERYVERYVERYVERYLONGVERYVERYVERYVERYVERYVERYLONGVERYVERYVERYVERYVERYVERYLONG" private String[] expectedColumnName = { "ABC", "123", "a2", "acdef", "colName6", "VERYVERYVERYVERYVERYVERYLONGVE",
,"'!!!'" "colName8", "colName9", "31415", "colName11", "col1", "col1_2", "col1_3", "col2col2col2col2col2col2col2co",
,"'!!!!'" "col2col2col2col2col2col2col2_2" };
,"3.1415"
,"\r" /**
,"col1" * Run just this test.
,"col1" *
,"col1" * @param a ignored
,"col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2" */
,"col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2" public static void main(String[] args) {
};
private String[] expectedColumnName= {"ABC"
,"123"
,"a2"
,"acdef"
,"colName6"
,"VERYVERYVERYVERYVERYVERYLONGVE"
,"colName8"
,"colName9"
,"31415"
,"colName11"
,"col1"
,"col1_2"
,"col1_3"
,"col2col2col2col2col2col2col2co"
,"col2col2col2col2col2col2col2_2"};
public static void main(String[] args){
new TestColumnNamer().test(); new TestColumnNamer().test();
} }
@Override
public void test() { public void test() {
ColumnNamer columnNamer = new ColumnNamer(null); ColumnNamer columnNamer = new ColumnNamer(null);
columnNamer.getConfiguration().configure("MAX_IDENTIFIER_LENGTH = 30"); columnNamer.getConfiguration().configure("MAX_IDENTIFIER_LENGTH = 30");
...@@ -54,14 +41,14 @@ public class TestColumnNamer extends TestBase { ...@@ -54,14 +41,14 @@ public class TestColumnNamer extends TestBase {
columnNamer.getConfiguration().configure("DEFAULT_COLUMN_NAME_PATTERN = 'colName$$'"); columnNamer.getConfiguration().configure("DEFAULT_COLUMN_NAME_PATTERN = 'colName$$'");
columnNamer.getConfiguration().configure("GENERATE_UNIQUE_COLUMN_NAMES = 1"); columnNamer.getConfiguration().configure("GENERATE_UNIQUE_COLUMN_NAMES = 1");
int index =0; int index = 0;
for(String id : ids){ for (String id : ids) {
Expression columnExp = ValueExpression.getDefault(); Expression columnExp = ValueExpression.getDefault();
String newColumnName = columnNamer.getColumnName(columnExp , index+1, id); String newColumnName = columnNamer.getColumnName(columnExp, index + 1, id);
assertTrue(newColumnName!=null); assertTrue(newColumnName != null);
assertTrue(newColumnName.length()<=30); assertTrue(newColumnName.length() <= 30);
assertTrue(newColumnName.length()>=1); assertTrue(newColumnName.length() >= 1);
assertEquals(newColumnName,expectedColumnName[index]); assertEquals(newColumnName, expectedColumnName[index]);
index++; index++;
} }
} }
......
...@@ -20,8 +20,8 @@ public class CheckTextFiles { ...@@ -20,8 +20,8 @@ public class CheckTextFiles {
private static final int MAX_SOURCE_LINE_SIZE = 120; private static final int MAX_SOURCE_LINE_SIZE = 120;
// must contain "+" otherwise this here counts as well // must contain "+" otherwise this here counts as well
private static final String COPYRIGHT = "Copyright 2004-2014 " + private static final String COPYRIGHT1 = "Copyright 2004-201";
"H2 Group."; private static final String COPYRIGHT2 = "H2 Group.";
private static final String LICENSE = "Multiple-Licensed " + private static final String LICENSE = "Multiple-Licensed " +
"under the MPL 2.0"; "under the MPL 2.0";
...@@ -144,10 +144,13 @@ public class CheckTextFiles { ...@@ -144,10 +144,13 @@ public class CheckTextFiles {
in.readFully(data); in.readFully(data);
in.close(); in.close();
if (checkLicense) { if (checkLicense) {
if (data.length > COPYRIGHT.length() + LICENSE.length()) { if (data.length > COPYRIGHT1.length() + LICENSE.length()) {
// don't check tiny files // don't check tiny files
String text = new String(data); String text = new String(data);
if (text.indexOf(COPYRIGHT) < 0) { if (text.indexOf(COPYRIGHT1) < 0) {
fail(file, "copyright is missing", 0);
}
if (text.indexOf(COPYRIGHT2) < 0) {
fail(file, "copyright is missing", 0); fail(file, "copyright is missing", 0);
} }
if (text.indexOf(LICENSE) < 0) { if (text.indexOf(LICENSE) < 0) {
......
...@@ -747,3 +747,10 @@ vectorwise preparation corrupting cubrid diffing unrestricted cleanups warns ...@@ -747,3 +747,10 @@ vectorwise preparation corrupting cubrid diffing unrestricted cleanups warns
rowspan specifically unoptimized stand emphasize cascaded exasol minimize rnum figure rowspan specifically unoptimized stand emphasize cascaded exasol minimize rnum figure
emptying goal gathers multithread amend raised iter gathered gather especially requiring emptying goal gathers multithread amend raised iter gathered gather especially requiring
collaboration thank essentially bunch vmlens subroutines nulled collaboration thank essentially bunch vmlens subroutines nulled
ndx quoss isn nonquoted pippin variation pierre allowable granny liberty fkey kervin veg banapple unconnected
alphanumeric england acdef landry arun mederp detached lyderic imperator morocco sumx websphere fruit
joaquim overides altertable novalidate udomain managed rewritten unquote identifer jake innocuous golay
bellotti clemens donators domainusername
veryveryveryveryveryverylongveryveryveryveryveryverylongveryveryveryveryveryverylong namer veryveryveryveryveryverylongve
chittanoor carrot
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论