使用 PHP 調(diào)用 Oracle 存儲(chǔ)過(guò)程

作者:Harry Fuecks
原文鏈接:http://www.oracle.com/technetwork/cn/articles/fuecks-sps-082839-zhs.html

存儲(chǔ)過(guò)程是實(shí)際位于 Oracle 中的程序趁蕊。大多數(shù)存儲(chǔ)過(guò)程都是用 PL/SQL 編寫(xiě)的熟嫩,在 Oracle 數(shù)據(jù)庫(kù) 10g 第 2 版和更高版本中素挽,您可以用 Java枪眉、.NET 或其他語(yǔ)言將它們編寫(xiě)為外部過(guò)程蹬叭。

存儲(chǔ)過(guò)程通常將一系列相關(guān)操作組成一個(gè) API藕咏。存儲(chǔ)過(guò)程執(zhí)行的操作包括由 SQL 語(yǔ)句以及 PL/SQL 語(yǔ)句執(zhí)行的操作,SQL 語(yǔ)句用于獲取和修改數(shù)據(jù)秽五,PL/SQL 語(yǔ)句將對(duì)這些數(shù)據(jù)進(jìn)行相應(yīng)操作孽查,如執(zhí)行某些數(shù)學(xué)運(yùn)算、對(duì)值進(jìn)行詳細(xì)驗(yàn)證值以及處理錯(cuò)誤條件坦喘。它們降低了調(diào)用程序與數(shù)據(jù)庫(kù)之間的“往返”次數(shù)并簡(jiǎn)化了客戶端中的數(shù)據(jù)管理邏輯盲再,從而有利于提高性能。

如果考慮一下管理表之間的多對(duì)多關(guān)系通常需要的代碼瓣铣,則會(huì)發(fā)現(xiàn)對(duì)現(xiàn)有數(shù)據(jù)執(zhí)行更新通常涉及三個(gè)不同的查詢答朋。通過(guò)將該進(jìn)程封裝在單個(gè)存儲(chǔ)過(guò)程中,將減少客戶端與數(shù)據(jù)庫(kù)之間的通信量棠笑,而通常需要在客戶端代碼分多個(gè)步驟執(zhí)行的操作將減化為一個(gè)數(shù)據(jù)庫(kù)調(diào)用梦碗。

PHP OCI8 擴(kuò)展支持對(duì)存儲(chǔ)過(guò)程的調(diào)用,您可以將參數(shù)綁定到過(guò)程語(yǔ)句(與將參數(shù)綁定到普通的 SQL 語(yǔ)句方法相同),并可以訪問(wèn)結(jié)果游標(biāo)和 Oracle 集合洪规。本方法文檔中提供了存儲(chǔ)過(guò)程的常見(jiàn)操作示例印屁。

存儲(chǔ)過(guò)程輸入和輸出

調(diào)用 Oracle 存儲(chǔ)過(guò)程時(shí),所有輸入和輸出數(shù)據(jù)均以參數(shù)形式傳遞給過(guò)程斩例。如果您習(xí)慣于使用某些參數(shù)調(diào)用 PHP 函數(shù)并讓它返回一個(gè)值的過(guò)程雄人,那么起初您可能對(duì)此感到有些迷惑不解,但通過(guò)示例卻可以一目了然念赶。假設(shè)有以下存儲(chǔ)過(guò)程簽名:
sayHello (name IN VARCHAR2, greeting OUT VARCHAR2)
調(diào)用此過(guò)程時(shí)础钠,第一個(gè)參數(shù)名將包含一個(gè)在調(diào)用時(shí)提供的輸入值,而 greeting 將由該過(guò)程填充叉谜,作為一個(gè)“返回”值珍坊,在該過(guò)程完成后使用。

閱讀規(guī)范

PL/SQL 編程不是本方法文檔的范疇正罢,但您需要對(duì)存儲(chǔ)過(guò)程有一個(gè)大致的了解并能夠閱讀接口規(guī)范阵漏,但不必深究。

對(duì)于存儲(chǔ)過(guò)程的源代碼翻具,開(kāi)始都需要先定義接受的參數(shù)履怯,例如:

PROCEDURE edit_entry(
status_out OUT NUMBER,
status_msg_out OUT VARCHAR2,
id_inout IN OUT INTEGER,
title_in IN VARCHAR2,
text_out OUT CLOB,
categories_in IN list_of_numbers
);

