支援的版本: 目前 (17) / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

34.7. 使用描述區 (Descriptor Areas) #

SQL 描述區是一種更複雜的方法,用於處理 SELECTFETCHDESCRIBE 陳述式的結果。SQL 描述區將一列資料的資料與中繼資料項目分組到一個資料結構中。當中繼資料對於執行動態 SQL 陳述式特別有用,因為結果欄位的性質可能事先未知。PostgreSQL 提供了兩種使用描述區的方法:具名 SQL 描述區和 C 結構 SQLDA。

34.7.1. 具名 SQL 描述區 (Named SQL Descriptor Areas) #

具名 SQL 描述區由一個標頭組成,其中包含有關整個描述符的資訊,以及一個或多個項目描述區,這些區域基本上每個都描述結果列中的一個欄位。

在使用 SQL 描述區之前,您需要分配一個

EXEC SQL ALLOCATE DESCRIPTOR identifier;

識別碼作為描述區的變數名稱。當您不再需要描述符時,應取消分配它

EXEC SQL DEALLOCATE DESCRIPTOR identifier;

要使用描述區,請在 INTO 子句中將其指定為儲存目標,而不是列出主機變數

EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc;

如果結果集為空,描述區仍然包含來自查詢的中繼資料,即欄位名稱。

對於尚未執行的預備查詢,可以使用 DESCRIBE 陳述式來取得結果集的中繼資料

EXEC SQL BEGIN DECLARE SECTION;
char *sql_stmt = "SELECT * FROM table1";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE stmt1 FROM :sql_stmt;
EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc;

在 PostgreSQL 9.0 之前,SQL 關鍵字是可選的,因此使用 DESCRIPTORSQL DESCRIPTOR 會產生具名 SQL 描述區。現在它是強制性的,省略 SQL 關鍵字會產生 SQLDA 描述區,請參閱第 34.7.2 節

DESCRIBEFETCH 陳述式中,可以使用 INTOUSING 關鍵字來類似地操作:它們在描述區中產生結果集和中繼資料。

現在,您如何從描述區中取得資料?您可以將描述區視為具有具名欄位的結構。要從標頭中檢索欄位的值並將其儲存到主機變數中,請使用以下命令

EXEC SQL GET DESCRIPTOR name :hostvar = field;

目前,僅定義了一個標頭欄位:COUNT,它告訴您存在多少個項目描述區(也就是說,結果中包含多少個欄位)。主機變數需要是整數類型。要從項目描述區取得欄位,請使用以下命令

EXEC SQL GET DESCRIPTOR name VALUE num :hostvar = field;

num 可以是文字整數或包含整數的主機變數。可能的欄位是

CARDINALITY (整數) #

結果集中的列數

DATA #

實際資料項目(因此,此欄位的資料類型取決於查詢)

DATETIME_INTERVAL_CODE (整數) #

TYPE9 時,DATETIME_INTERVAL_CODE 對於 DATE 將具有值 1,對於 TIME 將具有值 2,對於 TIMESTAMP 將具有值 3,對於 TIME WITH TIME ZONE 將具有值 4,或者對於 TIMESTAMP WITH TIME ZONE 將具有值 5

DATETIME_INTERVAL_PRECISION (整數) #

未實作

INDICATOR (整數) #

指示器(指示空值或值截斷)

KEY_MEMBER (整數) #

未實作

LENGTH (整數) #

資料中字元的長度

NAME (字串) #

欄位的名稱

NULLABLE (整數) #

未實作

OCTET_LENGTH (整數) #

以位元組為單位的資料字元表示的長度

PRECISION (整數) #

精度(對於 numeric 類型)

RETURNED_LENGTH (整數) #

資料中字元的長度

RETURNED_OCTET_LENGTH (整數) #

以位元組為單位的資料字元表示的長度

SCALE (整數) #

小數位數(對於 numeric 類型)

TYPE (整數) #

欄位資料型態的數字代碼

