You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2018/12/14 15:02:22 UTC

[syncope] branch 2_1_X updated (3e6f71c -> 40fc384)

This is an automated email from the ASF dual-hosted git repository.

fmartelli pushed a change to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git.


    from 3e6f71c  [SYNCOPE-1417] Raise exception when more than one plain attribute is requested for ordering
     new 772936c  [SYNCOPE-1416] removes null attr views
     new 40fc384  [SYNCOPE-1416] merge on jsonb implementation

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 105 ++++++++++++++++-----
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  |  88 ++++++++++++++---
 .../core/persistence/jpa/dao/SearchSupport.java    |  24 +++++
 .../persistence/jpa/dao/SearchViewSupport.java     |   4 -
 core/persistence-jpa/src/main/resources/views.xml  |  42 ---------
 .../core/persistence/jpa/inner/AnySearchTest.java  |  23 +++++
 .../src/main/resources/postgres/views.xml          |  42 ---------
 .../src/main/resources/sqlserver/views.xml         |  42 ---------
 .../org/apache/syncope/fit/core/SearchITCase.java  |  19 +++-
 9 files changed, 221 insertions(+), 168 deletions(-)


[syncope] 02/02: [SYNCOPE-1416] merge on jsonb implementation

Posted by fm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

fmartelli pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 40fc384f9851868c4db267457d49fb7757b23a77
Author: fmartelli <fa...@gmail.com>
AuthorDate: Fri Dec 14 15:38:23 2018 +0100

    [SYNCOPE-1416] merge on jsonb implementation
---
 .../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 105 ++++++++++++++++-----
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  |  11 +--
 .../core/persistence/jpa/dao/SearchSupport.java    |  24 +++++
 .../persistence/jpa/dao/SearchViewSupport.java     |   4 -
 .../org/apache/syncope/fit/core/SearchITCase.java  |   9 +-
 5 files changed, 118 insertions(+), 35 deletions(-)

diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
index f240705..75b8ff5 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
@@ -18,10 +18,16 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.text.ParseException;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -34,17 +40,60 @@ import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
 
 public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
 
+    private static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance(SyncopeConstants.DEFAULT_DATE_PATTERN);
+
     @Override
     SearchSupport buildSearchSupport(final AnyTypeKind kind) {
         return new SearchSupport(kind);
     }
 
     @Override
-    protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
+    protected void processOBS(
+            final SearchSupport svs,
+            final Set<String> involvedPlainAttrs,
+            final OrderBySupport obs,
+            final StringBuilder where) {
+
+        Set<String> attrs = obs.items.stream().
+                map(item -> item.orderBy.substring(0, item.orderBy.indexOf(" "))).collect(Collectors.toSet());
+
         obs.views.forEach(searchView -> {
-            where.append(',').
-                    append(searchView.name).
-                    append(' ').append(searchView.alias);
+            if (searchView.name.equals(svs.field().name)) {
+                StringBuilder attrWhere = new StringBuilder();
+                StringBuilder nullAttrWhere = new StringBuilder();
+
+                where.append(", (SELECT * FROM ").append(searchView.name);
+
+                if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
+                    attrs.forEach(field -> {
+                        if (attrWhere.length() == 0) {
+                            attrWhere.append(" WHERE ");
+                        } else {
+                            attrWhere.append(" OR ");
+                        }
+                        attrWhere.append("plainAttrs @> '[{\"schema\":\"").append(field).append("\"}]'::jsonb");
+
+                        nullAttrWhere.append(" UNION SELECT DISTINCT any_id,").append(svs.table().alias).append(".*, ").
+                                append("'{\"schema\": \"").
+                                append(field).
+                                append("\"}'::jsonb as attrs, '{}'::jsonb as attrValues").
+                                append(" FROM ").append(svs.table().name).append(" ").append(svs.table().alias).
+                                append(", ").append(svs.field().name).
+                                append(" WHERE ").
+                                append("any_id NOT IN ").
+                                append("(SELECT distinct any_id FROM ").
+                                append(svs.field().name).
+                                append(" WHERE ").append(svs.table().alias).append(".id=any_id AND ").
+                                append("plainAttrs @> '[{\"schema\":\"").append(field).append("\"}]'::jsonb)");
+                    });
+                    where.append(attrWhere).append(nullAttrWhere);
+                }
+
+                where.append(')');
+            } else {
+                where.append(',').append(searchView.name);
+            }
+            where.append(' ').append(searchView.alias);
         });
     }
 