該過(guò)程名為 edit_entry。圓括號(hào)中定義了可以傳遞給該過(guò)程的各參數(shù)(由逗號(hào)分隔)裆泳。每個(gè)參數(shù)中叹洲,你會(huì)看到用于在該過(guò)程內(nèi)部引用其值的名稱(不需要在 PHP 腳本中使用同一名稱)、參數(shù)的模式(如下所示)以及該參數(shù)的類型工禾。

對(duì)于該示例中的第一個(gè)參數(shù):
status_out OUT NUMBER,
內(nèi)部名稱為 status_out运提,模式為 OUT,類型為 NUMBER(它是一個(gè)原生的 Oracle 數(shù)據(jù)類型)闻葵。

后面有一個(gè) id_inout 參數(shù)民泵。
id_inout IN OUT INTEGER,
它的模式為 IN OUT,類型為 INTEGER槽畔。

最后是 categories_in 參數(shù):
categories_in IN list_of_numbers
此處的類型是由用戶定義的(稍后將對(duì)該類型進(jìn)行詳細(xì)介紹)栈妆。

參數(shù)模式

參數(shù)模式描述了數(shù)據(jù)從調(diào)用方到過(guò)程的“流”向:
IN - 該模式的參數(shù)由調(diào)用方提供。
OUT - 參數(shù)可以由過(guò)程分配值并返回至調(diào)用方厢钧。
IN OUT - 參數(shù)可以在兩個(gè)“方向”使用鳞尔;即,調(diào)用方可以為該參數(shù)提供值早直,而過(guò)程也可以修改參數(shù)值寥假。
參數(shù)項(xiàng)是必選項(xiàng)。從 PHP 調(diào)用過(guò)程時(shí)霞扬,必須將 PHP 變量綁定到它定義的所有參數(shù)糕韧。您不必向 PHP 變量分配值拾给,即使它們是輸入?yún)?shù) - 如果未向標(biāo)量類型分配值,Oracle 將把它視為 NULL 值兔沃。

值得注意的是蒋得,存儲(chǔ)過(guò)程可以在 Oracle 中“重載”。換言之乒疏,可以有兩個(gè)名稱相同但參數(shù)簽名不同的過(guò)程额衙。將依據(jù) PHP 變量綁定到的參數(shù)的數(shù)目和類型來(lái)決定要調(diào)用哪個(gè)過(guò)程。

復(fù)雜類型

存儲(chǔ)過(guò)程使用的參數(shù)并不只局限于 VARCHAR2 和 INTEGER 等標(biāo)量類型怕吴。也可以傳遞并接收復(fù)雜的數(shù)據(jù)類型窍侧,如值列表或與從表中選擇的行集相對(duì)應(yīng)的結(jié)果游標(biāo)。

一般說(shuō)來(lái)转绷,如果存在要迭代的數(shù)據(jù)行伟件,則您將通常會(huì)收到從存儲(chǔ)過(guò)程返回的游標(biāo),而如果您需要傳入值列表议经,則通常將使用集合斧账。以下示例通過(guò) PHP 演示了這些復(fù)雜類型。

調(diào)用方與定義方權(quán)限煞肾。Oracle 對(duì)“調(diào)用方”(執(zhí)行存儲(chǔ)過(guò)程的用戶)和定義方(以其身份執(zhí)行 CREATE PROCEDURE 語(yǔ)句的用戶)進(jìn)行了區(qū)分咧织。

默認(rèn)情況下,存儲(chǔ)過(guò)程是以定義方的權(quán)限執(zhí)行的籍救,即使調(diào)用方是不同的用戶习绢。這意味著表的所有訪問(wèn)權(quán)限(例如,在過(guò)程中的訪問(wèn)權(quán)限)將由定義方的權(quán)限控制蝙昙,因此調(diào)用方只需要執(zhí)行過(guò)程的權(quán)限而非它使用的表的權(quán)限闪萄。

可以在過(guò)程定義中用關(guān)鍵字 AUTHID CURRENT_USER 更改此模型。設(shè)置該指令后奇颠,執(zhí)行存儲(chǔ)過(guò)程時(shí)所需的權(quán)限將在運(yùn)行時(shí)依據(jù)執(zhí)行該過(guò)程的當(dāng)前用戶來(lái)決定败去。