EXECUTEDECLAREOPEN 語句中,INTOUSING 關鍵字的效果是不同的。 描述區 (Descriptor Area) 也可以手動建立,以提供查詢或游標的輸入參數,而 USING SQL DESCRIPTOR name 是將輸入參數傳遞到參數化查詢的方式。 建立具名 SQL 描述區的語法如下:

EXEC SQL SET DESCRIPTOR name VALUE num field = :hostvar;

PostgreSQL 支援在一個 FETCH 語句中檢索多個記錄,並將資料儲存在主機變數中,在這種情況下,假設該變數是一個陣列。例如:

EXEC SQL BEGIN DECLARE SECTION;
int id[5];
EXEC SQL END DECLARE SECTION;

EXEC SQL FETCH 5 FROM mycursor INTO SQL DESCRIPTOR mydesc;

EXEC SQL GET DESCRIPTOR mydesc VALUE 1 :id = DATA;

34.7.2. SQLDA 描述區 #

SQLDA 描述區是一個 C 語言結構,也可以用於獲取查詢的結果集和元資料。 一個結構儲存結果集中的一個記錄。

EXEC SQL include sqlda.h;
sqlda_t         *mysqlda;

EXEC SQL FETCH 3 FROM mycursor INTO DESCRIPTOR mysqlda;

請注意,SQL 關鍵字已省略。 關於 INTOUSING 關鍵字在 第 34.7.1 節 中的使用案例的段落也適用於此,但有一個補充。 在 DESCRIBE 語句中,如果使用 INTO 關鍵字,則可以完全省略 DESCRIPTOR 關鍵字

EXEC SQL DESCRIBE prepared_statement INTO mysqlda;

使用 SQLDA 的程式的一般流程是

  1. 準備一個查詢,並為它宣告一個游標。

  2. 為結果列宣告一個 SQLDA。

  3. 為輸入參數宣告一個 SQLDA,並初始化它們(記憶體配置、參數設定)。

  4. 使用輸入 SQLDA 開啟游標。

  5. 從游標中提取列,並將它們儲存到輸出 SQLDA 中。

  6. 從輸出 SQLDA 中讀取數值到主機變數中(如有必要,進行轉換)。

  7. 關閉游標。

  8. 釋放為輸入 SQLDA 分配的記憶體區域。

34.7.2.1. SQLDA 資料結構 #

SQLDA 使用三種資料結構類型:sqlda_tsqlvar_tstruct sqlname

提示

PostgreSQL 的 SQLDA 具有與 IBM DB2 Universal Database 中相似的資料結構,因此一些關於 DB2 SQLDA 的技術資訊可能有助於更好地理解 PostgreSQL 的 SQLDA。

34.7.2.1.1. sqlda_t 結構 #

結構類型 sqlda_t 是實際 SQLDA 的類型。它儲存一個記錄。 並且兩個或多個 sqlda_t 結構可以透過 desc_next 欄位中的指標連接到一個連結串列中,從而表示一個有序的列集合。 因此,當提取兩個或多個列時,應用程式可以透過追蹤每個 sqlda_t 節點中的 desc_next 指標來讀取它們。

sqlda_t 的定義是

struct sqlda_struct
{
    char            sqldaid[8];
    long            sqldabc;
    short           sqln;
    short           sqld;
    struct sqlda_struct *desc_next;
    struct sqlvar_struct sqlvar[1];
};

typedef struct sqlda_struct sqlda_t;

欄位的含義是

sqldaid #

它包含文字字串 "SQLDA "

sqldabc #

它包含以位元組為單位的已分配空間的大小。

sqln #

如果使用 USING 關鍵字傳遞到 OPENDECLAREEXECUTE 語句中,它包含參數化查詢的輸入參數的數量。 如果它用作 SELECTEXECUTEFETCH 語句的輸出,則其值與 sqld 語句相同

sqld #

它包含結果集中的欄位數量。

desc_next #