@@ -62,20 +111,12 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
 
         obs.views.add(svs.field());
 
-        item.select = svs.field().alias + ".attrValues ->> '" + fieldName + "' AS " + fieldName;
+        item.select = svs.field().alias + ".attrValues ->> '" + field(schema, null) + "' AS " + fieldName;
         item.where = "attrs ->> 'schema' = '" + fieldName + "'";
         item.orderBy = fieldName + " " + clause.getDirection().name();
     }
 
-    private void fillAttrQuery(
-            final AnyUtils anyUtils,
-            final StringBuilder query,
-            final PlainAttrValue attrValue,
-            final PlainSchema schema,
-            final AttributeCond cond,
-            final boolean not,
-            final List<Object> parameters) {
-
+    private Pair<Boolean, String> field(final PlainSchema schema, final AttributeCond.Type type) {
         String key;
         boolean lower = false;
         switch (schema.getType()) {
@@ -100,9 +141,22 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
                 break;
 
             default:
-                lower = cond.getType() == AttributeCond.Type.IEQ || cond.getType() == AttributeCond.Type.ILIKE;
+                lower = type == AttributeCond.Type.IEQ || type == AttributeCond.Type.ILIKE;
                 key = "stringValue";
         }
+        return Pair.of(lower, key);
+    }
+
+    private void fillAttrQuery(
+            final AnyUtils anyUtils,
+            final StringBuilder query,
+            final PlainAttrValue attrValue,
+            final PlainSchema schema,
+            final AttributeCond cond,
+            final boolean not,
+            final List<Object> parameters) {
+
+        Pair<Boolean, String> field = field(schema, cond.getType());
 
         if (!not && cond.getType() == AttributeCond.Type.EQ) {
             PlainAttr<?> container = anyUtils.newPlainAttr();
@@ -119,11 +173,11 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
         } else {
             query.append("attrs ->> 'schema' = ?").append(setParameter(parameters, cond.getSchema())).
                     append(" AND ").
-                    append(lower ? "LOWER(" : "").
+                    append(field.getLeft() ? "LOWER(" : "").
                     append(schema.isUniqueConstraint()
                             ? "attrs -> 'uniqueValue'" : "attrValues").
-                    append(" ->> '").append(key).append("'").
-                    append(lower ? ")" : "");
+                    append(" ->> '").append(field.getRight()).append("'").
+                    append(field.getLeft() ? ")" : "");
 
             switch (cond.getType()) {
                 case LIKE:
@@ -175,9 +229,18 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
                     query.append('=');
             }
 
-            query.append(lower ? "LOWER(" : "").
-                    append("?").append(setParameter(parameters, cond.getExpression())).
-                    append(lower ? ")" : "");
+            String value = cond.getExpression();
+            if (schema.getType() == AttrSchemaType.Date) {
+                try {
+                    value = String.valueOf(DATE_FORMAT.parse(value).getTime());
+                } catch (ParseException e) {
+                    LOG.error("Could not parse {} as date", value, e);
+                }
+            }
+
+            query.append(field.getLeft() ? "LOWER(" : "").
+                    append("?").append(setParameter(parameters, value)).
+                    append(field.getLeft() ? ")" : "");
         }
     }
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 11ace3a..0a50b2d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -245,10 +245,8 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
             final OrderBySupport obs,
             final StringBuilder where) {
 
-        Set<String> attrs = new HashSet<>(involvedPlainAttrs);
-        for (OrderBySupport.Item item : obs.items) {
-            attrs.add(item.orderBy.substring(0, item.orderBy.indexOf(" ")));
-        }
+        Set<String> attrs = obs.items.stream().
+                map(item -> item.orderBy.substring(0, item.orderBy.indexOf(" "))).collect(Collectors.toSet());
 
         obs.views.forEach(searchView -> {
             where.append(',');
@@ -261,10 +259,11 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
                 if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
                     attrs.forEach(field -> {
                         if (attrWhere.length() == 0) {
-                            attrWhere.append(" WHERE schema_id='").append(field).append("'");
+                            attrWhere.append(" WHERE ");
                         } else {
-                            attrWhere.append(" OR ").append("schema_id='").append(field).append("'");
+                            attrWhere.append(" OR ");
                         }
+                        attrWhere.append("schema_id='").append(field).append("'");
 
                         nullAttrWhere.append(" UNION SELECT any_id, ").
                                 append("'").
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index 3304a70..f10b29a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -22,6 +22,9 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 
 public class SearchSupport {
 
@@ -103,6 +106,27 @@ public class SearchSupport {
         return result;
     }
 
+    public SearchView table() {
+        String result;
+
+        switch (anyTypeKind) {
+            case ANY_OBJECT:
+                result = JPAAnyObject.TABLE;
+                break;
+
+            case GROUP:
+                result = JPAGroup.TABLE;
+                break;
+
+            case USER:
+            default:
+                result = JPAUser.TABLE;
+                break;
+        }
+
+        return new SearchView("t", result);
+    }
+
     public SearchView field() {
         String result;
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java
index 9dc95d8..93045f9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchViewSupport.java
@@ -30,10 +30,6 @@ public class SearchViewSupport extends SearchSupport {
         return new SearchView("sva", field().name + "_attr");
     }
 
-    public SearchView nullAttr() {
-        return new SearchView("svna", field().name + "_null_attr");
-    }
-
     public SearchView uniqueAttr() {
         return new SearchView("svua", field().name + "_unique_attr");
     }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index 98cfd21..6151871 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -293,7 +293,7 @@ public class SearchITCase extends AbstractITCase {
         PagedResult<UserTO> issueSYNCOPE1416 = userService.search(new AnyQuery.Builder().
                 realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().
-                        is("loginDate").lexicalNotBefore("2009-05-26").
+                        is("loginDate").lexicalNotBefore("2009-05-26T00:00:00+0300").
                         and("username").equalTo("rossini").query()).
                 orderBy(SyncopeClient.getOrderByClauseBuilder().asc("loginDate").build()).
                 build());
@@ -438,9 +438,10 @@ public class SearchITCase extends AbstractITCase {
     @Test
     public void orderBy() {
         PagedResult<UserTO> matchingUsers = userService.search(
-                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
-                        fiql(SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query()).
-                        orderBy(SyncopeClient.getOrderByClauseBuilder().asc("status").desc("firstname").build()).build());
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).fiql(
+                        SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query()).
+                        orderBy(SyncopeClient.getOrderByClauseBuilder().asc("status").desc("firstname").build()).
+                        build());
         assertNotNull(matchingUsers);
 
         assertFalse(matchingUsers.getResult().isEmpty());


[syncope] 01/02: [SYNCOPE-1416] removes null attr views

Posted by fm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

fmartelli pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 772936c5275f2e504a67bad9639e9fc34d94df59
Author: fmartelli <fa...@gmail.com>
AuthorDate: Fri Dec 14 10:09:16 2018 +0100

    [SYNCOPE-1416] removes null attr views
---
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  | 89 ++++++++++++++++++----
 core/persistence-jpa/src/main/resources/views.xml  | 42 ----------
 .../core/persistence/jpa/inner/AnySearchTest.java  | 23 ++++++
 .../src/main/resources/postgres/views.xml          | 42 ----------
 .../src/main/resources/sqlserver/views.xml         | 42 ----------
 .../org/apache/syncope/fit/core/SearchITCase.java  | 12 +++
 6 files changed, 110 insertions(+), 140 deletions(-)

diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index ee20e8d..11ace3a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -130,7 +130,10 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
         Pair<String, Set<String>> filter = getAdminRealmsFilter(adminRealms, svs, parameters);
 
         // 1. get the query string from the search condition
-        StringBuilder queryString = getQuery(buildEffectiveCond(cond, filter.getRight()), parameters, svs);
+        Pair<StringBuilder, Set<String>> queryInfo = 
+                getQuery(buildEffectiveCond(cond, filter.getRight()), parameters, svs);
+
+        StringBuilder queryString = queryInfo.getLeft();
 
         // 2. take into account administrative realms
         queryString.insert(0, "SELECT u.any_id FROM (");
@@ -164,16 +167,19 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
             Pair<String, Set<String>> filter = getAdminRealmsFilter(adminRealms, svs, parameters);
 
             // 1. get the query string from the search condition
-            StringBuilder queryString = getQuery(buildEffectiveCond(cond, filter.getRight()), parameters, svs);
+            Pair<StringBuilder, Set<String>> queryInfo = getQuery(buildEffectiveCond(cond, filter.getRight()),
+                    parameters, svs);
+
+            StringBuilder queryString = queryInfo.getLeft();
 
             // 2. take into account realms and ordering
             OrderBySupport obs = parseOrderBy(kind, svs, orderBy);
             if (queryString.charAt(0) == '(') {
                 queryString.insert(0, buildSelect(obs));
-                queryString.append(buildWhere(svs, obs));
+                queryString.append(buildWhere(svs, queryInfo.getRight(), obs));
             } else {
                 queryString.insert(0, buildSelect(obs).append('('));
-                queryString.append(')').append(buildWhere(svs, obs));
+                queryString.append(')').append(buildWhere(svs, queryInfo.getRight(), obs));
             }
             queryString.
                     append(filter.getLeft()).
@@ -233,14 +239,49 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
         return select;
     }
 
-    protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
+    protected void processOBS(
+            final SearchSupport svs,
+            final Set<String> involvedPlainAttrs,
+            final OrderBySupport obs,
+            final StringBuilder where) {
+
+        Set<String> attrs = new HashSet<>(involvedPlainAttrs);
+        for (OrderBySupport.Item item : obs.items) {
+            attrs.add(item.orderBy.substring(0, item.orderBy.indexOf(" ")));
+        }
+
         obs.views.forEach(searchView -> {
             where.append(',');
             if (searchView.name.equals(svs.asSearchViewSupport().attr().name)) {
+                StringBuilder attrWhere = new StringBuilder();
+                StringBuilder nullAttrWhere = new StringBuilder();
+
                 where.append(" (SELECT * FROM ").append(searchView.name);
 
                 if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
-                    where.append(" UNION SELECT * FROM ").append(svs.asSearchViewSupport().nullAttr().name);
+                    attrs.forEach(field -> {
+                        if (attrWhere.length() == 0) {
+                            attrWhere.append(" WHERE schema_id='").append(field).append("'");
+                        } else {
+                            attrWhere.append(" OR ").append("schema_id='").append(field).append("'");
+                        }
+
+                        nullAttrWhere.append(" UNION SELECT any_id, ").
+                                append("'").
+                                append(field).
+                                append("' AS schema_id, ").
+                                append("null AS booleanvalue, ").
+                                append("null AS datevalue, ").
+                                append("null AS doublevalue, ").
+                                append("null AS longvalue, ").
+                                append("null AS stringvalue FROM ").append(svs.field().name).
+                                append(" WHERE ").
+                                append("any_id NOT IN (").
+                                append("SELECT any_id FROM ").
+                                append(svs.asSearchViewSupport().attr().name).append(' ').append(searchView.alias).
+                                append(" WHERE ").append("schema_id='").append(field).append("')");
+                    });
+                    where.append(attrWhere).append(nullAttrWhere);
                 }
 
                 where.append(')');
@@ -251,9 +292,10 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
         });
     }
 
-    private StringBuilder buildWhere(final SearchSupport svs, final OrderBySupport obs) {
+    private StringBuilder buildWhere(
+            final SearchSupport svs, final Set<String> involvedPlainAttrs, final OrderBySupport obs) {
         StringBuilder where = new StringBuilder(" u");
-        processOBS(svs, obs, where);
+        processOBS(svs, involvedPlainAttrs, obs, where);
         where.append(" WHERE ");
         obs.views.forEach(searchView -> {
             where.append("u.any_id=").append(searchView.alias).append(".any_id AND ");
@@ -375,8 +417,10 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
         return obs;
     }
 
-    private StringBuilder getQuery(final SearchCond cond, final List<Object> parameters, final SearchSupport svs) {
+    private Pair<StringBuilder, Set<String>> getQuery(
+            final SearchCond cond, final List<Object> parameters, final SearchSupport svs) {
         StringBuilder query = new StringBuilder();
+        Set<String> involvedAttributes = new HashSet<>();
 
         switch (cond.getType()) {
             case LEAF:
@@ -419,6 +463,11 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
                 } else if (cond.getAttributeCond() != null) {
                     query.append(getQuery(cond.getAttributeCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
+                    try {
+                        involvedAttributes.add(check(cond.getAttributeCond(), svs.anyTypeKind).getLeft().getKey());
+                    } catch (IllegalArgumentException e) {
+                        // ignore
+                    }
                 } else if (cond.getAnyCond() != null) {
                     query.append(getQuery(cond.getAnyCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
@@ -426,29 +475,41 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
                 break;
 
             case AND:
-                String andSubQuery = getQuery(cond.getLeftSearchCond(), parameters, svs).toString();
+                Pair<StringBuilder, Set<String>> leftAndInfo = getQuery(cond.getLeftSearchCond(), parameters, svs);
+                involvedAttributes.addAll(leftAndInfo.getRight());
+
+                Pair<StringBuilder, Set<String>> rigthAndInfo = getQuery(cond.getRightSearchCond(), parameters, svs);
+                involvedAttributes.addAll(rigthAndInfo.getRight());
+
+                String andSubQuery = leftAndInfo.getKey().toString();
                 // Add extra parentheses
                 andSubQuery = andSubQuery.replaceFirst("WHERE ", "WHERE (");
                 query.append(andSubQuery).
                         append(" AND any_id IN ( ").
-                        append(getQuery(cond.getRightSearchCond(), parameters, svs)).
+                        append(rigthAndInfo.getKey()).
                         append("))");
                 break;
 
             case OR:
-                String orSubQuery = getQuery(cond.getLeftSearchCond(), parameters, svs).toString();
+                Pair<StringBuilder, Set<String>> leftOrInfo = getQuery(cond.getLeftSearchCond(), parameters, svs);
+                involvedAttributes.addAll(leftOrInfo.getRight());
+
+                Pair<StringBuilder, Set<String>> rigthOrInfo = getQuery(cond.getRightSearchCond(), parameters, svs);
+                involvedAttributes.addAll(rigthOrInfo.getRight());
+
+                String orSubQuery = leftOrInfo.getKey().toString();
                 // Add extra parentheses
                 orSubQuery = orSubQuery.replaceFirst("WHERE ", "WHERE (");
                 query.append(orSubQuery).
                         append(" OR any_id IN ( ").
-                        append(getQuery(cond.getRightSearchCond(), parameters, svs)).
+                        append(rigthOrInfo.getKey()).
                         append("))");
                 break;
 
             default:
         }
 
-        return query;
+        return Pair.of(query, involvedAttributes);
     }
 
     protected String getQuery(
diff --git a/core/persistence-jpa/src/main/resources/views.xml b/core/persistence-jpa/src/main/resources/views.xml
index e8e9a21..f1e8a60 100644
--- a/core/persistence-jpa/src/main/resources/views.xml
+++ b/core/persistence-jpa/src/main/resources/views.xml
@@ -78,20 +78,6 @@ under the License.
     FROM UPlainAttrValue uav, UPlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="user_search_null_attr">
-    CREATE VIEW user_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL AS booleanvalue,
-    NULL AS datevalue,
-    NULL AS doublevalue,
-    NULL AS longvalue,
-    NULL AS stringvalue
-    FROM SyncopeUser u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN UPlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="user_search_urelationship">
     CREATE VIEW user_search_urelationship AS
 
@@ -171,20 +157,6 @@ under the License.
     FROM APlainAttrValue uav, APlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="anyObject_search_null_attr">
-    CREATE VIEW anyObject_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL AS booleanvalue,
-    NULL AS datevalue,
-    NULL AS doublevalue,
-    NULL AS longvalue,
-    NULL AS stringvalue
-    FROM AnyObject u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN APlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="anyObject_search_arelationship">
     CREATE VIEW anyObject_search_arelationship AS
 
@@ -244,20 +216,6 @@ under the License.
     FROM GPlainAttrValue uav, GPlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="group_search_null_attr">
-    CREATE VIEW group_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL AS booleanvalue,
-    NULL AS datevalue,
-    NULL AS doublevalue,
-    NULL AS longvalue,
-    NULL AS stringvalue
-    FROM SyncopeGroup u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN GPlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="group_search_resource">
     CREATE VIEW group_search_resource AS
 
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
index 2c2f4d1..43cc944 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
@@ -747,4 +747,27 @@ public class AnySearchTest extends AbstractTest {
                 AnyTypeKind.USER);
         assertFalse(users.isEmpty());
     }
+    
+    @Test
+    public void issueSYNCOPE1416() {
+        AttributeCond idLeftCond = new AttributeCond(AttributeCond.Type.ISNOTNULL);
+        idLeftCond.setSchema("surname");
+        
+        AttributeCond idRightCond = new AttributeCond(AttributeCond.Type.ISNOTNULL);
+        idRightCond.setSchema("firstname");
+        
+        SearchCond searchCondition = SearchCond.getAndCond(
+                SearchCond.getLeafCond(idLeftCond), SearchCond.getLeafCond(idRightCond));
+
+        List<OrderByClause> orderByClauses = new ArrayList<>();
+        OrderByClause orderByClause = new OrderByClause();
+        orderByClause.setField("ctype");
+        orderByClause.setDirection(OrderByClause.Direction.ASC);
+        orderByClauses.add(orderByClause);
+
+        List<User> users = searchDAO.search(searchCondition, orderByClauses, AnyTypeKind.USER);
+        assertEquals(
+                searchDAO.count(SyncopeConstants.FULL_ADMIN_REALMS, searchCondition, AnyTypeKind.USER),
+                users.size());
+    }
 }
diff --git a/fit/core-reference/src/main/resources/postgres/views.xml b/fit/core-reference/src/main/resources/postgres/views.xml
index b6664c0..529901e 100644
--- a/fit/core-reference/src/main/resources/postgres/views.xml
+++ b/fit/core-reference/src/main/resources/postgres/views.xml
@@ -78,20 +78,6 @@ under the License.
     FROM UPlainAttrValue uav, UPlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="user_search_null_attr">
-    CREATE VIEW user_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL::int4 AS booleanvalue,
-    NULL::timestamp AS datevalue,
-    NULL::float8 AS doublevalue,
-    NULL::int8 AS longvalue,
-    NULL AS stringvalue
-    FROM SyncopeUser u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN UPlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="user_search_urelationship">
     CREATE VIEW user_search_urelationship AS
 
@@ -171,20 +157,6 @@ under the License.
     FROM APlainAttrValue uav, APlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="anyObject_search_null_attr">
-    CREATE VIEW anyObject_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL::int4 AS booleanvalue,
-    NULL::timestamp AS datevalue,
-    NULL::float8 AS doublevalue,
-    NULL::int8 AS longvalue,
-    NULL AS stringvalue
-    FROM AnyObject u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN APlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="anyObject_search_arelationship">
     CREATE VIEW anyObject_search_arelationship AS
 
@@ -244,20 +216,6 @@ under the License.
     FROM GPlainAttrValue uav, GPlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="group_search_null_attr">
-    CREATE VIEW group_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL::int4 AS booleanvalue,
-    NULL::timestamp AS datevalue,
-    NULL::float8 AS doublevalue,
-    NULL::int8 AS longvalue,
-    NULL AS stringvalue
-    FROM SyncopeGroup u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN GPlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="group_search_resource">
     CREATE VIEW group_search_resource AS
 
diff --git a/fit/core-reference/src/main/resources/sqlserver/views.xml b/fit/core-reference/src/main/resources/sqlserver/views.xml
index ab6be98..529901e 100644
--- a/fit/core-reference/src/main/resources/sqlserver/views.xml
+++ b/fit/core-reference/src/main/resources/sqlserver/views.xml
@@ -78,20 +78,6 @@ under the License.
     FROM UPlainAttrValue uav, UPlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="user_search_null_attr">
-    CREATE VIEW user_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL AS booleanvalue,
-    CAST (NULL AS DATETIME2) datevalue,
-    CAST (NULL AS FLOAT) doublevalue,
-    CAST (NULL AS BIGINT) longvalue,
-    CAST (NULL AS VARCHAR(255)) AS stringvalue
-    FROM SyncopeUser u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN UPlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="user_search_urelationship">
     CREATE VIEW user_search_urelationship AS
 
@@ -171,20 +157,6 @@ under the License.
     FROM APlainAttrValue uav, APlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="anyObject_search_null_attr">
-    CREATE VIEW anyObject_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL AS booleanvalue,
-    CAST (NULL AS DATETIME2) datevalue,
-    CAST (NULL AS FLOAT) doublevalue,
-    CAST (NULL AS BIGINT) longvalue,
-    CAST (NULL AS VARCHAR(255)) AS stringvalue
-    FROM AnyObject u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN APlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="anyObject_search_arelationship">
     CREATE VIEW anyObject_search_arelationship AS
 
@@ -244,20 +216,6 @@ under the License.
     FROM GPlainAttrValue uav, GPlainAttr ua
     WHERE uav.attribute_id = ua.id
   </entry>
-  <entry key="group_search_null_attr">
-    CREATE VIEW group_search_null_attr AS
-
-    SELECT u.id AS any_id,
-    PlainSchema.id AS schema_id,
-    NULL AS booleanvalue,
-    CAST (NULL AS DATETIME2) datevalue,
-    CAST (NULL AS FLOAT) doublevalue,
-    CAST (NULL AS BIGINT) longvalue,
-    CAST (NULL AS VARCHAR(255)) AS stringvalue
-    FROM SyncopeGroup u CROSS JOIN PlainSchema
-    LEFT OUTER JOIN GPlainAttr ua ON (PlainSchema.id = ua.schema_id AND ua.owner_id = u.id)
-    WHERE ua.id IS NULL
-  </entry>
   <entry key="group_search_resource">
     CREATE VIEW group_search_resource AS
 
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index 847f2aa..98cfd21 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -34,6 +34,7 @@ import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.search.SpecialAttr;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
 import org.apache.syncope.common.lib.to.PagedResult;
@@ -287,6 +288,17 @@ public class SearchITCase extends AbstractITCase {
                         and("username").equalTo("bellini").query()).
                 build());
         assertEquals(users, issueSYNCOPE1321);
+        
+        // SYNCOPE-1416 (check the search for attributes of type different from stringvalue)
+        PagedResult<UserTO> issueSYNCOPE1416 = userService.search(new AnyQuery.Builder().
+                realm(SyncopeConstants.ROOT_REALM).
+                fiql(SyncopeClient.getUserSearchConditionBuilder().
+                        is("loginDate").lexicalNotBefore("2009-05-26").
+                        and("username").equalTo("rossini").query()).
+                orderBy(SyncopeClient.getOrderByClauseBuilder().asc("loginDate").build()).
+                build());
+        assertEquals(1, issueSYNCOPE1416.getSize());
+        assertEquals("rossini", issueSYNCOPE1416.getResult().get(0).getUsername());
     }
 
     @Test