From 5da9c7ee7e85c929bbdb404a3619690fa6526bc1 Mon Sep 17 00:00:00 2001 From: gartens <41197811+gartens@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:26:31 +0200 Subject: [PATCH] Improve transaction handling in Prism Driver & Decimal validation (#514) --- .../db/algebra/core/CorrelationId.java | 2 +- .../org/polypheny/db/functions/Functions.java | 2 +- .../db/languages/LanguageManager.java | 21 +++---- .../polypheny/db/type/entity/PolyValue.java | 2 + .../org/polypheny/db/util/ByteString.java | 2 +- .../db/util/CaseInsensitiveComparator.java | 8 +-- .../db/processing/DataContextImpl.java | 2 +- .../db/transaction/TransactionImpl.java | 8 ++- .../db/jdbc/JdbcPreparedStatementsTest.java | 63 +++++++++++++++++++ .../db/sql/view/ComplexViewTest.java | 29 +++++++++ .../cottontail/util/CottontailTypeUtil.java | 2 + .../db/adapter/jdbc/ResultSetEnumerable.java | 4 +- .../jdbc/stores/AbstractJdbcStore.java | 2 +- .../polypheny/db/prisminterface/PIClient.java | 4 +- .../StatementProcessor.java | 2 + .../PIPreparedIndexedStatement.java | 44 +++++-------- .../statements/PIPreparedNamedStatement.java | 1 + .../statements/PIPreparedStatement.java | 2 + .../statements/PIStatement.java | 2 + .../PIUnparameterizedStatement.java | 1 + .../statements/StatementManager.java | 18 ++++-- 21 files changed, 162 insertions(+), 59 deletions(-) diff --git a/core/src/main/java/org/polypheny/db/algebra/core/CorrelationId.java b/core/src/main/java/org/polypheny/db/algebra/core/CorrelationId.java index 25fdba330f..b3eecd498e 100644 --- a/core/src/main/java/org/polypheny/db/algebra/core/CorrelationId.java +++ b/core/src/main/java/org/polypheny/db/algebra/core/CorrelationId.java @@ -109,7 +109,7 @@ public String toString() { @Override public int compareTo( CorrelationId other ) { - return id - other.id; + return Integer.compare( id, other.id ); } diff --git a/core/src/main/java/org/polypheny/db/functions/Functions.java b/core/src/main/java/org/polypheny/db/functions/Functions.java index 3fb9735e70..8f508b594a 100644 --- a/core/src/main/java/org/polypheny/db/functions/Functions.java +++ b/core/src/main/java/org/polypheny/db/functions/Functions.java @@ -2137,7 +2137,7 @@ public static PolyBoolean isNotFalse( PolyBoolean b ) { * NULL → NULL, FALSE → TRUE, TRUE → FALSE. */ public static PolyBoolean not( PolyBoolean b ) { - return PolyBoolean.of( !b.value ); + return b == null ? PolyBoolean.of( null ) : PolyBoolean.of( !b.value ); } diff --git a/core/src/main/java/org/polypheny/db/languages/LanguageManager.java b/core/src/main/java/org/polypheny/db/languages/LanguageManager.java index 9a253a020f..5ac68e7caa 100644 --- a/core/src/main/java/org/polypheny/db/languages/LanguageManager.java +++ b/core/src/main/java/org/polypheny/db/languages/LanguageManager.java @@ -130,6 +130,11 @@ public List anyPrepareQuery( QueryContext context, Statem String changedNamespace = null; for ( ParsedQueryContext parsed : parsedQueries ) { if ( i != 0 ) { + // as long as we directly commit the transaction, we cannot reuse the same transaction + if ( previousDdl && !transaction.isActive() ) { + transaction = parsed.getTransactionManager().startTransaction( transaction.getUser().id, transaction.getDefaultNamespace().id, transaction.isAnalyze(), transaction.getOrigin() ); + parsed.addTransaction( transaction ); + } statement = transaction.createStatement(); } if ( changedNamespace != null ) { @@ -155,22 +160,10 @@ public List anyPrepareQuery( QueryContext context, Statem new GenericRuntimeException( "DDL statement is not executable" ), implementationContexts ); } - // as long as we directly commit the transaction, we cannot reuse the same transaction - if ( previousDdl && !transaction.isActive() ) { - transaction = parsed.getTransactionManager().startTransaction( transaction.getUser().id, transaction.getDefaultNamespace().id, transaction.isAnalyze(), transaction.getOrigin() ); - statement = transaction.createStatement(); - parsed.addTransaction( transaction ); - } implementation = processor.prepareDdl( statement, (ExecutableStatement) parsed.getQueryNode().get(), parsed ); previousDdl = true; } else { - // as long as we directly commit the transaction, we cannot reuse the same transaction - if ( previousDdl && !transaction.isActive() ) { - transaction = parsed.getTransactionManager().startTransaction( transaction.getUser().id, transaction.getDefaultNamespace().id, transaction.isAnalyze(), transaction.getOrigin() ); - statement = transaction.createStatement(); - parsed.addTransaction( transaction ); - } previousDdl = false; if ( parsed.getLanguage().validatorSupplier() != null ) { if ( transaction.isAnalyze() ) { @@ -195,6 +188,10 @@ public List anyPrepareQuery( QueryContext context, Statem if ( transaction.isAnalyze() ) { statement.getOverviewDuration().stop( "Translation" ); } + + if ( !statement.getTransaction().isActive() ) { + log.warn( "Transaction is not active" ); + } implementation = statement.getQueryProcessor().prepareQuery( root, true ); } // queries are able to switch the context of the following queries diff --git a/core/src/main/java/org/polypheny/db/type/entity/PolyValue.java b/core/src/main/java/org/polypheny/db/type/entity/PolyValue.java index 679657a1fc..b8aa5466c6 100644 --- a/core/src/main/java/org/polypheny/db/type/entity/PolyValue.java +++ b/core/src/main/java/org/polypheny/db/type/entity/PolyValue.java @@ -799,6 +799,8 @@ public boolean isNumber() { public PolyNumber asNumber() { if ( isNumber() ) { return (PolyNumber) this; + } else if ( isString() ) { + return PolyFloat.convert( this.asString() ); } throw cannotParse( this, PolyNumber.class ); } diff --git a/core/src/main/java/org/polypheny/db/util/ByteString.java b/core/src/main/java/org/polypheny/db/util/ByteString.java index 5d9e8f3850..3d9ba9885a 100644 --- a/core/src/main/java/org/polypheny/db/util/ByteString.java +++ b/core/src/main/java/org/polypheny/db/util/ByteString.java @@ -103,7 +103,7 @@ public int compareTo( ByteString that ) { return c1 - c2; } } - return v1.length - v2.length; + return Integer.compare( v1.length, v2.length ); } diff --git a/core/src/main/java/org/polypheny/db/util/CaseInsensitiveComparator.java b/core/src/main/java/org/polypheny/db/util/CaseInsensitiveComparator.java index 0771f57740..ae4c2ba4c6 100644 --- a/core/src/main/java/org/polypheny/db/util/CaseInsensitiveComparator.java +++ b/core/src/main/java/org/polypheny/db/util/CaseInsensitiveComparator.java @@ -83,11 +83,11 @@ public int compare( Object o1, Object o2 ) { if ( c != 0 ) { return c; } - if ( o1 instanceof Key ) { - return ((Key) o1).compareResult; + if ( o1 instanceof Key key ) { + return key.compareResult; } - if ( o2 instanceof Key ) { - return -((Key) o2).compareResult; + if ( o2 instanceof Key key ) { + return -key.compareResult; } return s1.compareTo( s2 ); } diff --git a/dbms/src/main/java/org/polypheny/db/processing/DataContextImpl.java b/dbms/src/main/java/org/polypheny/db/processing/DataContextImpl.java index 0d2b3563a7..866dae5285 100644 --- a/dbms/src/main/java/org/polypheny/db/processing/DataContextImpl.java +++ b/dbms/src/main/java/org/polypheny/db/processing/DataContextImpl.java @@ -148,7 +148,7 @@ private PolyValue check( PolyValue value, AlgDataType type ) { switch ( type.getPolyType() ) { case DECIMAL -> { - if ( value.asNumber().toString().replace( ".", "" ).replace( "-", "" ).length() > type.getPrecision() ) { + if ( value.asNumber().toString().replaceFirst( "^0", "" ).replace( ".", "" ).replace( "-", "" ).length() > type.getPrecision() ) { throw new GenericRuntimeException( "Numeric value is too long" ); } } diff --git a/dbms/src/main/java/org/polypheny/db/transaction/TransactionImpl.java b/dbms/src/main/java/org/polypheny/db/transaction/TransactionImpl.java index 7d6e8da765..7abe1b83d4 100644 --- a/dbms/src/main/java/org/polypheny/db/transaction/TransactionImpl.java +++ b/dbms/src/main/java/org/polypheny/db/transaction/TransactionImpl.java @@ -199,6 +199,9 @@ public void commit() throws TransactionException { for ( Adapter adapter : involvedAdapters ) { adapter.commit( xid ); } + if ( involvedAdapters.isEmpty() ) { + log.debug( "No adapter used." ); + } this.statements.forEach( statement -> { if ( statement.getMonitoringEvent() != null ) { @@ -280,6 +283,9 @@ public Processor getProcessor( QueryLanguage language ) { @Override public StatementImpl createStatement() { + if ( !isActive() ) { + throw new IllegalStateException( "Transaction is not active!" ); + } StatementImpl statement = new StatementImpl( this ); statements.add( statement ); return statement; @@ -289,7 +295,7 @@ public StatementImpl createStatement() { @Override public int compareTo( @NonNull Object o ) { Transaction that = (Transaction) o; - return this.xid.hashCode() - that.getXid().hashCode(); + return Integer.compare( this.xid.hashCode(), that.getXid().hashCode() ); } diff --git a/dbms/src/test/java/org/polypheny/db/jdbc/JdbcPreparedStatementsTest.java b/dbms/src/test/java/org/polypheny/db/jdbc/JdbcPreparedStatementsTest.java index 38268c8850..9cc91dd357 100644 --- a/dbms/src/test/java/org/polypheny/db/jdbc/JdbcPreparedStatementsTest.java +++ b/dbms/src/test/java/org/polypheny/db/jdbc/JdbcPreparedStatementsTest.java @@ -1160,4 +1160,67 @@ public void arrayBatchTest() throws SQLException { } } + + @Test + public void transactionTest() throws SQLException { + try ( JdbcConnection polyphenyDbConnection = new JdbcConnection( false ) ) { + Connection connection = polyphenyDbConnection.getConnection(); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "CREATE TABLE transactions( " + + "id INTEGER PRIMARY KEY, " + + "ttext TEXT NOT NULL) " ); + + try { + PreparedStatement preparedInsert = connection.prepareStatement( "INSERT INTO transactions(id, ttext) VALUES (?, ?)" ); + + preparedInsert.setInt( 1, 1 ); + preparedInsert.setString( 2, "Row A" ); + preparedInsert.addBatch(); + + preparedInsert.setInt( 1, 2 ); + preparedInsert.setString( 2, "Row 2" ); + preparedInsert.addBatch(); + + preparedInsert.executeBatch(); + + connection.commit(); + } catch ( Throwable t ) { + statement.executeUpdate( "DROP TABLE transactions" ); + throw t; + } + } + } + + try ( JdbcConnection polyphenyDbConnection = new JdbcConnection( false ) ) { + Connection connection = polyphenyDbConnection.getConnection(); + try ( Statement statement = connection.createStatement() ) { + try { + PreparedStatement preparedSelect = connection.prepareStatement( "SELECT * FROM transactions WHERE id = ?" ); + preparedSelect.setInt( 1, 1 ); + preparedSelect.execute(); + preparedSelect.getResultSet().close(); + + PreparedStatement preparedUpdate = connection.prepareStatement( "UPDATE transactions SET ttext = ? WHERE id = ?" ); + preparedUpdate.setString( 1, "Row 1" ); + preparedUpdate.setInt( 2, 1 ); + preparedUpdate.execute(); + + connection.commit(); + + PreparedStatement preparedSelect2 = connection.prepareStatement( "SELECT * FROM transactions WHERE id = ?" ); + preparedSelect2.setInt( 1, 1 ); + preparedSelect2.execute(); + preparedSelect2.getResultSet().close(); + + preparedSelect.setInt( 1, 1 ); + preparedSelect.execute(); + + connection.commit(); + } finally { + statement.executeUpdate( "DROP TABLE transactions" ); + } + } + } + } + } diff --git a/dbms/src/test/java/org/polypheny/db/sql/view/ComplexViewTest.java b/dbms/src/test/java/org/polypheny/db/sql/view/ComplexViewTest.java index 921044dd9f..fbf431d751 100644 --- a/dbms/src/test/java/org/polypheny/db/sql/view/ComplexViewTest.java +++ b/dbms/src/test/java/org/polypheny/db/sql/view/ComplexViewTest.java @@ -22,6 +22,7 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.Date; +import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import lombok.extern.slf4j.Slf4j; @@ -1498,6 +1499,34 @@ public void testQ14() throws SQLException { } + @Test + public void testCast() throws SQLException { + try ( JdbcConnection polyphenyDbConnection = new JdbcConnection( true ) ) { + Connection connection = polyphenyDbConnection.getConnection(); + try ( Statement statement = connection.createStatement() ) { + initTables( statement ); + + try { + String query = """ + SELECT l_extendedprice + FROM + lineitem + WHERE + l_extendedprice >= cast(? as Integer)"""; + + PreparedStatement prepare = connection.prepareStatement( query ); + prepare.setString( 1, "3" ); + prepare.execute(); + connection.commit(); + } finally { + connection.rollback(); + dropTables( statement ); + } + } + } + } + + @Test public void testQ15() throws SQLException { try ( JdbcConnection polyphenyDbConnection = new JdbcConnection( true ) ) { diff --git a/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/util/CottontailTypeUtil.java b/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/util/CottontailTypeUtil.java index bc6195694a..9e0ea889e4 100644 --- a/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/util/CottontailTypeUtil.java +++ b/plugins/cottontail-adapter/src/main/java/org/polypheny/db/adapter/cottontail/util/CottontailTypeUtil.java @@ -277,6 +277,8 @@ public static CottontailGrpc.Literal toData( PolyValue value, PolyType actualTyp case DECIMAL: { if ( value.isNumber() ) { return builder.setStringData( value.asNumber().BigDecimalValue().toString() ).build(); + } else if ( value.isString() ) { + return builder.setStringData( value.asString().value ).build(); } break; } diff --git a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/ResultSetEnumerable.java b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/ResultSetEnumerable.java index 75449ae32a..c3c6badf67 100644 --- a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/ResultSetEnumerable.java +++ b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/ResultSetEnumerable.java @@ -411,7 +411,7 @@ private Enumerator enumeratorBasedOnStatement() { int updateCount = statement.getUpdateCount(); return Linq4j.singletonEnumerator( new PolyValue[]{ PolyLong.of( updateCount ) } ); } - } catch ( SQLException e ) { + } catch ( Throwable e ) { throw Static.RESOURCE.exceptionWhilePerformingQueryOnJdbcSubSchema( sql ).ex( e ); } finally { closeIfPossible( statement ); @@ -439,7 +439,7 @@ private Enumerator enumeratorBasedOnPreparedStatement() { return Linq4j.singletonEnumerator( new PolyValue[]{ PolyLong.of( updateCount ) } ); } } - } catch ( SQLException e ) { + } catch ( Throwable e ) { throw Static.RESOURCE.exceptionWhilePerformingQueryOnJdbcSubSchema( sql ).ex( e ); } finally { closeIfPossible( preparedStatement ); diff --git a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/stores/AbstractJdbcStore.java b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/stores/AbstractJdbcStore.java index 2e4eec76ab..584cc712c8 100644 --- a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/stores/AbstractJdbcStore.java +++ b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/stores/AbstractJdbcStore.java @@ -466,7 +466,7 @@ public void commit( PolyXid xid ) { if ( connectionFactory.hasConnectionHandler( xid ) ) { try { connectionFactory.getConnectionHandler( xid ).commit(); - } catch ( ConnectionHandlerException e ) { + } catch ( Throwable e ) { throw new GenericRuntimeException( e ); } } else { diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/PIClient.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/PIClient.java index a4953ceb47..4e3aba4118 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/PIClient.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/PIClient.java @@ -32,6 +32,8 @@ public class PIClient { @Getter private final String clientUUID; private final LogicalUser catalogUser; + @Getter + @Setter private Transaction currentTransaction; private final TransactionManager transactionManager; @Getter @@ -94,7 +96,7 @@ private void commitCurrentTransactionUnsynchronized() throws PIServiceException } try { currentTransaction.commit(); - } catch ( TransactionException e ) { + } catch ( Throwable e ) { throw new PIServiceException( "Committing current transaction failed: " + e.getMessage() ); } finally { clearCurrentTransaction(); diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statementProcessing/StatementProcessor.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statementProcessing/StatementProcessor.java index 820b1ec018..9af54b719a 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statementProcessing/StatementProcessor.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statementProcessing/StatementProcessor.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import org.polypheny.db.algebra.type.AlgDataType; +import org.polypheny.db.algebra.type.AlgDataTypeField; import org.polypheny.db.catalog.exceptions.GenericRuntimeException; import org.polypheny.db.catalog.logistic.DataModel; import org.polypheny.db.languages.LanguageManager; @@ -143,6 +144,7 @@ public static void prepare( PIPreparedStatement piStatement ) { Pair validated = queryProcessor.validate( transaction, parsed, false ); AlgDataType parameterRowType = queryProcessor.getParameterRowType( validated.left ); piStatement.setParameterMetas( RelationalMetaRetriever.retrieveParameterMetas( parameterRowType ) ); + piStatement.setParameterPolyTypes( parameterRowType.getFields().stream().map( AlgDataTypeField::getType ).toList() ); } } diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedIndexedStatement.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedIndexedStatement.java index abc538014a..ec5eb97051 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedIndexedStatement.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedIndexedStatement.java @@ -39,6 +39,7 @@ public class PIPreparedIndexedStatement extends PIPreparedStatement { private final String query; + @Setter private Statement statement; @Setter private PolyImplementation implementation; @@ -64,7 +65,7 @@ public List executeBatch( List> valuesBatch ) { } else { statement.getDataContext().resetParameterValues(); } - List types = IntStream.range( 0, valuesBatch.size() ).mapToObj( i -> deriveType( statement.getTransaction().getTypeFactory(), parameterMetas.get( i ) ) ).toList(); + List types = IntStream.range( 0, valuesBatch.size() ).mapToObj( i -> deriveType( statement.getTransaction().getTypeFactory(), parameterPolyTypes.get( i ) ) ).toList(); int i = 0; for ( List column : valuesBatch ) { statement.getDataContext().addParameterValues( i, types.get( i++ ), column ); @@ -83,11 +84,11 @@ public StatementResult execute( List values, List para } else { statement.getDataContext().resetParameterValues(); } - long index = 0; + int index = 0; for ( PolyValue value : values ) { if ( value != null ) { AlgDataType algDataType = parameterMetas.size() > index - ? deriveType( statement.getTransaction().getTypeFactory(), parameterMetas.get( (int) index ) ) + ? deriveType( statement.getTransaction().getTypeFactory(), parameterPolyTypes.get( index ) ) : statement.getTransaction().getTypeFactory().createPolyType( value.type ); statement.getDataContext().addParameterValues( index++, algDataType, List.of( value ) ); } @@ -97,9 +98,10 @@ public StatementResult execute( List values, List para } - private AlgDataType deriveType( JavaTypeFactory typeFactory, ParameterMeta parameterMeta ) { - return switch ( parameterMeta.getTypeName().toUpperCase() ) { - case "DECIMAL" -> { + private AlgDataType deriveType( JavaTypeFactory typeFactory, AlgDataType parameterMeta ) { + PolyType type = parameterMeta.getPolyType(); + return switch ( type ) { + case DECIMAL -> { if ( parameterMeta.getPrecision() >= 0 && parameterMeta.getScale() >= 0 ) { yield typeFactory.createPolyType( PolyType.DECIMAL, parameterMeta.getPrecision(), parameterMeta.getScale() ); } else if ( parameterMeta.getPrecision() >= 0 ) { @@ -107,57 +109,43 @@ private AlgDataType deriveType( JavaTypeFactory typeFactory, ParameterMeta param } yield typeFactory.createPolyType( PolyType.DECIMAL ); } - case "DOUBLE" -> typeFactory.createPolyType( PolyType.DOUBLE ); - case "FLOAT" -> typeFactory.createPolyType( PolyType.FLOAT ); - case "INT", "INTEGER" -> typeFactory.createPolyType( PolyType.INTEGER ); - case "VARCHAR" -> { + case VARCHAR -> { if ( parameterMeta.getPrecision() > 0 ) { yield typeFactory.createPolyType( PolyType.VARCHAR, parameterMeta.getPrecision() ); } yield typeFactory.createPolyType( PolyType.VARCHAR ); } - case "CHAR" -> { + case CHAR -> { if ( parameterMeta.getPrecision() > 0 ) { yield typeFactory.createPolyType( PolyType.CHAR, parameterMeta.getPrecision() ); } yield typeFactory.createPolyType( PolyType.CHAR ); } - case "TEXT" -> typeFactory.createPolyType( PolyType.TEXT ); - case "JSON" -> typeFactory.createPolyType( PolyType.JSON ); - case "BOOLEAN" -> typeFactory.createPolyType( PolyType.BOOLEAN ); - case "TINYINT" -> typeFactory.createPolyType( PolyType.TINYINT ); - case "SMALLINT" -> typeFactory.createPolyType( PolyType.SMALLINT ); - case "BIGINT" -> typeFactory.createPolyType( PolyType.BIGINT ); - case "DATE" -> typeFactory.createPolyType( PolyType.DATE ); - case "TIME" -> { + case TIME -> { if ( parameterMeta.getPrecision() >= 0 ) { yield typeFactory.createPolyType( PolyType.TIME, parameterMeta.getPrecision() ); } yield typeFactory.createPolyType( PolyType.TIME ); } - case "TIMESTAMP" -> { + case TIMESTAMP -> { if ( parameterMeta.getPrecision() >= 0 ) { yield typeFactory.createPolyType( PolyType.TIMESTAMP, parameterMeta.getPrecision() ); } yield typeFactory.createPolyType( PolyType.TIMESTAMP ); } - case "BINARY" -> { + case BINARY -> { if ( parameterMeta.getPrecision() > 0 ) { yield typeFactory.createPolyType( PolyType.BINARY, parameterMeta.getPrecision() ); } yield typeFactory.createPolyType( PolyType.BINARY ); } - case "VARBINARY" -> { + case VARBINARY -> { if ( parameterMeta.getPrecision() > 0 ) { yield typeFactory.createPolyType( PolyType.VARBINARY, parameterMeta.getPrecision() ); } yield typeFactory.createPolyType( PolyType.VARBINARY ); } - case "FILE" -> typeFactory.createPolyType( PolyType.FILE ); - case "IMAGE" -> typeFactory.createPolyType( PolyType.IMAGE ); - case "VIDEO" -> typeFactory.createPolyType( PolyType.VIDEO ); - case "AUDIO" -> typeFactory.createPolyType( PolyType.AUDIO ); - default -> typeFactory.createPolyType( PolyType.valueOf( parameterMeta.getTypeName() ) ); + default -> typeFactory.createPolyType( type ); }; } @@ -173,7 +161,7 @@ public void close() { @Override public Transaction getTransaction() { - return statement.getTransaction(); + return statement != null ? statement.getTransaction() : null; } } diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedNamedStatement.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedNamedStatement.java index f2fefeb363..9dadddf7c0 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedNamedStatement.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedNamedStatement.java @@ -39,6 +39,7 @@ public class PIPreparedNamedStatement extends PIPreparedStatement { @Setter private PolyImplementation implementation; @Getter + @Setter private Statement statement; private final NamedValueProcessor namedValueProcessor; diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedStatement.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedStatement.java index 402a5db79b..548bf52813 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedStatement.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIPreparedStatement.java @@ -19,6 +19,7 @@ import java.util.List; import lombok.Setter; import org.jetbrains.annotations.NotNull; +import org.polypheny.db.algebra.type.AlgDataType; import org.polypheny.db.catalog.entity.logical.LogicalNamespace; import org.polypheny.db.languages.QueryLanguage; import org.polypheny.db.prisminterface.PIClient; @@ -29,6 +30,7 @@ public abstract class PIPreparedStatement extends PIStatement implements Signaturizable { protected List parameterMetas; + protected List parameterPolyTypes; public List getParameterMetas() { diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIStatement.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIStatement.java index d31ca34a07..cab7974762 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIStatement.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIStatement.java @@ -74,6 +74,8 @@ public void closeResults() { public abstract void setImplementation( PolyImplementation implementation ); + public abstract void setStatement( Statement statement ); + public abstract Statement getStatement(); public abstract String getQuery(); diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIUnparameterizedStatement.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIUnparameterizedStatement.java index 7229b2d2f0..1ce4d162df 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIUnparameterizedStatement.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/PIUnparameterizedStatement.java @@ -33,6 +33,7 @@ public class PIUnparameterizedStatement extends PIStatement { private final String query; + @Setter private Statement statement; @Setter private PolyImplementation implementation; diff --git a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/StatementManager.java b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/StatementManager.java index 354b73f54e..b023c2daa2 100644 --- a/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/StatementManager.java +++ b/plugins/prism-interface/src/main/java/org/polypheny/db/prisminterface/statements/StatementManager.java @@ -17,6 +17,7 @@ package org.polypheny.db.prisminterface.statements; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -28,6 +29,7 @@ import org.polypheny.db.languages.QueryLanguage; import org.polypheny.db.prisminterface.PIClient; import org.polypheny.db.prisminterface.PIServiceException; +import org.polypheny.db.transaction.Statement; import org.polypheny.prism.ExecuteUnparameterizedStatementRequest; import org.polypheny.prism.PrepareStatementRequest; @@ -36,8 +38,8 @@ public class StatementManager { private final AtomicInteger statementIdGenerator; private final PIClient client; - private ConcurrentHashMap openStatements; - private ConcurrentHashMap openUnparameterizedBatches; + private final Map openStatements; + private final Map openUnparameterizedBatches; public StatementManager( PIClient client ) { @@ -190,25 +192,29 @@ public PIStatement getStatement( int statementId ) { if ( statement == null ) { throw new PIServiceException( "A statement with id " + statementId + " does not exist for that client" ); } + Statement s = statement.getStatement(); + if ( s != null && s.getTransaction().getId() != client.getOrCreateNewTransaction().getId() ) { + statement.setStatement( client.getCurrentTransaction().createStatement() ); + } return statement; } public PIPreparedNamedStatement getNamedPreparedStatement( int statementId ) throws PIServiceException { PIStatement statement = getStatement( statementId ); - if ( !(statement instanceof PIPreparedNamedStatement) ) { + if ( !(statement instanceof PIPreparedNamedStatement prepared) ) { throw new PIServiceException( "A named prepared statement with id " + statementId + " does not exist for that client" ); } - return (PIPreparedNamedStatement) statement; + return prepared; } public PIPreparedIndexedStatement getIndexedPreparedStatement( int statementId ) throws PIServiceException { PIStatement statement = getStatement( statementId ); - if ( !(statement instanceof PIPreparedIndexedStatement) ) { + if ( !(statement instanceof PIPreparedIndexedStatement prepared) ) { throw new PIServiceException( "A prepared indexed statement with id " + statementId + " does not exist for that client" ); } - return (PIPreparedIndexedStatement) statement; + return prepared; }