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