該方法的一個(gè)用途是測(cè)試一個(gè)修改表數(shù)據(jù)但實(shí)際上不修改實(shí)時(shí)數(shù)據(jù)的過(guò)程。這種情況下大刊,調(diào)用方在他們自己的模式中定義一個(gè)表(該表與從他們需要執(zhí)行的過(guò)程中訪問(wèn)的表同名)为迈,而過(guò)程依據(jù)本地表而非提供給定義方的表執(zhí)行。

從 PHP 中調(diào)用存儲(chǔ)過(guò)程

對(duì)于要從 PHP 中執(zhí)行以調(diào)用過(guò)程的 SQL 語(yǔ)句而言缺菌,您將通常在 Oracle BEGIN ...END; 塊(稱作 匿名塊)中嵌入調(diào)用。例如:

<?php 
// etc.

$sql = 'BEGIN sayHello(:name, :message); END;';

然后搜锰,通過(guò)調(diào)用 oci_bind_by_name() 將參數(shù)綁定到 PHP 變量伴郁。

如果使用以下 DDL 語(yǔ)句定義了 sayHello:

CREATE OR REPLACE PROCEDURE 
sayHello (name IN VARCHAR2, greeting OUT VARCHAR2) 
AS
BEGIN
greeting := 'Hello ' || name;
END;
/

注意,您可以使用 SQLPlus 命令行運(yùn)行上面的語(yǔ)句蛋叼。將該語(yǔ)句保存到文件 (SAYHELLO.SQL)焊傅。接下來(lái)剂陡,使用 SQLPlus 登錄:

$ sqlplus username@SID

然后,使用 START 命令創(chuàng)建該過(guò)程:

SQL> START /home/username/SAYHELLO.SQL

以下 PHP 腳本調(diào)用該過(guò)程:

<?php 
$conn = oci_connect('SCOTT','TIGER') or die;


$sql = 'BEGIN sayHello(:name, :message); END;';

$stmt = oci_parse($conn,$sql);

//  Bind the input parameter
oci_bind_by_name($stmt,':name',$name,32);

// Bind the output parameter
oci_bind_by_name($stmt,':message',$message,32);

// Assign a value to the input 
$name = 'Harry';

oci_execute($stmt);

// $message is now populated with the output value
print "$message\n";
?>

Blog 示例程序包狐胎。為演示調(diào)用存儲(chǔ)過(guò)程方面的某些技巧鸭栖,您將在此處使用以下名為 blog 的程序包,該程序包提供了一個(gè) API握巢,用于獲取和修改假設(shè)的網(wǎng)志應(yīng)用程序中的條目晕鹊。程序包用于通過(guò)其自身的作用域?qū)⑦^(guò)程、函數(shù)和數(shù)據(jù)封裝在其自身的命名空間內(nèi)部暴浦,并使它們獨(dú)立于全局?jǐn)?shù)據(jù)庫(kù)命名空間中的其他過(guò)程溅话。調(diào)用程序包中的過(guò)程時(shí),將使用句號(hào)來(lái)分隔程序包名稱與過(guò)程名稱歌焦。

可以使用以下語(yǔ)句指定 blog 程序包:

CREATE OR REPLACE PACKAGE blog AS
    
TYPE cursorType IS REF CURSOR RETURN blogs%ROWTYPE;
    
    /*
Fetch the latest num_entries_in from the blogs table, populating
entries_cursor_out with the result
    */
PROCEDURE latest(
num_entries_in IN NUMBER,
entries_cursor_out OUT cursorType
    );
    
    /*
Edit a blog entry.If id_inout is NULL, results in an INSERT, otherwise
attempts to UPDATE the existing blog entry. status_out will have the value
1 on success, otherwise a negative number on failure with status_msg_out
containing a description
categories_in is a collection where list_of_numbers is described by
TYPE list_of_numbers AS VARRAY(50) OF NUMBER;
    */
PROCEDURE edit_entry(
status_out OUT NUMBER,
status_msg_out OUT VARCHAR2,
id_inout IN OUT INTEGER,
title_in IN VARCHAR2,
text_out OUT CLOB,
categories_in IN list_of_numbers
    );
    
END blog;
/

