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

Cleanup#2

上级 9c1d1d29
......@@ -1040,8 +1040,6 @@ public class Database implements DataHandler {
* @param obj the object to add
*/
public void addSchemaObject(Session session, SchemaObject obj) {
//System.out.println("addSchemaObject="+obj.getName()+",sessionId="+session.getId()+",obj="+obj);
int id = obj.getId();
if (id > 0 && !starting) {
checkWritingAllowed();
......@@ -1875,7 +1873,7 @@ public class Database implements DataHandler {
* @param session the session
* @param obj the object to be removed
*/
public boolean removeSchemaObject(Session session,
public void removeSchemaObject(Session session,
SchemaObject obj) {
int type = obj.getType();
if (type == DbObject.TABLE_OR_VIEW) {
......@@ -1883,32 +1881,26 @@ public class Database implements DataHandler {
//table.setBeingDropped(true);
if (table.isTemporary() && !table.isGlobalTemporary()) {
session.removeLocalTempTable(table);
return true;
return;
}
} else if (type == DbObject.INDEX) {
Index index = (Index) obj;
Table table = index.getTable();
if (table.isTemporary() && !table.isGlobalTemporary()) {
session.removeLocalTempTableIndex(index);
return true;
return;
}
} else if (type == DbObject.CONSTRAINT) {
Constraint constraint = (Constraint) obj;
Table table = constraint.getTable();
if (table.isTemporary() && !table.isGlobalTemporary()) {
session.removeLocalTempTableConstraint(constraint);
return true;
return;
}
}
checkWritingAllowed();
/*Boolean wasLocked = */lockMeta(session);// was lockMetaNoWait
//if(wasLocked==null){
// removeSchemaObjectQueue.put(obj,session);
// System.out.println("deferred removal scheduled="+obj.getName()+",wasLocked="+wasLocked);
// return false;
//}
lockMeta(session);
synchronized (this) {
//String savedName = obj.getName();
Comment comment = findComment(obj);
if (comment != null) {
removeDatabaseObject(session, comment);
......@@ -1925,40 +1917,10 @@ public class Database implements DataHandler {
obj.removeChildrenAndResources(session);
}
else{
//System.out.println("Starting database detected");
}
//System.out.println("Removing db object id - also remove meta lock from session and session lock from meta, id="+id+",sessionId="+session.getId()+",name="+savedName+",obj="+obj);
removeMeta(session, id);
//flushDeferredRemoveSchemaObject();
return true;
}
}
// public void flushDeferredRemoveSchemaObject() {
// boolean progress = true;
// while(progress){
// progress = false;
// Iterator<Entry<SchemaObject, Session>> i = removeSchemaObjectQueue.entrySet().iterator();
// while(i.hasNext()){
// Entry<SchemaObject, Session> pair = i.next();
// i.remove();
// //System.out.println("re-attempting deferred removal="+pair.getKey().getName()+",size="+removeSchemaObjectQueue.size());
// progress = removeSchemaObject(pair.getValue(),pair.getKey());
// if(progress){
// //System.out.println("completed deferred removal="+pair.getKey().getName()+",size="+removeSchemaObjectQueue.size());
// unlockMeta(pair.getValue());
// }
// }
// }
// //System.out.println("flushDeferredRemoveSchemaObject.remove_q_size="+removeSchemaObjectQueue.size());
// if(removeSchemaObjectQueue.size()!=0){
// traceLock();
// }
// }
return;
}
}
/**
* Check if this database is disk-based.
......
......@@ -173,7 +173,6 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
Prepared p;
session.pushSubQueryInfo(masks, filters, filter, sortOrder);
try {
//System.out.println("ViewIndex.prepareSubQuery:"+sql);
p = session.prepare(sql, true, true);
} finally {
session.popSubQueryInfo();
......
......@@ -88,7 +88,6 @@ public class MVTable extends TableBase {
private final ArrayList<Index> indexes = New.arrayList();
private volatile long lastModificationId;
private volatile Session lockExclusiveSession;
private volatile Throwable lockExclusiveSessionStackTrace;
// using a ConcurrentHashMap as a set
private final ConcurrentHashMap<Session, Session> lockSharedSessions =
......@@ -401,21 +400,6 @@ public class MVTable extends TableBase {
traceLock.debug("{0} {1} {2} {3}", session.getId(),
exclusive ? "exclusive write lock" : "shared read lock", statusText,
getName());
// // create a stack trace when the lock is granted so we can debug where that was...
// if(statusText.equals(TRACE_LOCK_ADDED_FOR) || statusText.equals(TRACE_LOCK_ADD_UPGRADED_FOR)){
// lockExclusiveSessionStackTrace = new Throwable("trace lock - lock granted stack trace");
// }
//
// // clear the stack trace of the granted lock, on unlock
// if(statusText.equals(TRACE_LOCK_UNLOCK)){
// lockExclusiveSessionStackTrace = null;
// }
//
// // show the stack trace where the lock was granted, if a timeout happens...
// if(statusText.contains(TRACE_LOCK_TIMEOUT_AFTER) && lockExclusiveSessionStackTrace!=null){
// lockExclusiveSessionStackTrace.printStackTrace();
// }
}
}
......@@ -426,17 +410,7 @@ public class MVTable extends TableBase {
@Override
public boolean isLockedExclusivelyBy(Session session) {
Session localSession = lockExclusiveSession;
if(localSession!=null){
//System.out.println("Meta was locked by "+localSession.getId()+" tested for "+session.getId());
if(lockExclusiveSessionStackTrace!=null){
lockExclusiveSessionStackTrace.printStackTrace();
}
}
else{
//System.out.println("Meta was not locked by anyone, tested for "+session.getId());
}
return localSession == session;
return lockExclusiveSession == session;
}
@Override
......
......@@ -87,8 +87,6 @@ public abstract class Table extends SchemaObjectBase {
private boolean onCommitDrop, onCommitTruncate;
private volatile Row nullRow;
private boolean tableExpression;
// private boolean isBeingDropped;
public Table(Schema schema, int id, String name, boolean persistIndexes,
boolean persistData) {
......@@ -529,7 +527,6 @@ public abstract class Table extends SchemaObjectBase {
public void removeChildrenAndResources(Session session) {
while (dependentViews.size() > 0) {
TableView view = dependentViews.get(0);
//System.out.println("removeChildrenAndResources.dependentViews:"+view.getName());
dependentViews.remove(0);
database.removeSchemaObject(session, view);
}
......@@ -836,14 +833,12 @@ public abstract class Table extends SchemaObjectBase {
}
/**
* Remove the given view from the list.
* Remove the given view from the dependent views list.
*
* @param view the view to remove
*/
public void removeDependentView(TableView view) {
//System.out.println("removeDependentView(Before):"+dependentViews.toString());
dependentViews.remove(view);
//System.out.println("removeDependentView(Left):"+dependentViews.toString());
}
/**
......@@ -1251,13 +1246,4 @@ public abstract class Table extends SchemaObjectBase {
public boolean isTableExpression() {
return tableExpression;
}
// public boolean isBeingDropped(){
// return isBeingDropped;
// }
//
// public void setBeingDropped(boolean isBeingDropped){
// this.isBeingDropped = isBeingDropped;
// }
}
......@@ -105,7 +105,6 @@ public class TableView extends Table {
this.isRecursiveQueryDetected = false;
this.isTableExpression = isTableExpression;
this.isPersistent = isPersistent;
//this.session = session;
index = new ViewIndex(this, querySQL, params, allowRecursive);
initColumnsAndTables(session, literalsChecked);
}
......@@ -519,7 +518,6 @@ public class TableView extends Table {
private void removeCurrentViewFromOtherTables() {
if (tables != null) {
for (Table t : tables) {
//System.out.println("removeCurrentViewFromOtherTables:"+t.getName());
t.removeDependentView(this);
}
tables.clear();
......@@ -555,8 +553,9 @@ public class TableView extends Table {
Schema mainSchema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN);
String querySQL = query.getPlanSQL();
TableView v = new TableView(mainSchema, 0, name,
querySQL, query.getParameters(), null, session,
false, true /* literals have already been checked when parsing original query */, false, false/* is persistent*/);
querySQL, query.getParameters(), null /* column templates */, session,
false/* allow recursive */, true /* literals have already been checked when parsing original query */,
false /* is table expression */, false/* is persistent*/);
if (v.createException != null) {
throw v.createException;
}
......@@ -714,24 +713,18 @@ public class TableView extends Table {
ArrayList<Parameter> parameters, Column[] columnTemplates, Session session,
boolean literalsChecked, boolean isTableExpression, boolean isPersistent, Database db){
//Table shadowTable = Parser.createShadowTableForRecursiveTableExpression(isPersistent, session, name, schema, Arrays.asList(columnTemplates), db);
// build with recursion turned on
TableView view = new TableView(schema, id, name, querySQL,
parameters, columnTemplates, session,
true/* try recursive */, literalsChecked, isTableExpression, isPersistent );
//System.out.println("create recursive view:"+view);
//if(shadowTable!=null){
// Parser.destroyShadowTableForRecursiveExpression(isPersistent, session, shadowTable);
//}
//System.out.println("view.isRecursiveQueryDetected()="+view.isRecursiveQueryDetected());
// is not recursion detected ? if so - recreate it without recursion flag
// is recursion really detected ? if not - recreate it without recursion flag and no recursive index
if (!view.isRecursiveQueryDetected()) {
if(isPersistent){
db.addSchemaObject(session, view);
view.lock(session, true, true);
session.getDatabase().removeSchemaObject(session, view);
// during database startup - this method does not normally get called - and it needs to be
// to correctly un-register the table which the table expression uses...
view.removeChildrenAndResources(session);
......@@ -741,7 +734,6 @@ public class TableView extends Table {
view = new TableView(schema, id, name, querySQL, parameters,
columnTemplates, session,
false/* detected not recursive */, literalsChecked, isTableExpression, isPersistent);
//System.out.println("create nr view:"+view);
}
return view;
......
......@@ -54,6 +54,7 @@ import org.h2.test.db.TestOpenClose;
import org.h2.test.db.TestOptimizations;
import org.h2.test.db.TestOptimizerHints;
import org.h2.test.db.TestOutOfMemory;
import org.h2.test.db.TestPersistentCommonTableExpressions;
import org.h2.test.db.TestPowerOff;
import org.h2.test.db.TestQueryCache;
import org.h2.test.db.TestReadOnly;
......@@ -761,9 +762,10 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestOutOfMemory());
addTest(new TestReadOnly());
addTest(new TestRecursiveQueries());
addTest(new TestGeneralCommonTableQueries());
if(!memory){
// requires persistent store for reconnection tests
addTest(new TestGeneralCommonTableQueries());
addTest(new TestPersistentCommonTableExpressions());
}
addTest(new TestRights());
addTest(new TestRunscript());
......
......@@ -8,7 +8,6 @@ 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.jdbc.JdbcSQLException;
import org.h2.test.TestBase;
......@@ -42,14 +41,6 @@ public class TestGeneralCommonTableQueries extends TestBase {
testMerge();
testCreateTable();
testNestedSQL();
testRecursiveTable();
// turn on special locking debug
//System.setProperty("h2.check2", "true");
// persistent cte tests - also tests reconnects and database reloading...
testPersistentNonRecursiveTableInCreateView();
testPersistentRecursiveTableInCreateView();
}
private void testSimpleSelect() throws Exception {
......@@ -477,192 +468,4 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close();
deleteDb("commonTableExpressionQueries");
}
private void testRecursiveTable() throws Exception {
int maxRetries = 4;
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n X\nFROM 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 */\nWHERE BB.A IS A.VAL)"};
int expectedNumberOfRows = 3;
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";
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
}
private void testPersistentRecursiveTableInCreateView() throws Exception {
String SETUP_SQL = "--SET TRACE_LEVEL_SYSTEM_OUT 3;\n"
+"DROP TABLE IF EXISTS my_tree; \n"
+"DROP VIEW IF EXISTS v_my_tree; \n"
+"CREATE TABLE my_tree ( \n"
+" id INTEGER, \n"
+" parent_fk INTEGER \n"
+"); \n"
+" \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 1, NULL ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 11, 1 ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 111, 11 ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 12, 1 ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 121, 12 ); \n"
+" \n"
+"CREATE OR REPLACE VIEW v_my_tree AS \n"
+"WITH RECURSIVE tree_cte (sub_tree_root_id, tree_level, parent_fk, child_fk) AS ( \n"
+" SELECT mt.ID AS sub_tree_root_id, CAST(0 AS INT) AS tree_level, mt.parent_fk, mt.id \n"
+" FROM my_tree mt \n"
+" UNION ALL \n"
+" SELECT sub_tree_root_id, mtc.tree_level + 1 AS tree_level, mtc.parent_fk, mt.id \n"
+" FROM my_tree mt \n"
+"INNER JOIN tree_cte mtc ON mtc.child_fk = mt.parent_fk \n"
+"), \n"
+"unused_cte AS ( SELECT 1 AS unUsedColumn ) \n"
+"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte; \n"
;
String WITH_QUERY = "SELECT * FROM v_my_tree";
int maxRetries = 4;
String[] expectedRowData =new String[]{"|1|0|null|1",
"|11|0|1|11",
"|111|0|11|111",
"|12|0|1|12",
"|121|0|12|121",
"|1|1|null|11",
"|11|1|1|111",
"|1|1|null|12",
"|12|1|1|121",
"|1|2|null|111",
"|1|2|null|121"
};
String[] expectedColumnNames =new String[]{"SUB_TREE_ROOT_ID","TREE_LEVEL","PARENT_FK","CHILD_FK"};
int expectedNumberOfRows = 11;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
}
private void testPersistentNonRecursiveTableInCreateView() throws Exception {
String SETUP_SQL = ""
+"DROP VIEW IF EXISTS v_my_nr_tree; \n"
+"DROP TABLE IF EXISTS my_table; \n"
+"CREATE TABLE my_table ( \n"
+" id INTEGER, \n"
+" parent_fk INTEGER \n"
+"); \n"
+" \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 1, NULL ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 11, 1 ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 111, 11 ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 12, 1 ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 121, 12 ); \n"
+" \n"
+"CREATE OR REPLACE VIEW v_my_nr_tree AS \n"
+"WITH tree_cte_nr (sub_tree_root_id, tree_level, parent_fk, child_fk) AS ( \n"
+" SELECT mt.ID AS sub_tree_root_id, CAST(0 AS INT) AS tree_level, mt.parent_fk, mt.id \n"
+" FROM my_table mt \n"
+"), \n"
+"unused_cte AS ( SELECT 1 AS unUsedColumn ) \n"
+"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte_nr; \n"
;
String WITH_QUERY = "SELECT * FROM v_my_nr_tree";
int maxRetries = 6;
String[] expectedRowData =new String[]{
"|1|0|null|1",
"|11|0|1|11",
"|111|0|11|111",
"|12|0|1|12",
"|121|0|12|121",
};
String[] expectedColumnNames =new String[]{"SUB_TREE_ROOT_ID","TREE_LEVEL","PARENT_FK","CHILD_FK"};
int expectedNumberOfRows = 5;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
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++){
//System.out.println("==================================== Iteration #"+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){
//System.out.println("Reconnecting to database on iteration#"+queryRunTries+" of "+maxRetries);
conn.close();
conn = getConnection("commonTableExpressionQueries");
}
//System.out.println("=========== test with query");
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");
}
}
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
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;
/**
* Test persistent common table expressions queries using WITH.
*/
public class TestPersistentCommonTableExpressions extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws Exception {
// persistent cte tests - also tests reconnects and database reloading...
testRecursiveTable();
testPersistentNonRecursiveTableInCreateView();
testPersistentRecursiveTableInCreateView();
}
private void testRecursiveTable() throws Exception {
int maxRetries = 4;
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n X\nFROM 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 */\nWHERE BB.A IS A.VAL)"};
int expectedNumberOfRows = 3;
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";
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
}
private void testPersistentRecursiveTableInCreateView() throws Exception {
String SETUP_SQL = "--SET TRACE_LEVEL_SYSTEM_OUT 3;\n"
+"DROP TABLE IF EXISTS my_tree; \n"
+"DROP VIEW IF EXISTS v_my_tree; \n"
+"CREATE TABLE my_tree ( \n"
+" id INTEGER, \n"
+" parent_fk INTEGER \n"
+"); \n"
+" \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 1, NULL ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 11, 1 ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 111, 11 ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 12, 1 ); \n"
+"INSERT INTO my_tree ( id, parent_fk) VALUES ( 121, 12 ); \n"
+" \n"
+"CREATE OR REPLACE VIEW v_my_tree AS \n"
+"WITH RECURSIVE tree_cte (sub_tree_root_id, tree_level, parent_fk, child_fk) AS ( \n"
+" SELECT mt.ID AS sub_tree_root_id, CAST(0 AS INT) AS tree_level, mt.parent_fk, mt.id \n"
+" FROM my_tree mt \n"
+" UNION ALL \n"
+" SELECT sub_tree_root_id, mtc.tree_level + 1 AS tree_level, mtc.parent_fk, mt.id \n"
+" FROM my_tree mt \n"
+"INNER JOIN tree_cte mtc ON mtc.child_fk = mt.parent_fk \n"
+"), \n"
+"unused_cte AS ( SELECT 1 AS unUsedColumn ) \n"
+"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte; \n"
;
String WITH_QUERY = "SELECT * FROM v_my_tree";
int maxRetries = 4;
String[] expectedRowData =new String[]{"|1|0|null|1",
"|11|0|1|11",
"|111|0|11|111",
"|12|0|1|12",
"|121|0|12|121",
"|1|1|null|11",
"|11|1|1|111",
"|1|1|null|12",
"|12|1|1|121",
"|1|2|null|111",
"|1|2|null|121"
};
String[] expectedColumnNames =new String[]{"SUB_TREE_ROOT_ID","TREE_LEVEL","PARENT_FK","CHILD_FK"};
int expectedNumberOfRows = 11;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
}
private void testPersistentNonRecursiveTableInCreateView() throws Exception {
String SETUP_SQL = ""
+"DROP VIEW IF EXISTS v_my_nr_tree; \n"
+"DROP TABLE IF EXISTS my_table; \n"
+"CREATE TABLE my_table ( \n"
+" id INTEGER, \n"
+" parent_fk INTEGER \n"
+"); \n"
+" \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 1, NULL ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 11, 1 ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 111, 11 ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 12, 1 ); \n"
+"INSERT INTO my_table ( id, parent_fk) VALUES ( 121, 12 ); \n"
+" \n"
+"CREATE OR REPLACE VIEW v_my_nr_tree AS \n"
+"WITH tree_cte_nr (sub_tree_root_id, tree_level, parent_fk, child_fk) AS ( \n"
+" SELECT mt.ID AS sub_tree_root_id, CAST(0 AS INT) AS tree_level, mt.parent_fk, mt.id \n"
+" FROM my_table mt \n"
+"), \n"
+"unused_cte AS ( SELECT 1 AS unUsedColumn ) \n"
+"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte_nr; \n"
;
String WITH_QUERY = "SELECT * FROM v_my_nr_tree";
int maxRetries = 6;
String[] expectedRowData =new String[]{
"|1|0|null|1",
"|11|0|1|11",
"|111|0|11|111",
"|12|0|1|12",
"|121|0|12|121",
};
String[] expectedColumnNames =new String[]{"SUB_TREE_ROOT_ID","TREE_LEVEL","PARENT_FK","CHILD_FK"};
int expectedNumberOfRows = 5;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
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");
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论