4343``bindpwd`` (string)
4444The credentials for the binddn.
4545
46+ ``pageSize`` (integer)
47+ Paged mode size (default: 1000)
48+
49+
4650Usage Example
4751-------------
4852
7983 [email protected] | Some Test User | 8084 (3 rows)
8185
86+ .. code-block:: bash
87+
88+ CREATE FOREIGN TABLE ldapgroups (
89+ entryDN character varying,
90+ cn character varying,
91+ ou character varying[],
92+ gidnumber integer,
93+ memberuid character varying[],
94+ objectClass character varying[]
95+ ) server ldap_srv options (
96+ uri 'ldap://localhost',
97+ path 'ou=Groups,dc=example,dc=com',
98+ scope 'sub',
99+ objectclass '*',
100+ pagesize '200'
101+ );
102+
103+ SELECT cn,gidnumber,objectClass FROM ldapgroups WHERE cn = 'Administrators';
104+
105+ .. code-block:: bash
106+
107+ cn | gidnumber | objectclass
108+ ----------------+-----------+--------------------------------
109+ Administrators | 544 | {posixGroup,sambaGroupMapping}
110+ (1 row)
111+
112+ .. code-block:: bash
113+
114+ SELECT unnest(objectClass) as cls,count(entryDN) as cnt FROM ldapgroups GROUP BY cls;
115+
116+ .. code-block:: bash
117+
118+ cls | cnt
119+ ---------------------+-----
120+ domainRelatedObject | 1
121+ organizationalUnit | 4
122+ groupOfUniqueNames | 1
123+ top | 10
124+ sambaGroupMapping | 10
125+ posixGroup | 16
126+ (6 rows)
127+
82128"""
83129
84130from . import ForeignDataWrapper
@@ -110,6 +156,7 @@ class LdapFdw(ForeignDataWrapper):
110156 scope -- the ldap scope (one, sub or base)
111157 binddn -- the ldap bind DN (ex: 'cn=Admin,dc=example,dc=com')
112158 bindpwd -- the ldap bind Password
159+ pageSize -- the max entries per page (default: 1000 per Active Directory)
113160
114161 """
115162
@@ -123,7 +170,8 @@ def __init__(self, fdw_options, fdw_columns):
123170 ldap3 .Server (self .ldapuri ),
124171 user = fdw_options .get ("binddn" , None ),
125172 password = fdw_options .get ("bindpwd" , None ),
126- client_strategy = ldap3 .RESTARTABLE if ldap3 .version .__version__ > '2.0.0' else ldap3 .STRATEGY_SYNC_RESTARTABLE )
173+ client_strategy = ldap3 .RESTARTABLE if ldap3 .version .__version__ > '2.0.0' else ldap3 .STRATEGY_SYNC_RESTARTABLE ,
174+ return_empty_attributes = False )
127175 self .path = fdw_options ["path" ]
128176 self .scope = self .parse_scope (fdw_options .get ("scope" , None ))
129177 self .object_class = fdw_options ["objectclass" ]
@@ -133,6 +181,7 @@ def __init__(self, fdw_options, fdw_columns):
133181 self .array_columns = [
134182 col .column_name for name , col in self .field_definitions .items ()
135183 if col .type_name .endswith ('[]' )]
184+ self .page_size = int (fdw_options ["pagesize" ]) if "pagesize" in fdw_options else 1000
136185
137186 def execute (self , quals , columns ):
138187 request = unicode_ ("(objectClass=%s)" ) % self .object_class
@@ -150,22 +199,30 @@ def execute(self, quals, columns):
150199 val = qual .value
151200 request = unicode_ ("(&%s(%s=%s))" ) % (
152201 request , qual .field_name , val )
153- self .ldap .search (
202+ # Always use paged search mode to read data
203+ generator = self .ldap .extend .standard .paged_search (
154204 self .path , request , self .scope ,
155- attributes = list (self .field_definitions ))
156- for entry in self .ldap .response :
205+ attributes = list (self .field_definitions ),
206+ paged_size = self .page_size ,
207+ generator = True )
208+ for entry in generator :
157209 # Case insensitive lookup for the attributes
158210 litem = dict ()
159211 for key , value in entry ["attributes" ].items ():
160212 if key .lower () in self .field_definitions :
161213 pgcolname = self .field_definitions [key .lower ()].column_name
162214 if ldap3 .version .__version__ > '2.0.0' :
163- value = value
215+ if pgcolname in self .array_columns :
216+ value = value
217+ else :
218+ value = value [0 ] if isinstance (value , list ) else value
164219 else :
165220 if pgcolname in self .array_columns :
166221 value = value
167222 else :
168223 value = value [0 ]
224+ if not value :
225+ value = None
169226 litem [pgcolname ] = value
170227 yield litem
171228
0 commit comments