該程序包提供了兩個(gè)過(guò)程: blog.latest(返回包含最新 num_entries 網(wǎng)志條目的結(jié)果游標(biāo))和 blog.edit_entry(允許插入新的網(wǎng)志條目以及修改現(xiàn)有的網(wǎng)志條目)飞几。如果為 id_inout 參數(shù)提供值,則該過(guò)程將嘗試更新具有該 id 的相應(yīng)網(wǎng)志條目独撇。否則屑墨,它將插入一個(gè)新的網(wǎng)志條目并使用新行的主鍵填充 id_inout。該過(guò)程還接受與網(wǎng)志條目的主體相對(duì)應(yīng)的 CLOB 對(duì)象以及與該條目歸檔到的類別列表相對(duì)應(yīng)的集合對(duì)象纷铣。此處引用的集合類型 list_of_numbers 由以下語(yǔ)句定義:

CREATE OR REPLACE TYPE list_of_numbers AS VARRAY(50) OF NUMBER;

下面顯示了該程序包的主體绪钥。您可以通過(guò)其中的注釋了解它的功能而不必深入了解 PL/SQL:

CREATE OR REPLACE PACKAGE BODY blog AS
    
    /*------------------------------------------------*/
PROCEDURE latest(
num_entries_in IN NUMBER,
entries_cursor_out OUT cursorType
) AS
        
BEGIN
            
OPEN entries_cursor_out FOR
SELECT * FROM blogs WHERE rownum < num_entries_in
ORDER BY date_published DESC;
            
END latest;
    
    /*------------------------------------------------*/
