Home | History | Annotate | Line # | Download | only in back-sql
util.c revision 1.1.1.10
      1   1.1.1.9  christos /*	$NetBSD: util.c,v 1.1.1.10 2025/09/05 21:09:48 christos Exp $	*/
      2   1.1.1.2     lukem 
      3   1.1.1.4      tron /* $OpenLDAP$ */
      4       1.1     lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5       1.1     lukem  *
      6  1.1.1.10  christos  * Copyright 1999-2024 The OpenLDAP Foundation.
      7       1.1     lukem  * Portions Copyright 1999 Dmitry Kovalev.
      8       1.1     lukem  * Portions Copyright 2002 Pierangelo Masarati.
      9       1.1     lukem  * All rights reserved.
     10       1.1     lukem  *
     11       1.1     lukem  * Redistribution and use in source and binary forms, with or without
     12       1.1     lukem  * modification, are permitted only as authorized by the OpenLDAP
     13       1.1     lukem  * Public License.
     14       1.1     lukem  *
     15       1.1     lukem  * A copy of this license is available in the file LICENSE in the
     16       1.1     lukem  * top-level directory of the distribution or, alternatively, at
     17       1.1     lukem  * <http://www.OpenLDAP.org/license.html>.
     18       1.1     lukem  */
     19       1.1     lukem /* ACKNOWLEDGEMENTS:
     20       1.1     lukem  * This work was initially developed by Dmitry Kovalev for inclusion
     21       1.1     lukem  * by OpenLDAP Software.  Additional significant contributors include
     22       1.1     lukem  * Pierangelo Masarati.
     23       1.1     lukem  */
     24       1.1     lukem 
     25   1.1.1.5  christos #include <sys/cdefs.h>
     26   1.1.1.9  christos __RCSID("$NetBSD: util.c,v 1.1.1.10 2025/09/05 21:09:48 christos Exp $");
     27   1.1.1.5  christos 
     28       1.1     lukem #include "portable.h"
     29       1.1     lukem 
     30       1.1     lukem #include <stdio.h>
     31       1.1     lukem #include <sys/types.h>
     32       1.1     lukem #include "ac/string.h"
     33       1.1     lukem #include "ac/ctype.h"
     34       1.1     lukem #include "ac/stdarg.h"
     35       1.1     lukem 
     36       1.1     lukem #include "slap.h"
     37       1.1     lukem #include "proto-sql.h"
     38       1.1     lukem #include "lutil.h"
     39       1.1     lukem 
     40       1.1     lukem #define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b))
     41       1.1     lukem #define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b))
     42       1.1     lukem 
     43       1.1     lukem #define BACKSQL_STR_GROW 256
     44       1.1     lukem 
     45       1.1     lukem const char backsql_def_oc_query[] =
     46       1.1     lukem 	"SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return "
     47       1.1     lukem 	"FROM ldap_oc_mappings";
     48       1.1     lukem const char backsql_def_needs_select_oc_query[] =
     49       1.1     lukem 	"SELECT id,name,keytbl,keycol,create_proc,create_keyval,delete_proc,"
     50       1.1     lukem 	"expect_return FROM ldap_oc_mappings";
     51       1.1     lukem const char backsql_def_at_query[] =
     52       1.1     lukem 	"SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc,"
     53       1.1     lukem 	"param_order,expect_return,sel_expr_u FROM ldap_attr_mappings "
     54       1.1     lukem 	"WHERE oc_map_id=?";
     55       1.1     lukem const char backsql_def_delentry_stmt[] = "DELETE FROM ldap_entries WHERE id=?";
     56       1.1     lukem const char backsql_def_renentry_stmt[] =
     57       1.1     lukem 	"UPDATE ldap_entries SET dn=?,parent=?,keyval=? WHERE id=?";
     58       1.1     lukem const char backsql_def_insentry_stmt[] =
     59       1.1     lukem 	"INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) "
     60       1.1     lukem 	"VALUES (?,?,?,?)";
     61       1.1     lukem const char backsql_def_delobjclasses_stmt[] = "DELETE FROM ldap_entry_objclasses "
     62       1.1     lukem 	"WHERE entry_id=?";
     63       1.1     lukem const char backsql_def_subtree_cond[] = "ldap_entries.dn LIKE CONCAT('%',?)";
     64       1.1     lukem const char backsql_def_upper_subtree_cond[] = "(ldap_entries.dn) LIKE CONCAT('%',?)";
     65       1.1     lukem const char backsql_id_query[] = "SELECT id,keyval,oc_map_id,dn FROM ldap_entries WHERE ";
     66       1.1     lukem /* better ?||? or cast(?||? as varchar) */
     67       1.1     lukem const char backsql_def_concat_func[] = "CONCAT(?,?)";
     68       1.1     lukem 
     69       1.1     lukem /* TimesTen */
     70       1.1     lukem const char backsql_check_dn_ru_query[] = "SELECT dn_ru FROM ldap_entries";
     71       1.1     lukem 
     72       1.1     lukem struct berbuf *
     73       1.1     lukem backsql_strcat_x( struct berbuf *dest, void *memctx, ... )
     74       1.1     lukem {
     75       1.1     lukem 	va_list		strs;
     76       1.1     lukem 	ber_len_t	cdlen, cslen, grow;
     77       1.1     lukem 	char		*cstr;
     78       1.1     lukem 
     79       1.1     lukem 	assert( dest != NULL );
     80       1.1     lukem 	assert( dest->bb_val.bv_val == NULL
     81       1.1     lukem 			|| dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
     82       1.1     lukem 
     83       1.1     lukem #ifdef BACKSQL_TRACE
     84   1.1.1.9  christos 	Debug( LDAP_DEBUG_TRACE, "==>backsql_strcat()\n" );
     85       1.1     lukem #endif /* BACKSQL_TRACE */
     86       1.1     lukem 
     87       1.1     lukem 	va_start( strs, memctx );
     88       1.1     lukem 	if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
     89       1.1     lukem 		dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx );
     90       1.1     lukem 		dest->bb_val.bv_len = 0;
     91       1.1     lukem 		dest->bb_len = BACKSQL_STR_GROW;
     92       1.1     lukem 	}
     93       1.1     lukem 	cdlen = dest->bb_val.bv_len;
     94       1.1     lukem 	while ( ( cstr = va_arg( strs, char * ) ) != NULL ) {
     95       1.1     lukem 		cslen = strlen( cstr );
     96       1.1     lukem 		grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
     97       1.1     lukem 		if ( dest->bb_len - cdlen <= cslen ) {
     98       1.1     lukem 			char	*tmp_dest;
     99       1.1     lukem 
    100       1.1     lukem #ifdef BACKSQL_TRACE
    101       1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
    102       1.1     lukem 				"buflen=%d, cdlen=%d, cslen=%d "
    103       1.1     lukem 				"-- reallocating dest\n",
    104       1.1     lukem 				dest->bb_len, cdlen + 1, cslen );
    105       1.1     lukem #endif /* BACKSQL_TRACE */
    106       1.1     lukem 
    107       1.1     lukem 			tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val,
    108       1.1     lukem 					dest->bb_len + grow * sizeof( char ), memctx );
    109       1.1     lukem 			if ( tmp_dest == NULL ) {
    110       1.1     lukem 				Debug( LDAP_DEBUG_ANY, "backsql_strcat(): "
    111   1.1.1.9  christos 					"could not reallocate string buffer.\n" );
    112   1.1.1.5  christos 				va_end( strs );
    113       1.1     lukem 				return NULL;
    114       1.1     lukem 			}
    115       1.1     lukem 			dest->bb_val.bv_val = tmp_dest;
    116       1.1     lukem 			dest->bb_len += grow;
    117       1.1     lukem 
    118       1.1     lukem #ifdef BACKSQL_TRACE
    119       1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
    120       1.1     lukem 				"new buflen=%d, dest=%p\n",
    121   1.1.1.9  christos 				dest->bb_len, dest );
    122       1.1     lukem #endif /* BACKSQL_TRACE */
    123       1.1     lukem 		}
    124       1.1     lukem 		AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
    125       1.1     lukem 		cdlen += cslen;
    126       1.1     lukem 	}
    127       1.1     lukem 	va_end( strs );
    128       1.1     lukem 
    129       1.1     lukem #ifdef BACKSQL_TRACE
    130       1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest=\"%s\")\n",
    131   1.1.1.9  christos 			dest->bb_val.bv_val );
    132       1.1     lukem #endif /* BACKSQL_TRACE */
    133       1.1     lukem 
    134       1.1     lukem 	dest->bb_val.bv_len = cdlen;
    135       1.1     lukem 
    136       1.1     lukem 	return dest;
    137       1.1     lukem }
    138       1.1     lukem 
    139       1.1     lukem struct berbuf *
    140       1.1     lukem backsql_strfcat_x( struct berbuf *dest, void *memctx, const char *fmt, ... )
    141       1.1     lukem {
    142       1.1     lukem 	va_list		strs;
    143       1.1     lukem 	ber_len_t	cdlen;
    144       1.1     lukem 
    145       1.1     lukem 	assert( dest != NULL );
    146       1.1     lukem 	assert( fmt != NULL );
    147       1.1     lukem 	assert( dest->bb_len == 0 || dest->bb_len > dest->bb_val.bv_len );
    148       1.1     lukem 	assert( dest->bb_val.bv_val == NULL
    149       1.1     lukem 			|| dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
    150       1.1     lukem 
    151       1.1     lukem #ifdef BACKSQL_TRACE
    152   1.1.1.9  christos 	Debug( LDAP_DEBUG_TRACE, "==>backsql_strfcat()\n" );
    153       1.1     lukem #endif /* BACKSQL_TRACE */
    154       1.1     lukem 
    155       1.1     lukem 	va_start( strs, fmt );
    156       1.1     lukem 	if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
    157       1.1     lukem 		dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx );
    158       1.1     lukem 		dest->bb_val.bv_len = 0;
    159       1.1     lukem 		dest->bb_len = BACKSQL_STR_GROW;
    160       1.1     lukem 	}
    161       1.1     lukem 
    162       1.1     lukem 	cdlen = dest->bb_val.bv_len;
    163       1.1     lukem 	for ( ; fmt[0]; fmt++ ) {
    164       1.1     lukem 		ber_len_t	cslen, grow;
    165       1.1     lukem 		char		*cstr, cc[ 2 ] = { '\0', '\0' };
    166       1.1     lukem 		struct berval	*cbv;
    167       1.1     lukem 
    168       1.1     lukem 		switch ( fmt[ 0 ] ) {
    169       1.1     lukem 
    170       1.1     lukem 		/* berval */
    171       1.1     lukem 		case 'b':
    172       1.1     lukem 			cbv = va_arg( strs, struct berval * );
    173       1.1     lukem 			cstr = cbv->bv_val;
    174       1.1     lukem 			cslen = cbv->bv_len;
    175       1.1     lukem 			break;
    176       1.1     lukem 
    177       1.1     lukem 		/* length + string */
    178       1.1     lukem 		case 'l':
    179       1.1     lukem 			cslen = va_arg( strs, ber_len_t );
    180       1.1     lukem 			cstr = va_arg( strs, char * );
    181       1.1     lukem 			break;
    182       1.1     lukem 
    183       1.1     lukem 		/* string */
    184       1.1     lukem 		case 's':
    185       1.1     lukem 			cstr = va_arg( strs, char * );
    186       1.1     lukem 			cslen = strlen( cstr );
    187       1.1     lukem 			break;
    188       1.1     lukem 
    189       1.1     lukem 		/* char */
    190       1.1     lukem 		case 'c':
    191       1.1     lukem 			/*
    192       1.1     lukem 			 * `char' is promoted to `int' when passed through `...'
    193       1.1     lukem 			 */
    194       1.1     lukem 			cc[0] = va_arg( strs, int );
    195       1.1     lukem 			cstr = cc;
    196       1.1     lukem 			cslen = 1;
    197       1.1     lukem 			break;
    198       1.1     lukem 
    199       1.1     lukem 		default:
    200       1.1     lukem 			assert( 0 );
    201       1.1     lukem 		}
    202       1.1     lukem 
    203       1.1     lukem 		grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
    204       1.1     lukem 		if ( dest->bb_len - cdlen <= cslen ) {
    205       1.1     lukem 			char	*tmp_dest;
    206       1.1     lukem 
    207       1.1     lukem #ifdef BACKSQL_TRACE
    208       1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
    209       1.1     lukem 				"buflen=%d, cdlen=%d, cslen=%d "
    210       1.1     lukem 				"-- reallocating dest\n",
    211       1.1     lukem 				dest->bb_len, cdlen + 1, cslen );
    212       1.1     lukem #endif /* BACKSQL_TRACE */
    213       1.1     lukem 
    214       1.1     lukem 			tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val,
    215       1.1     lukem 					( dest->bb_len ) + grow * sizeof( char ), memctx );
    216       1.1     lukem 			if ( tmp_dest == NULL ) {
    217       1.1     lukem 				Debug( LDAP_DEBUG_ANY, "backsql_strfcat(): "
    218   1.1.1.9  christos 					"could not reallocate string buffer.\n" );
    219   1.1.1.5  christos 				va_end( strs );
    220       1.1     lukem 				return NULL;
    221       1.1     lukem 			}
    222       1.1     lukem 			dest->bb_val.bv_val = tmp_dest;
    223       1.1     lukem 			dest->bb_len += grow * sizeof( char );
    224       1.1     lukem 
    225       1.1     lukem #ifdef BACKSQL_TRACE
    226       1.1     lukem 			Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
    227   1.1.1.9  christos 				"new buflen=%d, dest=%p\n", dest->bb_len, dest );
    228       1.1     lukem #endif /* BACKSQL_TRACE */
    229       1.1     lukem 		}
    230       1.1     lukem 
    231       1.1     lukem 		assert( cstr != NULL );
    232       1.1     lukem 
    233       1.1     lukem 		AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
    234       1.1     lukem 		cdlen += cslen;
    235       1.1     lukem 	}
    236       1.1     lukem 
    237       1.1     lukem 	va_end( strs );
    238       1.1     lukem 
    239       1.1     lukem #ifdef BACKSQL_TRACE
    240       1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest=\"%s\")\n",
    241   1.1.1.9  christos 			dest->bb_val.bv_val );
    242       1.1     lukem #endif /* BACKSQL_TRACE */
    243       1.1     lukem 
    244       1.1     lukem 	dest->bb_val.bv_len = cdlen;
    245       1.1     lukem 
    246       1.1     lukem 	return dest;
    247       1.1     lukem }
    248       1.1     lukem 
    249       1.1     lukem int
    250       1.1     lukem backsql_entry_addattr(
    251       1.1     lukem 	Entry			*e,
    252       1.1     lukem 	AttributeDescription	*ad,
    253       1.1     lukem 	struct berval		*val,
    254       1.1     lukem 	void			*memctx )
    255       1.1     lukem {
    256       1.1     lukem 	int			rc;
    257       1.1     lukem 
    258       1.1     lukem #ifdef BACKSQL_TRACE
    259       1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): %s=%s\n",
    260       1.1     lukem 		e->e_name.bv_val, ad->ad_cname.bv_val, val->bv_val );
    261       1.1     lukem #endif /* BACKSQL_TRACE */
    262       1.1     lukem 
    263       1.1     lukem 	rc = attr_merge_normalize_one( e, ad, val, memctx );
    264       1.1     lukem 
    265       1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    266       1.1     lukem 		Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): "
    267       1.1     lukem 			"failed to merge value \"%s\" for attribute \"%s\"\n",
    268       1.1     lukem 			e->e_name.bv_val, val->bv_val, ad->ad_cname.bv_val );
    269       1.1     lukem 		return rc;
    270       1.1     lukem 	}
    271       1.1     lukem 
    272       1.1     lukem #ifdef BACKSQL_TRACE
    273       1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "<==backsql_entry_addattr(\"%s\")\n",
    274   1.1.1.9  christos 		e->e_name.bv_val );
    275       1.1     lukem #endif /* BACKSQL_TRACE */
    276       1.1     lukem 
    277       1.1     lukem 	return LDAP_SUCCESS;
    278       1.1     lukem }
    279       1.1     lukem 
    280       1.1     lukem static char *
    281       1.1     lukem backsql_get_table_spec( backsql_info *bi, char **p )
    282       1.1     lukem {
    283       1.1     lukem 	char		*s, *q;
    284       1.1     lukem 	struct berbuf	res = BB_NULL;
    285       1.1     lukem 
    286       1.1     lukem 	assert( p != NULL );
    287       1.1     lukem 	assert( *p != NULL );
    288       1.1     lukem 
    289       1.1     lukem 	s = *p;
    290       1.1     lukem 	while ( **p && **p != ',' ) {
    291       1.1     lukem 		(*p)++;
    292       1.1     lukem 	}
    293       1.1     lukem 
    294       1.1     lukem 	if ( **p ) {
    295       1.1     lukem 		*(*p)++ = '\0';
    296       1.1     lukem 	}
    297       1.1     lukem 
    298       1.1     lukem #define BACKSQL_NEXT_WORD { \
    299       1.1     lukem 		while ( *s && isspace( (unsigned char)*s ) ) s++; \
    300       1.1     lukem 		if ( !*s ) return res.bb_val.bv_val; \
    301       1.1     lukem 		q = s; \
    302       1.1     lukem 		while ( *q && !isspace( (unsigned char)*q ) ) q++; \
    303       1.1     lukem 		if ( *q ) *q++='\0'; \
    304       1.1     lukem 	}
    305       1.1     lukem 
    306       1.1     lukem 	BACKSQL_NEXT_WORD;
    307       1.1     lukem 	/* table name */
    308       1.1     lukem 	backsql_strcat_x( &res, NULL, s, NULL );
    309       1.1     lukem 	s = q;
    310       1.1     lukem 
    311       1.1     lukem 	BACKSQL_NEXT_WORD;
    312       1.1     lukem 	if ( strcasecmp( s, "AS" ) == 0 ) {
    313       1.1     lukem 		s = q;
    314       1.1     lukem 		BACKSQL_NEXT_WORD;
    315       1.1     lukem 	}
    316       1.1     lukem 
    317       1.1     lukem 	/* oracle doesn't understand "AS" :( and other RDBMSes don't need it */
    318       1.1     lukem 	backsql_strfcat_x( &res, NULL, "lbbsb",
    319       1.1     lukem 			STRLENOF( " " ), " ",
    320       1.1     lukem 			&bi->sql_aliasing,
    321       1.1     lukem 			&bi->sql_aliasing_quote,
    322       1.1     lukem 			s,
    323       1.1     lukem 			&bi->sql_aliasing_quote );
    324       1.1     lukem 
    325       1.1     lukem 	return res.bb_val.bv_val;
    326       1.1     lukem }
    327       1.1     lukem 
    328       1.1     lukem int
    329       1.1     lukem backsql_merge_from_clause(
    330       1.1     lukem 	backsql_info	*bi,
    331       1.1     lukem 	struct berbuf	*dest_from,
    332       1.1     lukem 	struct berval	*src_from )
    333       1.1     lukem {
    334       1.1     lukem 	char		*s, *p, *srcc, *pos, e;
    335       1.1     lukem 	struct berbuf	res = BB_NULL;
    336       1.1     lukem 
    337       1.1     lukem #ifdef BACKSQL_TRACE
    338       1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==>backsql_merge_from_clause(): "
    339       1.1     lukem 		"dest_from=\"%s\",src_from=\"%s\"\n",
    340       1.1     lukem  		dest_from ? dest_from->bb_val.bv_val : "<NULL>",
    341   1.1.1.9  christos 		src_from->bv_val );
    342       1.1     lukem #endif /* BACKSQL_TRACE */
    343       1.1     lukem 
    344       1.1     lukem 	srcc = ch_strdup( src_from->bv_val );
    345       1.1     lukem 	p = srcc;
    346       1.1     lukem 
    347       1.1     lukem 	if ( dest_from != NULL ) {
    348       1.1     lukem 		res = *dest_from;
    349       1.1     lukem 	}
    350       1.1     lukem 
    351       1.1     lukem 	while ( *p ) {
    352       1.1     lukem 		s = backsql_get_table_spec( bi, &p );
    353       1.1     lukem 
    354       1.1     lukem #ifdef BACKSQL_TRACE
    355       1.1     lukem 		Debug( LDAP_DEBUG_TRACE, "backsql_merge_from_clause(): "
    356   1.1.1.9  christos 			"p=\"%s\" s=\"%s\"\n", p, s );
    357       1.1     lukem #endif /* BACKSQL_TRACE */
    358       1.1     lukem 
    359       1.1     lukem 		if ( BER_BVISNULL( &res.bb_val ) ) {
    360       1.1     lukem 			backsql_strcat_x( &res, NULL, s, NULL );
    361       1.1     lukem 
    362       1.1     lukem 		} else {
    363       1.1     lukem 			pos = strstr( res.bb_val.bv_val, s );
    364       1.1     lukem 			if ( pos == NULL || ( ( e = pos[ strlen( s ) ] ) != '\0' && e != ',' ) ) {
    365       1.1     lukem 				backsql_strfcat_x( &res, NULL, "cs", ',', s );
    366       1.1     lukem 			}
    367       1.1     lukem 		}
    368       1.1     lukem 
    369       1.1     lukem 		if ( s ) {
    370       1.1     lukem 			ch_free( s );
    371       1.1     lukem 		}
    372       1.1     lukem 	}
    373       1.1     lukem 
    374       1.1     lukem #ifdef BACKSQL_TRACE
    375   1.1.1.9  christos 	Debug( LDAP_DEBUG_TRACE, "<==backsql_merge_from_clause()\n" );
    376       1.1     lukem #endif /* BACKSQL_TRACE */
    377       1.1     lukem 
    378       1.1     lukem 	free( srcc );
    379       1.1     lukem 	*dest_from = res;
    380       1.1     lukem 
    381       1.1     lukem 	return 1;
    382       1.1     lukem }
    383       1.1     lukem 
    384       1.1     lukem /*
    385       1.1     lukem  * splits a pattern in components separated by '?'
    386       1.1     lukem  * (double ?? are turned into single ? and left in the string)
    387       1.1     lukem  * expected contains the number of expected occurrences of '?'
    388       1.1     lukem  * (a negative value means parse as many as possible)
    389       1.1     lukem  */
    390       1.1     lukem 
    391       1.1     lukem int
    392       1.1     lukem backsql_split_pattern(
    393       1.1     lukem 	const char	*_pattern,
    394       1.1     lukem 	BerVarray	*split_pattern,
    395       1.1     lukem 	int		expected )
    396       1.1     lukem {
    397       1.1     lukem 	char		*pattern, *start, *end;
    398       1.1     lukem 	struct berval	bv;
    399       1.1     lukem 	int		rc = 0;
    400       1.1     lukem 
    401       1.1     lukem #define SPLIT_CHAR	'?'
    402       1.1     lukem 
    403       1.1     lukem 	assert( _pattern != NULL );
    404       1.1     lukem 	assert( split_pattern != NULL );
    405       1.1     lukem 
    406       1.1     lukem 	pattern = ch_strdup( _pattern );
    407       1.1     lukem 
    408       1.1     lukem 	start = pattern;
    409       1.1     lukem 	end = strchr( start, SPLIT_CHAR );
    410       1.1     lukem 	for ( ; start; expected-- ) {
    411       1.1     lukem 		char		*real_end = end;
    412       1.1     lukem 		ber_len_t	real_len;
    413       1.1     lukem 
    414       1.1     lukem 		if ( real_end == NULL ) {
    415       1.1     lukem 			real_end = start + strlen( start );
    416       1.1     lukem 
    417       1.1     lukem 		} else if ( real_end[ 1 ] == SPLIT_CHAR ) {
    418       1.1     lukem 			expected++;
    419       1.1     lukem 			AC_MEMCPY( real_end, real_end + 1, strlen( real_end ) );
    420       1.1     lukem 			end = strchr( real_end + 1, SPLIT_CHAR );
    421       1.1     lukem 			continue;
    422       1.1     lukem 		}
    423       1.1     lukem 
    424       1.1     lukem 		real_len = real_end - start;
    425       1.1     lukem 		if ( real_len == 0 ) {
    426       1.1     lukem 			ber_str2bv( "", 0, 1, &bv );
    427       1.1     lukem 		} else {
    428       1.1     lukem 			ber_str2bv( start, real_len, 1, &bv );
    429       1.1     lukem 		}
    430       1.1     lukem 
    431       1.1     lukem 		ber_bvarray_add( split_pattern, &bv );
    432       1.1     lukem 
    433       1.1     lukem 		if ( expected == 0 ) {
    434       1.1     lukem 			if ( end != NULL ) {
    435       1.1     lukem 				rc = -1;
    436       1.1     lukem 				goto done;
    437       1.1     lukem 			}
    438       1.1     lukem 			break;
    439       1.1     lukem 		}
    440       1.1     lukem 
    441       1.1     lukem 		if ( end != NULL ) {
    442       1.1     lukem 			start = end + 1;
    443       1.1     lukem 			end = strchr( start, SPLIT_CHAR );
    444       1.1     lukem 		}
    445       1.1     lukem 	}
    446       1.1     lukem 
    447       1.1     lukem done:;
    448       1.1     lukem 
    449       1.1     lukem      	ch_free( pattern );
    450       1.1     lukem 
    451       1.1     lukem 	return rc;
    452       1.1     lukem }
    453       1.1     lukem 
    454       1.1     lukem int
    455       1.1     lukem backsql_prepare_pattern(
    456       1.1     lukem 	BerVarray	split_pattern,
    457       1.1     lukem 	BerVarray	values,
    458       1.1     lukem 	struct berval	*res )
    459       1.1     lukem {
    460       1.1     lukem 	int		i;
    461       1.1     lukem 	struct berbuf	bb = BB_NULL;
    462       1.1     lukem 
    463       1.1     lukem 	assert( res != NULL );
    464       1.1     lukem 
    465       1.1     lukem 	for ( i = 0; values[i].bv_val; i++ ) {
    466       1.1     lukem 		if ( split_pattern[i].bv_val == NULL ) {
    467       1.1     lukem 			ch_free( bb.bb_val.bv_val );
    468       1.1     lukem 			return -1;
    469       1.1     lukem 		}
    470       1.1     lukem 		backsql_strfcat_x( &bb, NULL, "b", &split_pattern[ i ] );
    471       1.1     lukem 		backsql_strfcat_x( &bb, NULL, "b", &values[ i ] );
    472       1.1     lukem 	}
    473       1.1     lukem 
    474       1.1     lukem 	if ( split_pattern[ i ].bv_val == NULL ) {
    475       1.1     lukem 		ch_free( bb.bb_val.bv_val );
    476       1.1     lukem 		return -1;
    477       1.1     lukem 	}
    478       1.1     lukem 
    479       1.1     lukem 	backsql_strfcat_x( &bb, NULL, "b", &split_pattern[ i ] );
    480       1.1     lukem 
    481       1.1     lukem 	*res = bb.bb_val;
    482       1.1     lukem 
    483       1.1     lukem 	return 0;
    484       1.1     lukem }
    485       1.1     lukem 
    486       1.1     lukem int
    487       1.1     lukem backsql_entryUUID(
    488       1.1     lukem 	backsql_info	*bi,
    489       1.1     lukem 	backsql_entryID	*id,
    490       1.1     lukem 	struct berval	*entryUUID,
    491       1.1     lukem 	void		*memctx )
    492       1.1     lukem {
    493       1.1     lukem 	char		uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
    494       1.1     lukem 	struct berval	uuid;
    495       1.1     lukem #ifdef BACKSQL_ARBITRARY_KEY
    496       1.1     lukem 	int		i;
    497       1.1     lukem 	ber_len_t	l, lmax;
    498       1.1     lukem #endif /* BACKSQL_ARBITRARY_KEY */
    499       1.1     lukem 
    500       1.1     lukem 	/* entryUUID is generated as "%08x-%04x-%04x-0000-eaddrXXX"
    501       1.1     lukem 	 * with eid_oc_id as %08x and hi and lo eid_id as %04x-%04x */
    502       1.1     lukem 	assert( bi != NULL );
    503       1.1     lukem 	assert( id != NULL );
    504       1.1     lukem 	assert( entryUUID != NULL );
    505       1.1     lukem 
    506       1.1     lukem #ifdef BACKSQL_ARBITRARY_KEY
    507       1.1     lukem 	snprintf( uuidbuf, sizeof( uuidbuf ),
    508       1.1     lukem 			"%08x-0000-0000-0000-000000000000",
    509       1.1     lukem 			( id->eid_oc_id & 0xFFFFFFFF ) );
    510       1.1     lukem 	lmax = id->eid_keyval.bv_len < 12 ? id->eid_keyval.bv_len : 12;
    511       1.1     lukem 	for ( l = 0, i = 9; l < lmax; l++, i += 2 ) {
    512       1.1     lukem 		switch ( i ) {
    513       1.1     lukem 		case STRLENOF( "00000000-0000" ):
    514       1.1     lukem 		case STRLENOF( "00000000-0000-0000" ):
    515       1.1     lukem 		case STRLENOF( "00000000-0000-0000-0000" ):
    516       1.1     lukem 			uuidbuf[ i++ ] = '-';
    517       1.1     lukem 		/* FALLTHRU */
    518       1.1     lukem 
    519       1.1     lukem 		default:
    520       1.1     lukem 			snprintf( &uuidbuf[ i ], 3, "%2x", id->eid_keyval.bv_val[ l ] );
    521       1.1     lukem 			break;
    522       1.1     lukem 		}
    523       1.1     lukem 	}
    524       1.1     lukem #else /* ! BACKSQL_ARBITRARY_KEY */
    525       1.1     lukem 	/* note: works only with 32 bit architectures... */
    526       1.1     lukem 	snprintf( uuidbuf, sizeof( uuidbuf ),
    527       1.1     lukem 			"%08x-%04x-%04x-0000-000000000000",
    528       1.1     lukem 			( (unsigned)id->eid_oc_id & 0xFFFFFFFF ),
    529       1.1     lukem 			( ( (unsigned)id->eid_keyval & 0xFFFF0000 ) >> 020 /* 16 */ ),
    530       1.1     lukem 			( (unsigned)id->eid_keyval & 0xFFFF ) );
    531       1.1     lukem #endif /* ! BACKSQL_ARBITRARY_KEY */
    532       1.1     lukem 
    533       1.1     lukem 	uuid.bv_val = uuidbuf;
    534       1.1     lukem 	uuid.bv_len = strlen( uuidbuf );
    535       1.1     lukem 
    536       1.1     lukem 	ber_dupbv_x( entryUUID, &uuid, memctx );
    537       1.1     lukem 
    538       1.1     lukem 	return 0;
    539       1.1     lukem }
    540       1.1     lukem 
    541       1.1     lukem int
    542       1.1     lukem backsql_entryUUID_decode(
    543       1.1     lukem 	struct berval	*entryUUID,
    544       1.1     lukem 	unsigned long	*oc_id,
    545       1.1     lukem #ifdef BACKSQL_ARBITRARY_KEY
    546       1.1     lukem 	struct berval	*keyval
    547       1.1     lukem #else /* ! BACKSQL_ARBITRARY_KEY */
    548       1.1     lukem 	unsigned long	*keyval
    549       1.1     lukem #endif /* ! BACKSQL_ARBITRARY_KEY */
    550       1.1     lukem 	)
    551       1.1     lukem {
    552       1.1     lukem #if 0
    553       1.1     lukem 	fprintf( stderr, "==> backsql_entryUUID_decode()\n" );
    554       1.1     lukem #endif
    555       1.1     lukem 
    556       1.1     lukem 	*oc_id = ( entryUUID->bv_val[0] << 030 /* 24 */ )
    557       1.1     lukem 		+ ( entryUUID->bv_val[1] << 020 /* 16 */ )
    558       1.1     lukem 		+ ( entryUUID->bv_val[2] << 010 /* 8 */ )
    559       1.1     lukem 		+ entryUUID->bv_val[3];
    560       1.1     lukem 
    561       1.1     lukem #ifdef BACKSQL_ARBITRARY_KEY
    562       1.1     lukem 	/* FIXME */
    563       1.1     lukem #else /* ! BACKSQL_ARBITRARY_KEY */
    564       1.1     lukem 	*keyval = ( entryUUID->bv_val[4] << 030 /* 24 */ )
    565       1.1     lukem 		+ ( entryUUID->bv_val[5] << 020 /* 16 */ )
    566       1.1     lukem 		+ ( entryUUID->bv_val[6] << 010 /* 8 */ )
    567       1.1     lukem 		+ entryUUID->bv_val[7];
    568       1.1     lukem #endif /* ! BACKSQL_ARBITRARY_KEY */
    569       1.1     lukem 
    570       1.1     lukem #if 0
    571       1.1     lukem 	fprintf( stderr, "<== backsql_entryUUID_decode(): oc=%lu id=%lu\n",
    572       1.1     lukem 			*oc_id, *keyval );
    573       1.1     lukem #endif
    574       1.1     lukem 
    575       1.1     lukem 	return LDAP_SUCCESS;
    576       1.1     lukem }
    577       1.1     lukem 
    578