package edu.harvard.med.screensaver.util; import org.apache.commons.lang.StringUtils; import org.hibernate.EmptyInterceptor; /** * This solves the problem with NULL values sorting higher than non-NULL values in postgresql. * see: https://hibernate.onjira.com/browse/HHH-465 * fix for [#3478] PropertyPathDataFetcher based Search results sort null values higher than non-null values (in PostgreSQL) * TODO: NOTE that this fix breaks with subqueries (which aren't currently used * in our Hibernate implementations). */ public class CustomNullsFirstInterceptor extends EmptyInterceptor { private static final long serialVersionUID = -3156853534261313031L; private static final String ORDER_BY_TOKEN = "order by"; public String onPrepareStatement(String sql) { int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN); if (orderByStart == -1) { return super.onPrepareStatement(sql); } orderByStart += ORDER_BY_TOKEN.length() + 1; int orderByEnd = sql.indexOf(")", orderByStart); if (orderByEnd == -1) { orderByEnd = sql.indexOf(" UNION ", orderByStart); if (orderByEnd == -1) { orderByEnd = sql.indexOf(" LIMIT ", orderByStart); if (orderByEnd == -1) { orderByEnd = sql.indexOf(" OFFSET ", orderByStart); if (orderByEnd == -1) { orderByEnd = sql.length(); } } } } String orderByContent = sql.substring(orderByStart, orderByEnd); String[] orderByNames = orderByContent.split("\\,"); for (int i=0; i<orderByNames.length; i++) { if (orderByNames[i].trim().length() > 0) { if (orderByNames[i].trim().toLowerCase().endsWith("desc")) { orderByNames[i] += " NULLS LAST"; } else { orderByNames[i] += " NULLS FIRST"; } } } orderByContent = StringUtils.join(orderByNames, ","); sql = sql.substring(0, orderByStart) + orderByContent + sql.substring(orderByEnd); return super.onPrepareStatement(sql); } }