Unverified 提交 5e137043 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1764 from katzyn/sql

Assorted changes
...@@ -73,7 +73,9 @@ This clause can be used to reuse the same definition in multiple functions. ...@@ -73,7 +73,9 @@ This clause can be used to reuse the same definition in multiple functions.
If FOR UPDATE is specified, the tables or rows are locked for writing. If FOR UPDATE is specified, the tables or rows are locked for writing.
This clause is not allowed in DISTINCT queries and in queries with non-window aggregates, GROUP BY, or HAVING clauses. This clause is not allowed in DISTINCT queries and in queries with non-window aggregates, GROUP BY, or HAVING clauses.
When using default MVStore engine only the selected rows are locked as in an UPDATE statement; When using default MVStore engine only the selected rows are locked as in an UPDATE statement;
locking behavior for rows that were excluded from result using OFFSET / FETCH is undefined. locking behavior for rows that were excluded from result using OFFSET / FETCH or QUALIFY is undefined.
Rows are processed one by one. Committed row is read, tested with WHERE criteria, locked, read again and re-tested,
because its value may be changed by concurrent transaction before lock acquisition.
With PageStore engine the whole tables are locked. With PageStore engine the whole tables are locked.
"," ","
SELECT * FROM TEST; SELECT * FROM TEST;
...@@ -223,7 +225,8 @@ RUNSCRIPT FROM 'classpath:/com/acme/test.sql' ...@@ -223,7 +225,8 @@ RUNSCRIPT FROM 'classpath:/com/acme/test.sql'
" "
"Commands (DML)","SCRIPT"," "Commands (DML)","SCRIPT","
SCRIPT [ SIMPLE ] [ NODATA ] [ NOPASSWORDS ] [ NOSETTINGS ] SCRIPT { [ NODATA ] | [ SIMPLE ] [ COLUMNS ] }
[ NOPASSWORDS ] [ NOSETTINGS ]
[ DROP ] [ BLOCKSIZE blockSizeInt ] [ DROP ] [ BLOCKSIZE blockSizeInt ]
[ TO fileNameString scriptCompressionEncryption [ TO fileNameString scriptCompressionEncryption
[ CHARSET charsetString ] ] [ CHARSET charsetString ] ]
...@@ -232,8 +235,9 @@ SCRIPT [ SIMPLE ] [ NODATA ] [ NOPASSWORDS ] [ NOSETTINGS ] ...@@ -232,8 +235,9 @@ SCRIPT [ SIMPLE ] [ NODATA ] [ NOPASSWORDS ] [ NOSETTINGS ]
"," ","
Creates a SQL script from the database. Creates a SQL script from the database.
SIMPLE does not use multi-row insert statements.
NODATA will not emit INSERT statements. NODATA will not emit INSERT statements.
SIMPLE does not use multi-row insert statements.
COLUMNS includes column name lists into insert statements.
If the DROP option is specified, drop statements are created for tables, views, If the DROP option is specified, drop statements are created for tables, views,
and sequences. If the block size is set, CLOB and BLOB values larger than this and sequences. If the block size is set, CLOB and BLOB values larger than this
size are split into separate blocks. size are split into separate blocks.
......
...@@ -472,21 +472,143 @@ Other database engines may commit the transaction in this case when the result s ...@@ -472,21 +472,143 @@ Other database engines may commit the transaction in this case when the result s
<h3>Keywords / Reserved Words</h3> <h3>Keywords / Reserved Words</h3>
<p> <p>
There is a list of keywords that can't be used as identifiers (table names, column names and so on), There is a list of keywords that can't be used as identifiers (table names, column names and so on),
unless they are quoted (surrounded with double quotes). The list is currently: unless they are quoted (surrounded with double quotes).
</p><p> The following tokens are keywords in H2:
<code> </p>
ALL, ARRAY, CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, <table class="main">
CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, DISTINCT, EXCEPT, <thead>
EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, <tr>
IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE, <th>Keyword</th>
LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, <th>H2</th>
OFFSET, ON, ORDER, PRIMARY, QUALIFY, ROW, _ROWID_, ROWNUM, SELECT, <th>SQL:&#8203;2011</th>
SYSDATE, SYSTIME, SYSTIMESTAMP, TABLE, TODAY, TOP, TRUE, UNION, <th>SQL:&#8203;2008</th>
UNIQUE, VALUES, WHERE, WINDOW, WITH <th>SQL:&#8203;2003</th>
</code> <th>SQL:&#8203;1999</th>
</p><p> <th>SQL-92</th>
Certain words of this list are keywords because they are functions that can be used without '()', </tr>
for example <code>CURRENT_TIMESTAMP</code>. </thead>
<tbody>
<tr><td>ALL</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>ARRAY</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>CASE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CHECK</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CONSTRAINT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CROSS</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CURRENT_DATE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CURRENT_TIME</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CURRENT_TIMESTAMP</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CURRENT_USER</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>DISTINCT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>EXCEPT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>EXISTS</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>NR</td><td>+</td></tr>
<tr><td>FALSE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FETCH</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FOR</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FOREIGN</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FROM</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FULL</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>GROUP</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>HAVING</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>IF</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>INNER</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>INTERSECT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>INTERSECTS</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>INTERVAL</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>IS</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>JOIN</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>LIKE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>LIMIT</td>
<td>+</td><td>NR</td><td>NR</td><td></td><td>+</td><td></td></tr>
<tr><td>LOCALTIME</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>LOCALTIMESTAMP</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>MINUS</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>NATURAL</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>NOT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>NULL</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>OFFSET</td>
<td>+</td><td>+</td><td>+</td><td></td><td></td><td></td></tr>
<tr><td>ON</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>ORDER</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>PRIMARY</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>QUALIFY</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>ROW</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>_ROWID_</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>ROWNUM</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>SELECT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>SYSDATE</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>SYSTIME</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>SYSTIMESTAMP</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>TABLE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>TODAY</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>TOP</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>TRUE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>UNION</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>UNIQUE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>VALUES</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>WHERE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>WINDOW</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td></td><td></td></tr>
<tr><td>WITH</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
</tbody>
</table>
<p>
Most of them are also reserved (+) or non-reserved (NR) words in the SQL Standard.
Newer versions of H2 may have more keywords than older ones.
</p> </p>
<h2 id="standards_compliance">Standards Compliance</h2> <h2 id="standards_compliance">Standards Compliance</h2>
......
...@@ -21,6 +21,10 @@ Change Log ...@@ -21,6 +21,10 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1759: SELECT &#8230; FOR UPDATE returns old data in 1.4.198
</li>
<li>PR #1756: Fix DISTINCT ON in presence of ORDER BY
</li>
<li>PR #1754: Fix window functions in JOIN with ON condition <li>PR #1754: Fix window functions in JOIN with ON condition
</li> </li>
<li>Issue #1751: making it easier to open console and create local databases <li>Issue #1751: making it easier to open console and create local databases
......
...@@ -7032,12 +7032,16 @@ public class Parser { ...@@ -7032,12 +7032,16 @@ public class Parser {
private ScriptCommand parseScript() { private ScriptCommand parseScript() {
ScriptCommand command = new ScriptCommand(session); ScriptCommand command = new ScriptCommand(session);
boolean data = true, passwords = true, settings = true; boolean data = true, passwords = true, settings = true;
boolean dropTables = false, simple = false; boolean dropTables = false, simple = false, withColumns = false;
if (readIf("SIMPLE")) {
simple = true;
}
if (readIf("NODATA")) { if (readIf("NODATA")) {
data = false; data = false;
} else {
if (readIf("SIMPLE")) {
simple = true;
}
if (readIf("COLUMNS")) {
withColumns = true;
}
} }
if (readIf("NOPASSWORDS")) { if (readIf("NOPASSWORDS")) {
passwords = false; passwords = false;
...@@ -7057,6 +7061,7 @@ public class Parser { ...@@ -7057,6 +7061,7 @@ public class Parser {
command.setSettings(settings); command.setSettings(settings);
command.setDrop(dropTables); command.setDrop(dropTables);
command.setSimple(simple); command.setSimple(simple);
command.setWithColumns(withColumns);
if (readIf("TO")) { if (readIf("TO")) {
command.setFileNameExpr(readExpression()); command.setFileNameExpr(readExpression());
if (readIf("COMPRESSION")) { if (readIf("COMPRESSION")) {
......
...@@ -78,6 +78,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -78,6 +78,7 @@ public class ScriptCommand extends ScriptBase {
// true if we're generating the DROP statements // true if we're generating the DROP statements
private boolean drop; private boolean drop;
private boolean simple; private boolean simple;
private boolean withColumns;
private LocalResult result; private LocalResult result;
private String lineSeparatorString; private String lineSeparatorString;
private byte[] lineSeparator; private byte[] lineSeparator;
...@@ -387,9 +388,13 @@ public class ScriptCommand extends ScriptBase { ...@@ -387,9 +388,13 @@ public class ScriptCommand extends ScriptBase {
Cursor cursor = index.find(session, null, null); Cursor cursor = index.find(session, null, null);
Column[] columns = table.getColumns(); Column[] columns = table.getColumns();
StringBuilder builder = new StringBuilder("INSERT INTO "); StringBuilder builder = new StringBuilder("INSERT INTO ");
table.getSQL(builder).append('('); table.getSQL(builder);
Column.writeColumns(builder, columns); if (withColumns) {
builder.append(") VALUES"); builder.append('(');
Column.writeColumns(builder, columns);
builder.append(')');
}
builder.append(" VALUES");
if (!simple) { if (!simple) {
builder.append('\n'); builder.append('\n');
} }
...@@ -707,6 +712,10 @@ public class ScriptCommand extends ScriptBase { ...@@ -707,6 +712,10 @@ public class ScriptCommand extends ScriptBase {
this.simple = simple; this.simple = simple;
} }
public void setWithColumns(boolean withColumns) {
this.withColumns = withColumns;
}
public void setCharset(Charset charset) { public void setCharset(Charset charset) {
this.charset = charset; this.charset = charset;
} }
......
...@@ -35,7 +35,6 @@ import org.h2.result.LazyResult; ...@@ -35,7 +35,6 @@ import org.h2.result.LazyResult;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.ResultTarget; import org.h2.result.ResultTarget;
import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
...@@ -425,6 +424,18 @@ public class Select extends Query { ...@@ -425,6 +424,18 @@ public class Select extends Query {
return count; return count;
} }
boolean isConditionMetForUpdate() {
if (isConditionMet()) {
int count = filters.size();
for (int i = 0; i < count; i++) {
TableFilter tableFilter = filters.get(i);
tableFilter.set(tableFilter.getTable().lockRow(session, tableFilter.get()));
}
return isConditionMet();
}
return false;
}
boolean isConditionMet() { boolean isConditionMet() {
return condition == null || condition.getBooleanValue(session); return condition == null || condition.getBooleanValue(session);
} }
...@@ -498,12 +509,10 @@ public class Select extends Query { ...@@ -498,12 +509,10 @@ public class Select extends Query {
long rowNumber = 0; long rowNumber = 0;
setCurrentRowNumber(0); setCurrentRowNumber(0);
int sampleSize = getSampleSizeValue(session); int sampleSize = getSampleSizeValue(session);
ArrayList<Row>[] forUpdateRows = initForUpdateRows();
while (topTableFilter.next()) { while (topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
if (isConditionMet()) { if (isForUpdateMvcc ? isConditionMetForUpdate() : isConditionMet()) {
rowNumber++; rowNumber++;
addForUpdateRow(forUpdateRows);
groupData.nextSource(); groupData.nextSource();
updateAgg(columnCount, stage); updateAgg(columnCount, stage);
if (sampleSize > 0 && rowNumber >= sampleSize) { if (sampleSize > 0 && rowNumber >= sampleSize) {
...@@ -511,7 +520,6 @@ public class Select extends Query { ...@@ -511,7 +520,6 @@ public class Select extends Query {
} }
} }
} }
lockForUpdateRows(forUpdateRows);
groupData.done(); groupData.done();
} }
...@@ -704,10 +712,10 @@ public class Select extends Query { ...@@ -704,10 +712,10 @@ public class Select extends Query {
limitRows = Long.MAX_VALUE; limitRows = Long.MAX_VALUE;
} }
} }
ArrayList<Row>[] forUpdateRows = initForUpdateRows();
int sampleSize = getSampleSizeValue(session); int sampleSize = getSampleSizeValue(session);
LazyResultQueryFlat lazyResult = new LazyResultQueryFlat(expressionArray, LazyResultQueryFlat lazyResult = isForUpdateMvcc
sampleSize, columnCount); ? new LazyResultQueryFlatForUpdate(expressionArray, sampleSize, columnCount)
: new LazyResultQueryFlat(expressionArray, sampleSize, columnCount);
skipOffset(lazyResult, offset, quickOffset); skipOffset(lazyResult, offset, quickOffset);
if (result == null) { if (result == null) {
return lazyResult; return lazyResult;
...@@ -717,7 +725,6 @@ public class Select extends Query { ...@@ -717,7 +725,6 @@ public class Select extends Query {
} }
Value[] row = null; Value[] row = null;
while (result.getRowCount() < limitRows && lazyResult.next()) { while (result.getRowCount() < limitRows && lazyResult.next()) {
addForUpdateRow(forUpdateRows);
row = lazyResult.currentRow(); row = lazyResult.currentRow();
result.addRow(row); result.addRow(row);
} }
...@@ -728,49 +735,16 @@ public class Select extends Query { ...@@ -728,49 +735,16 @@ public class Select extends Query {
if (sort.compare(expected, row) != 0) { if (sort.compare(expected, row) != 0) {
break; break;
} }
addForUpdateRow(forUpdateRows);
result.addRow(row); result.addRow(row);
} }
result.limitsWereApplied(); result.limitsWereApplied();
} }
lockForUpdateRows(forUpdateRows);
return null; return null;
} }
private ArrayList<Row>[] initForUpdateRows() {
if (!this.isForUpdateMvcc) {
return null;
}
int count = filters.size();
@SuppressWarnings("unchecked")
ArrayList<Row>[] rows = new ArrayList[count];
for (int i = 0; i < count; i++) {
rows[i] = Utils.<Row>newSmallArrayList();
}
return rows;
}
private void addForUpdateRow(ArrayList<Row>[] forUpdateRows) {
if (forUpdateRows != null) {
int count = filters.size();
for (int i = 0; i < count; i++) {
filters.get(i).lockRowAdd(forUpdateRows[i]);
}
}
}
private void lockForUpdateRows(ArrayList<Row>[] forUpdateRows) {
if (forUpdateRows != null) {
int count = filters.size();
for (int i = 0; i < count; i++) {
filters.get(i).lockRows(forUpdateRows[i]);
}
}
}
private static void skipOffset(LazyResultSelect lazyResult, long offset, boolean quickOffset) { private static void skipOffset(LazyResultSelect lazyResult, long offset, boolean quickOffset) {
if (quickOffset) { if (quickOffset) {
while (offset > 0 && lazyResult.next()) { while (offset > 0 && lazyResult.skip()) {
offset--; offset--;
} }
} }
...@@ -1872,7 +1846,7 @@ public class Select extends Query { ...@@ -1872,7 +1846,7 @@ public class Select extends Query {
/** /**
* Lazy execution for a flat query. * Lazy execution for a flat query.
*/ */
private final class LazyResultQueryFlat extends LazyResultSelect { private class LazyResultQueryFlat extends LazyResultSelect {
int sampleSize; int sampleSize;
...@@ -1883,10 +1857,10 @@ public class Select extends Query { ...@@ -1883,10 +1857,10 @@ public class Select extends Query {
@Override @Override
protected Value[] fetchNextRow() { protected Value[] fetchNextRow() {
while ((sampleSize <= 0 || rowNumber < sampleSize) && while ((sampleSize <= 0 || rowNumber < sampleSize) && topTableFilter.next()) {
topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
if (isConditionMet()) { // This method may lock rows
if (isSelectConditionMet()) {
++rowNumber; ++rowNumber;
Value[] row = new Value[columnCount]; Value[] row = new Value[columnCount];
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
...@@ -1898,6 +1872,39 @@ public class Select extends Query { ...@@ -1898,6 +1872,39 @@ public class Select extends Query {
} }
return null; return null;
} }
@Override
protected boolean skipNextRow() {
while ((sampleSize <= 0 || rowNumber < sampleSize) && topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1);
// This method does not lock rows
if (isConditionMet()) {
++rowNumber;
return true;
}
}
return false;
}
boolean isSelectConditionMet() {
return isConditionMet();
}
}
/**
* Lazy execution for a flat for update query.
*/
private final class LazyResultQueryFlatForUpdate extends LazyResultQueryFlat {
LazyResultQueryFlatForUpdate(Expression[] expressions, int sampleSize, int columnCount) {
super(expressions, sampleSize, columnCount);
}
@Override
boolean isSelectConditionMet() {
return isConditionMetForUpdate();
}
} }
/** /**
......
...@@ -214,20 +214,6 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -214,20 +214,6 @@ public class MVPrimaryIndex extends BaseIndex {
} }
} }
/**
* Lock a set of rows.
*
* @param session database session
* @param rowsForUpdate rows to lock
*/
void lockRows(Session session, Iterable<Row> rowsForUpdate) {
TransactionMap<Value, Value> map = getMap(session);
for (Row row : rowsForUpdate) {
long key = row.getKey();
lockRow(map, key);
}
}
/** /**
* Lock a single row. * Lock a single row.
* *
......
...@@ -734,11 +734,6 @@ public class MVTable extends TableBase { ...@@ -734,11 +734,6 @@ public class MVTable extends TableBase {
analyzeIfRequired(session); analyzeIfRequired(session);
} }
@Override
public void lockRows(Session session, Iterable<Row> rowsForUpdate) {
primaryIndex.lockRows(session, rowsForUpdate);
}
@Override @Override
public Row lockRow(Session session, Row row) { public Row lockRow(Session session, Row row) {
return primaryIndex.lockRow(session, row); return primaryIndex.lockRow(session, row);
......
...@@ -71,6 +71,27 @@ public abstract class LazyResult implements ResultInterface { ...@@ -71,6 +71,27 @@ public abstract class LazyResult implements ResultInterface {
return false; return false;
} }
/**
* Go to the next row and skip it.
*
* @return true if a row exists
*/
public boolean skip() {
if (closed || afterLast) {
return false;
}
currentRow = null;
if (nextRow != null) {
nextRow = null;
return true;
}
if (skipNextRow()) {
return true;
}
afterLast = true;
return false;
}
@Override @Override
public boolean hasNext() { public boolean hasNext() {
if (closed || afterLast) { if (closed || afterLast) {
...@@ -89,6 +110,15 @@ public abstract class LazyResult implements ResultInterface { ...@@ -89,6 +110,15 @@ public abstract class LazyResult implements ResultInterface {
*/ */
protected abstract Value[] fetchNextRow(); protected abstract Value[] fetchNextRow();
/**
* Skip next row.
*
* @return true if next row was available
*/
protected boolean skipNextRow() {
return fetchNextRow() != null;
}
@Override @Override
public boolean isAfterLast() { public boolean isAfterLast() {
return afterLast; return afterLast;
......
...@@ -176,18 +176,6 @@ public abstract class Table extends SchemaObjectBase { ...@@ -176,18 +176,6 @@ public abstract class Table extends SchemaObjectBase {
*/ */
public abstract void removeRow(Session session, Row row); public abstract void removeRow(Session session, Row row);
/**
* Locks rows, preventing any updated to them, except from the session specified.
*
* @param session the session
* @param rowsForUpdate rows to lock
*/
public void lockRows(Session session, Iterable<Row> rowsForUpdate) {
for (Row row : rowsForUpdate) {
lockRow(session, row);
}
}
/** /**
* Locks row, preventing any updated to it, except from the session specified. * Locks row, preventing any updated to it, except from the session specified.
* *
......
...@@ -606,8 +606,6 @@ public class TableFilter implements ColumnResolver { ...@@ -606,8 +606,6 @@ public class TableFilter implements ColumnResolver {
* @param current the current row * @param current the current row
*/ */
public void set(Row current) { public void set(Row current) {
// this is currently only used so that check constraints work - to set
// the current (new) row
this.current = current; this.current = current;
this.currentSearchRow = current; this.currentSearchRow = current;
} }
...@@ -1177,15 +1175,6 @@ public class TableFilter implements ColumnResolver { ...@@ -1177,15 +1175,6 @@ public class TableFilter implements ColumnResolver {
} }
} }
/**
* Lock the given rows.
*
* @param forUpdateRows the rows to lock
*/
public void lockRows(Iterable<Row> forUpdateRows) {
table.lockRows(session, forUpdateRows);
}
public TableFilter getNestedJoin() { public TableFilter getNestedJoin() {
return nestedJoin; return nestedJoin;
} }
......
...@@ -31,11 +31,13 @@ public class TestTransaction extends TestDb { ...@@ -31,11 +31,13 @@ public class TestTransaction extends TestDb {
* @param a ignored * @param a ignored
*/ */
public static void main(String... a) throws Exception { public static void main(String... a) throws Exception {
TestBase.createCaller().init().test(); TestBase init = TestBase.createCaller().init();
init.config.multiThreaded = true;
init.test();
} }
@Override @Override
public void test() throws SQLException { public void test() throws Exception {
testClosingConnectionWithSessionTempTable(); testClosingConnectionWithSessionTempTable();
testClosingConnectionWithLockedTable(); testClosingConnectionWithLockedTable();
testConstraintCreationRollback(); testConstraintCreationRollback();
...@@ -45,6 +47,7 @@ public class TestTransaction extends TestDb { ...@@ -45,6 +47,7 @@ public class TestTransaction extends TestDb {
testRollback(); testRollback();
testRollback2(); testRollback2();
testForUpdate(); testForUpdate();
testForUpdate2();
testSetTransaction(); testSetTransaction();
testReferential(); testReferential();
testSavepoint(); testSavepoint();
...@@ -218,6 +221,81 @@ public class TestTransaction extends TestDb { ...@@ -218,6 +221,81 @@ public class TestTransaction extends TestDb {
conn.close(); conn.close();
} }
private void testForUpdate2() throws Exception {
// Exclude some configurations to avoid spending too much time in sleep()
if (config.mvStore && !config.multiThreaded || config.networked || config.cipher != null) {
return;
}
deleteDb("transaction");
Connection conn1 = getConnection("transaction");
Connection conn2 = getConnection("transaction");
Statement stat1 = conn1.createStatement();
stat1.execute("CREATE TABLE TEST (ID INT PRIMARY KEY, V INT)");
stat1.execute("INSERT INTO TEST VALUES (1, 0)");
conn1.setAutoCommit(false);
conn2.createStatement().execute("SET LOCK_TIMEOUT 2000");
if (config.mvStore) {
testForUpdate2(conn1, stat1, conn2, false);
}
testForUpdate2(conn1, stat1, conn2, true);
conn1.close();
conn2.close();
}
void testForUpdate2(Connection conn1, Statement stat1, Connection conn2, boolean forUpdate)
throws Exception {
testForUpdate2(conn1, stat1, conn2, forUpdate, false);
testForUpdate2(conn1, stat1, conn2, forUpdate, true);
}
void testForUpdate2(Connection conn1, Statement stat1, Connection conn2, boolean forUpdate,
boolean window) throws Exception {
testForUpdate2(conn1, stat1, conn2, forUpdate, window, false);
testForUpdate2(conn1, stat1, conn2, forUpdate, window, true);
}
void testForUpdate2(Connection conn1, Statement stat1, final Connection conn2, boolean forUpdate,
boolean window, boolean excluded) throws Exception {
stat1.execute("UPDATE TEST SET V = 1 WHERE ID = 1");
conn1.commit();
stat1.execute("UPDATE TEST SET V = 2 WHERE ID = 1");
final int[] res = new int[1];
final Exception[] ex = new Exception[1];
StringBuilder builder = new StringBuilder("SELECT V");
if (window) {
builder.append(", RANK() OVER (ORDER BY ID)");
}
builder.append(" FROM TEST WHERE ID = 1");
if (excluded) {
builder.append(" AND V = 1");
}
if (forUpdate) {
builder.append(" FOR UPDATE");
}
String query = builder.toString();
final PreparedStatement prep2 = conn2.prepareStatement(query);
Thread t = new Thread() {
@Override
public void run() {
try {
ResultSet resultSet = prep2.executeQuery();
res[0] = resultSet.next() ? resultSet.getInt(1) : -1;
conn2.commit();
} catch (SQLException e) {
ex[0] = e;
}
}
};
t.start();
Thread.sleep(500);
conn1.commit();
t.join();
if (ex[0] != null) {
throw ex[0];
}
assertEquals(forUpdate ? excluded ? -1 : 2 : 1, res[0]);
}
private void testRollback() throws SQLException { private void testRollback() throws SQLException {
deleteDb("transaction"); deleteDb("transaction");
Connection conn = getConnection("transaction"); Connection conn = getConnection("transaction");
......
...@@ -9,7 +9,17 @@ create memory table test(id int primary key, name varchar(255)); ...@@ -9,7 +9,17 @@ create memory table test(id int primary key, name varchar(255));
INSERT INTO TEST VALUES(2, STRINGDECODE('abcsond\344rzeich\344 ') || char(22222) || STRINGDECODE(' \366\344\374\326\304\334\351\350\340\361!')); INSERT INTO TEST VALUES(2, STRINGDECODE('abcsond\344rzeich\344 ') || char(22222) || STRINGDECODE(' \366\344\374\326\304\334\351\350\340\361!'));
> update count: 1 > update count: 1
script nopasswords nosettings; SCRIPT NOPASSWORDS NOSETTINGS;
> SCRIPT
> ---------------------------------------------------------------------------------------------------------------------------------------------------
> -- 1 +/- SELECT COUNT(*) FROM PUBLIC.TEST;
> ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID);
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, NAME VARCHAR(255) );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST VALUES (2, STRINGDECODE('abcsond\u00e4rzeich\u00e4 \u56ce \u00f6\u00e4\u00fc\u00d6\u00c4\u00dc\u00e9\u00e8\u00e0\u00f1!'));
> rows: 5
SCRIPT COLUMNS NOPASSWORDS NOSETTINGS;
> SCRIPT > SCRIPT
> ------------------------------------------------------------------------------------------------------------------------------------------------------------- > -------------------------------------------------------------------------------------------------------------------------------------------------------------
> -- 1 +/- SELECT COUNT(*) FROM PUBLIC.TEST; > -- 1 +/- SELECT COUNT(*) FROM PUBLIC.TEST;
......
...@@ -1111,11 +1111,11 @@ select * from test order by id; ...@@ -1111,11 +1111,11 @@ select * from test order by id;
script nopasswords nosettings; script nopasswords nosettings;
> SCRIPT > SCRIPT
> ----------------------------------------------------------------------------------------------------------------------------------------- > -------------------------------------------------------------------------------------------------------------------------------
> -- 3 +/- SELECT COUNT(*) FROM PUBLIC.TEST; > -- 3 +/- SELECT COUNT(*) FROM PUBLIC.TEST;
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT, D DOUBLE, F FLOAT ); > CREATE MEMORY TABLE PUBLIC.TEST( ID INT, D DOUBLE, F FLOAT );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST(ID, D, F) VALUES (0, POWER(0, -1), POWER(0, -1)), (1, (-POWER(0, -1)), (-POWER(0, -1))), (2, SQRT(-1), SQRT(-1)); > INSERT INTO PUBLIC.TEST VALUES (0, POWER(0, -1), POWER(0, -1)), (1, (-POWER(0, -1)), (-POWER(0, -1))), (2, SQRT(-1), SQRT(-1));
> rows: 4 > rows: 4
DROP TABLE TEST; DROP TABLE TEST;
...@@ -2138,7 +2138,7 @@ script nopasswords nosettings blocksize 10; ...@@ -2138,7 +2138,7 @@ script nopasswords nosettings blocksize 10;
> DROP ALIAS IF EXISTS SYSTEM_COMBINE_BLOB; > DROP ALIAS IF EXISTS SYSTEM_COMBINE_BLOB;
> DROP ALIAS IF EXISTS SYSTEM_COMBINE_CLOB; > DROP ALIAS IF EXISTS SYSTEM_COMBINE_CLOB;
> DROP TABLE IF EXISTS SYSTEM_LOB_STREAM; > DROP TABLE IF EXISTS SYSTEM_LOB_STREAM;
> INSERT INTO PUBLIC.TEST(ID, DATA) VALUES (1, SYSTEM_COMBINE_CLOB(0)); > INSERT INTO PUBLIC.TEST VALUES (1, SYSTEM_COMBINE_CLOB(0));
> INSERT INTO SYSTEM_LOB_STREAM VALUES(0, 0, 'abc ', NULL); > INSERT INTO SYSTEM_LOB_STREAM VALUES(0, 0, 'abc ', NULL);
> INSERT INTO SYSTEM_LOB_STREAM VALUES(0, 1, ' ', NULL); > INSERT INTO SYSTEM_LOB_STREAM VALUES(0, 1, ' ', NULL);
> INSERT INTO SYSTEM_LOB_STREAM VALUES(0, 2, ' ', NULL); > INSERT INTO SYSTEM_LOB_STREAM VALUES(0, 2, ' ', NULL);
...@@ -3706,7 +3706,7 @@ script NOPASSWORDS NOSETTINGS drop; ...@@ -3706,7 +3706,7 @@ script NOPASSWORDS NOSETTINGS drop;
> CREATE MEMORY TABLE PUBLIC.TEST( I INT NOT NULL, NAME VARCHAR(255), Y INT AS (I + 1) ); > CREATE MEMORY TABLE PUBLIC.TEST( I INT NOT NULL, NAME VARCHAR(255), Y INT AS (I + 1) );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> DROP TABLE IF EXISTS PUBLIC.TEST CASCADE; > DROP TABLE IF EXISTS PUBLIC.TEST CASCADE;
> INSERT INTO PUBLIC.TEST(I, NAME, Y) VALUES (1, 'Hello', 2); > INSERT INTO PUBLIC.TEST VALUES (1, 'Hello', 2);
> rows: 8 > rows: 8
INSERT INTO TEST(i, name) VALUES(2, 'World'); INSERT INTO TEST(i, name) VALUES(2, 'World');
...@@ -4355,9 +4355,9 @@ script simple nopasswords nosettings; ...@@ -4355,9 +4355,9 @@ script simple nopasswords nosettings;
> ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID); > ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID);
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, C CLOB, B BLOB ); > CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, C CLOB, B BLOB );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST(ID, C, B) VALUES(0, NULL, NULL); > INSERT INTO PUBLIC.TEST VALUES(0, NULL, NULL);
> INSERT INTO PUBLIC.TEST(ID, C, B) VALUES(1, '', X''); > INSERT INTO PUBLIC.TEST VALUES(1, '', X'');
> INSERT INTO PUBLIC.TEST(ID, C, B) VALUES(2, 'Cafe', X'cafe'); > INSERT INTO PUBLIC.TEST VALUES(2, 'Cafe', X'cafe');
> rows: 7 > rows: 7
drop table test; drop table test;
...@@ -4824,11 +4824,11 @@ SCRIPT SIMPLE NOPASSWORDS NOSETTINGS; ...@@ -4824,11 +4824,11 @@ SCRIPT SIMPLE NOPASSWORDS NOSETTINGS;
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, NAME VARCHAR(255) DEFAULT 1, CREATEDATE VARCHAR(255) DEFAULT '2001-01-01' NOT NULL, MODIFY_DATE TIMESTAMP ); > CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, NAME VARCHAR(255) DEFAULT 1, CREATEDATE VARCHAR(255) DEFAULT '2001-01-01' NOT NULL, MODIFY_DATE TIMESTAMP );
> CREATE MEMORY TABLE PUBLIC.TEST_SEQ( ID INT DEFAULT 20 NOT NULL, DATA VARCHAR ); > CREATE MEMORY TABLE PUBLIC.TEST_SEQ( ID INT DEFAULT 20 NOT NULL, DATA VARCHAR );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST(ID, NAME, CREATEDATE, MODIFY_DATE) VALUES(1, 'Hi', '2001-01-01', NULL); > INSERT INTO PUBLIC.TEST VALUES(1, 'Hi', '2001-01-01', NULL);
> INSERT INTO PUBLIC.TEST_SEQ(ID, DATA) VALUES(-1, '-1'); > INSERT INTO PUBLIC.TEST_SEQ VALUES(-1, '-1');
> INSERT INTO PUBLIC.TEST_SEQ(ID, DATA) VALUES(1, '1'); > INSERT INTO PUBLIC.TEST_SEQ VALUES(1, '1');
> INSERT INTO PUBLIC.TEST_SEQ(ID, DATA) VALUES(10, '10'); > INSERT INTO PUBLIC.TEST_SEQ VALUES(10, '10');
> INSERT INTO PUBLIC.TEST_SEQ(ID, DATA) VALUES(20, '20'); > INSERT INTO PUBLIC.TEST_SEQ VALUES(20, '20');
> rows: 12 > rows: 12
CREATE UNIQUE INDEX IDX_NAME_ID ON TEST(ID, NAME); CREATE UNIQUE INDEX IDX_NAME_ID ON TEST(ID, NAME);
...@@ -4856,7 +4856,7 @@ SCRIPT NOPASSWORDS NOSETTINGS; ...@@ -4856,7 +4856,7 @@ SCRIPT NOPASSWORDS NOSETTINGS;
> ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID); > ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID);
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, CREATEDATE VARCHAR(255) DEFAULT '2001-01-01' NOT NULL, MODIFY_DATE TIMESTAMP ); > CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, CREATEDATE VARCHAR(255) DEFAULT '2001-01-01' NOT NULL, MODIFY_DATE TIMESTAMP );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST(ID, CREATEDATE, MODIFY_DATE) VALUES (1, '2001-01-01', NULL); > INSERT INTO PUBLIC.TEST VALUES (1, '2001-01-01', NULL);
> rows: 5 > rows: 5
ALTER TABLE TEST ADD NAME VARCHAR(255) NULL BEFORE CREATEDATE; ALTER TABLE TEST ADD NAME VARCHAR(255) NULL BEFORE CREATEDATE;
...@@ -4869,7 +4869,7 @@ SCRIPT NOPASSWORDS NOSETTINGS; ...@@ -4869,7 +4869,7 @@ SCRIPT NOPASSWORDS NOSETTINGS;
> ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID); > ALTER TABLE PUBLIC.TEST ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(ID);
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, NAME VARCHAR(255), CREATEDATE VARCHAR(255) DEFAULT '2001-01-01' NOT NULL, MODIFY_DATE TIMESTAMP ); > CREATE MEMORY TABLE PUBLIC.TEST( ID INT NOT NULL, NAME VARCHAR(255), CREATEDATE VARCHAR(255) DEFAULT '2001-01-01' NOT NULL, MODIFY_DATE TIMESTAMP );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST(ID, NAME, CREATEDATE, MODIFY_DATE) VALUES (1, NULL, '2001-01-01', NULL); > INSERT INTO PUBLIC.TEST VALUES (1, NULL, '2001-01-01', NULL);
> rows: 5 > rows: 5
UPDATE TEST SET NAME = 'Hi'; UPDATE TEST SET NAME = 'Hi';
...@@ -6157,14 +6157,14 @@ CAST(XT AS TIMESTAMP) D2TS, CAST(XD AS TIMESTAMP) D2TS FROM TEST; ...@@ -6157,14 +6157,14 @@ CAST(XT AS TIMESTAMP) D2TS, CAST(XD AS TIMESTAMP) D2TS FROM TEST;
SCRIPT SIMPLE NOPASSWORDS NOSETTINGS; SCRIPT SIMPLE NOPASSWORDS NOSETTINGS;
> SCRIPT > SCRIPT
> ---------------------------------------------------------------------------------------------------------------------------------- > -----------------------------------------------------------------------------------------------------------------
> -- 4 +/- SELECT COUNT(*) FROM PUBLIC.TEST; > -- 4 +/- SELECT COUNT(*) FROM PUBLIC.TEST;
> CREATE MEMORY TABLE PUBLIC.TEST( ID INT, XT TIME, XD DATE, XTS TIMESTAMP(9) ); > CREATE MEMORY TABLE PUBLIC.TEST( ID INT, XT TIME, XD DATE, XTS TIMESTAMP(9) );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.TEST(ID, XT, XD, XTS) VALUES(0, TIME '00:00:00', DATE '0001-02-03', TIMESTAMP '0002-03-04 00:00:00'); > INSERT INTO PUBLIC.TEST VALUES(0, TIME '00:00:00', DATE '0001-02-03', TIMESTAMP '0002-03-04 00:00:00');
> INSERT INTO PUBLIC.TEST(ID, XT, XD, XTS) VALUES(1, TIME '01:02:03', DATE '0004-05-06', TIMESTAMP '0007-08-09 00:01:02'); > INSERT INTO PUBLIC.TEST VALUES(1, TIME '01:02:03', DATE '0004-05-06', TIMESTAMP '0007-08-09 00:01:02');
> INSERT INTO PUBLIC.TEST(ID, XT, XD, XTS) VALUES(2, TIME '23:59:59', DATE '1999-12-31', TIMESTAMP '1999-12-31 23:59:59.123456789'); > INSERT INTO PUBLIC.TEST VALUES(2, TIME '23:59:59', DATE '1999-12-31', TIMESTAMP '1999-12-31 23:59:59.123456789');
> INSERT INTO PUBLIC.TEST(ID, XT, XD, XTS) VALUES(NULL, NULL, NULL, NULL); > INSERT INTO PUBLIC.TEST VALUES(NULL, NULL, NULL, NULL);
> rows: 7 > rows: 7
DROP TABLE TEST; DROP TABLE TEST;
...@@ -7268,7 +7268,7 @@ SCRIPT NOPASSWORDS NOSETTINGS; ...@@ -7268,7 +7268,7 @@ SCRIPT NOPASSWORDS NOSETTINGS;
> CREATE MEMORY TABLE PUBLIC.A_TEST( A_INT INT NOT NULL, A_VARCHAR VARCHAR(255) DEFAULT 'x', A_DATE DATE, A_DECIMAL DECIMAL(10, 2) ); > CREATE MEMORY TABLE PUBLIC.A_TEST( A_INT INT NOT NULL, A_VARCHAR VARCHAR(255) DEFAULT 'x', A_DATE DATE, A_DECIMAL DECIMAL(10, 2) );
> CREATE MEMORY TABLE PUBLIC.B_TEST( B_INT INT DEFAULT -1 NOT NULL, B_VARCHAR VARCHAR(255) DEFAULT NULL ); > CREATE MEMORY TABLE PUBLIC.B_TEST( B_INT INT DEFAULT -1 NOT NULL, B_VARCHAR VARCHAR(255) DEFAULT NULL );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.B_TEST(B_INT, B_VARCHAR) VALUES (-1, 'XX'); > INSERT INTO PUBLIC.B_TEST VALUES (-1, 'XX');
> rows: 14 > rows: 14
DROP TABLE A_TEST; DROP TABLE A_TEST;
...@@ -7367,12 +7367,12 @@ SCRIPT SIMPLE NOPASSWORDS NOSETTINGS; ...@@ -7367,12 +7367,12 @@ SCRIPT SIMPLE NOPASSWORDS NOSETTINGS;
> CREATE MEMORY TABLE PUBLIC.FAMILY( ID INT, NAME VARCHAR(20) ); > CREATE MEMORY TABLE PUBLIC.FAMILY( ID INT, NAME VARCHAR(20) );
> CREATE MEMORY TABLE PUBLIC.PARENT( ID INT, FAMILY_ID INT, NAME VARCHAR(20) ); > CREATE MEMORY TABLE PUBLIC.PARENT( ID INT, FAMILY_ID INT, NAME VARCHAR(20) );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(100, 3, 1, 'Simon'); > INSERT INTO PUBLIC.CHILD VALUES(100, 3, 1, 'Simon');
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(101, 3, 1, 'Sabine'); > INSERT INTO PUBLIC.CHILD VALUES(101, 3, 1, 'Sabine');
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(200, NULL, NULL, 'Jim'); > INSERT INTO PUBLIC.CHILD VALUES(200, NULL, NULL, 'Jim');
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(201, NULL, NULL, 'Johann'); > INSERT INTO PUBLIC.CHILD VALUES(201, NULL, NULL, 'Johann');
> INSERT INTO PUBLIC.FAMILY(ID, NAME) VALUES(1, 'Capone'); > INSERT INTO PUBLIC.FAMILY VALUES(1, 'Capone');
> INSERT INTO PUBLIC.PARENT(ID, FAMILY_ID, NAME) VALUES(3, 1, 'Sue'); > INSERT INTO PUBLIC.PARENT VALUES(3, 1, 'Sue');
> rows: 17 > rows: 17
ALTER TABLE CHILD DROP CONSTRAINT PARENT_CHILD; ALTER TABLE CHILD DROP CONSTRAINT PARENT_CHILD;
...@@ -7391,12 +7391,12 @@ SCRIPT SIMPLE NOPASSWORDS NOSETTINGS; ...@@ -7391,12 +7391,12 @@ SCRIPT SIMPLE NOPASSWORDS NOSETTINGS;
> CREATE MEMORY TABLE PUBLIC.FAMILY( ID INT, NAME VARCHAR(20) ); > CREATE MEMORY TABLE PUBLIC.FAMILY( ID INT, NAME VARCHAR(20) );
> CREATE MEMORY TABLE PUBLIC.PARENT( ID INT, FAMILY_ID INT, NAME VARCHAR(20) ); > CREATE MEMORY TABLE PUBLIC.PARENT( ID INT, FAMILY_ID INT, NAME VARCHAR(20) );
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN; > CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN;
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(100, 3, 1, 'Simon'); > INSERT INTO PUBLIC.CHILD VALUES(100, 3, 1, 'Simon');
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(101, 3, 1, 'Sabine'); > INSERT INTO PUBLIC.CHILD VALUES(101, 3, 1, 'Sabine');
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(200, NULL, NULL, 'Jim'); > INSERT INTO PUBLIC.CHILD VALUES(200, NULL, NULL, 'Jim');
> INSERT INTO PUBLIC.CHILD(ID, PARENTID, FAMILY_ID, NAME) VALUES(201, NULL, NULL, 'Johann'); > INSERT INTO PUBLIC.CHILD VALUES(201, NULL, NULL, 'Johann');
> INSERT INTO PUBLIC.FAMILY(ID, NAME) VALUES(1, 'Capone'); > INSERT INTO PUBLIC.FAMILY VALUES(1, 'Capone');
> INSERT INTO PUBLIC.PARENT(ID, FAMILY_ID, NAME) VALUES(3, 1, 'Sue'); > INSERT INTO PUBLIC.PARENT VALUES(3, 1, 'Sue');
> rows: 16 > rows: 16
DELETE FROM PARENT; DELETE FROM PARENT;
......
...@@ -809,4 +809,4 @@ preserves masking holder unboxing avert iae transformed subtle reevaluate exclus ...@@ -809,4 +809,4 @@ preserves masking holder unboxing avert iae transformed subtle reevaluate exclus
presorted inclusion contexts aax mwd percentile cont interpolate mwa hypothetical regproc childed listagg foreground presorted inclusion contexts aax mwd percentile cont interpolate mwa hypothetical regproc childed listagg foreground
isodow isoyear psql isodow isoyear psql
waiters reliably httpsdocs privileged waiters reliably httpsdocs privileged narrow spending
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论