2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // AppleDatabase.h - Description t.b.d.
22 #ifndef _H_APPLEDATABASE
23 #define _H_APPLEDATABASE
25 #include "MetaRecord.h"
26 #include "SelectionPredicate.h"
29 #include <Security/AtomicFile.h>
30 #include <Security/Database.h>
31 #include <Security/DbContext.h>
32 #include <Security/handleobject.h>
33 #include <Security/refcount.h>
40 // Abstract database Cursor class.
45 struct AppleDatabaseTableName
48 const char *mTableName
;
50 // indices of meta-table entries in an array of table names
57 kNumRequiredTableNames
62 // This is what the CDSA standard refers to as a Relation. We use
63 // the more conventional term Table.
69 // Type used to refer to a table.
70 typedef CSSM_DB_RECORDTYPE Id
;
72 Table(const ReadSection
&inTableSection
);
75 Table(const CSSM_DB_RECORD_ATTRIBUTE_INFO
&inInfo
) :
76 mMetaRecord (inInfo
) {}
77 Table(Id inTableId
, const string
&inTableName
,
78 uint32 inNumberOfAttributes
,
79 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
*inAttributeInfo
,
80 uint32 inNumberOfIndexes
,
81 const CSSM_DB_SCHEMA_INDEX_INFO
*inIndexInfo
) :
82 mMetaRecord(inTableId
, inTableName
,
83 inNumberOfAttributes
, inAttributeInfo
)
84 { /* XXX Use inIndexInfo */ }
87 // Return a newly created cursor satisfying inQuery on the receiving table
88 // The returned Cursor may or may not use indexes depending on their availability.
89 Cursor
*createCursor(const CSSM_QUERY
*inQuery
, const DbVersion
&inDbVersion
) const;
91 const ReadSection
getRecordSection(uint32 inRecordNumber
) const;
93 const RecordId
getRecord(const RecordId
&inRecordId
,
94 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
96 CssmAllocator
&inAllocator
) const;
98 // Return the number of recordNumbers in use by this table including empty slots.
99 uint32
recordNumberCount() const { return mRecordNumbersCount
; }
100 uint32
freeListHead() const { return mFreeListHead
; }
102 // Return the record number corresponding to aFreeListHead and update
103 // aFreeListHead to point to the next availble recordNumber slot.
104 uint32
popFreeList(uint32
&aFreeListHead
) const;
106 MetaRecord
&getMetaRecord() { return mMetaRecord
; }
107 const MetaRecord
&getMetaRecord() const { return mMetaRecord
; }
109 uint32
getRecordsCount() const { return mRecordsCount
; }
110 const ReadSection
getRecordsSection() const;
112 const ReadSection
&getTableSection() const { return mTableSection
; }
114 bool matchesTableId(Id inTableId
) const;
116 void readIndexSection();
120 OffsetSize
= AtomSize
* 0,
121 OffsetId
= AtomSize
* 1,
122 OffsetRecordsCount
= AtomSize
* 2,
123 OffsetRecords
= AtomSize
* 3,
124 OffsetIndexesOffset
= AtomSize
* 4,
125 OffsetFreeListHead
= AtomSize
* 5,
126 OffsetRecordNumbersCount
= AtomSize
* 6,
127 OffsetRecordNumbers
= AtomSize
* 7
130 friend class ModifiedTable
;
132 MetaRecord mMetaRecord
;
133 const ReadSection mTableSection
;
135 uint32 mRecordsCount
;
136 uint32 mFreeListHead
;
137 // Number of record numbers (including freelist slots) in this table.
138 uint32 mRecordNumbersCount
;
140 // all the table's indexes, mapped by index id
141 typedef map
<uint32
, DbConstIndex
*> ConstIndexMap
;
142 ConstIndexMap mIndexMap
;
147 NOCOPY(ModifiedTable
)
149 ModifiedTable(const Table
*inTable
);
150 ModifiedTable(MetaRecord
*inMetaRecord
); // Take over ownership of inMetaRecord
153 // Mark the record with inRecordId as deleted.
154 void deleteRecord(const RecordId
&inRecordId
);
155 const RecordId
insertRecord(AtomicFile::VersionId inVersionId
,
156 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
157 const CssmData
*inData
);
158 const RecordId
updateRecord(const RecordId
&inRecordId
,
159 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
160 const CssmData
*inData
,
161 CSSM_DB_MODIFY_MODE inModifyMode
);
163 // Return the MetaRecord this table should use for writes.
164 const MetaRecord
&getMetaRecord() const;
166 // find, and create if needed, an index with the given id
167 DbMutableIndex
&findIndex(uint32 indexId
, const MetaRecord
&metaRecord
, bool isUniqueIndex
);
169 // Write this table to inOutputFile at inSectionOffset and return the new offset.
170 uint32
writeTable(AtomicFile
&inOutputFile
, uint32 inSectionOffset
);
173 // Return the next available record number for this table.
174 uint32
nextRecordNumber();
176 // Return the number of recordNumbers in use by this table including empty slots.
177 uint32
recordNumberCount() const;
180 void createMutableIndexes();
181 uint32
writeIndexSection(WriteSection
&tableSection
, uint32 offset
);
183 // Optional, this is merly a reference, we do not own this object.
186 // Optional, New MetaRecord. This is only present if it is different from the
187 // MetaRecord of mTable or mTable is nil.
188 const MetaRecord
*mNewMetaRecord
;
190 // Set of Records that have been deleted or modified.
191 typedef set
<uint32
> DeletedSet
;
192 DeletedSet mDeletedSet
;
194 // Set of Records that have been inserted or modified.
195 typedef map
<uint32
, WriteSection
*> InsertedMap
;
196 InsertedMap mInsertedMap
;
198 // Next lowest available RecordNumber
199 uint32 mRecordNumberCount
;
200 // Head of the free list (if there is one) or 0 if either we have no
201 // mTable of the free list has been exhausted.
202 uint32 mFreeListHead
;
204 // has this table actually been modified?
207 typedef map
<uint32
, DbMutableIndex
*> MutableIndexMap
;
208 MutableIndexMap mIndexMap
;
212 // Read only snapshot of a database.
221 HeaderOffset
= 0, // Absolute offset of header.
222 OffsetMagic
= AtomSize
* 0,
223 OffsetVersion
= AtomSize
* 1,
224 OffsetAuthOffset
= AtomSize
* 2,
225 OffsetSchemaOffset
= AtomSize
* 3,
226 HeaderSize
= AtomSize
* 4,
228 HeaderMagic
= FOUR_CHAR_CODE('kych'),
229 HeaderVersion
= 0x00010000
234 OffsetSchemaSize
= AtomSize
* 0,
235 OffsetTablesCount
= AtomSize
* 1,
236 OffsetTables
= AtomSize
* 2
241 // Read only representation of a database
243 class DbVersion
: public Metadata
, public RefCount
247 DbVersion(AtomicFile
&inDatabaseFile
, const class AppleDatabase
&db
);
250 // Return true if the file on which this DbVersion is based
251 // has been modified.
252 bool isDirty() const;
254 AtomicFile::VersionId
getVersionId() const { return mVersionId
; }
255 const RecordId
getRecord(Table::Id inTableId
, const RecordId
&inRecordId
,
256 CSSM_DB_RECORD_ATTRIBUTE_DATA
*inoutAttributes
,
257 CssmData
*inoutData
, CssmAllocator
&inAllocator
) const;
258 Cursor
*createCursor(const CSSM_QUERY
*inQuery
) const;
260 const Table
&findTable(Table::Id inTableId
) const;
261 Table
&findTable(Table::Id inTableId
);
264 void open(); // Part of constructor contract.
266 ReadSection mDatabase
;
267 AtomicFile
*mDatabaseFile
;
268 AtomicFile::VersionId mVersionId
;
270 friend class DbModifier
; // XXX Fixme
271 typedef map
<Table::Id
, Table
*> TableMap
;
273 const class AppleDatabase
&mDb
;
276 typedef Table value_type
;
277 typedef const Table
&const_reference
;
278 typedef const Table
*const_pointer
;
280 // A const forward iterator.
284 const_iterator(const TableMap::const_iterator
&it
) : mIterator(it
) {}
286 // Use default copy consturctor and assignment operator.
287 //const_iterator(const const_iterator &it) : mIterator(it.mIterator) {}
288 //const_iterator &operator=(const const_iterator &it) { mIterator = it.mIterator; return *this; }
289 const_reference
operator*() const { return *mIterator
->second
; }
290 const_iterator
&operator++() { mIterator
.operator++(); return *this; }
291 const_iterator
operator++(int i
) { return const_iterator(mIterator
.operator++(i
)); }
292 bool operator!=(const const_iterator
&other
) const { return mIterator
!= other
.mIterator
; }
293 bool operator==(const const_iterator
&other
) const { return mIterator
== other
.mIterator
; }
295 const_pointer
operator->() const { return mIterator
->second
; } // Not really needed.
298 TableMap::const_iterator mIterator
;
301 const_iterator
begin() const { return const_iterator(mTableMap
.begin()); }
302 const_iterator
end() const { return const_iterator(mTableMap
.end()); }
308 class Cursor
: public HandleObject
312 virtual bool next(Table::Id
&outTableId
,
313 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
315 CssmAllocator
&inAllocator
,
316 RecordId
&recordId
) = 0;
322 class LinearCursor
: public Cursor
326 LinearCursor(const CSSM_QUERY
*inQuery
, const DbVersion
&inDbVersion
,
327 const Table
&inTable
);
328 virtual ~LinearCursor();
329 virtual bool next(Table::Id
&outTableId
,
330 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
332 CssmAllocator
&inAllocator
,
336 const RefPointer
<const DbVersion
> mDbVersion
;
337 uint32 mRecordsCount
;
339 const ReadSection mRecordsSection
;
341 const MetaRecord
&mMetaRecord
;
343 CSSM_DB_CONJUNCTIVE mConjunctive
;
344 CSSM_QUERY_FLAGS mQueryFlags
; // If CSSM_QUERY_RETURN_DATA is set return the raw key bits;
345 typedef vector
<SelectionPredicate
*> PredicateVector
;
347 PredicateVector mPredicates
;
351 // A cursor that uses an index.
354 class IndexCursor
: public Cursor
358 IndexCursor(DbQueryKey
*queryKey
, const DbVersion
&inDbVersion
,
359 const Table
&table
, const DbConstIndex
*index
);
360 virtual ~IndexCursor();
362 virtual bool next(Table::Id
&outTableId
,
363 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
365 CssmAllocator
&inAllocator
,
369 auto_ptr
<DbQueryKey
> mQueryKey
;
370 const DbVersion
&mDbVersion
;
372 const DbConstIndex
*mIndex
;
374 DbIndexIterator mBegin
, mEnd
;
380 class MultiCursor
: public Cursor
384 MultiCursor(const CSSM_QUERY
*inQuery
, const DbVersion
&inDbVersion
);
385 virtual ~MultiCursor();
386 virtual bool next(Table::Id
&outTableId
,
387 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
389 CssmAllocator
&inAllocator
,
392 const RefPointer
<const DbVersion
> mDbVersion
;
393 auto_ptr
<CssmAutoQuery
> mQuery
;
395 DbVersion::const_iterator mTableIterator
;
396 auto_ptr
<Cursor
> mCursor
;
400 // A DbModifier contains all pending changes to be made to a DB.
401 // It also contains a DbVersion representing the state of the Database before any such changes
402 // No read-style operations are supported by DbModifier. If a DbModifier exists for a
403 // particular Database and a client wishes to perform a query commit() must be called and
404 // the client should perform the new query on the current database version after the commit.
405 // Otherwise a client will not see changes made since the DbModifier was instanciated.
407 class DbModifier
: public Metadata
411 DbModifier(AtomicFile
&inAtomicFile
, const class AppleDatabase
&db
);
414 // Whole database affecting members.
415 void createDatabase(const CSSM_DBINFO
&inDbInfo
,
416 const CSSM_ACL_ENTRY_INPUT
*inInitialAclEntry
);
417 void openDatabase(); // This is optional right now.
418 void closeDatabase();
419 void deleteDatabase();
424 // Record changing members
425 void deleteRecord(Table::Id inTableId
, const RecordId
&inRecordId
);
426 const RecordId
insertRecord(Table::Id inTableId
,
427 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
428 const CssmData
*inData
);
429 const RecordId
updateRecord(Table::Id inTableId
, const RecordId
&inRecordId
,
430 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
431 const CssmData
*inData
,
432 CSSM_DB_MODIFY_MODE inModifyMode
);
434 // Schema changing members
435 void insertTable(Table::Id inTableId
, const string
&inTableName
,
436 uint32 inNumberOfAttributes
,
437 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
*inAttributeInfo
,
438 uint32 inNumberOfIndexes
,
439 const CSSM_DB_SCHEMA_INDEX_INFO
*inIndexInfo
);
440 void deleteTable(Table::Id inTableId
);
442 // Record reading members
443 const RecordId
getRecord(Table::Id inTableId
, const RecordId
&inRecordId
,
444 CSSM_DB_RECORD_ATTRIBUTE_DATA
*inoutAttributes
,
445 CssmData
*inoutData
, CssmAllocator
&inAllocator
);
446 Cursor
*createCursor(const CSSM_QUERY
*inQuery
);
448 void modifyDatabase();
449 const RefPointer
<const DbVersion
> getDbVersion();
451 ModifiedTable
*createTable(MetaRecord
*inMetaRecord
); // Takes over ownership of inMetaRecord
453 void insertTableSchema(const CssmDbRecordAttributeInfo
&inInfo
,
454 const CSSM_DB_RECORD_INDEX_INFO
*inIndexInfo
= NULL
);
456 void insertTable(const CssmDbRecordAttributeInfo
&inInfo
,
457 const CSSM_DB_RECORD_INDEX_INFO
* inIndexInfo
= NULL
,
458 const CSSM_DB_PARSING_MODULE_INFO
* inParsingModule
= NULL
);
460 ModifiedTable
&findTable(Table::Id inTableId
);
462 uint32
writeAuthSection(uint32 inSectionOffset
);
463 uint32
writeSchemaSection(uint32 inSectionOffset
);
467 // Current DbVersion of this database before any changes we are going to make.
468 RefPointer
<const DbVersion
> mDbVersion
;
469 Mutex mDbVersionLock
;
471 AtomicFile
&mAtomicFile
;
472 AtomicFile::VersionId mVersionId
;
473 AtomicFile::FileRef mFileRef
;
476 typedef map
<Table::Id
, ModifiedTable
*> ModifiedTableMap
;
477 ModifiedTableMap mModifiedTableMap
;
479 const class AppleDatabase
&mDb
;
483 // AppleDatabaseManager
485 class AppleDatabaseManager
: public DatabaseManager
488 AppleDatabaseManager(const AppleDatabaseTableName
*tableNames
);
489 Database
*make(const DbName
&inDbName
);
492 const AppleDatabaseTableName
*mTableNames
;
498 class AppleDbContext
: public DbContext
501 AppleDbContext(Database
&inDatabase
,
502 DatabaseSession
&inDatabaseSession
,
503 CSSM_DB_ACCESS_TYPE inAccessRequest
,
504 const AccessCredentials
*inAccessCred
,
505 const void *inOpenParameters
);
506 virtual ~AppleDbContext();
507 bool autoCommit() const { return mAutoCommit
; }
508 void autoCommit(bool on
) { mAutoCommit
= on
; }
517 class AppleDatabase
: public Database
520 AppleDatabase(const DbName
&inDbName
, const AppleDatabaseTableName
*tableNames
);
521 virtual ~AppleDatabase();
524 dbCreate(DbContext
&inDbContext
, const CSSM_DBINFO
&inDBInfo
,
525 const CSSM_ACL_ENTRY_INPUT
*inInitialAclEntry
);
528 dbOpen(DbContext
&inDbContext
);
534 dbDelete(DatabaseSession
&inDatabaseSession
,
535 const AccessCredentials
*inAccessCred
);
538 createRelation(DbContext
&inDbContext
,
539 CSSM_DB_RECORDTYPE inRelationID
,
540 const char *inRelationName
,
541 uint32 inNumberOfAttributes
,
542 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
&inAttributeInfo
,
543 uint32 inNumberOfIndexes
,
544 const CSSM_DB_SCHEMA_INDEX_INFO
&inIndexInfo
);
547 destroyRelation(DbContext
&inDbContext
,
548 CSSM_DB_RECORDTYPE inRelationID
);
551 authenticate(DbContext
&inDbContext
,
552 CSSM_DB_ACCESS_TYPE inAccessRequest
,
553 const AccessCredentials
&inAccessCred
);
556 getDbAcl(DbContext
&inDbContext
,
557 const CSSM_STRING
*inSelectionTag
,
558 uint32
&outNumberOfAclInfos
,
559 CSSM_ACL_ENTRY_INFO_PTR
&outAclInfos
);
562 changeDbAcl(DbContext
&inDbContext
,
563 const AccessCredentials
&inAccessCred
,
564 const CSSM_ACL_EDIT
&inAclEdit
);
567 getDbOwner(DbContext
&inDbContext
, CSSM_ACL_OWNER_PROTOTYPE
&outOwner
);
570 changeDbOwner(DbContext
&inDbContext
,
571 const AccessCredentials
&inAccessCred
,
572 const CSSM_ACL_OWNER_PROTOTYPE
&inNewOwner
);
575 getDbNameFromHandle(const DbContext
&inDbContext
) const;
577 virtual CSSM_DB_UNIQUE_RECORD_PTR
578 dataInsert(DbContext
&inDbContext
,
579 CSSM_DB_RECORDTYPE RecordType
,
580 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
581 const CssmData
*inData
);
584 dataDelete(DbContext
&inDbContext
,
585 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
);
588 dataModify(DbContext
&inDbContext
,
589 CSSM_DB_RECORDTYPE inRecordType
,
590 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecordIdentifier
,
591 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributesToBeModified
,
592 const CssmData
*inDataToBeModified
,
593 CSSM_DB_MODIFY_MODE inModifyMode
);
596 dataGetFirst(DbContext
&inDbContext
,
597 const DLQuery
*inQuery
,
598 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
600 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
);
603 dataGetNext(DbContext
&inDbContext
,
604 CSSM_HANDLE inResultsHandle
,
605 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
607 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
);
610 dataAbortQuery(DbContext
&inDbContext
,
611 CSSM_HANDLE inResultsHandle
);
614 dataGetFromUniqueRecordId(DbContext
&inDbContext
,
615 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
616 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
617 CssmData
*inoutData
);
620 freeUniqueRecord(DbContext
&inDbContext
,
621 CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
);
623 virtual void passThrough(DbContext
&dbContext
,
624 uint32 passThroughId
,
625 const void *inputParams
,
626 void **outputParams
);
628 // Subclasses must implement this method.
629 virtual DbContext
*makeDbContext(DatabaseSession
&inDatabaseSession
,
630 CSSM_DB_ACCESS_TYPE inAccessRequest
,
631 const AccessCredentials
*inAccessCred
,
632 const void *inOpenParameters
);
634 const CssmDbRecordAttributeInfo schemaRelations
;
635 const CssmDbRecordAttributeInfo schemaAttributes
;
636 const CssmDbRecordAttributeInfo schemaIndexes
;
637 const CssmDbRecordAttributeInfo schemaParsingModule
;
639 const char *recordName(CSSM_DB_RECORDTYPE inRecordType
) const;
643 AppleDatabase::updateUniqueRecord(DbContext
&inDbContext
,
644 CSSM_DB_RECORDTYPE inTableId
,
645 const RecordId
&inRecordId
,
646 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecord
);
648 CSSM_DB_UNIQUE_RECORD_PTR
649 createUniqueRecord(DbContext
&inDbContext
, CSSM_DB_RECORDTYPE inTableId
,
650 const RecordId
&inRecordId
);
651 const RecordId
parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
652 CSSM_DB_RECORDTYPE
&outTableId
);
655 AtomicFile mAtomicFile
;
656 DbModifier mDbModifier
;
657 const AppleDatabaseTableName
*mTableNames
;
660 } // end namespace Security
662 #endif //_H_APPLEDATABASE