Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<groupId>com.github.gwenn</groupId>
<artifactId>sqlite-dialect</artifactId>
<packaging>jar</packaging>
<version>0.1.4</version>
<version>0.2.0</version>
<name>SQLite dialect for Hibernate</name>
<description>SQLite dialect for Hibernate</description>
<url>https://github.com/gwenn/sqlite-dialect</url>
Expand Down Expand Up @@ -46,6 +46,19 @@
<artifactId>hibernate-core</artifactId>
<version>5.6.15.Final</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.gwenn</groupId>
<artifactId>sqlite-jna</artifactId>
<version>0.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
38 changes: 16 additions & 22 deletions src/main/java/org/sqlite/hibernate/dialect/SQLiteDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public IdentityColumnSupport getIdentityColumnSupport() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
return sql + (hasOffset ? " limit ? offset ?" : " limit ?");
return sql + (hasOffset ? " LIMIT ? OFFSET ?" : " LIMIT ?");
}

@Override
Expand Down Expand Up @@ -182,17 +182,19 @@ public boolean isCurrentTimestampSelectStringCallable() {

@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp";
return "SELECT CURRENT_TIMESTAMP";
}

// Bulk ID Strategy support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@Override
public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() {
// SQLite supports temporary tables, and the default "PersistentTableBulkIdStrategy"
// used in the Dialect base class doesn't work anymore with Hibernate 5.4.21 and newer.
return new LocalTemporaryTableBulkIdStrategy(new IdTableSupportStandardImpl() {
@Override
public String getCreateIdTableCommand() {
return "create temporary table";
return "CREATE TEMPORARY TABLE";
}
}, AfterUseAction.CLEAN, null);
}
Expand Down Expand Up @@ -244,7 +246,7 @@ public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle ) & 0xFF;
if (errorCode == SQLITE_CONSTRAINT) {
return extractUsingTemplate( "constraint ", " failed", sqle.getMessage() );
return extractUsingTemplate( "constraint failed: ", "$", sqle.getMessage() );
}
return null;
}
Expand Down Expand Up @@ -282,7 +284,7 @@ public boolean qualifyIndexName() {

@Override
public String getAddColumnString() {
return "add column";
return "ADD COLUMN";
}

@Override
Expand Down Expand Up @@ -350,16 +352,11 @@ private SQLiteUniqueDelegate(Dialect dialect) {
}

/**
* SQLite use table creation sql to define unique constraints.
* SQLite uses table creation sql to define unique constraints.
*/
@Override
public String getColumnDefinitionUniquenessFragment(Column column) {
return "";
}

@Override
public String getColumnDefinitionUniquenessFragment(Column column, SqlStringGenerationContext context) {
return getColumnDefinitionUniquenessFragment(column);
return "";
}

/**
Expand All @@ -368,42 +365,39 @@ public String getColumnDefinitionUniquenessFragment(Column column, SqlStringGene
* Such as "create table person( first_name varchar(255),last_name varchar(255),unique(first_name, last_name) )".
*/
@Override
public String getTableCreationUniqueConstraintsFragment(Table table) {
public String getTableCreationUniqueConstraintsFragment(Table table, SqlStringGenerationContext context) {
// get all uniqueKeys
StringBuilder builder = new StringBuilder();
Iterator<UniqueKey> iter = table.getUniqueKeyIterator();
while(iter.hasNext()) {
UniqueKey key = iter.next();
builder.append(", ").append(uniqueConstraintSql(key));
builder.append(", CONSTRAINT ").append(dialect.quote(key.getName())).append(" ").append(uniqueConstraintSql(key));
}
return builder.toString();
}

@Override
public String getTableCreationUniqueConstraintsFragment(Table table, SqlStringGenerationContext context) {
return getTableCreationUniqueConstraintsFragment(table);
}

/**
* SQLite do not support 'alter table' to add constraints.
*/
@Override
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) {
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
SqlStringGenerationContext context) {
return "";
}

/**
* SQLite do not support 'drop constraint'.
*/
@Override
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) {
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
SqlStringGenerationContext context) {
return "";
}
}