如果查詢傳回多個記錄,則會傳回多個連結的 SQLDA 結構,並且 desc_next 保存指向列表中下一個條目的指標。

sqlvar #

這是結果集中的欄位陣列。

34.7.2.1.2. sqlvar_t 結構 #

結構類型 sqlvar_t 保存欄位值和元資料,例如類型和長度。 該類型的定義是

struct sqlvar_struct
{
    short          sqltype;
    short          sqllen;
    char          *sqldata;
    short         *sqlind;
    struct sqlname sqlname;
};

typedef struct sqlvar_struct sqlvar_t;

欄位的含義是

sqltype #

包含欄位的類型識別符。 有關數值,請參閱 ecpgtype.h 中的 enum ECPGttype

sqllen #

包含欄位的二進位長度。 例如,ECPGt_int 為 4 個位元組。

sqldata #

指向資料。 資料的格式在 第 34.4.4 節 中進行了描述。

sqlind #

指向空值指示器。 0 表示非空值,-1 表示空值。

sqlname #

欄位的名稱。

34.7.2.1.3. struct sqlname 結構 #

struct sqlname 結構保存欄位名稱。 它用作 sqlvar_t 結構的成員。 該結構的定義是

#define NAMEDATALEN 64

struct sqlname
{
        short           length;
        char            data[NAMEDATALEN];
};

欄位的含義是

length #

包含欄位名稱的長度。

data #

包含實際的欄位名稱。

34.7.2.2. 使用 SQLDA 檢索結果集 #

透過 SQLDA 檢索查詢結果集的一般步驟是

  1. 宣告一個 sqlda_t 結構以接收結果集。

  2. 執行 FETCH/EXECUTE/DESCRIBE 命令來處理指定宣告的 SQLDA 的查詢。

  3. 透過查看 sqlda_t 結構的成員 sqln 來檢查結果集中的記錄數。

  4. sqlda_t 結構的成員 sqlvar[0]sqlvar[1] 等獲取每個欄位的值。

  5. 透過追蹤 sqlda_t 結構中的成員 desc_next 指標,前往下一列(sqlda_t 結構)。

  6. 視您的需要重複上述步驟。

以下範例展示如何透過 SQLDA 擷取結果集。

首先,宣告一個 sqlda_t 結構來接收結果集。

sqlda_t *sqlda1;

接著,在指令中指定 SQLDA。這是一個 FETCH 指令的範例。

EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

執行迴圈追蹤鏈結串列以擷取列。

sqlda_t *cur_sqlda;

for (cur_sqlda = sqlda1;
     cur_sqlda != NULL;
     cur_sqlda = cur_sqlda->desc_next)
{
    ...
}

在迴圈內部,執行另一個迴圈以擷取該列的每個欄位資料(sqlvar_t 結構)。

for (i = 0; i < cur_sqlda->sqld; i++)
{
    sqlvar_t v = cur_sqlda->sqlvar[i];
    char *sqldata = v.sqldata;
    short sqllen  = v.sqllen;
    ...
}

若要取得欄位值,請檢查 sqlvar_t 結構的成員 sqltype 的值。然後,根據欄位類型,切換到適當的方式,將資料從 sqlvar 欄位複製到主機變數。

char var_buf[1024];

switch (v.sqltype)
{
    case ECPGt_char:
        memset(&var_buf, 0, sizeof(var_buf));
        memcpy(&var_buf, sqldata, (sizeof(var_buf) <= sqllen ? sizeof(var_buf) - 1 : sqllen));
        break;

    case ECPGt_int: /* integer */
        memcpy(&intval, sqldata, sqllen);
        snprintf(var_buf, sizeof(var_buf), "%d", intval);
        break;

    ...
}

34.7.2.3. 使用 SQLDA 傳遞查詢參數 #