PROCEDURE edit_entry(
status_out OUT NUMBER,
status_msg_out OUT VARCHAR2,
id_inout IN OUT INTEGER,
title_in IN VARCHAR2,
text_out OUT CLOB,
categories_in IN list_of_numbers
AS
        
ENTRY_NOT_FOUND EXCEPTION;
entry_found INTEGER := 0;
        
BEGIN
            
/* Default status to success */
status_out := 1;
            
/* If id_inout has a value then attempt to UPDATE */
IF id_inout IS NOT NULL THEN
                
/* Check the id exists - raise ENTRY_NOT_FOUND if not */
SELECT COUNT(*) INTO entry_found
FROM blogs b WHERE b.id = id_inout;
IF entry_found != 1 THEN RAISE ENTRY_NOT_FOUND; END IF;
                
/* Update the blogs table returning the CLOB field */
UPDATE blogs b SET b.title = title_in, b.text = EMPTY_CLOB()
WHERE b.id = id_inout RETURNING b.text INTO text_out;
                
/* Remove any existing relationships to categories
- new categories inserted below */
DELETE FROM blogs_to_categories WHERE blog_id = id_inout;
                
status_msg_out := 'Blog entry ' || id_inout || ' updated';
            
/* id_inout was null so INSERT new record */
ELSE
                
INSERT INTO blogs b ( b.id, b.title, b.date_published, b.text )
VALUES ( blog_id_seq.nextval, title_in, SYSDATE, EMPTY_CLOB() )
RETURNING b.id, b.text INTO id_inout, text_out;
                
status_msg_out := 'Blog entry ' || id_inout || ' inserted';
                
END IF;
            
/* Now handle assignment to categories.
Loop over the categories_in collection,
inserting the new category assignments */
FOR i IN 1 .. categories_in.count
LOOP
INSERT INTO blogs_to_categories (blog_id,category_id)
VALUES (id_inout,categories_in(i));
END LOOP;
            
status_msg_out := status_msg_out || ' - added to '
|| categories_in.count || ' categories';
            
EXCEPTION
/* Catch the exception when id_inout not found */
WHEN ENTRY_NOT_FOUND THEN
status_out := -1001;
status_msg_out := 'No entry found in table blogs with id = '
|| id_inout;
/* Catch any other exceptions raised by Oracle */
WHEN OTHERS THEN
status_out := -1;
status_msg_out := 'Error:' || TO_CHAR (SQLCODE) || SQLERRM;
        
END edit_entry;

END blog;
/
The underlying table structure the procedures are using is:
CREATE SEQUENCE blog_id_seq
INCREMENT BY 1;
/
CREATE TABLE blogs (
id NUMBER PRIMARY KEY,
title VARCHAR2(200),
date_published DATE,
text CLOB
);
/
CREATE SEQUENCE category_id_seq
INCREMENT BY 1;

CREATE TABLE categories (
id NUMBER PRIMARY KEY,
name VARCHAR2(30) UNIQUE
);
/
CREATE TABLE blogs_to_categories (
blog_id INTEGER NOT NULL
REFERENCES blogs(id),
category_id INTEGER NOT NULL
REFERENCES categories(id),
PRIMARY KEY (blog_id, category_id)
);
/

存儲(chǔ)過(guò)程和引用游標(biāo)

看一下 blog.latest 過(guò)程,您將看到它返回一個(gè)用于迭代 blogs 表行的引用游標(biāo)关炼。

與直接從 SELECT 語(yǔ)句中訪問(wèn)行相比程腹,在 PHP 中使用游標(biāo)需要兩個(gè)額外的步驟。第一步是使用 oci_new_cursor() 函數(shù)(該函數(shù)隨后用于綁定到相應(yīng)的參數(shù))在 PHP 中準(zhǔn)備一個(gè)游標(biāo)資源儒拂。執(zhí)行 SQL 語(yǔ)句后寸潦,第二步是對(duì)游標(biāo)資源調(diào)用 oci_execute() 。

以下 PHP 腳本演示了該過(guò)程:

<?php 
$conn = oci_connect('SCOTT','TIGER') or die;


$sql = 'BEGIN blog.latest(:num_entries, :blog_entries); END;';

$stmt = oci_parse($conn, $sql);

// Bind the input num_entries argument to the $max_entries PHP variable
$max_entries = 5;
oci_bind_by_name($stmt,":num_entries",$max_entries,32);

// Create a new cursor resource
$blog_entries = oci_new_cursor($conn);

// Bind the cursor resource to the Oracle argument
oci_bind_by_name($stmt,":blog_entries",$blog_entries,-1,OCI_B_CURSOR);

// Execute the statement
oci_execute($stmt);

// Execute the cursor
oci_execute($blog_entries);

print "The $max_entries most recent blog entries\n";

// Use OCIFetchinto in the same way as you would with SELECT
while ($entry = oci_fetch_assoc($blog_entries, OCI_RETURN_LOBS )) {
print_r($entry);
}
?>

存儲(chǔ)過(guò)程和 LOB

Oracle Long 對(duì)象與存儲(chǔ)過(guò)程之間可以進(jìn)行相互傳遞社痛,方法與內(nèi)部的 SQL 之間進(jìn)行的相互傳遞幾乎相同见转。

以下示例演示了如何使用 CLOB 調(diào)用 blog.edit_entry 過(guò)程。該示例未向 id 參數(shù)分配值蒜哀,因此它相當(dāng)于插入一個(gè)新的網(wǎng)志條目:

<?php 
$conn = oci_connect('SCOTT','TIGER') or die;

$sql = 'BEGIN blog.edit_entry(:status, :status_msg, :id, :title,  :text, :categories); END;';

$stmt = oci_parse($conn,$sql);

$title = 'This is a test entry';

oci_bind_by_name($stmt,":status",$status,32);
oci_bind_by_name($stmt,":status_msg",$status_msg,500);
oci_bind_by_name($stmt,":id",$id,32);
oci_bind_by_name($stmt,":title",$title,200);

// Explained in the next example...(use an empty value for now)
$Categories = oci_new_collection($conn,'LIST_OF_NUMBERS');
oci_bind_by_name($stmt,':categories',$Categories,32,OCI_B_SQLT_NTY);

// Create a new lob descriptor object
$textLob = oci_new_descriptor($conn, OCI_D_LOB);

// Bind it to the parameter
oci_bind_by_name($stmt, ":text", $textLob, -1, OCI_B_CLOB);

// Execute the statement but do not commit
oci_execute($stmt, OCI_DEFAULT);

// The status parameter will be negative if the procedure encountered a problem
if ( !$status ) {
// Rollback the procedure
oci_rollback($conn);
die ("$status_msg\n");
}

// Save the body of the blog entry to the CLOB
if ( !$textLob->save('This is the body of the test entry') ) {
// Rollback the procedure
oci_rollback($conn);
die ("Error saving lob\n");
}

// Everything OK so commit
oci_commit($conn);
print $status_msg."\n";
?>

正如該腳本所演示的斩箫,關(guān)鍵問(wèn)題是如何在使用 LOB 時(shí)處理事務(wù)。由于更新 LOB 是一個(gè)分為兩階段的過(guò)程撵儿,因此您在此處選擇將所有事務(wù)處理委托給 PHP 腳本乘客。

注意,默認(rèn)情況下淀歇,Oracle 只允許在任何給定的會(huì)話中一次運(yùn)行一個(gè)事務(wù)易核。這意味著從 PHP 調(diào)用的過(guò)程中發(fā)出的 commit 或 rollback 語(yǔ)句將覆蓋對(duì) oci_commit() 或 oci_rollback() 的調(diào)用±四可以使用匿名事務(wù)(使用位于過(guò)程定義內(nèi)部的 pragma PRAGMA AUTONOMOUS_TRANSACTION 啟用)更改此行為牡直。例如缀匕,您可以在從其他過(guò)程中調(diào)用的日志記錄程序包中使用匿名事務(wù);使用這一方法您可以記錄有關(guān)存儲(chǔ)過(guò)程調(diào)用的信息碰逸,而不會(huì)干擾正在會(huì)話中運(yùn)行的事務(wù)乡小。

存儲(chǔ)過(guò)程和集合

集合是一種用于將復(fù)雜數(shù)據(jù)類型傳遞到存儲(chǔ)過(guò)程中的機(jī)制。在網(wǎng)志應(yīng)用程序中饵史,可以將網(wǎng)志條目歸檔到多個(gè)分類中(與“blogs”表和“categories”表之間的多對(duì)多關(guān)系相對(duì)應(yīng))满钟。

必須在數(shù)據(jù)庫(kù)中全局定義 Oracle 中的集合類型,在本示例中约急,您將使用以下定義:
CREATE OR REPLACE TYPE list_of_numbers AS VARRAY(50) OF NUMBER;
該定義允許您一次最多向 50 個(gè)類別分配一個(gè)網(wǎng)志條目零远,方法是將該類型的實(shí)例傳遞給 blog.edit_entry 過(guò)程。

在 PHP 中厌蔽,集合由預(yù)定義的 PHP 類 OCI-Collection 表示牵辣。可以通過(guò)調(diào)用 oci_new_collection() 函數(shù)創(chuàng)建此類實(shí)例奴饮。OCI-Collection 對(duì)象提供了以下方法:
append :將元素添加到集合末尾
assign :從現(xiàn)有集合中將元素添加到某個(gè)集合
assignElem :將值分配給集合纬向,并標(biāo)識(shí)應(yīng)將該元素置于的集合中的索引位置
free :釋放與集合句柄關(guān)聯(lián)的資源
getElem :從集合中的特殊索引位置檢索元素
max :返回集合中的最大元素?cái)?shù)
size :返回集合的當(dāng)前大小
trim :從集合末尾刪除一些元素
此處,您只希望使用 append 方法戴卜,因此可以將類別 ID 列表附加到過(guò)程調(diào)用逾条。在以下示例中,您將更新在前一個(gè)示例中創(chuàng)建的現(xiàn)有網(wǎng)志條目投剥,方法是將它的 ID 傳遞給 blog.edit_entry 過(guò)程以及類別 id 列表:

