Skip to content

Commit

Permalink
HHH-18033 Fix LimitHandler detect wrong statement end if sql contains…
Browse files Browse the repository at this point in the history
… quoted semicolon
  • Loading branch information
quaff committed May 8, 2024
1 parent dc0ca63 commit 957c6ad
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ protected boolean renderOffsetRowsKeyword() {
};

private static final Pattern WITH_OPTION_PATTERN =
Pattern.compile("\\s+with\\s+(" + String.join("|", WITH_OPTIONS) + ")\\b|\\s*(;|$)");
Pattern.compile("\\s+with\\s+(" + String.join("|", WITH_OPTIONS) + ")\\b|\\s*;?\\s*$");

/**
* The offset/fetch clauses must come before
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public int convertToFirstRowValue(int zeroBasedFirstResult) {
}

private static final Pattern FOR_UPDATE_PATTERN =
compile("\\s+for\\s+update\\b|\\s+with\\s+lock\\b|\\s*(;|$)", CASE_INSENSITIVE);
compile("\\s+for\\s+update\\b|\\s+with\\s+lock\\b|\\s*;?\\s*$", CASE_INSENSITIVE);

@Override
protected Pattern getForUpdatePattern() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.community.dialect;

import org.hibernate.community.dialect.pagination.IngresLimitHandler;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.orm.test.dialect.AbstractLimitHandlerTest;

/**
* @author Yanming Zhou
*/
public class IngresLimitHandlerTest extends AbstractLimitHandlerTest {

@Override
protected AbstractLimitHandler getLimitHandler() {
return IngresLimitHandler.INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.community.dialect;

import org.hibernate.community.dialect.pagination.RowsLimitHandler;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.orm.test.dialect.AbstractLimitHandlerTest;

/**
* @author Yanming Zhou
*/
public class RowsLimitHandlerTest extends AbstractLimitHandlerTest {

@Override
protected AbstractLimitHandler getLimitHandler() {
return RowsLimitHandler.INSTANCE;
}

@Override
protected String getLimitClause() {
return " rows ?";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public abstract class AbstractLimitHandler implements LimitHandler {
compile( "^\\s*select(\\s+(distinct|all))?\\b", CASE_INSENSITIVE );

private static final Pattern END_PATTERN =
compile("\\s*(;|$)", CASE_INSENSITIVE);
compile("\\s*;?\\s*$", CASE_INSENSITIVE);

private static final Pattern FOR_UPDATE_PATTERN =
compile("\\s+for\\s+update\\b|\\s*(;|$)", CASE_INSENSITIVE);
compile("\\s+for\\s+update\\b|\\s*;?\\s*$", CASE_INSENSITIVE);


@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public DerbyLimitHandler(boolean variableLimit) {
}

private static final Pattern FOR_UPDATE_WITH_LOCK_PATTERN =
Pattern.compile("\\s+for\\s+(update|read|fetch)\\b|\\s+with\\s+(rr|rs|cs|ur)\\b|\\s*(;|$)");
Pattern.compile("\\s+for\\s+(update|read|fetch)\\b|\\s+with\\s+(rr|rs|cs|ur)\\b|\\s*;?\\s*$");

/**
* The offset/fetch clauses must come before the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ protected String offsetOnlyClause() {
}

private static final Pattern FOR_UPDATE_PATTERN =
compile("\\s+for\\s+update\\b|\\s+lock\\s+in\\s+shared\\s+mode\\b|\\s*(;|$)", CASE_INSENSITIVE);
compile("\\s+for\\s+update\\b|\\s+lock\\s+in\\s+shared\\s+mode\\b|\\s*;?\\s*$", CASE_INSENSITIVE);

@Override
protected Pattern getForUpdatePattern() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.dialect;

import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.query.spi.Limit;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Yanming Zhou
*/
public abstract class AbstractLimitHandlerTest {

@Test
public void testSqlWithSemicolonInsideQuotedString() {
String sql = "select * from Person p where p.name like ';'";
String expected = "select * from Person p where p.name like ';'" + getLimitClause();
assertGenerateExpectedSql(expected, sql);
}

@Test
public void testSqlWithSemicolonInsideQuotedStringAndEndsWithSemicolon() {
String sql = "select * from Person p where p.name like ';';";
String expected = "select * from Person p where p.name like ';'" + getLimitClause() + ";";
assertGenerateExpectedSql(expected, sql);
}

@Test
public void testSqlWithSemicolonInsideQuotedStringAndEndsWithSemicolonAndSpaces() {
String sql = "select * from Person p where p.name like ';' ; ";
String expected = "select * from Person p where p.name like ';'" + getLimitClause() + " ; ";
assertGenerateExpectedSql(expected, sql);
}

protected void assertGenerateExpectedSql(String expected, String sql) {
assertEquals(expected, getLimitHandler().processSql(sql, new Limit(0, 10)));
}

protected abstract LimitHandler getLimitHandler();

protected Limit getLimit() {
return new Limit(0, 10);
}

protected String getLimitClause() {
LimitHandler handler = getLimitHandler();
if (handler instanceof OffsetFetchLimitHandler) {
OffsetFetchLimitHandler oflh = (OffsetFetchLimitHandler) handler;
return " fetch first " + (oflh.supportsVariableLimit() ? "?" : String.valueOf(getLimit().getMaxRows())) + " rows only";
}
return " limit ?";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.dialect;

import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.DB2LimitHandler;

/**
* @author Yanming Zhou
*/
public class DB2LimitHandlerTest extends AbstractLimitHandlerTest {

@Override
protected AbstractLimitHandler getLimitHandler() {
return DB2LimitHandler.INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.dialect;

import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.DerbyLimitHandler;

/**
* @author Yanming Zhou
*/
public class DerbyLimitHandlerTest extends AbstractLimitHandlerTest {

@Override
protected AbstractLimitHandler getLimitHandler() {
return DerbyLimitHandler.INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.dialect;

import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitLimitHandler;

/**
* @author Yanming Zhou
*/
public class LimitLimitHandlerTest extends AbstractLimitHandlerTest {

@Override
protected AbstractLimitHandler getLimitHandler() {
return LimitLimitHandler.INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.dialect;

import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;

/**
* @author Yanming Zhou
*/
public class OffsetFetchLimitHandlerTest extends AbstractLimitHandlerTest {

@Override
protected AbstractLimitHandler getLimitHandler() {
return OffsetFetchLimitHandler.INSTANCE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.Jira;
import org.hibernate.testing.orm.junit.JiraKey;
import org.junit.Test;
import junit.framework.Assert;

Expand Down Expand Up @@ -546,6 +547,36 @@ public Class getParameterType() {
}
}

@Test
@JiraKey("HHH-18033")
public void testNativeQueryContainsQuotedSemicolonWithLimit() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
try {
Item item = new Item( "Mouse;", "Micro$oft mouse" );
em.persist( item );
em.flush();

Query q = em.createNativeQuery( "select * from Item where name like '%;%'" );
q.setMaxResults(10);
assertEquals( 1, q.getResultList().size() );

q = em.createNativeQuery( "select * from Item where name like '%;%';" );
q.setMaxResults(10);
assertEquals( 1, q.getResultList().size() );

q = em.createNativeQuery( "select * from Item where name like '%;%' ; " );
q.setMaxResults(10);
assertEquals( 1, q.getResultList().size() );
}
finally {
if ( em.getTransaction() != null && em.getTransaction().isActive() ) {
em.getTransaction().rollback();
}
em.close();
}
}

@Test
public void testAggregationReturnType() throws Exception {
EntityManager em = getOrCreateEntityManager();
Expand Down

0 comments on commit 957c6ad

Please sign in to comment.