使用 SQLDA 傳遞輸入參數到預備查詢的一般步驟如下:

  1. 建立預備查詢(prepared statement)。

  2. 宣告一個 sqlda_t 結構作為輸入 SQLDA。

  3. 為輸入 SQLDA 配置記憶體區域(作為 sqlda_t 結構)。

  4. 在已配置的記憶體中設定(複製)輸入值。

  5. 使用指定的輸入 SQLDA 開啟游標。

以下是一個範例。

首先,建立一個預備語句。

EXEC SQL BEGIN DECLARE SECTION;
char query[1024] = "SELECT d.oid, * FROM pg_database d, pg_stat_database s WHERE d.oid = s.datid AND (d.datname = ? OR d.oid = ?)";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE stmt1 FROM :query;

接著,為 SQLDA 配置記憶體,並在 sqlda_t 結構的成員變數 sqln 中設定輸入參數的數量。當預備查詢需要兩個或更多個輸入參數時,應用程式必須配置額外的記憶體空間,其計算方式為 (參數數量 - 1) * sizeof(sqlvar_t)。此處顯示的範例為兩個輸入參數配置記憶體空間。

sqlda_t *sqlda2;

sqlda2 = (sqlda_t *) malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));

sqlda2->sqln = 2; /* number of input variables */

在記憶體配置後,將參數值儲存到 sqlvar[] 陣列中。(這與 SQLDA 接收結果集時用於擷取欄位值的相同陣列。)在本範例中,輸入參數為具有字串類型的 "postgres" 和具有整數類型的 1

sqlda2->sqlvar[0].sqltype = ECPGt_char;
sqlda2->sqlvar[0].sqldata = "postgres";
sqlda2->sqlvar[0].sqllen  = 8;

int intval = 1;
sqlda2->sqlvar[1].sqltype = ECPGt_int;
sqlda2->sqlvar[1].sqldata = (char *) &intval;
sqlda2->sqlvar[1].sqllen  = sizeof(intval);

透過開啟游標並指定先前設定的 SQLDA,輸入參數會傳遞到預備語句。

EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

最後,在使用輸入 SQLDA 之後,必須明確釋放已配置的記憶體空間,這與用於接收查詢結果的 SQLDA 不同。

free(sqlda2);

34.7.2.4. 使用 SQLDA 的範例應用程式 #

以下是一個範例程式,描述如何從系統目錄中擷取由輸入參數指定的資料庫存取統計資訊。

此應用程式將兩個系統表 pg_database 和 pg_stat_database 依據資料庫 OID 進行 JOIN,並且擷取並顯示由兩個輸入參數(一個資料庫 postgres 和 OID 1)擷取的資料庫統計資訊。

首先,宣告一個用於輸入的 SQLDA 和一個用於輸出的 SQLDA。

EXEC SQL include sqlda.h;

sqlda_t *sqlda1; /* an output descriptor */
sqlda_t *sqlda2; /* an input descriptor  */

接著,連接到資料庫,準備語句,並為預備語句宣告一個游標。

int
main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char query[1024] = "SELECT d.oid,* FROM pg_database d, pg_stat_database s WHERE d.oid=s.datid AND ( d.datname=? OR d.oid=? )";
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT TO testdb AS con1 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

    EXEC SQL PREPARE stmt1 FROM :query;
    EXEC SQL DECLARE cur1 CURSOR FOR stmt1;

接著,將一些值放入輸入 SQLDA 中,以用於輸入參數。為輸入 SQLDA 配置記憶體,並將輸入參數的數量設定為 sqln。將類型、值和值長度儲存到 sqlvar 結構中的 sqltypesqldatasqllen

    /* Create SQLDA structure for input parameters. */
    sqlda2 = (sqlda_t *) malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
    memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));
    sqlda2->sqln = 2; /* number of input variables */

    sqlda2->sqlvar[0].sqltype = ECPGt_char;
    sqlda2->sqlvar[0].sqldata = "postgres";
    sqlda2->sqlvar[0].sqllen  = 8;

    intval = 1;
    sqlda2->sqlvar[1].sqltype = ECPGt_int;
    sqlda2->sqlvar[1].sqldata = (char *)&intval;
    sqlda2->sqlvar[1].sqllen  = sizeof(intval);

