<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 第16章:編寫自定義存儲引擎 ### 16.1.?前言 對于MySQL 5.1,MySQL AB公司引入了插件式存儲引擎體系結構,這樣,就能創建新的存儲引擎,并將它們添加到正在運行的MySQL服務器上,而不必重新編譯服務器本身。 該體系結構簡化了新存儲引擎的開發和部署。 本章的意圖是作為指南,用于幫助你為新的插件式存儲引擎體系結構開發存儲引擎。 關于MySQL插件式存儲引擎體系結構的更多信息,請參見[第14章:](#)[_插件式存儲引擎體系結構_](# "Chapter?14.?Pluggable Storage Engine Architecture")。 ### 16.2.?概述 MySQL服務器采用了模塊化風格。 **圖16.1:MySQL體系結構** ![MySQL architecture](https://box.kancloud.cn/2015-07-10_559fc76827881.png) 存儲引擎負責管理數據存儲,以及MySQL的索引管理。通過定義的API,MySQL服務器能夠與存儲引擎進行通信。 每個存儲引擎均是1個繼承類,每個類實例作為處理程序而被引用。 針對需要與特殊表一起工作的每個線程,處理程序是在1個處理程序的基礎上實例化的。例如,如果3個連接全都在相同的表上工作,需要創建3個處理程序實例。 一旦創建了處理程序實例,MySQL服務器將向處理程序發送命令,以便執行數據存儲和檢索任務,如打開表、操縱行和管理索引等。 能夠以累進方式創建定制存儲引擎:開發人員能夠以只讀存儲引擎啟動,隨后添加對INSERT、UPDATE和DELETE操作的支持,甚至能夠增加對索引功能、事務和其他高級操作的支持。 ### 16.3.?創建存儲引擎源文件 實施新存儲引擎的最簡單方法是,通過拷貝和更改EXAMPLE存儲引擎開始。在MySQL 5.1源碼樹的sql/examples/目錄下可找到文件ha_example.cc和ha_example.h。關于如何獲得5.1源碼樹的說明,請參見[2.8.3節,“從開發源碼樹安裝”](# "2.8.3.?Installing from the Development Source Tree")。 復制文件時,將名稱從ha_example.cc和ha_example.h更改為與存儲引擎相適應的名稱,如ha_foo.cc和ha_foo.h。 拷貝并重命名了這些文件后,必須更換所有的EXAMPLE示例,以及具有存儲引擎名稱的示例。如果你熟悉sed,也能自動完成這些步驟: sed s/EXAMPLE/FOO/g ha_example.h | sed s/example/foo/g ha_foo.h sed s/EXAMPLE/FOO/g ha_example.cc | sed s/example/foo/g ha_foo.cc ### 16.4.?創建handlerton`` handlerton(“單個處理程序”的簡稱)定義了存儲引擎,并包含指向函數的函數指針,它以整體方式作用在引擎上,而函數工作在單獨的處理程序實例中。在這類函數的一些示例中,包含用于處理注釋和回滾的事務函數。 下面給出了一個來自EXAMPLE存儲引擎的示例: handlerton example_hton= { ? "EXAMPLE", ? SHOW_OPTION_YES, ? "Example storage engine", ??DB_TYPE_EXAMPLE_DB, ? NULL,??? /* Initialize */ ? 0,?????? /* slot */ ? 0,?????? /* savepoint size. */ ? NULL,??? /* close_connection */ ? NULL,??? /* savepoint */ ? NULL,??? /* rollback to savepoint */ ? NULL,??? /* release savepoint */ ? NULL,??? /* commit */ ? NULL,??? /* rollback */ ? NULL,??? /* prepare */ ? NULL,??? /* recover */ ? NULL,??? /* commit_by_xid */ ? NULL,??? /* rollback_by_xid */ ? NULL,??? /* create_cursor_read_view */ ? NULL,??? /* set_cursor_read_view */ ? NULL,??? /* close_cursor_read_view */ ? example_create_handler,??? /* Create a new handler */ ? NULL,??? /* Drop a database */ ? NULL,??? /* Panic call */ ? NULL,??? /* Release temporary latches */ ? NULL,??? /* Update Statistics */ ? NULL,??? /* Start Consistent Snapshot */ ? NULL,??? /* Flush logs */ ? NULL,??? /* Show status */ ? NULL,??? /* Replication Report Sent Binlog */ ? HTON_CAN_RECREATE }; 下面給出了來自handler.h的handlerton定義: typedef struct ? { ??? const char *name; ??? SHOW_COMP_OPTION state; ??? const char *comment; ??? enum db_type db_type; ??? bool (*init)(); ??? uint slot; ??? uint savepoint_offset; ??? int? (*close_connection)(THD *thd); ??? int? (*savepoint_set)(THD *thd, void *sv); ??? int? (*savepoint_rollback)(THD *thd, void *sv); ??? int? (*savepoint_release)(THD *thd, void *sv); ??? int? (*commit)(THD *thd, bool all); ?? ?int? (*rollback)(THD *thd, bool all); ??? int? (*prepare)(THD *thd, bool all); ??? int? (*recover)(XID *xid_list, uint len); ??? int? (*commit_by_xid)(XID *xid); ??? int? (*rollback_by_xid)(XID *xid); ??? void *(*create_cursor_read_view)(); ??? void (*set_cursor_read_view)(void *); ??? void (*close_cursor_read_view)(void *); ??? handler *(*create)(TABLE *table); ??? void (*drop_database)(char* path); ??? int (*panic)(enum ha_panic_function flag); ??? int (*release_temporary_latches)(THD *thd); ??? int (*update_statistics)(); ??? int (*start_consistent_snapshot)(THD *thd); ??? bool (*flush_logs)(); ??? bool (*show_status)(THD *thd, stat_print_fn *print, enum ha_stat_type stat); ??? int (*repl_report_sent_binlog)(THD *thd, char *log_file_name, my_off_t end_offset); ??? uint32 flags;??????????????????????????????? ??} handlerton;? 共有30個handlerton元素,但只有少量元素是強制性的(明確地講是前4個元素和第21個元素)。 1.??? 存儲引擎的名稱。這是創建表時將使用的名稱(CREATE TABLE ... ENGINE = _FOO_;)。 2.??? 確定使用SHOW STORAGE ENGINES命令時是否列出存儲引擎。 3.??? 存儲引擎注釋,對使用SHOW STORAGE ENGINES命令時顯示的存儲引擎的描述。 4.??? 在MySQL服務器內唯一識別存儲引擎的整數。內置存儲引擎使用的常數定義在handler.h文件中。作為創建常數的可選方法,可使用大于25的整數。 5.??? 指向存儲引擎初始化程序的指針。僅當啟動服務器時才調用該函數,以便在實例化處理程序之前,存儲引擎類能執行必要的內務操作。 6.??? 插槽。保存每連接的信息時,每個存儲引擎在thd中有自己的內存區域(實際上為指針)。它是作為thd->ha_data[_foo__hton.slot]訪問的。插槽編號在調用_foo__init()后由MySQL初始化。 7.??? 保存點偏移。為了保存每個savepoint數據,為存儲引擎提供了請求的大小(典型情況下為0)。 必須以靜態方式初始化savepoint偏移,使其具有所有的內存大小,以便保存每個savepoint的信息。在_foo__init之后,它被更改為savepoint存儲區域的偏移,存儲引擎不需要使用它。 8.??? 由事務性存儲引擎使用,清理其存儲段內分配的內存,和/或回滾任何未完成的事務。 9.??? 由事務性存儲引擎選擇性使用,創建savepoint(保存點),并將其保存到提供的內存中。 10.指向處理程序rollback_to_savepoint()函數的函數指針。它用于在事務期間返回savepoint。僅對支持保存點的存儲引擎才會填充它。 11.指向處理程序release_savepoint()函數的函數指針。它用于在事務期間釋放保存點的資源。僅對支持保存點的存儲引擎才會填充它。 12.指向處理程序commit()函數的函數指針。它用于提交事務。僅對支持事務的存儲引擎才會填充它。 13.指向處理程序rollback()函數的函數指針。它用于回滾交易。僅對支持事務的存儲引擎才會填充它。 14.XA事務性存儲引擎所需。為提交操作準備事務。將XID與事務關聯起來。 15.XA事務性存儲引擎所需。恢復由XID標識的事務。 16.XA事務性存儲引擎所需。提交由XID標識的事務。 17.XA事務性存儲引擎所需。回滾由XID標識的事務。 18.與服務器端光標一起使用,尚未實施。 19.與服務器端光標一起使用,尚未實施。 20.與服務器端光標一起使用,尚未實施。 21._MANDATORY_:構造并返回處理程序實例。 22.撤銷方案時,如果存儲引擎需要執行特殊步驟時使用(如在使用表空間的存儲引擎中使用)。 23.清理在服務器關閉和崩潰時調用的函數。 24.InnoDB特殊函數。 25.在啟動SHOW STATUS時調用InnoDB特殊函數。 26.調用InnoDB特殊函數以開始連續讀取。 27.調用它,指明應將日志刷新為可靠的存儲。 28.在存儲引擎上提供可被人員讀取的狀態信息。 29.InnoDB特殊函數用于復制。 30.Handlerton標志,通常與ALTER TABLE相關。可能的值定義于sql/handler.h文件中,并在此列出; 31.?????? #define HTON_NO_FLAGS???????????????? 0 32.?????? #define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0) 33.?????? #define HTON_ALTER_NOT_SUPPORTED ????(1 << 1) 34.?????? #define HTON_CAN_RECREATE??????????? (1 << 2) 35.?????? #define HTON_FLUSH_AFTER_RENAME????? (1 << 3) 36.?????? #define HTON_NOT_USER_SELECTABLE???? (1 << 4) HTON_ALTER_NOT_SUPPORTED由FEDERATED存儲引擎使用,用以指明存儲引擎不接受AFTER TABLE語句。 HTON_FLUSH_AFTER_RENAME指明,重命名表后 ,必須調用FLUSH LOGS。 HTON_NOT_USER_SELECTABLE指明存儲引擎不能由用戶選擇,而是用作系統存儲引擎,如用于二進制日志的偽存儲引擎。 ### 16.5.?對處理程序進行實例化處理 調用存儲引擎的第1個方法是調用新的處理程序實例。 在存儲引擎源文件中定義handlerton之前,必須定義用于函數實例化的函數題頭。下面給出了1個來自CSV引擎的示例: static handler* tina_create_handler(TABLE *table); 正如你所見到的那樣,函數接受指向處理程序準備管理的表的指針,并返回處理程序對象。 定義了函數題頭后,用第21個handlerton元素中的函數指針命名函數,指明函數負責生成新的處理程序實例。 下面給出了MyISAM存儲引擎的實例化函數示例: static handler *myisam_create_handler(TABLE *table) ? { ? ??return new ha_myisam(table); ? } 該調用隨后與存儲引擎的構造程序一起工作。下面給出了來自FEDERATED存儲引擎的1個示例: ha_federated::ha_federated(TABLE *table_arg) ? :handler(&federated_hton, table_arg), ? mysql(0), stored_result(0), scan_flag(0), ? ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) ? {} 下面給出了來自EXAMPLE存儲引擎的另一個示例: ha_example::ha_example(TABLE *table_arg) ? :handler(&example_hton, table_arg) ? {}? FEDERATED示例中的附加元素是處理程序的額外初始化要素。所要求的最低實施是EXAMPLE示例中顯示的handler()初始化。 ### 16.6.?定義表擴展 就給定的表、數據和索引,要求存儲引擎為MySQL服務器提供存儲引擎所使用的擴展列表。 擴展應采用以Null終結的字符串數組形式。下面給出了CSV引擎使用的數組: static const char *ha_tina_exts[] = { ? ".CSV", ? NullS }; 調用[bas_ext()](# "16.14.1.?bas_ext")函數時返回該數組。 const char **ha_tina::bas_ext() const { ? return ha_tina_exts; } 通過提供擴展信息,你還能忽略DROP TABLE功能的實施,這是因為,通過關閉表并用你指定的擴展刪除所有文件,MySQL服務器能實現該功能。 ### 16.7.?創建表 一旦實例化了處理程序,所需的第1個操作很可能是創建表。 你的存儲引擎必須實現[create()](# "16.14.3.?create")虛擬函數: virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; 該函數應創建所有必須的文件,然后關閉表。MySQL服務器將調用隨后需打開的表。 *name參數是表的名稱。*form參數是st_table結構,該結構定義了表并與MySQL服務器已創建的_tablename_.frm文件的內容匹配。在大多數情況下,存儲引擎不需要更改_tablename_.frm文件,也沒有支持該操作的預置功能。 *info參數是包含CREATE TABLE語句用于創建表所需信息的結構。該結構定義于handler.h文件中,并為了便于參考列于下面: typedef struct st_ha_create_information ? { ??? CHARSET_INFO *table_charset, *default_table_charset; ??? LEX_STRING connect_string; ??? const char *comment,*password; ??? const char *data_file_name, *index_file_name; ??? const char *alias; ??? ulonglong max_rows,min_rows; ??? ulonglong auto_increment_value; ??? ulong table_options; ??? ulong avg_row_length; ??? ulong raid_chunksize; ??? ulong used_fields; ??? SQL_LIST merge_list; ??? enum db_type db_type; ??? enum row_type row_type; ??? uint null_bits;?????????????????????? /* NULL bits at start of record */ ??? uint options;???????????????????????????? ????????????????? /* OR of HA_CREATE_ options */ ??? uint raid_type,raid_chunks; ??? uint merge_insert_method; ??? uint extra_size;????????????????????? /* length of extra data segment */ ??? bool table_existed;?????????????????????? ????????????? /* 1 in create if table existed */ ??? bool frm_only;??????????????????????? /* 1 if no ha_create_table() */ ??? bool varchar;???????????????????????? /* 1 if table has a VARCHAR */ ? } HA_CREATE_INFO; 基本的存儲引擎能忽略*form和*info的內容,這是因為,真正所需的是創建存儲引擎所使用的數據文件,以及對數據文件的可能初始化操作(假定存儲文件是基于文件的)。 下面給出了來自CSV存儲引擎的實施示例: int ha_tina::create(const char *name, TABLE *table_arg, ? HA_CREATE_INFO *create_info) ? { ??? char name_buff[FN_REFLEN]; ??? File create_file; ??? DBUG_ENTER("ha_tina::create"); ? ????if ((create_file= my_create(fn_format(name_buff, name, "", ".CSV", ????????? MY_REPLACE_EXT|MY_UNPACK_FILENAME),0, ????????? O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) ??? DBUG_RETURN(-1); ? ????my_close(create_file,MYF(0)); ????DBUG_RETURN(0); ? } 在前面的例子中,CSV引擎未引用*table_arg或*create_info參數,而是簡單地創建了所需的數據文件,關閉它們,并返回。 my_create和my_close函數是定義于src/include/my_sys.h文件中的助手函數。 ### 16.8.?打開表 在表上執行任何讀或寫操作之前,MySQL服務器將調用[open()](# "16.14.9.?open")方法打開表數據和索引文件(如果存在的話)。 int open(const char *name, int mode, int test_if_locked); 第1個參數是要打開的表的名稱。第2個參數確定了要打開的文件或準備執行的操作。它們的值定義于handler.h中,并為了方便起見列在下面: #define HA_OPEN_KEYFILE?????????????? ? 1 #define HA_OPEN_RNDFILE?????????????? ? 2 #define HA_GET_INDEX?????????? ??? 4 #define HA_GET_INFO??????????? ????? 8 ??? /* do a ha_info() after open */ #define HA_READ_ONLY?????????? ??? 16? ? /* File opened as readonly */ #define HA_TRY_READ_ONLY?????? ? 32??? /* Try readonly if can't open with read and write */ #define HA_WAIT_IF_LOCKED????? ? 64??? ? /* Wait if locked on open */ #define HA_ABORT_IF_LOCKED???? 128???? ? /* skip if locked on open.*/ #define HA_BLOCK_LOCK????????? ??? 256 ? /* unlock when reading some records */ #define HA_OPEN_TEMPORARY????? ? 512 最后一個選項規定了是否要在打開表之前檢查表上的鎖定。 在典型情況下,存儲引擎需要實施某種形式的共享訪問控制,以防止在多線程環境下的文件損壞。關于如何實施文件鎖定的示例,請參見sql/examples/ha_tina.cc的get_share()和free_share()方法。 ### 16.9.?實施基本的表掃描功能 [ 16.9.1. 實施store_lock()函數``](#)[ 16.9.2. 實施external_lock()函數](#)[ 16.9.3. 實施rnd_init()函數``](#)[ 16.9.4. 實施info()函數``](#)[ 16.9.5. 實施extra()函數``](#)[ 16.9.6. 實施rnd_next()函數``](#) 最基本的存儲引擎能實現只讀表掃描功能。這類引擎可用于支持SQL日志查詢、以及在MySQL之外填充的其他數據文件。 本節介紹的方法實施提供了創建更高級存儲引擎的基礎。 下面給出了在CSV引擎的9行表掃描過程中進行的方法調用: ha_tina::store_lock ha_tina::external_lock ha_tina::info ha_tina::rnd_init ha_tina::extra - ENUM HA_EXTRA_CACHE Cache record in HA_rrnd() ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::rnd_next ha_tina::extra - ENUM HA_EXTRA_NO_CACHE End cacheing of records (def) ha_tina::external_lock ha_tina::extra - ENUM HA_EXTRA_RESET Reset database to after open ### 16.9.1.?實施store_lock()函數`` 在執行任何讀取或寫操作之前,調用[store_lock()](# "16.14.12.?store_lock")函數。 將鎖定添加到表鎖定處理程序之前(請參見thr_lock.c),mysqld將用請求的鎖調用存儲鎖定。目前,存儲鎖定能將寫鎖定更改為讀鎖定(或其他鎖定),忽略鎖定(如果不打算使用MySQL鎖定的話),或為很多表添加鎖定(就像使用MERGE處理程序時作的那樣)。 例如,Berkeley DB能將所有的WRITE鎖定更改為TL_WRITE_ALLOW_WRITE(表示我們正在執行WRITES,但我們仍允許其他人員進行操作)。 釋放鎖定時,也將調用store_lock(),在這種情況下,通常不需做任何事。 在某些特殊情況下,MySQL可能會發送對TL_IGNORE的請求。這意味著我們正在請求與上次相同的鎖定,這也應被忽略(當我們打開了表的某一部分時,如果其他人執行了表刷新操作,就會出現該情況,此時,mysqld將關閉并再次打開表,然后獲取與上次相同的鎖定)。我們打算在將來刪除該特性。 可能的鎖定類型定義于includes/thr_lock.h中,并列在下面: enum thr_lock_type { ???????? TL_IGNORE=-1, ????????????? ?????TL_UNLOCK,??????????????? ???????????? /* UNLOCK ANY LOCK */ ????????????? ?????TL_READ,????????????????? ?????????????? /* Read lock */ ????????????? ?????TL_READ_WITH_SHARED_LOCKS,? ?????????TL_READ_HIGH_PRIORITY,????? /* High prior. than TL_WRITE. Allow concurrent insert */ ???????? TL_READ_NO_INSERT, ????????? ?????/* READ, Don't allow concurrent insert */ ???????? TL_WRITE_ALLOW_WRITE, ?????????????? ???/*?? Write lock, but allow other threads to read / write. */ ???????? TL_WRITE_ALLOW_READ,? ??????/*?????? Write lock, but allow other threads to read / write. */ ???????? TL_WRITE_CONCURRENT_INSERT, /* WRITE lock used by concurrent insert. */ ???????? TL_WRITE_DELAYED,? ????????? ?????/* Write used by INSERT DELAYED.? Allows READ locks */ ???????? TL_WRITE_LOW_PRIORITY,?????? ???? /* WRITE lock that has lower priority than TL_READ */ ???????? TL_WRITE,????????? ????????? ?????/* Normal WRITE lock */ ???????? TL_WRITE_ONLY?????????????? /* Abort new lock request with an error */ };? 實際的鎖定處理因鎖定實施的不同而不同,你可以選擇某些請求的鎖定類型或不選擇任何鎖定類型,并根據情況恰當地代入你自己的方法。下面給出了1個CSV存儲引擎實施示例: THR_LOCK_DATA **ha_tina::store_lock(THD *thd, ???????????????????????????????????? THR_LOCK_DATA **to, ???????????????????????????????????? enum thr_lock_type lock_type) { ?? if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) ???? lock.type=lock_type; ?? *to++= &lock; ?? return to; }? ### 16.9.2.?實施external_lock()函數 [external_lock()](# "16.14.6.?external_lock")函數是在事務開始時調用的,或發出LOCK TABLES語句時調用的,用于事務性存儲引擎。 在sql/ha_innodb.cc和sql/ha_berkeley.cc文件中,可找到使用external_lock()的示例,但大多數存儲引擎簡單地返回0,就像EXAMPLE存儲引擎那樣: int ha_example::external_lock(THD *thd, int lock_type) { ?? DBUG_ENTER("ha_example::external_lock"); ?? DBUG_RETURN(0); } ### 16.9.3.?實施rnd_init()函數`` 在任何表掃描之前調用的函數是[rnd_init()](# "16.14.10.?rnd_init")函數。函數rnd_init()用于為表掃描作準備,將計數器和指針復位為表的開始狀態。 下述示例來自CSV存儲引擎: int ha_tina::rnd_init(bool scan) { DBUG_ENTER("ha_tina::rnd_init"); current_position= next_position= 0; records= 0; chain_ptr= chain; DBUG_RETURN(0); } ### 16.9.4.?實施info()函數`` 執行表掃描操作之前,將調用[info()](# "16.14.8.?info")函數,以便為優化程序提供額外信息。 優化程序所需的信息不是通過返回值給定的,你需填充存儲引擎類的特定屬性,當info()調用返回后,優化程序將讀取存儲引擎類。 除了供優化程序使用外,在調用info()函數期間,很多值集合還將用于SHOW TABLE STATUS語句。 在sql/handler.h中列出了完整的公共屬性,下面給出了一些常見的屬性: ulonglong data_file_length;?????????? /* Length off data file */ ulonglong max_data_file_length;?????? /* Length off data file */ ulonglong index_file_length; ulonglong max_index_file_length; ulonglong delete_length;????????????? /* Free bytes */ ulonglong auto_increment_value; ha_rows records;????????????????????? /* Records in table */ ha_rows deleted;????????????????????? /* Deleted records */ ulong raid_chunksize; ulong mean_rec_length;???????? /* physical reclength */ time_t create_time;?????????????????? /* When table was created */ time_t check_time; time_t update_time;? 對于表掃描,最重要的屬性是“records”,它指明了表中的記錄數。當存儲引擎指明表中有0或1行時,或有2行以上時,在這兩種情況下,優化程序的執行方式不同。因此,當你在執行表掃描之前不清楚表中有多少行時,應返回大于等于2的值,這很重要(例如,數據是在外部填充的)。 ### 16.9.5.?實施extra()函數`` 執行某些操作之前,應調用[extra()](# "16.14.7.?extra")函數,以便為存儲引擎就如何執行特定操作予以提示。 額外調用中的提示實施不是強制性的,大多數存儲引擎均返回0: int ha_tina::extra(enum ha_extra_function operation) { DBUG_ENTER("ha_tina::extra"); DBUG_RETURN(0); } ### 16.9.6.?實施rnd_next()函數`` 完成表的初始化操作后,MySQL服務器將調用處理程序的[rnd_next()](# "16.14.11.?rnd_next")函數,每兩個掃描行調用1次,直至滿足了服務器的搜索條件或到達文件結尾為止,在后一種情況下,處理程序將返回HA_ERR_END_OF_FILE。 rnd_next()函數有一個名為*buf的單字節數組參數。對于*buf參數,必須按內部MySQL格式用表行的內容填充它。 服務器采用了三種數據格式:固定長度行,可變長度行,以及具有BLOB指針的可變長度行。對于每種格式,各列將按照它們由CREATE TABLE語句定義的順序顯示(表定義保存在.frm文件中,優化程序和處理程序均能從相同的源,即TABLE結構,訪問表的元數據)。 每種格式以每列1比特的"NULL bitmap"開始。對于含6個列的表,其bitmap為1字節,對于含9~16列的表,其bitmap為2字節,依此類推。要想指明特定的值是NULL,應將該列NULL位設置為1。 當NULL bitmap逐個進入列后,每列將具有MySQL手冊的“MySQL數據類型”一節中指定的大小。在服務器中,列的數據類型定義在sql/field.cc文件中。對于固定長度行格式,列將簡單地逐個放置。對于可變長度行,VARCHAR列將被編碼為1字節長,后跟字符串。對于具有BLOB列的可變長度行,每個blob由兩部分表示:首先是表示BLOB實際大小的整數,然后是指向內存中BLOB的指針。 在任何表處理程序中從rnd_next()開始,可找到行轉換(或“包裝”)的示例。例如,在ha_tina.cc中,find_current_row()內的代碼給出了使用TABLE結構(由表指向的)和字符串對象(命名緩沖)包裝字符數據(來自CSV文件)的方法。將行寫回磁盤需要反向轉換,從內部格式解包。 下述示例來自CSV存儲引擎: int ha_tina::rnd_next(byte *buf) { ? ?DBUG_ENTER("ha_tina::rnd_next"); ???statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status); ???current_position= next_position; ?? if (!share->mapped_file) ???? DBUG_RETURN(HA_ERR_END_OF_FILE); ?? if (HA_ERR_END_OF_FILE == find_current_row(buf) ) ???? DBUG_RETURN(HA_ERR_END_OF_FILE); ???records++; ?? DBUG_RETURN(0); }? 對于從內部行格式到CSV行格式的轉換,它是在find_current_row()函數中執行的。 int ha_tina::find_current_row(byte *buf) { ?? byte *mapped_ptr= (byte *)share->mapped_file + current_position; ?? byte *end_ptr; ?? DBUG_ENTER("ha_tina::find_current_row"); ???/* EOF should be counted as new line */ ?? if ((end_ptr=? find_eoln(share->mapped_file, current_position, ??????????????????????????? share->file_stat.st_size)) == 0) ???? DBUG_RETURN(HA_ERR_END_OF_FILE); ???for (Field **field=table->field ; *field ; field++) ?? { ???? buffer.length(0); ???? mapped_ptr++; // Increment past the first quote ???? for(;mapped_ptr != end_ptr; mapped_ptr++) ???? { ?????? // Need to convert line feeds! ?????? if (*mapped_ptr == '"' && ?????????? (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || ??????????? (mapped_ptr == end_ptr -1 ))) ?????? { ???????? mapped_ptr += 2; // Move past the , and the " ???????? break; ??? ???} ?????? if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1)) ?????? { ???????? mapped_ptr++; ???????? if (*mapped_ptr == 'r') ?????????? buffer.append('\r'); ???????? else if (*mapped_ptr == 'n' ) ?????????? buffer.append('\n'); ???????? else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"')) ?????????? buffer.append(*mapped_ptr); ???????? else? /* This could only happed with an externally created file */ ???????? { ?????????? buffer.append('\\'); ?????????? buffer.append(*mapped_ptr); ???????? } ?? ????} ?????? else ???????? buffer.append(*mapped_ptr); ???? } ???? (*field)->store(buffer.ptr(), buffer.length(), system_charset_info); ?? } ?? next_position= (end_ptr - share->mapped_file)+1; ?? /* Maybe use \N for null? */ ?? memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */ ???DBUG_RETURN(0); }? ### 16.10.?關閉表 當MySQL服務器完成表操作時,它將調用[close()](# "16.14.2.?close")方法關閉文件指針并釋放任何其他資源。 對于使用共享訪問方法的存儲引擎(如CSV引擎和其他示例引擎中顯示的方法),必須將它們自己從共享結構中刪除: int ha_tina::close(void) { ?? DBUG_ENTER("ha_tina::close"); ?? DBUG_RETURN(free_share(share)); }? 對于使用其自己共享管理系統的存儲引擎,應使用任何所需的方法,在它們的處理程序中,從已打開表的共享區刪除處理程序實例。 ### 16.11.?為存儲引擎添加對INSERT的支持`` 一旦在你的存儲引擎中有了讀支持,下一個需要實施的特性是對INSERT語句的支持。有了INSERT支持,存儲引擎就能處理WORM(寫一次,讀多次)應用程序,如用于以后分析的日志和歸檔應用等。 所有的INSERT操作均是通過[write_row()](# "16.14.14.?write_row")函數予以處理的: int ha_foo::write_row(byte *buf)? *buf參數包含將要插入的行,采用內部MySQL格式。基本的存儲引擎將簡單地前進到數據文件末尾,并直接在末尾處添加緩沖的內容,這樣就能使行讀取變得簡單,這是因為,你可以讀取行并將其直接傳遞到rnd_next()函數的緩沖參數中。 寫入行的進程與讀取行的進程相反:從MySQL內部行格式獲取數據,并將其寫入數據文件。下述示例來自CSV存儲引擎: int ha_tina::write_row(byte * buf) { ?? int size; ?? DBUG_ENTER("ha_tina::write_row"); ???statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); ???if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) ???? table->timestamp_field->set_time(); ???size= encode_quote(buf); ???if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP))) ???? DBUG_RETURN(-1); ? ?? if (get_mmap(share, 0) > 0) ???? DBUG_RETURN(-1); ?? DBUG_RETURN(0); } 前述示例中的兩條注釋包括,更新關于寫入操作的表統計,以及在寫入行之前設置時間戳。 ### 16.12.?為存儲引擎添加對UPDATE的支持`` 通過執行表掃描操作,在找到與UPDATE語句的WHERE子句匹配的行后,MySQL服務器將執行UPDATE語句,然后調用[update_row()函數](# "16.14.13.?update_row"): int ha_foo::update_row(const byte *old_data, byte *new_data) *old_data參數包含更新前位于行中的數據,而*new_data參數包含行的新內容(采用MySQL內部行格式)。 更新的執行取決于行格式和存儲實施方式。某些存儲引擎將替換恰當位置的數據,而其他實施方案則會刪除已有的行,并在數據文件末尾添加新行。 非事務性存儲引擎通常會忽略*old_data參數的內容,僅處理*new_data緩沖。事務性存儲引擎可能需要比較緩沖,以確定在上次回滾中出現了什么變化。 如果正在更新的表中包含時間戳列,對時間戳的更新將由update_row()調用管理。下述示例來自CSV引擎: int ha_tina::update_row(const byte * old_data, byte * new_data) { ?? int size; ?? DBUG_ENTER("ha_tina::update_row"); ???statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, ????????????? ??????&LOCK_status); ???if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) ???? table->timestamp_field->set_time(); ???size= encode_quote(new_data); ???if (chain_append()) ???? DBUG_RETURN(-1); ???if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP))) ???? DBUG_RETURN(-1); ?? DBUG_RETURN(0); } 請注意上例中的時間戳設置。 ### 16.13.?為存儲引擎添加對DELETE的支持`` MySQL服務器采用了與INSERT語句相同的方法來執行DELETE語句:服務器使用rnd_next()函數跳到要刪除的行,然后調用[delete_row()](# "16.14.4.?delete_row")函數刪除行。 int ha_foo::delete_row(const byte *buf) *buf參數包含要刪除行的內容。對于大多數存儲引擎,該參數可被忽略,但事務性存儲引擎可能需要保存刪除的數據,以供回滾操作使用。 下述示例來自CSV存儲引擎: int ha_tina::delete_row(const byte * buf) { ?? DBUG_ENTER("ha_tina::delete_row"); ?? statistic_increment(table->in_use->status_var.ha_delete_count, ?????????????????????? &LOCK_status); ???if (chain_append()) ???? DBUG_RETURN(-1); ? ???--records; ???DBUG_RETURN(0); } 前述示例的步驟是更新delete_count統計,并記錄計數。 ### 16.14.?API引用 [16.14.1. bas_ext](#)[16.14.2. close](#)[16.14.3. create](#)[16.14.4. delete_row](#)[16.14.5. delete_table](#)[16.14.6. external_lock](#)[16.14.7. extra](#)[16.14.8. info](#)[16.14.9. open](#)[16.14.10. rnd_init](#)[16.14.11. rnd_next](#)[16.14.12. store_lock](#)[16.14.13. update_row](#)[16.14.14. write_row](#) ### 16.14.1.?bas_ext #### 目的 定義存儲引擎所使用的文件擴展。 #### 概要 | virtual const char ** **bas_ext** ( | ); | ? | |-----|-----|-----| | ? | ; | |-----|-----| #### 描述 這是bas_ext方法。調用它,可為MySQL服務器提供存儲引擎所使用的文件擴展列表。該列表將返回以Null終結的字符串數組。 通過提供擴展列表,在很多情況下,存儲引擎能省略[delete_table()](# "16.14.5.?delete_table")函數,這是因為MySQL服務器將關閉所有對表的引用,并使用指定的擴展刪除所有文件。 #### 參數 該函數無參數。 #### 返回值 - 返回值是存儲引擎擴展的以Null終結的字符串數組。下面給出了CSV引擎的示例: static const char *ha_tina_exts[] = { ".CSV", NullS }; #### 用法 static const char *ha_tina_exts[] = { ".CSV", NullS }; const char **ha_tina::bas_ext() const { return ha_tina_exts; } #### 默認實施 static const char *ha_example_exts[] = { NullS }; const char **ha_example::bas_ext() const { return ha_example_exts; } ### 16.14.2.?close #### 目的 關閉打開的表。 #### 概要 | virtual int **close** ( | void); | ? | |-----|-----|-----| | ? | void ; | |-----|-----| #### 描述 這是close方法。 關閉表。這是釋放任何已分配資源的恰當時機。 從sql_base.cc、sql_select.cc和table.cc調用它。在sql_select.cc中,它僅用于關閉臨時表,或在將臨時表轉換為myisam表的過程中關閉表。關于sql_base.cc,請查看close_data_tables()。 #### 參數 - void #### 返回值 無返回值。 #### 用法 取自CSV引擎的示例: int ha_example::close(void) { DBUG_ENTER("ha_example::close"); DBUG_RETURN(free_share(share)); } ### 16.14.3.?create #### 目的 創建新表。 #### 概要 | virtual int **create** ( | name, | ? | |-----|-----|-----| | ? | form, | ? | | ? | info); | ? | | const char *? | name ; | |-----|-----| | TABLE *? | form ; | | HA_CREATE_INFO *? | info ; | #### 描述 這是create方法。 調用create()以創建表。變量名稱為表的名稱。調用create()時,不需要打開表。此外,由于已創建了.frm文件,不推薦調整create_info。 由ha_create_table()從handle.cc中調用。 #### 參數 - name - form - info #### 返回值 無返回值。 #### 用法 CSV搜索引擎示例: int ha_tina::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { char name_buff[FN_REFLEN]; File create_file; DBUG_ENTER("ha_tina::create"); if ((create_file= my_create(fn_format(name_buff, name, "", ".CSV", MY_REPLACE_EXT|MY_UNPACK_FILENAME),0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) DBUG_RETURN(-1); my_close(create_file,MYF(0)); DBUG_RETURN(0); } ### 16.14.4.?delete_row #### 目的 刪除行。 #### 概要 | virtual int **delete_row** ( | buf); | ? | |-----|-----|-----| | const byte *? | buf ; | |-----|-----| #### 描述 這是delete_row方法。 _Buf_包含刪除行的副本。調用了當前行后,服務器將立刻調用它(通過前一個rnd_next()或索引調用)。如果存在指向上一行的指針,或能夠訪問 主鍵,刪除操作將更為容易。請記住,服務器不保證連續刪除。可以使用ORDER BY子句。 在sql_acl.cc和sql_udf.cc中調用,以管理內部的表信息。在sql_delete.cc、sql_insert.cc和sql_select.cc中調用。在sql_select中,它用于刪除副本,而在插入操作中,它用于REPLACE調用。 #### 參數 - buf #### 返回值 無返回值。 #### 用法 #### 默認實施 { return HA_ERR_WRONG_COMMAND; } ### 16.14.5.?delete_table #### 目的 用來自[bas_ext()](# "16.14.1.?bas_ext")的擴展刪除所有文件。 #### 概要 | virtual int **delete_table** ( | name); | ? | |-----|-----|-----| | const char *? | name ; | |-----|-----| #### 描述 這是delete_table方法。 用于刪除表。調用delete_table()時,所有已打開的對該表的引用均將被關閉(并釋放全局共享的引用)。變量名稱為表名。此時,需要刪除任何已創建的文件。 如果未實施它,將從handler.cc調用默認的delete_table(),并用bas_ext()返回的文件擴展刪除所有文件。假定處理程序返回的擴展比文件實際使用的多。 由delete_table和ha_create_table()從handler.cc調用。如果為存儲引擎指定了table_flagHA_DROP_BEFORE_CREATE,僅在創建過程中使用。 #### 參數 - name: 表的基本名稱 #### 返回值 ????????? 如果成功地從base_ext刪除了至少1個文件而且未出現除ENOENT之外的錯誤,返回0。 ????????? #: Error #### 用法 大多數存儲引擎均會忽略該函數的實施。 ### 16.14.6.?external_lock #### 目的 為事務處理表鎖定。 #### 概要 | virtual int **external_lock** ( | thd, | ? | |-----|-----|-----| | ? | lock_type); | ? | | THD *? | thd ; | |-----|-----| | int? | lock_type ; | #### 描述 這是external_lock方法。 在lock.cc中“用于mysql的鎖定函數”一節,給出了關于該議題的額外注釋,值的一讀。 在表上創建鎖定。如果實施了能處理事務的存儲引擎,請查看ha_berkely.cc,以了解如何執行該操作的方法。否則,應考慮在此調用flock()。 由lock_external()和unlock_external()從lock.cc中調用。也能由copy_data_between_tables()從sql_table.cc中調用。 #### 參數 - thd - lock_type #### 返回值 無返回值。 #### 默認實施 { return 0; } ### 16.14.7.?extra #### 目的 將提示從服務器傳遞給存儲引擎。 #### 概要 | virtual int **extra** ( | operation); | ? | |-----|-----|-----| | enum ha_extra_function? | operation ; | |-----|-----| #### 描述 這是extra方法。 無論何時,當服務器希望將提示發送到存儲引擎時,將調用extra()。MyISAM引擎實現了大多數提示。ha_innodb.cc給出了最詳盡的提示列表。 #### 參數 - operation #### 返回值 無返回值。 #### 用法 #### 默認實施 默認情況下,存儲引擎傾向于不實施任何提示。 { return 0; } ### 16.14.8.?info #### 目的 提示存儲引擎通報統計信息。 #### 概要 | virtual void **info** ( | uint); | ? | |-----|-----|-----| | ? | uint ; | |-----|-----| #### 描述 這是info方法。 ::info()用于將信息返回給優化程序。目前,該表處理程序未實施實際需要的大多數字段。SHOW也能利用該數據。注意,或許你打算在你的代碼中包含下述內容“if (records > 2) records = 2”。原因在于,服務器僅優化具有一條記錄的情形。如果在表掃描過程中,你不清楚記錄的數目,最好將記錄數設為2,以便能夠返回盡可能多的所需記錄。除了記錄外,你或許還希望設置其他變量,包括:刪除的記錄,data_file_length,index_file_length,delete_length,check_time。更多信息,請參見handler.h中的公共變量。 在下述文件中調用:filesort.cc ha_heap.cc item_sum.cc opt_sum.cc sql_delete.cc sql_delete.cc sql_derived.cc sql_select.cc sql_select.cc sql_select.cc sql_select.cc sql_select.cc sql_show.cc sql_show.cc sql_show.cc sql_show.cc sql_table.cc sql_union.cc sql_update.cc #### 參數 - uint #### 返回值 無返回值。 #### 用法 該示例取自CSV存儲引擎: void ha_tina::info(uint flag) { DBUG_ENTER("ha_tina::info"); /* This is a lie, but you don't want the optimizer to see zero or 1 */ if (records < 2) records= 2; DBUG_VOID_RETURN; } ### 16.14.9.?open #### 目的 打開表。 #### 概要 | virtual int **open** ( | name, | ? | |-----|-----|-----| | ? | mode, | ? | | ? | test_if_locked); | ? | | const char *? | name ; | |-----|-----| | int? | mode ; | | uint? | test_if_locked ; | #### 描述 這是open方法。 用于打開表。名稱是文件的名稱。在需要打開表時打開它。例如,當請求在表上執行選擇操作時(對于每一請求,表未打開并被關閉,對其進行高速緩沖處理)。 由handler::ha_open()從handler.cc中調用。通過調用ha_open(),然后調用處理程序相關的open(),服務器打開所有表。 對于處理程序對象,將作為初始化的一部分并在將其用于正常查詢之前打開它(并非總在元數據變化之前)。如果打開了對象,在刪除之前還將關閉它。 這是open方法。調用open以打開數據庫表。 第1個參數是要打開的表的名稱。第2個參數決定了要打開的文件或將要執行的操作。這類值定義于handler.h中,為了方便起見在此列出: ??????? #define HA_OPEN_KEYFILE?????????????? ? 1 ??????? #define HA_OPEN_RNDFILE?????????????? ? 2 ??????? #define HA_GET_INDEX????????? ??? 4 ??????? #define HA_GET_INFO?????????? ????? 8 ??? /* do a ha_info() after open */ ??????? #define HA_READ_ONLY????????? ??? 16? ? /* File opened as readonly */ ??????? #define HA_TRY_READ_ONLY????? ? 32??? /* Try readonly if can't open with read and write */ ??????? #define HA_WAIT_IF_LOCKED???? ? 64??? ? /* Wait if locked on open */ ??????? #define HA_ABORT_IF_LOCKED??? 128???? ? /* skip if locked on open.*/ ??????? #define HA_BLOCK_LOCK???????? ??? 256 ? /* unlock when reading some records */ ??????? #define HA_OPEN_TEMPORARY???? ? 512 ????? 最后的選項規定了在打開表之前是否應檢查表上的鎖定。 典型情況下,存儲引擎需要實現某種形式的共享訪問控制,以防止多線程環境下的文件損壞。關于如何實現文件鎖定的示例,請參見sql/examples/ha_tina.cc的get_share()和free_share()方法。 #### 參數 - name - mode - test_if_locked #### 返回值 無返回值。 #### 用法 該示例取自CSV存儲引擎: int ha_tina::open(const char *name, int mode, uint test_if_locked) { DBUG_ENTER("ha_tina::open"); if (!(share= get_share(name, table))) DBUG_RETURN(1); thr_lock_data_init(&share->lock,&lock,NULL); ref_length=sizeof(off_t); DBUG_RETURN(0); } ### 16.14.10.?rnd_init #### 目的 為表掃描功能初始化處理程序。 #### 概要 | virtual int **rnd_init** ( | scan); | ? | |-----|-----|-----| | bool? | scan ; | |-----|-----| #### 描述 這是rnd_init方法。 當系統希望存儲引擎執行表掃描時,將調用rnd_init()。 與index_init()不同,rnd_init()可以調用兩次,兩次調用之間不使用rnd_end()(僅當scan=1時才有意義)。隨后,第2次調用應準備好新的表掃描。例如,如果rnd_init分配了光標,第2次調用應將光標定位于表的開始部分,不需要撤銷分配并再次分配。 從下述文件調用:filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc, 和sql_update.cc。 #### 參數 - scan #### 返回值 無返回值。 #### 用法 該示例取自CSV存儲引擎: int ha_tina::rnd_init(bool scan) { DBUG_ENTER("ha_tina::rnd_init"); current_position= next_position= 0; records= 0; chain_ptr= chain; DBUG_RETURN(0); } ### 16.14.11.?rnd_next #### 目的 從表中讀取下一行,并將其返回服務器。 #### 概要 | virtual int **rnd_next** ( | buf); | ? | |-----|-----|-----| | byte *? | buf ; | |-----|-----| #### 描述 這是rnd_next方法。 對于表掃描的每一行調用它。耗盡記錄時,應返回HA_ERR_END_OF_FILE。用行信息填充buff。表的字段結構是以服務器能理解的方式將數據保存到buf中的鍵。 從下述文件調用:filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc, 和sql_update.cc。 #### 參數 - buf #### 返回值 無返回值。 #### 用法 下述示例取自ARCHIVE存儲引擎: int ha_archive::rnd_next(byte *buf) { int rc; DBUG_ENTER("ha_archive::rnd_next"); if (share->crashed) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); if (!scan_rows) DBUG_RETURN(HA_ERR_END_OF_FILE); scan_rows--; statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status); current_position= gztell(archive); rc= get_row(archive, buf); if (rc != HA_ERR_END_OF_FILE) records++; DBUG_RETURN(rc); } ### 16.14.12.?store_lock #### 目的 創建和釋放表鎖定。 #### 概要 | virtual THR_LOCK_DATA ** **store_lock** ( | thd, | ? | |-----|-----|-----| | ? | to, | ? | | ? | lock_type); | ? | | THD *? | thd ; | |-----|-----| | THR_LOCK_DATA **? | to ; | | enum thr_lock_type? | lock_type ; | #### 描述 這是store_lock方法。 下面介紹了關于handler::store_lock()的概念: 該語句決定了在表上需要何種鎖定。對于updates/deletes/inserts,我們得到WRITE鎖定;對于SELECT...,我們得到讀鎖定。 將鎖定添加到表鎖定處理程序之前(請參見thr_lock.c),mysqld將用請求的鎖定調用存儲鎖定。目前,存儲鎖定能將寫鎖定更改為讀鎖定(或某些其他鎖定),忽略鎖定(如果不打算使用MySQL表鎖定),或為很多表添加鎖定(就像使用MERGE處理程序時那樣)。 例如,Berkeley DB能夠將所有的WRITE鎖定更改為TL_WRITE_ALLOW_WRITE(表明正在執行WRITES操作,但我們仍允許其他人執行操作)。 釋放鎖定時,也將調用store_lock()。在這種情況下,通常不需要作任何事。 在某些特殊情況下,MySQL可能會發送對TL_IGNORE的請求。這意味著我們正在請求與上次相同的鎖定,這也應被忽略(當我們打開了表的某一部分時,如果其他人執行了表刷新操作,就會出現該情況,此時,mysqld將關閉并再次打開表,然后獲取與上次相同的鎖定)。我們打算在將來刪除該特性。 由get_lock_data()從lock.cc中調用。 #### 參數 - thd - to - lock_type #### 返回值 無返回值。 #### 用法 下述示例取自ARCHIVE存儲引擎: /* Below is an example of how to setup row level locking. */ THR_LOCK_DATA **ha_archive::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { if (lock_type == TL_WRITE_DELAYED) delayed_insert= TRUE; else delayed_insert= FALSE; if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { /* Here is where we get into the guts of a row level lock. If TL_UNLOCK is set If we are not doing a LOCK TABLE or DISCARD/IMPORT TABLESPACE, then allow multiple writers */ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && lock_type <= TL_WRITE) && !thd->in_lock_tables && !thd->tablespace_op) lock_type = TL_WRITE_ALLOW_WRITE; /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... MySQL would use the lock TL_READ_NO_INSERT on t2, and that would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts to t2. Convert the lock to a normal read lock to allow concurrent inserts to t2. */ if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) lock_type = TL_READ; lock.type=lock_type; } *to++= &lock; return to; } ### 16.14.13.?update_row #### 目的 更新已有行的內容。 #### 概要 | virtual int **update_row** ( | old_data, | ? | |-----|-----|-----| | ? | new_data); | ? | | const byte *? | old_data ; | |-----|-----| | byte *? | new_data ; | #### 描述 這是update_row方法。 old_data將保存前一行的記錄,而new_data將保存最新的數據。 如果使用了ORDER BY子句,服務器能夠根據排序執行更新操作。不保證連續排序。 目前,new_data不會擁有已更新的auto_increament記錄,或已更新的時間戳字段。你可以通過下述方式(例如)完成該操作:if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); if (table->next_number_field && record == table->record[0]) update_auto_increment(); 從sql_select.cc, sql_acl.cc, sql_update.cc和sql_insert.cc調用。 #### 參數 - old_data - new_data #### 返回值 無返回值。 #### 用法 #### 默認實施 { return HA_ERR_WRONG_COMMAND; } ### 16.14.14.?write_row #### 目的 為表添加新行。 #### 概要 | virtual int **write_row** ( | buf); | ? | |-----|-----|-----| | byte *? | buf ; | |-----|-----| #### 描述 這是write_row方法。 write_row()用于插入行。目前,如果出現大量加載,不會給出任何[extra()](# "16.14.7.?extra")提示。buf是數據的字節數組,大小為table->s->reclength。 可以使用字段信息從本地字節數組類型提取數據。例如: for (Field **field=table->field ; *field ; field++) { ... } BLOB必須特殊處理: ??? for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields ; ptr != end ; ptr++) ??{ ????????char *data_ptr; ????????uint32 size= ((Field_blob*)table->field[*ptr])->get_length(); ??????? ((Field_blob*)table->field[*ptr])->get_ptr(&data_ptr); ????????... ??} 關于以字符串形式提取所有數據的示例,請參見ha_tina.cc。在ha_berkeley.cc中,對于ha_berkeley自己的本地存儲類型,給出了一個通過“包裝功能”完整保存它的例子。 請參見update_row()關于auto_increments和時間戳的注釋。該情形也適用于write_row()。 從item_sum.cc、item_sum.cc、sql_acl.cc、sql_insert.cc、sql_insert.cc、sql_select.cc、sql_table.cc、sql_udf.cc、以及sql_update.cc調用。 #### 參數 - 數據的buf字節數組 #### 返回值 無返回值。 #### 用法 #### 默認實施 { return HA_ERR_WRONG_COMMAND; } 這是MySQL參考手冊的翻譯版本,關于MySQL參考手冊,請訪問[dev.mysql.com](http://dev.mysql.com/doc/mysql/en)。 原始參考手冊為英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。
                  <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>

                              哎呀哎呀视频在线观看