<?php 
$conn = oci_connect('SCOTT','TIGER') or die;


$sql = 'BEGIN blog.edit_entry(:status, :status_msg, :id, :title, :text, :categories); END;';

$stmt = oci_parse($conn, $sql);

$id = 1; // ID of the new entry
$title = 'This is a test entry (v2)';

oci_bind_by_name($stmt,":status",$status,32);
oci_bind_by_name($stmt,":status_msg",$status_msg,500);
oci_bind_by_name($stmt,":id",$id,32);
oci_bind_by_name($stmt,":title",$title,200);
$textLob = oci_new_descriptor($conn, OCI_D_LOB);
oci_bind_by_name($stmt, ":text", $textLob, -1, OCI_B_CLOB);

// Create an OCI-Collection object
$Categories = oci_new_collection($conn,'LIST_OF_NUMBERS');

// Append some category IDs to the collection;
$Categories->append(2);
$Categories->append(4);
$Categories->append(5);

// Bind the collection to the parameter
oci_bind_by_name($stmt,':categories',$Categories,-1,OCI_B_SQLT_NTY);

oci_execute($stmt, OCI_DEFAULT);

if ( !$status ) {
oci_rollback($conn);
die ("$status_msg\n");
}

if ( !$textLob->save('This is the body of the test entry [v2]') ) {
oci_rollback($conn);
die ("Error saving lob\n");
}