在設定輸入 SQLDA 後,使用輸入 SQLDA 開啟游標。

    /* Open a cursor with input parameters. */
    EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

從開啟的游標將列擷取到輸出 SQLDA。(通常,您必須在迴圈中重複呼叫 FETCH,才能擷取結果集中的所有列。)

    while (1)
    {
        sqlda_t *cur_sqlda;

        /* Assign descriptor to the cursor  */
        EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

接著,透過追蹤 sqlda_t 結構的鏈結串列,從 SQLDA 擷取擷取的紀錄。

    for (cur_sqlda = sqlda1 ;
         cur_sqlda != NULL ;
         cur_sqlda = cur_sqlda->desc_next)
    {
        ...

讀取第一筆紀錄中的每個欄位。欄位的數量儲存在 sqld 中,第一欄的實際資料儲存在 sqlvar[0] 中,兩者都是 sqlda_t 結構的成員。

        /* Print every column in a row. */
        for (i = 0; i < sqlda1->sqld; i++)
        {
            sqlvar_t v = sqlda1->sqlvar[i];
            char *sqldata = v.sqldata;
            short sqllen  = v.sqllen;

            strncpy(name_buf, v.sqlname.data, v.sqlname.length);
            name_buf[v.sqlname.length] = '\0';

現在,欄位資料儲存在變數 v 中。查看 v.sqltype 以取得欄位的類型,然後將每個資料複製到主機變數中。

            switch (v.sqltype) {
                int intval;
                double doubleval;
                unsigned long long int longlongval;

                case ECPGt_char:
                    memset(&var_buf, 0, sizeof(var_buf));
                    memcpy(&var_buf, sqldata, (sizeof(var_buf) <= sqllen ? sizeof(var_buf)-1 : sqllen));
                    break;

                case ECPGt_int: /* integer */
                    memcpy(&intval, sqldata, sqllen);
                    snprintf(var_buf, sizeof(var_buf), "%d", intval);
                    break;

                ...

                default:
                    ...
            }

            printf("%s = %s (type: %d)\n", name_buf, var_buf, v.sqltype);
        }

在處理完所有紀錄後,關閉游標,並與資料庫斷線。

    EXEC SQL CLOSE cur1;
    EXEC SQL COMMIT;

    EXEC SQL DISCONNECT ALL;

整個程式顯示在範例 34.1中。

範例 34.1. SQLDA 程式範例

#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

EXEC SQL include sqlda.h;

sqlda_t *sqlda1; /* descriptor for output */
sqlda_t *sqlda2; /* descriptor for input */

EXEC SQL WHENEVER NOT FOUND DO BREAK;
EXEC SQL WHENEVER SQLERROR STOP;

int
main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char query[1024] = "SELECT d.oid,* FROM pg_database d, pg_stat_database s WHERE d.oid=s.datid AND ( d.datname=? OR d.oid=? )";

    int intval;
    unsigned long long int longlongval;
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT TO uptimedb AS con1 USER uptime;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

    EXEC SQL PREPARE stmt1 FROM :query;
    EXEC SQL DECLARE cur1 CURSOR FOR stmt1;

    /* Create an SQLDA structure for an input parameter */
    sqlda2 = (sqlda_t *)malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
    memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));
    sqlda2->sqln = 2; /* a number of input variables */

    sqlda2->sqlvar[0].sqltype = ECPGt_char;
    sqlda2->sqlvar[0].sqldata = "postgres";
    sqlda2->sqlvar[0].sqllen  = 8;

    intval = 1;
    sqlda2->sqlvar[1].sqltype = ECPGt_int;
    sqlda2->sqlvar[1].sqldata = (char *) &intval;
    sqlda2->sqlvar[1].sqllen  = sizeof(intval);

    /* Open a cursor with input parameters. */
    EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

    while (1)
    {
        sqlda_t *cur_sqlda;

        /* Assign descriptor to the cursor  */
        EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

        for (cur_sqlda = sqlda1 ;
             cur_sqlda != NULL ;
             cur_sqlda = cur_sqlda->desc_next)
        {
            int i;
            char name_buf[1024];
            char var_buf[1024];

            /* Print every column in a row. */
            for (i=0 ; i<cur_sqlda->sqld ; i++)
            {
                sqlvar_t v = cur_sqlda->sqlvar[i];
                char *sqldata = v.sqldata;
                short sqllen  = v.sqllen;

                strncpy(name_buf, v.sqlname.data, v.sqlname.length);
                name_buf[v.sqlname.length] = '\0';

                switch (v.sqltype)
                {
                    case ECPGt_char:
                        memset(&var_buf, 0, sizeof(var_buf));
                        memcpy(&var_buf, sqldata, (sizeof(var_buf)<=sqllen ? sizeof(var_buf)-1 : sqllen) );
                        break;

                    case ECPGt_int: /* integer */
                        memcpy(&intval, sqldata, sqllen);
                        snprintf(var_buf, sizeof(var_buf), "%d", intval);
                        break;

                    case ECPGt_long_long: /* bigint */
                        memcpy(&longlongval, sqldata, sqllen);
                        snprintf(var_buf, sizeof(var_buf), "%lld", longlongval);
                        break;

                    default:
                    {
                        int i;
                        memset(var_buf, 0, sizeof(var_buf));
                        for (i = 0; i < sqllen; i++)
                        {
                            char tmpbuf[16];
                            snprintf(tmpbuf, sizeof(tmpbuf), "%02x ", (unsigned char) sqldata[i]);
                            strncat(var_buf, tmpbuf, sizeof(var_buf));
                        }
                    }
                        break;
                }

                printf("%s = %s (type: %d)\n", name_buf, var_buf, v.sqltype);
            }

            printf("\n");
        }
    }

    EXEC SQL CLOSE cur1;
    EXEC SQL COMMIT;

    EXEC SQL DISCONNECT ALL;

    return 0;
}

