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