1/*
2 * Copyright (c) 2005-2006,2010 Apple 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 * 01DL_CreateReleation.c
24 */
25
26#include <stdlib.h>
27#include <unistd.h>
28#include <Security/cssmapi.h>
29#include <Security/cssmapple.h>
30
31#include "testmore.h"
32#include "testenv.h"
33#include "testcssm.h"
34#include "testleaks.h"
35
36#define DBNAME "testdl"
37
38CSSM_APPLEDL_OPEN_PARAMETERS openParameters =
39{
40	sizeof(CSSM_APPLEDL_OPEN_PARAMETERS),
41	CSSM_APPLEDL_OPEN_PARAMETERS_VERSION,
42	CSSM_FALSE,
43	kCSSM_APPLEDL_MASK_MODE,
44	0600
45};
46CSSM_DBINFO dbInfo =
47{
48	0 /* NumberOfRecordTypes */,
49	NULL,
50	NULL,
51	NULL,
52	CSSM_TRUE /* IsLocal */,
53	NULL, /* AccessPath - URL, dir path, etc. */
54	NULL /* reserved */
55};
56CSSM_DB_SCHEMA_ATTRIBUTE_INFO attributeInfo[] =
57{
58	{
59		1,
60		"string-1",
61		{},
62		CSSM_DB_ATTRIBUTE_FORMAT_STRING
63	},
64	{
65		2,
66		"sint32-2",
67		{},
68		CSSM_DB_ATTRIBUTE_FORMAT_SINT32
69	},
70	{
71		3,
72		"uint32-3",
73		{},
74		CSSM_DB_ATTRIBUTE_FORMAT_UINT32
75	},
76	{
77		4,
78		"big_num-4",
79		{},
80		CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
81	},
82	{
83		5,
84		"real-5",
85		{},
86		CSSM_DB_ATTRIBUTE_FORMAT_REAL
87	},
88	{
89		6,
90		"time-date-6",
91		{},
92		CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
93	},
94	{
95		7,
96		"blob-7",
97		{},
98		CSSM_DB_ATTRIBUTE_FORMAT_BLOB
99	},
100	{
101		8,
102		"multi-uint32-8",
103		{},
104		CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
105	},
106#if 0
107	/* @@@ DL bug if you create a relation with a
108	   CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX type attribute it succeeds but
109	   subsequent inserts in that table fail.  */
110	{
111		9,
112		"complex-9",
113		{},
114		CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX
115	}
116#endif
117};
118CSSM_DB_SCHEMA_INDEX_INFO indexInfo[] =
119{
120	{
121		1,
122		0,
123		CSSM_DB_INDEX_UNIQUE,
124		CSSM_DB_INDEX_ON_ATTRIBUTE
125	},
126	{
127		1,
128		1,
129		CSSM_DB_INDEX_NONUNIQUE,
130		CSSM_DB_INDEX_ON_ATTRIBUTE
131	},
132	{
133		2,
134		2,
135		CSSM_DB_INDEX_NONUNIQUE,
136		CSSM_DB_INDEX_ON_ATTRIBUTE
137	}
138};
139CSSM_DATA values_str_1[] =
140{
141	{ 7, (uint8 *)"value-1" }
142};
143CSSM_DATA values_str_2[] =
144{
145	{ 7, (uint8 *)"value-2" }
146};
147CSSM_DATA values_sint32_1[] =
148{
149	{ sizeof(sint32), (uint8 *)"1111" }
150};
151CSSM_DATA values_sint32_2[] =
152{
153	{ sizeof(sint32), (uint8 *)"2222" }
154};
155
156CSSM_DB_ATTRIBUTE_DATA attributeData[] =
157{
158	{
159		{
160			CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
161			{ (char *)((uint64_t)1<<32|1) },
162			CSSM_DB_ATTRIBUTE_FORMAT_STRING
163		},
164		sizeof(values_str_1) / sizeof(CSSM_DATA),
165		values_str_1
166	},
167	{
168		{
169			CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
170			{ (char *)((uint64_t)2<<32|2) },
171			CSSM_DB_ATTRIBUTE_FORMAT_SINT32
172		},
173		sizeof(values_sint32_1) / sizeof(CSSM_DATA),
174		values_sint32_1
175	}
176};
177CSSM_DB_RECORD_ATTRIBUTE_DATA attributes =
178{
179	42,
180	0x00008000,
181	sizeof(attributeData) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
182	attributeData
183};
184
185CSSM_DB_ATTRIBUTE_DATA newAttributeData[] =
186{
187	{
188		{
189			CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
190			{ (char *)((uint64_t)1<<32|1) },
191			CSSM_DB_ATTRIBUTE_FORMAT_STRING
192		},
193		sizeof(values_str_2) / sizeof(CSSM_DATA),
194		values_str_2
195	},
196	{
197		{
198			CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
199			{ (char *)((uint64_t)2<<32|2) },
200			CSSM_DB_ATTRIBUTE_FORMAT_SINT32
201		},
202		sizeof(values_sint32_2) / sizeof(CSSM_DATA),
203		values_sint32_2
204	}
205};
206CSSM_DB_RECORD_ATTRIBUTE_DATA newAttributes =
207{
208	42,
209	0x80000001, /* Semantic Information. */
210	sizeof(newAttributeData) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
211	newAttributeData
212};
213
214static void free_attributes_data(const CSSM_API_MEMORY_FUNCS *memfuncs,
215	CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes, CSSM_DATA_PTR data)
216{
217	if (data && data->Data)
218	{
219		memfuncs->free_func(data->Data, memfuncs->AllocRef);
220		data->Data = NULL;
221	}
222
223	if (attributes && attributes->AttributeData)
224	{
225		uint32 aix;
226		for (aix = 0; aix < attributes->NumberOfAttributes; ++aix)
227		{
228			if (attributes->AttributeData[aix].Value)
229			{
230				uint32 vix;
231				for (vix = 0;
232					vix < attributes->AttributeData[aix].NumberOfValues; ++vix)
233				{
234					if (attributes->AttributeData[aix].Value[vix].Data)
235					{
236						memfuncs->free_func(
237                            attributes->AttributeData[aix].Value[vix].Data,
238							memfuncs->AllocRef);
239					}
240				}
241
242				memfuncs->free_func(attributes->AttributeData[aix].Value,
243					memfuncs->AllocRef);
244				attributes->AttributeData[aix].NumberOfValues = 0;
245				attributes->AttributeData[aix].Value = NULL;
246			}
247		}
248	}
249}
250
251static int test_is_attributes_data(
252	const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes1, const CSSM_DATA *data1,
253	const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes2, const CSSM_DATA *data2,
254	const char *description, const char *directive,
255	const char *reason, const char *file, unsigned line)
256{
257	if (attributes1 || attributes2)
258	{
259		if (!attributes1 || !attributes2)
260			return test_ok(0, description, directive, reason, file, line,
261				"#             got CSSM_DB_RECORD_ATTRIBUTE_DATA %p\n"
262				"#        expected CSSM_DB_RECORD_ATTRIBUTE_DATA %p\n",
263				attributes1, attributes2);
264
265		if (attributes1->DataRecordType != attributes2->DataRecordType ||
266			attributes1->SemanticInformation !=
267				attributes2->SemanticInformation ||
268			attributes1->NumberOfAttributes != attributes2->NumberOfAttributes)
269			return test_ok(0, description, directive, reason, file, line,
270				"#         got CSSM_DB_RECORD_ATTRIBUTE_DATA:\n"
271				"#         DataRecordType: %08x\n"
272				"#    SemanticInformation: %08x\n"
273				"#     NumberOfAttributes: %lu\n"
274				"#    expected CSSM_DB_RECORD_ATTRIBUTE_DATA:\n"
275				"#         DataRecordType: %08x\n"
276				"#    SemanticInformation: %08x\n"
277				"#     NumberOfAttributes: %lu\n",
278				attributes1->DataRecordType,
279				attributes1->SemanticInformation,
280				attributes1->NumberOfAttributes,
281				attributes2->DataRecordType,
282				attributes2->SemanticInformation,
283				attributes2->NumberOfAttributes);
284		uint32 ai;
285		for (ai = 0; ai < attributes1->NumberOfAttributes; ++ai)
286		{
287			const CSSM_DB_ATTRIBUTE_DATA *a1 = &attributes1->AttributeData[ai];
288			const CSSM_DB_ATTRIBUTE_DATA *a2 = &attributes2->AttributeData[ai];
289			if (a1->Info.AttributeFormat != a2->Info.AttributeFormat ||
290				a1->NumberOfValues != a2->NumberOfValues)
291				return test_ok(0, description, directive, reason, file, line,
292					"#         got AttributeData[%lu]:\n"
293					"#         AttributeFormat: %08x\n"
294					"#          NumberOfValues: %lu\n"
295					"#    expected AttributeData[%lu]:\n"
296					"#         AttributeFormat: %08x\n"
297					"#          NumberOfValues: %lu\n",
298					ai, a1->Info.AttributeFormat, a1->NumberOfValues,
299					ai, a2->Info.AttributeFormat, a2->NumberOfValues);
300			uint32 vi;
301			for (vi = 0; vi < a1->NumberOfValues; ++vi)
302			{
303				const CSSM_DATA *d1 = &a1->Value[vi];
304				const CSSM_DATA *d2 = &a2->Value[vi];
305				if (d1->Length != d2->Length || !d1->Data || !d2->Data ||
306					memcmp(d1->Data, d2->Data, d1->Length))
307					return test_ok(d1->Data == d2->Data, description,
308                        directive, reason, file, line,
309					   "#         got AttributeData[%lu].Value[%lu]:\n"
310					   "#                 length: %lu\n"
311					   "#                   data: '%.*s'\n"
312					   "#    expected AttributeData[%lu].Value[%lu]:\n"
313					   "#                 length: %lu\n"
314					   "#                   data: '%.*s'\n",
315					   ai, vi, d1->Length, (int)d1->Length, d1->Data,
316					   ai, vi, d2->Length, (int)d2->Length, d2->Data);
317			}
318		}
319	}
320	if (data1 || data2)
321	{
322		if (!data1 || !data2)
323			return test_ok(0, description, directive, reason, file, line,
324				"#                   got CSSM_DATA %p\n"
325				"#              expected CSSM_DATA %p\n", data1, data2);
326        if (data1->Length != data2->Length || !data1->Data || !data2->Data ||
327			memcmp(data1->Data, data2->Data, data1->Length))
328			return test_ok(data1->Data == data2->Data, description, directive,
329                reason, file, line,
330			   "#                   got CSSM_DATA:\n"
331			   "#                 length: %lu\n"
332			   "#                   data: '%.*s'\n"
333			   "#              expected CSSM_DATA:\n"
334			   "#                 length: %lu\n"
335			   "#                   data: '%.*s'\n",
336			   data1->Length, (int)data1->Length, data1->Data,
337			   data2->Length, (int)data2->Length, data2->Data);
338	}
339
340	return test_ok(1, description, directive, reason, file, line, NULL);
341}
342
343#define is_attributes_data(A1, D1, A2, D2, TESTNAME) \
344( \
345	test_is_attributes_data((A1), (D1), (A2), (D2), \
346		TESTNAME, test_directive, test_reason, __FILE__, __LINE__) \
347)
348
349static void test1(CSSM_DL_HANDLE dl)
350{
351    CSSM_DL_DB_HANDLE dldb = { dl };
352    CSSM_DB_UNIQUE_RECORD_PTR uniqueId;
353
354	CSSM_DATA data = { 4, (uint8 *)"test" };
355    ok_status(CSSM_DL_DbCreate(dl, DBNAME, NULL /* DbLocation */,
356                  &dbInfo,
357                  CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
358                  NULL /* CredAndAclEntry */,
359                  NULL /* &openParameters */,
360                  &dldb.DBHandle),
361        "CSSM_DL_DbCreate");
362
363    is_status(CSSM_DL_DataInsert(dldb,
364        attributes.DataRecordType,
365        &attributes,
366        &data,
367        &uniqueId),
368        CSSMERR_DL_INVALID_RECORDTYPE, "CSSM_DL_DataInsert no table");
369
370    ok_status(CSSM_DL_CreateRelation(dldb,
371        42,
372        "Fourty Two",
373        sizeof(attributeInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO),
374        attributeInfo,
375        sizeof(indexInfo) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO),
376        indexInfo), "CSSM_DL_CreateRelation");
377
378    ok_status(CSSM_DL_DataInsert(dldb,
379        attributes.DataRecordType,
380        &attributes,
381        &data,
382        &uniqueId), "CSSM_DL_DataInsert");
383
384    is_status(CSSM_DL_DataInsert(dldb,
385        attributes.DataRecordType,
386        &attributes,
387        &data,
388        &uniqueId),
389        CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA, "CSSM_DL_DataInsert dupe");
390
391    ok_status(CSSM_DL_DataModify(dldb,
392        attributes.DataRecordType,
393		uniqueId,
394        &newAttributes,
395        &data,
396        CSSM_DB_MODIFY_ATTRIBUTE_REPLACE), "CSSM_DL_DataModify");
397
398    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
399        "CSSM_DL_FreeUniqueRecord");
400
401    ok_status(CSSM_DL_DataInsert(dldb,
402        attributes.DataRecordType,
403        &attributes,
404        &data,
405        &uniqueId), "CSSM_DL_DataInsert old one again");
406
407	CSSM_API_MEMORY_FUNCS memfuncs = {};
408	ok_status(CSSM_GetAPIMemoryFunctions(dldb.DLHandle, &memfuncs),
409		"CSSM_GetAPIMemoryFunctions");
410
411    ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId, NULL, NULL),
412		"CSSM_DL_DataGetFromUniqueRecordId get nothing");
413
414	CSSM_DATA resultData = {};
415    ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
416		NULL, &resultData),
417		"CSSM_DL_DataGetFromUniqueRecordId get data");
418	is_attributes_data(NULL, &resultData, NULL, &data, "Does data match?");
419	free_attributes_data(&memfuncs, NULL, &resultData);
420
421	CSSM_DB_RECORD_ATTRIBUTE_DATA baseNoAttrs = attributes;
422	baseNoAttrs.NumberOfAttributes = 0;
423	baseNoAttrs.AttributeData = NULL;
424	CSSM_DB_RECORD_ATTRIBUTE_DATA resultNoAttrs = {};
425    ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
426		&resultNoAttrs, NULL),
427		"CSSM_DL_DataGetFromUniqueRecordId get 0 attributes");
428	is_attributes_data(&resultNoAttrs, NULL, &baseNoAttrs, NULL,
429		"Do attrs match?");
430	free_attributes_data(&memfuncs, &resultNoAttrs, NULL);
431
432    ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
433		&resultNoAttrs, &resultData),
434		"CSSM_DL_DataGetFromUniqueRecordId get data and 0 attributes");
435	is_attributes_data(&resultNoAttrs, &resultData, &baseNoAttrs, &data,
436		"Do attrs and data match?");
437	free_attributes_data(&memfuncs, &resultNoAttrs, &resultData);
438
439	CSSM_DB_ATTRIBUTE_DATA resultAttributeData[] =
440	{
441		{{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)1<<32|1) } }},
442		{{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)2<<32|2) } }}
443	};
444	CSSM_DB_RECORD_ATTRIBUTE_DATA resultAttrs =
445	{
446		0, 0,
447		sizeof(resultAttributeData) / sizeof(*resultAttributeData),
448		resultAttributeData
449	};
450    ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
451		&resultAttrs, &resultData),
452		"CSSM_DL_DataGetFromUniqueRecordId get data and 2 attributes");
453	is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
454		"Do attrs and data match?");
455	free_attributes_data(&memfuncs, &resultAttrs, &resultData);
456
457    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
458        "CSSM_DL_FreeUniqueRecord");
459
460    CSSM_SELECTION_PREDICATE predicates[] =
461    {
462        {
463            CSSM_DB_EQUAL,
464            {
465                { CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)1<<32|1) } },
466                1, values_str_1
467            }
468        }
469    };
470	CSSM_QUERY query =
471	{
472		attributes.DataRecordType,
473		CSSM_DB_AND,
474		sizeof(predicates) / sizeof(*predicates),
475		predicates,
476		{ CSSM_QUERY_TIMELIMIT_NONE, CSSM_QUERY_SIZELIMIT_NONE },
477		0 /* CSSM_QUERY_RETURN_DATA -- for keys only to return raw key bits */
478	};
479	CSSM_HANDLE search = CSSM_INVALID_HANDLE;
480    is_status(CSSM_DL_DataGetFirst(dldb, &query, NULL,
481		NULL, NULL, NULL), CSSM_ERRCODE_INVALID_POINTER,
482        "CSSM_DL_DataGetFirst no search handle, no unique_record");
483    is_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
484		NULL, NULL, NULL), CSSM_ERRCODE_INVALID_POINTER,
485        "CSSM_DL_DataGetFirst no unique_record");
486    is_status(CSSM_DL_DataGetFirst(dldb, &query, NULL,
487		NULL, NULL, &uniqueId), CSSM_ERRCODE_INVALID_POINTER,
488        "CSSM_DL_DataGetFirst no search handle");
489
490    ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
491		NULL, NULL, &uniqueId),
492        "CSSM_DL_DataGetFirst no data no attrs");
493    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
494        "CSSM_DL_FreeUniqueRecord");
495    ok_status(CSSM_DL_DataAbortQuery(dldb, search),
496        "CSSM_DL_DataAbortQuery");
497
498    ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
499		&resultNoAttrs, NULL, &uniqueId),
500        "CSSM_DL_DataGetFirst 0 attrs");
501	is_attributes_data(&resultNoAttrs, NULL, &baseNoAttrs, NULL,
502		"Do attrs match?");
503	free_attributes_data(&memfuncs, &resultNoAttrs, NULL);
504    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
505        "CSSM_DL_FreeUniqueRecord");
506    ok_status(CSSM_DL_DataAbortQuery(dldb, search),
507        "CSSM_DL_DataAbortQuery");
508
509    ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
510		NULL, &resultData, &uniqueId),
511        "CSSM_DL_DataGetFirst data");
512	is_attributes_data(NULL, &resultData, NULL, &data, "Does data match?");
513	free_attributes_data(&memfuncs, NULL, &resultData);
514    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
515        "CSSM_DL_FreeUniqueRecord");
516    ok_status(CSSM_DL_DataAbortQuery(dldb, search),
517        "CSSM_DL_DataAbortQuery");
518
519    ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
520		&resultNoAttrs, &resultData, &uniqueId),
521        "CSSM_DL_DataGetFirst 0 attrs and data");
522	is_attributes_data(&resultNoAttrs, &resultData, &baseNoAttrs, &data,
523		"Do attrs and data match?");
524	free_attributes_data(&memfuncs, &resultNoAttrs, &resultData);
525    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
526        "CSSM_DL_FreeUniqueRecord");
527    ok_status(CSSM_DL_DataAbortQuery(dldb, search),
528        "CSSM_DL_DataAbortQuery");
529
530    ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
531		&resultAttrs, &resultData, &uniqueId),
532        "CSSM_DL_DataGetFirst 2 attrs and data");
533    is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
534        "Do attrs and data match?");
535	free_attributes_data(&memfuncs, &resultAttrs, &resultData);
536    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
537        "CSSM_DL_FreeUniqueRecord");
538    ok_status(CSSM_DL_DataAbortQuery(dldb, search),
539        "CSSM_DL_DataAbortQuery");
540
541    SKIP: {
542        skip("nothing to free", 2,
543            ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
544                &resultAttrs, &resultData, &uniqueId),
545                "CSSM_DL_DataGetFirst 2 attrs and data"));
546        is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
547            "Do attrs and data match?");
548        free_attributes_data(&memfuncs, &resultAttrs, &resultData);
549        ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
550            "CSSM_DL_FreeUniqueRecord");
551    }
552
553    is_status(CSSM_DL_DataGetNext(dldb, search,
554		&resultAttrs, &resultData, &uniqueId),
555        CSSMERR_DL_ENDOFDATA, "CSSM_DL_DataGetNext returns eod");
556
557	CSSM_QUERY query2 =
558	{
559		attributes.DataRecordType,
560		CSSM_DB_NONE,
561		0,
562		NULL,
563		{ CSSM_QUERY_TIMELIMIT_NONE, CSSM_QUERY_SIZELIMIT_NONE },
564		0 /* CSSM_QUERY_RETURN_DATA -- for keys only to return raw key bits */
565	};
566    ok_status(CSSM_DL_DataGetFirst(dldb, &query2, &search,
567        &resultAttrs, &resultData, &uniqueId),
568        "CSSM_DL_DataGetFirst 2 attrs and data");
569    free_attributes_data(&memfuncs, &resultAttrs, &resultData);
570    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
571        "CSSM_DL_FreeUniqueRecord");
572    ok_status(CSSM_DL_DataGetNext(dldb, search,
573		&resultAttrs, &resultData, &uniqueId),
574        "CSSM_DL_DataGetNext 2 attrs and data");
575    free_attributes_data(&memfuncs, &resultAttrs, &resultData);
576    ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
577        "CSSM_DL_FreeUniqueRecord");
578    ok_status(CSSM_DL_DataAbortQuery(dldb, search),
579        "CSSM_DL_DataAbortQuery");
580
581    ok_status(CSSM_DL_DbClose(dldb),
582        "CSSM_DL_DbClose");
583}
584
585static void test2(CSSM_DL_HANDLE dl)
586{
587	CSSM_DL_DB_HANDLE dldb = { dl };
588	CSSM_DB_UNIQUE_RECORD_PTR uniqueId;
589
590    ok_status(CSSM_DL_DbCreate(dl, DBNAME, NULL /* DbLocation */,
591                  &dbInfo,
592                  CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
593                  NULL /* CredAndAclEntry */,
594                  NULL,
595                  &dldb.DBHandle),
596        "CSSM_DL_DbCreate");
597
598    ok_status(CSSM_DL_DbClose(dldb),
599        "CSSM_DL_DbClose");
600
601	ok_status(CSSM_DL_DbOpen(dl, DBNAME, NULL /* DbLocation */,
602                  CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
603                  NULL /* CredAndAclEntry */,
604                  &openParameters,
605                  &dldb.DBHandle),
606		"CSSM_DL_DbOpen");
607
608	is_status(CSSM_DL_DataInsert(dldb,
609		attributes.DataRecordType,
610		&attributes,
611		NULL,
612		&uniqueId),
613		CSSMERR_DL_INVALID_RECORDTYPE, "CSSM_DL_DataInsert no table");
614
615	ok_status(CSSM_DL_CreateRelation(dldb,
616		42,
617		"Fourty Two",
618		sizeof(attributeInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO),
619		attributeInfo,
620		sizeof(indexInfo) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO),
621		indexInfo), "CSSM_DL_CreateRelation");
622
623	ok_status(CSSM_DL_DataInsert(dldb,
624		attributes.DataRecordType,
625		&attributes,
626		NULL,
627		&uniqueId), "CSSM_DL_DataInsert fails unless 4039735 is fixed");
628
629	is_status(CSSM_DL_DataInsert(dldb,
630		attributes.DataRecordType,
631		&attributes,
632		NULL,
633		&uniqueId),
634		CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA,
635		"CSSM_DL_DataInsert dupe");
636
637	ok_status(CSSM_DL_DataDelete(dldb, uniqueId),
638		"CSSM_DL_Delete");
639
640	is_status(CSSM_DL_DataDelete(dldb, uniqueId),
641		CSSMERR_DL_RECORD_NOT_FOUND, "delete again should fail");
642
643	ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
644		"CSSM_DL_FreeUniqueRecord");
645
646	ok_status(CSSM_DL_DataInsert(dldb,
647		attributes.DataRecordType,
648		&attributes,
649		NULL,
650		&uniqueId), "Insert again after delete");
651
652	ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
653		"CSSM_DL_FreeUniqueRecord");
654
655	ok_status(CSSM_DL_DbClose(dldb),
656		"CSSM_DL_DbDelete");
657}
658
659int
660main(int argc, char * const *argv)
661{
662	int guid_alt = argc > 1 && !strcmp(argv[1], "-g");
663	/* {2cb56191-ee6f-432d-a377-853d3c6b949e} */
664	CSSM_GUID s3dl_guid =
665	{
666			0x2cb56191, 0xee6f, 0x432d,
667			{ 0xa3, 0x77, 0x85, 0x3d, 0x3c, 0x6b, 0x94, 0x9e }
668	};
669	const CSSM_GUID *guid = guid_alt ? & s3dl_guid : &gGuidAppleFileDL;
670
671	plan_tests(70);
672
673	CSSM_DL_HANDLE dl;
674	ok(cssm_attach(guid, &dl), "cssm_attach");
675	ok(tests_begin(argc, argv), "tests_begin");
676
677	test1(dl);
678	ok_status(CSSM_DL_DbDelete(dl, DBNAME, NULL /* DbLocation */,
679		NULL /* AccessCred */), "CSSM_DL_DbDelete");
680	test2(dl);
681	ok_status(CSSM_DL_DbDelete(dl, DBNAME, NULL /* DbLocation */,
682		NULL /* AccessCred */), "CSSM_DL_DbDelete");
683	ok(cssm_detach(guid, dl), "cssm_detach");
684	ok_leaks("no leaks");
685
686	return !tests_end(1);
687}
688