此範例的輸出應該如下所示(某些數字可能會有所不同)。

oid = 1 (type: 1)
datname = template1 (type: 1)
datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = t (type: 1)
datallowconn = t (type: 1)
dathasloginevt = f (type: 1)
datconnlimit = -1 (type: 5)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
datconfig =  (type: 1)
datacl = {=c/uptime,uptime=CTc/uptime} (type: 1)
datid = 1 (type: 1)
datname = template1 (type: 1)
numbackends = 0 (type: 5)
xact_commit = 113606 (type: 9)
xact_rollback = 0 (type: 9)
blks_read = 130 (type: 9)
blks_hit = 7341714 (type: 9)
tup_returned = 38262679 (type: 9)
tup_fetched = 1836281 (type: 9)
tup_inserted = 0 (type: 9)
tup_updated = 0 (type: 9)
tup_deleted = 0 (type: 9)

oid = 11511 (type: 1)
datname = postgres (type: 1)
datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = f (type: 1)
datallowconn = t (type: 1)
dathasloginevt = f (type: 1)
datconnlimit = -1 (type: 5)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
datconfig =  (type: 1)
datacl =  (type: 1)
datid = 11511 (type: 1)
datname = postgres (type: 1)
numbackends = 0 (type: 5)
xact_commit = 221069 (type: 9)
xact_rollback = 18 (type: 9)
blks_read = 1176 (type: 9)
blks_hit = 13943750 (type: 9)
tup_returned = 77410091 (type: 9)
tup_fetched = 3253694 (type: 9)
tup_inserted = 0 (type: 9)
tup_updated = 0 (type: 9)
tup_deleted = 0 (type: 9)

提交更正

如果您在文件中發現任何不正確、與您特定功能的使用經驗不符或需要進一步澄清的地方,請使用此表單來報告文件問題。