2 * Copyright (c) 2000-2001, 2003 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 // Return a newly created cursor satisfying inQuery on the receiving table
76 // The returned Cursor may or may not use indexes depending on their availability.
77 Cursor
*createCursor(const CSSM_QUERY
*inQuery
, const DbVersion
&inDbVersion
) const;
79 const ReadSection
getRecordSection(uint32 inRecordNumber
) const;
81 const RecordId
getRecord(const RecordId
&inRecordId
,
82 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
84 CssmAllocator
&inAllocator
) const;
86 // Return the number of recordNumbers in use by this table including empty slots.
87 uint32
recordNumberCount() const { return mRecordNumbersCount
; }
88 uint32
freeListHead() const { return mFreeListHead
; }
90 // Return the record number corresponding to aFreeListHead and update
91 // aFreeListHead to point to the next availble recordNumber slot.
92 uint32
popFreeList(uint32
&aFreeListHead
) const;
94 MetaRecord
&getMetaRecord() { return mMetaRecord
; }
95 const MetaRecord
&getMetaRecord() const { return mMetaRecord
; }
97 uint32
getRecordsCount() const { return mRecordsCount
; }
98 const ReadSection
getRecordsSection() const;
100 const ReadSection
&getTableSection() const { return mTableSection
; }
102 bool matchesTableId(Id inTableId
) const;
104 void readIndexSection();
108 OffsetSize
= AtomSize
* 0,
109 OffsetId
= AtomSize
* 1,
110 OffsetRecordsCount
= AtomSize
* 2,
111 OffsetRecords
= AtomSize
* 3,
112 OffsetIndexesOffset
= AtomSize
* 4,
113 OffsetFreeListHead
= AtomSize
* 5,
114 OffsetRecordNumbersCount
= AtomSize
* 6,
115 OffsetRecordNumbers
= AtomSize
* 7
118 friend class ModifiedTable
;
120 MetaRecord mMetaRecord
;
121 const ReadSection mTableSection
;
123 uint32 mRecordsCount
;
124 uint32 mFreeListHead
;
125 // Number of record numbers (including freelist slots) in this table.
126 uint32 mRecordNumbersCount
;
128 // all the table's indexes, mapped by index id
129 typedef map
<uint32
, DbConstIndex
*> ConstIndexMap
;
130 ConstIndexMap mIndexMap
;
135 NOCOPY(ModifiedTable
)
137 ModifiedTable(const Table
*inTable
);
138 ModifiedTable(MetaRecord
*inMetaRecord
); // Take over ownership of inMetaRecord
141 // Mark the record with inRecordId as deleted.
142 void deleteRecord(const RecordId
&inRecordId
);
143 const RecordId
insertRecord(uint32 inVersionId
,
144 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
145 const CssmData
*inData
);
146 const RecordId
updateRecord(const RecordId
&inRecordId
,
147 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
148 const CssmData
*inData
,
149 CSSM_DB_MODIFY_MODE inModifyMode
);
151 // Return the MetaRecord this table should use for writes.
152 const MetaRecord
&getMetaRecord() const;
154 // find, and create if needed, an index with the given id
155 DbMutableIndex
&findIndex(uint32 indexId
, const MetaRecord
&metaRecord
, bool isUniqueIndex
);
157 // Write this table to inOutputFile at inSectionOffset and return the new offset.
158 uint32
writeTable(AtomicTempFile
&inAtomicTempFile
, uint32 inSectionOffset
);
161 // Return the next available record number for this table.
162 uint32
nextRecordNumber();
164 // Return the number of recordNumbers in use by this table including empty slots.
165 uint32
recordNumberCount() const;
168 void createMutableIndexes();
169 uint32
writeIndexSection(WriteSection
&tableSection
, uint32 offset
);
171 // Optional, this is merly a reference, we do not own this object.
174 // Optional, New MetaRecord. This is only present if it is different from the
175 // MetaRecord of mTable or mTable is nil.
176 const MetaRecord
*mNewMetaRecord
;
178 // Set of Records that have been deleted or modified.
179 typedef set
<uint32
> DeletedSet
;
180 DeletedSet mDeletedSet
;
182 // Set of Records that have been inserted or modified.
183 typedef map
<uint32
, WriteSection
*> InsertedMap
;
184 InsertedMap mInsertedMap
;
186 // Next lowest available RecordNumber
187 uint32 mRecordNumberCount
;
188 // Head of the free list (if there is one) or 0 if either we have no
189 // mTable of the free list has been exhausted.
190 uint32 mFreeListHead
;
192 // has this table actually been modified?
195 typedef map
<uint32
, DbMutableIndex
*> MutableIndexMap
;
196 MutableIndexMap mIndexMap
;
200 // Read only snapshot of a database.
209 HeaderOffset
= 0, // Absolute offset of header.
210 OffsetMagic
= AtomSize
* 0,
211 OffsetVersion
= AtomSize
* 1,
212 OffsetAuthOffset
= AtomSize
* 2,
213 OffsetSchemaOffset
= AtomSize
* 3,
214 HeaderSize
= AtomSize
* 4,
216 HeaderMagic
= FOUR_CHAR_CODE('kych'),
217 HeaderVersion
= 0x00010000
222 OffsetSchemaSize
= AtomSize
* 0,
223 OffsetTablesCount
= AtomSize
* 1,
224 OffsetTables
= AtomSize
* 2
229 // Read only representation of a database
231 class DbVersion
: public Metadata
, public RefCount
235 DbVersion(const class AppleDatabase
&db
, const RefPointer
<AtomicBufferedFile
> &inAtomicBufferedFile
);
238 uint32
getVersionId() const { return mVersionId
; }
239 const RecordId
getRecord(Table::Id inTableId
, const RecordId
&inRecordId
,
240 CSSM_DB_RECORD_ATTRIBUTE_DATA
*inoutAttributes
,
241 CssmData
*inoutData
, CssmAllocator
&inAllocator
) const;
242 Cursor
*createCursor(const CSSM_QUERY
*inQuery
) const;
244 const Table
&findTable(Table::Id inTableId
) const;
245 Table
&findTable(Table::Id inTableId
);
248 void open(); // Part of constructor contract.
250 ReadSection mDatabase
;
253 friend class DbModifier
; // XXX Fixme
254 typedef map
<Table::Id
, Table
*> TableMap
;
256 const class AppleDatabase
&mDb
;
257 RefPointer
<AtomicBufferedFile
> mBufferedFile
;
260 typedef Table value_type
;
261 typedef const Table
&const_reference
;
262 typedef const Table
*const_pointer
;
264 // A const forward iterator.
268 const_iterator(const TableMap::const_iterator
&it
) : mIterator(it
) {}
270 // Use default copy consturctor and assignment operator.
271 //const_iterator(const const_iterator &it) : mIterator(it.mIterator) {}
272 //const_iterator &operator=(const const_iterator &it) { mIterator = it.mIterator; return *this; }
273 const_reference
operator*() const { return *mIterator
->second
; }
274 const_iterator
&operator++() { mIterator
.operator++(); return *this; }
275 const_iterator
operator++(int i
) { return const_iterator(mIterator
.operator++(i
)); }
276 bool operator!=(const const_iterator
&other
) const { return mIterator
!= other
.mIterator
; }
277 bool operator==(const const_iterator
&other
) const { return mIterator
== other
.mIterator
; }
279 const_pointer
operator->() const { return mIterator
->second
; } // Not really needed.
282 TableMap::const_iterator mIterator
;
285 const_iterator
begin() const { return const_iterator(mTableMap
.begin()); }
286 const_iterator
end() const { return const_iterator(mTableMap
.end()); }
292 class Cursor
: public HandleObject
296 virtual bool next(Table::Id
&outTableId
,
297 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
299 CssmAllocator
&inAllocator
,
300 RecordId
&recordId
) = 0;
306 class LinearCursor
: public Cursor
310 LinearCursor(const CSSM_QUERY
*inQuery
, const DbVersion
&inDbVersion
,
311 const Table
&inTable
);
312 virtual ~LinearCursor();
313 virtual bool next(Table::Id
&outTableId
,
314 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
316 CssmAllocator
&inAllocator
,
320 const RefPointer
<const DbVersion
> mDbVersion
;
321 uint32 mRecordsCount
;
323 const ReadSection mRecordsSection
;
325 const MetaRecord
&mMetaRecord
;
327 CSSM_DB_CONJUNCTIVE mConjunctive
;
328 CSSM_QUERY_FLAGS mQueryFlags
; // If CSSM_QUERY_RETURN_DATA is set return the raw key bits;
329 typedef vector
<SelectionPredicate
*> PredicateVector
;
331 PredicateVector mPredicates
;
335 // A cursor that uses an index.
338 class IndexCursor
: public Cursor
342 IndexCursor(DbQueryKey
*queryKey
, const DbVersion
&inDbVersion
,
343 const Table
&table
, const DbConstIndex
*index
);
344 virtual ~IndexCursor();
346 virtual bool next(Table::Id
&outTableId
,
347 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
349 CssmAllocator
&inAllocator
,
353 auto_ptr
<DbQueryKey
> mQueryKey
;
354 const DbVersion
&mDbVersion
;
356 const DbConstIndex
*mIndex
;
358 DbIndexIterator mBegin
, mEnd
;
364 class MultiCursor
: public Cursor
368 MultiCursor(const CSSM_QUERY
*inQuery
, const DbVersion
&inDbVersion
);
369 virtual ~MultiCursor();
370 virtual bool next(Table::Id
&outTableId
,
371 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
373 CssmAllocator
&inAllocator
,
376 const RefPointer
<const DbVersion
> mDbVersion
;
377 auto_ptr
<CssmAutoQuery
> mQuery
;
379 DbVersion::const_iterator mTableIterator
;
380 auto_ptr
<Cursor
> mCursor
;
384 // A DbModifier contains all pending changes to be made to a DB.
385 // It also contains a DbVersion representing the state of the Database before any such changes
386 // No read-style operations are supported by DbModifier. If a DbModifier exists for a
387 // particular Database and a client wishes to perform a query commit() must be called and
388 // the client should perform the new query on the current database version after the commit.
389 // Otherwise a client will not see changes made since the DbModifier was instanciated.
391 class DbModifier
: public Metadata
395 DbModifier(AtomicFile
&inAtomicFile
, const class AppleDatabase
&db
);
398 // Whole database affecting members.
399 void createDatabase(const CSSM_DBINFO
&inDbInfo
,
400 const CSSM_ACL_ENTRY_INPUT
*inInitialAclEntry
,
402 void openDatabase(); // This is optional right now.
403 void closeDatabase();
404 void deleteDatabase();
407 void rollback() throw();
409 // Record changing members
410 void deleteRecord(Table::Id inTableId
, const RecordId
&inRecordId
);
411 const RecordId
insertRecord(Table::Id inTableId
,
412 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
413 const CssmData
*inData
);
414 const RecordId
updateRecord(Table::Id inTableId
, const RecordId
&inRecordId
,
415 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
416 const CssmData
*inData
,
417 CSSM_DB_MODIFY_MODE inModifyMode
);
419 // Schema changing members
420 void insertTable(Table::Id inTableId
, const string
&inTableName
,
421 uint32 inNumberOfAttributes
,
422 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
*inAttributeInfo
,
423 uint32 inNumberOfIndexes
,
424 const CSSM_DB_SCHEMA_INDEX_INFO
*inIndexInfo
);
425 void deleteTable(Table::Id inTableId
);
427 // Record reading members
428 const RecordId
getRecord(Table::Id inTableId
, const RecordId
&inRecordId
,
429 CSSM_DB_RECORD_ATTRIBUTE_DATA
*inoutAttributes
,
430 CssmData
*inoutData
, CssmAllocator
&inAllocator
);
431 Cursor
*createCursor(const CSSM_QUERY
*inQuery
);
433 void modifyDatabase();
434 const RefPointer
<const DbVersion
> getDbVersion();
436 ModifiedTable
*createTable(MetaRecord
*inMetaRecord
); // Takes over ownership of inMetaRecord
438 void insertTableSchema(const CssmDbRecordAttributeInfo
&inInfo
,
439 const CSSM_DB_RECORD_INDEX_INFO
*inIndexInfo
= NULL
);
441 void insertTable(const CssmDbRecordAttributeInfo
&inInfo
,
442 const CSSM_DB_RECORD_INDEX_INFO
* inIndexInfo
= NULL
,
443 const CSSM_DB_PARSING_MODULE_INFO
* inParsingModule
= NULL
);
445 ModifiedTable
&findTable(Table::Id inTableId
);
447 uint32
writeAuthSection(uint32 inSectionOffset
);
448 uint32
writeSchemaSection(uint32 inSectionOffset
);
452 // Current DbVersion of this database before any changes we are going to make.
453 RefPointer
<const DbVersion
> mDbVersion
;
454 Mutex mDbVersionLock
;
456 AtomicFile
&mAtomicFile
;
458 RefPointer
<AtomicTempFile
> mAtomicTempFile
;
460 typedef map
<Table::Id
, ModifiedTable
*> ModifiedTableMap
;
461 ModifiedTableMap mModifiedTableMap
;
463 const class AppleDatabase
&mDb
;
467 // AppleDatabaseManager
469 class AppleDatabaseManager
: public DatabaseManager
472 AppleDatabaseManager(const AppleDatabaseTableName
*tableNames
);
473 Database
*make(const DbName
&inDbName
);
476 const AppleDatabaseTableName
*mTableNames
;
482 class AppleDbContext
: public DbContext
485 AppleDbContext(Database
&inDatabase
,
486 DatabaseSession
&inDatabaseSession
,
487 CSSM_DB_ACCESS_TYPE inAccessRequest
,
488 const AccessCredentials
*inAccessCred
,
489 const void *inOpenParameters
);
490 virtual ~AppleDbContext();
491 bool autoCommit() const { return mAutoCommit
; }
492 void autoCommit(bool on
) { mAutoCommit
= on
; }
493 mode_t
mode() const { return mMode
; }
503 class AppleDatabase
: public Database
506 AppleDatabase(const DbName
&inDbName
, const AppleDatabaseTableName
*tableNames
);
507 virtual ~AppleDatabase();
510 dbCreate(DbContext
&inDbContext
, const CSSM_DBINFO
&inDBInfo
,
511 const CSSM_ACL_ENTRY_INPUT
*inInitialAclEntry
);
514 dbOpen(DbContext
&inDbContext
);
520 dbDelete(DatabaseSession
&inDatabaseSession
,
521 const AccessCredentials
*inAccessCred
);
524 createRelation(DbContext
&inDbContext
,
525 CSSM_DB_RECORDTYPE inRelationID
,
526 const char *inRelationName
,
527 uint32 inNumberOfAttributes
,
528 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
&inAttributeInfo
,
529 uint32 inNumberOfIndexes
,
530 const CSSM_DB_SCHEMA_INDEX_INFO
&inIndexInfo
);
533 destroyRelation(DbContext
&inDbContext
,
534 CSSM_DB_RECORDTYPE inRelationID
);
537 authenticate(DbContext
&inDbContext
,
538 CSSM_DB_ACCESS_TYPE inAccessRequest
,
539 const AccessCredentials
&inAccessCred
);
542 getDbAcl(DbContext
&inDbContext
,
543 const CSSM_STRING
*inSelectionTag
,
544 uint32
&outNumberOfAclInfos
,
545 CSSM_ACL_ENTRY_INFO_PTR
&outAclInfos
);
548 changeDbAcl(DbContext
&inDbContext
,
549 const AccessCredentials
&inAccessCred
,
550 const CSSM_ACL_EDIT
&inAclEdit
);
553 getDbOwner(DbContext
&inDbContext
, CSSM_ACL_OWNER_PROTOTYPE
&outOwner
);
556 changeDbOwner(DbContext
&inDbContext
,
557 const AccessCredentials
&inAccessCred
,
558 const CSSM_ACL_OWNER_PROTOTYPE
&inNewOwner
);
561 getDbNameFromHandle(const DbContext
&inDbContext
) const;
563 virtual CSSM_DB_UNIQUE_RECORD_PTR
564 dataInsert(DbContext
&inDbContext
,
565 CSSM_DB_RECORDTYPE RecordType
,
566 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
567 const CssmData
*inData
);
570 dataDelete(DbContext
&inDbContext
,
571 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
);
574 dataModify(DbContext
&inDbContext
,
575 CSSM_DB_RECORDTYPE inRecordType
,
576 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecordIdentifier
,
577 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributesToBeModified
,
578 const CssmData
*inDataToBeModified
,
579 CSSM_DB_MODIFY_MODE inModifyMode
);
582 dataGetFirst(DbContext
&inDbContext
,
583 const DLQuery
*inQuery
,
584 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
586 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
);
589 dataGetNext(DbContext
&inDbContext
,
590 CSSM_HANDLE inResultsHandle
,
591 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
593 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
);
596 dataAbortQuery(DbContext
&inDbContext
,
597 CSSM_HANDLE inResultsHandle
);
600 dataGetFromUniqueRecordId(DbContext
&inDbContext
,
601 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
602 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
603 CssmData
*inoutData
);
606 freeUniqueRecord(DbContext
&inDbContext
,
607 CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
);
609 virtual void passThrough(DbContext
&dbContext
,
610 uint32 passThroughId
,
611 const void *inputParams
,
612 void **outputParams
);
614 // Subclasses must implement this method.
615 virtual DbContext
*makeDbContext(DatabaseSession
&inDatabaseSession
,
616 CSSM_DB_ACCESS_TYPE inAccessRequest
,
617 const AccessCredentials
*inAccessCred
,
618 const void *inOpenParameters
);
620 const CssmDbRecordAttributeInfo schemaRelations
;
621 const CssmDbRecordAttributeInfo schemaAttributes
;
622 const CssmDbRecordAttributeInfo schemaIndexes
;
623 const CssmDbRecordAttributeInfo schemaParsingModule
;
625 const char *recordName(CSSM_DB_RECORDTYPE inRecordType
) const;
629 AppleDatabase::updateUniqueRecord(DbContext
&inDbContext
,
630 CSSM_DB_RECORDTYPE inTableId
,
631 const RecordId
&inRecordId
,
632 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecord
);
634 CSSM_DB_UNIQUE_RECORD_PTR
635 createUniqueRecord(DbContext
&inDbContext
, CSSM_DB_RECORDTYPE inTableId
,
636 const RecordId
&inRecordId
);
637 const RecordId
parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
638 CSSM_DB_RECORDTYPE
&outTableId
);
641 AtomicFile mAtomicFile
;
642 DbModifier mDbModifier
;
643 const AppleDatabaseTableName
*mTableNames
;
646 } // end namespace Security
648 #endif //_H_APPLEDATABASE