mirror of
https://github.com/luapower/mysql.git
synced 2024-12-29 12:20:32 +01:00
unimportant
This commit is contained in:
parent
e704307b1c
commit
0d9be36a39
611
mysql_client.lua
611
mysql_client.lua
@ -3,14 +3,14 @@
|
||||
-- Written by Yichun Zhang (agentzh). BSD license.
|
||||
-- Modified by Cosmin Apreutesei. Pulbic domain.
|
||||
|
||||
local sha1 = require'sha1'.sha1
|
||||
local ffi = require'ffi'
|
||||
local bit = require'bit'
|
||||
local null = require'cjson'.null
|
||||
local sha1 = require'sha1'.sha1
|
||||
local glue = require'glue'
|
||||
|
||||
local sub = string.sub
|
||||
local strbyte = string.byte
|
||||
local strchar = string.char
|
||||
local strfind = string.find
|
||||
local format = string.format
|
||||
local strrep = string.rep
|
||||
local band = bit.band
|
||||
@ -20,94 +20,413 @@ local lshift = bit.lshift
|
||||
local rshift = bit.rshift
|
||||
local tohex = bit.tohex
|
||||
local concat = table.concat
|
||||
local unpack = unpack
|
||||
local setmetatable = setmetatable
|
||||
local error = error
|
||||
local tonumber = tonumber
|
||||
|
||||
local buffer = glue.buffer
|
||||
local index = glue.index
|
||||
local repl = glue.repl
|
||||
|
||||
local ok, new_tab = pcall(require, 'table.new')
|
||||
new_tab = ok and new_tab or function() return {} end
|
||||
|
||||
local mysql = {}
|
||||
|
||||
-- constants
|
||||
|
||||
local STATE_CONNECTED = 1
|
||||
local STATE_COMMAND_SENT = 2
|
||||
|
||||
local COM_QUIT = 0x01
|
||||
local COM_QUERY = 0x03
|
||||
local CLIENT_SSL = 0x0800
|
||||
|
||||
local SERVER_MORE_RESULTS_EXISTS = 8
|
||||
|
||||
-- 16MB - 1, the default max allowed packet size used by libmysqlclient
|
||||
local FULL_PACKET_SIZE = 16777215
|
||||
local collation_names = {
|
||||
[ 1] = 'big5_chinese_ci',
|
||||
[ 2] = 'latin2_czech_cs',
|
||||
[ 3] = 'dec8_swedish_ci',
|
||||
[ 4] = 'cp850_general_ci',
|
||||
[ 5] = 'latin1_german1_ci',
|
||||
[ 6] = 'hp8_english_ci',
|
||||
[ 7] = 'koi8r_general_ci',
|
||||
[ 8] = 'latin1_swedish_ci',
|
||||
[ 9] = 'latin2_general_ci',
|
||||
[ 10] = 'swe7_swedish_ci',
|
||||
[ 11] = 'ascii_general_ci',
|
||||
[ 12] = 'ujis_japanese_ci',
|
||||
[ 13] = 'sjis_japanese_ci',
|
||||
[ 14] = 'cp1251_bulgarian_ci',
|
||||
[ 15] = 'latin1_danish_ci',
|
||||
[ 16] = 'hebrew_general_ci',
|
||||
[ 18] = 'tis620_thai_ci',
|
||||
[ 19] = 'euckr_korean_ci',
|
||||
[ 20] = 'latin7_estonian_cs',
|
||||
[ 21] = 'latin2_hungarian_ci',
|
||||
[ 22] = 'koi8u_general_ci',
|
||||
[ 23] = 'cp1251_ukrainian_ci',
|
||||
[ 24] = 'gb2312_chinese_ci',
|
||||
[ 25] = 'greek_general_ci',
|
||||
[ 26] = 'cp1250_general_ci',
|
||||
[ 27] = 'latin2_croatian_ci',
|
||||
[ 28] = 'gbk_chinese_ci',
|
||||
[ 29] = 'cp1257_lithuanian_ci',
|
||||
[ 30] = 'latin5_turkish_ci',
|
||||
[ 31] = 'latin1_german2_ci',
|
||||
[ 32] = 'armscii8_general_ci',
|
||||
[ 33] = 'utf8_general_ci',
|
||||
[ 34] = 'cp1250_czech_cs',
|
||||
[ 35] = 'ucs2_general_ci',
|
||||
[ 36] = 'cp866_general_ci',
|
||||
[ 37] = 'keybcs2_general_ci',
|
||||
[ 38] = 'macce_general_ci',
|
||||
[ 39] = 'macroman_general_ci',
|
||||
[ 40] = 'cp852_general_ci',
|
||||
[ 41] = 'latin7_general_ci',
|
||||
[ 42] = 'latin7_general_cs',
|
||||
[ 43] = 'macce_bin',
|
||||
[ 44] = 'cp1250_croatian_ci',
|
||||
[ 45] = 'utf8mb4_general_ci',
|
||||
[ 46] = 'utf8mb4_bin',
|
||||
[ 47] = 'latin1_bin',
|
||||
[ 48] = 'latin1_general_ci',
|
||||
[ 49] = 'latin1_general_cs',
|
||||
[ 50] = 'cp1251_bin',
|
||||
[ 51] = 'cp1251_general_ci',
|
||||
[ 52] = 'cp1251_general_cs',
|
||||
[ 53] = 'macroman_bin',
|
||||
[ 54] = 'utf16_general_ci',
|
||||
[ 55] = 'utf16_bin',
|
||||
[ 56] = 'utf16le_general_ci',
|
||||
[ 57] = 'cp1256_general_ci',
|
||||
[ 58] = 'cp1257_bin',
|
||||
[ 59] = 'cp1257_general_ci',
|
||||
[ 60] = 'utf32_general_ci',
|
||||
[ 61] = 'utf32_bin',
|
||||
[ 62] = 'utf16le_bin',
|
||||
[ 63] = 'binary',
|
||||
[ 64] = 'armscii8_bin',
|
||||
[ 65] = 'ascii_bin',
|
||||
[ 66] = 'cp1250_bin',
|
||||
[ 67] = 'cp1256_bin',
|
||||
[ 68] = 'cp866_bin',
|
||||
[ 69] = 'dec8_bin',
|
||||
[ 70] = 'greek_bin',
|
||||
[ 71] = 'hebrew_bin',
|
||||
[ 72] = 'hp8_bin',
|
||||
[ 73] = 'keybcs2_bin',
|
||||
[ 74] = 'koi8r_bin',
|
||||
[ 75] = 'koi8u_bin',
|
||||
[ 76] = 'utf8_tolower_ci',
|
||||
[ 77] = 'latin2_bin',
|
||||
[ 78] = 'latin5_bin',
|
||||
[ 79] = 'latin7_bin',
|
||||
[ 80] = 'cp850_bin',
|
||||
[ 81] = 'cp852_bin',
|
||||
[ 82] = 'swe7_bin',
|
||||
[ 83] = 'utf8_bin',
|
||||
[ 84] = 'big5_bin',
|
||||
[ 85] = 'euckr_bin',
|
||||
[ 86] = 'gb2312_bin',
|
||||
[ 87] = 'gbk_bin',
|
||||
[ 88] = 'sjis_bin',
|
||||
[ 89] = 'tis620_bin',
|
||||
[ 90] = 'ucs2_bin',
|
||||
[ 91] = 'ujis_bin',
|
||||
[ 92] = 'geostd8_general_ci',
|
||||
[ 93] = 'geostd8_bin',
|
||||
[ 94] = 'latin1_spanish_ci',
|
||||
[ 95] = 'cp932_japanese_ci',
|
||||
[ 96] = 'cp932_bin',
|
||||
[ 97] = 'eucjpms_japanese_ci',
|
||||
[ 98] = 'eucjpms_bin',
|
||||
[ 99] = 'cp1250_polish_ci',
|
||||
[101] = 'utf16_unicode_ci',
|
||||
[102] = 'utf16_icelandic_ci',
|
||||
[103] = 'utf16_latvian_ci',
|
||||
[104] = 'utf16_romanian_ci',
|
||||
[105] = 'utf16_slovenian_ci',
|
||||
[106] = 'utf16_polish_ci',
|
||||
[107] = 'utf16_estonian_ci',
|
||||
[108] = 'utf16_spanish_ci',
|
||||
[109] = 'utf16_swedish_ci',
|
||||
[110] = 'utf16_turkish_ci',
|
||||
[111] = 'utf16_czech_ci',
|
||||
[112] = 'utf16_danish_ci',
|
||||
[113] = 'utf16_lithuanian_ci',
|
||||
[114] = 'utf16_slovak_ci',
|
||||
[115] = 'utf16_spanish2_ci',
|
||||
[116] = 'utf16_roman_ci',
|
||||
[117] = 'utf16_persian_ci',
|
||||
[118] = 'utf16_esperanto_ci',
|
||||
[119] = 'utf16_hungarian_ci',
|
||||
[120] = 'utf16_sinhala_ci',
|
||||
[121] = 'utf16_german2_ci',
|
||||
[122] = 'utf16_croatian_ci',
|
||||
[123] = 'utf16_unicode_520_ci',
|
||||
[124] = 'utf16_vietnamese_ci',
|
||||
[128] = 'ucs2_unicode_ci',
|
||||
[129] = 'ucs2_icelandic_ci',
|
||||
[130] = 'ucs2_latvian_ci',
|
||||
[131] = 'ucs2_romanian_ci',
|
||||
[132] = 'ucs2_slovenian_ci',
|
||||
[133] = 'ucs2_polish_ci',
|
||||
[134] = 'ucs2_estonian_ci',
|
||||
[135] = 'ucs2_spanish_ci',
|
||||
[136] = 'ucs2_swedish_ci',
|
||||
[137] = 'ucs2_turkish_ci',
|
||||
[138] = 'ucs2_czech_ci',
|
||||
[139] = 'ucs2_danish_ci',
|
||||
[140] = 'ucs2_lithuanian_ci',
|
||||
[141] = 'ucs2_slovak_ci',
|
||||
[142] = 'ucs2_spanish2_ci',
|
||||
[143] = 'ucs2_roman_ci',
|
||||
[144] = 'ucs2_persian_ci',
|
||||
[145] = 'ucs2_esperanto_ci',
|
||||
[146] = 'ucs2_hungarian_ci',
|
||||
[147] = 'ucs2_sinhala_ci',
|
||||
[148] = 'ucs2_german2_ci',
|
||||
[149] = 'ucs2_croatian_ci',
|
||||
[150] = 'ucs2_unicode_520_ci',
|
||||
[151] = 'ucs2_vietnamese_ci',
|
||||
[159] = 'ucs2_general_mysql500_ci',
|
||||
[160] = 'utf32_unicode_ci',
|
||||
[161] = 'utf32_icelandic_ci',
|
||||
[162] = 'utf32_latvian_ci',
|
||||
[163] = 'utf32_romanian_ci',
|
||||
[164] = 'utf32_slovenian_ci',
|
||||
[165] = 'utf32_polish_ci',
|
||||
[166] = 'utf32_estonian_ci',
|
||||
[167] = 'utf32_spanish_ci',
|
||||
[168] = 'utf32_swedish_ci',
|
||||
[169] = 'utf32_turkish_ci',
|
||||
[170] = 'utf32_czech_ci',
|
||||
[171] = 'utf32_danish_ci',
|
||||
[172] = 'utf32_lithuanian_ci',
|
||||
[173] = 'utf32_slovak_ci',
|
||||
[174] = 'utf32_spanish2_ci',
|
||||
[175] = 'utf32_roman_ci',
|
||||
[176] = 'utf32_persian_ci',
|
||||
[177] = 'utf32_esperanto_ci',
|
||||
[178] = 'utf32_hungarian_ci',
|
||||
[179] = 'utf32_sinhala_ci',
|
||||
[180] = 'utf32_german2_ci',
|
||||
[181] = 'utf32_croatian_ci',
|
||||
[182] = 'utf32_unicode_520_ci',
|
||||
[183] = 'utf32_vietnamese_ci',
|
||||
[192] = 'utf8_unicode_ci',
|
||||
[193] = 'utf8_icelandic_ci',
|
||||
[194] = 'utf8_latvian_ci',
|
||||
[195] = 'utf8_romanian_ci',
|
||||
[196] = 'utf8_slovenian_ci',
|
||||
[197] = 'utf8_polish_ci',
|
||||
[198] = 'utf8_estonian_ci',
|
||||
[199] = 'utf8_spanish_ci',
|
||||
[200] = 'utf8_swedish_ci',
|
||||
[201] = 'utf8_turkish_ci',
|
||||
[202] = 'utf8_czech_ci',
|
||||
[203] = 'utf8_danish_ci',
|
||||
[204] = 'utf8_lithuanian_ci',
|
||||
[205] = 'utf8_slovak_ci',
|
||||
[206] = 'utf8_spanish2_ci',
|
||||
[207] = 'utf8_roman_ci',
|
||||
[208] = 'utf8_persian_ci',
|
||||
[209] = 'utf8_esperanto_ci',
|
||||
[210] = 'utf8_hungarian_ci',
|
||||
[211] = 'utf8_sinhala_ci',
|
||||
[212] = 'utf8_german2_ci',
|
||||
[213] = 'utf8_croatian_ci',
|
||||
[214] = 'utf8_unicode_520_ci',
|
||||
[215] = 'utf8_vietnamese_ci',
|
||||
[223] = 'utf8_general_mysql500_ci',
|
||||
[224] = 'utf8mb4_unicode_ci',
|
||||
[225] = 'utf8mb4_icelandic_ci',
|
||||
[226] = 'utf8mb4_latvian_ci',
|
||||
[227] = 'utf8mb4_romanian_ci',
|
||||
[228] = 'utf8mb4_slovenian_ci',
|
||||
[229] = 'utf8mb4_polish_ci',
|
||||
[230] = 'utf8mb4_estonian_ci',
|
||||
[231] = 'utf8mb4_spanish_ci',
|
||||
[232] = 'utf8mb4_swedish_ci',
|
||||
[233] = 'utf8mb4_turkish_ci',
|
||||
[234] = 'utf8mb4_czech_ci',
|
||||
[235] = 'utf8mb4_danish_ci',
|
||||
[236] = 'utf8mb4_lithuanian_ci',
|
||||
[237] = 'utf8mb4_slovak_ci',
|
||||
[238] = 'utf8mb4_spanish2_ci',
|
||||
[239] = 'utf8mb4_roman_ci',
|
||||
[240] = 'utf8mb4_persian_ci',
|
||||
[241] = 'utf8mb4_esperanto_ci',
|
||||
[242] = 'utf8mb4_hungarian_ci',
|
||||
[243] = 'utf8mb4_sinhala_ci',
|
||||
[244] = 'utf8mb4_german2_ci',
|
||||
[245] = 'utf8mb4_croatian_ci',
|
||||
[246] = 'utf8mb4_unicode_520_ci',
|
||||
[247] = 'utf8mb4_vietnamese_ci',
|
||||
[248] = 'gb18030_chinese_ci',
|
||||
[249] = 'gb18030_bin',
|
||||
[250] = 'gb18030_unicode_520_ci',
|
||||
[255] = 'utf8mb4_0900_ai_ci',
|
||||
[256] = 'utf8mb4_de_pb_0900_ai_ci',
|
||||
[257] = 'utf8mb4_is_0900_ai_ci',
|
||||
[258] = 'utf8mb4_lv_0900_ai_ci',
|
||||
[259] = 'utf8mb4_ro_0900_ai_ci',
|
||||
[260] = 'utf8mb4_sl_0900_ai_ci',
|
||||
[261] = 'utf8mb4_pl_0900_ai_ci',
|
||||
[262] = 'utf8mb4_et_0900_ai_ci',
|
||||
[263] = 'utf8mb4_es_0900_ai_ci',
|
||||
[264] = 'utf8mb4_sv_0900_ai_ci',
|
||||
[265] = 'utf8mb4_tr_0900_ai_ci',
|
||||
[266] = 'utf8mb4_cs_0900_ai_ci',
|
||||
[267] = 'utf8mb4_da_0900_ai_ci',
|
||||
[268] = 'utf8mb4_lt_0900_ai_ci',
|
||||
[269] = 'utf8mb4_sk_0900_ai_ci',
|
||||
[270] = 'utf8mb4_es_trad_0900_ai_ci',
|
||||
[271] = 'utf8mb4_la_0900_ai_ci',
|
||||
[273] = 'utf8mb4_eo_0900_ai_ci',
|
||||
[274] = 'utf8mb4_hu_0900_ai_ci',
|
||||
[275] = 'utf8mb4_hr_0900_ai_ci',
|
||||
[277] = 'utf8mb4_vi_0900_ai_ci',
|
||||
[278] = 'utf8mb4_0900_as_cs',
|
||||
[279] = 'utf8mb4_de_pb_0900_as_cs',
|
||||
[280] = 'utf8mb4_is_0900_as_cs',
|
||||
[281] = 'utf8mb4_lv_0900_as_cs',
|
||||
[282] = 'utf8mb4_ro_0900_as_cs',
|
||||
[283] = 'utf8mb4_sl_0900_as_cs',
|
||||
[284] = 'utf8mb4_pl_0900_as_cs',
|
||||
[285] = 'utf8mb4_et_0900_as_cs',
|
||||
[286] = 'utf8mb4_es_0900_as_cs',
|
||||
[287] = 'utf8mb4_sv_0900_as_cs',
|
||||
[288] = 'utf8mb4_tr_0900_as_cs',
|
||||
[289] = 'utf8mb4_cs_0900_as_cs',
|
||||
[290] = 'utf8mb4_da_0900_as_cs',
|
||||
[291] = 'utf8mb4_lt_0900_as_cs',
|
||||
[292] = 'utf8mb4_sk_0900_as_cs',
|
||||
[293] = 'utf8mb4_es_trad_0900_as_cs',
|
||||
[294] = 'utf8mb4_la_0900_as_cs',
|
||||
[296] = 'utf8mb4_eo_0900_as_cs',
|
||||
[297] = 'utf8mb4_hu_0900_as_cs',
|
||||
[298] = 'utf8mb4_hr_0900_as_cs',
|
||||
[300] = 'utf8mb4_vi_0900_as_cs',
|
||||
[303] = 'utf8mb4_ja_0900_as_cs',
|
||||
[304] = 'utf8mb4_ja_0900_as_cs_ks',
|
||||
[305] = 'utf8mb4_0900_as_ci',
|
||||
[306] = 'utf8mb4_ru_0900_ai_ci',
|
||||
[307] = 'utf8mb4_ru_0900_as_cs',
|
||||
[308] = 'utf8mb4_zh_0900_as_cs',
|
||||
[309] = 'utf8mb4_0900_bin',
|
||||
}
|
||||
|
||||
-- the following charset map is generated from the following mysql query:
|
||||
-- SELECT CHARACTER_SET_NAME, ID
|
||||
-- FROM information_schema.collations
|
||||
-- WHERE IS_DEFAULT = 'Yes' ORDER BY id;
|
||||
local CHARSET_MAP = {
|
||||
_default = 0,
|
||||
big5 = 1,
|
||||
dec8 = 3,
|
||||
cp850 = 4,
|
||||
hp8 = 6,
|
||||
koi8r = 7,
|
||||
latin1 = 8,
|
||||
latin2 = 9,
|
||||
swe7 = 10,
|
||||
ascii = 11,
|
||||
ujis = 12,
|
||||
sjis = 13,
|
||||
hebrew = 16,
|
||||
tis620 = 18,
|
||||
euckr = 19,
|
||||
koi8u = 22,
|
||||
gb2312 = 24,
|
||||
greek = 25,
|
||||
cp1250 = 26,
|
||||
gbk = 28,
|
||||
latin5 = 30,
|
||||
armscii8 = 32,
|
||||
utf8 = 33,
|
||||
ucs2 = 35,
|
||||
cp866 = 36,
|
||||
keybcs2 = 37,
|
||||
macce = 38,
|
||||
macroman = 39,
|
||||
cp852 = 40,
|
||||
latin7 = 41,
|
||||
utf8mb4 = 45,
|
||||
cp1251 = 51,
|
||||
utf16 = 54,
|
||||
utf16le = 56,
|
||||
cp1256 = 57,
|
||||
cp1257 = 59,
|
||||
utf32 = 60,
|
||||
binary = 63,
|
||||
geostd8 = 92,
|
||||
cp932 = 95,
|
||||
eucjpms = 97,
|
||||
gb18030 = 248
|
||||
local collation_codes = index(collation_names)
|
||||
|
||||
local default_collations = {
|
||||
big5 = 'big5_chinese_ci',
|
||||
dec8 = 'dec8_swedish_ci',
|
||||
cp850 = 'cp850_general_ci',
|
||||
hp8 = 'hp8_english_ci',
|
||||
koi8r = 'koi8r_general_ci',
|
||||
latin1 = 'latin1_swedish_ci',
|
||||
latin2 = 'latin2_general_ci',
|
||||
swe7 = 'swe7_swedish_ci',
|
||||
ascii = 'ascii_general_ci',
|
||||
ujis = 'ujis_japanese_ci',
|
||||
sjis = 'sjis_japanese_ci',
|
||||
hebrew = 'hebrew_general_ci',
|
||||
tis620 = 'tis620_thai_ci',
|
||||
euckr = 'euckr_korean_ci',
|
||||
koi8u = 'koi8u_general_ci',
|
||||
gb2312 = 'gb2312_chinese_ci',
|
||||
greek = 'greek_general_ci',
|
||||
cp1250 = 'cp1250_general_ci',
|
||||
gbk = 'gbk_chinese_ci',
|
||||
latin5 = 'latin5_turkish_ci',
|
||||
armscii8 = 'armscii8_general_ci',
|
||||
utf8 = 'utf8_general_ci',
|
||||
ucs2 = 'ucs2_general_ci',
|
||||
cp866 = 'cp866_general_ci',
|
||||
keybcs2 = 'keybcs2_general_ci',
|
||||
macce = 'macce_general_ci',
|
||||
macroman = 'macroman_general_ci',
|
||||
cp852 = 'cp852_general_ci',
|
||||
latin7 = 'latin7_general_ci',
|
||||
cp1251 = 'cp1251_general_ci',
|
||||
utf16 = 'utf16_general_ci',
|
||||
utf16le = 'utf16le_general_ci',
|
||||
cp1256 = 'cp1256_general_ci',
|
||||
cp1257 = 'cp1257_general_ci',
|
||||
utf32 = 'utf32_general_ci',
|
||||
binary = 'binary',
|
||||
geostd8 = 'geostd8_general_ci',
|
||||
cp932 = 'cp932_japanese_ci',
|
||||
eucjpms = 'eucjpms_japanese_ci',
|
||||
gb18030 = 'gb18030_chinese_ci',
|
||||
utf8mb4 = 'utf8mb4_0900_ai_ci',
|
||||
}
|
||||
|
||||
local buffer_type_names = {
|
||||
[ 0] = 'decimal',
|
||||
[ 1] = 'tiny',
|
||||
[ 2] = 'short',
|
||||
[ 3] = 'long',
|
||||
[ 4] = 'float',
|
||||
[ 5] = 'double',
|
||||
[ 6] = 'null',
|
||||
[ 7] = 'timestamp',
|
||||
[ 8] = 'longlong',
|
||||
[ 9] = 'int24',
|
||||
[ 10] = 'date',
|
||||
[ 11] = 'time',
|
||||
[ 12] = 'datetime',
|
||||
[ 13] = 'year',
|
||||
[ 15] = 'varchar',
|
||||
[ 16] = 'bit',
|
||||
[246] = 'newdecimal',
|
||||
[247] = 'enum',
|
||||
[248] = 'set',
|
||||
[249] = 'tiny_blob',
|
||||
[250] = 'medium_blob',
|
||||
[251] = 'long_blob',
|
||||
[252] = 'blob',
|
||||
[253] = 'var_string',
|
||||
[254] = 'string',
|
||||
[255] = 'geometry',
|
||||
}
|
||||
|
||||
local type_names = {
|
||||
tiny = 'tinyint',
|
||||
short = 'shortint',
|
||||
long = 'int',
|
||||
int24 = 'mediumint',
|
||||
longlong = 'bigint',
|
||||
newdecimal = 'decimal',
|
||||
}
|
||||
|
||||
local bin_type_names = {
|
||||
tiny_blob = 'tinyblob',
|
||||
medium_blob = 'mediumblob',
|
||||
long_blob = 'longblob',
|
||||
blob = 'blob',
|
||||
var_string = 'varbinary',
|
||||
string = 'binary',
|
||||
}
|
||||
|
||||
local text_type_names = {
|
||||
tiny_blob = 'tinytext',
|
||||
medium_blob = 'mediumtext',
|
||||
long_blob = 'longtext',
|
||||
blob = 'text',
|
||||
var_string = 'varchar',
|
||||
string = 'char',
|
||||
}
|
||||
|
||||
local conn = {}
|
||||
local mt = {__index = conn}
|
||||
|
||||
-- mysql field value type converters
|
||||
local converters = {}
|
||||
|
||||
for i = 0x01, 0x05 do -- tiny, short, long, float, double
|
||||
converters[i] = tonumber
|
||||
end
|
||||
converters[0x00] = tonumber -- decimal
|
||||
-- converters[0x08] = tonumber -- long long
|
||||
converters[0x09] = tonumber -- int24
|
||||
converters[0x0d] = tonumber -- year
|
||||
converters[0xf6] = tonumber -- newdecimal
|
||||
|
||||
local converters = {
|
||||
tinyint = tonumber,
|
||||
shortint = tonumber,
|
||||
mediumint = tonumber,
|
||||
int = tonumber,
|
||||
bigint = tonumber,
|
||||
year = tonumber,
|
||||
float = tonumber,
|
||||
double = tonumber,
|
||||
}
|
||||
|
||||
local function _get_byte2(data, i)
|
||||
local a, b = strbyte(data, i, i + 1)
|
||||
@ -161,7 +480,7 @@ end
|
||||
|
||||
|
||||
local function _from_cstring(data, i)
|
||||
local last = strfind(data, '\0', i, true)
|
||||
local last = data:find('\0', i, true)
|
||||
if not last then
|
||||
return nil, nil
|
||||
end
|
||||
@ -234,29 +553,10 @@ local function _send_packet(self, req, size)
|
||||
return sock:send(packet)
|
||||
end
|
||||
|
||||
--static, auto-growing buffer allocation pattern (ctype must be vla).
|
||||
local max, ceil, log = math.max, math.ceil, math.log
|
||||
local function nextpow2(x)
|
||||
return max(0, 2^(ceil(log(x) / log(2))))
|
||||
end
|
||||
local function grow_buffer(ctype)
|
||||
local vla = ffi.typeof(ctype)
|
||||
local buf, len = nil, -1
|
||||
return function(minlen)
|
||||
if minlen == false then
|
||||
buf, len = nil, -1
|
||||
elseif minlen > len then
|
||||
len = nextpow2(minlen)
|
||||
buf = vla(len)
|
||||
end
|
||||
return buf, len
|
||||
end
|
||||
end
|
||||
|
||||
local function _recv(self, sz)
|
||||
local buf = self.buf
|
||||
if not buf then
|
||||
buf = grow_buffer'char[?]'
|
||||
buf = buffer'char[?]'
|
||||
self.buf = buf
|
||||
end
|
||||
local buf = buf(sz)
|
||||
@ -335,7 +635,7 @@ local function _from_length_coded_bin(data, pos)
|
||||
end
|
||||
|
||||
if first == 251 then
|
||||
return null, pos + 1
|
||||
return nil, pos + 1
|
||||
end
|
||||
|
||||
if first == 252 then
|
||||
@ -360,8 +660,8 @@ end
|
||||
local function _from_length_coded_str(data, pos)
|
||||
local len
|
||||
len, pos = _from_length_coded_bin(data, pos)
|
||||
if not len or len == null then
|
||||
return null, pos
|
||||
if not len then
|
||||
return nil, pos
|
||||
end
|
||||
return sub(data, pos, pos + len - 1), pos + len
|
||||
end
|
||||
@ -376,6 +676,10 @@ local function _parse_ok_packet(packet)
|
||||
|
||||
res.insert_id, pos = _from_length_coded_bin(packet, pos)
|
||||
|
||||
if res.insert_id == 0 then
|
||||
res.insert_id = nil
|
||||
end
|
||||
|
||||
--print('insert id: ', res.insert_id, ', pos:', pos)
|
||||
|
||||
res.server_status, pos = _get_byte2(packet, pos)
|
||||
@ -386,10 +690,7 @@ local function _parse_ok_packet(packet)
|
||||
|
||||
--print('warning count: ', res.warning_count, ', pos: ', pos)
|
||||
|
||||
local message = _from_length_coded_str(packet, pos)
|
||||
if message and message ~= null then
|
||||
res.message = message
|
||||
end
|
||||
res.message = _from_length_coded_str(packet, pos)
|
||||
|
||||
--print('message: ', res.message, ', pos:', pos)
|
||||
|
||||
@ -419,6 +720,7 @@ local function _parse_err_packet(packet)
|
||||
end
|
||||
|
||||
local message = sub(packet, pos)
|
||||
message = message:gsub('You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ', 'Syntax error: ')
|
||||
return errno, message, sqlstate
|
||||
end
|
||||
|
||||
@ -440,7 +742,7 @@ local AUTO_INCREMENT_FLAG = 512
|
||||
|
||||
local function _parse_field(data, pos)
|
||||
local s, pos = _from_length_coded_str(data, pos)
|
||||
s = s ~= null and s ~= '' and s:lower() or nil
|
||||
s = s and s ~= '' and s:lower() or nil
|
||||
return s, pos
|
||||
end
|
||||
|
||||
@ -450,38 +752,45 @@ local function _parse_field_packet(data)
|
||||
col.catalog, pos = _parse_field(data, 1)
|
||||
col.schema, pos = _parse_field(data, pos)
|
||||
col.table, pos = _parse_field(data, pos)
|
||||
col.orig_table, pos = _parse_field(data, pos)
|
||||
col.origin_table, pos = _parse_field(data, pos)
|
||||
col.name, pos = _parse_field(data, pos)
|
||||
col.orig_name, pos = _parse_field(data, pos)
|
||||
col.origin_name, pos = _parse_field(data, pos)
|
||||
pos = pos + 1 -- ignore the filler
|
||||
col.charsetnr, pos = _get_byte2(data, pos)
|
||||
local collation, pos = _get_byte2(data, pos)
|
||||
col.length, pos = _get_byte4(data, pos)
|
||||
col.type = strbyte(data, pos)
|
||||
local buffer_type = buffer_type_names[strbyte(data, pos)]
|
||||
local text_type_names = collation == 63 and bin_type_names or text_type_names
|
||||
col.type = text_type_names[buffer_type]
|
||||
if col.type then
|
||||
col.collation = collation_names[collation]
|
||||
col.charset = col.collation and col.collation:match'^[^_]+'
|
||||
else
|
||||
col.type = type_names[buffer_type] or buffer_type
|
||||
end
|
||||
pos = pos + 1
|
||||
col.flags, pos = _get_byte2(data, pos)
|
||||
col.not_null = band(col.flags, NOT_NULL_FLAG) ~= 0 or nil
|
||||
col.pri_key = band(col.flags, PRI_KEY_FLAG) ~= 0 or nil
|
||||
col.unique_key = band(col.flags, UNIQUE_KEY_FLAG) ~= 0 or nil
|
||||
col.unsigned = band(col.flags, UNSIGNED_FLAG) ~= 0 or nil
|
||||
col.auto_increment = band(col.flags, AUTO_INCREMENT_FLAG) ~= 0 or nil
|
||||
local flags, pos = _get_byte2(data, pos)
|
||||
col.not_null = band(flags, NOT_NULL_FLAG ) ~= 0 or nil
|
||||
col.pri_key = band(flags, PRI_KEY_FLAG ) ~= 0 or nil
|
||||
col.unique_key = band(flags, UNIQUE_KEY_FLAG ) ~= 0 or nil
|
||||
col.unsigned = band(flags, UNSIGNED_FLAG ) ~= 0 or nil
|
||||
col.auto_increment = band(flags, AUTO_INCREMENT_FLAG) ~= 0 or nil
|
||||
col.decimals = strbyte(data, pos)
|
||||
pos = pos + 1
|
||||
local default = sub(data, pos + 2)
|
||||
if default and default ~= '' then
|
||||
col.default = default
|
||||
end
|
||||
col.default = repl(sub(data, pos + 2), '', nil)
|
||||
return col
|
||||
end
|
||||
|
||||
|
||||
local function _parse_row_data_packet(data, cols, compact)
|
||||
local function _parse_row_data_packet(data, cols, compact, to_array, null_value)
|
||||
local pos = 1
|
||||
local ncols = #cols
|
||||
local row
|
||||
if compact then
|
||||
row = new_tab(ncols, 0)
|
||||
else
|
||||
row = new_tab(0, ncols)
|
||||
if not to_array then
|
||||
if compact then
|
||||
row = new_tab(ncols, 0)
|
||||
else
|
||||
row = new_tab(0, ncols)
|
||||
end
|
||||
end
|
||||
for i = 1, ncols do
|
||||
local value
|
||||
@ -492,16 +801,22 @@ local function _parse_row_data_packet(data, cols, compact)
|
||||
|
||||
--print('row field value: ', value, ', type: ', typ)
|
||||
|
||||
if value ~= null then
|
||||
if value ~= nil then
|
||||
local conv = converters[typ]
|
||||
if conv then
|
||||
value = conv(value)
|
||||
end
|
||||
else
|
||||
value = null_value
|
||||
end
|
||||
|
||||
if to_array then
|
||||
return value
|
||||
end
|
||||
|
||||
if compact then
|
||||
row[i] = value
|
||||
elseif value ~= null then
|
||||
else
|
||||
row[name] = value
|
||||
end
|
||||
end
|
||||
@ -555,9 +870,12 @@ function conn:connect(opts)
|
||||
local database = opts.database or ''
|
||||
local user = opts.user or ''
|
||||
|
||||
local charset = CHARSET_MAP[opts.charset or '_default']
|
||||
if not charset then
|
||||
return nil, 'charset \'' .. opts.charset .. '\' is not supported'
|
||||
local collation = 0 --default
|
||||
if opts.collation then
|
||||
collation = assert(collation_codes[opts.collation], 'invalid collation')
|
||||
elseif opts.charset then
|
||||
collation = assert(default_collations[opts.charset], 'invalid charset')
|
||||
collation = assert(collation_codes[collation])
|
||||
end
|
||||
|
||||
local host = opts.host
|
||||
@ -652,7 +970,7 @@ function conn:connect(opts)
|
||||
-- send a SSL Request Packet
|
||||
local req = _set_byte4(bor(client_flags, CLIENT_SSL))
|
||||
.. _set_byte4(self._max_packet_size)
|
||||
.. strchar(charset)
|
||||
.. strchar(collation)
|
||||
.. strrep('\0', 23)
|
||||
|
||||
local packet_len = 4 + 4 + 1 + 23
|
||||
@ -675,7 +993,7 @@ function conn:connect(opts)
|
||||
|
||||
local req = _set_byte4(client_flags)
|
||||
.. _set_byte4(self._max_packet_size)
|
||||
.. strchar(charset)
|
||||
.. strchar(collation)
|
||||
.. strrep('\0', 23)
|
||||
.. _to_cstring(user)
|
||||
.. _to_binary_coded_string(token)
|
||||
@ -712,7 +1030,7 @@ function conn:connect(opts)
|
||||
return nil, 'bad packet type: ' .. typ
|
||||
end
|
||||
|
||||
self.state = STATE_CONNECTED
|
||||
self.state = 'ready'
|
||||
|
||||
return 1
|
||||
end
|
||||
@ -735,7 +1053,7 @@ function conn:server_ver()
|
||||
end
|
||||
|
||||
function conn:send_query(query)
|
||||
assert(self.state == STATE_CONNECTED)
|
||||
assert(self.state == 'ready')
|
||||
local sock = assert(self.sock)
|
||||
|
||||
self.packet_no = -1
|
||||
@ -748,30 +1066,24 @@ function conn:send_query(query)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
self.state = STATE_COMMAND_SENT
|
||||
self.state = 'read'
|
||||
|
||||
--print('packet sent ', bytes, ' bytes')
|
||||
|
||||
return bytes
|
||||
end
|
||||
|
||||
function conn:read_result(est_nrows, compact)
|
||||
assert(self.state == STATE_COMMAND_SENT)
|
||||
function conn:read_result(opt)
|
||||
assert(self.state == 'read')
|
||||
local sock = assert(self.sock)
|
||||
|
||||
compact = compact == 'compact'
|
||||
if est_nrows == 'compact' then
|
||||
est_nrows = null
|
||||
compact = true
|
||||
end
|
||||
|
||||
local packet, typ, err = _recv_packet(self)
|
||||
if not packet then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if typ == 'ERR' then
|
||||
self.state = STATE_CONNECTED
|
||||
self.state = 'ready'
|
||||
|
||||
local errno, msg, sqlstate = _parse_err_packet(packet)
|
||||
return nil, msg, errno, sqlstate
|
||||
@ -783,12 +1095,12 @@ function conn:read_result(est_nrows, compact)
|
||||
return res, 'again'
|
||||
end
|
||||
|
||||
self.state = STATE_CONNECTED
|
||||
self.state = 'ready'
|
||||
return res
|
||||
end
|
||||
|
||||
if typ ~= 'DATA' then
|
||||
self.state = STATE_CONNECTED
|
||||
self.state = 'ready'
|
||||
|
||||
return nil, 'packet type ' .. typ .. ' not supported'
|
||||
end
|
||||
@ -808,7 +1120,9 @@ function conn:read_result(est_nrows, compact)
|
||||
return nil, err, errno, sqlstate
|
||||
end
|
||||
|
||||
col.index = i
|
||||
cols[i] = col
|
||||
cols[col.name] = col
|
||||
end
|
||||
|
||||
local packet, typ, err = _recv_packet(self)
|
||||
@ -823,7 +1137,11 @@ function conn:read_result(est_nrows, compact)
|
||||
|
||||
-- typ == 'EOF'
|
||||
|
||||
local rows = new_tab(est_nrows or 4, 0)
|
||||
local compact = opt and opt.compact
|
||||
local to_array = opt and opt.to_array and #cols == 1
|
||||
local null_value = opt and opt.null_value
|
||||
|
||||
local rows = new_tab(4, 0)
|
||||
local i = 0
|
||||
while true do
|
||||
--print('reading a row')
|
||||
@ -851,20 +1169,21 @@ function conn:read_result(est_nrows, compact)
|
||||
|
||||
-- typ == 'DATA'
|
||||
|
||||
local row = _parse_row_data_packet(packet, cols, compact)
|
||||
local row = _parse_row_data_packet(packet, cols, compact, to_array, null_value)
|
||||
|
||||
i = i + 1
|
||||
rows[i] = row
|
||||
end
|
||||
|
||||
self.state = STATE_CONNECTED
|
||||
self.state = 'ready'
|
||||
|
||||
return rows, nil, cols
|
||||
end
|
||||
|
||||
function conn:query(query, est_nrows)
|
||||
function conn:query(query, opt)
|
||||
local bytes, err, errcode = self:send_query(query)
|
||||
if not bytes then return nil, err, errcode end
|
||||
return self:read_result(est_nrows)
|
||||
return self:read_result(opt)
|
||||
end
|
||||
|
||||
local qmap = {
|
||||
|
@ -30,7 +30,7 @@ local res = assert(cn:query('create table cats '
|
||||
.. 'name varchar(5))'))
|
||||
|
||||
local res = assert(cn:query('insert into cats (name) '
|
||||
.. 'values (\'Bob\'),(\'\'),(null)'))
|
||||
.. "values ('Bob'),(''),(null)"))
|
||||
|
||||
print(res.affected_rows, ' rows inserted into table cats ',
|
||||
'(last insert id: ', res.insert_id, ')')
|
||||
@ -61,12 +61,8 @@ The `options` argument is a Lua table holding the following keys:
|
||||
* `database`: the MySQL database name.
|
||||
* `user`: MySQL account name for login.
|
||||
* `password`: MySQL account password for login (in clear text).
|
||||
* `charset`: the character set used for the connection, which can be one of:
|
||||
`big5`, `dec8`, `cp850`, `hp8`, `koi8r`, `latin1`, `latin2`,
|
||||
`swe7`, `ascii`, `ujis`, `sjis`, `hebrew`, `tis620`, `euckr`, `koi8u`, `gb2312`, `greek`,
|
||||
`cp1250`, `gbk`, `latin5`, `armscii8`, `utf8`, `ucs2`, `cp866`, `keybcs2`, `macce`,
|
||||
`macroman`, `cp852`, `latin7`, `utf8mb4`, `cp1251`, `utf16`, `utf16le`, `cp1256`,
|
||||
`cp1257`, `utf32`, `binary`, `geostd8`, `cp932`, `eucjpms`, `gb18030`.
|
||||
* `collation`: the collation used for the connection (`charset` is implied with this).
|
||||
* `charset`: the character set used for the connection (the default collation for the charset is selected).
|
||||
* `max_packet_size`: the upper limit for the reply packets sent from the server (default to 1MB).
|
||||
* `ssl`: if `true`, then uses SSL to connect to MySQL (default to `false`).
|
||||
If the server does not have SSL support (or just disabled), the error string
|
||||
@ -83,7 +79,7 @@ Sends the query to the remote MySQL server without waiting for its replies.
|
||||
|
||||
Returns the bytes successfully sent out. Use `read_result()` to read the replies.
|
||||
|
||||
### `cn:read_result([nrows,]['compact']) -> res,nil,cols | nil,err,errcode,sqlstate`
|
||||
### `cn:read_result([options]) -> res,nil|'again',cols | nil,err,errcode,sqlstate`
|
||||
|
||||
Reads in one result returned from the server.
|
||||
|
||||
@ -91,23 +87,12 @@ It returns a Lua table (`res`) describing the MySQL `OK packet`
|
||||
or `result set packet` for the query result.
|
||||
|
||||
For queries corresponding to a result set, it returns an array holding all the rows.
|
||||
Each row holds key-value pairs for each data fields. For instance,
|
||||
|
||||
```lua
|
||||
{
|
||||
{ name = "Bob", age = 32, phone = mysql.null },
|
||||
{ name = "Marry", age = 18, phone = "10666372" }
|
||||
}
|
||||
```
|
||||
The `options` arg can contain:
|
||||
|
||||
If `'compact'` given, it returns an array-of-arrays instead:
|
||||
|
||||
```lua
|
||||
{
|
||||
{ "Bob", 32, null },
|
||||
{ "Marry", 18, "10666372" }
|
||||
}
|
||||
```
|
||||
* `compact = true` -- return an array of arrays instead of an array of `{column->value}` maps.
|
||||
* `to_array = true` -- return an array of values for single-column results.
|
||||
* `null_value = val` -- value to use for `null` (defaults to `nil`).
|
||||
|
||||
For queries that do not correspond to a result set, it returns a Lua table like this:
|
||||
|
||||
@ -126,7 +111,7 @@ will be given the string `again`. One should always check this (second) return
|
||||
value and if it is `again`, then she should call this method again to retrieve
|
||||
more results. This usually happens when the original query contains multiple
|
||||
statements (separated by semicolon in the same query string) or calling a
|
||||
MySQL procedure. See also [Multi-Resultset Support](#multi-resultset-support).
|
||||
MySQL procedure.
|
||||
|
||||
In case of errors, this method returns at most 4 values: `nil`, `err`, `errcode`, and `sqlstate`.
|
||||
The `err` return value contains a string describing the error, the `errcode`
|
||||
@ -135,18 +120,14 @@ the `sqlstate` return value contains the standard SQL error code that consists
|
||||
of 5 characters. Note that, the `errcode` and `sqlstate` might be `nil`
|
||||
if MySQL does not return them.
|
||||
|
||||
The optional argument `nrows` can be used to specify an approximate number
|
||||
of rows for the result set. This value can be used to pre-allocate space
|
||||
in the resulting Lua table for the result set. By default, it takes the value 4.
|
||||
|
||||
### `cn:query(query, [nrows]) -> res,nil,cols | nil,err,errcode,sqlstate`
|
||||
### `cn:query(query, [options]) -> res,nil,cols | nil,err,errcode,sqlstate`
|
||||
|
||||
This is a shortcut for combining the [send_query](#send_query) call
|
||||
and the first [read_result](#read_result) call.
|
||||
|
||||
You should always check if the `err` return value is `again` in case of
|
||||
success because this method will only call [read_result](#read_result)
|
||||
only once for you. See also [Multi-Resultset Support](#multi-resultset-support).
|
||||
once for you.
|
||||
|
||||
### `cn:server_ver() -> s`
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user