diff --git a/core/src/main/java/org/polypheny/db/adapter/DataSource.java b/core/src/main/java/org/polypheny/db/adapter/DataSource.java index 6234046bfd..062edf3e69 100644 --- a/core/src/main/java/org/polypheny/db/adapter/DataSource.java +++ b/core/src/main/java/org/polypheny/db/adapter/DataSource.java @@ -60,6 +60,7 @@ public static class ExportedColumn { public final String physicalColumnName; public final int physicalPosition; public final boolean primary; + public final boolean autoIncrement; public String getDisplayType() { diff --git a/core/src/main/java/org/polypheny/db/adapter/RelationalModifyDelegate.java b/core/src/main/java/org/polypheny/db/adapter/RelationalModifyDelegate.java index 8e37fe5e51..cd5c9c73c8 100644 --- a/core/src/main/java/org/polypheny/db/adapter/RelationalModifyDelegate.java +++ b/core/src/main/java/org/polypheny/db/adapter/RelationalModifyDelegate.java @@ -112,8 +112,8 @@ public void dropGraph( Context context, AllocationGraph allocation ) { @Override public List createCollection( Context context, LogicalCollection logical, AllocationCollection allocation ) { PhysicalTable physical = Scannable.createSubstitutionTable( modifiable, context, logical, allocation, "_doc_", List.of( - new ColumnContext( DocumentType.DOCUMENT_ID, null, PolyType.TEXT, false ), - new ColumnContext( DocumentType.DOCUMENT_DATA, null, PolyType.TEXT, true ) ), 1 ); + new ColumnContext( DocumentType.DOCUMENT_ID, null, PolyType.TEXT, false, false ), + new ColumnContext( DocumentType.DOCUMENT_DATA, null, PolyType.TEXT, true, false ) ), 1 ); catalog.addPhysical( allocation, physical ); return List.of( physical ); diff --git a/core/src/main/java/org/polypheny/db/adapter/Scannable.java b/core/src/main/java/org/polypheny/db/adapter/Scannable.java index 1d775179f9..cab57e2108 100644 --- a/core/src/main/java/org/polypheny/db/adapter/Scannable.java +++ b/core/src/main/java/org/polypheny/db/adapter/Scannable.java @@ -60,7 +60,7 @@ static PhysicalEntity createSubstitutionEntity( Scannable scannable, Context con int i = 0; for ( ColumnContext col : columnsInformations ) { - LogicalColumn column = new LogicalColumn( builder.getNewFieldId(), col.name, table.id, table.namespaceId, i, col.type, null, col.precision, null, null, null, col.nullable, Collation.getDefaultCollation(), null ); + LogicalColumn column = new LogicalColumn( builder.getNewFieldId(), col.name, table.id, table.namespaceId, i, col.type, null, col.precision, null, null, null, col.nullable, Collation.getDefaultCollation(), null, col.autoIncrement ); columns.add( column ); i++; } @@ -170,24 +170,24 @@ static AlgNode getDocumentScanSubstitute( Scannable scannable, long allocId, Alg static List createGraphSubstitute( Scannable scannable, Context context, LogicalGraph logical, AllocationGraph allocation ) { PhysicalEntity node = createSubstitutionEntity( scannable, context, logical, allocation, "_node_", List.of( - new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false ), - new ColumnContext( "label", null, PolyType.TEXT, false ) ), 2 ); + new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false, false ), + new ColumnContext( "label", null, PolyType.TEXT, false, false ) ), 2 ); PhysicalEntity nProperties = createSubstitutionEntity( scannable, context, logical, allocation, "_nProperties_", List.of( - new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false ), - new ColumnContext( "key", null, PolyType.TEXT, false ), - new ColumnContext( "value", null, PolyType.TEXT, true ) ), 2 ); + new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false, false ), + new ColumnContext( "key", null, PolyType.TEXT, false, false ), + new ColumnContext( "value", null, PolyType.TEXT, true, false ) ), 2 ); PhysicalEntity edge = createSubstitutionEntity( scannable, context, logical, allocation, "_edge_", List.of( - new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false ), - new ColumnContext( "label", null, PolyType.TEXT, true ), - new ColumnContext( "_l_id_", GraphType.ID_SIZE, PolyType.VARCHAR, true ), - new ColumnContext( "_r_id_", GraphType.ID_SIZE, PolyType.VARCHAR, true ) ), 1 ); + new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false, false ), + new ColumnContext( "label", null, PolyType.TEXT, true, false ), + new ColumnContext( "_l_id_", GraphType.ID_SIZE, PolyType.VARCHAR, true, false ), + new ColumnContext( "_r_id_", GraphType.ID_SIZE, PolyType.VARCHAR, true, false ) ), 1 ); PhysicalEntity eProperties = createSubstitutionEntity( scannable, context, logical, allocation, "_eProperties_", List.of( - new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false ), - new ColumnContext( "key", null, PolyType.TEXT, false ), - new ColumnContext( "value", null, PolyType.TEXT, true ) ), 2 ); + new ColumnContext( "id", GraphType.ID_SIZE, PolyType.VARCHAR, false, false ), + new ColumnContext( "key", null, PolyType.TEXT, false, false ), + new ColumnContext( "value", null, PolyType.TEXT, true, false ) ), 2 ); scannable.getCatalog().addPhysical( allocation, node, nProperties, edge, eProperties ); return List.of( node, nProperties, edge, eProperties ); @@ -222,8 +222,8 @@ static void dropGraphSubstitute( Scannable scannable, Context context, Allocatio static List createCollectionSubstitute( Scannable scannable, Context context, LogicalCollection logical, AllocationCollection allocation ) { PhysicalEntity doc = createSubstitutionEntity( scannable, context, logical, allocation, "_doc_", List.of( - new ColumnContext( DocumentType.DOCUMENT_ID, null, PolyType.TEXT, false ), - new ColumnContext( DocumentType.DOCUMENT_DATA, null, PolyType.TEXT, false ) ), 1 ); + new ColumnContext( DocumentType.DOCUMENT_ID, null, PolyType.TEXT, false, false ), + new ColumnContext( DocumentType.DOCUMENT_DATA, null, PolyType.TEXT, false, false ) ), 1 ); scannable.getCatalog().addPhysical( allocation, doc ); return List.of( doc ); @@ -250,7 +250,7 @@ static void dropCollectionSubstitute( Scannable scannable, Context context, Allo void renameLogicalColumn( long id, String newColumnName ); - record ColumnContext( String name, Integer precision, PolyType type, boolean nullable ) { + record ColumnContext( String name, Integer precision, PolyType type, boolean nullable, boolean autoIncrement ) { } diff --git a/core/src/main/java/org/polypheny/db/algebra/type/AlgDataType.java b/core/src/main/java/org/polypheny/db/algebra/type/AlgDataType.java index d6a27184c0..d3142cb13f 100644 --- a/core/src/main/java/org/polypheny/db/algebra/type/AlgDataType.java +++ b/core/src/main/java/org/polypheny/db/algebra/type/AlgDataType.java @@ -130,6 +130,8 @@ default AlgDataType asGraph() { */ boolean isNullable(); + boolean isAutoIncrement(); + /** * Gets the component type if this type is a collection, otherwise null. * diff --git a/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeFactoryImpl.java b/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeFactoryImpl.java index a2d6aeecf1..3fa6f6b1c0 100644 --- a/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeFactoryImpl.java +++ b/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeFactoryImpl.java @@ -591,6 +591,11 @@ public boolean isNullable() { return nullable; } + @Override + public boolean isAutoIncrement() { + return false; + } + @Override public AlgDataTypeFamily getFamily() { diff --git a/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeImpl.java b/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeImpl.java index 6516e35704..7538dd26e5 100644 --- a/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeImpl.java +++ b/core/src/main/java/org/polypheny/db/algebra/type/AlgDataTypeImpl.java @@ -232,6 +232,11 @@ public boolean isNullable() { return false; } + @Override + public boolean isAutoIncrement() { + return false; + } + @Override public Charset getCharset() { diff --git a/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java b/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java index a49b875501..94be2d82a6 100644 --- a/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java +++ b/core/src/main/java/org/polypheny/db/algebra/type/DocumentType.java @@ -183,6 +183,11 @@ public boolean isNullable() { return false; } + @Override + public boolean isAutoIncrement() { + return false; + } + @Override public AlgDataType getComponentType() { diff --git a/core/src/main/java/org/polypheny/db/algebra/type/GraphType.java b/core/src/main/java/org/polypheny/db/algebra/type/GraphType.java index 14fa621215..6c57b464af 100644 --- a/core/src/main/java/org/polypheny/db/algebra/type/GraphType.java +++ b/core/src/main/java/org/polypheny/db/algebra/type/GraphType.java @@ -131,6 +131,11 @@ public boolean isNullable() { return false; } + @Override + public boolean isAutoIncrement() { + return false; + } + @Override public AlgDataType getComponentType() { diff --git a/core/src/main/java/org/polypheny/db/catalog/catalogs/LogicalRelationalCatalog.java b/core/src/main/java/org/polypheny/db/catalog/catalogs/LogicalRelationalCatalog.java index d9e35236a6..6ea08f0ece 100644 --- a/core/src/main/java/org/polypheny/db/catalog/catalogs/LogicalRelationalCatalog.java +++ b/core/src/main/java/org/polypheny/db/catalog/catalogs/LogicalRelationalCatalog.java @@ -121,7 +121,7 @@ public interface LogicalRelationalCatalog extends LogicalCatalog { * @param collation The collation of the field (if applicable, else null) * @return The id of the inserted column */ - LogicalColumn addColumn( String name, long tableId, int position, PolyType type, PolyType collectionsType, Integer length, Integer scale, Integer dimension, Integer cardinality, boolean nullable, Collation collation ); + LogicalColumn addColumn( String name, long tableId, int position, PolyType type, PolyType collectionsType, Integer length, Integer scale, Integer dimension, Integer cardinality, boolean nullable, Collation collation, boolean autoIncrement ); /** diff --git a/core/src/main/java/org/polypheny/db/catalog/entity/logical/LogicalColumn.java b/core/src/main/java/org/polypheny/db/catalog/entity/logical/LogicalColumn.java index 18b75cc056..3d3d7d439f 100644 --- a/core/src/main/java/org/polypheny/db/catalog/entity/logical/LogicalColumn.java +++ b/core/src/main/java/org/polypheny/db/catalog/entity/logical/LogicalColumn.java @@ -21,6 +21,7 @@ import io.activej.serializer.annotations.Serialize; import io.activej.serializer.annotations.SerializeNullable; import java.io.Serial; +import java.util.concurrent.atomic.AtomicLong; import lombok.NonNull; import lombok.Value; import lombok.experimental.NonFinal; @@ -91,6 +92,12 @@ public class LogicalColumn implements PolyObject, Comparable { @JsonProperty public boolean nullable; + @Serialize + @JsonProperty + public boolean autoIncrement; + + public AtomicLong currentValue = new AtomicLong(0l); + @Serialize @JsonProperty public @SerializeNullable Collation collation; @@ -117,7 +124,8 @@ public LogicalColumn( @Deserialize("cardinality") final Integer cardinality, @Deserialize("nullable") final boolean nullable, @Deserialize("collation") final Collation collation, - @Deserialize("defaultValue") final LogicalDefaultValue defaultValue ) { + @Deserialize("defaultValue") final LogicalDefaultValue defaultValue, + @Deserialize("autoIncrement") final boolean autoIncrement) { this.id = id; this.name = name; this.tableId = tableId; @@ -132,6 +140,7 @@ public LogicalColumn( this.nullable = nullable; this.collation = collation; this.defaultValue = defaultValue; + this.autoIncrement = autoIncrement; } diff --git a/core/src/main/java/org/polypheny/db/catalog/impl/logical/RelationalCatalog.java b/core/src/main/java/org/polypheny/db/catalog/impl/logical/RelationalCatalog.java index 568eedd67e..74de105425 100644 --- a/core/src/main/java/org/polypheny/db/catalog/impl/logical/RelationalCatalog.java +++ b/core/src/main/java/org/polypheny/db/catalog/impl/logical/RelationalCatalog.java @@ -292,9 +292,9 @@ public void deleteKey( long id ) { @Override - public LogicalColumn addColumn( String name, long tableId, int position, PolyType type, PolyType collectionsType, Integer length, Integer scale, Integer dimension, Integer cardinality, boolean nullable, Collation collation ) { + public LogicalColumn addColumn( String name, long tableId, int position, PolyType type, PolyType collectionsType, Integer length, Integer scale, Integer dimension, Integer cardinality, boolean nullable, Collation collation, boolean autoIncrement ) { long id = idBuilder.getNewFieldId(); - LogicalColumn column = new LogicalColumn( id, name, tableId, logicalNamespace.id, position, type, collectionsType, length, scale, dimension, cardinality, nullable, collation, null ); + LogicalColumn column = new LogicalColumn( id, name, tableId, logicalNamespace.id, position, type, collectionsType, length, scale, dimension, cardinality, nullable, collation, null, autoIncrement ); columns.put( id, column ); change( CatalogEvent.LOGICAL_REL_FIELD_CREATED, null, id ); return column; diff --git a/core/src/main/java/org/polypheny/db/ddl/DdlManager.java b/core/src/main/java/org/polypheny/db/ddl/DdlManager.java index c4c8653198..79e41fd70d 100644 --- a/core/src/main/java/org/polypheny/db/ddl/DdlManager.java +++ b/core/src/main/java/org/polypheny/db/ddl/DdlManager.java @@ -166,7 +166,7 @@ public static DdlManager getInstance() { * @param defaultValue a default value for the column; can be null * @param statement the query statement */ - public abstract void createColumn( String columnName, LogicalTable table, String beforeColumnName, String afterColumnName, ColumnTypeInformation type, boolean nullable, PolyValue defaultValue, Statement statement ); + public abstract void createColumn( String columnName, LogicalTable table, String beforeColumnName, String afterColumnName, ColumnTypeInformation type, boolean nullable, PolyValue defaultValue, Statement statement, boolean autoIncrement ); /** * Add a foreign key to a table @@ -605,7 +605,7 @@ public ConstraintInformation( String name, ConstraintType type, List col * decoupled from the used query language */ - public record ColumnTypeInformation( PolyType type, @Nullable PolyType collectionType, Integer precision, Integer scale, Integer dimension, Integer cardinality, Boolean nullable ) { + public record ColumnTypeInformation( PolyType type, @Nullable PolyType collectionType, Integer precision, Integer scale, Integer dimension, Integer cardinality, Boolean nullable, Boolean autoIncrement ) { public ColumnTypeInformation( PolyType type, @@ -614,7 +614,8 @@ public ColumnTypeInformation( Integer scale, Integer dimension, Integer cardinality, - Boolean nullable ) { + Boolean nullable, + Boolean autoIncrement ) { this.type = type; this.collectionType = collectionType == type ? null : collectionType; this.precision = precision == null || precision == -1 ? null : precision; @@ -622,6 +623,18 @@ public ColumnTypeInformation( this.dimension = dimension == null || dimension == -1 ? null : dimension; this.cardinality = cardinality == null || cardinality == -1 ? null : cardinality; this.nullable = nullable; + this.autoIncrement = autoIncrement == null ? false : autoIncrement; + } + + public ColumnTypeInformation( + PolyType type, + @Nullable PolyType collectionType, + Integer precision, + Integer scale, + Integer dimension, + Integer cardinality, + Boolean nullable ) { + this(type, collectionType, precision, scale, dimension, cardinality, nullable, false); } @@ -633,7 +646,8 @@ public static ColumnTypeInformation fromDataTypeSpec( DataTypeSpec sqlDataType ) sqlDataType.getScale(), sqlDataType.getDimension(), sqlDataType.getCardinality(), - sqlDataType.getNullable() ); + sqlDataType.getNullable(), + sqlDataType.getAutoIncrement()); } } diff --git a/core/src/main/java/org/polypheny/db/nodes/DataTypeSpec.java b/core/src/main/java/org/polypheny/db/nodes/DataTypeSpec.java index a47e4b2a33..ef1acd0602 100644 --- a/core/src/main/java/org/polypheny/db/nodes/DataTypeSpec.java +++ b/core/src/main/java/org/polypheny/db/nodes/DataTypeSpec.java @@ -35,6 +35,8 @@ public interface DataTypeSpec extends Visitable { Boolean getNullable(); + Boolean getAutoIncrement(); + Identifier getCollectionsTypeName(); PolyType getCollectionsType(); diff --git a/core/src/main/java/org/polypheny/db/type/AbstractPolyType.java b/core/src/main/java/org/polypheny/db/type/AbstractPolyType.java index 124f1b0086..254292fb68 100644 --- a/core/src/main/java/org/polypheny/db/type/AbstractPolyType.java +++ b/core/src/main/java/org/polypheny/db/type/AbstractPolyType.java @@ -50,6 +50,7 @@ public abstract class AbstractPolyType extends AlgDataTypeImpl implements Clonea protected final PolyType typeName; protected boolean isNullable; + protected boolean isAutoIncrement; /** @@ -79,6 +80,11 @@ public boolean isNullable() { return isNullable; } + @Override + public boolean isAutoIncrement() { + return isAutoIncrement; + } + // implement RelDataType @Override diff --git a/dbms/src/main/java/org/polypheny/db/ddl/DdlManagerImpl.java b/dbms/src/main/java/org/polypheny/db/ddl/DdlManagerImpl.java index 81f973d537..bebb71b114 100644 --- a/dbms/src/main/java/org/polypheny/db/ddl/DdlManagerImpl.java +++ b/dbms/src/main/java/org/polypheny/db/ddl/DdlManagerImpl.java @@ -254,7 +254,8 @@ public void createSource( String uniqueName, String adapterName, long namespace, exportedColumn.dimension, exportedColumn.cardinality, exportedColumn.nullable, - Collation.getDefaultCollation() ); + Collation.getDefaultCollation(), + exportedColumn.autoIncrement); AllocationColumn allocationColumn = catalog.getAllocRel( namespace ).addColumn( placement.id, @@ -408,7 +409,8 @@ public void addColumnToSourceTable( LogicalTable table, String columnPhysicalNam exportedColumn.dimension, exportedColumn.cardinality, exportedColumn.nullable, - Collation.getDefaultCollation() + Collation.getDefaultCollation(), + exportedColumn.autoIncrement ); // Add default value @@ -455,7 +457,7 @@ private void updateColumnPosition( LogicalTable table, LogicalColumn column, int @Override - public void createColumn( String columnName, LogicalTable table, String beforeColumnName, String afterColumnName, ColumnTypeInformation type, boolean nullable, PolyValue defaultValue, Statement statement ) { + public void createColumn( String columnName, LogicalTable table, String beforeColumnName, String afterColumnName, ColumnTypeInformation type, boolean nullable, PolyValue defaultValue, Statement statement, boolean autoIncrement ) { columnName = adjustNameIfNeeded( columnName, table.namespaceId ); // Check if the column either allows null values or has a default value defined. if ( defaultValue == null && !nullable ) { @@ -484,7 +486,8 @@ public void createColumn( String columnName, LogicalTable table, String beforeCo type.dimension(), type.cardinality(), nullable, - Collation.getDefaultCollation() + Collation.getDefaultCollation(), + autoIncrement ); // Add default value @@ -1683,7 +1686,8 @@ public void createView( String viewName, long namespaceId, AlgNode algNode, AlgC column.typeInformation().dimension(), column.typeInformation().cardinality(), column.typeInformation().nullable(), - column.collation() ); + column.collation(), + column.typeInformation().autoIncrement()); } catalog.updateSnapshot(); @@ -1973,7 +1977,8 @@ private List getViewColumnInformation( List projectedC type.getScale(), alg.getType().getPolyType() == PolyType.ARRAY ? (int) ((ArrayType) alg.getType()).getDimension() : -1, alg.getType().getPolyType() == PolyType.ARRAY ? (int) ((ArrayType) alg.getType()).getCardinality() : -1, - alg.getType().isNullable() ), + alg.getType().isNullable(), + alg.getType().isAutoIncrement()), Collation.getDefaultCollation(), null, position ) ); @@ -1992,7 +1997,8 @@ private List getViewColumnInformation( List projectedC -1, -1, -1, - false ), + false, + false), Collation.getDefaultCollation(), null, position ) ); @@ -2762,7 +2768,8 @@ private LogicalColumn addColumn( long namespaceId, String columnName, ColumnType typeInformation.dimension(), typeInformation.cardinality(), typeInformation.nullable(), - collation + collation, + typeInformation.autoIncrement() ); // Add default value diff --git a/dbms/src/test/java/org/polypheny/db/catalog/CatalogTransactionTest.java b/dbms/src/test/java/org/polypheny/db/catalog/CatalogTransactionTest.java index 16239ec72c..a6778db2ae 100644 --- a/dbms/src/test/java/org/polypheny/db/catalog/CatalogTransactionTest.java +++ b/dbms/src/test/java/org/polypheny/db/catalog/CatalogTransactionTest.java @@ -56,11 +56,11 @@ public void simpleRollbackTest() { LogicalTable table = catalog.getLogicalRel( namespaceId ).addTable( "testTable", EntityType.ENTITY, true ); - catalog.getLogicalRel( namespaceId ).addColumn( "testCol1", table.id, 1, PolyType.BIGINT, null, null, null, null, null, false, null ); + catalog.getLogicalRel( namespaceId ).addColumn( "testCol1", table.id, 1, PolyType.BIGINT, null, null, null, null, null, false, null, false ); catalog.commit(); - LogicalColumn id = catalog.getLogicalRel( namespaceId ).addColumn( "testCol4", table.id, 2, PolyType.BIGINT, null, null, null, null, null, true, null ); + LogicalColumn id = catalog.getLogicalRel( namespaceId ).addColumn( "testCol4", table.id, 2, PolyType.BIGINT, null, null, null, null, null, true, null, false ); catalog.rollback(); assert (catalog.getSnapshot().rel().getColumn( id.id ).isEmpty()); @@ -77,13 +77,13 @@ public void rollbackTest() { LogicalTable table = catalog.getLogicalRel( namespaceId ).addTable( "testTable", EntityType.ENTITY, true ); - catalog.getLogicalRel( namespaceId ).addColumn( "testCol1", table.id, 1, PolyType.BIGINT, null, null, null, null, null, false, null ); - catalog.getLogicalRel( namespaceId ).addColumn( "testCol2", table.id, 2, PolyType.VARCHAR, null, 2646, 5, 2, 2, true, Collation.CASE_INSENSITIVE ); + catalog.getLogicalRel( namespaceId ).addColumn( "testCol1", table.id, 1, PolyType.BIGINT, null, null, null, null, null, false, null, false ); + catalog.getLogicalRel( namespaceId ).addColumn( "testCol2", table.id, 2, PolyType.VARCHAR, null, 2646, 5, 2, 2, true, Collation.CASE_INSENSITIVE, false ); // catalog.getLogicalRel( namespaceId ).createColumn( "testCol3", table.id, 3, PolyType.BIGINT, null,null, null, null, null, true, null ); 127 catalog.commit(); - LogicalColumn id = catalog.getLogicalRel( namespaceId ).addColumn( "testCol4", table.id, 3, PolyType.BIGINT, null, null, null, null, null, true, null ); + LogicalColumn id = catalog.getLogicalRel( namespaceId ).addColumn( "testCol4", table.id, 3, PolyType.BIGINT, null, null, null, null, null, true, null, false ); catalog.rollback(); assert (catalog.getSnapshot().rel().getColumn( id.id ).isEmpty()); diff --git a/dbms/src/test/java/org/polypheny/db/sql/clause/SimpleSqlTest.java b/dbms/src/test/java/org/polypheny/db/sql/clause/SimpleSqlTest.java index 4f7298b20c..d1bb489123 100644 --- a/dbms/src/test/java/org/polypheny/db/sql/clause/SimpleSqlTest.java +++ b/dbms/src/test/java/org/polypheny/db/sql/clause/SimpleSqlTest.java @@ -16,9 +16,12 @@ package org.polypheny.db.sql.clause; +import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Statement; import java.util.List; +import com.google.common.collect.ImmutableList; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Tag; @@ -52,6 +55,43 @@ public void dropTable() { ); } + @Test + public void autoIncrement() throws SQLException { + // skip this test if store.default.equals("file") + String store = System.getProperty( "store.default" ); + if ( store != null && store.equals( "file" ) ) { + return; + } + try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( true ) ) { + Connection connection = polyphenyDbConnection.getConnection(); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS TableAutoInc" ); + statement.executeUpdate( "CREATE TABLE TableAutoInc(RID INTEGER NOT NULL AUTO_INCREMENT, YAC INTEGER NOT NULL, PRIMARY KEY (RID))" ); + statement.executeUpdate( "INSERT INTO TableAutoInc VALUES (1, 61), (2, 62)" ); + statement.executeUpdate( "INSERT INTO TableAutoInc(YAC) VALUES (63)" ); + statement.executeUpdate( "INSERT INTO TableAutoInc VALUES (100, 120)" ); + statement.executeUpdate( "INSERT INTO TableAutoInc(YAC) VALUES (121)" ); + statement.executeUpdate( "INSERT INTO TableAutoInc VALUES (4, 64)" ); + statement.executeUpdate( "INSERT INTO TableAutoInc(YAC) VALUES (122)" ); + TestHelper.checkResultSet( + statement.executeQuery( "SELECT RID, YAC FROM TableAutoInc" ), + ImmutableList.of( + new Object[]{1, 61}, + new Object[]{2, 62}, + new Object[]{3, 63}, + new Object[]{100, 120}, + new Object[]{101, 121}, + new Object[]{4, 64}, + new Object[]{102, 122} + ) + ); + statement.executeUpdate( "DROP TABLE TableAutoInc" ); + connection.commit(); + } + + } + } + @Test public void insert() throws SQLException { diff --git a/plugins/csv-adapter/src/main/java/org/polypheny/db/adapter/csv/CsvSource.java b/plugins/csv-adapter/src/main/java/org/polypheny/db/adapter/csv/CsvSource.java index af190419ae..5590c5cb82 100644 --- a/plugins/csv-adapter/src/main/java/org/polypheny/db/adapter/csv/CsvSource.java +++ b/plugins/csv-adapter/src/main/java/org/polypheny/db/adapter/csv/CsvSource.java @@ -264,7 +264,8 @@ public Map> getExportedColumns() { physicalTableName, name, position, - position == 1 ) ); + position == 1, + false) ); position++; } } catch ( IOException e ) { diff --git a/plugins/ethereum-adapter/src/main/java/org/polypheny/db/adapter/ethereum/EthereumPlugin.java b/plugins/ethereum-adapter/src/main/java/org/polypheny/db/adapter/ethereum/EthereumPlugin.java index 5f355f985f..bfdaa468b7 100644 --- a/plugins/ethereum-adapter/src/main/java/org/polypheny/db/adapter/ethereum/EthereumPlugin.java +++ b/plugins/ethereum-adapter/src/main/java/org/polypheny/db/adapter/ethereum/EthereumPlugin.java @@ -188,7 +188,8 @@ public Map> getExportedColumns() { "block", blockCol, position, - position == 0 ) ); + position == 0, + false) ); position++; } @@ -209,7 +210,8 @@ public Map> getExportedColumns() { "transaction", transactCol, position, - position == 0 ) ); + position == 0, + false) ); position++; } map.put( "transaction", transactCols ); diff --git a/plugins/excel-adapter/src/main/java/org/polypheny/db/adapter/excel/ExcelSource.java b/plugins/excel-adapter/src/main/java/org/polypheny/db/adapter/excel/ExcelSource.java index 9b64d91dc9..ba6da454ca 100644 --- a/plugins/excel-adapter/src/main/java/org/polypheny/db/adapter/excel/ExcelSource.java +++ b/plugins/excel-adapter/src/main/java/org/polypheny/db/adapter/excel/ExcelSource.java @@ -326,7 +326,8 @@ public Map> getExportedColumns() { physicalTableName, name, position, - position == 1 ) ); // TODO + position == 1, + false) ); // TODO position++; } catch ( Exception e ) { diff --git a/plugins/file-adapter/src/main/java/org/polypheny/db/adapter/file/source/Qfs.java b/plugins/file-adapter/src/main/java/org/polypheny/db/adapter/file/source/Qfs.java index 14a06c15f5..51887ead5b 100644 --- a/plugins/file-adapter/src/main/java/org/polypheny/db/adapter/file/source/Qfs.java +++ b/plugins/file-adapter/src/main/java/org/polypheny/db/adapter/file/source/Qfs.java @@ -244,7 +244,8 @@ public Map> getExportedColumns() { physTableName, "path", 1, - true + true, + false ) ); columns.add( new ExportedColumn( @@ -260,6 +261,7 @@ public Map> getExportedColumns() { physTableName, "name", 2, + false, false ) ); @@ -276,6 +278,7 @@ public Map> getExportedColumns() { physTableName, "size", 3, + false, false ) ); @@ -292,6 +295,7 @@ public Map> getExportedColumns() { physTableName, "file", 4, + false, false ) ); diff --git a/plugins/google-sheet-adapter/src/main/java/org/polypheny/db/adapter/googlesheet/GoogleSheetSource.java b/plugins/google-sheet-adapter/src/main/java/org/polypheny/db/adapter/googlesheet/GoogleSheetSource.java index b4759b90e9..eeed77dba8 100644 --- a/plugins/google-sheet-adapter/src/main/java/org/polypheny/db/adapter/googlesheet/GoogleSheetSource.java +++ b/plugins/google-sheet-adapter/src/main/java/org/polypheny/db/adapter/googlesheet/GoogleSheetSource.java @@ -297,7 +297,8 @@ public Map> getExportedColumns() { tableName, col.toString(), position, - position == 0 + position == 0, + false ) ); position++; } diff --git a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/sources/AbstractJdbcSource.java b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/sources/AbstractJdbcSource.java index 47f361c263..4db3632735 100644 --- a/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/sources/AbstractJdbcSource.java +++ b/plugins/jdbc-adapter-framework/src/main/java/org/polypheny/db/adapter/jdbc/sources/AbstractJdbcSource.java @@ -296,7 +296,8 @@ public Map> getExportedColumns() { row.getString( "TABLE_NAME" ), row.getString( "COLUMN_NAME" ), row.getInt( "ORDINAL_POSITION" ), - primaryKeyColumns.contains( row.getString( "COLUMN_NAME" ) ) + primaryKeyColumns.contains( row.getString( "COLUMN_NAME" )), + false ) ); } map.put( tableName, list ); diff --git a/plugins/sql-language/src/main/codegen/Parser.jj b/plugins/sql-language/src/main/codegen/Parser.jj index 62e3cef494..4be73f7e1f 100644 --- a/plugins/sql-language/src/main/codegen/Parser.jj +++ b/plugins/sql-language/src/main/codegen/Parser.jj @@ -1951,6 +1951,7 @@ void TableElement(List list) : SqlIdentifier refTable; SqlIdentifier refColumn; final boolean primary; + final boolean auto_increment; } { id = SimpleIdentifier() @@ -1978,6 +1979,15 @@ void TableElement(List list) : primary = false; } ) + ( + { + auto_increment = true; + } + | + { + auto_increment = false; + } + ) ( [ ] @@ -2013,7 +2023,7 @@ void TableElement(List list) : } ) { - list.add( SqlDdlNodes.column(s.add(id).end(this), id, type.withNullable(nullable), collation, e, strategy)); + list.add( SqlDdlNodes.column(s.add(id).end(this), id, type.withNullable(nullable).withAutoIncrement(auto_increment), collation, e, strategy)); if ( primary ) { list.add( SqlDdlNodes.primary( s.add(id ).end( this ), id, new SqlNodeList( List.of( id ), s.end(this) ) ) ); } @@ -7508,6 +7518,7 @@ SqlPostfixOperator PostfixRowOperator() : | < ATTRIBUTE: "ATTRIBUTE" > | < ATTRIBUTES: "ATTRIBUTES" > | < AUTHORIZATION: "AUTHORIZATION" > +| < AUTO_INCREMENT: "AUTO_INCREMENT" > | < AVG: "AVG" > | < BEFORE: "BEFORE" > | < BEGIN: "BEGIN" > @@ -8222,6 +8233,7 @@ void NonReservedKeyWord0of3() : | | | + | < AUTO_INCREMENT> | | | diff --git a/plugins/sql-language/src/main/java/org/polypheny/db/sql/SqlProcessor.java b/plugins/sql-language/src/main/java/org/polypheny/db/sql/SqlProcessor.java index bcf5568c54..3fa24c64f0 100644 --- a/plugins/sql-language/src/main/java/org/polypheny/db/sql/SqlProcessor.java +++ b/plugins/sql-language/src/main/java/org/polypheny/db/sql/SqlProcessor.java @@ -58,6 +58,7 @@ import org.polypheny.db.sql.language.SqlLiteral; import org.polypheny.db.sql.language.SqlNode; import org.polypheny.db.sql.language.SqlNodeList; +import org.polypheny.db.sql.language.SqlNumericLiteral; import org.polypheny.db.sql.language.SqlUtil; import org.polypheny.db.sql.language.dialect.PolyphenyDbSqlDialect; import org.polypheny.db.sql.language.fun.SqlStdOperatorTable; @@ -71,6 +72,8 @@ import org.polypheny.db.transaction.LockManager; import org.polypheny.db.transaction.Statement; import org.polypheny.db.transaction.Transaction; +import org.polypheny.db.type.PolyType; +import org.polypheny.db.type.entity.numerical.PolyBigDecimal; import org.polypheny.db.util.Casing; import org.polypheny.db.util.Conformance; import org.polypheny.db.util.DeadlockException; @@ -280,6 +283,12 @@ private void addDefaultValues( Transaction transaction, SqlInsert insert ) { SqlBasicCall call = (SqlBasicCall) sqlNode; int position = getPositionInSqlNodeList( oldColumnList, column.name ); if ( position >= 0 ) { + if ( column.autoIncrement && ( column.type == PolyType.BIGINT || column.type == PolyType.INTEGER ) ) { + long valueToInsert = ((PolyBigDecimal) ((SqlNumericLiteral) call.getOperands()[position]).value).value.longValue(); + if ( valueToInsert >= column.currentValue.get() ) { + column.currentValue.set( valueToInsert + 1 ); + } + } newValues[i][pos] = call.getOperands()[position]; } else { // Add value @@ -315,6 +324,8 @@ private void addDefaultValues( Transaction transaction, SqlInsert insert ) { } } else if ( column.nullable ) { newValues[i][pos] = SqlLiteral.createNull( ParserPos.ZERO ); + } else if ( column.autoIncrement ) { + newValues[i][pos] = SqlLiteral.createExactNumeric( String.valueOf( column.currentValue.getAndAdd( 1 ) ), ParserPos.ZERO ); } else { throw new PolyphenyDbException( "The not nullable field '" + column.name + "' is missing in the insert statement and has no default value defined." ); } @@ -360,6 +371,22 @@ private void addDefaultValues( Transaction transaction, SqlInsert insert ) { call.getPos(), newValues[i] ); } + } else { + // update the auto increment values if needed + LogicalTable catalogTable = getTable( transaction, (SqlIdentifier) insert.getTargetTable() ); + for ( LogicalColumn column : catalogTable.getColumns() ) { + if ( column.autoIncrement && ( column.type == PolyType.BIGINT || column.type == PolyType.INTEGER ) ) { + for ( SqlNode sqlNode : ((SqlBasicCall) insert.getSource()).getOperands() ) { + SqlBasicCall call = (SqlBasicCall) sqlNode; + int position = column.position - 1; + assert position >= 0; + long valueToInsert = ((PolyBigDecimal) ((SqlNumericLiteral) call.getOperands()[position]).value).value.longValue(); + if ( valueToInsert >= column.currentValue.get() ) { + column.currentValue.set( valueToInsert + 1 ); + } + } + } + } } } diff --git a/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/SqlDataTypeSpec.java b/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/SqlDataTypeSpec.java index 477fa7cfa6..a14dab29df 100644 --- a/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/SqlDataTypeSpec.java +++ b/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/SqlDataTypeSpec.java @@ -74,6 +74,8 @@ public class SqlDataTypeSpec extends SqlNode implements DataTypeSpec { */ private Boolean nullable; + private Boolean autoIncrement = false; + /** * Creates a type specification representing a regular, non-collection type. @@ -151,6 +153,48 @@ public SqlDataTypeSpec( this.nullable = nullable; } + public SqlDataTypeSpec( + SqlIdentifier collectionsTypeName, + SqlIdentifier typeName, + SqlIdentifier baseTypeName, + int precision, + int scale, + int dimension, + int cardinality, + String charSetName, + TimeZone timeZone, + Boolean nullable, + ParserPos pos, + boolean autoIncrement) { + super( pos ); + this.collectionsTypeName = collectionsTypeName; + this.typeName = typeName; + this.baseTypeName = baseTypeName; + this.precision = precision; + this.scale = scale; + this.dimension = dimension; + this.cardinality = cardinality; + this.charSetName = charSetName; + this.timeZone = timeZone; + this.nullable = nullable; + this.autoIncrement = autoIncrement; + } + + public SqlDataTypeSpec( + SqlIdentifier collectionsTypeName, + SqlIdentifier typeName, + int precision, + int scale, + int dimension, + int cardinality, + String charSetName, + TimeZone timeZone, + Boolean nullable, + ParserPos pos, + boolean autoIncrement) { + this( collectionsTypeName, typeName, typeName, precision, scale, dimension, cardinality, charSetName, timeZone, nullable, pos, autoIncrement ); + } + @Override public SqlNode clone( ParserPos pos ) { @@ -198,6 +242,13 @@ public SqlDataTypeSpec withNullable( Boolean nullable ) { return new SqlDataTypeSpec( collectionsTypeName, typeName, precision, scale, dimension, cardinality, charSetName, timeZone, nullable, getPos() ); } + public SqlDataTypeSpec withAutoIncrement( boolean autoIncrement ) { + if ( Objects.equals( autoIncrement, this.autoIncrement ) ) { + return this; + } + return new SqlDataTypeSpec( collectionsTypeName, typeName, precision, scale, dimension, cardinality, charSetName, timeZone, nullable, getPos(), autoIncrement ); + } + /** * Returns a new SqlDataTypeSpec corresponding to the component type if the type spec is a collections type spec.
diff --git a/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/SqlColumnDeclaration.java b/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/SqlColumnDeclaration.java index 9bbd01b35f..cce02b4664 100644 --- a/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/SqlColumnDeclaration.java +++ b/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/SqlColumnDeclaration.java @@ -53,6 +53,9 @@ public class SqlColumnDeclaration extends SqlCall { final ColumnStrategy strategy; final String collation; + @Getter + final boolean auto_increment; + /** * Creates a SqlColumnDeclaration; use {@link SqlDdlNodes#column}. @@ -64,6 +67,17 @@ public class SqlColumnDeclaration extends SqlCall { this.expression = expression; this.strategy = strategy; this.collation = collation; + this.auto_increment = false; + } + + SqlColumnDeclaration( ParserPos pos, SqlIdentifier name, SqlDataTypeSpec dataType, String collation, SqlNode expression, ColumnStrategy strategy, boolean auto_increment ) { + super( pos ); + this.name = name; + this.dataType = dataType; + this.expression = expression; + this.strategy = strategy; + this.collation = collation; + this.auto_increment = auto_increment; } diff --git a/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/altertable/SqlAlterTableAddColumn.java b/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/altertable/SqlAlterTableAddColumn.java index 8032afc309..e779ada2bc 100644 --- a/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/altertable/SqlAlterTableAddColumn.java +++ b/plugins/sql-language/src/main/java/org/polypheny/db/sql/language/ddl/altertable/SqlAlterTableAddColumn.java @@ -148,7 +148,8 @@ public void execute( Context context, Statement statement, ParsedQueryContext pa ColumnTypeInformation.fromDataTypeSpec( type ), nullable, defaultValue == null ? null : SqlLiteral.toPoly( defaultValue ), - statement ); + statement, + false); } } diff --git a/plugins/sql-language/src/test/java/org/polypheny/db/sql/SqlLanguageDependent.java b/plugins/sql-language/src/test/java/org/polypheny/db/sql/SqlLanguageDependent.java index 8a944a3792..69830b19f0 100644 --- a/plugins/sql-language/src/test/java/org/polypheny/db/sql/SqlLanguageDependent.java +++ b/plugins/sql-language/src/test/java/org/polypheny/db/sql/SqlLanguageDependent.java @@ -107,9 +107,9 @@ private static void createHrSchema( TestHelper testHelper ) throws TransactionEx DdlManager manager = DdlManager.getInstance(); List columns = List.of( - new FieldInformation( "deptno", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, false ), null, null, 0 ), - new FieldInformation( "name", new ColumnTypeInformation( PolyType.VARCHAR, null, 20, null, null, null, false ), null, null, 1 ), - new FieldInformation( "loc", new ColumnTypeInformation( PolyType.VARCHAR, null, 50, null, null, null, true ), null, null, 2 ) + new FieldInformation( "deptno", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, false, false ), null, null, 0 ), + new FieldInformation( "name", new ColumnTypeInformation( PolyType.VARCHAR, null, 20, null, null, null, false, false ), null, null, 1 ), + new FieldInformation( "loc", new ColumnTypeInformation( PolyType.VARCHAR, null, 50, null, null, null, true, false ), null, null, 2 ) ); List constraints = List.of( @@ -133,9 +133,9 @@ private static void createTestSchema( TestHelper testHelper ) { DdlManager manager = DdlManager.getInstance(); List columns = List.of( - new FieldInformation( "deptno", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, false ), null, null, 0 ), - new FieldInformation( "name", new ColumnTypeInformation( PolyType.VARCHAR, null, 20, null, null, null, false ), null, null, 1 ), - new FieldInformation( "loc", new ColumnTypeInformation( PolyType.VARCHAR, null, 50, null, null, null, true ), null, null, 2 ) + new FieldInformation( "deptno", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, false, false ), null, null, 0 ), + new FieldInformation( "name", new ColumnTypeInformation( PolyType.VARCHAR, null, 20, null, null, null, false, false ), null, null, 1 ), + new FieldInformation( "loc", new ColumnTypeInformation( PolyType.VARCHAR, null, 50, null, null, null, true, false ), null, null, 2 ) ); List constraints = List.of( @@ -146,13 +146,13 @@ private static void createTestSchema( TestHelper testHelper ) { // "CREATE TABLE employee( empid BIGINT NOT NULL, ename VARCHAR(20), job VARCHAR(10), mgr INTEGER, hiredate DATE, salary DECIMAL(7,2), commission DECIMAL(7,2), deptno INTEGER NOT NULL, PRIMARY KEY (empid)) " columns = List.of( - new FieldInformation( "empid", new ColumnTypeInformation( PolyType.BIGINT, null, null, null, null, null, false ), null, null, 0 ), - new FieldInformation( "ename", new ColumnTypeInformation( PolyType.VARCHAR, null, 20, null, null, null, true ), null, null, 1 ), - new FieldInformation( "job", new ColumnTypeInformation( PolyType.VARCHAR, null, 10, null, null, null, true ), null, null, 2 ), - new FieldInformation( "mgr", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, true ), null, null, 3 ), - new FieldInformation( "hiredate", new ColumnTypeInformation( PolyType.DATE, null, null, null, null, null, true ), null, null, 4 ), - new FieldInformation( "salary", new ColumnTypeInformation( PolyType.DECIMAL, null, null, 7, 2, null, true ), null, null, 5 ), - new FieldInformation( "deptno", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, true ), null, null, 6 ) + new FieldInformation( "empid", new ColumnTypeInformation( PolyType.BIGINT, null, null, null, null, null, false, false ), null, null, 0 ), + new FieldInformation( "ename", new ColumnTypeInformation( PolyType.VARCHAR, null, 20, null, null, null, true, false ), null, null, 1 ), + new FieldInformation( "job", new ColumnTypeInformation( PolyType.VARCHAR, null, 10, null, null, null, true, false ), null, null, 2 ), + new FieldInformation( "mgr", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, true, false ), null, null, 3 ), + new FieldInformation( "hiredate", new ColumnTypeInformation( PolyType.DATE, null, null, null, null, null, true, false ), null, null, 4 ), + new FieldInformation( "salary", new ColumnTypeInformation( PolyType.DECIMAL, null, null, 7, 2, null, true, false ), null, null, 5 ), + new FieldInformation( "deptno", new ColumnTypeInformation( PolyType.INTEGER, null, null, null, null, null, true, false ), null, null, 6 ) ); constraints = List.of( @@ -165,7 +165,7 @@ private static void createTestSchema( TestHelper testHelper ) { long id = manager.createNamespace( "customer", DataModel.RELATIONAL, true, false, transaction.createStatement() ); columns = List.of( - new FieldInformation( "fname", new ColumnTypeInformation( PolyType.VARCHAR, null, 50, null, null, null, false ), null, null, 0 ) + new FieldInformation( "fname", new ColumnTypeInformation( PolyType.VARCHAR, null, 50, null, null, null, false, false ), null, null, 0 ) ); constraints = List.of(