--- /dev/null
+/*
+ * Copyright (c) 2000-2001, 2003 Apple Computer, Inc. All Rights Reserved.
+ *
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please obtain
+ * a copy of the License at http://www.apple.com/publicsource and read it before
+ * using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+ * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+ * specific language governing rights and limitations under the License.
+ */
+
+
+//
+// AppleDatabase.h - Description t.b.d.
+//
+#ifndef _H_APPLEDATABASE
+#define _H_APPLEDATABASE
+
+#include "MetaRecord.h"
+#include "SelectionPredicate.h"
+#include "DbIndex.h"
+
+#include <security_filedb/AtomicFile.h>
+#include <security_cdsa_plugin/Database.h>
+#include <security_cdsa_plugin/DbContext.h>
+#include <security_cdsa_utilities/handleobject.h>
+#include <security_utilities/refcount.h>
+#include <memory>
+#include <vector>
+#include <CoreFoundation/CFDate.h>
+
+namespace Security
+{
+
+// Abstract database Cursor class.
+class Cursor;
+class DbVersion;
+class CssmAutoQuery;
+
+struct AppleDatabaseTableName
+{
+ uint32 mTableId;
+ const char *mTableName;
+
+ // indices of meta-table entries in an array of table names
+
+ enum {
+ kSchemaInfo = 0,
+ kSchemaAttributes,
+ kSchemaIndexes,
+ kSchemaParsingModule,
+ kNumRequiredTableNames
+ };
+};
+
+//
+// This is what the CDSA standard refers to as a Relation. We use
+// the more conventional term Table.
+//
+class Table
+{
+ NOCOPY(Table)
+public:
+ // Type used to refer to a table.
+ typedef CSSM_DB_RECORDTYPE Id;
+
+ Table(const ReadSection &inTableSection);
+ ~Table();
+
+ // Return a newly created cursor satisfying inQuery on the receiving table
+ // The returned Cursor may or may not use indexes depending on their availability.
+ Cursor *createCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion) const;
+
+ const ReadSection getRecordSection(uint32 inRecordNumber) const;
+
+ const RecordId getRecord(const RecordId &inRecordId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
+ CssmData *inoutData,
+ Allocator &inAllocator) const;
+
+ // Return the number of recordNumbers in use by this table including empty slots.
+ uint32 recordNumberCount() const { return mRecordNumbersCount; }
+ uint32 freeListHead() const { return mFreeListHead; }
+
+ // Return the record number corresponding to aFreeListHead and update
+ // aFreeListHead to point to the next availble recordNumber slot.
+ uint32 popFreeList(uint32 &aFreeListHead) const;
+
+ MetaRecord &getMetaRecord() { return mMetaRecord; }
+ const MetaRecord &getMetaRecord() const { return mMetaRecord; }
+
+ uint32 getRecordsCount() const { return mRecordsCount; }
+ const ReadSection getRecordsSection() const;
+
+ const ReadSection &getTableSection() const { return mTableSection; }
+
+ bool matchesTableId(Id inTableId) const;
+
+ void readIndexSection();
+
+ enum
+ {
+ OffsetSize = AtomSize * 0,
+ OffsetId = AtomSize * 1,
+ OffsetRecordsCount = AtomSize * 2,
+ OffsetRecords = AtomSize * 3,
+ OffsetIndexesOffset = AtomSize * 4,
+ OffsetFreeListHead = AtomSize * 5,
+ OffsetRecordNumbersCount = AtomSize * 6,
+ OffsetRecordNumbers = AtomSize * 7
+ };
+protected:
+ friend class ModifiedTable;
+
+ MetaRecord mMetaRecord;
+ const ReadSection mTableSection;
+
+ uint32 mRecordsCount;
+ uint32 mFreeListHead;
+ // Number of record numbers (including freelist slots) in this table.
+ uint32 mRecordNumbersCount;
+
+ // all the table's indexes, mapped by index id
+ typedef map<uint32, DbConstIndex *> ConstIndexMap;
+ ConstIndexMap mIndexMap;
+};
+
+class ModifiedTable
+{
+ NOCOPY(ModifiedTable)
+public:
+ ModifiedTable(const Table *inTable);
+ ModifiedTable(MetaRecord *inMetaRecord); // Take over ownership of inMetaRecord
+ ~ModifiedTable();
+
+ // Mark the record with inRecordId as deleted.
+ void deleteRecord(const RecordId &inRecordId);
+ const RecordId insertRecord(uint32 inVersionId,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
+ const CssmData *inData);
+ const RecordId updateRecord(const RecordId &inRecordId,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
+ const CssmData *inData,
+ CSSM_DB_MODIFY_MODE inModifyMode);
+ const RecordId getRecord(const RecordId &inRecordId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
+ CssmData *inoutData,
+ Allocator &inAllocator) const;
+
+ // Return the MetaRecord this table should use for writes.
+ const MetaRecord &getMetaRecord() const;
+
+ // find, and create if needed, an index with the given id
+ DbMutableIndex &findIndex(uint32 indexId, const MetaRecord &metaRecord, bool isUniqueIndex);
+
+ // Write this table to inOutputFile at inSectionOffset and return the new offset.
+ uint32 writeTable(AtomicTempFile &inAtomicTempFile, uint32 inSectionOffset);
+
+private:
+ // Return the next available record number for this table.
+ uint32 nextRecordNumber();
+
+ // Return the number of recordNumbers in use by this table including empty slots.
+ uint32 recordNumberCount() const;
+
+ void modifyTable();
+ void createMutableIndexes();
+ uint32 writeIndexSection(WriteSection &tableSection, uint32 offset);
+
+ // Optional, this is merly a reference, we do not own this object.
+ const Table *mTable;
+
+ // Optional, New MetaRecord. This is only present if it is different from the
+ // MetaRecord of mTable or mTable is nil.
+ const MetaRecord *mNewMetaRecord;
+
+ // Set of Records that have been deleted or modified.
+ typedef set<uint32> DeletedSet;
+ DeletedSet mDeletedSet;
+
+ // Set of Records that have been inserted or modified.
+ typedef map<uint32, WriteSection *> InsertedMap;
+ InsertedMap mInsertedMap;
+
+ // Next lowest available RecordNumber
+ uint32 mRecordNumberCount;
+ // Head of the free list (if there is one) or 0 if either we have no
+ // mTable of the free list has been exhausted.
+ uint32 mFreeListHead;
+
+ // has this table actually been modified?
+ bool mIsModified;
+
+ typedef map<uint32, DbMutableIndex *> MutableIndexMap;
+ MutableIndexMap mIndexMap;
+};
+
+//
+// Read only snapshot of a database.
+//
+class Metadata
+{
+ NOCOPY(Metadata)
+protected:
+ Metadata() {}
+ enum
+ {
+ HeaderOffset = 0, // Absolute offset of header.
+ OffsetMagic = AtomSize * 0,
+ OffsetVersion = AtomSize * 1,
+ OffsetAuthOffset = AtomSize * 2,
+ OffsetSchemaOffset = AtomSize * 3,
+ HeaderSize = AtomSize * 4,
+
+ HeaderMagic = FOUR_CHAR_CODE('kych'),
+ HeaderVersion = 0x00010000
+ };
+
+ enum
+ {
+ OffsetSchemaSize = AtomSize * 0,
+ OffsetTablesCount = AtomSize * 1,
+ OffsetTables = AtomSize * 2
+ };
+};
+
+//
+// Read only representation of a database
+//
+class DbVersion : public Metadata, public RefCount
+{
+ NOCOPY(DbVersion)
+public:
+ DbVersion(const class AppleDatabase &db, const RefPointer <AtomicBufferedFile> &inAtomicBufferedFile);
+ ~DbVersion();
+
+ uint32 getVersionId() const { return mVersionId; }
+ const RecordId getRecord(Table::Id inTableId, const RecordId &inRecordId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
+ CssmData *inoutData, Allocator &inAllocator) const;
+ Cursor *createCursor(const CSSM_QUERY *inQuery) const;
+protected:
+ const Table &findTable(Table::Id inTableId) const;
+ Table &findTable(Table::Id inTableId);
+
+private:
+ void open(); // Part of constructor contract.
+
+ ReadSection mDatabase;
+ uint32 mVersionId;
+
+ friend class DbModifier; // XXX Fixme
+ typedef map<Table::Id, Table *> TableMap;
+ TableMap mTableMap;
+ const class AppleDatabase &mDb;
+ RefPointer<AtomicBufferedFile> mBufferedFile;
+
+public:
+ typedef Table value_type;
+ typedef const Table &const_reference;
+ typedef const Table *const_pointer;
+
+ // A const forward iterator.
+ class const_iterator
+ {
+ public:
+ const_iterator(const TableMap::const_iterator &it) : mIterator(it) {}
+
+ // Use default copy consturctor and assignment operator.
+ //const_iterator(const const_iterator &it) : mIterator(it.mIterator) {}
+ //const_iterator &operator=(const const_iterator &it) { mIterator = it.mIterator; return *this; }
+ const_reference operator*() const { return *mIterator->second; }
+ const_iterator &operator++() { mIterator.operator++(); return *this; }
+ const_iterator operator++(int i) { return const_iterator(mIterator.operator++(i)); }
+ bool operator!=(const const_iterator &other) const { return mIterator != other.mIterator; }
+ bool operator==(const const_iterator &other) const { return mIterator == other.mIterator; }
+
+ const_pointer operator->() const { return mIterator->second; } // Not really needed.
+
+ private:
+ TableMap::const_iterator mIterator;
+ };
+
+ const_iterator begin() const { return const_iterator(mTableMap.begin()); }
+ const_iterator end() const { return const_iterator(mTableMap.end()); }
+
+ bool hasTable(Table::Id inTableId) const;
+};
+
+//
+// Cursor
+//
+class Cursor : public HandleObject
+{
+public:
+ Cursor();
+ Cursor(const DbVersion &inDbVersion);
+ virtual ~Cursor();
+ virtual bool next(Table::Id &outTableId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
+ CssmData *outData,
+ Allocator &inAllocator,
+ RecordId &recordId);
+protected:
+ const RefPointer<const DbVersion> mDbVersion;
+};
+
+
+//
+// LinearCursor
+//
+class LinearCursor : public Cursor
+{
+ NOCOPY(LinearCursor)
+public:
+ LinearCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion,
+ const Table &inTable);
+ virtual ~LinearCursor();
+ virtual bool next(Table::Id &outTableId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
+ CssmData *outData,
+ Allocator &inAllocator,
+ RecordId &recordId);
+
+private:
+ uint32 mRecordsCount;
+ uint32 mRecord;
+ const ReadSection mRecordsSection;
+ uint32 mReadOffset;
+ const MetaRecord &mMetaRecord;
+
+ CSSM_DB_CONJUNCTIVE mConjunctive;
+ CSSM_QUERY_FLAGS mQueryFlags; // If CSSM_QUERY_RETURN_DATA is set return the raw key bits;
+ typedef vector<SelectionPredicate *> PredicateVector;
+
+ PredicateVector mPredicates;
+};
+
+//
+// A cursor that uses an index.
+//
+
+class IndexCursor : public Cursor
+{
+ NOCOPY(IndexCursor)
+public:
+ IndexCursor(DbQueryKey *queryKey, const DbVersion &inDbVersion,
+ const Table &table, const DbConstIndex *index);
+ virtual ~IndexCursor();
+
+ virtual bool next(Table::Id &outTableId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
+ CssmData *outData,
+ Allocator &inAllocator,
+ RecordId &recordId);
+
+private:
+ auto_ptr<DbQueryKey> mQueryKey;
+ const Table &mTable;
+ const DbConstIndex *mIndex;
+
+ DbIndexIterator mBegin, mEnd;
+};
+
+//
+// MultiCursor
+//
+class MultiCursor : public Cursor
+{
+ NOCOPY(MultiCursor)
+public:
+ MultiCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion);
+ virtual ~MultiCursor();
+ virtual bool next(Table::Id &outTableId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
+ CssmData *outData,
+ Allocator &inAllocator,
+ RecordId &recordId);
+private:
+ auto_ptr<CssmAutoQuery> mQuery;
+
+ DbVersion::const_iterator mTableIterator;
+ auto_ptr<Cursor> mCursor;
+};
+
+//
+// A DbModifier contains all pending changes to be made to a DB.
+// It also contains a DbVersion representing the state of the Database before any such changes
+// No read-style operations are supported by DbModifier. If a DbModifier exists for a
+// particular Database and a client wishes to perform a query commit() must be called and
+// the client should perform the new query on the current database version after the commit.
+// Otherwise a client will not see changes made since the DbModifier was instanciated.
+//
+class DbModifier : public Metadata
+{
+ NOCOPY(DbModifier)
+public:
+ DbModifier(AtomicFile &inAtomicFile, const class AppleDatabase &db);
+ ~DbModifier();
+
+ // Whole database affecting members.
+ void createDatabase(const CSSM_DBINFO &inDbInfo,
+ const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry,
+ mode_t mode);
+ void openDatabase(); // This is optional right now.
+ void closeDatabase();
+ void deleteDatabase();
+
+ void commit();
+ void rollback() throw();
+
+ // Record changing members
+ void deleteRecord(Table::Id inTableId, const RecordId &inRecordId);
+ const RecordId insertRecord(Table::Id inTableId,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
+ const CssmData *inData);
+ const RecordId updateRecord(Table::Id inTableId, const RecordId &inRecordId,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
+ const CssmData *inData,
+ CSSM_DB_MODIFY_MODE inModifyMode);
+
+ // Schema changing members
+ void insertTable(Table::Id inTableId, const string &inTableName,
+ uint32 inNumberOfAttributes,
+ const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
+ uint32 inNumberOfIndexes,
+ const CSSM_DB_SCHEMA_INDEX_INFO *inIndexInfo);
+ void deleteTable(Table::Id inTableId);
+
+ // Record reading members
+ const RecordId getRecord(Table::Id inTableId, const RecordId &inRecordId,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
+ CssmData *inoutData, Allocator &inAllocator);
+ Cursor *createCursor(const CSSM_QUERY *inQuery);
+
+ bool hasTable(Table::Id inTableid);
+
+protected:
+ void modifyDatabase();
+ const RefPointer<const DbVersion> getDbVersion(bool force);
+
+ ModifiedTable *createTable(MetaRecord *inMetaRecord); // Takes over ownership of inMetaRecord
+
+ void insertTableSchema(const CssmDbRecordAttributeInfo &inInfo,
+ const CSSM_DB_RECORD_INDEX_INFO *inIndexInfo = NULL);
+
+ void insertTable(const CssmDbRecordAttributeInfo &inInfo,
+ const CSSM_DB_RECORD_INDEX_INFO * inIndexInfo = NULL,
+ const CSSM_DB_PARSING_MODULE_INFO * inParsingModule = NULL);
+
+ ModifiedTable &findTable(Table::Id inTableId);
+
+ uint32 writeAuthSection(uint32 inSectionOffset);
+ uint32 writeSchemaSection(uint32 inSectionOffset);
+
+private:
+
+ /* mDbVersion is the current DbVersion of this database before any changes
+ we are going to make. mNotifyCount holds the value of gNotifyCount at
+ the time mDbVersion was created. mDbLastRead is the time at which we
+ last checked if the file from which mDbVersion was read has changed.
+ mDbVersionLock protects the other 3 fields. */
+ RefPointer<const DbVersion> mDbVersion;
+ int32_t mNotifyCount;
+ CFAbsoluteTime mDbLastRead;
+ Mutex mDbVersionLock;
+
+ AtomicFile &mAtomicFile;
+ uint32 mVersionId;
+ RefPointer<AtomicTempFile> mAtomicTempFile;
+
+ typedef map<Table::Id, ModifiedTable *> ModifiedTableMap;
+ ModifiedTableMap mModifiedTableMap;
+
+ const class AppleDatabase &mDb;
+};
+
+//
+// AppleDatabaseManager
+//
+class AppleDatabaseManager : public DatabaseManager
+{
+public:
+ AppleDatabaseManager(const AppleDatabaseTableName *tableNames);
+ Database *make(const DbName &inDbName);
+
+protected:
+ const AppleDatabaseTableName *mTableNames;
+};
+
+//
+// AppleDbContext
+//
+class AppleDbContext : public DbContext
+{
+public:
+ AppleDbContext(Database &inDatabase,
+ DatabaseSession &inDatabaseSession,
+ CSSM_DB_ACCESS_TYPE inAccessRequest,
+ const AccessCredentials *inAccessCred,
+ const void *inOpenParameters);
+ virtual ~AppleDbContext();
+ bool autoCommit() const { return mAutoCommit; }
+ void autoCommit(bool on) { mAutoCommit = on; }
+ mode_t mode() const { return mMode; }
+
+private:
+ bool mAutoCommit;
+ mode_t mMode;
+};
+
+//
+// AppleDatabase
+//
+class AppleDatabase : public Database
+{
+public:
+ AppleDatabase(const DbName &inDbName, const AppleDatabaseTableName *tableNames);
+ virtual ~AppleDatabase();
+
+ virtual void
+ dbCreate(DbContext &inDbContext, const CSSM_DBINFO &inDBInfo,
+ const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry);
+
+ virtual void
+ dbOpen(DbContext &inDbContext);
+
+ virtual void
+ dbClose();
+
+ virtual void
+ dbDelete(DatabaseSession &inDatabaseSession,
+ const AccessCredentials *inAccessCred);
+
+ virtual void
+ createRelation(DbContext &inDbContext,
+ CSSM_DB_RECORDTYPE inRelationID,
+ const char *inRelationName,
+ uint32 inNumberOfAttributes,
+ const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
+ uint32 inNumberOfIndexes,
+ const CSSM_DB_SCHEMA_INDEX_INFO &inIndexInfo);
+
+ virtual void
+ destroyRelation(DbContext &inDbContext,
+ CSSM_DB_RECORDTYPE inRelationID);
+
+ virtual void
+ authenticate(DbContext &inDbContext,
+ CSSM_DB_ACCESS_TYPE inAccessRequest,
+ const AccessCredentials &inAccessCred);
+
+ virtual void
+ getDbAcl(DbContext &inDbContext,
+ const CSSM_STRING *inSelectionTag,
+ uint32 &outNumberOfAclInfos,
+ CSSM_ACL_ENTRY_INFO_PTR &outAclInfos);
+
+ virtual void
+ changeDbAcl(DbContext &inDbContext,
+ const AccessCredentials &inAccessCred,
+ const CSSM_ACL_EDIT &inAclEdit);
+
+ virtual void
+ getDbOwner(DbContext &inDbContext, CSSM_ACL_OWNER_PROTOTYPE &outOwner);
+
+ virtual void
+ changeDbOwner(DbContext &inDbContext,
+ const AccessCredentials &inAccessCred,
+ const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner);
+
+ virtual char *
+ getDbNameFromHandle(const DbContext &inDbContext) const;
+
+ virtual CSSM_DB_UNIQUE_RECORD_PTR
+ dataInsert(DbContext &inDbContext,
+ CSSM_DB_RECORDTYPE RecordType,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
+ const CssmData *inData);
+
+ virtual void
+ dataDelete(DbContext &inDbContext,
+ const CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier);
+
+ virtual void
+ dataModify(DbContext &inDbContext,
+ CSSM_DB_RECORDTYPE inRecordType,
+ CSSM_DB_UNIQUE_RECORD &inoutUniqueRecordIdentifier,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributesToBeModified,
+ const CssmData *inDataToBeModified,
+ CSSM_DB_MODIFY_MODE inModifyMode);
+
+ virtual CSSM_HANDLE
+ dataGetFirst(DbContext &inDbContext,
+ const CssmQuery *inQuery,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
+ CssmData *inoutData,
+ CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord);
+
+ virtual bool
+ dataGetNext(DbContext &inDbContext,
+ CSSM_HANDLE inResultsHandle,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
+ CssmData *inoutData,
+ CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord);
+
+ virtual void
+ dataAbortQuery(DbContext &inDbContext,
+ CSSM_HANDLE inResultsHandle);
+
+ virtual void
+ dataGetFromUniqueRecordId(DbContext &inDbContext,
+ const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
+ CssmData *inoutData);
+
+ virtual void
+ freeUniqueRecord(DbContext &inDbContext,
+ CSSM_DB_UNIQUE_RECORD &inUniqueRecord);
+
+ virtual void passThrough(DbContext &dbContext,
+ uint32 passThroughId,
+ const void *inputParams,
+ void **outputParams);
+
+ // Subclasses must implement this method.
+ virtual DbContext *makeDbContext(DatabaseSession &inDatabaseSession,
+ CSSM_DB_ACCESS_TYPE inAccessRequest,
+ const AccessCredentials *inAccessCred,
+ const void *inOpenParameters);
+
+ const CssmDbRecordAttributeInfo schemaRelations;
+ const CssmDbRecordAttributeInfo schemaAttributes;
+ const CssmDbRecordAttributeInfo schemaIndexes;
+ const CssmDbRecordAttributeInfo schemaParsingModule;
+
+ const char *recordName(CSSM_DB_RECORDTYPE inRecordType) const;
+
+private:
+ static void
+ updateUniqueRecord(DbContext &inDbContext,
+ CSSM_DB_RECORDTYPE inTableId,
+ const RecordId &inRecordId,
+ CSSM_DB_UNIQUE_RECORD &inoutUniqueRecord);
+
+ CSSM_DB_UNIQUE_RECORD_PTR
+ createUniqueRecord(DbContext &inDbContext, CSSM_DB_RECORDTYPE inTableId,
+ const RecordId &inRecordId);
+ const RecordId parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
+ CSSM_DB_RECORDTYPE &outTableId);
+
+ Mutex mWriteLock;
+ AtomicFile mAtomicFile;
+ DbModifier mDbModifier;
+ const AppleDatabaseTableName *mTableNames;
+};
+
+} // end namespace Security
+
+#endif //_H_APPLEDATABASE