24 独自のDBFSストアの作成
DBFSコンテンツSPI (DBMS_DBFS_CONTENT_SPI)
を使用して、独自のDBFSストアを作成できます。
内容は次のとおりです。
24.1 DBFSストアの作成および使用の概要
DBFSストアをカスタマイズするには、DBFSコンテンツSPI (DBMS_DBFS_CONTENT_SPI)
を実装する必要があります。これは、DBFS SecureFilesストアやDFFS階層ストアなどの既存のストア、および作成する任意のユーザー定義DBFSストアの基礎となります。
PL/SQLインタフェースなどのクライアント側のアプリケーションは、DBFSコンテンツAPIでファンクションおよびプロシージャを起動します。これにより、DBFSコンテンツAPIは、DBFSコンテンツSPIで対応するサブプログラムを起動し、ストアを作成し、他の関連ファンクションを実行します。
DBFSストアを作成すると、SecureFilesストアの場合とほぼ同じ方法でそれを実行します。
24.2 DBFSコンテンツ・ストア・プロバイダ・インタフェース(DBFSコンテンツSPI)
DBFSコンテンツSPI (ストア・プロバイダ・インタフェース)は単なる仕様にすぎず、パッケージ本体はありません。
DBFSコンテンツAPIからのコールに応答するためにパッケージ本体を実装する必要があります。つまり、DBFSコンテンツSPIは、指定されたメソッド・シグネチャおよびセマンティクスを使用して実装する必要がある、必須プログラム仕様のコレクションです。
必要な場合、ファンクションおよびプロシージャをDBFSコンテンツSPIパッケージ本体に追加できます。実装によっては、その他のメソッドの実装および他のインタフェースの公開が可能ですが、DBFSコンテンツAPIはそれらのインタフェースを使用しません。
DBFSコンテンツSPIは、DBFSコンテンツAPI (パッケージDBMS_DBFS_CONTENT
)で定義された各種の要素(定数、タイプおよび例外など)を参照します。
すべてのパス名参照がストア修飾であること、つまり、プロバイダSPIのメソッドを呼び出す前に、DBFSコンテンツAPIによってマウント・ポイントの概念および完全絶対パス名が正規化され、ストア修飾パス名に変換されていることが必要な点に注意してください。
DBFSコンテンツAPIおよびプロバイダSPIは1対多プラガブル・アーキテクチャであるため、DBFSコンテンツAPIでは動的SQLを使用してプロバイダSPIのメソッドが呼び出されます。これにより、プロバイダSPIの実装がこのドキュメントのプロバイダSPIの仕様に準拠していない場合、ランタイム・エラーが発生することがあります。
DBFSコンテンツAPIで特定のプロバイダSPIがプラグ化またはプラグ解除されるタイミングを示す明示的な初期または最終メソッドはありません。プロバイダSPIは、いずれかのSPIエントリ・ポイントで、自身を自動初期化できる必要があります。
24.3 カスタム・プロバイダの作成
DBFS用のこのストア・プロバイダの例(TaBleFileSystem Store Provider (tbfs))をカスタム・プロバイダのスケルトンまたは学習ツールとして使用することにより、DBFSとそのSPIについて詳しく理解できるようになります。
この例のDBFSのストア・プロバイダは、BLOB
列が含まれるリレーショナル表をフラットな非階層ファイルシステム(つまり、名前付きファイルのコレクション)として公開します。
この例を使用するには、Oracle Database 12cをインストールしていること、DBFSの概念に詳しいこと、さらにdbfs_client
とFUSE
をインストールして使用し、標準SFSストア・プロバイダで支えられているファイルシステムのマウントとアクセスを行っていることが前提です。
TaBleFileSystemストア・プロバイダ(tbfs)は、豊富な機能の提供を意図したものではなく、まして機能を完備したものではありません。これは十分なデモンストレーションを提供することにより、DBFSのユーザーが独自のカスタム・プロバイダを作成して、dbfs_client
を介して表を従来のファイルシステム・プログラムに公開する際に役立ちます。
内容は次のとおりです。
24.3.1 メカニズム
DBFSのストア・プロバイダの例であるTaBleFileSystemストア・プロバイダ(tbfs)のメカニズムを次に示します。
内容は次のとおりです。
24.3.1.1 インストールと設定
DBFS TaBleFileSystemストア・プロバイダ(tbfs)のインストールと設定には、特定のファイルが必要です。
TBFSは、次のSQLファイルから構成されています。
tbfs.sql
最上位ドライバ・スクリプト
tbl.sql
ファイルシステム用のテスト・ユーザー、表領域、表などを作成するスクリプト。
spec.sql
tbfsのSPI仕様
body.sql
tbfsのSPI実装
capi.sql
DBFS登録/マウント・スクリプト
TBFSをインストールするには、前述のファイルがすべて含まれるディレクトリでSYSDBA
としてtbfs.sql
のみを実行します。tbfs.sql
により、他のSQLファイルが正しい順序でロードされます。
名前の競合を無視して、コンパイル・エラーなしですべてのSQLファイルがロードされます。すべてのSQLファイルは、ランタイム・エラーなしでロードされます。init.oraのplsql_warningsパラメータの値によっては、様々な警告が表示されますが問題はありません。
名前の競合(表領域名TBFS、データファイル名tbfs.f、ユーザー名TBFS、パッケージ名TBFS)がある場合は、様々なSQLファイルで該当する参照箇所を同じように変更する必要があります。
24.3.1.2 TBFSの使用
DBFSのストア・プロバイダの例であるTaBleFileSystemストア・プロバイダ(tbfs)がインストールされると、複数の異なる方法でファイルを追加または削除したり、TBFSに対して他の変更を加えることができるようになります。
ユーザーTBFSとして接続したdbfs_client
には、RDBMS表(TBFS.TBFST)に基づいて単純な非階層ファイルシステムが表示されます。
このファイルシステムでファイルを追加または削除するには、SQL (基礎となる表に対するDML)、Unixユーティリティ(dbfs_client
によって仲介)、またはPL/SQL (DBFS API使用)を使用します。
いずれかのアクセス方法によって行われたファイルシステムへの変更は、他のすべてのアクセス方法で確認でき、その際にはトランザクションの一貫性が維持されます(コミット/ロールバックの境界に対応します)。
24.3.1.3 TBFSの内部
TBFSは、本来の目的が学習用の例として使用することであるため、単純な構造になります。
ただし、その実装には、DBFSにプラグインできるとともに既存のリレーショナル・データをUNIXファイルシステムとして公開できる、強力な本番品質のカスタムSPIの構築に向けた道筋が示されます。
TBFSは、簡潔にするために様々な簡易化が行われています(ただし、これらはDBFSやSPIの制限ではないため、そのとおりにする必要はありません)。
-
TBFS SPIパッケージは、ハードコードされた名前(TBFS.TBFST)を持つ単一の表のみを処理します。動的SQLおよび追加構成情報を使用して、単一のSPIパッケージに複数の表をそれぞれ個別ファイルシステムとしてサポートさせることができます(複数の表内のデータを単一のファイルシステムとして統合することもできます)。
-
TBFSは、ファイルシステム階層をサポートしません。TBFSは、フラットなネームスペース(仮想ルート・ディレクトリ(/)の下で単純なアイテム名によって識別されるファイルのコレクション)を設定します。ディレクトリ階層の実装は、ストア・プロバイダが親/子関係を一貫性のある方法で管理する必要があるため、非常に複雑になります。
さらに、通常、既存のリレーショナル・データ(TBFSがファイルシステムとして公開しようとしているデータの種類)には、ディレクトリ/ファイル階層を形成する行間の関係が含まれません。
-
TBFSではフラットなネームスペースしかサポートされないため、SPIのほとんどのメソッドは実装されず、メソッド本体によって
dbms_dbfs_content.unsupported_operation
例外が生成されます。この例外は、独自のカスタムSPIを作成する適切な出発点にもなります。まずDBMS_DBFS_CONTENT_SPI
パッケージから単純なSPIスケルトンを複製して、この例外を生成したメソッド本体をすべてのメソッド本体のデフォルトとして設定し、その後、現実にあわせた実装を少しずつ追加します。 -
TBFSの基礎となる表は、最小限の構造(キー/名前列とLOB列)に近いものです。つまり、DBFSおよび
dbfs_client
が使用または予期する様々なプロパティを動的に生成する必要があります(TBFS実装によって、std:guid
プロパティの場合の方法が示されます)。他のプロパティ(Unix形式のタイムスタンプなど)はまったく実装されていません。この場合でも、驚くほど高機能のファイルシステムを実装できます。ただし、独自のカスタムSPIを作成すると、その他のDBFSプロパティのサポートを容易に組み込むことができます。それらのDBFSプロパティの値を提供するためには、基礎となる表の構造を拡張して必要に応じて列を増やすか、既存の表の既存の列を使用します。
-
TBFSでは名前変更や移動のメソッドは実装されません。そのためのサポート(
renamePath
メソッドの適切なUPDATE
文)の追加はユーザーに任されています。 -
TBFSの例では、複数の場所(表領域、データファイル、ユーザー、パッケージ、さらにファイルシステム名)で文字列tbfsが使用されます。tbfsのこれらの使用箇所はすべて異なるネームスペースに属しており、どのネームスペースが文字列の特定のオカレンスに対応するかを示しています。このような例のtbfsは、DBFSの概念を明確に理解できているかどうかを確認するための学習課題として適切です。
24.3.2 TBFS.SQL
TBFS.SQLは、トップレベルのドライバ・スクリプトです。
TBFS.SQLスクリプト:
set echo on; @tbl @spec @body @capi quit;
24.3.3 TBL.SQL
TBL.SQLスクリプトは、テスト・ユーザー、表領域、ファイルシステムをサポートする表などを作成します。
TBL.SQLスクリプト:
connect / as sysdba create tablespace tbfs datafile 'tbfs.f' size 100m reuse autoextend on extent management local segment space management auto; create user tbfs identified by tbfs; alter user tbfs default tablespace tbfs; grant connect, resource, dbfs_role to tbfs; connect tbfs/tbfs; drop table tbfst; purge recyclebin; create table tbfst( key varchar2(256) primary key check (instr(key, '/') = 0), data blob) tablespace tbfs lob(data) store as securefile (tablespace tbfs); grant select on tbfst to dbfs_role; grant insert on tbfst to dbfs_role; grant delete on tbfst to dbfs_role; grant update on tbfst to dbfs_role;
24.3.4 spec.sql
spec.sql
スクリプトは、tbfsのSPI仕様を提供します。
spec.sql
スクリプト:
connect / as sysdba; create or replace package tbfs authid current_user as /* * Lookup store features (see dbms_dbfs_content.feature_XXX). Lookup * store id. * * A store ID identifies a provider-specific store, across * registrations and mounts, but independent of changes to the store * contents. * * I.e. changes to the store table(s) should be reflected in the * store ID, but re-initialization of the same store table(s) should * preserve the store ID. * * Providers should also return a "version" (either specific to a * provider package, or to an individual store) based on a standard * <a.b.c> naming convention (for <major>, <minor>, and <patch> * components). * */ function getFeatures( store_name in varchar2) return integer; function getStoreId( store_name in varchar2) return number; function getVersion( store_name in varchar2) return varchar2; /* * Lookup pathnames by (store_name, std_guid) or (store_mount, * std_guid) tuples. * * If the underlying "std_guid" is found in the underlying store, * this function returns the store-qualified pathname. * * If the "std_guid" is unknown, a "null" value is returned. Clients * are expected to handle this as appropriate. * */ function getPathByStoreId( store_name in varchar2, guid in integer) return varchar2; /* * DBFS SPI: space usage. * * Clients can query filesystem space usage statistics via the * "spaceUsage()" method. Providers are expected to support this * method for their stores (and to make a best effort determination * of space usage---esp. if the store consists of multiple * tables/indexes/lobs, etc.). * * "blksize" is the natural tablespace blocksize that holds the * store---if multiple tablespaces with different blocksizes are * used, any valid blocksize is acceptable. * * "tbytes" is the total size of the store in bytes, and "fbytes" is * the free/unused size of the store in bytes. These values are * computed over all segments that comprise the store. * * "nfile", "ndir", "nlink", and "nref" count the number of * currently available files, directories, links, and references in * the store. * * Since database objects are dynamically growable, it is not easy * to estimate the division between "free" space and "used" space. * */ procedure spaceUsage( store_name in varchar2, blksize out integer, tbytes out integer, fbytes out integer, nfile out integer, ndir out integer, nlink out integer, nref out integer); /* * DBFS SPI: notes on pathnames. * * All pathnames used in the SPI are store-qualified, i.e. a 2-tuple * of the form (store_name, pathname) (where the pathname is rooted * within the store namespace). * * * Stores/providers that support contentID-based access (see * "feature_content_id") also support a form of addressing that is * not based on pathnames. Items are identified by an explicit store * name, a "null" pathname, and possibly a contentID specified as a * parameter or via the "opt_content_id" property. * * Not all operations are supported with contentID-based access, and * applications should depend only on the simplest create/delete * functionality being available. * */ /* * DBFS SPI: creation operations * * The SPI must allow the DBFS API to create directory, file, link, * and reference elements (subject to store feature support). * * * All of the creation methods require a valid pathname (see the * special exemption for contentID-based access below), and can * optionally specify properties to be associated with the pathname * as it is created. It is also possible for clients to fetch-back * item properties after the creation completes (so that * automatically generated properties (e.g. "std_creation_time") are * immediately available to clients (the exact set of properties * fetched back is controlled by the various "prop_xxx" bitmasks in * "prop_flags"). * * * Links and references require an additional pathname to associate * with the primary pathname. * * File pathnames can optionally specify a BLOB value to use to * initially populate the underlying file content (the provided BLOB * may be any valid lob: temporary or permanent). On creation, the * underlying lob is returned to the client (if "prop_data" is * specified in "prop_flags"). * * Non-directory pathnames require that their parent directory be * created first. Directory pathnames themselves can be recursively * created (i.e. the pathname hierarchy leading up to a directory * can be created in one call). * * * Attempts to create paths that already exist is an error; the one * exception is pathnames that are "soft-deleted" (see below for * delete operations)---in these cases, the soft-deleted item is * implicitly purged, and the new item creation is attempted. * * * Stores/providers that support contentID-based access accept an * explicit store name and a "null" path to create a new element. * The contentID generated for this element is available via the * "opt_content_id" property (contentID-based creation automatically * implies "prop_opt" in "prop_flags"). * * The newly created element may also have an internally generated * pathname (if "feature_lazy_path" is not supported) and this path * is available via the "std_canonical_path" property. * * Only file elements are candidates for contentID-based access. * */ procedure createFile( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content in out nocopy blob, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure createLink( store_name in varchar2, srcPath in varchar2, dstPath in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure createReference( store_name in varchar2, srcPath in varchar2, dstPath in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure createDirectory( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, prop_flags in integer, recurse in integer, ctx in dbms_dbfs_content_context_t); /* * DBFS SPI: deletion operations * * The SPI must allow the DBFS API to delete directory, file, link, * and reference elements (subject to store feature support). * * * By default, the deletions are "permanent" (get rid of the * successfully deleted items on transaction commit), but stores may * also support "soft-delete" features. If requested by the client, * soft-deleted items are retained by the store (but not typically * visible in normal listings or searches). * * Soft-deleted items can be "restore"d, or explicitly purged. * * * Directory pathnames can be recursively deleted (i.e. the pathname * hierarchy below a directory can be deleted in one call). * Non-recursive deletions can be performed only on empty * directories. Recursive soft-deletions apply the soft-delete to * all of the items being deleted. * * * Individual pathnames (or all soft-deleted pathnames under a * directory) can be restored or purged via the restore and purge * methods. * * * Providers that support filtering can use the provider "filter" to * identify subsets of items to delete---this makes most sense for * bulk operations (deleteDirectory, restoreAll, purgeAll), but all * of the deletion-related operations accept a "filter" argument. * * * Stores/providers that support contentID-based access can also * allow file items to be deleted by specifying their contentID. * */ procedure deleteFile( store_name in varchar2, path in varchar2, filter in varchar2, soft_delete in integer, ctx in dbms_dbfs_content_context_t); procedure deleteContent( store_name in varchar2, contentID in raw, filter in varchar2, soft_delete in integer, ctx in dbms_dbfs_content_context_t); procedure deleteDirectory( store_name in varchar2, path in varchar2, filter in varchar2, soft_delete in integer, recurse in integer, ctx in dbms_dbfs_content_context_t); procedure restorePath( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t); procedure purgePath( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t); procedure restoreAll( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t); procedure purgeAll( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t); /* * DBFS SPI: path get/put operations. * * Existing path items can be accessed (for query or for update) and * modified via simple get/put methods. * * All pathnames allow their metadata (i.e. properties) to be * read/modified. On completion of the call, the client can request * (via "prop_flags") specific properties to be fetched as well. * * File pathnames allow their data (i.e. content) to be * read/modified. On completion of the call, the client can request * (via the "prop_data" bitmaks in "prop_flags") a new BLOB locator * that can be used to continue data access. * * Files can also be read/written without using BLOB locators, by * explicitly specifying logical offsets/buffer-amounts and a * suitably sized buffer. * * * Update accesses must specify the "forUpdate" flag. Access to link * pathnames can be implicitly and internally deferenced by stores * (subject to feature support) if the "deref" flag is * specified---however, this is dangerous since symbolic links are * not always resolvable. * * * The read methods (i.e. "getPath" where "forUpdate" is "false" * also accepts a valid "asof" timestamp parameter that can be used * by stores to implement "as of" style flashback queries. Mutating * versions of the "getPath" and the "putPath" methods do not * support as-of modes of operation. * * * "getPathNowait" implies a "forUpdate", and, if implemented (see * "feature_nowait"), allows providers to return an exception * (ORA-54) rather than wait for row locks. * */ procedure getPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content out nocopy blob, item_type out integer, prop_flags in integer, forUpdate in integer, deref in integer, ctx in dbms_dbfs_content_context_t); procedure getPathNowait( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content out nocopy blob, item_type out integer, prop_flags in integer, deref in integer, ctx in dbms_dbfs_content_context_t); procedure getPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, amount in out number, offset in number, buffer out nocopy raw, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure getPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, amount in out number, offset in number, buffers out nocopy dbms_dbfs_content_raw_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure putPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content in out nocopy blob, item_type out integer, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure putPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, amount in number, offset in number, buffer in raw, prop_flags in integer, ctx in dbms_dbfs_content_context_t); procedure putPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, written out number, offset in number, buffers in dbms_dbfs_content_raw_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t); /* * DBFS SPI: rename/move operations. * * Pathnames can be renamed or moved, possibly across directory * hierarchies and mount-points, but within the same store. * * * Non-directory pathnames previously accessible via "oldPath" are * renamed as a single item subsequently accessible via "newPath"; * assuming that "newPath" does not already exist. * * If "newPath" exists and is not a directory, the rename implicitly * deletes the existing item before renaming "oldPath". If "newPath" * exists and is a directory, "oldPath" is moved into the target * directory. * * * Directory pathnames previously accessible via "oldPath" are * renamed by moving the directory and all of its children to * "newPath" (if it does not already exist) or as children of * "newPath" (if it exists and is a directory). * * * Stores/providers that support contentID-based access and lazy * pathname binding also support the "setPath" method that * associates an existing "contentID" with a new "path". * */ procedure renamePath( store_name in varchar2, oldPath in varchar2, newPath in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, ctx in dbms_dbfs_content_context_t); procedure setPath( store_name in varchar2, contentID in raw, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, ctx in dbms_dbfs_content_context_t); /* * DBFS SPI: directory navigation and search. * * The DBFS API can list or search the contents of directory * pathnames, optionally recursing into sub-directories, optionally * seeing soft-deleted items, optionally using flashback "as of" a * provided timestamp, and optionally filtering items in/out within * the store based on list/search predicates. * */ function list( store_name in varchar2, path in varchar2, filter in varchar2, recurse in integer, ctx in dbms_dbfs_content_context_t) return dbms_dbfs_content_list_items_t pipelined; function search( store_name in varchar2, path in varchar2, filter in varchar2, recurse in integer, ctx in dbms_dbfs_content_context_t) return dbms_dbfs_content_list_items_t pipelined; /* * DBFS SPI: locking operations. * * Clients of the DBFS API can apply user-level locks to any valid * pathname (subject to store feature support), associate the lock * with user-data, and subsequently unlock these pathnames. * * The status of locked items is available via various optional * properties (see "opt_lock*" above). * * * It is the responsibility of the store (assuming it supports * user-defined lock checking) to ensure that lock/unlock operations * are performed in a consistent manner. * */ procedure lockPath( store_name in varchar2, path in varchar2, lock_type in integer, lock_data in varchar2, ctx in dbms_dbfs_content_context_t); procedure unlockPath( store_name in varchar2, path in varchar2, ctx in dbms_dbfs_content_context_t); /* * DBFS SPI: access checks. * * Check if a given pathname (store_name, path, pathtype) can be * manipulated by "operation (see the various * "dbms_dbfs_content.op_xxx" opcodes) by "principal". * * This is a convenience function for the DBFS API; a store that * supports access control still internally performs these checks to * guarantee security. * */ function checkAccess( store_name in varchar2, path in varchar2, pathtype in integer, operation in varchar2, principal in varchar2) return integer; end; / show errors; create or replace public synonym tbfs for sys.tbfs; grant execute on tbfs to dbfs_role;
24.3.5 body.sql
body.sql
スクリプトは、tbfsのSPI仕様を提供します。
body.sql
スクリプト:
connect / as sysdba; create or replace package body tbfs as /* * Lookup store features (see dbms_dbfs_content.feature_XXX). Lookup * store id. * * A store ID identifies a provider-specific store, across * registrations and mounts, but independent of changes to the store * contents. * * I.e. changes to the store table(s) should be reflected in the * store ID, but re-initialization of the same store table(s) should * preserve the store ID. * * Providers should also return a "version" (either specific to a * provider package, or to an individual store) based on a standard * <a.b.c> naming convention (for <major>, <minor>, and <patch> * components). * */ function getFeatures( store_name in varchar2) return integer is begin return dbms_dbfs_content.feature_locator; end; function getStoreId( store_name in varchar2) return number is begin return 1; end; function getVersion( store_name in varchar2) return varchar2 is begin return '1.0.0'; end; /* * Lookup pathnames by (store_name, std_guid) or (store_mount, * std_guid) tuples. * * If the underlying "std_guid" is found in the underlying store, * this function returns the store-qualified pathname. * * If the "std_guid" is unknown, a "null" value is returned. Clients * are expected to handle this as appropriate. * */ function getPathByStoreId( store_name in varchar2, guid in integer) return varchar2 is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: space usage. * * Clients can query filesystem space usage statistics via the * "spaceUsage()" method. Providers are expected to support this * method for their stores (and to make a best effort determination * of space usage---esp. if the store consists of multiple * tables/indexes/lobs, etc.). * * "blksize" is the natural tablespace blocksize that holds the * store---if multiple tablespaces with different blocksizes are * used, any valid blocksize is acceptable. * * "tbytes" is the total size of the store in bytes, and "fbytes" is * the free/unused size of the store in bytes. These values are * computed over all segments that comprise the store. * * "nfile", "ndir", "nlink", and "nref" count the number of * currently available files, directories, links, and references in * the store. * * Since database objects are dynamically growable, it is not easy * to estimate the division between "free" space and "used" space. * */ procedure spaceUsage( store_name in varchar2, blksize out integer, tbytes out integer, fbytes out integer, nfile out integer, ndir out integer, nlink out integer, nref out integer) is nblks number; begin select count(*) into nfile from tbfs.tbfst; ndir := 0; nlink := 0; nref := 0; select sum(bytes) into tbytes from user_segments; select sum(blocks) into nblks from user_segments; blksize := tbytes/nblks; fbytes := 0; /* change as needed */ end; /* * DBFS SPI: notes on pathnames. * * All pathnames used in the SPI are store-qualified, i.e. a 2-tuple * of the form (store_name, pathname) (where the pathname is rooted * within the store namespace). * * * Stores/providers that support contentID-based access (see * "feature_content_id") also support a form of addressing that is * not based on pathnames. Items are identified by an explicit store * name, a "null" pathname, and possibly a contentID specified as a * parameter or via the "opt_content_id" property. * * Not all operations are supported with contentID-based access, and * applications should depend only on the simplest create/delete * functionality being available. * */ /* * DBFS SPI: creation operations * * The SPI must allow the DBFS API to create directory, file, link, * and reference elements (subject to store feature support). * * * All of the creation methods require a valid pathname (see the * special exemption for contentID-based access below), and can * optionally specify properties to be associated with the pathname * as it is created. It is also possible for clients to fetch-back * item properties after the creation completes (so that * automatically generated properties (e.g. "std_creation_time") are * immediately available to clients (the exact set of properties * fetched back is controlled by the various "prop_xxx" bitmasks in * "prop_flags"). * * * Links and references require an additional pathname to associate * with the primary pathname. * * File pathnames can optionally specify a BLOB value to use to * initially populate the underlying file content (the provided BLOB * may be any valid lob: temporary or permanent). On creation, the * underlying lob is returned to the client (if "prop_data" is * specified in "prop_flags"). * * Non-directory pathnames require that their parent directory be * created first. Directory pathnames themselves can be recursively * created (i.e. the pathname hierarchy leading up to a directory * can be created in one call). * * * Attempts to create paths that already exist is an error; the one * exception is pathnames that are "soft-deleted" (see below for * delete operations)---in these cases, the soft-deleted item is * implicitly purged, and the new item creation is attempted. * * * Stores/providers that support contentID-based access accept an * explicit store name and a "null" path to create a new element. * The contentID generated for this element is available via the * "opt_content_id" property (contentID-based creation automatically * implies "prop_opt" in "prop_flags"). * * The newly created element may also have an internally generated * pathname (if "feature_lazy_path" is not supported) and this path * is available via the "std_canonical_path" property. * * Only file elements are candidates for contentID-based access. * */ procedure createFile( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content in out nocopy blob, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is guid number; begin if (path = '/') then raise dbms_dbfs_content.invalid_path; end if; if content is null then content := empty_blob(); end if; begin insert into tbfs.tbfst values (substr(path,2), content) returning data into content; exception when dup_val_on_index then raise dbms_dbfs_content.path_exists; end; select ora_hash(path) into guid from dual; properties := dbms_dbfs_content_properties_t( dbms_dbfs_content_property_t( 'std:length', to_char(dbms_lob.getlength(content)), dbms_types.TYPECODE_NUMBER), dbms_dbfs_content_property_t( 'std:guid', to_char(guid), dbms_types.TYPECODE_NUMBER)); end; procedure createLink( store_name in varchar2, srcPath in varchar2, dstPath in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure createReference( store_name in varchar2, srcPath in varchar2, dstPath in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure createDirectory( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, prop_flags in integer, recurse in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: deletion operations * * The SPI must allow the DBFS API to delete directory, file, link, * and reference elements (subject to store feature support). * * * By default, the deletions are "permanent" (get rid of the * successfully deleted items on transaction commit), but stores may * also support "soft-delete" features. If requested by the client, * soft-deleted items are retained by the store (but not typically * visible in normal listings or searches). * * Soft-deleted items can be "restore"d, or explicitly purged. * * * Directory pathnames can be recursively deleted (i.e. the pathname * hierarchy below a directory can be deleted in one call). * Non-recursive deletions can be performed only on empty * directories. Recursive soft-deletions apply the soft-delete to * all of the items being deleted. * * * Individual pathnames (or all soft-deleted pathnames under a * directory) can be restored or purged via the restore and purge * methods. * * * Providers that support filtering can use the provider "filter" to * identify subsets of items to delete---this makes most sense for * bulk operations (deleteDirectory, restoreAll, purgeAll), but all * of the deletion-related operations accept a "filter" argument. * * * Stores/providers that support contentID-based access can also * allow file items to be deleted by specifying their contentID. * */ procedure deleteFile( store_name in varchar2, path in varchar2, filter in varchar2, soft_delete in integer, ctx in dbms_dbfs_content_context_t) is begin if (path = '/') then raise dbms_dbfs_content.invalid_path; end if; if ((soft_delete <> 0) or (filter is not null)) then raise dbms_dbfs_content.unsupported_operation; end if; delete from tbfs.tbfst t where ('/' || t.key) = path; if sql%rowcount <> 1 then raise dbms_dbfs_content.invalid_path; end if; end; procedure deleteContent( store_name in varchar2, contentID in raw, filter in varchar2, soft_delete in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure deleteDirectory( store_name in varchar2, path in varchar2, filter in varchar2, soft_delete in integer, recurse in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure restorePath( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure purgePath( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure restoreAll( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure purgeAll( store_name in varchar2, path in varchar2, filter in varchar2, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: path get/put operations. * * Existing path items can be accessed (for query or for update) and * modified via simple get/put methods. * * All pathnames allow their metadata (i.e. properties) to be * read/modified. On completion of the call, the client can request * (via "prop_flags") specific properties to be fetched as well. * * File pathnames allow their data (i.e. content) to be * read/modified. On completion of the call, the client can request * (via the "prop_data" bitmaks in "prop_flags") a new BLOB locator * that can be used to continue data access. * * Files can also be read/written without using BLOB locators, by * explicitly specifying logical offsets/buffer-amounts and a * suitably sized buffer. * * * Update accesses must specify the "forUpdate" flag. Access to link * pathnames can be implicitly and internally deferenced by stores * (subject to feature support) if the "deref" flag is * specified---however, this is dangerous since symbolic links are * not always resolvable. * * * The read methods (i.e. "getPath" where "forUpdate" is "false" * also accepts a valid "asof" timestamp parameter that can be used * by stores to implement "as of" style flashback queries. Mutating * versions of the "getPath" and the "putPath" methods do not * support as-of modes of operation. * * * "getPathNowait" implies a "forUpdate", and, if implemented (see * "feature_nowait"), allows providers to return an exception * (ORA-54) rather than wait for row locks. * */ procedure getPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content out nocopy blob, item_type out integer, prop_flags in integer, forUpdate in integer, deref in integer, ctx in dbms_dbfs_content_context_t) is guid number; begin if (deref <> 0) then raise dbms_dbfs_content.unsupported_operation; end if; select ora_hash(path) into guid from dual; if (path = '/') then if (forUpdate <> 0) then raise dbms_dbfs_content.unsupported_operation; end if; content := null; item_type := dbms_dbfs_content.type_directory; properties := dbms_dbfs_content_properties_t( dbms_dbfs_content_property_t( 'std:guid', to_char(guid), dbms_types.TYPECODE_NUMBER)); return; end if; begin if (forUpdate <> 0) then select t.data into content from tbfs.tbfst t where ('/' || t.key) = path for update; else select t.data into content from tbfs.tbfst t where ('/' || t.key) = path; end if; exception when no_data_found then raise dbms_dbfs_content.invalid_path; end; item_type := dbms_dbfs_content.type_file; properties := dbms_dbfs_content_properties_t( dbms_dbfs_content_property_t( 'std:length', to_char(dbms_lob.getlength(content)), dbms_types.TYPECODE_NUMBER), dbms_dbfs_content_property_t( 'std:guid', to_char(guid), dbms_types.TYPECODE_NUMBER)); end; procedure getPathNowait( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content out nocopy blob, item_type out integer, prop_flags in integer, deref in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure getPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, amount in out number, offset in number, buffer out nocopy raw, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is content blob; guid number; begin if (path = '/') then raise dbms_dbfs_content.unsupported_operation; end if; begin select t.data into content from tbfs.tbfst t where ('/' || t.key) = path; exception when no_data_found then raise dbms_dbfs_content.invalid_path; end; select ora_hash(path) into guid from dual; dbms_lob.read(content, amount, offset, buffer); properties := dbms_dbfs_content_properties_t( dbms_dbfs_content_property_t( 'std:length', to_char(dbms_lob.getlength(content)), dbms_types.TYPECODE_NUMBER), dbms_dbfs_content_property_t( 'std:guid', to_char(guid), dbms_types.TYPECODE_NUMBER)); end; procedure getPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, amount in out number, offset in number, buffers out nocopy dbms_dbfs_content_raw_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure putPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, content in out nocopy blob, item_type out integer, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is guid number; begin if (path = '/') then raise dbms_dbfs_content.unsupported_operation; end if; if content is null then content := empty_blob(); end if; update tbfs.tbfst t set t.data = content where ('/' || t.key) = path returning t.data into content; if sql%rowcount <> 1 then raise dbms_dbfs_content.invalid_path; end if; select ora_hash(path) into guid from dual; item_type := dbms_dbfs_content.type_file; properties := dbms_dbfs_content_properties_t( dbms_dbfs_content_property_t( 'std:length', to_char(dbms_lob.getlength(content)), dbms_types.TYPECODE_NUMBER), dbms_dbfs_content_property_t( 'std:guid', to_char(guid), dbms_types.TYPECODE_NUMBER)); end; procedure putPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, amount in number, offset in number, buffer in raw, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is content blob; guid number; begin if (path = '/') then raise dbms_dbfs_content.unsupported_operation; end if; begin select t.data into content from tbfs.tbfst t where ('/' || t.key) = path for update; exception when no_data_found then raise dbms_dbfs_content.invalid_path; end; select ora_hash(path) into guid from dual; dbms_lob.write(content, amount, offset, buffer); properties := dbms_dbfs_content_properties_t( dbms_dbfs_content_property_t( 'std:length', to_char(dbms_lob.getlength(content)), dbms_types.TYPECODE_NUMBER), dbms_dbfs_content_property_t( 'std:guid', to_char(guid), dbms_types.TYPECODE_NUMBER)); end; procedure putPath( store_name in varchar2, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, written out number, offset in number, buffers in dbms_dbfs_content_raw_t, prop_flags in integer, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: rename/move operations. * * Pathnames can be renamed or moved, possibly across directory * hierarchies and mount-points, but within the same store. * * * Non-directory pathnames previously accessible via "oldPath" are * renamed as a single item subsequently accessible via "newPath"; * assuming that "newPath" does not already exist. * * If "newPath" exists and is not a directory, the rename implicitly * deletes the existing item before renaming "oldPath". If "newPath" * exists and is a directory, "oldPath" is moved into the target * directory. * * * Directory pathnames previously accessible via "oldPath" are * renamed by moving the directory and all of its children to * "newPath" (if it does not already exist) or as children of * "newPath" (if it exists and is a directory). * * * Stores/providers that support contentID-based access and lazy * pathname binding also support the "setPath" method that * associates an existing "contentID" with a new "path". * */ procedure renamePath( store_name in varchar2, oldPath in varchar2, newPath in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure setPath( store_name in varchar2, contentID in raw, path in varchar2, properties in out nocopy dbms_dbfs_content_properties_t, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: directory navigation and search. * * The DBFS API can list or search the contents of directory * pathnames, optionally recursing into sub-directories, optionally * seeing soft-deleted items, optionally using flashback "as of" a * provided timestamp, and optionally filtering items in/out within * the store based on list/search predicates. * */ function list( store_name in varchar2, path in varchar2, filter in varchar2, recurse in integer, ctx in dbms_dbfs_content_context_t) return dbms_dbfs_content_list_items_t pipelined is begin for rws in (select * from tbfs.tbfst) loop pipe row(dbms_dbfs_content_list_item_t( '/' || rws.key, rws.key, dbms_dbfs_content.type_file)); end loop; end; function search( store_name in varchar2, path in varchar2, filter in varchar2, recurse in integer, ctx in dbms_dbfs_content_context_t) return dbms_dbfs_content_list_items_t pipelined is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: locking operations. * * Clients of the DBFS API can apply user-level locks to any valid * pathname (subject to store feature support), associate the lock * with user-data, and subsequently unlock these pathnames. * * The status of locked items is available via various optional * properties (see "opt_lock*" above). * * * It is the responsibility of the store (assuming it supports * user-defined lock checking) to ensure that lock/unlock operations * are performed in a consistent manner. * */ procedure lockPath( store_name in varchar2, path in varchar2, lock_type in integer, lock_data in varchar2, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; procedure unlockPath( store_name in varchar2, path in varchar2, ctx in dbms_dbfs_content_context_t) is begin raise dbms_dbfs_content.unsupported_operation; end; /* * DBFS SPI: access checks. * * Check if a given pathname (store_name, path, pathtype) can be * manipulated by "operation (see the various * "dbms_dbfs_content.op_xxx" opcodes) by "principal". * * This is a convenience function for the DBFS API; a store that * supports access control still internally performs these checks to * guarantee security. * */ function checkAccess( store_name in varchar2, path in varchar2, pathtype in integer, operation in varchar2, principal in varchar2) return integer is begin return 1; end; end; / show errors;