1 /*        $NetBSD: back-sql.h,v 1.3 2021/08/14 16:15:01 christos Exp $          */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2021 The OpenLDAP Foundation.
7  * Portions Copyright 1999 Dmitry Kovalev.
8  * Portions Copyright 2002 Pierangelo Mararati.
9  * Portions Copyright 2004 Mark Adamson.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by Dmitry Kovalev for inclusion
22  * by OpenLDAP Software.  Additional significant contributors include
23  * Pierangelo Masarati and Mark Adamson.
24  */
25 /*
26  * The following changes have been addressed:
27  *
28  * Enhancements:
29  *   - re-styled code for better readability
30  *   - upgraded backend API to reflect recent changes
31  *   - LDAP schema is checked when loading SQL/LDAP mapping
32  *   - AttributeDescription/ObjectClass pointers used for more efficient
33  *     mapping lookup
34  *   - bervals used where string length is required often
35  *   - atomized write operations by committing at the end of each operation
36  *     and defaulting connection closure to rollback
37  *   - added LDAP access control to write operations
38  *   - fully implemented modrdn (with rdn attrs change, deleteoldrdn,
39  *     access check, parent/children check and more)
40  *   - added parent access control, children control to delete operation
41  *   - added structuralObjectClass operational attribute check and
42  *     value return on search
43  *   - added hasSubordinate operational attribute on demand
44  *   - search limits are appropriately enforced
45  *   - function backsql_strcat() has been made more efficient
46  *   - concat function has been made configurable by means of a pattern
47  *   - added config switches:
48  *       - fail_if_no_mapping write operations fail if there is no mapping
49  *       - has_ldapinfo_dn_ru overrides autodetect
50  *       - concat_pattern     a string containing two '?' is used
51  *                                      (note that "?||?" should be more portable
52  *                                      than builtin function "CONCAT(?,?)")
53  *       - strcast_func                 cast of string constants in "SELECT DISTINCT
54  *                                      statements (needed by PostgreSQL)
55  *       - upper_needs_cast   cast the argument of upper when required
56  *                                      (basically when building dn substring queries)
57  *   - added noop control
58  *   - added values return filter control
59  *   - hasSubordinate can be used in search filters (with limitations)
60  *   - eliminated oc->name; use oc->oc->soc_cname instead
61  *
62  * Todo:
63  *   - add security checks for SQL statements that can be injected (?)
64  *   - re-test with previously supported RDBMs
65  *   - replace dn_ru and so with normalized dn (no need for upper() and so
66  *     in dn match)
67  *   - implement a backsql_normalize() function to replace the upper()
68  *     conversion routines
69  *   - note that subtree deletion, subtree renaming and so could be easily
70  *     implemented (rollback and consistency checks are available :)
71  *   - implement "lastmod" and other operational stuff (ldap_entries table ?)
72  *   - check how to allow multiple operations with one statement, to remove
73  *     BACKSQL_REALLOC_STMT from modify.c (a more recent unixODBC lib?)
74  */
75 /*
76  * Improvements submitted by (ITS#3432)
77  *
78  * 1. id_query.patch                    applied (with changes)
79  * 2. shortcut.patch                    applied (reworked)
80  * 3. create_hint.patch                 applied
81  * 4. count_query.patch                 applied (reworked)
82  * 5. returncodes.patch                 applied (with sanity checks)
83  * 6. connpool.patch                    under evaluation
84  * 7. modoc.patch             under evaluation (requires
85  *                                      manageDSAit and "manage"
86  *                                      access privileges)
87  * 8. miscfixes.patch                   applied (reworked; other
88  *                                      operations need to load the
89  *                                      entire entry for ACL purposes;
90  *                                      see ITS#3480, now fixed)
91  *
92  * original description:
93 
94          Changes that were made to the SQL backend.
95 
96 The patches were made against 2.2.18 and can be applied individually,
97 but would best be applied in the numerical order of the file names.
98 A synopsis of each patch is given here:
99 
100 
101 1. Added an option to set SQL query for the "id_query" operation.
102 
103 2. Added an option to the SQL backend called "use_subtree_shortcut".
104 When a search is performed, the SQL query includes a WHERE clause
105 which says the DN must be "LIKE %<searchbase>".  The LIKE operation
106 can be slow in an RDBM. This shortcut option says that if the
107 searchbase of the LDAP search is the root DN of the SQL backend,
108 and thus all objects will match the LIKE operator, do not include
109 the "LIKE %<searchbase>" clause in the SQL query (it is replaced
110 instead by the always true "1=1" clause to keep the "AND"'s
111 working correctly).  This option is off by default, and should be
112 turned on only if all objects to be found in the RDBM are under the
113 same root DN. Multiple backends working within the same RDBM table
114 space would encounter problems. LDAP searches whose searchbase are
115 not at the root DN will bypass this shortcut and employ the LIKE
116 clause.
117 
118 3. Added a "create_hint" column to ldap_oc_mappings table. Allows
119 taking the value of an attr named in "create_hint" and passing it to
120 the create_proc procedure.  This is necessary for when an objectClass's
121 table is partition indexed by some indexing column and thus the value
122 in that indexing column cannot change after the row is created. The
123 value for the indexed column is passed into the create_proc, which
124 uses it to fill in the indexed column as the new row is created.
125 
126 4. When loading the values of an attribute, the count(*) of the number
127 of values is fetched first and memory is allocated for the array of
128 values and normalized values. The old system of loading the values one
129 by one and running realloc() on the array of values and normalized
130 values each time was badly fragmenting memory. The array of values and
131 normalized values would be side by side in memory, and realloc()'ing
132 them over and over would force them to leapfrog each other through all
133 of available memory. Attrs with a large number of values could not be
134 loaded without crashing the slapd daemon.
135 
136 5. Added code to interpret the value returned by stored procedures
137 which have expect_return set. Returned value is interpreted as an LDAP
138 return code. This allows the distinction between the SQL failing to
139 execute and the SQL running to completion and returning an error code
140 which can indicate a policy violation.
141 
142 6. Added RDBM connection pooling. Once an operation is finished the
143 connection to the RDBM is returned to a pool rather than closing.
144 Allows the next operation to skip the initialization and authentication
145 phases of contacting the RDBM. Also, if licensing with ODBC places
146 a limit on the number of connections, an LDAP thread can block waiting
147 for another thread to finish, so that no LDAP errors are returned
148 for having more LDAP connections than allowed RDBM connections. An
149 RDBM connection which receives an SQL error is marked as "tainted"
150 so that it will be closed rather than returned to the pool.
151   Also, RDBM connections must be bound to a given LDAP connection AND
152 operation number, and NOT just the connection number.  Asynchronous
153 LDAP clients can have multiple simultaneous LDAP operations which
154 should not share the same RDBM connection.  A given LDAP operation can
155 even make multiple SQL operations (e.g. a BIND operation which
156 requires SASL to perform an LDAP search to convert the SASL ID to an
157 LDAP DN), so each RDBM connection now has a refcount that must reach
158 zero before the connection is returned to the free pool.
159 
160 7. Added ability to change the objectClass of an object. Required
161 considerable work to copy all attributes out of old object and into
162 new object.  Does a schema check before proceeding.  Creates a new
163 object, fills it in, deletes the old object, then changes the
164 oc_map_id and keyval of the entry in the "ldap_entries" table.
165 
166 8.  Generic fixes. Includes initializing pointers before they
167 get used in error branch cases, pointer checks before dereferencing,
168 resetting a return code to success after a COMPARE op, sealing
169 memory leaks, and in search.c, changing some of the "1=1" tests to
170 "2=2", "3=3", etc so that when reading slapd trace output, the
171 location in the source code where the x=x test was added to the SQL
172 can be easily distinguished.
173  */
174 
175 #ifndef __BACKSQL_H__
176 #define __BACKSQL_H__
177 
178 /* former sql-types.h */
179 #include <sql.h>
180 #include <sqlext.h>
181 
182 typedef struct {
183           SWORD               ncols;
184           BerVarray col_names;
185           UDWORD              *col_prec;
186           SQLSMALLINT         *col_type;
187           char                **cols;
188           SQLLEN              *value_len;
189 } BACKSQL_ROW_NTS;
190 
191 /*
192  * Better use the standard length of 8192 (as of slap.h)?
193  *
194  * NOTE: must be consistent with definition in ldap_entries table
195  */
196 /* #define BACKSQL_MAX_DN_LEN SLAP_LDAPDN_MAXLEN */
197 #define BACKSQL_MAX_DN_LEN    255
198 
199 /*
200  * define to enable very extensive trace logging (debug only)
201  */
202 #undef BACKSQL_TRACE
203 
204 /*
205  * define if using MS SQL and workaround needed (see sql-wrap.c)
206  */
207 #undef BACKSQL_MSSQL_WORKAROUND
208 
209 /*
210  * define to enable values counting for attributes
211  */
212 #define BACKSQL_COUNTQUERY
213 
214 /*
215  * define to enable prettification/validation of values
216  */
217 #define BACKSQL_PRETTY_VALIDATE
218 
219 /*
220  * define to enable varchars as unique keys in user tables
221  *
222  * by default integers are used (and recommended)
223  * for performances.  Integers are used anyway in back-sql
224  * related tables.
225  */
226 #undef BACKSQL_ARBITRARY_KEY
227 
228 /*
229  * type used for keys
230  */
231 #if defined(HAVE_LONG_LONG) && defined(SQL_C_UBIGINT) && \
232           ( defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ) )
233 typedef unsigned long long backsql_key_t;
234 #define BACKSQL_C_NUMID       SQL_C_UBIGINT
235 #define BACKSQL_IDNUMFMT "%llu"
236 #define BACKSQL_STR2ID lutil_atoullx
237 #else /* ! HAVE_LONG_LONG || ! SQL_C_UBIGINT */
238 typedef unsigned long backsql_key_t;
239 #define BACKSQL_C_NUMID       SQL_C_ULONG
240 #define BACKSQL_IDNUMFMT "%lu"
241 #define BACKSQL_STR2ID lutil_atoulx
242 #endif /* ! HAVE_LONG_LONG */
243 
244 /*
245  * define to enable support for syncprov overlay
246  */
247 #define BACKSQL_SYNCPROV
248 
249 /*
250  * define to the appropriate aliasing string
251  *
252  * some RDBMSes tolerate (or require) that " AS " is not used
253  * when aliasing tables/columns
254  */
255 #define BACKSQL_ALIASING      "AS "
256 /* #define          BACKSQL_ALIASING    "" */
257 
258 /*
259  * define to the appropriate quoting char
260  *
261  * some RDBMSes tolerate/require that the aliases be enclosed
262  * in quotes.  This is especially true for those that do not
263  * allow keywords used as aliases.
264  */
265 #define BACKSQL_ALIASING_QUOTE          ""
266 /* #define BACKSQL_ALIASING_QUOTE       "\"" */
267 /* #define BACKSQL_ALIASING_QUOTE       "'" */
268 
269 /*
270  * API
271  *
272  * a simple mechanism to allow DN mucking between the LDAP
273  * and the stored string representation.
274  */
275 typedef struct backsql_api {
276           char                          *ba_name;
277           int                           (*ba_config)( struct backsql_api *self, int argc, char *argv[] );
278           int                           (*ba_destroy)( struct backsql_api *self );
279 
280           int                           (*ba_dn2odbc)( Operation *op, SlapReply *rs, struct berval *dn );
281           int                           (*ba_odbc2dn)( Operation *op, SlapReply *rs, struct berval *dn );
282 
283           void                          *ba_private;
284           struct backsql_api  *ba_next;
285           char **ba_argv;
286           int       ba_argc;
287 } backsql_api;
288 
289 /*
290  * "structural" objectClass mapping structure
291  */
292 typedef struct backsql_oc_map_rec {
293           /*
294            * Structure of corresponding LDAP objectClass definition
295            */
296           ObjectClass                   *bom_oc;
297 #define BACKSQL_OC_NAME(ocmap)          ((ocmap)->bom_oc->soc_cname.bv_val)
298 
299           struct berval                 bom_keytbl;
300           struct berval                 bom_keycol;
301           /* expected to return keyval of newly created entry */
302           char                          *bom_create_proc;
303           /* in case create_proc does not return the keyval of the newly
304            * created row */
305           char                          *bom_create_keyval;
306           /* supposed to expect keyval as parameter and delete
307            * all the attributes as well */
308           char                          *bom_delete_proc;
309           /* flags whether delete_proc is a function (whether back-sql
310            * should bind first parameter as output for return code) */
311           int                           bom_expect_return;
312           backsql_key_t                 bom_id;
313           Avlnode                       *bom_attrs;
314           AttributeDescription          *bom_create_hint;
315 } backsql_oc_map_rec;
316 
317 /*
318  * attributeType mapping structure
319  */
320 typedef struct backsql_at_map_rec {
321           /* Description of corresponding LDAP attribute type */
322           AttributeDescription          *bam_ad;
323           AttributeDescription          *bam_true_ad;
324           /* ObjectClass if bam_ad is objectClass */
325           ObjectClass                   *bam_oc;
326 
327           struct berval       bam_from_tbls;
328           struct berval       bam_join_where;
329           struct berval       bam_sel_expr;
330 
331           /* TimesTen, or, if a uppercase function is defined,
332            * an uppercased version of bam_sel_expr */
333           struct berval       bam_sel_expr_u;
334 
335           /* supposed to expect 2 binded values: entry keyval
336            * and attr. value to add, like "add_name(?,?,?)" */
337           char                *bam_add_proc;
338           /* supposed to expect 2 binded values: entry keyval
339            * and attr. value to delete */
340           char                *bam_delete_proc;
341           /* for optimization purposes attribute load query
342            * is preconstructed from parts on schemamap load time */
343           char                *bam_query;
344 #ifdef BACKSQL_COUNTQUERY
345           char                *bam_countquery;
346 #endif /* BACKSQL_COUNTQUERY */
347           /* following flags are bitmasks (first bit used for add_proc,
348            * second - for delete_proc) */
349           /* order of parameters for procedures above;
350            * 1 means "data then keyval", 0 means "keyval then data" */
351           int                 bam_param_order;
352           /* flags whether one or more of procedures is a function
353            * (whether back-sql should bind first parameter as output
354            * for return code) */
355           int                 bam_expect_return;
356 
357           /* next mapping for attribute */
358           struct backsql_at_map_rec     *bam_next;
359 } backsql_at_map_rec;
360 
361 #define BACKSQL_AT_MAP_REC_INIT { NULL, NULL, BER_BVC(""), BER_BVC(""), BER_BVNULL, BER_BVNULL, NULL, NULL, NULL, 0, 0, NULL }
362 
363 /* define to uppercase filters only if the matching rule requires it
364  * (currently broken) */
365 /* #define          BACKSQL_UPPERCASE_FILTER */
366 
367 #define   BACKSQL_AT_CANUPPERCASE(at)   ( !BER_BVISNULL( &(at)->bam_sel_expr_u ) )
368 
369 /* defines to support bitmasks above */
370 #define BACKSQL_ADD 0x1
371 #define BACKSQL_DEL 0x2
372 
373 #define BACKSQL_IS_ADD(x)     ( ( BACKSQL_ADD & (x) ) == BACKSQL_ADD )
374 #define BACKSQL_IS_DEL(x)     ( ( BACKSQL_DEL & (x) ) == BACKSQL_DEL )
375 
376 #define BACKSQL_NCMP(v1,v2)   ber_bvcmp((v1),(v2))
377 
378 #define BACKSQL_CONCAT
379 /*
380  * berbuf structure: a berval with a buffer size associated
381  */
382 typedef struct berbuf {
383           struct berval       bb_val;
384           ber_len_t bb_len;
385 } BerBuffer;
386 
387 #define BB_NULL               { BER_BVNULL, 0 }
388 
389 /*
390  * Entry ID structure
391  */
392 typedef struct backsql_entryID {
393           /* #define BACKSQL_ARBITRARY_KEY to allow a non-numeric key.
394            * It is required by some special applications that use
395            * strings as keys for the main table.
396            * In this case, #define BACKSQL_MAX_KEY_LEN consistently
397            * with the key size definition */
398 #ifdef BACKSQL_ARBITRARY_KEY
399           struct berval                 eid_id;
400           struct berval                 eid_keyval;
401 #define BACKSQL_MAX_KEY_LEN   64
402 #else /* ! BACKSQL_ARBITRARY_KEY */
403           /* The original numeric key is maintained as default. */
404           backsql_key_t                 eid_id;
405           backsql_key_t                 eid_keyval;
406 #endif /* ! BACKSQL_ARBITRARY_KEY */
407 
408           backsql_key_t                 eid_oc_id;
409           backsql_oc_map_rec  *eid_oc;
410           struct berval                 eid_dn;
411           struct berval                 eid_ndn;
412           struct backsql_entryID        *eid_next;
413 } backsql_entryID;
414 
415 #ifdef BACKSQL_ARBITRARY_KEY
416 #define BACKSQL_ENTRYID_INIT { BER_BVNULL, BER_BVNULL, 0, NULL, BER_BVNULL, BER_BVNULL, NULL }
417 #else /* ! BACKSQL_ARBITRARY_KEY */
418 #define BACKSQL_ENTRYID_INIT { 0, 0, 0, NULL, BER_BVNULL, BER_BVNULL, NULL }
419 #endif /* BACKSQL_ARBITRARY_KEY */
420 
421 /* the function must collect the entry associated to nbase */
422 #define BACKSQL_ISF_GET_ID    0x1U
423 #define BACKSQL_ISF_GET_ENTRY ( 0x2U | BACKSQL_ISF_GET_ID )
424 #define BACKSQL_ISF_GET_OC    ( 0x4U | BACKSQL_ISF_GET_ID )
425 #define BACKSQL_ISF_MATCHED   0x8U
426 #define BACKSQL_IS_GET_ID(f) \
427           ( ( (f) & BACKSQL_ISF_GET_ID ) == BACKSQL_ISF_GET_ID )
428 #define BACKSQL_IS_GET_ENTRY(f) \
429           ( ( (f) & BACKSQL_ISF_GET_ENTRY ) == BACKSQL_ISF_GET_ENTRY )
430 #define BACKSQL_IS_GET_OC(f) \
431           ( ( (f) & BACKSQL_ISF_GET_OC ) == BACKSQL_ISF_GET_OC )
432 #define BACKSQL_IS_MATCHED(f) \
433           ( ( (f) & BACKSQL_ISF_MATCHED ) == BACKSQL_ISF_MATCHED )
434 typedef struct backsql_srch_info {
435           Operation           *bsi_op;
436           SlapReply           *bsi_rs;
437 
438           unsigned            bsi_flags;
439 #define   BSQL_SF_NONE                            0x0000U
440 #define   BSQL_SF_ALL_USER              0x0001U
441 #define   BSQL_SF_ALL_OPER              0x0002U
442 #define   BSQL_SF_ALL_ATTRS             (BSQL_SF_ALL_USER|BSQL_SF_ALL_OPER)
443 #define BSQL_SF_FILTER_HASSUBORDINATE   0x0010U
444 #define BSQL_SF_FILTER_ENTRYUUID        0x0020U
445 #define BSQL_SF_FILTER_ENTRYCSN                   0x0040U
446 #define BSQL_SF_RETURN_ENTRYUUID        (BSQL_SF_FILTER_ENTRYUUID << 8)
447 #define   BSQL_ISF(bsi, f)              ( ( (bsi)->bsi_flags & f ) == f )
448 #define   BSQL_ISF_ALL_USER(bsi)                  BSQL_ISF(bsi, BSQL_SF_ALL_USER)
449 #define   BSQL_ISF_ALL_OPER(bsi)                  BSQL_ISF(bsi, BSQL_SF_ALL_OPER)
450 #define   BSQL_ISF_ALL_ATTRS(bsi)                 BSQL_ISF(bsi, BSQL_SF_ALL_ATTRS)
451 
452           struct berval                 *bsi_base_ndn;
453           int                           bsi_use_subtree_shortcut;
454           backsql_entryID               bsi_base_id;
455           int                           bsi_scope;
456 /* BACKSQL_SCOPE_BASE_LIKE can be set by API in ors_scope
457  * whenever the search base DN contains chars that cannot
458  * be mapped into the charset used in the RDBMS; so they're
459  * turned into '%' and an approximate ('LIKE') condition
460  * is used */
461 #define BACKSQL_SCOPE_BASE_LIKE                   ( LDAP_SCOPE_BASE | 0x1000 )
462           Filter                        *bsi_filter;
463           time_t                        bsi_stoptime;
464 
465           backsql_entryID               *bsi_id_list,
466                                         **bsi_id_listtail,
467                                         *bsi_c_eid;
468           int                           bsi_n_candidates;
469           int                           bsi_status;
470 
471           backsql_oc_map_rec  *bsi_oc;
472           struct berbuf                 bsi_sel,
473                                         bsi_from,
474                                         bsi_join_where,
475                                         bsi_flt_where;
476           ObjectClass                   *bsi_filter_oc;
477           SQLHDBC                       bsi_dbh;
478           AttributeName                 *bsi_attrs;
479 
480           Entry                         *bsi_e;
481 } backsql_srch_info;
482 
483 /*
484  * Backend private data structure
485  */
486 typedef struct backsql_info {
487           char                *sql_dbhost;
488           int                 sql_dbport;
489           char                *sql_dbuser;
490           char                *sql_dbpasswd;
491           char                *sql_dbname;
492 
493           /*
494            * SQL condition for subtree searches differs in syntax:
495            * "LIKE CONCAT('%',?)" or "LIKE '%'+?" or "LIKE '%'||?"
496            * or smtg else
497            */
498           struct berval       sql_subtree_cond;
499           struct berval       sql_children_cond;
500           struct berval       sql_dn_match_cond;
501           char                *sql_oc_query;
502           char                *sql_at_query;
503           char                *sql_insentry_stmt;
504           char                *sql_delentry_stmt;
505           char                *sql_renentry_stmt;
506           char                *sql_delobjclasses_stmt;
507           char                *sql_id_query;
508           char                *sql_has_children_query;
509           char                *sql_list_children_query;
510 
511           MatchingRule        *sql_caseIgnoreMatch;
512           MatchingRule        *sql_telephoneNumberMatch;
513 
514           struct berval       sql_upper_func;
515           struct berval       sql_upper_func_open;
516           struct berval       sql_upper_func_close;
517           struct berval       sql_strcast_func;
518           BerVarray sql_concat_func;
519           char                *sql_concat_patt;
520 
521           struct berval       sql_aliasing;
522           struct berval       sql_aliasing_quote;
523           struct berval       sql_dn_oc_aliasing;
524 
525           AttributeName       *sql_anlist;
526 
527           unsigned int        sql_flags;
528 #define   BSQLF_SCHEMA_LOADED           0x0001
529 #define   BSQLF_UPPER_NEEDS_CAST                  0x0002
530 #define   BSQLF_CREATE_NEEDS_SELECT     0x0004
531 #define   BSQLF_FAIL_IF_NO_MAPPING      0x0008
532 #define BSQLF_HAS_LDAPINFO_DN_RU        0x0010
533 #define BSQLF_DONTCHECK_LDAPINFO_DN_RU  0x0020
534 #define BSQLF_USE_REVERSE_DN            0x0040
535 #define BSQLF_ALLOW_ORPHANS             0x0080
536 #define BSQLF_USE_SUBTREE_SHORTCUT      0x0100
537 #define BSQLF_FETCH_ALL_USERATTRS       0x0200
538 #define BSQLF_FETCH_ALL_OPATTRS                   0x0400
539 #define   BSQLF_FETCH_ALL_ATTRS                   (BSQLF_FETCH_ALL_USERATTRS|BSQLF_FETCH_ALL_OPATTRS)
540 #define BSQLF_CHECK_SCHEMA              0x0800
541 #define BSQLF_AUTOCOMMIT_ON             0x1000
542 
543 #define BACKSQL_ISF(si, f) \
544           (((si)->sql_flags & f) == f)
545 
546 #define   BACKSQL_SCHEMA_LOADED(si) \
547           BACKSQL_ISF(si, BSQLF_SCHEMA_LOADED)
548 #define BACKSQL_UPPER_NEEDS_CAST(si) \
549           BACKSQL_ISF(si, BSQLF_UPPER_NEEDS_CAST)
550 #define BACKSQL_CREATE_NEEDS_SELECT(si) \
551           BACKSQL_ISF(si, BSQLF_CREATE_NEEDS_SELECT)
552 #define BACKSQL_FAIL_IF_NO_MAPPING(si) \
553           BACKSQL_ISF(si, BSQLF_FAIL_IF_NO_MAPPING)
554 #define BACKSQL_HAS_LDAPINFO_DN_RU(si) \
555           BACKSQL_ISF(si, BSQLF_HAS_LDAPINFO_DN_RU)
556 #define BACKSQL_DONTCHECK_LDAPINFO_DN_RU(si) \
557           BACKSQL_ISF(si, BSQLF_DONTCHECK_LDAPINFO_DN_RU)
558 #define BACKSQL_USE_REVERSE_DN(si) \
559           BACKSQL_ISF(si, BSQLF_USE_REVERSE_DN)
560 #define BACKSQL_CANUPPERCASE(si) \
561           (!BER_BVISNULL( &(si)->sql_upper_func ))
562 #define BACKSQL_ALLOW_ORPHANS(si) \
563           BACKSQL_ISF(si, BSQLF_ALLOW_ORPHANS)
564 #define BACKSQL_USE_SUBTREE_SHORTCUT(si) \
565           BACKSQL_ISF(si, BSQLF_USE_SUBTREE_SHORTCUT)
566 #define BACKSQL_FETCH_ALL_USERATTRS(si) \
567           BACKSQL_ISF(si, BSQLF_FETCH_ALL_USERATTRS)
568 #define BACKSQL_FETCH_ALL_OPATTRS(si) \
569           BACKSQL_ISF(si, BSQLF_FETCH_ALL_OPATTRS)
570 #define BACKSQL_FETCH_ALL_ATTRS(si) \
571           BACKSQL_ISF(si, BSQLF_FETCH_ALL_ATTRS)
572 #define BACKSQL_CHECK_SCHEMA(si) \
573           BACKSQL_ISF(si, BSQLF_CHECK_SCHEMA)
574 #define BACKSQL_AUTOCOMMIT_ON(si) \
575           BACKSQL_ISF(si, BSQLF_AUTOCOMMIT_ON)
576 
577           Entry               *sql_baseObject;
578           char                *sql_base_ob_file;
579 #ifdef BACKSQL_ARBITRARY_KEY
580 #define BACKSQL_BASEOBJECT_IDSTR        "baseObject"
581 #define BACKSQL_BASEOBJECT_KEYVAL       BACKSQL_BASEOBJECT_IDSTR
582 #define   BACKSQL_IS_BASEOBJECT_ID(id)  (bvmatch((id), &backsql_baseObject_bv))
583 #else /* ! BACKSQL_ARBITRARY_KEY */
584 #define BACKSQL_BASEOBJECT_ID           0
585 #define BACKSQL_BASEOBJECT_IDSTR        LDAP_XSTRING(BACKSQL_BASEOBJECT_ID)
586 #define BACKSQL_BASEOBJECT_KEYVAL       0
587 #define   BACKSQL_IS_BASEOBJECT_ID(id)  (*(id) == BACKSQL_BASEOBJECT_ID)
588 #endif /* ! BACKSQL_ARBITRARY_KEY */
589 #define BACKSQL_BASEOBJECT_OC           0
590 
591           Avlnode             *sql_db_conns;
592           SQLHDBC             sql_dbh;
593           ldap_pvt_thread_mutex_t                 sql_dbconn_mutex;
594           Avlnode             *sql_oc_by_oc;
595           Avlnode             *sql_oc_by_id;
596           ldap_pvt_thread_mutex_t                 sql_schema_mutex;
597           SQLHENV             sql_db_env;
598 
599           backsql_api         *sql_api;
600 } backsql_info;
601 
602 #define BACKSQL_SUCCESS( rc ) \
603           ( (rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO )
604 
605 #define BACKSQL_AVL_STOP                0
606 #define BACKSQL_AVL_CONTINUE            1
607 
608 /* see ldap.h for the meaning of the macros and of the values */
609 #define BACKSQL_LEGAL_ERROR( rc ) \
610           ( LDAP_RANGE( (rc), 0x00, 0x0e ) \
611             || LDAP_ATTR_ERROR( (rc) ) \
612             || LDAP_NAME_ERROR( (rc) ) \
613             || LDAP_SECURITY_ERROR( (rc) ) \
614             || LDAP_SERVICE_ERROR( (rc) ) \
615             || LDAP_UPDATE_ERROR( (rc) ) )
616 #define BACKSQL_SANITIZE_ERROR( rc ) \
617           ( BACKSQL_LEGAL_ERROR( (rc) ) ? (rc) : LDAP_OTHER )
618 
619 #define BACKSQL_IS_BINARY(ct) \
620           ( (ct) == SQL_BINARY \
621             || (ct) == SQL_VARBINARY \
622             || (ct) == SQL_LONGVARBINARY)
623 
624 #ifdef BACKSQL_ARBITRARY_KEY
625 #define BACKSQL_IDFMT "%s"
626 #define BACKSQL_IDARG(arg) ((arg).bv_val)
627 #else /* ! BACKSQL_ARBITRARY_KEY */
628 #define BACKSQL_IDFMT BACKSQL_IDNUMFMT
629 #define BACKSQL_IDARG(arg) (arg)
630 #endif /* ! BACKSQL_ARBITRARY_KEY */
631 
632 #endif /* __BACKSQL_H__ */
633 
634