PDO 直接 SELECT clob_col FROM table 當字段超過驅動/內存限制時會截斷或報錯,需分片讀取並拼接。
CREATE OR REPLACE PROCEDURE get_clob(
t_name IN VARCHAR2, -- 表名
f_name IN VARCHAR2, -- 字段名
u_id IN INTEGER, -- 主鍵值
l_pos IN INTEGER, -- 起始位置 (1-based)
l_amt IN BINARY_INTEGER, -- 讀取長度
ret_val OUT VARCHAR2 -- 返回片段
) IS
v_clob CLOB;
v_buf VARCHAR2(3999);
v_amt BINARY_INTEGER;
BEGIN
EXECUTE IMMEDIATE 'SELECT '||f_name||' FROM '||t_name||' WHERE id=:1'
INTO v_clob USING u_id;
v_amt := l_amt;
DBMS_LOB.READ(v_clob, v_amt, l_pos, v_buf);
ret_val := v_buf;
END get_clob;
/
$pdo = new PDO('oci:dbname=//host:1521/sid', $user, $pass);
// 1. 先查總長度
$stmt = $pdo->prepare("SELECT LENGTH(content) AS len FROM test WHERE id = :id");
$stmt->execute(['id' => $id]);
$total = (int)$stmt->fetchColumn();
// 2. 循環讀取拼接
$content = '';
$chunk = 2500; // 每片長度 (<= 32767)
$start = 1;
while ($start <= $total) {
$ret = '';
$sql = "BEGIN get_clob(?,?,?,?,?,?); END;";
$st = $pdo->prepare($sql);
$st->bindParam(1, 'test', PDO::PARAM_STR, 100);
$st->bindParam(2, 'content', PDO::PARAM_STR, 100);
$st->bindParam(3, $id, PDO::PARAM_STR, 100);
$st->bindParam(4, $start, PDO::PARAM_STR, 100);
$st->bindParam(5, $chunk, PDO::PARAM_STR, 100);
$st->bindParam(6, $ret, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 5000);
$st->execute();
$content .= $ret;
$start += $chunk;
}
$pdo = null;
echo $content; // 完整 CLOB 內容
DBMS_LOB.READ 支援任意位置/長度讀取,避免一次性載入巨大 LOB。EXECUTE IMMEDIATE) 實現表/字段參數化,通用性強。PARAM_INPUT_OUTPUT 接收 OUT 參數,5000 需大於片段長度。TO_LOB / DBMS_LOB.CONVERTTOBLOB 配合 SELECT ... FROM TABLE(CAST(...))。oci_fetch_array + OCI_LOB->read() 流式讀取。DBMS_LOB.SUBSTR(clob, 4000, offset) 避免存儲過程。