oci_commit($conn);
print $status_msg."\n";
?>

結(jié)論

您現(xiàn)在已經(jīng)了解了有關(guān)如何從 PHP 中調(diào)用存儲(chǔ)過(guò)程(既包括只涉及標(biāo)量數(shù)據(jù)類型的簡(jiǎn)單過(guò)程师脂,也包含更復(fù)雜的使用 LOB、游標(biāo)和集合的過(guò)程)的示例江锨。還對(duì)存儲(chǔ)過(guò)程的定義進(jìn)行了足夠的了解吃警,能讀懂它們的 PL/SQL 規(guī)范,這樣您就可以從 PHP 中正確地調(diào)用它們并綁定相應(yīng)的類型啄育。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酌心,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挑豌,更是在濱河造成了極大的恐慌安券,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氓英,死亡現(xiàn)場(chǎng)離奇詭異侯勉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)债蓝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門壳鹤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人饰迹,你說(shuō)我怎么就攤上這事芳誓。” “怎么了啊鸭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵锹淌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我赠制,道長(zhǎng)赂摆,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任钟些,我火速辦了婚禮烟号,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘政恍。我一直安慰自己汪拥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布篙耗。 她就那樣靜靜地躺著迫筑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宗弯。 梳的紋絲不亂的頭發(fā)上脯燃,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音蒙保,去河邊找鬼辕棚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛邓厕,可吹牛的內(nèi)容都是我干的逝嚎。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼邑狸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼懈糯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起单雾,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赚哗,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后硅堆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屿储,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年渐逃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了够掠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茄菊,死狀恐怖疯潭,靈堂內(nèi)的尸體忽然破棺而出赊堪,到底是詐尸還是另有隱情,我是刑警寧澤竖哩,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布哭廉,位于F島的核電站,受9級(jí)特大地震影響相叁,放射性物質(zhì)發(fā)生泄漏遵绰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一增淹、第九天 我趴在偏房一處隱蔽的房頂上張望椿访。 院中可真熱鬧,春花似錦虑润、人聲如沸成玫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)梁剔。三九已至,卻和暖如春舞蔽,著一層夾襖步出監(jiān)牢的瞬間荣病,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工渗柿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留个盆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓朵栖,卻偏偏與公主長(zhǎng)得像颊亮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陨溅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • oracle存儲(chǔ)過(guò)程常用技巧 我們?cè)谶M(jìn)行pl/sql編程時(shí)打交道最多的就是存儲(chǔ)過(guò)程了终惑。存儲(chǔ)過(guò)程的結(jié)構(gòu)是非常的簡(jiǎn)單的...
    dertch閱讀 3,499評(píng)論 1 12
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法门扇,內(nèi)部類的語(yǔ)法雹有,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法臼寄,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,665評(píng)論 18 399
  • 1.1 基本結(jié)構(gòu) PL/SQL程序由三個(gè)塊組成霸奕,即聲明部分、執(zhí)行部分吉拳、異常處理部分质帅。 1.2 命名規(guī)則 1.3 記...
    慢清塵閱讀 3,853評(píng)論 3 14
  • 我們?cè)谶M(jìn)行pl/sql編程時(shí)打交道最多的就是存儲(chǔ)過(guò)程了。存儲(chǔ)過(guò)程的結(jié)構(gòu)是非常的簡(jiǎn)單的,我們?cè)谶@里除了學(xué)習(xí)存儲(chǔ)過(guò)程的...
    AlbenXie閱讀 2,973評(píng)論 1 3
  • 故煤惩,此生世事何為嫉嘀,你看那江山如漾,誰(shuí)又舍你一瓢一粒到襄陽(yáng)盟庞,你只管上馬仗劍吃沪,霸道擎天一腳蹬翻塵世浪汤善,老來(lái)去說(shuō)老混賬什猖。
    尤冉閱讀 275評(píng)論 0 1