1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "Relation.h"
25#include "LDAPDLModule.h"
26#include "CommonCode.h"
27
28TableRelation *LDAPDLModule::mSchemaRelationRelation = NULL,
29			  *LDAPDLModule::mSchemaAttributeRelation = NULL,
30			  *LDAPDLModule::mSchemaIndexRelation = NULL,
31			  *LDAPDLModule::mSchemaParsingModuleRelation = NULL;
32DSX509Relation *LDAPDLModule::mX509Relation = NULL;
33RelationMap *LDAPDLModule::mRelationMap;
34
35
36void LDAPDLModule::SetupSchemaRelationRelation ()
37{
38	// setup the CSSM_DL_DB_SCHEMA_INDEXES
39
40	static columnInfoLoader ciLoader[] = {
41		{ 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
42		{ 0, "RelationName", CSSM_DB_ATTRIBUTE_FORMAT_STRING },
43	};
44
45	mSchemaRelationRelation = new TableRelation (CSSM_DL_DB_SCHEMA_INFO, (sizeof(ciLoader) / sizeof(columnInfoLoader)), ciLoader);
46
47	mSchemaRelationRelation->AddTuple (new UInt32Value (CSSM_DL_DB_SCHEMA_INFO), new StringValue ("CSSM_DL_DB_SCHEMA_INFO"));
48	mSchemaRelationRelation->AddTuple (new UInt32Value (CSSM_DL_DB_SCHEMA_ATTRIBUTES), new StringValue ("CSSM_DL_DB_SCHEMA_ATTRIBUTES"));
49	mSchemaRelationRelation->AddTuple (new UInt32Value (CSSM_DL_DB_SCHEMA_INDEXES), new StringValue ("CSSM_DL_DB_SCHEMA_INDEXES"));
50	mSchemaRelationRelation->AddTuple (new UInt32Value (CSSM_DL_DB_SCHEMA_PARSING_MODULE), new StringValue ("CSSM_DL_DB_SCHEMA_PARSING_MODULE"));
51	mSchemaRelationRelation->AddTuple (new UInt32Value (CSSM_DL_DB_RECORD_X509_CERTIFICATE), new StringValue ("CSSM_DL_DB_RECORD_X509_CERTIFICATE"));
52	(*mRelationMap)[CSSM_DL_DB_SCHEMA_INFO] = mSchemaRelationRelation;
53	(*mRelationMap)[CSSM_DL_DB_SCHEMA_INDEXES] = mSchemaRelationRelation;
54}
55
56
57struct attributeLoader {
58	UInt32 relationID;
59	UInt32 attrID;
60	const char * attrName;
61	UInt32 attrFormat;
62};
63
64void LDAPDLModule::SetupSchemaAttributeRelation ()
65{
66	static columnInfoLoader ciLoader[] = {
67		{ 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
68		{ 1, "AttributeID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
69		{ 2, "AttributeNameFormat", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
70		{ 3, "AttributeName", CSSM_DB_ATTRIBUTE_FORMAT_STRING },
71		{ 4, "AttributeNameID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
72		{ 5, "AttributeFormat", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
73	};
74	mSchemaAttributeRelation = new TableRelation (CSSM_DL_DB_SCHEMA_ATTRIBUTES, (sizeof(ciLoader) / sizeof(columnInfoLoader)), ciLoader);
75
76	static struct attributeLoader loader[] = {
77		// setup the index
78		{  CSSM_DL_DB_SCHEMA_INFO, 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
79		{  CSSM_DL_DB_SCHEMA_INFO, 1, "RelationName", CSSM_DB_ATTRIBUTE_FORMAT_STRING },
80
81		// setup the attribute table
82		{  CSSM_DL_DB_SCHEMA_ATTRIBUTES, 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
83		{  CSSM_DL_DB_SCHEMA_ATTRIBUTES, 1, "AttributeID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
84		{  CSSM_DL_DB_SCHEMA_ATTRIBUTES, 2, "AttributeNameFormat", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
85		{  CSSM_DL_DB_SCHEMA_ATTRIBUTES, 3, "AttributeName", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
86		{  CSSM_DL_DB_SCHEMA_ATTRIBUTES, 4, "AttributeName", CSSM_DB_ATTRIBUTE_FORMAT_STRING },
87		{  CSSM_DL_DB_SCHEMA_ATTRIBUTES, 5, "AttributeNameID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
88
89		// setup the index table
90		{  CSSM_DL_DB_SCHEMA_INDEXES, 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
91		{  CSSM_DL_DB_SCHEMA_INDEXES, 1, "IndexID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
92		{  CSSM_DL_DB_SCHEMA_INDEXES, 2, "AttributeID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
93		{  CSSM_DL_DB_SCHEMA_INDEXES, 3, "IndexType", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
94		{  CSSM_DL_DB_SCHEMA_INDEXES, 4, "IndexedDataLocation", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
95
96		// setup the schema parsing module
97		{  CSSM_DL_DB_SCHEMA_PARSING_MODULE, 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
98		{  CSSM_DL_DB_SCHEMA_PARSING_MODULE, 1, "AttributeID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
99		{  CSSM_DL_DB_SCHEMA_PARSING_MODULE, 2, "ModuleID", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
100		{  CSSM_DL_DB_SCHEMA_PARSING_MODULE, 3, "AddInVersion", CSSM_DB_ATTRIBUTE_FORMAT_STRING },
101		{  CSSM_DL_DB_SCHEMA_PARSING_MODULE, 4, "SSID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
102		{  CSSM_DL_DB_SCHEMA_PARSING_MODULE, 5, "SubserviceType", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
103
104	};
105
106	int nrows = sizeof(loader) / sizeof(struct attributeLoader);
107	for(int i=0; i < nrows; i++)
108		mSchemaAttributeRelation->AddTuple (new UInt32Value (loader[i].relationID),new UInt32Value (loader[i].attrID),new UInt32Value (CSSM_DB_ATTRIBUTE_NAME_AS_STRING),new StringValue (loader[i].attrName), NULL, new UInt32Value (loader[i].attrFormat));
109
110	(*mRelationMap)[CSSM_DL_DB_SCHEMA_ATTRIBUTES] = mSchemaAttributeRelation;
111}
112
113
114
115struct indexLoader {
116	UInt32 relationID;
117	UInt32 indexID;
118	UInt32 attributeID;
119	UInt32 indexType;
120	UInt32 indexedDataLocation;
121};
122
123void LDAPDLModule::SetupSchemaIndexRelation ()
124{
125	static columnInfoLoader ciLoader[] = {
126		{ 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
127		{ 1, "IndexID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
128		{ 2, "AttributeID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
129		{ 3, "IndexType", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
130		{ 4, "IndexedDataLocation", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
131	};
132	mSchemaIndexRelation = new TableRelation (CSSM_DL_DB_SCHEMA_INDEXES, (sizeof(ciLoader) / sizeof(columnInfoLoader)), ciLoader);
133
134	static struct indexLoader loader[] = {
135		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 0, 'ctyp', 0, 1 },
136		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 1, 'issu', 0, 1 },
137		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 2, 'snbr', 0, 1 },
138		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 3, 'alis', 1, 1 },
139		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 4, 'subj', 1, 1 },
140		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 5, 'issu', 1, 1 },
141		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 6, 'snbr', 1, 1 },
142		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 7, 'skid', 1, 1 },
143		{ CSSM_DL_DB_RECORD_X509_CERTIFICATE, 8, 'hpky', 1, 1 },
144	};
145
146	int nrows = sizeof(loader) / sizeof(struct indexLoader);
147	for(int i=0; i < nrows; i++)
148		mSchemaIndexRelation->AddTuple (new UInt32Value (loader[i].relationID),new UInt32Value (loader[i].indexID), new UInt32Value (loader[i].attributeID), new UInt32Value (loader[i].indexType), new UInt32Value (loader[i].indexedDataLocation));
149
150	(*mRelationMap)[CSSM_DL_DB_SCHEMA_INDEXES] = mSchemaIndexRelation;
151}
152
153
154
155void LDAPDLModule::SetupSchemaParsingModuleRelation ()
156{
157	static columnInfoLoader ciLoader[] = {
158		{ 0, "RelationID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
159		{ 1, "AttributeID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
160		{ 2, "ModuleID", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
161		{ 3, "AddinVersion", CSSM_DB_ATTRIBUTE_FORMAT_STRING },
162		{ 4, "SSID", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
163		{ 5, "SubserviceType", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
164	};
165	mSchemaParsingModuleRelation = new TableRelation (CSSM_DL_DB_SCHEMA_PARSING_MODULE, (sizeof(ciLoader) / sizeof(columnInfoLoader)), ciLoader);
166	(*mRelationMap)[CSSM_DL_DB_SCHEMA_PARSING_MODULE] = mSchemaParsingModuleRelation;
167}
168
169
170
171void LDAPDLModule::SetupX509Relation ()
172{
173	static columnInfoLoader ciLoader[] = {
174		{ 'ctyp', "CertType", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
175		{ 'cenc', "CertEncoding", CSSM_DB_ATTRIBUTE_FORMAT_UINT32 },
176		{ 'labl', "PrintName", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
177		{ 'alis', "Alias", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
178		{ 'subj', "Subject", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
179		{ 'issu', "Issuer", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
180		{ 'snbr', "SerialNumber", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
181		{ 'skid', "SubjectKeyIdentifier", CSSM_DB_ATTRIBUTE_FORMAT_BLOB },
182		{ 'hpky', "PublicKeyHash", CSSM_DB_ATTRIBUTE_FORMAT_BLOB }
183	};
184	mX509Relation = new DSX509Relation (CSSM_DL_DB_RECORD_X509_CERTIFICATE, (sizeof(ciLoader) / sizeof(columnInfoLoader)), ciLoader);
185
186	// add the relation to the attributes table
187	int max = mX509Relation->GetNumberOfColumns ();
188
189	for (int i = 0; i < max; ++i)
190		mSchemaAttributeRelation->AddTuple (new UInt32Value (CSSM_DL_DB_RECORD_X509_CERTIFICATE), new UInt32Value (mX509Relation->GetColumnIDs (i)), new UInt32Value (CSSM_DB_ATTRIBUTE_NAME_AS_STRING),
191											mX509Relation->GetColumnName (i), NULL, new UInt32Value (mX509Relation->GetColumnFormat (i)));
192	(*mRelationMap)[CSSM_DL_DB_RECORD_X509_CERTIFICATE] = mX509Relation;
193
194	// add to the attribute info database
195	mSchemaRelationRelation->AddTuple (new UInt32Value (CSSM_DL_DB_RECORD_X509_CERTIFICATE), new StringValue ("CSSM_DL_DB_RECORD_X509_CERTIFICATE"));
196
197}
198
199
200
201void LDAPDLModule::InitializeRelations ()
202{
203	mRelationMap = new RelationMap;
204	SetupSchemaRelationRelation ();
205	SetupSchemaAttributeRelation ();
206	SetupSchemaIndexRelation ();
207	SetupSchemaParsingModuleRelation ();
208	SetupX509Relation ();
209}
210
211
212
213LDAPDLModule::LDAPDLModule (pthread_mutex_t *globalLock, CSSM_SPI_ModuleEventHandler CssmNotifyCallback, void* CssmNotifyCallbackCtx) :
214	DataStorageLibrary (globalLock, CssmNotifyCallback, CssmNotifyCallbackCtx)
215{
216}
217
218
219
220LDAPDLModule::~LDAPDLModule ()
221{
222}
223
224
225
226AttachedInstance* LDAPDLModule::MakeAttachedInstance ()
227{
228	return new LDAPAttachedInstance ();
229}
230
231
232
233Relation* LDAPDLModule::LookupRelation (CSSM_DB_RECORDTYPE recordType)
234{
235    if (mSchemaRelationRelation == NULL)
236		InitializeRelations ();
237	RelationMap::iterator r = (*mRelationMap).find (recordType);
238	if (r == (*mRelationMap).end ())
239		CSSMError::ThrowCSSMError (CSSMERR_DL_INVALID_RECORDTYPE);
240
241	return (*r).second;
242}
243
244
245
246Database* LDAPAttachedInstance::MakeDatabaseObject ()
247{
248	return new LDAPDatabase (this);
249}
250
251
252
253LDAPDatabase::LDAPDatabase (AttachedInstance *ai) : Database (ai), mNextHandle (0)
254{
255}
256
257
258
259LDAPDatabase::~LDAPDatabase ()
260{
261}
262
263
264
265void LDAPDatabase::DbOpen (const char* DbName, const CSSM_NET_ADDRESS *dbLocation, const CSSM_DB_ACCESS_TYPE accessRequest,
266						   const CSSM_ACCESS_CREDENTIALS *accessCredentials, const void* openParameters)
267{
268	if (DbName == NULL)
269		CSSMError::ThrowCSSMError (CSSMERR_CSSM_INVALID_POINTER);
270
271	// this database can only be opened read only.  Any attempt to gain write permissions will be dealt with severely
272	if (accessRequest != CSSM_DB_ACCESS_READ)
273		CSSMError::ThrowCSSMError (CSSMERR_DL_INVALID_ACCESS_REQUEST);
274
275	mDatabaseName = DbName;
276}
277
278
279
280void LDAPDatabase::DbClose ()
281{
282	// we're about to disappear...
283}
284
285
286
287void LDAPDatabase::DbGetDbNameFromHandle (char** dbName)
288{
289	// return the name of our storage library
290
291	*dbName = (char*) mAttachedInstance->malloc (mDatabaseName.length () + 1);
292	strcpy (*dbName, mDatabaseName.c_str ());
293}
294
295
296
297void LDAPDatabase::CopyAttributes (Relation *r, Tuple *t, CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes)
298{
299	// fill out each attribute requested
300	if(t == NULL || r == NULL || attributes == NULL) return;
301
302	uint32 i;
303	CSSM_DB_ATTRIBUTE_DATA* d = attributes->AttributeData;
304	attributes->DataRecordType = r->GetRecordType ();
305	Value *v;
306
307	for (i = 0; i < attributes->NumberOfAttributes; ++i, d++) {
308		int columnNumber;
309		switch (d->Info.AttributeNameFormat) {
310		case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
311			columnNumber = r->GetColumnNumber (d->Info.Label.AttributeName);
312			break;
313		case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
314			columnNumber = r->GetColumnNumber (d->Info.Label.AttributeID);
315			break;
316		default:
317			columnNumber = r->GetColumnNumber (d->Info.Label.AttributeID);
318			break;
319		}
320
321		if ( columnNumber != -1 && (v = t->GetValue (columnNumber)) != NULL) {
322			d->Value = (CSSM_DATA_PTR) mAttachedInstance->malloc (sizeof (CSSM_DATA));
323			d->Info.AttributeFormat = v->GetValueType();
324			uint32 numItems, length;
325
326			d->Value->Data = v->CloneContents (mAttachedInstance, numItems, length);
327			d->Value->Length = length;
328			d->NumberOfValues = numItems;
329		} else {
330			d->Value = NULL;
331			d->NumberOfValues = 0;
332		}
333	}
334}
335
336
337
338const uint32 kMaximumSelectionPredicates = 1000;
339
340
341
342void LDAPDatabase::GetDataFromTuple (Tuple *t, CSSM_DATA &data)
343{
344	// get the data from the tuple
345	CSSM_DATA tmpData;
346	t->GetData (tmpData);
347
348	// clone it
349	data.Data = (uint8 *)mAttachedInstance->malloc (tmpData.Length);
350	data.Length = tmpData.Length;
351	memmove(data.Data, tmpData.Data, data.Length);
352}
353
354
355void LDAPDatabase::processNext(CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes, CSSM_DATA_PTR data,CSSM_DB_UNIQUE_RECORD_PTR *uniqueID, Query *q, Relation *r)
356{
357	UniqueIdentifier *id;
358	Tuple* t = q->GetNextTuple (id);
359
360	if (t == NULL)  CSSMError::ThrowCSSMError (CSSMERR_DL_ENDOFDATA);
361	if(attributes != NULL)  CopyAttributes (r, t, attributes);
362	if (data != NULL) GetDataFromTuple (t, *data);
363
364	// new record unique ID
365	ExportUniqueID (id, uniqueID);
366}
367
368CSSM_HANDLE LDAPDatabase::DbDataGetFirst (const CSSM_QUERY *query,
369										  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes,
370										  CSSM_DATA_PTR data,
371										  CSSM_DB_UNIQUE_RECORD_PTR *uniqueID)
372{
373	// since we really only track one record type, record type CSSM_DL_DB_RECORD_ANY is the same as
374	// CSSM_DL_DB_RECORD_X509_CERTIFICATE
375
376	*uniqueID = NULL;
377
378	if(!query) CSSMError::ThrowCSSMError (CSSMERR_DL_ENDOFDATA);
379
380	CSSM_DB_RECORDTYPE recordType = query->RecordType;
381
382	switch (recordType) {
383		case CSSM_DL_DB_RECORD_ANY:
384			recordType = CSSM_DL_DB_RECORD_X509_CERTIFICATE;
385			break;
386		case CSSM_DL_DB_SCHEMA_INFO:
387			break;
388		case CSSM_DL_DB_SCHEMA_INDEXES:
389			break;
390		case CSSM_DL_DB_SCHEMA_ATTRIBUTES:
391			break;
392		case CSSM_DL_DB_SCHEMA_PARSING_MODULE:
393		 	break;
394		case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
395			break;
396		default:
397			CSSMError::ThrowCSSMError (CSSMERR_DL_ENDOFDATA);
398			break;
399	}
400
401
402	// do error checking on the attributes
403	if ((attributes != NULL) && (attributes->SemanticInformation != 0)) CSSMError::ThrowCSSMError (CSSMERR_DL_INVALID_QUERY);
404
405	// set an arbitrary limit on the number of selection predicates -- mostly for range checking
406	if (query->NumSelectionPredicates > kMaximumSelectionPredicates) CSSMError::ThrowCSSMError (CSSMERR_DL_UNSUPPORTED_NUM_SELECTION_PREDS);
407
408	// lookup our relation in the relation map
409	Relation* r = LDAPDLModule::LookupRelation (recordType);
410
411	// make a query for this request
412	Query *q = r->MakeQuery (query);
413
414	if(!q) CSSMError::ThrowCSSMError (CSSMERR_DL_ENDOFDATA);
415
416	processNext(attributes, data, uniqueID, q, r);
417
418	// make a new handle for this query
419	CSSM_HANDLE h = mNextHandle++;
420	mQueryMap[h] = q;
421	return h;
422}
423
424
425bool LDAPDatabase::DbDataGetNext (CSSM_HANDLE resultsHandle,
426								  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes,
427								  CSSM_DATA_PTR data,
428								  CSSM_DB_UNIQUE_RECORD_PTR *uniqueID)
429{
430	*uniqueID = NULL;
431
432	QueryMap::iterator it = mQueryMap.find (resultsHandle);
433	if (it == mQueryMap.end ())  CSSMError::ThrowCSSMError (CSSMERR_DL_ENDOFDATA);
434
435	Query* q = (*it).second;
436
437	if(!q) CSSMError::ThrowCSSMError (CSSMERR_DL_ENDOFDATA);
438	Relation *r = q->GetRelation ();
439
440	processNext(attributes, data, uniqueID, q, r);
441
442	return true;
443}
444
445
446void LDAPDatabase::ExportUniqueID (UniqueIdentifier *id, CSSM_DB_UNIQUE_RECORD_PTR *uniqueID)
447{
448	CSSM_DB_UNIQUE_RECORD *ur = new CSSM_DB_UNIQUE_RECORD;
449	// id->Export (*ur);
450	ur->RecordIdentifier.Length = sizeof (id);
451	ur->RecordIdentifier.Data = (uint8*) id;
452	*uniqueID = ur;
453}
454
455
456void LDAPDatabase::DbDataAbortQuery (CSSM_HANDLE resultsHandle)
457{
458	QueryMap::iterator it = mQueryMap.find (resultsHandle);
459	if (it == mQueryMap.end ()) return;
460
461	Query* q = (*it).second;
462	delete q;
463	mQueryMap.erase (resultsHandle);
464}
465
466
467
468void LDAPDatabase::DbFreeUniqueRecord (CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord)
469{
470	UniqueIdentifier* id = (UniqueIdentifier*) uniqueRecord->RecordIdentifier.Data;
471	delete id;
472	delete uniqueRecord;
473}
474
475
476
477void LDAPDatabase::DbDataGetFromUniqueRecordID (const CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord,
478												CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes,
479												CSSM_DATA_PTR data)
480{
481	// recover the identifier
482	if(uniqueRecord == NULL) return;
483
484	UniqueIdentifier* id = (UniqueIdentifier*) uniqueRecord->RecordIdentifier.Data;
485	if(id==NULL) return;
486
487	CSSM_DB_RECORDTYPE recordType = id->GetRecordType ();
488	Relation* r = LDAPDLModule::LookupRelation (recordType);
489	if(r == NULL)return;
490
491	Tuple* t = r->GetTupleFromUniqueIdentifier (id);
492	if(t == NULL) return;
493
494	if(attributes != NULL)  CopyAttributes (r, t, attributes);
495	if (data != NULL) GetDataFromTuple (t, *data);
496}
497