Table of Contents
- Introduction
- Establishing a Connection
- Searching Hierarchical Data
- Browsing Attributes (this page)
- Timeouts
- Modifying Data
Searching Hierarchical Data with Attributes
Returning attributes with search results
The examples in the prior chapter use the “1.1” code to return no attributes.
In this example we’ll return two of the attributes associated with an entry.
Instead of building a collection of one element containing “1.1”, the collection will have the name of each attributes we want to return.
Also note, the attronly => 0 parameter. If attronly is 1 then only the names of attributes will be returned. With 0, the values associated with each attributes are also returned.
DECLARE v_result PLS_INTEGER; v_session DBMS_LDAP.session; v_search_attrs DBMS_LDAP.string_collection; v_search_results DBMS_LDAP.MESSAGE; v_entry DBMS_LDAP.MESSAGE; v_distinguished_name VARCHAR2(256); v_values DBMS_LDAP.string_collection; BEGIN DBMS_LDAP.use_exception := TRUE; v_session := DBMS_LDAP.init(hostname => 'db.debian.org', portnum => DBMS_LDAP.port); v_search_attrs(1) := 'description'; v_search_attrs(2) := 'admin'; v_result := DBMS_LDAP.search_s(ld => v_session, base => 'host=beach,ou=hosts,dc=debian,dc=org', scope => DBMS_LDAP.scope_base, filter => 'objectclass=*', attrs => v_search_attrs, attronly => 0, res => v_search_results); v_entry := DBMS_LDAP.first_entry(v_session, v_search_results); v_distinguished_name := DBMS_LDAP.get_dn(v_session, v_entry); DBMS_OUTPUT.put_line('DN: ' || v_distinguished_name); FOR i IN 1 .. v_search_attrs.COUNT LOOP v_values := DBMS_LDAP.get_values(v_session, v_entry, v_search_attrs(i)); IF v_values.COUNT > 0 THEN FOR j IN v_values.FIRST .. v_values.LAST LOOP DBMS_OUTPUT.put_line(v_search_attrs(i) || ' : ' || v_values(j)); END LOOP; ELSE DBMS_OUTPUT.put_line(v_search_attrs(i) || ' not found'); END IF; END LOOP; v_result := DBMS_LDAP.msgfree(v_entry); v_result := DBMS_LDAP.unbind_s(v_session); END; / DN: host=beach,ou=hosts,dc=debian,dc=org description : bugs.debian.org web frontend admin : debian-admin@lists.debian.org
Sometimes you might not know all of the attributes for an entry. Perhaps you’re doing a sub-tree search across different entry types and the attributes might change. In these scenarios you may need to employ a wildcard search and return all of the attributes for a given entry.
To return all of them, simply define an attribute array of one element consisting of the value ‘*’. It is legal syntax to include other attribute names in the array, but there is no functional value in doing so.
In the snippet below we’ll pull all of the attributes for the “host=beach” entry. Because we don’t know their names, in order to retrieve them we use a new data type: “DBMS_LDAP.BER_ELEMENT”. “BER” stands for Basic Encoding Rule. The datatype is a RAW, holding a pointer to the encoded attributes. With attronly set to 1, only the names of the attributes will be returned.
DECLARE v_result PLS_INTEGER; v_session DBMS_LDAP.session; v_search_attrs DBMS_LDAP.string_collection; v_search_results DBMS_LDAP.MESSAGE; v_entry DBMS_LDAP.MESSAGE; v_distinguished_name VARCHAR2(256); v_attribute_name VARCHAR2(256); v_ber DBMS_LDAP.ber_element; BEGIN DBMS_LDAP.use_exception := TRUE; v_session := DBMS_LDAP.init(hostname => 'db.debian.org', portnum => DBMS_LDAP.port); v_search_attrs(1) := '*'; v_result := DBMS_LDAP.search_s(ld => v_session, base => 'host=beach,ou=hosts,dc=debian,dc=org', scope => DBMS_LDAP.scope_base, filter => 'objectclass=*', attrs => v_search_attrs, attronly => 1, res => v_search_results); v_entry := DBMS_LDAP.first_entry(v_session, v_search_results); v_distinguished_name := DBMS_LDAP.get_dn(v_session, v_entry); DBMS_OUTPUT.put_line('DN: ' || v_distinguished_name); v_attribute_name := DBMS_LDAP.first_attribute(v_session, v_entry, v_ber); WHILE v_attribute_name IS NOT NULL LOOP DBMS_OUTPUT.put_line(v_attribute_name); v_attribute_name := DBMS_LDAP.next_attribute(v_session, v_entry, v_ber); END LOOP; DBMS_LDAP.ber_free(v_ber, 1); v_result := DBMS_LDAP.unbind_s(v_session); END; / DN: host=beach,ou=hosts,dc=debian,dc=org objectClass distribution access admin architecture host purpose allowedGroups description hostname sshRSAHostKey mXRecord rebootPolicy physicalHost sponsor ipHostNumber
Once you have the names you could then go back and pull values for specific attributes as shown in the first example above. Or, we can return the attributes from a wildcard along with their attributes.
DECLARE v_result PLS_INTEGER; v_session DBMS_LDAP.session; v_search_attrs DBMS_LDAP.string_collection; v_search_results DBMS_LDAP.MESSAGE; v_entry DBMS_LDAP.MESSAGE; v_distinguished_name VARCHAR2(256); v_attribute_name VARCHAR2(256); v_attribute_values DBMS_LDAP.string_collection; v_ber DBMS_LDAP.ber_element; -- Basic Encoding Rule BEGIN DBMS_LDAP.use_exception := TRUE; v_session := DBMS_LDAP.init(hostname => 'db.debian.org', portnum => DBMS_LDAP.port); v_search_attrs(1) := '*'; v_result := DBMS_LDAP.search_s(ld => v_session, base => 'host=beach,ou=hosts,dc=debian,dc=org', scope => DBMS_LDAP.scope_base, filter => 'objectclass=*', attrs => v_search_attrs, attronly => 0, res => v_search_results); v_entry := DBMS_LDAP.first_entry(v_session, v_search_results); v_distinguished_name := DBMS_LDAP.get_dn(v_session, v_entry); DBMS_OUTPUT.put_line('DN: ' || v_distinguished_name); v_attribute_name := DBMS_LDAP.first_attribute(v_session, v_entry, v_ber); WHILE v_attribute_name IS NOT NULL LOOP v_attribute_values := DBMS_LDAP.get_values(v_session, v_entry, v_attribute_name); CASE v_attribute_values.COUNT WHEN 0 THEN NULL; WHEN 1 THEN DBMS_OUTPUT.put_line(v_attribute_name || ' : ' || v_attribute_values(0)); ELSE DBMS_OUTPUT.put_line(v_attribute_name || ' :'); FOR i IN v_attribute_values.FIRST .. v_attribute_values.LAST LOOP DBMS_OUTPUT.put_line('...' || v_attribute_values(i)); END LOOP; END CASE; v_attribute_name := DBMS_LDAP.next_attribute(v_session, v_entry, v_ber); END LOOP; DBMS_LDAP.ber_free(v_ber, 1); v_result := DBMS_LDAP.unbind_s(v_session); END; / DN: host=beach,ou=hosts,dc=debian,dc=org objectClass : ...top ...debianServer distribution : Debian GNU/Linux access : restricted admin : debian-admin@lists.debian.org architecture : amd64 host : beach purpose : [[*bugs.debian.org|bugs web frontend]] allowedGroups : ...debbugs ...Debian description : bugs.debian.org web frontend hostname : beach.debian.org
Note, some of the attributes can have more than one value. The “objectClass” attribute is a common one to have multiple values. This is important to remember when retrieving values for an entry that there isn’t a 1:1 distribution.
Also note, while you can wildcard the entirety of an attribute set, the “attrs” parameter collection does not support wildcards within an attribute name.
For example there is no syntax to request all attributes starting with the letter “a”. Trying something like “v_search_attrs(1) := ‘a*’;” won’t produce an error, it will simply fail to find an attribute with the exact name “a*”.
If you wanted to simulate such functionality you would need to return the list of all attribute names, then use that list to generate just the subset of attributes in which you were interested and build a collection of those. Then search again using just those names, as in the first example, but with attrsonly=>0 to return their values.
In the next chapter we’ll explore setting timeouts on searches.
Great article!
I have a question :
Is it possible (using dbms_ldap package) to update/add attributes that support multiple values (for example a Distribution list/group with multiple “member” values) ?
Thanks,
Alex
Yes it is possible. In part 6 of my series I show how to modify data including adding, updating, and deleting records.
When inserting or updating you populate an array of values. In my examples I only use one attribute, but it’s an array so you can insert or modify more than one value at a time.
There is no api for modifying more than one dn entries value at a time though.
If you had multiple entries to insert/update/delete you’d have to loop through them calling the add_s, modify_s, delete_s, or delete function for each one.