如何使用Oracle DBMS_LDAP执行大型(大于Sizelimit)LDAP查询

如何使用Oracle DBMS_LDAP执行大型(大于Sizelimit)LDAP查询,oracle,plsql,ldap,Oracle,Plsql,Ldap,我在11g数据库中有一个PL/SQL包,它查找各种属性并处理组成员身份等问题。特别是一个函数是一个流水线函数,它返回函数参数中指定的组的所有成员。对于成员少于1000人的团队来说,它非常有效。在这种情况下,我会收到以下错误消息: ORA-31202:DBMS_LDAP:LDAP客户端/服务器错误:超出了Sizelimit 我知道LDAP(特别是MS Active Directory,这是我正在处理的)的查询结果集大小限制为1000。如果LDAP搜索的结果超过了这么多条目,那么查询就会失败,并且不

我在11g数据库中有一个PL/SQL包,它查找各种属性并处理组成员身份等问题。特别是一个函数是一个流水线函数,它返回函数参数中指定的组的所有成员。对于成员少于1000人的团队来说,它非常有效。在这种情况下,我会收到以下错误消息:

ORA-31202:DBMS_LDAP:LDAP客户端/服务器错误:超出了Sizelimit

我知道LDAP(特别是MS Active Directory,这是我正在处理的)的查询结果集大小限制为1000。如果LDAP搜索的结果超过了这么多条目,那么查询就会失败,并且不返回任何结果。我没有修改广告模式或类似内容的选项。我知道LDAP中有一个“分页”结果集的概念,但在我所回顾的DBMS_LDAP文档中没有提到该功能

我将非常感谢您为解决方案或解决方法提供的任何建议、指导或文档URL


如果“查询切片”是最好的方法,那么请注意,从查询所有顶级OU开始,并在搜索筛选器中使用逻辑and可能适用于某些情况,但不能保证一个OU中不会有1000个或更多用户对象,并且也是目标安全组的成员。因此,它可能比你的限制要聪明一些。

在论坛中找到一些非官方的对等支持响应后,我相信截至2015年,DB11G附带的DBMS_LDAP包没有实现标准的“分页搜索结果控制”()

解决这个问题的方法(仍然有限)是创建一个嵌套for循环,逐步遍历字母表中的每个字母,创建一个通用名称过滤短语。再加上LDAP组成员资格可以通过memberof多值属性或primaryGroupID属性表示,您就有52个单独的过滤查询了!它起作用了,不是太快,但它起作用了

  DECLARE
      l_retval      PLS_INTEGER;
      l_alphabet    varchar2(26) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      l_slice_prefix varchar2(16);
      l_slice_suffix varchar2(16);
      l_filter     dbms_ldap.string_collection;
      l_slice_filter varchar2(1000);
      l_primaryGroupToken varchar2(128);
   BEGIN     
      l_primaryGroupToken := get_primaryGroupToken(p_group);

      l_retval := get_ldap_session();

      --LDAP idiosyncracy: primaryGroup is NOT listed in member of. 
      --So you really need two distinct queries and "union" them together.     

      l_filter(0) := '(&(objectCategory=person)(objectClass=user)(primaryGroupID='|| l_primaryGroupToken ||')(!(description=Built-in*)))';
      -- lfilter(1) must be populated with output of get_group_dn...
      l_filter(1) := '(&(objectCategory=person)(objectClass=user)(memberof='|| get_group_dn(p_group) ||'))';

        --ORA-31202: DBMS_LDAP: LDAP client/server error: Sizelimit exceeded
        --https://msdn.microsoft.com/en-us/library/ms180880%28v=vs.80%29.aspx
        --So shame on MS for the small limit, and shame on Oracle 
        --for not implementing paging.
        --Now we have to implement our own slicing/paging. 
        --In this case we'll just do first char of the CN
        --against each letter of the alphabet. So 26 "non-uniform" pages.

      <<filter_loop>> 
      for iq in l_filter.FIRST..l_filter.LAST LOOP
          <<slice_loop>> --see above explanation for sizelimits, this is in lieu of real LDAP control paging.
          FOR alphaindex in 1..26 LOOP 
              l_slice_prefix := '(&(CN='||substr(l_alphabet,alphaindex,1)||'*)';
              l_slice_suffix := ')';
              l_slice_filter := l_slice_prefix || l_filter(iq) || l_slice_suffix;
              l_retval := dbms_ldap.search_s(ld       => g_session,
                                             base     => g_ldap_auth_base,
                                             scope    => dbms_ldap.scope_subtree,
                                             filter   => l_slice_prefix || l_filter(iq) || l_slice_suffix,
                                             attrs    => l_attrs,
                                             attronly => 0,
                                             res      => l_message);
              if L_retval = DBMS_LDAP.SUCCESS then

              -- ...

              END IF;
           END LOOP slice_loop;
        END LOOP filter_loop;
   END;
声明
l_retval PLS_INTEGER;
字母varchar2(26):=“ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
l_slice_前缀varchar2(16);
l_slice_后缀varchar2(16);
l_filter dbms_ldap.string_集合;
l_片_滤波器varchar2(1000);
l_primaryGroupToken varchar2(128);
开始
l_primaryGroupToken:=获取_primaryGroupToken(p_组);
l_retval:=get_ldap_session();
--LDAP特性:primaryGroup未列在的成员中。
--因此,您确实需要两个不同的查询并将它们“联合”在一起。
l|u过滤器(0):='(&(objectCategory=person)(objectClass=user)(primaryGroupID='| | l|u primaryGroupToken | |])(!(description=内置*));
--lfilter(1)必须填充get\u group\u dn的输出。。。
l|u filter(1):='(&(objectCategory=person)(objectClass=user)(memberof='| | get|u group| |');
--ORA-31202:DBMS_LDAP:LDAP客户端/服务器错误:超出了Sizelimit
--https://msdn.microsoft.com/en-us/library/ms180880%28v=vs.80%29.aspx
--因此,微软的小限制让人羞愧,甲骨文也让人羞愧
--用于不实现分页。
--现在我们必须实现自己的切片/分页。
--在本例中,我们将只执行CN的第一个字符
--对照字母表中的每个字母。所以有26个“非统一”页面。
对于l_筛选器中的iq。第一个..l_筛选器。最后一个循环
--请参见上面关于sizelimits的解释,这将代替真正的LDAP控件分页。
对于1..26循环中的alphaindex
l_slice_前缀:='(&(CN='| | substr(l_字母表,字母索引,1)| |'*);
l_slice_后缀:=')';
l_slice_filter:=l_slice_前缀| | l_filter(iq)| l_slice_后缀;
l_retval:=dbms_ldap.search_s(ld=>g_session,
base=>g_ldap_auth_base,
scope=>dbms\u ldap.scope\u子树,
filter=>l|u slice_前缀| l|u filter(iq)| l|u slice_后缀,
属性=>l_属性,
attronly=>0,
res=>l_消息);
如果L_retval=DBMS_LDAP.SUCCESS,则
-- ...
如果结束;
端环切片_环;
端环滤波器;
结束;