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