1 Star 0 Fork 346

zyzswz / swoole-src

forked from swoole / swoole-src 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
swoole_mysql.c 46.38 KB
一键复制 编辑 原始数据 按行查看 历史
韩天峰 提交于 2017-06-22 17:28 . Merge branch '1.9'
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| Copyright (c) 2012-2015 The Swoole Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "php_swoole.h"
#include "swoole_mysql.h"
#ifdef SW_USE_MYSQLND
#include "ext/mysqlnd/mysqlnd.h"
#include "ext/mysqlnd/mysqlnd_charset.h"
#endif
static PHP_METHOD(swoole_mysql, __construct);
static PHP_METHOD(swoole_mysql, __destruct);
static PHP_METHOD(swoole_mysql, connect);
#ifdef SW_USE_MYSQLND
static PHP_METHOD(swoole_mysql, escape);
#endif
static PHP_METHOD(swoole_mysql, query);
static PHP_METHOD(swoole_mysql, close);
static PHP_METHOD(swoole_mysql, on);
static zend_class_entry swoole_mysql_ce;
static zend_class_entry *swoole_mysql_class_entry_ptr;
static zend_class_entry swoole_mysql_exception_ce;
static zend_class_entry *swoole_mysql_exception_class_entry_ptr;
#define UTF8_MB4 "utf8mb4"
#define UTF8_MB3 "utf8"
typedef struct _mysql_charset
{
unsigned int nr;
const char *name;
const char *collation;
} mysql_charset;
static const mysql_charset swoole_mysql_charsets[] =
{
{ 1, "big5", "big5_chinese_ci" },
{ 3, "dec8", "dec8_swedish_ci" },
{ 4, "cp850", "cp850_general_ci" },
{ 6, "hp8", "hp8_english_ci" },
{ 7, "koi8r", "koi8r_general_ci" },
{ 8, "latin1", "latin1_swedish_ci" },
{ 5, "latin1", "latin1_german1_ci" },
{ 9, "latin2", "latin2_general_ci" },
{ 2, "latin2", "latin2_czech_cs" },
{ 10, "swe7", "swe7_swedish_ci" },
{ 11, "ascii", "ascii_general_ci" },
{ 12, "ujis", "ujis_japanese_ci" },
{ 13, "sjis", "sjis_japanese_ci" },
{ 16, "hebrew", "hebrew_general_ci" },
{ 17, "filename", "filename" },
{ 18, "tis620", "tis620_thai_ci" },
{ 19, "euckr", "euckr_korean_ci" },
{ 21, "latin2", "latin2_hungarian_ci" },
{ 27, "latin2", "latin2_croatian_ci" },
{ 22, "koi8u", "koi8u_general_ci" },
{ 24, "gb2312", "gb2312_chinese_ci" },
{ 25, "greek", "greek_general_ci" },
{ 26, "cp1250", "cp1250_general_ci" },
{ 28, "gbk", "gbk_chinese_ci" },
{ 30, "latin5", "latin5_turkish_ci" },
{ 31, "latin1", "latin1_german2_ci" },
{ 15, "latin1", "latin1_danish_ci" },
{ 32, "armscii8", "armscii8_general_ci" },
{ 33, UTF8_MB3, UTF8_MB3"_general_ci" },
{ 35, "ucs2", "ucs2_general_ci" },
{ 36, "cp866", "cp866_general_ci" },
{ 37, "keybcs2", "keybcs2_general_ci" },
{ 38, "macce", "macce_general_ci" },
{ 39, "macroman", "macroman_general_ci" },
{ 40, "cp852", "cp852_general_ci" },
{ 41, "latin7", "latin7_general_ci" },
{ 20, "latin7", "latin7_estonian_cs" },
{ 57, "cp1256", "cp1256_general_ci" },
{ 59, "cp1257", "cp1257_general_ci" },
{ 63, "binary", "binary" },
{ 97, "eucjpms", "eucjpms_japanese_ci" },
{ 29, "cp1257", "cp1257_lithuanian_ci" },
{ 31, "latin1", "latin1_german2_ci" },
{ 34, "cp1250", "cp1250_czech_cs" },
{ 42, "latin7", "latin7_general_cs" },
{ 43, "macce", "macce_bin" },
{ 44, "cp1250", "cp1250_croatian_ci" },
{ 45, UTF8_MB4, UTF8_MB4"_general_ci" },
{ 46, UTF8_MB4, UTF8_MB4"_bin" },
{ 47, "latin1", "latin1_bin" },
{ 48, "latin1", "latin1_general_ci" },
{ 49, "latin1", "latin1_general_cs" },
{ 51, "cp1251", "cp1251_general_ci" },
{ 14, "cp1251", "cp1251_bulgarian_ci" },
{ 23, "cp1251", "cp1251_ukrainian_ci" },
{ 50, "cp1251", "cp1251_bin" },
{ 52, "cp1251", "cp1251_general_cs" },
{ 53, "macroman", "macroman_bin" },
{ 54, "utf16", "utf16_general_ci" },
{ 55, "utf16", "utf16_bin" },
{ 56, "utf16le", "utf16le_general_ci" },
{ 58, "cp1257", "cp1257_bin" },
{ 60, "utf32", "utf32_general_ci" },
{ 61, "utf32", "utf32_bin" },
{ 62, "utf16le", "utf16le_bin" },
{ 64, "armscii8", "armscii8_bin" },
{ 65, "ascii", "ascii_bin" },
{ 66, "cp1250", "cp1250_bin" },
{ 67, "cp1256", "cp1256_bin" },
{ 68, "cp866", "cp866_bin" },
{ 69, "dec8", "dec8_bin" },
{ 70, "greek", "greek_bin" },
{ 71, "hebrew", "hebrew_bin" },
{ 72, "hp8", "hp8_bin" },
{ 73, "keybcs2", "keybcs2_bin" },
{ 74, "koi8r", "koi8r_bin" },
{ 75, "koi8u", "koi8u_bin" },
{ 77, "latin2", "latin2_bin" },
{ 78, "latin5", "latin5_bin" },
{ 79, "latin7", "latin7_bin" },
{ 80, "cp850", "cp850_bin" },
{ 81, "cp852", "cp852_bin" },
{ 82, "swe7", "swe7_bin" },
{ 83, UTF8_MB3, UTF8_MB3"_bin" },
{ 84, "big5", "big5_bin" },
{ 85, "euckr", "euckr_bin" },
{ 86, "gb2312", "gb2312_bin" },
{ 87, "gbk", "gbk_bin" },
{ 88, "sjis", "sjis_bin" },
{ 89, "tis620", "tis620_bin" },
{ 90, "ucs2", "ucs2_bin" },
{ 91, "ujis", "ujis_bin" },
{ 92, "geostd8", "geostd8_general_ci" },
{ 93, "geostd8", "geostd8_bin" },
{ 94, "latin1", "latin1_spanish_ci" },
{ 95, "cp932", "cp932_japanese_ci" },
{ 96, "cp932", "cp932_bin" },
{ 97, "eucjpms", "eucjpms_japanese_ci" },
{ 98, "eucjpms", "eucjpms_bin" },
{ 99, "cp1250", "cp1250_polish_ci" },
{ 128, "ucs2", "ucs2_unicode_ci" },
{ 129, "ucs2", "ucs2_icelandic_ci" },
{ 130, "ucs2", "ucs2_latvian_ci" },
{ 131, "ucs2", "ucs2_romanian_ci" },
{ 132, "ucs2", "ucs2_slovenian_ci" },
{ 133, "ucs2", "ucs2_polish_ci" },
{ 134, "ucs2", "ucs2_estonian_ci" },
{ 135, "ucs2", "ucs2_spanish_ci" },
{ 136, "ucs2", "ucs2_swedish_ci" },
{ 137, "ucs2", "ucs2_turkish_ci" },
{ 138, "ucs2", "ucs2_czech_ci" },
{ 139, "ucs2", "ucs2_danish_ci" },
{ 140, "ucs2", "ucs2_lithuanian_ci" },
{ 141, "ucs2", "ucs2_slovak_ci" },
{ 142, "ucs2", "ucs2_spanish2_ci" },
{ 143, "ucs2", "ucs2_roman_ci" },
{ 144, "ucs2", "ucs2_persian_ci" },
{ 145, "ucs2", "ucs2_esperanto_ci" },
{ 146, "ucs2", "ucs2_hungarian_ci" },
{ 147, "ucs2", "ucs2_sinhala_ci" },
{ 148, "ucs2", "ucs2_german2_ci" },
{ 149, "ucs2", "ucs2_croatian_ci" },
{ 150, "ucs2", "ucs2_unicode_520_ci" },
{ 151, "ucs2", "ucs2_vietnamese_ci" },
{ 160, "utf32", "utf32_unicode_ci" },
{ 161, "utf32", "utf32_icelandic_ci" },
{ 162, "utf32", "utf32_latvian_ci" },
{ 163, "utf32", "utf32_romanian_ci" },
{ 164, "utf32", "utf32_slovenian_ci" },
{ 165, "utf32", "utf32_polish_ci" },
{ 166, "utf32", "utf32_estonian_ci" },
{ 167, "utf32", "utf32_spanish_ci" },
{ 168, "utf32", "utf32_swedish_ci" },
{ 169, "utf32", "utf32_turkish_ci" },
{ 170, "utf32", "utf32_czech_ci" },
{ 171, "utf32", "utf32_danish_ci" },
{ 172, "utf32", "utf32_lithuanian_ci" },
{ 173, "utf32", "utf32_slovak_ci" },
{ 174, "utf32", "utf32_spanish2_ci" },
{ 175, "utf32", "utf32_roman_ci" },
{ 176, "utf32", "utf32_persian_ci" },
{ 177, "utf32", "utf32_esperanto_ci" },
{ 178, "utf32", "utf32_hungarian_ci" },
{ 179, "utf32", "utf32_sinhala_ci" },
{ 180, "utf32", "utf32_german2_ci" },
{ 181, "utf32", "utf32_croatian_ci" },
{ 182, "utf32", "utf32_unicode_520_ci" },
{ 183, "utf32", "utf32_vietnamese_ci" },
{ 192, UTF8_MB3, UTF8_MB3"_unicode_ci" },
{ 193, UTF8_MB3, UTF8_MB3"_icelandic_ci" },
{ 194, UTF8_MB3, UTF8_MB3"_latvian_ci" },
{ 195, UTF8_MB3, UTF8_MB3"_romanian_ci" },
{ 196, UTF8_MB3, UTF8_MB3"_slovenian_ci" },
{ 197, UTF8_MB3, UTF8_MB3"_polish_ci" },
{ 198, UTF8_MB3, UTF8_MB3"_estonian_ci" },
{ 199, UTF8_MB3, UTF8_MB3"_spanish_ci" },
{ 200, UTF8_MB3, UTF8_MB3"_swedish_ci" },
{ 201, UTF8_MB3, UTF8_MB3"_turkish_ci" },
{ 202, UTF8_MB3, UTF8_MB3"_czech_ci" },
{ 203, UTF8_MB3, UTF8_MB3"_danish_ci" },
{ 204, UTF8_MB3, UTF8_MB3"_lithuanian_ci" },
{ 205, UTF8_MB3, UTF8_MB3"_slovak_ci" },
{ 206, UTF8_MB3, UTF8_MB3"_spanish2_ci" },
{ 207, UTF8_MB3, UTF8_MB3"_roman_ci" },
{ 208, UTF8_MB3, UTF8_MB3"_persian_ci" },
{ 209, UTF8_MB3, UTF8_MB3"_esperanto_ci" },
{ 210, UTF8_MB3, UTF8_MB3"_hungarian_ci" },
{ 211, UTF8_MB3, UTF8_MB3"_sinhala_ci" },
{ 212, UTF8_MB3, UTF8_MB3"_german2_ci" },
{ 213, UTF8_MB3, UTF8_MB3"_croatian_ci" },
{ 214, UTF8_MB3, UTF8_MB3"_unicode_520_ci" },
{ 215, UTF8_MB3, UTF8_MB3"_vietnamese_ci" },
{ 224, UTF8_MB4, UTF8_MB4"_unicode_ci" },
{ 225, UTF8_MB4, UTF8_MB4"_icelandic_ci" },
{ 226, UTF8_MB4, UTF8_MB4"_latvian_ci" },
{ 227, UTF8_MB4, UTF8_MB4"_romanian_ci" },
{ 228, UTF8_MB4, UTF8_MB4"_slovenian_ci" },
{ 229, UTF8_MB4, UTF8_MB4"_polish_ci" },
{ 230, UTF8_MB4, UTF8_MB4"_estonian_ci" },
{ 231, UTF8_MB4, UTF8_MB4"_spanish_ci" },
{ 232, UTF8_MB4, UTF8_MB4"_swedish_ci" },
{ 233, UTF8_MB4, UTF8_MB4"_turkish_ci" },
{ 234, UTF8_MB4, UTF8_MB4"_czech_ci" },
{ 235, UTF8_MB4, UTF8_MB4"_danish_ci" },
{ 236, UTF8_MB4, UTF8_MB4"_lithuanian_ci" },
{ 237, UTF8_MB4, UTF8_MB4"_slovak_ci" },
{ 238, UTF8_MB4, UTF8_MB4"_spanish2_ci" },
{ 239, UTF8_MB4, UTF8_MB4"_roman_ci" },
{ 240, UTF8_MB4, UTF8_MB4"_persian_ci" },
{ 241, UTF8_MB4, UTF8_MB4"_esperanto_ci" },
{ 242, UTF8_MB4, UTF8_MB4"_hungarian_ci" },
{ 243, UTF8_MB4, UTF8_MB4"_sinhala_ci" },
{ 244, UTF8_MB4, UTF8_MB4"_german2_ci" },
{ 245, UTF8_MB4, UTF8_MB4"_croatian_ci" },
{ 246, UTF8_MB4, UTF8_MB4"_unicode_520_ci" },
{ 247, UTF8_MB4, UTF8_MB4"_vietnamese_ci" },
{ 248, "gb18030", "gb18030_chinese_ci" },
{ 249, "gb18030", "gb18030_bin" },
{ 254, UTF8_MB3, UTF8_MB3"_general_cs" },
{ 0, NULL, NULL},
};
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_on, 0, 0, 2)
ZEND_ARG_INFO(0, event_name)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_connect, 0, 0, 2)
ZEND_ARG_ARRAY_INFO(0, server_config, 0)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO()
#ifdef SW_USE_MYSQLND
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_escape, 0, 0, 1)
ZEND_ARG_INFO(0, string)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_query, 0, 0, 2)
ZEND_ARG_INFO(0, sql)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO()
static const zend_function_entry swoole_mysql_methods[] =
{
PHP_ME(swoole_mysql, __construct, arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(swoole_mysql, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
PHP_ME(swoole_mysql, connect, arginfo_swoole_mysql_connect, ZEND_ACC_PUBLIC)
#ifdef SW_USE_MYSQLND
PHP_ME(swoole_mysql, escape, arginfo_swoole_mysql_escape, ZEND_ACC_PUBLIC)
#endif
PHP_ME(swoole_mysql, query, arginfo_swoole_mysql_query, ZEND_ACC_PUBLIC)
PHP_ME(swoole_mysql, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
PHP_ME(swoole_mysql, on, arginfo_swoole_mysql_on, ZEND_ACC_PUBLIC)
PHP_FE_END
};
static void mysql_client_free(mysql_client *client, zval* zobject);
static void mysql_client_free(mysql_client *client, zval* zobject)
{
//close the connection
client->cli->close(client->cli);
//release client object memory
swClient_free(client->cli);
efree(client->cli);
client->cli = NULL;
}
#ifdef SW_MYSQL_DEBUG
static void mysql_client_info(mysql_client *client);
static void mysql_column_info(mysql_field *field);
#endif
static int swoole_mysql_onRead(swReactor *reactor, swEvent *event);
static int swoole_mysql_onWrite(swReactor *reactor, swEvent *event);
static int swoole_mysql_onError(swReactor *reactor, swEvent *event);
static void swoole_mysql_onConnect(mysql_client *client TSRMLS_DC);
static swString *mysql_request_buffer = NULL;
static int isset_event_callback = 0;
void swoole_mysql_init(int module_number TSRMLS_DC)
{
SWOOLE_INIT_CLASS_ENTRY(swoole_mysql_ce, "swoole_mysql", "Swoole\\MySQL", swoole_mysql_methods);
swoole_mysql_class_entry_ptr = zend_register_internal_class(&swoole_mysql_ce TSRMLS_CC);
SWOOLE_CLASS_ALIAS(swoole_mysql, "Swoole\\MySQL");
SWOOLE_INIT_CLASS_ENTRY(swoole_mysql_exception_ce, "swoole_mysql_exception", "Swoole\\MySQL\\Exception", NULL);
swoole_mysql_exception_class_entry_ptr = sw_zend_register_internal_class_ex(&swoole_mysql_exception_ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
SWOOLE_CLASS_ALIAS(swoole_mysql_exception, "Swoole\\MySQL\\Exception");
}
int mysql_request(swString *sql, swString *buffer)
{
bzero(buffer->str, 5);
//length
mysql_pack_length(sql->length + 1, buffer->str);
//command
buffer->str[4] = SW_MYSQL_COM_QUERY;
buffer->length = 5;
return swString_append(buffer, sql);
}
int mysql_get_charset(char *name)
{
const mysql_charset *c = swoole_mysql_charsets;
while (c[0].nr != 0)
{
if (!strcasecmp(c->name, name))
{
return c->nr;
}
++c;
}
return -1;
}
int mysql_get_result(mysql_connector *connector, char *buf, int len)
{
char *tmp = buf;
int packet_length = mysql_uint3korr(tmp);
if (len < packet_length + 4)
{
return 0;
}
//int packet_number = tmp[3];
tmp += 4;
uint8_t opcode = *tmp;
tmp += 1;
//ERROR Packet
if (opcode == 0xff)
{
connector->error_code = *(uint16_t *) tmp;
connector->error_msg = tmp + 2;
connector->error_length = packet_length - 3;
return -1;
}
else
{
return 1;
}
}
/**
1 [0a] protocol version
string[NUL] server version
4 connection id
string[8] auth-plugin-data-part-1
1 [00] filler
2 capability flags (lower 2 bytes)
if more data in the packet:
1 character set
2 status flags
2 capability flags (upper 2 bytes)
if capabilities & CLIENT_PLUGIN_AUTH {
1 length of auth-plugin-data
} else {
1 [00]
}
string[10] reserved (all [00])
if capabilities & CLIENT_SECURE_CONNECTION {
string[$len] auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))
if capabilities & CLIENT_PLUGIN_AUTH {
string[NUL] auth-plugin name
}
*/
int mysql_handshake(mysql_connector *connector, char *buf, int len)
{
char *tmp = buf;
/**
* handshake request
*/
mysql_handshake_request request;
bzero(&request, sizeof(request));
request.packet_length = mysql_uint3korr(tmp);
//continue to wait for data
if (len < request.packet_length + 4)
{
return 0;
}
request.packet_number = tmp[3];
tmp += 4;
request.protocol_version = *tmp;
tmp += 1;
//ERROR Packet
if (request.protocol_version == 0xff)
{
connector->error_code = *(uint16_t *) tmp;
connector->error_msg = tmp + 2;
connector->error_length = request.packet_length - 3;
return -1;
}
//1 [0a] protocol version
request.server_version = tmp;
tmp += (strlen(request.server_version) + 1);
//4 connection id
request.connection_id = *((int *) tmp);
tmp += 4;
//string[8] auth-plugin-data-part-1
memcpy(request.auth_plugin_data, tmp, 8);
tmp += 8;
//1 [00] filler
request.filler = *tmp;
tmp += 1;
//2 capability flags (lower 2 bytes)
memcpy(((char *) (&request.capability_flags)), tmp, 2);
tmp += 2;
if (tmp - tmp < len)
{
//1 character set
request.character_set = *tmp;
tmp += 1;
//2 status flags
memcpy(&request.status_flags, tmp, 2);
tmp += 2;
//2 capability flags (upper 2 bytes)
memcpy(((char *) (&request.capability_flags) + 2), tmp, 2);
tmp += 2;
request.l_auth_plugin_data = *tmp;
tmp += 1;
memcpy(&request.reserved, tmp, sizeof(request.reserved));
tmp += sizeof(request.reserved);
if (request.capability_flags & SW_MYSQL_CLIENT_SECURE_CONNECTION)
{
int len = MAX(13, request.l_auth_plugin_data - 8);
memcpy(request.auth_plugin_data + 8, tmp, len);
tmp += len;
}
if (request.capability_flags & SW_MYSQL_CLIENT_PLUGIN_AUTH)
{
request.auth_plugin_name = tmp;
request.l_auth_plugin_name = MIN(strlen(tmp), len - (tmp - buf));
}
}
int value;
tmp = connector->buf + 4;
//capability flags, CLIENT_PROTOCOL_41 always set
value = SW_MYSQL_CLIENT_PROTOCOL_41 | SW_MYSQL_CLIENT_SECURE_CONNECTION | SW_MYSQL_CLIENT_CONNECT_WITH_DB | SW_MYSQL_CLIENT_PLUGIN_AUTH;
memcpy(tmp, &value, sizeof(value));
tmp += 4;
//max-packet size
value = 300;
memcpy(tmp, &value, sizeof(value));
tmp += 4;
//use the server character_set when the character_set is not set.
if (connector->character_set == 0)
{
connector->character_set = request.character_set;
}
//character set
*tmp = connector->character_set;
tmp += 1;
//string[23] reserved (all [0])
tmp += 23;
//string[NUL] username
memcpy(tmp, connector->user, connector->user_len);
tmp[connector->user_len] = '\0';
tmp += (connector->user_len + 1);
if (connector->password_len > 0)
{
//auth-response
char hash_0[20];
bzero(hash_0, sizeof (hash_0));
php_swoole_sha1(connector->password, connector->password_len, (uchar *) hash_0);
char hash_1[20];
bzero(hash_1, sizeof (hash_1));
php_swoole_sha1(hash_0, sizeof (hash_0), (uchar *) hash_1);
char str[40];
memcpy(str, request.auth_plugin_data, 20);
memcpy(str + 20, hash_1, 20);
char hash_2[20];
php_swoole_sha1(str, sizeof (str), (uchar *) hash_2);
char hash_3[20];
int *a = (int *) hash_2;
int *b = (int *) hash_0;
int *c = (int *) hash_3;
int i;
for (i = 0; i < 5; i++)
{
c[i] = a[i] ^ b[i];
}
*tmp = 20;
memcpy(tmp + 1, hash_3, 20);
tmp += 21;
}
else
{
*tmp = 0;
tmp++;
}
//string[NUL] database
memcpy(tmp, connector->database, connector->database_len);
tmp[connector->database_len] = '\0';
tmp += (connector->database_len + 1);
//string[NUL] auth plugin name
memcpy(tmp, request.auth_plugin_name, request.l_auth_plugin_name);
tmp[request.l_auth_plugin_name] = '\0';
tmp += (request.l_auth_plugin_name + 1);
connector->packet_length = tmp - connector->buf - 4;
mysql_pack_length(connector->packet_length, connector->buf);
connector->buf[3] = 1;
return 1;
}
int mysql_response(mysql_client *client)
{
swString *buffer = client->buffer;
char *p = buffer->str + buffer->offset;
int ret;
char nul;
int n_buf = buffer->length - buffer->offset;
while (n_buf > 0)
{
switch (client->state)
{
case SW_MYSQL_STATE_READ_START:
if (buffer->length - buffer->offset < 5)
{
client->response.wait_recv = 1;
return SW_ERR;
}
client->response.packet_length = mysql_uint3korr(p);
client->response.packet_number = p[3];
p += 4;
n_buf -= 4;
if (n_buf < client->response.packet_length)
{
client->response.wait_recv = 1;
return SW_ERR;
}
client->response.response_type = p[0];
p ++;
n_buf --;
/* error */
if (client->response.response_type == 0xff)
{
client->response.error_code = mysql_uint2korr(p);
/* status flag 1byte (#), skip.. */
memcpy(client->response.status_msg, p + 3, 5);
client->response.server_msg = p + 8;
/**
* int<1> header [ff] header of the ERR packet
* int<2> error_code error-code
* if capabilities & CLIENT_PROTOCOL_41 {
* string[1] sql_state_marker # marker of the SQL State
* string[5] sql_state SQL State
* }
*/
client->response.l_server_msg = client->response.packet_length - 9;
client->state = SW_MYSQL_STATE_READ_END;
return SW_OK;
}
/* eof */
else if (client->response.response_type == 0xfe)
{
client->response.warnings = mysql_uint2korr(p);
client->response.status_code = mysql_uint2korr(p + 2);
client->state = SW_MYSQL_STATE_READ_END;
return SW_OK;
}
/* ok */
else if (client->response.response_type == 0)
{
/* affected rows */
ret = mysql_length_coded_binary(p, &client->response.affected_rows, &nul, n_buf);
n_buf -= ret;
p += ret;
/* insert id */
ret = mysql_length_coded_binary(p, &client->response.insert_id, &nul, n_buf);
n_buf -= ret;
p += ret;
/* server status */
client->response.status_code = mysql_uint2korr(p);
n_buf -= 2;
p += 2;
/* server warnings */
client->response.warnings = mysql_uint2korr(p);
client->state = SW_MYSQL_STATE_READ_END;
return SW_OK;
}
/* result set */
else
{
//Protocol::LengthEncodedInteger
ret = mysql_length_coded_binary(p - 1, &client->response.num_column, &nul, n_buf + 1);
if (ret < 0)
{
return SW_ERR;
}
client->buffer->offset += (4 + ret);
client->response.columns = ecalloc(client->response.num_column, sizeof(mysql_field));
client->state = SW_MYSQL_STATE_READ_FIELD;
break;
}
case SW_MYSQL_STATE_READ_FIELD:
if (mysql_read_columns(client) < 0)
{
return SW_ERR;
}
else
{
client->state = SW_MYSQL_STATE_READ_ROW;
break;
}
case SW_MYSQL_STATE_READ_ROW:
if (mysql_read_rows(client) < 0)
{
return SW_ERR;
}
else
{
client->state = SW_MYSQL_STATE_READ_END;
return SW_OK;
}
default:
return SW_ERR;
}
}
return SW_OK;
}
#ifdef SW_MYSQL_DEBUG
void mysql_client_info(mysql_client *client)
{
printf("\n"SW_START_LINE"\nmysql_client\nbuffer->offset=%ld\nbuffer->length=%ld\nstatus=%d\n"
"packet_length=%d\npacket_number=%d\n"
"insert_id=%d\naffected_rows=%d\n"
"warnings=%d\n"SW_END_LINE, client->buffer->offset, client->buffer->length, client->response.status_code,
client->response.packet_length, client->response.packet_number,
client->response.insert_id, client->response.affected_rows,
client->response.warnings);
int i;
if (client->response.num_column)
{
for (i = 0; i < client->response.num_column; i++)
{
mysql_column_info(&client->response.columns[i]);
}
}
}
void mysql_column_info(mysql_field *field)
{
printf("\n"SW_START_LINE"\nname=%s, table=%s, db=%s\n"
"name_length=%d, table_length=%d, db_length=%d\n"
"catalog=%s, default_value=%s\n"
"length=%ld, type=%d\n"SW_END_LINE,
field->name, field->table, field->db,
field->name_length, field->table_length, field->db_length,
field->catalog, field->def,
field->length, field->type
);
}
#endif
static PHP_METHOD(swoole_mysql, __construct)
{
if (!mysql_request_buffer)
{
mysql_request_buffer = swString_new(SW_MYSQL_QUERY_INIT_SIZE);
if (!mysql_request_buffer)
{
swoole_php_fatal_error(E_ERROR, "[1] swString_new(%d) failed.", SW_HTTP_RESPONSE_INIT_SIZE);
RETURN_FALSE;
}
}
mysql_client *client = emalloc(sizeof(mysql_client));
bzero(client, sizeof(mysql_client));
swoole_set_object(getThis(), client);
}
static PHP_METHOD(swoole_mysql, connect)
{
zval *server_info;
zval *callback;
char buf[2048];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &server_info, &callback) == FAILURE)
{
RETURN_FALSE;
}
php_swoole_array_separate(server_info);
HashTable *_ht = Z_ARRVAL_P(server_info);
zval *value;
mysql_client *client = swoole_get_object(getThis());
mysql_connector *connector = &client->connector;
if (php_swoole_array_get_value(_ht, "host", value))
{
convert_to_string(value);
connector->host = Z_STRVAL_P(value);
connector->host_len = Z_STRLEN_P(value);
}
else
{
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, "HOST parameter is required.", 11 TSRMLS_CC);
RETURN_FALSE;
}
if (php_swoole_array_get_value(_ht, "port", value))
{
convert_to_long(value);
connector->port = Z_LVAL_P(value);
}
else
{
connector->port = SW_MYSQL_DEFAULT_PORT;
}
if (php_swoole_array_get_value(_ht, "user", value))
{
convert_to_string(value);
connector->user = Z_STRVAL_P(value);
connector->user_len = Z_STRLEN_P(value);
}
else
{
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, "USER parameter is required.", 11 TSRMLS_CC);
RETURN_FALSE;
}
if (php_swoole_array_get_value(_ht, "password", value))
{
convert_to_string(value);
connector->password = Z_STRVAL_P(value);
connector->password_len = Z_STRLEN_P(value);
}
else
{
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, "PASSWORD parameter is required.", 11 TSRMLS_CC);
RETURN_FALSE;
}
if (php_swoole_array_get_value(_ht, "database", value))
{
convert_to_string(value);
connector->database = Z_STRVAL_P(value);
connector->database_len = Z_STRLEN_P(value);
}
else
{
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, "DATABASE parameter is required.", 11 TSRMLS_CC);
RETURN_FALSE;
}
if (php_swoole_array_get_value(_ht, "timeout", value))
{
convert_to_double(value);
connector->timeout = Z_DVAL_P(value);
}
else
{
connector->timeout = SW_MYSQL_CONNECT_TIMEOUT;
}
if (php_swoole_array_get_value(_ht, "charset", value))
{
convert_to_string(value);
connector->character_set = mysql_get_charset(Z_STRVAL_P(value));
if (connector->character_set < 0)
{
snprintf(buf, sizeof(buf), "unknown charset [%s].", Z_STRVAL_P(value));
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, buf, 11 TSRMLS_CC);
RETURN_FALSE;
}
}
//use the server default charset.
else
{
connector->character_set = 0;
}
swClient *cli = emalloc(sizeof(swClient));
int type = SW_SOCK_TCP;
if (strncasecmp(connector->host, ZEND_STRL("unix:/")) == 0)
{
connector->host = connector->host + 5;
connector->host_len = connector->host_len - 5;
type = SW_SOCK_UNIX_STREAM;
}
else if (strchr(connector->host, ':'))
{
type = SW_SOCK_TCP6;
}
php_swoole_check_reactor();
if (!isset_event_callback)
{
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_MYSQL | SW_EVENT_READ, swoole_mysql_onRead);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_MYSQL | SW_EVENT_WRITE, swoole_mysql_onWrite);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_MYSQL | SW_EVENT_ERROR, swoole_mysql_onError);
}
//create socket
if (swClient_create(cli, type, 0) < 0)
{
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, "swClient_create failed.", 1 TSRMLS_CC);
RETURN_FALSE;
}
//tcp nodelay
if (type != SW_SOCK_UNIX_STREAM)
{
int tcp_nodelay = 1;
if (setsockopt(cli->socket->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1)
{
swoole_php_sys_error(E_WARNING, "setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) failed.", cli->socket->fd);
}
}
//connect to mysql server
int ret = cli->connect(cli, connector->host, connector->port, connector->timeout, 1);
if ((ret < 0 && errno == EINPROGRESS) || ret == 0)
{
if (SwooleG.main_reactor->add(SwooleG.main_reactor, cli->socket->fd, PHP_SWOOLE_FD_MYSQL | SW_EVENT_WRITE) < 0)
{
RETURN_FALSE;
}
}
else
{
snprintf(buf, sizeof(buf), "connect to mysql server[%s:%d] failed.", connector->host, connector->port);
zend_throw_exception(swoole_mysql_exception_class_entry_ptr, buf, 2 TSRMLS_CC);
RETURN_FALSE;
}
zend_update_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("onConnect"), callback TSRMLS_CC);
zend_update_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("serverInfo"), server_info TSRMLS_CC);
zend_update_property_long(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("sock"), cli->socket->fd TSRMLS_CC);
client->buffer = swString_new(SW_BUFFER_SIZE_BIG);
client->fd = cli->socket->fd;
client->object = getThis();
client->cli = cli;
sw_copy_to_stack(client->object, client->_object);
sw_zval_add_ref(&client->object);
sw_zval_ptr_dtor(&server_info);
swConnection *_socket = swReactor_get(SwooleG.main_reactor, cli->socket->fd);
_socket->object = client;
_socket->active = 0;
RETURN_TRUE;
}
static PHP_METHOD(swoole_mysql, query)
{
zval *callback;
swString sql;
bzero(&sql, sizeof(sql));
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &sql.str, &sql.length, &callback) == FAILURE)
{
return;
}
if (sql.length <= 0)
{
swoole_php_fatal_error(E_WARNING, "Query is empty.");
RETURN_FALSE;
}
mysql_client *client = swoole_get_object(getThis());
if (!client)
{
swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_mysql.");
RETURN_FALSE;
}
if (!client->cli)
{
swoole_php_fatal_error(E_WARNING, "mysql connection#%d is closed.", client->fd);
RETURN_FALSE;
}
if (client->state != SW_MYSQL_STATE_QUERY)
{
swoole_php_fatal_error(E_WARNING, "mysql client is waiting response, cannot send new sql query.");
RETURN_FALSE;
}
sw_zval_add_ref(&callback);
client->callback = sw_zval_dup(callback);
swString_clear(mysql_request_buffer);
if (mysql_request(&sql, mysql_request_buffer) < 0)
{
RETURN_FALSE;
}
//send query
if (SwooleG.main_reactor->write(SwooleG.main_reactor, client->fd, mysql_request_buffer->str, mysql_request_buffer->length) < 0)
{
//connection is closed
if (swConnection_error(errno) == SW_CLOSE)
{
zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("connected"), 0 TSRMLS_CC);
zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("errno"), 2006 TSRMLS_CC);
}
RETURN_FALSE;
}
else
{
client->state = SW_MYSQL_STATE_READ_START;
RETURN_TRUE;
}
}
static PHP_METHOD(swoole_mysql, __destruct)
{
mysql_client *client = swoole_get_object(getThis());
if (!client)
{
return;
}
if (client->state != SW_MYSQL_STATE_CLOSED && client->cli)
{
zval *retval = NULL;
zval *zobject = getThis();
client->cli->destroyed = 1;
sw_zend_call_method_with_0_params(&zobject, swoole_mysql_class_entry_ptr, NULL, "close", &retval);
if (retval)
{
sw_zval_ptr_dtor(&retval);
}
}
//release buffer memory
if (client->buffer)
{
swString_free(client->buffer);
}
efree(client);
swoole_set_object(getThis(), NULL);
}
static PHP_METHOD(swoole_mysql, close)
{
mysql_client *client = swoole_get_object(getThis());
if (!client)
{
swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_mysql.");
RETURN_FALSE;
}
if (!client->cli)
{
swoole_php_fatal_error(E_WARNING, "mysql connection#%d is closed.", client->fd);
RETURN_FALSE;
}
if (client->cli->socket->closing)
{
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSING, "The mysql connection[%d] is closing.", client->fd);
RETURN_FALSE;
}
zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("connected"), 0 TSRMLS_CC);
SwooleG.main_reactor->del(SwooleG.main_reactor, client->fd);
swConnection *socket = swReactor_get(SwooleG.main_reactor, client->fd);
socket->object = NULL;
zend_bool is_destroyed = client->cli->destroyed;
zval *retval = NULL;
zval **args[1];
zval *object = getThis();
if (client->onClose)
{
client->cli->socket->closing = 1;
args[0] = &object;
if (sw_call_user_function_ex(EG(function_table), NULL, client->onClose, &retval, 1, args, 0, NULL TSRMLS_CC) != SUCCESS)
{
swoole_php_fatal_error(E_WARNING, "swoole_mysql onClose callback error.");
}
if (EG(exception))
{
zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
}
if (retval)
{
sw_zval_ptr_dtor(&retval);
}
}
mysql_client_free(client, getThis());
if (!is_destroyed)
{
sw_zval_ptr_dtor(&object);
}
}
static PHP_METHOD(swoole_mysql, on)
{
char *name;
zend_size_t len;
zval *cb;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &len, &cb) == FAILURE)
{
return;
}
mysql_client *client = swoole_get_object(getThis());
if (!client)
{
swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_mysql.");
RETURN_FALSE;
}
if (strncasecmp("close", name, len) == 0)
{
zend_update_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("onClose"), cb TSRMLS_CC);
client->onClose = sw_zend_read_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("onClose"), 0 TSRMLS_CC);
sw_copy_to_stack(client->onClose, client->_onClose);
}
else
{
swoole_php_error(E_WARNING, "Unknown event type[%s]", name);
RETURN_FALSE;
}
RETURN_TRUE;
}
static int swoole_mysql_onError(swReactor *reactor, swEvent *event)
{
swClient *cli = event->socket->object;
if (cli->socket->active)
{
#if PHP_MAJOR_VERSION < 7
TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL);
#endif
mysql_client *client = event->socket->object;
if (!client)
{
close(event->fd);
return SW_ERR;
}
zval *retval = NULL;
zval *zobject = client->object;
sw_zend_call_method_with_0_params(&zobject, swoole_mysql_class_entry_ptr, NULL, "close", &retval);
if (retval)
{
sw_zval_ptr_dtor(&retval);
}
return SW_OK;
}
else
{
return swoole_mysql_onWrite(reactor, event);
}
}
static void swoole_mysql_onConnect(mysql_client *client TSRMLS_DC)
{
zval *zobject = client->object;
zval *callback = sw_zend_read_property(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("onConnect"), 0 TSRMLS_CC);
zval *retval = NULL;
zval *result;
zval **args[2];
SW_MAKE_STD_ZVAL(result);
if (client->connector.error_code > 0)
{
zend_update_property_stringl(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("connect_error"), client->connector.error_msg, client->connector.error_length TSRMLS_CC);
zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("connect_errno"), client->connector.error_code TSRMLS_CC);
ZVAL_BOOL(result, 0);
}
else
{
zend_update_property_bool(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("connected"), 1 TSRMLS_CC);
ZVAL_BOOL(result, 1);
}
args[0] = &zobject;
args[1] = &result;
if (sw_call_user_function_ex(EG(function_table), NULL, callback, &retval, 2, args, 0, NULL TSRMLS_CC) != SUCCESS)
{
swoole_php_fatal_error(E_WARNING, "swoole_mysql onConnect handler error.");
}
if (EG(exception))
{
zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
}
if (retval != NULL)
{
sw_zval_ptr_dtor(&retval);
}
sw_zval_ptr_dtor(&result);
if (client->connector.error_code > 0)
{
retval = NULL;
//close
sw_zend_call_method_with_0_params(&zobject, swoole_mysql_class_entry_ptr, NULL, "close", &retval);
if (retval)
{
sw_zval_ptr_dtor(&retval);
}
}
}
static int swoole_mysql_onWrite(swReactor *reactor, swEvent *event)
{
#if PHP_MAJOR_VERSION < 7
TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL);
#endif
if (event->socket->active)
{
return swReactor_onWrite(SwooleG.main_reactor, event);
}
socklen_t len = sizeof(SwooleG.error);
if (getsockopt(event->fd, SOL_SOCKET, SO_ERROR, &SwooleG.error, &len) < 0)
{
swWarn("getsockopt(%d) failed. Error: %s[%d]", event->fd, strerror(errno), errno);
return SW_ERR;
}
mysql_client *client = event->socket->object;
//success
if (SwooleG.error == 0)
{
//listen read event
SwooleG.main_reactor->set(SwooleG.main_reactor, event->fd, PHP_SWOOLE_FD_MYSQL | SW_EVENT_READ);
//connected
event->socket->active = 1;
client->handshake = SW_MYSQL_HANDSHAKE_WAIT_REQUEST;
}
else
{
client->connector.error_code = SwooleG.error;
client->connector.error_msg = strerror(SwooleG.error);
client->connector.error_length = strlen(client->connector.error_msg);
mysql_client_free(client, client->object);
swoole_mysql_onConnect(client TSRMLS_CC);
}
return SW_OK;
}
static int swoole_mysql_onHandShake(mysql_client *client TSRMLS_DC)
{
swString *buffer = client->buffer;
swClient *cli = client->cli;
mysql_connector *connector = &client->connector;
int n = cli->recv(cli, buffer->str + buffer->length, buffer->size - buffer->length, 0);
if (n < 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swSysError("Read from socket[%d] failed.", cli->socket->fd);
return SW_ERR;
case SW_CLOSE:
goto system_call_error;
case SW_WAIT:
return SW_OK;
default:
return SW_ERR;
}
}
else if (n == 0)
{
errno = ECONNRESET;
goto system_call_error;
}
buffer->length += n;
int ret;
if (client->handshake == SW_MYSQL_HANDSHAKE_WAIT_REQUEST)
{
ret = mysql_handshake(connector, buffer->str, buffer->length);
if (ret < 0)
{
swoole_mysql_onConnect(client TSRMLS_CC);
}
else if (ret > 0)
{
if (cli->send(cli, connector->buf, connector->packet_length + 4, 0) < 0)
{
system_call_error: connector->error_code = errno;
connector->error_msg = strerror(errno);
connector->error_length = strlen(connector->error_msg);
swoole_mysql_onConnect(client TSRMLS_CC);
return SW_OK;
}
else
{
swString_clear(buffer);
client->handshake = SW_MYSQL_HANDSHAKE_WAIT_RESULT;
}
}
}
else
{
ret = mysql_get_result(connector, buffer->str, buffer->length);
if (ret < 0)
{
swoole_mysql_onConnect(client TSRMLS_CC);
}
else if (ret > 0)
{
swString_clear(buffer);
client->handshake = SW_MYSQL_HANDSHAKE_COMPLETED;
swoole_mysql_onConnect(client TSRMLS_CC);
}
}
return SW_OK;
}
static int swoole_mysql_onRead(swReactor *reactor, swEvent *event)
{
#if PHP_MAJOR_VERSION < 7
TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL);
#endif
mysql_client *client = event->socket->object;
if (client->handshake != SW_MYSQL_HANDSHAKE_COMPLETED)
{
return swoole_mysql_onHandShake(client TSRMLS_CC);
}
int sock = event->fd;
int ret;
zval *zobject = client->object;
swString *buffer = client->buffer;
zval **args[2];
zval *callback = NULL;
zval *retval = NULL;
zval *result = NULL;
while(1)
{
ret = recv(sock, buffer->str + buffer->length, buffer->size - buffer->length, 0);
if (ret < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swSysError("Read from socket[%d] failed.", event->fd);
return SW_ERR;
case SW_CLOSE:
goto close_fd;
case SW_WAIT:
goto parse_response;
default:
return SW_ERR;
}
}
}
else if (ret == 0)
{
close_fd:
if (client->state == SW_MYSQL_STATE_READ_END)
{
goto parse_response;
}
sw_zend_call_method_with_0_params(&zobject, swoole_mysql_class_entry_ptr, NULL, "close", &retval);
if (retval)
{
sw_zval_ptr_dtor(&retval);
}
return SW_OK;
}
else
{
buffer->length += ret;
//recv again
if (buffer->length == buffer->size)
{
if (swString_extend(buffer, buffer->size * 2) < 0)
{
swoole_php_fatal_error(E_ERROR, "malloc failed.");
reactor->del(SwooleG.main_reactor, event->fd);
}
continue;
}
parse_response:
if (mysql_response(client) < 0)
{
return SW_OK;
}
zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("affected_rows"), client->response.affected_rows TSRMLS_CC);
zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("insert_id"), client->response.insert_id TSRMLS_CC);
client->state = SW_MYSQL_STATE_QUERY;
args[0] = &zobject;
//OK
if (client->response.response_type == 0)
{
SW_ALLOC_INIT_ZVAL(result);
ZVAL_BOOL(result, 1);
}
//ERROR
else if (client->response.response_type == 255)
{
SW_ALLOC_INIT_ZVAL(result);
ZVAL_BOOL(result, 0);
zend_update_property_stringl(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("error"), client->response.server_msg, client->response.l_server_msg TSRMLS_CC);
zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("errno"), client->response.error_code TSRMLS_CC);
}
//ResultSet
else
{
result = client->response.result_array;
}
args[1] = &result;
callback = client->callback;
if (sw_call_user_function_ex(EG(function_table), NULL, callback, &retval, 2, args, 0, NULL TSRMLS_CC) != SUCCESS)
{
swoole_php_fatal_error(E_WARNING, "swoole_async_mysql callback[2] handler error.");
reactor->del(SwooleG.main_reactor, event->fd);
}
if (EG(exception))
{
zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
}
/* free memory */
if (retval)
{
sw_zval_ptr_dtor(&retval);
}
if (result)
{
sw_zval_free(result);
}
//free callback object
sw_zval_free(callback);
swConnection *_socket = swReactor_get(SwooleG.main_reactor, event->fd);
if (_socket->object)
{
//clear buffer
swString_clear(client->buffer);
bzero(&client->response, sizeof(client->response));
}
return SW_OK;
}
}
return SW_OK;
}
#ifdef SW_USE_MYSQLND
static PHP_METHOD(swoole_mysql, escape)
{
swString str;
bzero(&str, sizeof(str));
long flags;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str.str, &str.length, &flags) == FAILURE)
{
return;
}
if (str.length <= 0)
{
swoole_php_fatal_error(E_WARNING, "String is empty.");
RETURN_FALSE;
}
mysql_client *client = swoole_get_object(getThis());
if (!client)
{
swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_mysql.");
RETURN_FALSE;
}
if (!client->cli)
{
swoole_php_fatal_error(E_WARNING, "mysql connection#%d is closed.", client->fd);
RETURN_FALSE;
}
char *newstr = safe_emalloc(2, str.length + 1, 1);
if (newstr == NULL)
{
swoole_php_fatal_error(E_ERROR, "emalloc(%ld) failed.", str.length + 1);
RETURN_FALSE;
}
const MYSQLND_CHARSET* cset = mysqlnd_find_charset_nr(client->connector.character_set);
int newstr_len = mysqlnd_cset_escape_slashes(cset, newstr, str.str, str.length TSRMLS_CC);
if (newstr_len < 0)
{
swoole_php_fatal_error(E_ERROR, "mysqlnd_cset_escape_slashes() failed.");
RETURN_FALSE;
}
SW_RETURN_STRINGL(newstr, newstr_len, 0);
}
#endif
C
1
https://gitee.com/zyzswz/swoole.git
git@gitee.com:zyzswz/swoole.git
zyzswz
swoole
swoole-src
master

搜索帮助