@Override
public String getSelectGUIDString() {
return "select hex(randomblob(16))";
return "SELECT hex(randomblob(16))";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
package org.sqlite.hibernate.dialect;

import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.spi.MetadataBuilderInitializer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
import org.jboss.logging.Logger;

public class SQLiteMetadataBuilderInitializer implements MetadataBuilderInitializer {

private final static Logger logger = Logger.getLogger(SQLiteMetadataBuilderInitializer.class);

@Override
public void contribute(MetadataBuilder metadataBuilder, StandardServiceRegistry serviceRegistry) {
DialectResolver dialectResolver = serviceRegistry.getService(DialectResolver.class);

if (!(dialectResolver instanceof DialectResolverSet)) {
logger.warnf("DialectResolver '%s' is not an instance of DialectResolverSet, not registering SQLiteDialect",
dialectResolver);
return;
}

((DialectResolverSet) dialectResolver).addResolver(resolver);
}

static private final SQLiteDialect dialect = new SQLiteDialect();

static private final DialectResolver resolver = new DialectResolver() {

@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
if (info.getDatabaseName().equals("SQLite"))
return dialect;

return null;
}

};
}
package org.sqlite.hibernate.dialect;

import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.spi.MetadataBuilderInitializer;
import org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
import org.jboss.logging.Logger;

public class SQLiteMetadataBuilderInitializer implements MetadataBuilderInitializer {

private static final Logger logger = Logger.getLogger(SQLiteMetadataBuilderInitializer.class);

@Override
public void contribute(MetadataBuilder metadataBuilder, StandardServiceRegistry serviceRegistry) {
DialectResolver dialectResolver = serviceRegistry.getService(DialectResolver.class);

if (!(dialectResolver instanceof DialectResolverSet)) {
logger.warnf("DialectResolver '%s' is not an instance of DialectResolverSet, not registering SQLiteDialect",
dialectResolver);
return;
}

((DialectResolverSet) dialectResolver).addResolver(resolver);
}

private static final SQLiteDialect dialect = new SQLiteDialect();

private static final DialectResolver resolver = info -> {
if (info.getDatabaseName().startsWith("SQLite"))
return dialect;
return null;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ public boolean hasDataTypeInIdentityColumn() {

@Override
public String appendIdentitySelectToInsert(String insertString) {
// FIXME does not work when PK is not an alias of rowid (ie not INTEGER PRIMARY KEY)
return insertString + " RETURNING rowid";
}

@Override
public String getIdentitySelectString(String table, String column, int type) {
return "select last_insert_rowid()";
return "SELECT last_insert_rowid()";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.tutorial.annotations;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.exception.ConstraintViolationException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;

import static org.junit.Assert.*;

/**
* Illustrates the use of Hibernate native APIs. The code here is unchanged from the {@code basic} example, the
* only difference being the use of annotations to supply the metadata instead of Hibernate mapping files.
*
* @author Steve Ebersole
*/
public class AnnotationsIllustrationTest {
private SessionFactory sessionFactory;

@Before
public void setUp() {
// A SessionFactory is set up once for an application!
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure() // configures settings from hibernate.cfg.xml
.build();
try {
sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
} catch (Exception e) {
// The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
// so destroy it manually.
StandardServiceRegistryBuilder.destroy(registry);
throw e;
}
}

@After
public void tearDown() {
if (sessionFactory != null) {
sessionFactory.close();
}
}

@Test
public void testBasicUsage() {
// create a couple of events...
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
session.save(new Event("Our very first event!", Timestamp.valueOf(LocalDateTime.now())));
session.save(new Event("A follow up event", Timestamp.valueOf(LocalDateTime.now())));
session.getTransaction().commit();
}
// now lets pull events from the database and list them
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
List<Event> result = session.createQuery("from Event", Event.class).list();
for (Event event : result) {
System.out.println("Event (" + event.getDate() + ") : " + event.getTitle());
}
session.getTransaction().commit();
}
}

@Test
public void uniqueConstraint() {
// create a couple of events...
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
final String title = "Dup";
session.save(new Event(title, Timestamp.valueOf(LocalDateTime.now())));
session.save(new Event(title, Timestamp.valueOf(LocalDateTime.now())));
fail("UNIQUE constraint violation expected");
} catch (ConstraintViolationException cve) {
assertEquals("EVENTS.title", cve.getConstraintName());
}
}
}
Loading