X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-sql%2Fentry-id.c;h=071be1e47a6a1e9372dd2ae22fc369e234850956;hb=4abbf9c610d4fbaeee0dbdceaad1e0f94ed8e8fe;hp=81729c8f309a183ea0f055bc2739f79b53a7e947;hpb=d9d591238366b90d60bf6ccf0fc6b968f330c2ae;p=openldap diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 81729c8f30..071be1e47a 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -1,89 +1,180 @@ -/* - * Copyright 1999, Dmitry Kovalev , All rights reserved. +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2005 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * Portions Copyright 2002 Pierangelo Masarati. + * Portions Copyright 2004 Mark Adamson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. * - * Redistribution and use in source and binary forms are permitted only - * as authorized by the OpenLDAP Public License. A copy of this - * license is available at http://www.OpenLDAP.org/license.html or - * in file LICENSE in the top-level directory of the distribution. + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. Additional significant contributors include + * Pierangelo Masarati and Mark Adamson. */ #include "portable.h" -#ifdef SLAPD_SQL - #include #include #include "ac/string.h" -#include "lber_pvt.h" -#include "ldap_pvt.h" + #include "slap.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "schema-map.h" -#include "entry-id.h" -#include "util.h" +#include "proto-sql.h" + +#ifdef BACKSQL_ARBITRARY_KEY +struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR ); +#endif /* BACKSQL_ARBITRARY_KEY */ backsql_entryID * -backsql_free_entryID( backsql_entryID *id, int freeit ) +backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit ) { backsql_entryID *next; assert( id ); - next = id->next; + next = id->eid_next; + + if ( !BER_BVISNULL( &id->eid_ndn ) ) { + if ( !BER_BVISNULL( &id->eid_dn ) + && id->eid_dn.bv_val != id->eid_ndn.bv_val ) + { + op->o_tmpfree( id->eid_dn.bv_val, op->o_tmpmemctx ); + BER_BVZERO( &id->eid_dn ); + } + + op->o_tmpfree( id->eid_ndn.bv_val, op->o_tmpmemctx ); + BER_BVZERO( &id->eid_ndn ); + } - if ( id->dn.bv_val != NULL ) { - free( id->dn.bv_val ); +#ifdef BACKSQL_ARBITRARY_KEY + if ( !BER_BVISNULL( &id->eid_id ) ) { + op->o_tmpfree( id->eid_id.bv_val, op->o_tmpmemctx ); + BER_BVZERO( &id->eid_id ); } + if ( !BER_BVISNULL( &id->eid_keyval ) ) { + op->o_tmpfree( id->eid_keyval.bv_val, op->o_tmpmemctx ); + BER_BVZERO( &id->eid_keyval ); + } +#endif /* BACKSQL_ARBITRARY_KEY */ + if ( freeit ) { - free( id ); + op->o_tmpfree( id, op->o_tmpmemctx ); } return next; } +/* + * NOTE: the dn must be normalized + */ int backsql_dn2id( - backsql_info *bi, - backsql_entryID *id, + Operation *op, + SlapReply *rs, SQLHDBC dbh, - struct berval *dn ) + struct berval *ndn, + backsql_entryID *id, + int matched, + int muck ) { - SQLHSTMT sth; + backsql_info *bi = op->o_bd->be_private; + SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row; RETCODE rc; int res; + struct berval realndn = BER_BVNULL; /* TimesTen */ char upperdn[ BACKSQL_MAX_DN_LEN + 1 ]; - char *toBind; + struct berval tbbDN; int i, j; - Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(): dn='%s'\n", - dn->bv_val, 0, 0 ); + /* + * NOTE: id can be NULL; in this case, the function + * simply checks whether the DN can be successfully + * turned into an ID, returning LDAP_SUCCESS for + * positive cases, or the most appropriate error + */ - assert( id ); + Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n", + ndn->bv_val, id == NULL ? " (no ID expected)" : "", + matched ? " matched expected" : "" ); - if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) { + if ( id ) { + /* NOTE: trap inconsistencies */ + assert( BER_BVISNULL( &id->eid_ndn ) ); + } + + if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) { Debug( LDAP_DEBUG_TRACE, - "backsql_dn2id(): DN \"%s\" (%ld bytes) " - "exceeds max DN length (%d):\n", - dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN ); + " backsql_dn2id(\"%s\"): DN length=%ld " + "exceeds max DN length %d:\n", + ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN ); return LDAP_OTHER; } + + /* return baseObject if available and matches */ + /* FIXME: if ndn is already mucked, we cannot check this */ + if ( bi->sql_baseObject != NULL && + dn_match( ndn, &bi->sql_baseObject->e_nname ) ) + { + if ( id != NULL ) { +#ifdef BACKSQL_ARBITRARY_KEY + ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv, + op->o_tmpmemctx ); + ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv, + op->o_tmpmemctx ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + id->eid_id = BACKSQL_BASEOBJECT_ID; + id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL; +#endif /* ! BACKSQL_ARBITRARY_KEY */ + id->eid_oc_id = BACKSQL_BASEOBJECT_OC; + + ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname, + op->o_tmpmemctx ); + ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name, + op->o_tmpmemctx ); + + id->eid_next = NULL; + } + + return LDAP_SUCCESS; + } /* begin TimesTen */ - Debug(LDAP_DEBUG_TRACE, "id_query '%s'\n", bi->id_query, 0, 0); - assert( bi->id_query ); - rc = backsql_Prepare( dbh, &sth, bi->id_query, 0 ); + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): id_query \"%s\"\n", + ndn->bv_val, bi->sql_id_query, 0 ); + assert( bi->sql_id_query ); + rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, - "backsql_dn2id(): error preparing SQL:\n%s", - bi->id_query, 0, 0); - backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); - return LDAP_OTHER; + " backsql_dn2id(\"%s\"): " + "error preparing SQL:\n %s", + ndn->bv_val, bi->sql_id_query, 0 ); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); + res = LDAP_OTHER; + goto done; + } + + realndn = *ndn; + if ( muck ) { + if ( backsql_api_dn2odbc( op, rs, &realndn ) ) { + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " + "backsql_api_dn2odbc(\"%s\") failed\n", + ndn->bv_val, realndn.bv_val, 0 ); + res = LDAP_OTHER; + goto done; + } } if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) { @@ -92,74 +183,161 @@ backsql_dn2id( * that can be searched using indexes */ - for ( i = 0, j = dn->bv_len - 1; dn->bv_val[ i ]; i++, j--) { - upperdn[ i ] = dn->bv_val[ j ]; + for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--) + { + upperdn[ i ] = realndn.bv_val[ j ]; } upperdn[ i ] = '\0'; ldap_pvt_str2upper( upperdn ); - Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(): upperdn='%s'\n", - upperdn, 0, 0 ); - toBind = upperdn; + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " + "upperdn=\"%s\"\n", + ndn->bv_val, upperdn, 0 ); + ber_str2bv( upperdn, 0, 0, &tbbDN ); + } else { if ( BACKSQL_USE_REVERSE_DN( bi ) ) { - AC_MEMCPY( upperdn, dn->bv_val, dn->bv_len + 1 ); + AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 ); ldap_pvt_str2upper( upperdn ); Debug( LDAP_DEBUG_TRACE, - "==>backsql_dn2id(): upperdn='%s'\n", - upperdn, 0, 0 ); - toBind = upperdn; + " backsql_dn2id(\"%s\"): " + "upperdn=\"%s\"\n", + ndn->bv_val, upperdn, 0 ); + ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { - toBind = dn->bv_val; + tbbDN = realndn; } } - rc = backsql_BindParamStr( sth, 1, toBind, BACKSQL_MAX_DN_LEN ); + rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN ); if ( rc != SQL_SUCCESS) { /* end TimesTen */ - Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): " + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error binding dn=\"%s\" parameter:\n", - toBind, 0, 0 ); - backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); - return LDAP_OTHER; + ndn->bv_val, tbbDN.bv_val, 0 ); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); + res = LDAP_OTHER; + goto done; } rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): " + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error executing query (\"%s\", \"%s\"):\n", - bi->id_query, toBind, 0 ); - backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); - return LDAP_OTHER; + ndn->bv_val, bi->sql_id_query, tbbDN.bv_val ); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); + res = LDAP_OTHER; + goto done; } backsql_BindRowAsStrings( sth, &row ); rc = SQLFetch( sth ); if ( BACKSQL_SUCCESS( rc ) ) { - id->id = strtol( row.cols[ 0 ], NULL, 0 ); - id->keyval = strtol( row.cols[ 1 ], NULL, 0 ); - id->oc_id = strtol( row.cols[ 2 ], NULL, 0 ); - ber_dupbv( &id->dn, dn ); - id->next = NULL; + char buf[ SLAP_TEXT_BUFLEN ]; + +#ifdef LDAP_DEBUG + snprintf( buf, sizeof(buf), + "id=%s keyval=%s oc_id=%s dn=%s", + row.cols[ 0 ], row.cols[ 1 ], + row.cols[ 2 ], row.cols[ 3 ] ); + Debug( LDAP_DEBUG_TRACE, + " backsql_dn2id(\"%s\"): %s\n", + ndn->bv_val, buf, 0 ); +#endif /* LDAP_DEBUG */ res = LDAP_SUCCESS; + if ( id != NULL ) { + struct berval dn; + +#ifdef BACKSQL_ARBITRARY_KEY + ber_str2bv_x( row.cols[ 0 ], 0, 1, &id->eid_id, + op->o_tmpmemctx ); + ber_str2bv_x( row.cols[ 1 ], 0, 1, &id->eid_keyval, + op->o_tmpmemctx ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + id->eid_id = strtol( row.cols[ 0 ], NULL, 0 ); + id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 ); +#endif /* ! BACKSQL_ARBITRARY_KEY */ + id->eid_oc_id = strtol( row.cols[ 2 ], NULL, 0 ); + + ber_str2bv( row.cols[ 3 ], 0, 0, &dn ); + + if ( backsql_api_odbc2dn( op, rs, &dn ) ) { + res = LDAP_OTHER; + + } else { + res = dnPrettyNormal( NULL, &dn, + &id->eid_dn, &id->eid_ndn, + op->o_tmpmemctx ); + if ( res != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + " backsql_dn2id(\"%s\"): " + "dnPrettyNormal failed (%d: %s)\n", + realndn.bv_val, res, + ldap_err2string( res ) ); + + /* cleanup... */ + (void)backsql_free_entryID( op, id, 0 ); + } + + if ( dn.bv_val != row.cols[ 3 ] ) { + free( dn.bv_val ); + } + } + + id->eid_next = NULL; + } } else { res = LDAP_NO_SUCH_OBJECT; + if ( matched ) { + struct berval pdn = *ndn; + + /* + * Look for matched + */ + rs->sr_matched = NULL; + while ( !be_issuffix( op->o_bd, &pdn ) ) { + char *matchedDN = NULL; + + dnParent( &pdn, &pdn ); + + /* + * Empty DN ("") defaults to LDAP_SUCCESS + */ + rs->sr_err = backsql_dn2id( op, rs, dbh, &pdn, id, 0, 1 ); + switch ( rs->sr_err ) { + case LDAP_NO_SUCH_OBJECT: + /* try another one */ + break; + + case LDAP_SUCCESS: + matchedDN = pdn.bv_val; + /* fail over to next case */ + + default: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_matched = matchedDN; + goto done; + } + } + } } backsql_FreeRow( &row ); - SQLFreeStmt( sth, SQL_DROP ); - if ( res == LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "<==backsql_dn2id(): id=%ld\n", - id->id, 0, 0 ); - } else { - Debug( LDAP_DEBUG_TRACE, "<==backsql_dn2id(): no match\n", - 0, 0, 0 ); +done:; + Debug( LDAP_DEBUG_TRACE, + "<==backsql_dn2id(\"%s\"): err=%d\n", + ndn->bv_val, res, 0 ); + if ( sth != SQL_NULL_HSTMT ) { + SQLFreeStmt( sth, SQL_DROP ); } + + if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != ndn->bv_val ) { + ch_free( realndn.bv_val ); + } + return res; } @@ -170,12 +348,12 @@ backsql_count_children( struct berval *dn, unsigned long *nchildren ) { - SQLHSTMT sth; + SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row; RETCODE rc; int res = LDAP_SUCCESS; - Debug( LDAP_DEBUG_TRACE, "==>backsql_count_children(): dn='%s'\n", + Debug( LDAP_DEBUG_TRACE, "==>backsql_count_children(): dn=\"%s\"\n", dn->bv_val, 0, 0 ); if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) { @@ -187,26 +365,26 @@ backsql_count_children( } /* begin TimesTen */ - Debug(LDAP_DEBUG_TRACE, "children id query '%s'\n", - bi->has_children_query, 0, 0); - assert( bi->has_children_query ); - rc = backsql_Prepare( dbh, &sth, bi->has_children_query, 0 ); + Debug(LDAP_DEBUG_TRACE, "children id query \"%s\"\n", + bi->sql_has_children_query, 0, 0); + assert( bi->sql_has_children_query ); + rc = backsql_Prepare( dbh, &sth, bi->sql_has_children_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): error preparing SQL:\n%s", - bi->has_children_query, 0, 0); - backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc ); + bi->sql_has_children_query, 0, 0); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return LDAP_OTHER; } - rc = backsql_BindParamStr( sth, 1, dn->bv_val, BACKSQL_MAX_DN_LEN ); + rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, dn ); if ( rc != SQL_SUCCESS) { /* end TimesTen */ Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): " "error binding dn=\"%s\" parameter:\n", dn->bv_val, 0, 0 ); - backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc ); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return LDAP_OTHER; } @@ -215,8 +393,8 @@ backsql_count_children( if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): " "error executing query (\"%s\", \"%s\"):\n", - bi->has_children_query, dn->bv_val, 0 ); - backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc ); + bi->sql_has_children_query, dn->bv_val, 0 ); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return LDAP_OTHER; } @@ -228,7 +406,10 @@ backsql_count_children( char *end; *nchildren = strtol( row.cols[ 0 ], &end, 0 ); - if ( end[ 0 ] != '\0' ) { + if ( end[ 0 ] != '\0' && end[0] != '.' ) { + /* FIXME: braindead RDBMSes return + * a fractional number from COUNT! + */ res = LDAP_OTHER; } @@ -268,73 +449,355 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) { backsql_at_map_rec *at = v_at; backsql_srch_info *bsi = v_bsi; - backsql_info *bi = (backsql_info *)bsi->op->o_bd->be_private; + backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; RETCODE rc; - SQLHSTMT sth; + SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row; - int i; + unsigned long i, + k = 0, + oldcount = 0; +#ifdef BACKSQL_COUNTQUERY + unsigned long count, + countsize = sizeof( count ), + j; + Attribute *attr = NULL; + + slap_mr_normalize_func *normfunc = NULL; +#endif /* BACKSQL_COUNTQUERY */ +#ifdef BACKSQL_PRETTY_VALIDATE + slap_syntax_validate_func *validate = NULL; + slap_syntax_transform_func *pretty = NULL; +#endif /* BACKSQL_PRETTY_VALIDATE */ assert( at ); assert( bsi ); - + +#ifdef BACKSQL_ARBITRARY_KEY Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): " - "oc='%s' attr='%s' keyval=%ld\n", - BACKSQL_OC_NAME( bsi->oc ), at->ad->ad_cname.bv_val, - bsi->c_eid->keyval ); + "oc=\"%s\" attr=\"%s\" keyval=%s\n", + BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, + bsi->bsi_c_eid->eid_keyval.bv_val ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): " + "oc=\"%s\" attr=\"%s\" keyval=%ld\n", + BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, + bsi->bsi_c_eid->eid_keyval ); +#endif /* ! BACKSQL_ARBITRARY_KEY */ + +#ifdef BACKSQL_PRETTY_VALIDATE + validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate; + pretty = at->bam_ad->ad_type->sat_syntax->ssyn_pretty; + + if ( validate == NULL && pretty == NULL ) { + return 1; + } +#endif /* BACKSQL_PRETTY_VALIDATE */ - rc = backsql_Prepare( bsi->dbh, &sth, at->query, 0 ); +#ifdef BACKSQL_COUNTQUERY + if ( at->bam_ad->ad_type->sat_equality ) { + normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize; + } + + /* Count how many rows will be returned. This avoids memory + * fragmentation that can result from loading the values in + * one by one and using realloc() + */ + rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " - "error preparing query: %s\n", at->query, 0, 0 ); - backsql_PrintErrors( bi->db_env, bsi->dbh, sth, rc ); + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error preparing count query: %s\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); return 1; } - rc = backsql_BindParamID( sth, 1, &bsi->c_eid->keyval ); + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, + &bsi->bsi_c_eid->eid_keyval ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "error binding key value parameter\n", 0, 0, 0 ); + SQLFreeStmt( sth, SQL_DROP ); return 1; } rc = SQLExecute( sth ); if ( ! BACKSQL_SUCCESS( rc ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " - "error executing attribute query '%s'\n", - at->query, 0, 0 ); - backsql_PrintErrors( bi->db_env, bsi->dbh, sth, rc ); + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error executing attribute count query '%s'\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return 1; } - backsql_BindRowAsStrings( sth, &row ); + SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG, + (SQLPOINTER)&count, + (SQLINTEGER)sizeof( count ), + &countsize ); rc = SQLFetch( sth ); - for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error fetch results of count query: %s\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "number of values in query: %d\n", count, 0, 0 ); + SQLFreeStmt( sth, SQL_DROP ); + if ( count == 0 ) { + return 1; + } + + attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad ); + if ( attr != NULL ) { + BerVarray tmp; + + if ( attr->a_vals != NULL ) { + for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ ) + /* just count */ ; + } + + tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); + if ( tmp == NULL ) { + return 1; + } + attr->a_vals = tmp; + memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) ); + + if ( normfunc ) { + tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); + if ( tmp == NULL ) { + return 1; + } + attr->a_nvals = tmp; + memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) ); + + } else { + attr->a_nvals = attr->a_vals; + } + + } else { + Attribute **ap; + + /* Make space for the array of values */ + attr = (Attribute *) ch_malloc( sizeof( Attribute ) ); + attr->a_desc = at->bam_ad; + attr->a_flags = 0; + attr->a_next = NULL; + attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) ); + if ( attr->a_vals == NULL ) { + Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 ); + ch_free( attr ); + return 1; + } + memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) ); + if ( normfunc ) { + attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) ); + if ( attr->a_nvals == NULL ) { + ch_free( attr->a_vals ); + ch_free( attr ); + return 1; + + } else { + memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) ); + } + + } else { + attr->a_nvals = attr->a_vals; + } + + for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next ) + /* goto last */ ; + *ap = attr; + } +#endif /* BACKSQL_COUNTQUERY */ + + rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error preparing query: %s\n", at->bam_query, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + return 1; + } + + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, + &bsi->bsi_c_eid->eid_keyval ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error binding key value parameter\n", 0, 0, 0 ); + return 1; + } + +#ifdef BACKSQL_TRACE +#ifdef BACKSQL_ARBITRARY_KEY + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "query=\"%s\" keyval=%s\n", at->bam_query, + bsi->bsi_c_eid->eid_keyval.bv_val, 0 ); +#else /* !BACKSQL_ARBITRARY_KEY */ + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "query=\"%s\" keyval=%d\n", at->bam_query, + bsi->bsi_c_eid->eid_keyval, 0 ); +#endif /* ! BACKSQL_ARBITRARY_KEY */ +#endif /* BACKSQL_TRACE */ + + rc = SQLExecute( sth ); + if ( ! BACKSQL_SUCCESS( rc ) ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error executing attribute query \"%s\"\n", + at->bam_query, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + backsql_BindRowAsStrings( sth, &row ); +#ifdef BACKSQL_COUNTQUERY + j = oldcount; +#endif /* BACKSQL_COUNTQUERY */ + for ( rc = SQLFetch( sth ), k = 0; + BACKSQL_SUCCESS( rc ); + rc = SQLFetch( sth ), k++ ) + { for ( i = 0; i < row.ncols; i++ ) { + if ( row.value_len[ i ] > 0 ) { - struct berval bv; + struct berval bv; + int retval; +#ifdef BACKSQL_TRACE + AttributeDescription *ad = NULL; + const char *text; + + retval = slap_bv2ad( &row.col_names[ i ], &ad, &text ); + if ( retval != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "unable to find AttributeDescription %s " + "in schema (%d)\n", + bsi->bsi_e->e_name.bv_val, + row.col_names[ i ].bv_val, retval ); + return 1; + } + + if ( ad != at->bam_ad ) { + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "column name %s differs from " + "AttributeDescription %s\n", + bsi->bsi_e->e_name.bv_val, + ad->ad_cname.bv_val, + at->bam_ad->ad_cname.bv_val ); + return 1; + } +#endif /* BACKSQL_TRACE */ - bv.bv_val = row.cols[ i ]; -#if 0 - bv.bv_len = row.col_prec[ i ]; -#else /* * FIXME: what if a binary * is fetched? */ - bv.bv_len = strlen( row.cols[ i ] ); -#endif - backsql_entry_addattr( bsi->e, - &row.col_names[ i ], &bv, - bsi->op->o_tmpmemctx ); + ber_str2bv( row.cols[ i ], 0, 0, &bv ); + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + struct berval pbv; + + retval = pretty( at->bam_ad->ad_type->sat_syntax, + &bv, &pbv, bsi->bsi_op->o_tmpmemctx ); + bv = pbv; + + } else { + retval = validate( at->bam_ad->ad_type->sat_syntax, + &bv ); + } + + if ( retval != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + /* FIXME: we're ignoring invalid values, + * but we're accepting the attributes; + * should we fail at all? */ + snprintf( buf, sizeof( buf ), + "unable to %s value #%d " + "of AttributeDescription %s", + pretty ? "prettify" : "validate", + at->bam_ad->ad_cname.bv_val, + k - oldcount ); + Debug( LDAP_DEBUG_TRACE, + "==>backsql_get_attr_vals(\"%s\"): " + "%s (%d)\n", + bsi->bsi_e->e_name.bv_val, buf, retval ); + continue; + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + +#ifndef BACKSQL_COUNTQUERY + (void)backsql_entry_addattr( bsi->bsi_e, + at->bam_ad, &bv, + bsi->bsi_op->o_tmpmemctx ); + +#else /* BACKSQL_COUNTQUERY */ + if ( normfunc ) { + struct berval nbv; + + retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + at->bam_ad->ad_type->sat_syntax, + at->bam_ad->ad_type->sat_equality, + &bv, &nbv, + bsi->bsi_op->o_tmpmemctx ); + + if ( retval != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + /* FIXME: we're ignoring invalid values, + * but we're accepting the attributes; + * should we fail at all? */ + snprintf( buf, sizeof( buf ), + "unable to normalize value #%d " + "of AttributeDescription %s", + at->bam_ad->ad_cname.bv_val, + k - oldcount ); + Debug( LDAP_DEBUG_TRACE, + "==>backsql_get_attr_vals(\"%s\"): " + "%s (%d)\n", + bsi->bsi_e->e_name.bv_val, buf, retval ); + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + bsi->bsi_op->o_tmpfree( bv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + + continue; + } + ber_dupbv( &attr->a_nvals[ j ], &nbv ); + bsi->bsi_op->o_tmpfree( nbv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } + + ber_dupbv( &attr->a_vals[ j ], &bv ); + + assert( j < oldcount + count ); + j++; +#endif /* BACKSQL_COUNTQUERY */ + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + bsi->bsi_op->o_tmpfree( bv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } +#endif /* BACKSQL_PRETTY_VALIDATE */ #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "prec=%d\n", (int)row.col_prec[ i ], 0, 0 ); + } else { Debug( LDAP_DEBUG_TRACE, "NULL value " - "in this row for attribute '%s'\n", + "in this row for attribute \"%s\"\n", row.col_names[ i ].bv_val, 0, 0 ); #endif /* BACKSQL_TRACE */ } @@ -345,66 +808,130 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) SQLFreeStmt( sth, SQL_DROP ); Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 ); + if ( at->bam_next ) { + return backsql_get_attr_vals( at->bam_next, v_bsi ); + } + return 1; } -Entry * -backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid ) +int +backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) { + Operation *op = bsi->bsi_op; + backsql_info *bi = (backsql_info *)op->o_bd->be_private; int i; - backsql_at_map_rec *at; int rc; - AttributeDescription *ad_oc = slap_schema.si_ad_objectClass; Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 ); - rc = dnPrettyNormal( NULL, &eid->dn, &e->e_name, &e->e_nname, - bsi->op->o_tmpmemctx ); - if ( rc != LDAP_SUCCESS ) { - return NULL; + assert( bsi->bsi_e ); + + memset( bsi->bsi_e, 0, sizeof( Entry ) ); + + if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) { + Entry *e; + + e = entry_dup( bi->sql_baseObject ); + if ( e == NULL ) { + return LDAP_NO_MEMORY; + } + + *bsi->bsi_e = *e; + free( e ); + goto done; } - bsi->oc = backsql_id2oc( bsi->op->o_bd->be_private, eid->oc_id ); - bsi->e = e; - bsi->c_eid = eid; - e->e_attrs = NULL; - e->e_private = NULL; - - e->e_id = eid->id; + ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx ); + ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx ); + + bsi->bsi_e->e_attrs = NULL; + bsi->bsi_e->e_private = NULL; + + bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private, + eid->eid_oc_id ); + bsi->bsi_c_eid = eid; + +#ifndef BACKSQL_ARBITRARY_KEY + /* FIXME: unused */ + bsi->bsi_e->e_id = eid->eid_id; +#endif /* ! BACKSQL_ARBITRARY_KEY */ - if ( bsi->attrs != NULL ) { + rc = attr_merge_normalize_one( bsi->bsi_e, + slap_schema.si_ad_objectClass, + &bsi->bsi_oc->bom_oc->soc_cname, + bsi->bsi_op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + entry_clean( bsi->bsi_e ); + return rc; + } + + if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) + { + Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " + "retrieving all attributes\n", 0, 0, 0 ); + avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals, + bsi, 0, AVL_INORDER ); + + } else { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " "custom attribute list\n", 0, 0, 0 ); - for ( i = 0; bsi->attrs[ i ].an_name.bv_val; i++ ) { - AttributeName *attr = &bsi->attrs[ i ]; + for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) { + backsql_at_map_rec **vat; + AttributeName *an = &bsi->bsi_attrs[ i ]; + int j; + + /* if one of the attributes listed here is + * a subtype of another, it must be ignored, + * because subtypes are already dealt with + * by backsql_supad2at() + */ + for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) { + /* skip self */ + if ( j == i ) { + continue; + } + + /* skip subtypes */ + if ( is_at_subtype( an->an_desc->ad_type, + bsi->bsi_attrs[ j ].an_desc->ad_type ) ) + { + goto next; + } + } - if ( attr->an_desc == ad_oc ) { + rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat ); + if ( rc != 0 || vat == NULL ) { + Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " + "attribute \"%s\" is not defined " + "for objectlass \"%s\"\n", + an->an_name.bv_val, + BACKSQL_OC_NAME( bsi->bsi_oc ), 0 ); continue; } - at = backsql_ad2at( bsi->oc, attr->an_desc ); - if ( at != NULL ) { - backsql_get_attr_vals( at, bsi ); - } else { - Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " - "attribute '%s' is not defined " - "for objectlass '%s'\n", - attr->an_name.bv_val, - BACKSQL_OC_NAME( bsi->oc ), 0 ); + for ( j = 0; vat[j]; j++ ) { + backsql_get_attr_vals( vat[j], bsi ); } - } - } else { - Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " - "retrieving all attributes\n", 0, 0, 0 ); - avl_apply( bsi->oc->attrs, backsql_get_attr_vals, - bsi, 0, AVL_INORDER ); + ch_free( vat ); + +next:; + } } - if ( attr_merge_normalize_one( bsi->e, ad_oc, &bsi->oc->oc->soc_cname, - bsi->op->o_tmpmemctx ) ) { - entry_free( e ); - return NULL; + if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) { + Attribute *a_entryUUID, + **ap; + + a_entryUUID = backsql_operational_entryUUID( bi, eid ); + if ( a_entryUUID != NULL ) { + for ( ap = &bsi->bsi_e->e_attrs; + *ap; + ap = &(*ap)->a_next ); + + *ap = a_entryUUID; + } } if ( global_schemacheck ) { @@ -415,32 +942,37 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid ) struct berval soc; int rc; - bv[ 0 ] = bsi->oc->oc->soc_cname; - bv[ 1 ].bv_val = NULL; + bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname; + BER_BVZERO( &bv[ 1 ] ); rc = structural_class( bv, &soc, NULL, &text, textbuf, textlen ); if ( rc != LDAP_SUCCESS ) { - entry_free( e ); - return NULL; + Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " + "structural_class() failed %d (%s)\n", + bsi->bsi_e->e_name.bv_val, + rc, text ? text : "" ); + entry_clean( bsi->bsi_e ); + return rc; } - if ( ( bsi->bsi_flags | BSQL_SF_ALL_OPER ) - || an_find( bsi->attrs, &AllOper ) ) { - rc = attr_merge_normalize_one( bsi->e, + if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER ) + || an_find( bsi->bsi_attrs, &AllOper ) + || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) ) + { + rc = attr_merge_normalize_one( bsi->bsi_e, slap_schema.si_ad_structuralObjectClass, - &soc, bsi->op->o_tmpmemctx ); + &soc, bsi->bsi_op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { - entry_free( e ); - return NULL; + entry_clean( bsi->bsi_e ); + return rc; } } } +done:; Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 ); - return e; + return LDAP_SUCCESS; } -#endif /* SLAPD_SQL */ -