第五十章. 函數
用戶可調用的函數的參考.
注意:本節需要人來寫.願當支援者嗎?
第五十一章. 大對象
內容
歷史信息
實現的特點
接口
內建的已注冊函數
從 LIBPQ 裡訪問大對象
例子程序
在 Postgres 裡,記錄存儲在數據頁面裡並且單個記錄裡的數據大小不能超過數據頁面的大小.因為數據頁面大小是 8192 字節,所以數據值的大小是相當小的.為了存儲更大的不可分割數值(原子數值),Postgres 提供了大對象接口.這個接口給用戶提供對定義為大對象的用戶數據的面向文件的接口.本節描述 Postgres 大對象數據的實現,編程和查詢語言接口.
歷史信息
最初,Postgres 4.2 支持三種大對象的標準實現:作為 Postgres 的文件擴展,作為由 Postgres 管理的 UNIX 文件,以及作為存儲在 Postgres 數據庫裡面的數據.這樣做容易導致用戶的迷惑.結果是,我們只支持把大對象作為數據存儲在Postgres 數據庫裡,即使這樣做令數據訪問變得有些慢,但卻保証了更嚴格的數據完整性.由歷史原因,這種存儲機制被稱為倒轉大對象.(我們將在本章中交互使用倒轉和大對象來表示同一個意思)。
--------------------------------------------------------------------------------
實現的特點
倒轉大對象把大對象分解成"塊" ("chunks"),然把塊存放在數據庫記錄裡面.在隨機讀寫時使用一個B-tree 索引保証對正確的塊(chunk)號的檢索.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
接口
Postgres 提供的用訪問大對象的機制,包括作為用戶定義函數的端的一部分或者作為使用接口的前端應用的一部分,都在下面描述.對熟悉 Postgres 4.2 的用戶,PostgreSQL 有一套新的函數提供更連貫的接口.
注意:所有大對象的操作都必須在一個SQL事務裡實現。這在 Postgres v6.5 裡有嚴格的要求,盡管在以前的版本裡就隱含這樣的要求,如果忽略這一點會導致錯誤的表現。
Postgres 大對象接口是對 UNIX 文件系統的模仿,有仿真的 open(2),read(2),write(2),lseek(2),等.用戶函數調用這些路徑從一個大對象中檢索她們感興趣的數據.例如,如果一個名為 mugshot 的大對象類型存在,在其中保存面孔的圖象,那可以在 mugshot 數據上定義一個叫 beard (胡子)的函數.Beard (胡子函數)會檢查圖片的下三分之一區域,並且如果存在胡子的話判斷胡子的顏色.整個大對象的值不需要被 brard 函數緩存起來或者甚至是作些檢查.大對象可以從動態裝載的 C 函數或者是鏈接該庫的數據庫客戶程序訪問.Postgres 提供一套過程支持對大對象的打開,讀,寫,關閉和搜索。
創建大對象
過程
Oid lo_creat(PGconn *conn, int mode)
創建一個新的大對象.mode 是一個位掩碼,描述新對象的不同屬性.這裡列出的符號常量在 $PGROOT/src/backend/libpq/libpq-fs.h.訪問類型(讀,寫或者兩者)是對位 INV_READ 和 INV_WRITE進行 OR (或)操作構成的.如果大對象應被歸檔--也就是說,如果因歷史原因它應該被周期地移到一個特殊的歸檔關系(表)中--那就要設置 INV_ARCHIVE 位.掩碼的低十六位是大對象要存放內的存儲管理器號.對除 Berkeley (伯克利)以外的節點,這些位都應總是零.下面的命令創建一個(倒轉的)大對象:
inv_oid = lo_creat(INV_READ|INV_WRITE|INV_ARCHIVE);
輸入大對象
要把一個 UNIX 文件輸入成為大對象,調用
Oid lo_import(PGconn *conn, const char *filename)
filename 參數指明要被輸入成為大對象的 UNIX 文件路徑名.
輸出大對象
要把一個大對象輸出為 UNIX 文件,調用
int lo_export(PGconn *conn, Oid lobjId, const char *filename)
lobjId 參數指明要輸出的大對象 Oid,filename 參數指明 UNIX 文件的路徑名.
打開一個現有的大對象
要打開一個現存的大對象,調用
int lo_open(PGconn *conn, Oid lobjId, int mode)
參數 lobjId 指明要打開的大對象的 Oid (對象標識).mode 位控制該對象是用讀(INV_READ),寫還是讀寫.一個大對象在其創建之前不能被打開.lo_open 返回一個大對象標識用以的 lo_read,lo_write,lo_lseek,lo_tell,and lo_close。
向大對象中寫數據
過程
int lo_write(PGconn *conn, int fd, const char *buf, size_t len)
從 buf 中向大對象 fd 中寫 len 字節.參數 fd 必須是前面一個 lo_open 的返回.返回實際寫的字節數.出錯時返回負數.
從大對象中讀取數據
過程
int lo_read(PGconn *conn, int fd, char *buf, size_t len)
從大對象中讀取 len 字節數據到 buf 中。fd 參數必須是前面的一個 lo_open 調用的返回。返回實際讀取的字節數。出錯時,返回一個負數。
對大對象中數據的查找
要改變當前大對象的讀或寫位置,調用
int lo_lseek(PGconn *conn, int fd, int offset, int whence)
這個過程把當前 fd 代表的大對象位置指針移動到 offset 指明的新的位置.參數 whence 的合法的取值是 SEEK_SET SEEK_CUR 和 SEEK_END.
關閉一個大對象描述符
可以通過調用
int lo_close(PGconn *conn, int fd)
關閉一個大對象,這裡 fd 是 lo_open 返回的大對象的描述符.成功時,lo_close 返回零.錯誤時,返回值是負數.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
內建的已注冊函數
有兩個內建的已注冊函數,lo_import 和 lo_export 可以很方便的在 SQL 查詢裡面使用.下面是一些例子
CREATE TABLE image (
name text,
raster oid
);
INSERT INTO image (name, raster)
VALUES ('beautiful image', lo_import('/etc/motd'));
SELECT lo_export(image.raster, '/tmp/motd') from image
WHERE name = 'beautiful image';
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
通過 LIBPQ 訪問大對象
下面是一個例子程序,顯示如何使用 LIBPQ 裡大對象接口的.程序的一部分是注釋掉的,但仍然保留在源碼裡面供讀者參考.這個程序可以在 ../src/test/examples 裡找到.使用 LIBPQ 裡大對象接口的前端應用應該包括頭文件libpq/libpq-fs.h 並且聯接 libpq 庫.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
例子程序
/*--------------------------------------------------------------
*
* testlo.c--
* test using large objects with libpq
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* /usr/local/devel/pglite/cvs/src/doc/manual.me,v 1.16 1995/09/01 23:55:00 jolly Exp
*
*--------------------------------------------------------------
*/
#include
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#define BUFSIZE 1024
/*
* importFile * import file "in_filename" into database as large object "lobjOid"
*
*/
Oid importFile(PGconn *conn, char *filename)
{
Oid lobjId;
int lobj_fd;
char buf[BUFSIZE];
int nbytes, tmp;
int fd;
/*
* open the file to be read in
*/
fd = open(filename, O_RDONLY, 0666);
if (fd < 0) { /* error */
fprintf(stderr, "can't open unix file %s\n", filename);
}
/*
* create the large object
*/
lobjId = lo_creat(conn, INV_READ|INV_WRITE);
if (lobjId == 0) {
fprintf(stderr, "can't create large object\n");
}
lobj_fd = lo_open(conn, lobjId, INV_WRITE);
/*
* read in from the Unix file and write to the inversion file
*/
while ((nbytes = read(fd, buf, BUFSIZE)) > 0) {
tmp = lo_write(conn, lobj_fd, buf, nbytes);
if (tmp < nbytes) {
fprintf(stderr, "error while reading large object\n");
}
}
(void) close(fd);
(void) lo_close(conn, lobj_fd);
return lobjId;
}
void pickout(PGconn *conn, Oid lobjId, int start, int len)
{
int lobj_fd;
char* buf;
int nbytes;
int nread;
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0) {
fprintf(stderr,"can't open large object %d\n",
lobjId);
}
lo_lseek(conn, lobj_fd, start, SEEK_SET);
buf = malloc(len+1);
nread = 0;
while (len - nread > 0) {
nbytes = lo_read(conn, lobj_fd, buf, len - nread);
buf[nbytes] = ' ';
fprintf(stderr,">>> %s", buf);
nread += nbytes;
}
fprintf(stderr,"\n");
lo_close(conn, lobj_fd);
}
void overwrite(PGconn *conn, Oid lobjId, int start, int len)
{
int lobj_fd;
char* buf;
int nbytes;
int nwritten;
int i;
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0) {
fprintf(stderr,"can't open large object %d\n",
lobjId);
}
lo_lseek(conn, lobj_fd, start, SEEK_SET);
buf = malloc(len+1);
for (i=0;i buf[i] = 'X';
buf[i] = ' ';
nwritten = 0;
while (len - nwritten > 0) {
nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten);
nwritten += nbytes;
}
fprintf(stderr,"\n");
lo_close(conn, lobj_fd);
}
/*
* exportFile * export large object "lobjOid" to file "out_filename"
*
*/
void exportFile(PGconn *conn, Oid lobjId, char *filename)
{
int lobj_fd;
char buf[BUFSIZE];
int nbytes, tmp;
int fd;
/*
* create an inversion "object"
*/
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0) {
fprintf(stderr,"can't open large object %d\n",
lobjId);
}
/*
* open the file to be written to
*/
fd = open(filename, O_CREAT|O_WRONLY, 0666);
if (fd < 0) { /* error */
fprintf(stderr, "can't open unix file %s\n",
filename);
}
/*
* read in from the Unix file and write to the inversion file
*/
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) {
tmp = write(fd, buf, nbytes);
if (tmp < nbytes) {
fprintf(stderr,"error while writing %s\n",
filename);
}
}
(void) lo_close(conn, lobj_fd);
(void) close(fd);
return;
}
void
exit_nicely(PGconn* conn)
{
PQfinish(conn);
exit(1);
}
int
main(int argc, char **argv)
{
char *in_filename, *out_filename;
char *database;
Oid lobjOid;
PGconn *conn;
PGresult *res;
if (argc != 4) {
fprintf(stderr, "Usage: %s database_name in_filename out_filename\n",
argv[0]);
exit(1);
}
database = argv[1];
in_filename = argv[2];
out_filename = argv[3];
/*
* set up the connection
*/
conn = PQsetdb(NULL, NULL, NULL, NULL, database);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", database);
fprintf(stderr,"%s",PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn, "begin");
PQclear(res);
printf("importing file %s\n", in_filename);
/* lobjOid = importFile(conn, in_filename); */
lobjOid = lo_import(conn, in_filename);
/*
printf("as large object %d.\n", lobjOid);
printf("picking out bytes 1000-2000 of the large object\n");
pickout(conn, lobjOid, 1000, 1000);
printf("overwriting bytes 1000-2000 of the large object with X's\n");
overwrite(conn, lobjOid, 1000, 1000);
*/
printf("exporting large object to file %s\n", out_filename);
/* exportFile(conn, lobjOid, out_filename); */
lo_export(conn, lobjOid,out_filename);
res = PQexec(conn, "end");
PQclear(res);
PQfinish(conn);
exit(0);
}
--------------------------------------------------------------------------------
(http://www.fanqiang.com)
進入【UNIX論壇】
|