<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 35.11\. 用戶定義類型 正如[Section 35.2](#calibre_link-830)所說,PostgreSQL 可以擴展為支持新的數據類型。本節描述如何定義新的基本類型, 這些類型是那些定義在SQL語言之下的數據類型。 創建一個新的基本類型要求實現函數在低層語言(通常是 C)的類型上操作。 本節的例子可以在源碼發布中`src/tutorial`目錄的`complex.sql` 和`complex.c`里找到。參見同目錄下的`README` 文件獲取關于如何運行例子的指示。 一個用戶定義的類型總是有輸入和輸出函數。 這些函數決定該類型如何在字符串里出現(讓用戶輸入和輸出給用戶)以及類型如何在內存里組織。 輸入函數以一個以空(null)結尾的字符串為參數并且返回該類型的內部(內存里)的表現形式。 輸出類型以該類型的內部表現形式為參數并且返回一個以空(null)結尾的字符串。 如果我們想做任何比簡單存儲它更多的事情,我們必須提供額外的函數來實現我們想要對這個類型的操作。 假設要定義一個`complex`類型來表示復數。通常, 選用下面的 C 結構來在內存里表現復數: ``` typedef struct Complex { double x; double y; } Complex; ``` 我們需要將它變成引用傳遞類型,因為它太大,不能放在一個單獨的`Datum`值中。 對于該類型的外部表現形式,選擇形如`(x,y)`的字符串。 輸入輸出函數通常并不難寫,尤其是輸出函數。但是,在定義你的外部(字符串)表現形式時, 要注意你最后必須為該表現形式寫一個完整而且健壯的分析器作為輸入函數。比如: ``` PG_FUNCTION_INFO_V1(complex_in); Datum complex_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); double x, y; Complex *result; if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for complex: \"%s\"", str))); result = (Complex *) palloc(sizeof(Complex)); result->x = x; result->y = y; PG_RETURN_POINTER(result); } ``` 輸出函數可以簡單的寫成: ``` PG_FUNCTION_INFO_V1(complex_out); Datum complex_out(PG_FUNCTION_ARGS) { Complex *complex = (Complex *) PG_GETARG_POINTER(0); char *result; result = (char *) palloc(100); snprintf(result, 100, "(%g,%g)", complex->x, complex->y); PG_RETURN_CSTRING(result); } ``` 你應該把你的輸入和輸出函數做成互逆函數。 如果不這樣做就可能在需要把數據輸出來再加載回去時碰到很嚴重的問題, 當涉及浮點數時,這是非常普遍的問題。 另外,一個用戶定義類型可以提供二進制輸入和輸出過程。二進制 I/O 通常更快, 但是沒有文本 I/O 移植性好。因為對于文本 I/O 而言,完全由你來定義外部的二進制形式。 大多數內置的數據類型都盡可能提供一個與機器無關的二進制形式。對于`complex`, 將把二進制 I/O 建立在`float8`的基礎上: ``` PG_FUNCTION_INFO_V1(complex_recv); Datum complex_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); Complex *result; result = (Complex *) palloc(sizeof(Complex)); result->x = pq_getmsgfloat8(buf); result->y = pq_getmsgfloat8(buf); PG_RETURN_POINTER(result); } PG_FUNCTION_INFO_V1(complex_send); Datum complex_send(PG_FUNCTION_ARGS) { Complex *complex = (Complex *) PG_GETARG_POINTER(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendfloat8(&buf, complex->x); pq_sendfloat8(&buf, complex->y); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } ``` 一旦我們寫好 I/O 函數并將其編譯為共享庫,就可以定義 SQL 中的`complex`類型。 我們首先聲明其為 shell 類型: ``` CREATE TYPE complex; ``` 這將作為一個占位符以允許在定義其 I/O 函數時引用該類型。現在我們定義其 I/O 函數: ``` CREATE FUNCTION complex_in(cstring) RETURNS complex AS '_filename_' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION complex_out(complex) RETURNS cstring AS '_filename_' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION complex_recv(internal) RETURNS complex AS '_filename_' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION complex_send(complex) RETURNS bytea AS '_filename_' LANGUAGE C IMMUTABLE STRICT; ``` 最后,可以完整定義該數據類型: ``` CREATE TYPE complex ( internallength = 16, input = complex_in, output = complex_out, receive = complex_recv, send = complex_send, alignment = double ); ``` 當你定義一種新的基本類型時,PostgreSQL 自動提供對該類型的數組支持。因為歷史原因, 數組類型的類型名是與該類型同名的字符串前面加個下劃線字符(`_`)。 一旦數據類型存在,就可以聲明額外的函數以提供在該數據類型上的操作, 然后就可以在這些函數上定義操作符。如果需要, 還可以創建操作符類支持該數據類型的索引。這些將在后面的章節介紹。 如果你的數據類型的大小是變化的(內部形式),那么你應該把它們標記為可 TOAST的(參閱[Section 58.2](#calibre_link-80))。 即使數據總是太小以至于被壓縮或存儲在外部你也應該這樣做,因為TOAST 可以通過減少頭開銷在小數據上節約空間。 要做到這一點,該類型的內部形式必需遵循變長數據內部形式的標準布局: 頭四個字節必需是一個從來沒有直接訪問的 `char[4]`字段(通常叫 `vl_len_`)。你必須使用`SET_VARSIZE()` 來存儲這個字段里的數據的長度,使用`VARSIZE()`來取回這個長度。 在該類型上操作的 C 函數必須通過使用 `PG_DETOAST_DATUM` 小心地解開它們處理的任何"烘烤"過的數值(這些細節通常都可以通過定義類型相關的 `GETARG_DATATYPE_P`宏掩蓋)。最后, 在使用`CREATE TYPE`命令的時候,聲明內部長度為`variable` 并且選擇恰當的存儲選項。 如果對齊是不重要的(不管是只是對于一個特定的函數還是因為數據類型指定字節對齊) 那么避免`PG_DETOAST_DATUM`的一些開銷是可能的。 你可以使用`PG_DETOAST_DATUM_PACKED`代替(通常通過定義一個 `GETARG_DATATYPE_PP`宏指令),并且使用宏指令`VARSIZE_ANY_EXHDR` 和`VARDATA_ANY`來使用一個潛在封裝的數據。 另外,由這些宏指令返回的數據是不對齊的,即使數據類型定義聲明了一個對齊。 如果對齊是重要的,那么你必須通過正規的`PG_DETOAST_DATUM`接口。 > **Note:** 舊代碼經常聲明`vl_len_`為一個`int32`字段而不是`char[4]`。 只要結構體的定義中其他字段至少有`int32`個隊列的話這么做是可以的。 但是當使用一個潛在的對齊數據時,使用這樣一個結構體定義是危險的; 編譯器可能把它當做一個許可來假設數據實際上已經對齊,導致在架構上的核心轉儲嚴格對齊。 更多細節請參閱[CREATE TYPE](#calibre_link-100)命令。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看