diff --git a/YAF_DB.md b/YAF_DB.md
new file mode 100644
index 00000000..14309d3a
--- /dev/null
+++ b/YAF_DB.md
@@ -0,0 +1,839 @@
+# yaf_db
+
+## Catalogue
+ - Instruction
+ - Requirement
+ - Create test table
+ - Start yaf_db
+ - Init yaf_db connection
+ - Native SQL query
+ - Error Info
+ - Where statement
+ - Select statement
+ - Insert statement
+ - Replace statement
+ - Update statement
+ - Delete statement
+ - Whole Example
+ - Database Transaction
+ - Data Caching
+ - MySQL Database Connection Pool
+ - Redis Connection Pool
+
+## Instruction
+ 1、Fast : yaf_db is an mysql database ORM written in c, built in php extension, as we known, database ORM is a very time-consuming operation, especially for interpretive languages such as PHP, and for a project, the proportion of ORM is very high,so here I will implement the MySQL ORM operation in C language, and use the performance of C language to improve the performance of ORM.
+ 2、Safe : yaf_db can solve SQL injection through parameter binding.
+ 3、Powerful : concise and powerful usage , support any operation in database.
+ 4、Easy : Extremely easy to learn and use, friendly construction.
+ 5、Data-cache : yaf_db supports data caching. You can use redis as a medium to cache database data, but remember that when the update, insert, and delete operations involve caching data, you need to delete your cache to ensure data consistency.
+ 6、Connection-pool : yaf_db uses a special way to establish a stable connection pool with MySQL. performance can be increased by at least 30%, According to PHP's operating mechanism, long connections can only reside on top of the worker process after establishment, that is, how many work processes are there. How many long connections, for example, we have 10 PHP servers, each launching 1000 PHP-FPM worker processes, they connect to the same MySQL instance, then there will be a maximum of 10,000 long connections on this MySQL instance, the number is completely Out of control! And PHP's connection pool heartbeat mechanism is not perfect
+ 1、快速 - yaf_db是一个为PHP扩展写的纯C语言写的mysql数据库ORM扩展,众所周知,数据库ORM是一个非常耗时的操作,尤其对于解释性语言如PHP,而且对于一个项目来说,ORM大多数情况能占到项目很大的一个比例,所以这里我将MySQL的ORM操作用C语言实现,利用C语言的性能,提升ORM的性能。
+ 2、安全 - yaf_db能通过参数绑定的方式解决SQL注入的问题。
+ 3、强大 - 便捷的函数,支持所有数据库操作。
+ 4、简单 - 使用和学习非常简单,界面友好。
+ 5、数据缓存 - yaf_db支持数据缓存,你可以采用redis作为介质来缓存数据库的数据,但是记得在update、insert、delete 操作涉及到与缓存数据相关的数据修改时,需要按key删除您的缓存,以保证数据一致性。
+ 6、连接池 - yaf_db通过一种特殊的方式来建立一个稳定的与MySQL之间的连接池,性能至少能提升30%,按照 PHP 的运行机制,长连接在建立之后只能寄居在工作进程之上,也就是说有多少个工作进程,就有多少个长连接,打个比方,我们有 10 台 PHP 服务器,每台启动 1000 个 PHP-FPM 工作进程,它们连接同一个 MySQL 实例,那么此 MySQL 实例上最多将存在 10000 个长连接,数量完全失控了!而且PHP的连接池心跳机制不完善。
+
+#### 中文文档(Chinese Document): https://blog.csdn.net/caohao0591/article/details/84390713
+
+## Requirement
+- PHP 7.0 +
+- need support **PDO** for mysql
+
+## Create test table
+```sql
+CREATE TABLE `user_info_test` (
+ `uid` int(11) NOT NULL COMMENT 'userid' AUTO_INCREMENT,
+ `username` varchar(64) NOT NULL COMMENT 'username',
+ `sexuality` varchar(8) DEFAULT 'male' COMMENT 'sexuality:male - 男性 female - 女性',
+ `age` int(11) DEFAULT 0 COMMENT 'age',
+ `height` double(11,2) DEFAULT 0 COMMENT 'height of a person, 身高',
+ `bool_flag` int(11) DEFAULT 1 COMMENT 'flag',
+ `remark` varchar(11) DEFAULT NULL,
+ PRIMARY KEY (`uid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='userinfo';
+```
+
+## Start yaf_db
+- new yaf_db()
+```php
+$db_conf = array("host" => "127.0.0.1",
+ "username" => "root",
+ "password" => "test123123",
+ "dbname" => "userinfo",
+ "port" => '3306',
+ "option" => array(
+ PDO::ATTR_CASE => PDO::CASE_NATURAL,
+ PDO::ATTR_TIMEOUT => 2));
+
+$yaf_db = new yaf_db($db_conf);
+```
+
+ we can start by creating a yaf_db object (yaf_db) from the obove code, db_conf include host,username,password,dbname,port and option, option is a pdo attribution, you can get the detail from http://php.net/manual/en/pdo.setattribute.php, For example, PDO::ATTR_TIMEOUT in the above code is specifies the timeout duration in seconds, and PDO::ATTR_CASE is forcing column names to a specific case.
+
+## Init yaf_db connection
+- we need to init pdo connection before we use yaf_db.
+```php
+try{
+ $yaf_db->initialize();
+} catch (PDOException $e) {
+ echo "find PDOException when initialize\n";
+ var_dump($e);
+ exit;
+}
+```
+
+## Native SQL query
+
+We can directly execute the sql statement through the exec() function,the return value is the number of rows affected by the execution, or return insert_id if it is insert statement, when the table has not AUTO_INCREMENT field, the insert_id should be zero, and execute select statement through the query() function, If $ret = -1 indicates that the sql execution error occurs, we can pass $yaf_db->errorCode(), $yaf_db- >errorInfo() returns the error code and error description respectively.
+
+
+- insert data
+```php
+$insert_id = $yaf_db->exec("insert into user_info_test(username, sexuality, age, height)
+ values('smallhow', 'male', 29, 180)");
+if($insert_id == -1) {
+ $code = $yaf_db->errorCode();
+ $info = $yaf_db->errorInfo();
+ echo "code:" . $code . "\n";
+ echo "info:" . $info[2] . "\n";
+} else {
+ echo $insert_id;
+}
+```
+
+- update data
+
+ ![Image](https://github.com/caohao0730/ycdatabase/blob/master/ycdatabase_extension/image-folder/table.jpg)
+
+if we execute the following update statement, $ret returns 3 if the current data is the above image.
+```php
+$ret = $yaf_db->exec("update user_info_test set remark='test' where height>=180");
+echo $ret; //ret is 3
+```
+
+- select data
+```php
+$ret = $yaf_db->query("select * from user_info_test where bool_flag=1");
+echo json_encode($ret);
+```
+ ![Image](https://github.com/caohao0730/ycdatabase/blob/master/ycdatabase_extension/image-folder/query_select.jpg)
+
+```php
+ $ret = $yaf_db->query("select username from user_info_test where bool_flag=1");
+echo json_encode($ret);
+```
+![Image](https://raw.githubusercontent.com/caohao0730/ycdatabase/master/ycdatabase_extension/image-folder/query_single.png)
+
+## Error Info
+
+Error codes and error messages can be obtained through the errorCode and errorInfo function
+
+```php
+$code = $yaf_db->errorCode();
+$info = $yaf_db->errorInfo();
+```
+
+## Where statement
+- Basic usage
+```php
+$yaf_db->select("user_info_test", "*", ["sexuality" => "male"]);
+// WHERE sexuality = 'male'
+
+$yaf_db->select("user_info_test", "*", ["age" => 29]); // WHERE age = 29
+
+$yaf_db->select("user_info_test", "*", ["age[>]" => 29]); // WHERE age > 29
+
+$yaf_db->select("user_info_test", "*", ["age[>=]" => 29]); // WHERE age >= 29
+
+$yaf_db->select("user_info_test", "*", ["age[!]" => 29]); // WHERE age != 29
+
+$yaf_db->select("user_info_test", "*", ["age[<>]" => [28, 29]]); // WHERE age BETWEEN 28 AND 29
+
+$yaf_db->select("user_info_test", "*", ["age[><]" => [28, 29]]); // WHERE age NOT BETWEEN 28 AND 29
+
+$yaf_db->select("user_info_test", "*", ["username" => ["Tom", "Red", "carlo"]]); // WHERE username in ('Tom', 'Red', 'carlo')
+
+//Multiple conditional query
+$data = $yaf_db->select("user_info_test", "*", [
+ "uid[!]" => 10,
+ "username[!]" => "James",
+ "height[!]" => [165, 168, 172],
+ "bool_flag" => true,
+ "remark[!]" => null
+]);
+// WHERE uid != 10 AND username != "James" AND height NOT IN ( 165, 168, 172) AND bool_flag = 1 AND remark IS NOT NULL
+```
+
+- Conditional Query
+
+You can use "AND" or "OR" to make up very complex SQL statements.
+```php
+$data = $yaf_db->select("user_info_test", "*", [
+ "OR" => [
+ "uid[>]" => 3,
+ "age[<>]" => [28, 29],
+ "sexuality" => "female"
+ ]
+]);
+// WHERE uid > 3 OR age BETWEEN 29 AND 29 OR sexuality = 'female'
+
+$data = $yaf_db->select("user_info_test", "*", [
+ "AND" => [
+ "OR" => [
+ "age" => 29,
+ "sexuality" => "female"
+ ],
+ "height" => 177
+ ]
+]);
+// WHERE (age = 29 OR sexuality='female') AND height = 177
+
+//Attention: Because yaf_db uses array arguments, the first OR is overwritten, the following usage is wrong,
+$data = $yaf_db->select("user_info_test", "*", [
+ "AND" => [
+ "OR" => [
+ "age" => 29,
+ "sexuality" => "female"
+ ],
+ "OR" => [
+ "uid[!]" => 3,
+ "height[>=]" => 170
+ ],
+ ]
+]);
+// [X] SELECT * FROM user_info_test WHERE (uid != 3 OR height >= 170)
+
+//We can use # and comments to distinguish between two diffrents OR
+$data = $yaf_db->select("user_info_test", "*", [
+ "AND" => [
+ "OR #1" => [
+ "age" => 29,
+ "sexuality" => "female"
+ ],
+ "OR #2" => [
+ "uid[!]" => 3,
+ "height[>=]" => 170
+ ],
+ ]
+]);
+// [√] SELECT * FROM user_info_test WHERE (age = 29 OR sexuality = 'female') AND (uid != 3 OR height >= 170)
+```
+- Fuzzy Matching _Like_
+
+LIKE USAGE [~].
+```php
+$data = $yaf_db->select("user_info_test", "*", [ "username[~]" => "%ide%" ]);
+// WHERE username LIKE '%ide%'
+
+$data = $yaf_db->select("user_info_test", "*", ["username[~]" => ["%ide%", "Jam%", "%ace"]]);
+// WHERE username LIKE '%ide%' OR username LIKE 'Jam%' OR username LIKE '%ace'
+
+$data = $yaf_db->select("user_info_test", "*", [ "username[!~]" => "%ide%" ]);
+// WHERE username NOT LIKE '%ide%'
+```
+
+- Use of wildcards
+```php
+$yaf_db->select("user_info_test", "*", [ "username[~]" => "Londo_" ]); // London, Londox, Londos...
+
+$yaf_db->select("user_info_test", "id", [ "username[~]" => "[BCR]at" ]); // Bat, Cat, Rat
+
+$yaf_db->select("user_info_test", "id", [ "username[~]" => "[!BCR]at" ]); // Eat, Fat, Hat...
+```
+
+- ORDER BY And LIMIT
+```php
+$data = $yaf_db->select("user_info_test", "*", [
+ 'sexuality' => 'male',
+ 'ORDER' => [
+ "age",
+ "height" => "DESC",
+ "uid" => "ASC"
+ ],
+ 'LIMIT' => 100, //Get the first 100 of rows (overwritten by next LIMIT)
+ 'LIMIT' => [20, 100] //Started from the top 20 rows, and get the next 100
+]);
+//SELECT * FROM `user_info_test` WHERE `sexuality` = 'male' ORDER BY `age`, `height` DESC, `uid` ASC LIMIT 100 OFFSET 20
+```
+
+- GROUP And HAVING
+```php
+$yaf_db->select("user_info_test", "sexuality,age,height", [
+ 'GROUP' => 'sexuality',
+
+ // GROUP by array of values
+ 'GROUP' => [
+ 'sexuality',
+ 'age',
+ 'height'
+ ],
+
+ // Must have to use it with GROUP together
+ 'HAVING' => [
+ 'age[>]' => 30
+ ]
+]);
+//SELECT uid FROM `user_info_test` GROUP BY sexuality,age,height HAVING `age` > 30
+```
+
+## Select statement
+- usage
+
+```php
+select($table, $columns, $where)
+```
+
+#### table [string]
+> table name
+
+#### columns [string/array]
+> Columns to be queried.
+
+#### where (optional) [array]
+> The conditions of the query.
+
+```php
+select($table, $join, $columns, $where)
+```
+#### table [string]
+> table name
+
+#### join [array]
+> Multi-table query, can be ignored if not used.
+
+#### columns [string/array]
+> Columns to be queried.
+
+#### where (optional) [array]
+> The conditions of the query.
+
+#### return: [array]
+>Fail if -1 is returned, otherwise result array is returned
+
+
+- example
+
+You can use * to match all fields, but if you specify columns you can improve performance.
+```php
+$datas = $yaf_db->select("user_info_test", [
+ "uid",
+ "username"
+], [
+ "age[>]" => 31
+]);
+
+// $datas = array(
+// [0] => array(
+// "uid" => 6,
+// "username" => "Aiden"
+// ),
+// [1] => array(
+// "uid" => 11,
+// "username" => "smallhow"
+// )
+// )
+
+// Select all columns
+$datas = $yaf_db->select("user_info_test", "*");
+
+// Select a column
+$datas = $yaf_db->select("user_info_test", "username");
+
+// $datas = array(
+// [0] => "lucky",
+// [1] => "Tom",
+// [2] => "Red"
+// )
+```
+
+
+- Table join
+
+Multi-table query SQL is more complicated, and it can be easily solved with yaf_db.
+
+```php
+// [>] == RIGH JOIN
+// [<] == LEFT JOIN
+// [<>] == FULL JOIN
+// [><] == INNER JOIN
+
+$yaf_db->select("user_info_test",
+[ // Table Join Info
+ "[>]account" => ["uid" => "userid"], // RIGHT JOIN `account` ON `user_info_test`.`uid`= `account`.`userid`
+
+ // This is a shortcut to declare the relativity if the row name are the same in both table.
+ "[>]album" => "uid", //RIGHT JOIN `album` USING (`uid`)
+
+ // Like above, there are two row or more are the same in both table.
+ "[<]detail" => ["uid", "age"], // LEFT JOIN `detail` USING (`uid`,`age`)
+
+ // You have to assign the table with alias.
+ "[<]address(addr_alias)" => ["uid" => "userid"], //LEFT JOIN `address` AS `addr_alias` ON `user_info_test`.`uid`=`addr_alias`.`userid`
+
+ // You can refer the previous joined table by adding the table name before the column.
+ "[<>]album" => ["account.userid" => "userid"], //FULL JOIN `album` ON `account`.`userid` = `album`.`userid`
+
+ // Multiple condition
+ "[><]account" => [
+ "uid" => "userid",
+ "album.userid" => "userid"
+ ]
+], [ // columns
+ "user_info_test.uid",
+ "user_info_test.age",
+ "addr_alias.country",
+ "addr_alias.city"
+], [ // where condition
+ "user_info_test.uid[>]" => 3,
+ "ORDER" => ["user_info_test.uid" => "DESC"],
+ "LIMIT" => 50
+]);
+
+
+// SELECT
+// user_info_test.uid,
+// user_info_test.age,
+// addr_alias.country,
+// addr_alias.city
+// FROM `user_info_test`
+// RIGHT JOIN `account` ON `user_info_test`.`uid`= `account`.`userid`
+// RIGHT JOIN `album` USING (`uid`)
+// LEFT JOIN `detail` USING (`uid`,`age`)
+// LEFT JOIN `address` AS `addr_alias` ON `user_info_test`.`uid`=`addr_alias`.`userid`
+// FULL JOIN `album` ON `account`.`userid` = `album`.`userid`
+// INNER JOIN `account` ON `user_info_test`.`uid`= `account`.`userid`
+// AND `album`.`userid` = `account`.`userid`
+// WHERE `user_info_test`.`uid` > 3
+// ORDER BY `user_info_test`.`uid` DESC
+// LIMIT 50
+```
+
+- alias
+
+You can use aliases to prevent field conflicts
+
+```php
+$data = $yaf_db->select("user_info_test(uinfo)", [
+ "[<]account(A)" => "userid",
+], [
+ "uinfo.uid(uid)",
+ "A.userid"
+]);
+
+// SELECT uinfo.uid AS `uid`, A.userid
+// FROM `user_info_test` AS `uinfo`
+// LEFT JOIN `account` AS `A` USING (`userid`)
+```
+
+## Insert statement
+
+```php
+insert($table, $data, $cache_info)
+```
+#### table [string]
+> table name
+
+#### data [array]
+> insert data
+
+#### cache_info (optional) [array]
+> cache info
+
+#### return [int]
+>Fail if -1 is returned, otherwise insert_id is returned, if the table has no AUTO_INCREMENT field, the insert_id is zero
+
+```php
+$data = array('username' => 'smallhow','sexuality' => 'male','age' => 35, 'height' => '168');
+$insert_id = $yaf_db->insert("user_info_test", $data);
+if($insert_id == -1) {
+ $code = $yaf_db->errorCode();
+ $info = $yaf_db->errorInfo();
+ echo "code:" . $code . "\n";
+ echo "info:" . $info[2] . "\n";
+} else {
+ echo $insert_id;
+}
+
+```
+
+## Replace statement
+
+```php
+replace($table, $data, $cache_info)
+```
+#### table [string]
+> table name
+
+#### data [array]
+> replace data
+
+#### cache_info (optional) [array]
+> cache info
+
+#### return [int]
+>Fail if -1 is returned, otherwise insert_id is returned
+
+```php
+$data = array('username' => 'smallhow','sexuality' => 'male','age' => 35, 'height' => '168');
+$insert_id = $yaf_db->replace("user_info_test", $data);
+if($insert_id == -1) {
+ $code = $yaf_db->errorCode();
+ $info = $yaf_db->errorInfo();
+ echo "code:" . $code . "\n";
+ echo "info:" . $info[2] . "\n";
+} else {
+ echo $insert_id;
+}
+
+```
+
+## Update statement
+
+```php
+update($table, $data, $where)
+```
+#### table [string]
+> table name
+
+#### data [array]
+> update data
+
+#### where (optional) [array]
+> where condition [可选]
+
+#### return [int]
+>Fail if -1 is returned, otherwise the number of update records is returned
+
+```php
+$data = array('height' => 182,'age' => 33);
+$where = array('username' => 'smallhow');
+$ret = $yaf_db->update("user_info_test", $data, $where);
+```
+
+## Delete statement
+
+```php
+delete($table, $where)
+```
+#### table [string]
+> table name
+
+#### where (optional) [array]
+> where condition [可选]
+
+#### return [int]
+>Fail if -1 is returned, otherwise the number of delete records is returned
+
+```php
+$where = array('username' => 'smallhow');
+$ret = $yaf_db->delete("user_info_test", $where);
+```
+
+## Whole Example
+
+```php
+$table = "table_a(a)";
+
+$join = [
+ "[>]AAAA(a1)" => "id",
+ "[<]BBBB" => ["E1", "E2", "E3"],
+ "[>]CCCC(c1)" => [ "GG" => "HH", "II.KK" => "LL"]
+];
+
+$columns = ["name(a)", "avatar(b)", "age"];
+
+$where = [
+ "user.email[!]" => ["foo@bar.com", "cat@dog.com", "admin@yaf_db.in"],
+ "user.uid[<]" => 11111,
+ "uid[>=]" => 222,
+ "uid[!]" => null,
+ "count[!]" => [36, 57, 89],
+ "id[!]" => true,
+ "int_num[!]" => 3,
+ "double_num[!]" => 3.76,
+ "AA[~]" => "%saa%",
+ "BB[!~]" => "%sbb",
+ "CC[~]" => ["11%", "22_", "33%"],
+ "DD[!~]" => ["%44%", "55%", "66%"],
+ "EE[~]" => ["AND" => ["%E11", "E22"]],
+ "FF[~]" => ["OR" => ["%F33", "F44"]],
+ "GG[!~]" => ["AND" => ["%G55", "G66"]],
+ "HH[!~]" => ["OR" => ["H77", "H88"]],
+ "II[<>]" => ["1", "12"],
+ "LL[><]" => ["1", "12"],
+ "AND #1" => [
+ "OR #1" => [
+ "user_name" => null,
+ "email" => "foo@bar.com",
+ ],
+ "OR #2" => [
+ "user_name" => "bar",
+ "email" => "bar@foo.com"
+ ]
+ ],
+ "OR" => [
+ "user_name[!]" => "foo",
+ "promoted[!]" => true
+ ],
+ 'GROUP' => 'userid',
+ 'GROUP' => ['type', 'age', 'gender'],
+ 'HAVING' => [
+ "uid.num[>]" => 111,
+ "type[>]" => "smart",
+ "id[!]" => false,
+ "god3[!]" => 9.86,
+ "uid[!]" => null,
+ "AA[~]" => "SSA%",
+ "CC[~]" => ["11%", "22%", "%33"],
+ ],
+ 'ORDER' => [
+ "user.score",
+ "user.uid" => "ASC",
+ "time" => "DESC",
+ ],
+ "LIMIT" => 33,
+];
+
+$yaf_db->select($table, $join, $columns, $where);
+```
+
+## Database transaction
+
+```php
+$yaf_db->begin();
+
+$ret1 = $yaf_db->exec("insert into user_info_test(username, sexuality, age, height) values('smallhow', 'male', 29, 180)");
+$ret2 = $yaf_db->exec("insert into user_info_test(username, sexuality, age, height) values('jesson', 'female', 28, 175)");
+
+if($ret1 == -1 || $ret2 == -1 ) {
+ $yaf_db->rollback();
+} else {
+ $yaf_db->commit()
+}
+```
+
+## Data Caching
+
+We can use redis, or any other cache system that supports set/get/del/expire function as the medium to store the data returned by the database. If you do not specify the expiration time, the default storage expiration time is 5 minutes. if The cache is specified. When we call data update function such as update/delete/insert, we should pass in the same cache key so that yaf_db can clear the cache to ensure data consistency.
+
+```php
+//we want cache data by redis
+$redis = new Redis();
+$redis->connect('/home/redis/pid/redis.sock');
+
+$option = array("host" => "127.0.0.1",
+ "username" => "test",
+ "password" => "test",
+ "dbname" => "test",
+ "port" => '3306',
+ "cache" => $redis, //cache instance
+ 'option' => array(
+ PDO::ATTR_CASE => PDO::CASE_NATURAL,
+ PDO::ATTR_TIMEOUT => 2));
+
+
+$yaf_db = new yaf_db($option);
+
+try{
+ $yaf_db->initialize();
+} catch (PDOException $e) {
+ echo "find PDOException when initialize\n";
+ exit;
+}
+
+// I want to keep the 29-year-old user data queried by the database in the cache, and keep it for 10 minutes.
+$age = 29;
+$cache_key = 'pre_cache_key_' . $age;
+
+$data = $yaf_db->select("user_info_test", "*", [
+ 'age' => $age,
+ 'CACHE' => ['key' => $cache_key, 'expire' => 600] //cache key an expire time (seconds)
+]);
+
+echo $redis->get($cache_key) . "\n";
+
+// If I update these 29-year-old user data, or even add a new 29-year-old user information,
+// it's best to enter the cache key to clean up the cache to keep the data consistent.
+$yaf_db->update("user_info_test", ['remark' => '29-year-old'], [
+ 'age' => $age,
+ 'CACHE' => ['key' => $cache_key] //cache key
+]);
+
+echo $redis->get($cache_key) . "\n";
+
+//If you are going to delete the relevant data, it is best to also clean up the cache by cache_key.
+$yaf_db->delete("user_info_test", [
+ 'age' => $age,
+ 'CACHE' => ['key' => $cache_key] //cache key
+]);
+
+echo $redis->get($cache_key) . "\n";
+
+//Clean up the cache by cache_key when the data you insert is related to the cached data.
+$insert_data = array();
+$insert_data['username'] = 'test';
+$insert_data['sexuality'] = 'male';
+$insert_data['age'] = 29;
+$insert_data['height'] = 176;
+
+$insert_id = $yaf_db->insert("user_info_test", $insert_data, ['key' => $cache_key]);
+
+echo $redis->get($cache_key) . "\n";
+```
+
+## MySQL Database Connection Pool
+
+Short connection performance is generally not available. CPU resources are consumed by the system. Once the network is jittered, there will be a large number of TIME_WAIT generated. The service has to be restarted periodically or the machine is restarted periodically. The server is unstable, QPS is high and low, and the connection is stable and efficient. The pool can effectively solve the above problems, it is the basis of high concurrency. yaf_db uses a special way to establish a stable connection pool with MySQL. performance can be increased by at least 30%, According to PHP's operating mechanism, long connections can only reside on top of the worker process after establishment, that is, how many work processes are there. How many long connections, for example, we have 10 PHP servers, each launching 1000 PHP-FPM worker processes, they connect to the same MySQL instance, then there will be a maximum of 10,000 long connections on this MySQL instance, the number is completely Out of control! And PHP's connection pool heartbeat mechanism is not perfect
+
+
+### How ?
+Let's focus on Nginx, its stream module implements load balancing of TCP/UDP services, and with the stream-lua module, we can implement programmable stream services, that is, custom TCP/N with Nginx. UDP service! Of course, you can write TCP/UDP services from scratch, but standing on Nginx's shoulder is a more time-saving and labor-saving choice. We can choose the OpenResty library to complete the MySQL connection pool function. OpenResty is a very powerful and well-functioning Nginx Lua framework. It encapsulates Socket, MySQL, Redis, Memcache, etc. But what is the relationship between Nginx and PHP connection pool? And listen to me slowly: Usually most PHP is used with Nginx, and PHP and Nginx are mostly on the same server. With this objective condition, we can use Nginx to implement a connection pool, connect to services such as MySQL on Nginx, and then connect to Nginx through a local Unix Domain Socket, thus avoiding all kinds of short links. Disadvantages, but also enjoy the benefits of the connection pool.
+
+### OpenResty Install
+OpenResty Document: https://moonbingbing.gitbooks.io/openresty-best-practices/content/openresty/install_on_centos.html
+OpenResty Official Website : http://www.openresty.org/
+
+CentOS 6.8 Install :
+```
+###### Install the necessary libraries ######
+$yum install readline-devel pcre-devel openssl-devel perl
+
+###### Install OpenResty ######
+$cd ~/ycdatabase/openresty
+$tar -xzvf openresty-1.13.6.1.tar.gz
+$cd openresty-1.13.6.1
+$./configure --prefix=/usr/local/openresty.1.13 --with-luajit --without-http_redis2_module --with-http_iconv_module
+$gmake
+$gmake install
+
+###### open mysql pool ######
+$cp -rf ~/ycdatabase/openresty/openresty-pool ~/
+$mkdir ~/openresty-pool/logs
+$/usr/local/openresty.1.13/nginx/sbin/nginx -p ~/openresty-pool
+```
+
+### MySQL Database Connection Pool Config
+~/openresty-pool/conf/nginx.conf :
+
+```lua
+worker_processes 1; #nginx worker process num
+
+error_log logs/error.log; #nginx error log path
+
+events {
+ worker_connections 1024;
+}
+
+stream {
+ lua_code_cache on;
+
+ lua_check_client_abort on;
+
+ server {
+ listen unix:/tmp/mysql_pool.sock;
+
+ content_by_lua_block {
+ local mysql_pool = require "mysql_pool"
+
+ local config = {host = "127.0.0.1",
+ user = "root",
+ password = "test",
+ database = "collect",
+ timeout = 2000,
+ max_idle_timeout = 10000,
+ pool_size = 200}
+
+ pool = mysql_pool:new(config)
+
+ pool:run()
+ }
+ }
+}
+```
+If you have more than a MySQL Server, you can start another server and add a new listener to unix domain socket.
+
+
+### PHP Code
+Except the option is array("unix_socket" => "/tmp/mysql_pool.sock") , Php mysql connection pool usage is exactly the same as before,But, MySQL does not support transactions in unix domain socket mode.
+
+
+```php
+$option = array("unix_socket" => "/tmp/mysql_pool.sock");
+$yaf_db = new yaf_db($option);
+$ret = $yaf_db->select("user_info_test", "*", ["sexuality" => "male"]);
+
+if($ret == -1) {
+ $code = $yaf_db->errorCode();
+ $info = $yaf_db->errorInfo();
+ echo "code:" . $code . "\n";
+ echo "info:" . $info[2] . "\n";
+} else {
+ print_r($ret);
+}
+```
+
+## Redis Connection Pool
+Similarly, Redis can solve the connection pool problem in the same way.
+
+### Redis Connection Pool Config
+~/openresty-pool/conf/nginx.conf
+```lua
+worker_processes 1; #nginx worker process num
+
+error_log logs/error.log; #error log path
+
+events {
+ worker_connections 1024;
+}
+
+stream {
+ lua_code_cache on;
+
+ lua_check_client_abort on;
+
+ server {
+ listen unix:/tmp/redis_pool.sock;
+
+ content_by_lua_block {
+ local redis_pool = require "redis_pool"
+
+ pool = redis_pool:new({ip = "127.0.0.1", port = 6379, auth = "password"})
+
+ pool:run()
+ }
+ }
+
+ server {
+
+ listen unix:/tmp/mysql_pool.sock;
+
+ content_by_lua_block {
+ local mysql_pool = require "mysql_pool"
+
+ local config = {host = "127.0.0.1",
+ user = "root",
+ password = "test",
+ database = "collect",
+ timeout = 2000,
+ max_idle_timeout = 10000,
+ pool_size = 200}
+
+ pool = mysql_pool:new(config)
+
+ pool:run()
+ }
+ }
+}
+
+```
+
+### PHP Code
+```php
+$redis = new Redis();
+$redis->pconnect('/tmp/redis_pool.sock');
+var_dump($redis->hSet("foo1", "vvvvv42", 2));
+var_dump($redis->hSet("foo1", "vvvv", 33));
+var_dump($redis->expire("foo1", 111));
+var_dump($redis->hGetAll("foo1"));
+```
diff --git a/config.m4 b/config.m4
index af99974d..1037e686 100644
--- a/config.m4
+++ b/config.m4
@@ -72,7 +72,8 @@ if test "$PHP_YAF" != "no"; then
yaf_loader.c \
yaf_registry.c \
yaf_plugin.c \
- yaf_session.c,
+ yaf_session.c \
+ yaf_db.c,
$ext_shared)
PHP_ADD_BUILD_DIR([$ext_builddir/configs])
PHP_ADD_BUILD_DIR([$ext_builddir/requests])
diff --git a/config.w32 b/config.w32
index 68d79493..fbaeac51 100644
--- a/config.w32
+++ b/config.w32
@@ -5,7 +5,7 @@ ARG_ENABLE("yaf", "enable yaf support", "no");
if (PHP_YAF == "yes") {
- EXTENSION("yaf", "yaf.c yaf_application.c yaf_bootstrap.c yaf_dispatcher.c yaf_exception.c yaf_config.c yaf_request.c yaf_response.c yaf_view.c yaf_controller.c yaf_action.c yaf_router.c yaf_loader.c yaf_registry.c yaf_plugin.c yaf_session.c");
+ EXTENSION("yaf", "yaf.c yaf_application.c yaf_bootstrap.c yaf_dispatcher.c yaf_exception.c yaf_config.c yaf_request.c yaf_response.c yaf_view.c yaf_controller.c yaf_action.c yaf_router.c yaf_loader.c yaf_registry.c yaf_plugin.c yaf_session.c yaf_db.c");
ADD_FLAG("CFLAGS_YAF", "/I " + configure_module_dirname);
diff --git a/package.xml b/package.xml
index 452f79c9..0486e7f1 100644
--- a/package.xml
+++ b/package.xml
@@ -62,6 +62,8 @@
+
+
diff --git a/php_yaf.h b/php_yaf.h
index 592af31f..e590ece1 100644
--- a/php_yaf.h
+++ b/php_yaf.h
@@ -70,8 +70,8 @@ extern zend_module_entry yaf_module_entry;
#define YAF_ME(c, m, a, f) {m, PHP_MN(c), a, (uint) (sizeof(a)/sizeof(struct _zend_arg_info)-1), f},
-extern PHPAPI void php_var_dump(zval **struc, int level);
-extern PHPAPI void php_debug_zval_dump(zval **struc, int level);
+//extern PHPAPI void php_var_dump(zval **struc, int level);
+//extern PHPAPI void php_debug_zval_dump(zval **struc, int level);
ZEND_BEGIN_MODULE_GLOBALS(yaf)
zend_string *ext;
diff --git a/yaf.c b/yaf.c
index ce5f5ffb..fb699b6a 100644
--- a/yaf.c
+++ b/yaf.c
@@ -42,6 +42,7 @@
#include "yaf_plugin.h"
#include "yaf_registry.h"
#include "yaf_session.h"
+#include "yaf_db.h"
ZEND_DECLARE_MODULE_GLOBALS(yaf);
@@ -141,6 +142,7 @@ PHP_MINIT_FUNCTION(yaf)
YAF_STARTUP(registry);
YAF_STARTUP(session);
YAF_STARTUP(exception);
+ YAF_STARTUP(db);
return SUCCESS;
}
diff --git a/yaf_db.c b/yaf_db.c
new file mode 100644
index 00000000..b8183514
--- /dev/null
+++ b/yaf_db.c
@@ -0,0 +1,2936 @@
+/*
+ +----------------------------------------------------------------------+
+ | yaf_db / yaf_db |
+ +----------------------------------------------------------------------+
+ | yaf_db is a php database ORM extension for mysql written in c language |
+ +----------------------------------------------------------------------+
+ | Author: Cao Hao <649947921@qq.com> |
+ | CreateTime: 2018-11-19 |
+ +----------------------------------------------------------------------+
+*/
+
+#include "php.h"
+#include "Zend/zend_interfaces.h"
+
+#include "php_yaf.h"
+#include "yaf_exception.h"
+#include "zend_variables.h"
+#include "yaf_db.h"
+#include
+#include
+#include
+
+zend_class_entry yaf_db_ce;
+zend_class_entry* yaf_db_ce_ptr;
+
+//类的成员函数
+static zend_function_entry yaf_db_methods[] = {
+ PHP_ME(yaf_db, __construct, arginfo_yaf_db_construct_oo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(yaf_db, __destruct, arginfo_yaf_db_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
+ PHP_ME(yaf_db, errorCode, arginfo_yaf_db_construct_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, errorInfo, arginfo_yaf_db_construct_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, select, arginfo_yaf_db_select_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, exec, arginfo_yaf_db_exec_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, query, arginfo_yaf_db_query_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, insert, arginfo_yaf_db_insert_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, replace, arginfo_yaf_db_replace_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, insert_id, arginfo_yaf_db_void, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, update, arginfo_yaf_db_update_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, delete, arginfo_yaf_db_delete_oo, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, initialize, arginfo_yaf_db_void, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, begin, arginfo_yaf_db_void, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, commit, arginfo_yaf_db_void, ZEND_ACC_PUBLIC)
+ PHP_ME(yaf_db, rollback, arginfo_yaf_db_void, ZEND_ACC_PUBLIC)
+ NULL, NULL, NULL
+};
+
+
+/** {{{ YAF_STARTUP_FUNCTION
+*/
+YAF_STARTUP_FUNCTION(db) {
+ INIT_CLASS_ENTRY(yaf_db_ce, "yaf_db", yaf_db_methods);
+ yaf_db_ce_ptr = zend_register_internal_class(&yaf_db_ce TSRMLS_CC);
+ yaf_db_ce_ptr->serialize = zend_class_serialize_deny;
+ yaf_db_ce_ptr->unserialize = zend_class_unserialize_deny;
+
+ zend_declare_property_long(yaf_db_ce_ptr, ZEND_STRL("mapkey_index"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("username"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("password"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("dbname"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_long(yaf_db_ce_ptr, ZEND_STRL("port"), 3306, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_string(yaf_db_ce_ptr, ZEND_STRL("charset"), "utf8", ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("option"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("errcode"),ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("errinfo"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("_pdo"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("cache"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_long(yaf_db_ce_ptr, ZEND_STRL("insert_id"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(yaf_db_ce_ptr, ZEND_STRL("unix_socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
+
+ return SUCCESS;
+}
+/* }}} */
+
+//yaf_db构造函数
+PHP_METHOD(yaf_db, __construct) {
+ zval* thisObject = getThis();
+ zval *option = NULL;
+ zval *v;
+ HashTable *vht;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &option) == FAILURE) {
+ return;
+ }
+
+ if (Z_TYPE_P(option) != IS_ARRAY) {
+ RETURN_FALSE;
+ }
+
+ vht = Z_ARRVAL_P(option);
+ if ((v = php_yaf_array_get_value(vht, "host")) != NULL) {
+ convert_to_string(v);
+ zend_update_property_string(yaf_db_ce_ptr, thisObject, ZEND_STRL("host"), Z_STRVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "username")) != NULL) {
+ convert_to_string(v);
+ zend_update_property_string(yaf_db_ce_ptr, thisObject, ZEND_STRL("username"), Z_STRVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "password")) != NULL) {
+ convert_to_string(v);
+ zend_update_property_string(yaf_db_ce_ptr, thisObject, ZEND_STRL("password"), Z_STRVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "dbname")) != NULL) {
+ convert_to_string(v);
+ zend_update_property_string(yaf_db_ce_ptr, thisObject, ZEND_STRL("dbname"), Z_STRVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "port")) != NULL) {
+ convert_to_long(v);
+ zend_update_property_long(yaf_db_ce_ptr, thisObject, ZEND_STRL("port"), Z_LVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "charset")) != NULL) {
+ convert_to_string(v);
+ zend_update_property_string(yaf_db_ce_ptr, thisObject, ZEND_STRL("charset"), Z_STRVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "cache")) != NULL) {
+ zend_update_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("cache"), v TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "unix_socket")) != NULL) {
+ convert_to_string(v);
+ zend_update_property_string(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket"), Z_STRVAL_P(v) TSRMLS_DC);
+ }
+
+ if ((v = php_yaf_array_get_value(vht, "option")) != NULL) {
+ zend_update_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("option"), v TSRMLS_DC);
+ }
+
+ update_error_info(thisObject, "00000", "");
+}
+
+PHP_METHOD(yaf_db, __destruct) {
+}
+
+PHP_METHOD(yaf_db, errorCode) {
+ zval* errorCode = yaf_read_init_property(yaf_db_ce_ptr, getThis(), ZEND_STRL("errcode") TSRMLS_CC);
+ RETURN_ZVAL(errorCode, 1, 0);
+}
+
+PHP_METHOD(yaf_db, errorInfo) {
+ zval* errorInfo = yaf_read_init_property(yaf_db_ce_ptr, getThis(), ZEND_STRL("errinfo") TSRMLS_CC);
+ RETURN_ZVAL(errorInfo, 1, 0);
+}
+
+PHP_METHOD(yaf_db, initialize) {
+ zval* thisObject = getThis();
+
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { ///// unix domain sockcet ////
+ RETURN_TRUE;
+ }
+
+ zval* pdo = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo") TSRMLS_CC);
+
+ if (YAF_IS_NULL(pdo)) {
+ zval *dsn;
+ zval **args[4];
+
+ //参数
+ zval* host = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("host") TSRMLS_CC);
+ zval* username = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("username") TSRMLS_CC);
+ zval* password = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("password") TSRMLS_CC);
+ zval* dbname = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("dbname") TSRMLS_CC);
+ zval* port = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("port") TSRMLS_CC);
+ zval* charset = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("charset") TSRMLS_CC);
+ zval* option = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("option") TSRMLS_CC);
+
+ YAF_MAKE_STD_ZVAL(dsn);
+ char str[128] = {0};
+ sprintf(str, "mysql:host=%s;port=%d;dbname=%s", Z_STRVAL_P(host), Z_LVAL_P(port), Z_STRVAL_P(dbname));
+ YAF_ZVAL_STRING(dsn, str, 1);
+
+ args[0] = &dsn;
+ args[1] = &username;
+ args[2] = &password;
+ args[3] = &option;
+
+ //创建pdo, 连接数据库
+ object_init_ex(pdo, get_pdo_ce());
+
+ if (yaf_call_user_function_construct_fast(&pdo, 4, args) == FAILURE) {
+ yaf_zval_ptr_dtor(&dsn);
+ yaf_php_fatal_error(E_ERROR, "Fail to connect database by PDO");
+ RETURN_FALSE;
+ }
+
+ if (EG(exception)) {
+ yaf_zval_ptr_dtor(&dsn);
+ RETURN_FALSE;
+ }
+
+ yaf_zval_ptr_dtor(&dsn);
+
+ zend_update_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo"), pdo TSRMLS_CC);
+
+ //设置字符集
+ zval *charset_sql;
+ zval** exec_args[1];
+
+ YAF_MAKE_STD_ZVAL(charset_sql);
+ char str2[128] = {0};
+ sprintf(str2, "SET NAMES %s", Z_STRVAL_P(charset));
+ YAF_ZVAL_STRING(charset_sql, str2, 1);
+
+ exec_args[0] = &charset_sql;
+
+ int setret = yaf_call_user_function_return_bool_or_unsigned(&pdo, "exec", 1, exec_args);
+
+ if (setret == FAILURE) {
+ yaf_zval_ptr_dtor(&charset_sql);
+ yaf_php_fatal_error(E_WARNING, "failed to set database charset.");
+ RETURN_FALSE;
+ }
+
+ if (EG(exception)) {
+ yaf_zval_ptr_dtor(&charset_sql);
+ RETURN_FALSE;
+ }
+
+ yaf_zval_ptr_dtor(&charset_sql);
+ }
+
+ RETURN_TRUE;
+}
+
+//事务开始
+PHP_METHOD(yaf_db, begin) {
+ zval* thisObject = getThis();
+
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { ///// unix domain sockcet ////
+ RETURN_MY_ERROR("unix domain socket not support transaction");
+ }
+
+ zval* pdo = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo") TSRMLS_CC);
+ if (YAF_IS_NULL(pdo)) {
+ RETURN_MY_ERROR("pdo is empty");
+ }
+
+ if (yaf_call_user_function_return_bool_or_unsigned(&pdo, "beginTransaction", 0, NULL) == 1) {
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+//事务提交
+PHP_METHOD(yaf_db, commit) {
+ zval* thisObject = getThis();
+
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { ///// unix domain sockcet ////
+ RETURN_MY_ERROR("unix domain socket not support transaction");
+ }
+
+ zval* pdo = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo") TSRMLS_CC);
+ if (YAF_IS_NULL(pdo)) {
+ RETURN_MY_ERROR("pdo is empty");
+ }
+
+ if (yaf_call_user_function_return_bool_or_unsigned(&pdo, "commit", 0, NULL) == 1) {
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+
+//事务回滚
+PHP_METHOD(yaf_db, rollback) {
+ zval* thisObject = getThis();
+
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { ///// unix domain sockcet ////
+ RETURN_MY_ERROR("unix domain socket not support transaction");
+ }
+
+ zval* pdo = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo") TSRMLS_CC);
+ if (YAF_IS_NULL(pdo)) {
+ RETURN_MY_ERROR("pdo is empty");
+ }
+
+ if (yaf_call_user_function_return_bool_or_unsigned(&pdo, "rollBack", 0, NULL) == 1) {
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+
+//执行查询
+PHP_METHOD(yaf_db, exec) {
+ zval* thisObject = getThis();
+ zval *query = NULL, *map = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &query, &map) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ if (Z_TYPE_P(query) != IS_STRING) {
+ RETURN_MY_ERROR("Argument 1 passed must be of the type string");
+ }
+
+ //初始化错误
+ update_error_info(thisObject, "00000", "");
+
+ //判断是否数据库 WRITE 写操作,或者 SELECT 查询
+ int is_write = is_write_type(Z_STRVAL_P(query));
+ int isinsert = is_insert(Z_STRVAL_P(query));
+
+ //unix socket
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+
+ if(YAF_IS_NOT_NULL(unix_socket)) { ////////////////// unix socket ////////////////////////
+ php_stream* stream = unix_socket_conn(Z_STRVAL_P(unix_socket));
+
+ if(stream == NULL) {
+ update_error_info(thisObject, "E0001", "can`t connect to unix socket");
+ RETURN_MY_ERROR("[exception] can`t connect to unix socket");
+ }
+
+ //发送请求
+ size_t buf_size = 10 + Z_STRLEN_P(query) + 1;
+ char* send_buf = (char*) malloc(buf_size);
+ memset(send_buf, 0, buf_size);
+ sprintf(send_buf, "%d\n%s", Z_STRLEN_P(query), Z_STRVAL_P(query));
+
+ size_t send_len = php_stream_write(stream, send_buf, strlen(send_buf));
+ free(send_buf);
+
+ if(send_len <= 0) {
+ php_stream_close(stream);
+ RETURN_MY_ERROR("[exception] unixsocket send failed");
+ }
+
+ //发送 map
+ if (YAF_IS_NOT_NULL(map) && Z_TYPE_P(map) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(map))) {
+ smart_str smart_map_buf = {0};
+ php_json_encode_ex(&smart_map_buf, map);
+ smart_str_0(&smart_map_buf);
+
+ if(smart_map_buf.s != NULL && ZSTR_VAL(smart_map_buf.s) != NULL && ZSTR_LEN(smart_map_buf.s) > 0) {
+ char* map_str = ZSTR_VAL(smart_map_buf.s);
+ int smart_map_buf_len = strlen(map_str);
+ size_t map_buf_size = 10 + smart_map_buf_len + 2;
+ char* map_buf = (char*)malloc(map_buf_size);
+ memset(map_buf, 0, map_buf_size);
+
+ if(map_str[0] == '{' && map_str[smart_map_buf_len-1] != '}') { //php_json_encode_ex bug end with not '}'
+ sprintf(map_buf, "%d\n%s}", smart_map_buf_len+1, map_str);
+ } else if(map_str[0] == '[' && map_str[smart_map_buf_len-1] != ']') { //php_json_encode_ex bug end with not ']'
+ sprintf(map_buf, "%d\n%s]", smart_map_buf_len+1, map_str);
+ } else {
+ sprintf(map_buf, "%d\n%s", smart_map_buf_len, map_str);
+ }
+
+ php_stream_write(stream, map_buf, strlen(map_buf));
+ free(map_buf);
+ } else {
+ php_stream_write(stream, "0\n", strlen("0\n"));
+ }
+
+ smart_str_free(&smart_map_buf);
+ } else {
+ php_stream_write(stream, "0\n", strlen("0\n"));
+ }
+
+ //获取结果数据长度
+ char recv_len_buf[10] = {0};
+ size_t recv_len = 0;
+ php_stream_get_line(stream, recv_len_buf, 10, &recv_len);
+ if(recv_len <= 0) {
+ php_stream_close(stream);
+ RETURN_MY_ERROR("[exception] unixsocket receive length failed");
+ }
+
+ recv_len_buf[recv_len - 1] = 0;
+ recv_len = atoi(recv_len_buf) + 1;
+
+ //获取结果数据
+ char* recv_buf = (char*) malloc(recv_len);
+ size_t len;
+ memset(recv_buf, 0, recv_len);
+
+ size_t p = 0;
+ char * ret = NULL;
+ do {
+ ret = php_stream_get_line(stream, recv_buf + p, recv_len, &len);
+ recv_len -= len;
+ p += len;
+ } while(ret != NULL && recv_len > 0);
+
+ //关闭 unix socket
+ php_stream_close(stream);
+
+ //string_debug("recv_buf", recv_buf);
+ if(recv_buf[0] == 0) {
+ free(recv_buf);
+ RETURN_MY_ERROR("[exception] receive buff failed");
+ }
+
+ //返回结果转化为json
+ zval* recv_array = NULL;
+ YAF_MAKE_STD_ZVAL(recv_array);
+
+ php_json_decode_ex(recv_array, recv_buf, strlen(recv_buf), 1);
+ free(recv_buf);
+
+ if(YAF_IS_NULL(recv_array) || YAF_IS_NOT_ARRAY(recv_array)) {
+ yaf_zval_ptr_dtor(&recv_array);
+ update_error_info(thisObject, "E0001", "convert recvbuff from json to array erro");
+ RETURN_MY_ERROR("[exception] convert recvbuff from json to array erro");
+ }
+
+ //查询返回错误码
+ zval* error_no = php_yaf_array_get_value(Z_ARRVAL_P(recv_array), "errno");
+ if(YAF_IS_NULL(error_no) || Z_TYPE_P(error_no) != IS_LONG || Z_LVAL_P(error_no) != 0) { //返回错误信息
+ zval* errorCode = php_yaf_array_get_value(Z_ARRVAL_P(recv_array), "errorCode");
+ zval* errorInfo = php_yaf_array_get_value(Z_ARRVAL_P(recv_array), "errorInfo");
+ update_pdo_error(thisObject, errorCode, errorInfo);
+ yaf_zval_ptr_dtor(&recv_array);
+ RETURN_LONG(-1);
+ }
+
+ zval* data = php_yaf_array_get_value(Z_ARRVAL_P(recv_array), "data");
+
+ if(is_write) {
+ zval* return_info = NULL;
+ if(isinsert) {
+ return_info = php_yaf_array_get_value(Z_ARRVAL_P(data), "insert_id");
+ } else {
+ return_info = php_yaf_array_get_value(Z_ARRVAL_P(data), "affected_rows");
+ }
+
+ int return_int = Z_LVAL_P(return_info);
+
+ yaf_zval_ptr_dtor(&recv_array);
+ RETURN_LONG(return_int);
+ } else {
+ //是否单列
+ int ret_count = zend_hash_num_elements(Z_ARRVAL_P(data));
+
+ if(ret_count > 0) {
+ zval* first_element = yaf_get_element_by_hashtable_index(Z_ARRVAL_P(data), 0);
+ ret_count = zend_hash_num_elements(Z_ARRVAL_P(first_element));
+
+ if(ret_count == 1) { //单列
+ zval *single_column_result = NULL;
+ YAF_MAKE_STD_ZVAL(single_column_result);
+ yaf_array_single_columns(&single_column_result, data);
+ yaf_zval_ptr_dtor(&recv_array);
+ RETURN_ZVAL(single_column_result, 0, 0);
+ }
+ }
+
+ zval *copy = yaf_zval_copy(data);
+ yaf_zval_ptr_dtor(&recv_array);
+
+ RETURN_ZVAL(copy, 0, 0);
+ }
+
+ } else { /////////////////////////// pdo /////////////////////////////////
+ zval* pdo = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo") TSRMLS_CC);
+ if (YAF_IS_NULL(pdo)) {
+ RETURN_MY_ERROR("pdo is empty");
+ }
+
+ //prepare query
+ zval** prepare_args[1];
+ zval* statement = NULL;
+
+ prepare_args[0] = &query;
+
+ if (yaf_call_user_function_ex_fast(&pdo, "prepare", &statement, 1, prepare_args) == FAILURE) {
+ yaf_zval_free(statement);
+ yaf_php_fatal_error(E_ERROR, "failed to prepare query");
+ RETURN_LONG(-1);
+ }
+
+ if (EG(exception) || YAF_IS_NULL(statement)) {
+ yaf_zval_free(statement);
+ RETURN_MY_ERROR("failed to prepare query, pdo is not initialized");
+ }
+
+ //bind value
+ if (YAF_IS_NOT_NULL(map) && Z_TYPE_P(map) == IS_ARRAY) {
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(map), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ continue;
+ }
+
+ zval** bind_args[3];
+ zval *bind_key = NULL, *bind_type = NULL;
+
+ YAF_MAKE_STD_ZVAL(bind_key);
+ YAF_MAKE_STD_ZVAL(bind_type);
+ YAF_ZVAL_STRING(bind_key, key, 1);
+
+ bind_args[0] = &bind_key;
+ bind_args[1] = &value;
+
+ //绑定类型
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ ZVAL_LONG(bind_type, PDO_PARAM_NULL);
+ break;
+ case IS_LONG:
+ ZVAL_LONG(bind_type, PDO_PARAM_INT);
+ break;
+ case IS_DOUBLE:
+ ZVAL_LONG(bind_type, PDO_PARAM_STR);
+ break;
+ #if PHP_MAJOR_VERSION < 7 /* PHP Version 5 */
+ case IS_BOOL:
+ #else /* PHP Version 7 */
+ case IS_TRUE:
+ case IS_FALSE:
+ #endif
+ ZVAL_LONG(bind_type, PDO_PARAM_BOOL);
+ break;
+ case IS_STRING:
+ //if (is_numeric_string(Z_STRVAL_P(value), Z_STRLEN_P(value), NULL, NULL, 0)) { //当varchar类型的数字 where update为字符串的时候,数据库报错。
+ // ZVAL_LONG(bind_type, PDO_PARAM_INT);
+ //} else {
+ ZVAL_LONG(bind_type, PDO_PARAM_STR);
+ //}
+ break;
+ default:
+ break;
+ }
+
+ bind_args[2] = &bind_type;
+
+ int ret = yaf_call_user_function_return_bool_or_unsigned(&statement, "bindValue", 3, bind_args);
+ yaf_zval_ptr_dtor(&bind_key);
+ yaf_zval_ptr_dtor(&bind_type);
+
+ if (ret == FAILURE) {
+ yaf_zval_free(statement);
+ yaf_php_fatal_error(E_ERROR, "failed to bind value");
+ RETURN_LONG(-1);
+ }
+
+ YAF_HASHTABLE_FOREACH_END();
+ }
+
+ //execute
+ if (yaf_call_user_function_return_bool_or_unsigned(&statement, "execute", 0, NULL) == FAILURE) {
+ yaf_zval_free(statement);
+ yaf_php_fatal_error(E_ERROR, "failed to execute sql");
+ RETURN_LONG(-1);
+ }
+
+ if (EG(exception)) {
+ yaf_zval_free(statement);
+ RETURN_MY_ERROR("[exception] failed to execute sql");
+ }
+
+ //获取查询 error 信息
+ zval* errorCode = NULL;
+ zval* errorInfo = NULL;
+
+ yaf_call_user_function_ex_fast(&statement, "errorCode", &errorCode, 0, NULL);
+ yaf_call_user_function_ex_fast(&statement, "errorInfo", &errorInfo, 0, NULL);
+
+ update_pdo_error(thisObject, errorCode, errorInfo);
+
+ if (YAF_IS_NULL(errorCode) || strcmp(Z_STRVAL_P(errorCode), "00000") != 0) {
+ yaf_zval_free(statement);
+ yaf_zval_free(errorCode);
+ yaf_zval_free(errorInfo);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_free(errorCode);
+ yaf_zval_free(errorInfo);
+
+ if (is_write) {
+ if(isinsert) {
+ zval* insertid = NULL;
+ yaf_zval_free(statement);
+
+ if (yaf_call_user_function_ex_fast(&pdo, "lastInsertId", &insertid, 0, NULL) == FAILURE) {
+ yaf_zval_free(insertid);
+ yaf_php_fatal_error(E_ERROR, "failed to get lastInsertId");
+ RETURN_LONG(-1);
+ }
+
+ if (EG(exception) || YAF_IS_NULL(insertid)) {
+ yaf_zval_free(insertid);
+ RETURN_MY_ERROR("failed to get lastInsertId, pdo is not initialized");
+ }
+
+ RETVAL_ZVAL(insertid, 1, 1);
+ efree(insertid);
+ } else {
+ int row_count = yaf_call_user_function_return_bool_or_unsigned(&statement, "rowCount", 0, NULL);
+ yaf_zval_free(statement);
+ RETURN_LONG(row_count);
+ }
+ } else {
+ RETVAL_ZVAL(statement, 1, 1);
+ efree(statement);
+ }
+ }
+}
+
+//原生查询query
+PHP_METHOD(yaf_db, query) {
+ zval* thisObject = getThis();
+ zval *z_sql = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &z_sql) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ if (Z_TYPE_P(z_sql) != IS_STRING) {
+ RETURN_MY_ERROR("Argument 1 passed must be of the type string");
+ }
+
+ //执行SQL
+ zval *statement = NULL;
+ zval **exec_args[1];
+ exec_args[0] = &z_sql;
+
+ if (yaf_call_user_function_ex_fast(&thisObject, "exec", &statement, 1, exec_args) == FAILURE) {
+ yaf_zval_free(statement);
+ RETURN_LONG(-1);
+ }
+
+ //unix socket
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { // unix socket
+ if(YAF_IS_NULL(statement)) {
+ yaf_zval_free(statement);
+ RETURN_LONG(-1);
+ }
+
+ zval *copy = yaf_zval_copy(statement);
+ yaf_zval_free(statement);
+ RETURN_ZVAL(copy, 0, 0);
+ } else if (YAF_IS_NOT_NULL(statement) && Z_TYPE_P(statement) == IS_OBJECT) { //获取结果
+ zval **fetch_args[1];
+ zval *result = NULL, *fetch_type = NULL;
+
+ YAF_MAKE_STD_ZVAL(fetch_type);
+ ZVAL_LONG(fetch_type, PDO_FETCH_ASSOC);
+
+ fetch_args[0] = &fetch_type;
+
+ if (yaf_call_user_function_ex_fast(&statement, "fetchAll", &result, 1, fetch_args) == FAILURE) {
+ yaf_zval_free(statement);
+ yaf_zval_free(result);
+ yaf_zval_ptr_dtor(&fetch_type);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_free(statement);
+ yaf_zval_ptr_dtor(&fetch_type);
+
+ RETVAL_ZVAL(result, 1, 1);
+ efree(result);
+ } else {
+ yaf_zval_free(statement);
+ RETURN_LONG(-1);
+ }
+}
+
+PHP_METHOD(yaf_db, insert_id) {
+ zval *thisObject = getThis();
+
+ //初始化错误
+ update_error_info(thisObject, "00000", "");
+
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { ///// unix domain sockcet ////
+ zval* insert_id = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("insert_id") TSRMLS_CC);
+ RETVAL_ZVAL(insert_id, 1, 0);
+ } else {
+ zval* pdo = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("_pdo") TSRMLS_CC);
+ if (YAF_IS_NULL(pdo)) {
+ RETURN_MY_ERROR("pdo is empty");
+ }
+
+ //exec
+ zval* insertid = NULL;
+ if (yaf_call_user_function_ex_fast(&pdo, "lastInsertId", &insertid, 0, NULL) == FAILURE) {
+ yaf_zval_free(insertid);
+ yaf_php_fatal_error(E_ERROR, "failed to get lastInsertId");
+ RETURN_LONG(-1);
+ }
+
+ if (EG(exception) || YAF_IS_NULL(insertid)) {
+ yaf_zval_free(insertid);
+ RETURN_MY_ERROR("failed to get lastInsertId, pdo is not initialized");
+ }
+
+ RETVAL_ZVAL(insertid, 1, 1);
+ efree(insertid);
+ }
+}
+
+//insert 插入
+PHP_METHOD(yaf_db, insert) {
+ char *table = NULL;
+ zval *thisObject = getThis();
+ zend_size_t table_len;
+ zval *data = NULL, *cache_info = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &table, &table_len, &data, &cache_info) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ //删除缓存
+ if(YAF_IS_NOT_NULL(cache_info) && YAF_IS_ARRAY(cache_info)) {
+ zval* cache_obj = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("cache") TSRMLS_CC);
+ del_cache(cache_obj, cache_info);
+ }
+
+ //解析data数据
+ char *insert_sql, *insert_keys,*insert_value;
+ char *key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+ char longval[MAP_ITOA_INT_SIZE], doubleval[32];
+
+ yaf_string_emalloc_32(&insert_sql, 0);
+ yaf_string_emalloc_32(&insert_keys, 0);
+ yaf_string_emalloc_32(&insert_value, 0);
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(data), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ yaf_string_efree_32(insert_keys);
+ yaf_string_efree_32(insert_value);
+ yaf_string_efree_32(insert_sql);
+ RETURN_MY_ERROR("input data must be key/value hash, not index array.");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&insert_keys, 3, "`", key, "`,");
+
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "NULL,");
+ break;
+ case IS_ARRAY:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "ARRAY,");
+ break;
+#if PHP_MAJOR_VERSION < 7 /* PHP Version 5 */
+ case IS_BOOL:
+ if (Z_BVAL_P(value)) {
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "1,");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "0,");
+ }
+ break;
+#else /* PHP Version 7 */
+ case IS_TRUE:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "1,");
+ break;
+ case IS_FALSE:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "0,");
+ break;
+#endif
+ case IS_LONG:
+ yaf_itoa(Z_LVAL_P(value), longval);
+ yaf_multi_memcpy_auto_realloc(&insert_value, 2, longval, ",");
+ break;
+
+ case IS_DOUBLE:
+ sprintf(doubleval, "%g", Z_DVAL_P(value));
+ yaf_multi_memcpy_auto_realloc(&insert_value, 2, doubleval, ",");
+ break;
+ case IS_STRING:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 3, "'", Z_STRVAL_P(value), "',");
+ break;
+ }
+
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ rtrim_str(insert_keys, ",");
+ rtrim_str(insert_value, ",");
+ yaf_multi_memcpy_auto_realloc(&insert_sql, 7, "INSERT INTO `", table, "` (", insert_keys ,") values (", insert_value, ")");
+ yaf_string_efree_32(insert_keys);
+ yaf_string_efree_32(insert_value);
+
+ //执行SQL
+ zval *result = NULL, *z_sql = NULL;
+ zval **exec_args[1];
+
+ YAF_MAKE_STD_ZVAL(z_sql);
+ YAF_ZVAL_STRING(z_sql, insert_sql, 1);
+ yaf_string_efree_32(insert_sql);
+ exec_args[0] = &z_sql;
+
+ if (yaf_call_user_function_ex_fast(&thisObject, "exec", &result, 1, exec_args) == FAILURE) {
+ yaf_zval_ptr_dtor(&z_sql);
+ yaf_zval_free(result);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_ptr_dtor(&z_sql);
+ RETVAL_ZVAL(result, 1, 1);
+ efree(result);
+}
+
+//replace 替换
+PHP_METHOD(yaf_db, replace) {
+ char *table = NULL;
+ zval *thisObject = getThis();
+ zend_size_t table_len;
+ zval *data = NULL, *cache_info = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &table, &table_len, &data, &cache_info) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ //删除缓存
+ if(YAF_IS_NOT_NULL(cache_info) && YAF_IS_ARRAY(cache_info)) {
+ zval* cache_obj = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("cache") TSRMLS_CC);
+ del_cache(cache_obj, cache_info);
+ }
+
+ //解析data数据
+ char *insert_sql, *insert_keys,*insert_value;
+ char *key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+ char longval[MAP_ITOA_INT_SIZE], doubleval[32];
+
+ yaf_string_emalloc_32(&insert_sql, 0);
+ yaf_string_emalloc_32(&insert_keys, 0);
+ yaf_string_emalloc_32(&insert_value, 0);
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(data), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ yaf_string_efree_32(insert_keys);
+ yaf_string_efree_32(insert_value);
+ yaf_string_efree_32(insert_sql);
+ RETURN_MY_ERROR("input data must be key/value hash, not index array.");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&insert_keys, 3, "`", key, "`,");
+
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "NULL,");
+ break;
+ case IS_ARRAY:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "ARRAY,");
+ break;
+#if PHP_MAJOR_VERSION < 7 /* PHP Version 5 */
+ case IS_BOOL:
+ if (Z_BVAL_P(value)) {
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "1,");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "0,");
+ }
+ break;
+#else /* PHP Version 7 */
+ case IS_TRUE:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "1,");
+ break;
+ case IS_FALSE:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 1, "0,");
+ break;
+#endif
+ case IS_LONG:
+ yaf_itoa(Z_LVAL_P(value), longval);
+ yaf_multi_memcpy_auto_realloc(&insert_value, 2, longval, ",");
+ break;
+
+ case IS_DOUBLE:
+ sprintf(doubleval, "%g", Z_DVAL_P(value));
+ yaf_multi_memcpy_auto_realloc(&insert_value, 2, doubleval, ",");
+ break;
+ case IS_STRING:
+ yaf_multi_memcpy_auto_realloc(&insert_value, 3, "'", Z_STRVAL_P(value), "',");
+ break;
+ }
+
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ rtrim_str(insert_keys, ",");
+ rtrim_str(insert_value, ",");
+ yaf_multi_memcpy_auto_realloc(&insert_sql, 7, "REPLACE INTO `", table, "` (", insert_keys ,") values (", insert_value, ")");
+ yaf_string_efree_32(insert_keys);
+ yaf_string_efree_32(insert_value);
+
+ //执行SQL
+ zval *result = NULL, *z_sql = NULL;
+ zval **exec_args[1];
+
+ YAF_MAKE_STD_ZVAL(z_sql);
+ YAF_ZVAL_STRING(z_sql, insert_sql, 1);
+ yaf_string_efree_32(insert_sql);
+ exec_args[0] = &z_sql;
+
+ if (yaf_call_user_function_ex_fast(&thisObject, "exec", &result, 1, exec_args) == FAILURE) {
+ yaf_zval_ptr_dtor(&z_sql);
+ yaf_zval_free(result);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_ptr_dtor(&z_sql);
+ RETVAL_ZVAL(result, 1, 1);
+ efree(result);
+}
+
+//update 更新
+PHP_METHOD(yaf_db, update) {
+ char *table = NULL;
+ zval *thisObject = getThis();
+ zend_size_t table_len;
+ zval *data = NULL, *where = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &table, &table_len, &data, &where) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ //更新语句
+ char *update_sql;
+ yaf_string_emalloc_32(&update_sql, 0);
+
+ char *update_datas;
+ char *key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+ char longval[MAP_ITOA_INT_SIZE], doubleval[32];
+
+ yaf_string_emalloc_32(&update_datas, 0);
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(data), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ yaf_string_efree_32(update_datas);
+ yaf_string_efree_32(update_sql);
+ RETURN_MY_ERROR("input data must be key/value hash, not index array.");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&update_datas, 3, "`", key, "` = ");
+
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ yaf_multi_memcpy_auto_realloc(&update_datas, 1, "NULL,");
+ break;
+ case IS_ARRAY:
+ yaf_multi_memcpy_auto_realloc(&update_datas, 1, "ARRAY,");
+ break;
+#if PHP_MAJOR_VERSION < 7 /* PHP Version 5 */
+ case IS_BOOL:
+ if (Z_BVAL_P(value)) {
+ yaf_multi_memcpy_auto_realloc(&update_datas, 1, "1,");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&update_datas, 1, "0,");
+ }
+ break;
+#else /* PHP Version 7 */
+ case IS_TRUE:
+ yaf_multi_memcpy_auto_realloc(&update_datas, 1, "1,");
+ break;
+ case IS_FALSE:
+ yaf_multi_memcpy_auto_realloc(&update_datas, 1, "0,");
+ break;
+#endif
+ case IS_LONG:
+ yaf_itoa(Z_LVAL_P(value), longval);
+ yaf_multi_memcpy_auto_realloc(&update_datas, 2, longval, ",");
+ break;
+
+ case IS_DOUBLE:
+ sprintf(doubleval, "%g", Z_DVAL_P(value));
+ yaf_multi_memcpy_auto_realloc(&update_datas, 2, doubleval, ",");
+ break;
+ case IS_STRING:
+ yaf_multi_memcpy_auto_realloc(&update_datas, 3, "'", Z_STRVAL_P(value), "',");
+ break;
+ }
+
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ rtrim_str(update_datas, ",");
+ yaf_multi_memcpy_auto_realloc(&update_sql, 4, "UPDATE `", table, "` SET ", update_datas);
+ yaf_string_efree_32(update_datas);
+
+ //where条件
+ zval *map, *cache_info = NULL;
+ YAF_MAKE_STD_ZVAL(map);
+ array_init(map);
+
+ where_clause(where, map, & update_sql, &cache_info);
+
+ //删除缓存
+ if(YAF_IS_NOT_NULL(cache_info) && YAF_IS_ARRAY(cache_info)) {
+ zval* cache_obj = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("cache") TSRMLS_CC);
+ del_cache(cache_obj, cache_info);
+ }
+
+ //执行 SQL 语句
+ zval *z_sql = NULL, *result = NULL;
+ zval **exec_args[2];
+
+ YAF_MAKE_STD_ZVAL(z_sql);
+ YAF_ZVAL_STRING(z_sql, update_sql, 1);
+ yaf_string_efree_32(update_sql);
+
+ exec_args[0] = &z_sql;
+ exec_args[1] = ↦
+
+ if (yaf_call_user_function_ex_fast(&thisObject, "exec", &result, 2, exec_args) == FAILURE) {
+ yaf_zval_ptr_dtor(&map);
+ yaf_zval_ptr_dtor(&z_sql);
+ yaf_zval_free(result);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_ptr_dtor(&map);
+ yaf_zval_ptr_dtor(&z_sql);
+ RETVAL_ZVAL(result, 1, 1);
+ efree(result);
+}
+
+
+//delete 删除
+PHP_METHOD(yaf_db, delete) {
+ char *table = NULL;
+ zval *thisObject = getThis();
+ zend_size_t table_len;
+ zval *where = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &table, &table_len, &where) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ //更新语句
+ char *delete_sql;
+ yaf_string_emalloc_32(&delete_sql, 0);
+ yaf_multi_memcpy_auto_realloc(&delete_sql, 3, "DELETE FROM `", table, "` ");
+
+ //cache 缓存
+ zval *cache_info = NULL;
+
+ //where条件
+ zval *map;
+ YAF_MAKE_STD_ZVAL(map);
+ array_init(map);
+
+ where_clause(where, map, & delete_sql, &cache_info);
+
+ //删除缓存
+ if(YAF_IS_NOT_NULL(cache_info) && YAF_IS_ARRAY(cache_info)) {
+ zval* cache_obj = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("cache") TSRMLS_CC);
+ del_cache(cache_obj, cache_info);
+ }
+
+ //执行 SQL 语句
+ zval *z_sql = NULL, *result = NULL;
+ zval **exec_args[2];
+
+ YAF_MAKE_STD_ZVAL(z_sql);
+ YAF_ZVAL_STRING(z_sql, delete_sql, 1);
+ yaf_string_efree_32(delete_sql);
+
+ exec_args[0] = &z_sql;
+ exec_args[1] = ↦
+
+ if (yaf_call_user_function_ex_fast(&thisObject, "exec", &result, 2, exec_args) == FAILURE) {
+ yaf_zval_ptr_dtor(&map);
+ yaf_zval_ptr_dtor(&z_sql);
+ yaf_zval_free(result);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_ptr_dtor(&map);
+ yaf_zval_ptr_dtor(&z_sql);
+ RETVAL_ZVAL(result, 1, 1);
+ efree(result);
+}
+
+//select 查询
+PHP_METHOD(yaf_db, select) {
+ char* table = NULL;
+ zval* thisObject = getThis();
+ zend_size_t table_len;
+ zval* join = NULL, *columns = NULL, *where = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|zz", &table, &table_len, &join, &columns, &where) == FAILURE) {
+ RETURN_LONG(-1);
+ }
+
+ //是否查询单个列,当 where 为空的时候, 判断 join 是不是 "*",否则判断 columns 是不是 "*"
+ int is_single_column = 0;
+ if ((YAF_IS_NULL(where) && Z_TYPE_P(join) == IS_STRING && strcmp(Z_STRVAL_P(join), "*") != 0 && yaf_strpos(Z_STRVAL_P(join), ",") < 0)
+ ||(YAF_IS_NOT_NULL(where) && Z_TYPE_P(columns) == IS_STRING && strcmp(Z_STRVAL_P(columns), "*") != 0) && yaf_strpos(Z_STRVAL_P(join), ",") < 0) {
+ is_single_column = 1;
+ }
+
+ //查询语句初始化
+ char *sql;
+ zval *map;
+ zval *cache_info = NULL, *cache_obj = NULL, *cache_key = NULL;
+
+ YAF_MAKE_STD_ZVAL(map);
+ array_init(map);
+ yaf_string_emalloc_32(&sql, 0);
+
+ select_context(table, map, join, columns, where, &sql, &cache_info);
+
+ //缓存获取数据
+ if(YAF_IS_NOT_NULL(cache_info) && YAF_IS_ARRAY(cache_info)) {
+ cache_obj = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("cache") TSRMLS_CC);
+ if (YAF_IS_NOT_NULL(cache_obj)) {
+ cache_key = php_yaf_array_get_value(Z_ARRVAL_P(cache_info), "key");
+ if(YAF_IS_NOT_NULL(cache_key)) {
+ zval* cache_ret = get_cache(cache_obj, cache_key);
+
+ if(cache_ret != NULL) {
+ RETVAL_ZVAL(cache_ret, 1, 1);
+ efree(cache_ret);
+ yaf_string_efree_32(sql);
+ yaf_zval_ptr_dtor(&map);
+ return;
+ }
+ }
+ }
+ }
+
+ //执行SQL
+ zval *z_sql = NULL, *statement = NULL;
+ zval **exec_args[2];
+
+ YAF_MAKE_STD_ZVAL(z_sql);
+ YAF_ZVAL_STRING(z_sql, sql, 1);
+ yaf_string_efree_32(sql);
+
+ exec_args[0] = &z_sql;
+ exec_args[1] = ↦
+
+ if (yaf_call_user_function_ex_fast(&thisObject, "exec", &statement, 2, exec_args) == FAILURE) {
+ yaf_zval_ptr_dtor(&map);
+ yaf_zval_ptr_dtor(&z_sql);
+ yaf_zval_free(statement);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_ptr_dtor(&map);
+ yaf_zval_ptr_dtor(&z_sql);
+
+ //unix socket
+ zval* unix_socket = yaf_read_init_property(yaf_db_ce_ptr, thisObject, ZEND_STRL("unix_socket") TSRMLS_CC);
+ if(YAF_IS_NOT_NULL(unix_socket)) { // unix socket
+ if(YAF_IS_NULL(statement)) {
+ yaf_zval_free(statement);
+ RETURN_LONG(-1);
+ }
+
+ zval *copy = yaf_zval_copy(statement);
+ yaf_zval_free(statement);
+ RETURN_ZVAL(copy, 0, 0);
+ } else if (YAF_IS_NOT_NULL(statement) && Z_TYPE_P(statement) == IS_OBJECT) { //获取结果
+ zval **fetch_args[1];
+ zval *result = NULL, *fetch_type = NULL;
+
+ YAF_MAKE_STD_ZVAL(fetch_type);
+ if (is_single_column == 1) {
+ ZVAL_LONG(fetch_type, PDO_FETCH_COLUMN);
+ } else {
+ ZVAL_LONG(fetch_type, PDO_FETCH_ASSOC);
+ }
+
+ fetch_args[0] = &fetch_type;
+
+ if (yaf_call_user_function_ex_fast(&statement, "fetchAll", &result, 1, fetch_args) == FAILURE) {
+ yaf_zval_free(statement);
+ yaf_zval_free(result);
+ yaf_zval_ptr_dtor(&fetch_type);
+ RETURN_LONG(-1);
+ }
+
+ yaf_zval_free(statement);
+ yaf_zval_ptr_dtor(&fetch_type);
+
+ //缓存数据
+ if(YAF_IS_NOT_NULL(cache_key)) {
+ zval* cache_expire = php_yaf_array_get_value(Z_ARRVAL_P(cache_info), "expire");
+ zval* real_expire = NULL;
+ if(YAF_IS_NULL(cache_expire)) { //默认5分钟/300秒
+ YAF_MAKE_STD_ZVAL(real_expire);
+ ZVAL_LONG(real_expire, 300);
+ } else {
+ real_expire = cache_expire;
+ }
+
+ set_cache(cache_obj, cache_key, real_expire, result);
+ }
+
+ RETVAL_ZVAL(result, 1, 1);
+ efree(result);
+ } else {
+ yaf_zval_free(statement);
+ RETURN_LONG(-1);
+ }
+}
+
+int set_cache(zval* cache_obj, zval* cache_key, zval* cache_expire, zval* cache_value) {
+ zval* set_string_value;
+ YAF_MAKE_STD_ZVAL(set_string_value);
+ yaf_serialize(set_string_value, cache_value);
+
+ //set value
+ zval **set_args[2];
+ set_args[0] = &cache_key;
+ set_args[1] = &set_string_value;
+ int ret = yaf_call_user_function_return_bool_or_unsigned(&cache_obj, "set", 2, set_args);
+ yaf_zval_ptr_dtor(&set_string_value);
+
+ //set expire time
+ if(ret == 1) {
+ zval **set_args[2];
+ set_args[0] = &cache_key;
+ set_args[1] = &cache_expire;
+ ret = yaf_call_user_function_return_bool_or_unsigned(&cache_obj, "expire", 2, set_args);
+ }
+}
+
+zval* get_cache(zval* cache_obj, zval* cache_key) {
+ zval *ret_string = NULL;
+ zval **get_args[1];
+ get_args[0] = &cache_key;
+
+ if (yaf_call_user_function_ex_fast(&cache_obj, "get", &ret_string, 1, get_args) == FAILURE) {
+ yaf_zval_free(ret_string);
+ return NULL;
+ }
+
+ if (Z_TYPE_P(ret_string) != IS_STRING){
+ yaf_zval_free(ret_string);
+ return NULL;
+ }
+
+ zval *ret_array;
+ YAF_ALLOC_INIT_ZVAL(ret_array);
+ yaf_unserialize(ret_array, ret_string);
+ yaf_zval_free(ret_string);
+
+ if (YAF_IS_NULL(ret_array) || Z_TYPE_P(ret_array) != IS_ARRAY) {
+ yaf_zval_free(ret_array);
+ return NULL;
+ }
+
+ return ret_array;
+}
+
+void del_cache(zval* cache_obj, zval* cache_info) {
+ if (YAF_IS_NOT_NULL(cache_obj)) {
+ zval* cache_key = php_yaf_array_get_value(Z_ARRVAL_P(cache_info), "key");
+ if(YAF_IS_NOT_NULL(cache_key)) {
+ zval **del_args[1];
+ del_args[0] = &cache_key;
+ yaf_call_user_function_return_bool_or_unsigned(&cache_obj, "del", 1, del_args);
+ }
+ }
+}
+
+char *select_context(char* table, zval* map, zval* join, zval* columns, zval* where, char** sql, zval** cache_info) {
+ //表别名
+ char* table_query;
+ yaf_string_emalloc_32(&table_query, 0);
+
+ char table_match[MAX_TABLE_SIZE] = {0};
+ char alias_match[MAX_TABLE_SIZE] = {0};
+ preg_table_match(table, table_match, alias_match);
+ if (yaf_is_string_not_empty(table_match) && yaf_is_string_not_empty(alias_match)) {
+ yaf_multi_memcpy_auto_realloc(&table_query, 5, "`", table_match, "` AS `", alias_match, "`");
+ } else {
+ yaf_multi_memcpy_auto_realloc(&table_query, 3, "`", table, "`");
+ }
+
+ //解析 join
+ char* first_join_key = NULL;
+ zval* real_where = where;
+ zval* real_columns = columns;
+
+ if (YAF_IS_ARRAY(join) && (first_join_key = yaf_get_array_key_index(join, 0)) != NULL && yaf_strpos(first_join_key, "[") == 0) { //第二个参数不为空,而且判断是 join 的情况
+ if (yaf_is_string_not_empty(alias_match)) {
+ handle_join(join, alias_match, &table_query);
+ } else {
+ handle_join(join, table, &table_query);
+ }
+ } else {
+ if (YAF_IS_NULL(where)) { //第四个参数为空时,第二个参数为 column , 第三个参数为 where
+ real_columns = join;
+ real_where = columns;
+ }
+ }
+
+ //选择要查询的列
+ char* column_query;
+ yaf_string_emalloc_32(&column_query, 0);
+
+ column_push(real_columns, map, &column_query);
+
+ yaf_multi_memcpy_auto_realloc(sql, 4, "SELECT ", column_query, " FROM ", table_query);
+
+ yaf_string_efree_32(column_query);
+ yaf_string_efree_32(table_query);
+
+ where_clause(real_where, map, sql, cache_info);
+ return *sql;
+}
+
+//处理 where 条件
+char* where_clause(zval* where, zval* map, char** sql, zval** cache_info) {
+ if (YAF_IS_EMPTY(where)) {
+ return *sql;
+ }
+
+ char* group_by_condition = NULL;
+ char* having_condition = NULL;
+ char* order_condition = NULL;
+ char* limit_condition = NULL;
+
+ char* where_condition = NULL;
+ yaf_string_emalloc_32(&where_condition, 0);
+
+ if (YAF_IS_ARRAY(where)) {
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(where), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ continue;
+ } else {
+ if (strcmp(key, "GROUP") == 0) { //分组
+ yaf_string_emalloc_32(&group_by_condition, 0);
+ group_by_implode(value, &group_by_condition);
+ } else if (strcmp(key, "HAVING") == 0) { //分组条件
+ yaf_string_emalloc_32(&having_condition, 0);
+ having_implode(value, map, &having_condition);
+ } else if (strcmp(key, "ORDER") == 0) { //排序
+ yaf_string_emalloc_32(&order_condition, 0);
+ order_implode(value, &order_condition);
+ } else if (strcmp(key, "LIMIT") == 0) { //结果条数
+ yaf_string_emalloc_32(&limit_condition, 0);
+ limit_implode(value, &limit_condition);
+ } else if (strcmp(key, "CACHE") == 0) { //结果条数
+ *cache_info = value;
+ } else { // where clause
+ where_implode(key, value, map, &where_condition, "AND");
+ }
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ strreplace(where_condition, "( AND", "(");
+ trim(ltrim_str(ltrim(where_condition), "AND"));
+ if (where_condition[0] != '\0') {
+ yaf_multi_memcpy_auto_realloc(sql, 2, " WHERE ", where_condition);
+ }
+ }
+
+ yaf_string_efree_32(where_condition);
+
+ if (group_by_condition != NULL) {
+ yaf_multi_memcpy_auto_realloc(sql, 2, " GROUP BY ", group_by_condition);
+ yaf_string_efree_32(group_by_condition);
+ }
+
+ if (having_condition != NULL) {
+ yaf_multi_memcpy_auto_realloc(sql, 2, " HAVING ", having_condition);
+ yaf_string_efree_32(having_condition);
+ }
+
+ if (order_condition != NULL) {
+ yaf_multi_memcpy_auto_realloc(sql, 2, " ORDER BY ", order_condition);
+ yaf_string_efree_32(order_condition);
+ }
+
+ if (limit_condition != NULL) {
+ yaf_multi_memcpy_auto_realloc(sql, 2, " LIMIT ", limit_condition);
+ yaf_string_efree_32(limit_condition);
+ }
+
+ return *sql;
+}
+
+
+//where condition
+char* where_implode(char* key, zval* value, zval* map, char** where_query, char* connector) {
+ //key是否是 AND 或者 OR
+ char relation_ship[MAX_OPERATOR_SIZE] = {0};
+ preg_and_or_match(key, relation_ship);
+
+ if (Z_TYPE_P(value) == IS_ARRAY && yaf_is_string_not_empty(relation_ship)) {
+ char* relation_key;
+ zval* relation_value;
+ uint32_t relation_key_len;
+ int relation_key_type;
+
+ char* sub_where_clause = NULL;
+ yaf_string_emalloc_32(&sub_where_clause, 0);
+
+ yaf_multi_memcpy_auto_realloc(where_query, 1, " AND (");
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(value), relation_key, relation_key_len, relation_key_type, relation_value)
+ if (HASH_KEY_IS_STRING != relation_key_type) {
+ continue;
+ } else {
+ where_implode(relation_key, relation_value, map, &sub_where_clause, relation_ship);
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ yaf_multi_memcpy_auto_realloc(where_query, 2, sub_where_clause, ")");
+ yaf_string_efree_32(sub_where_clause);
+ return *where_query;
+ }
+
+ char column[MAX_TABLE_SIZE] = {0};
+ char operator[MAX_OPERATOR_SIZE] = {0};
+ preg_operator_match(key, column, operator);
+
+ if (yaf_is_string_not_empty(column)) {
+ char mapkey[MAP_KEY_SIZE] = {0};
+
+ column_quote(column, column);
+
+ if (yaf_is_string_not_empty(operator)) {
+ if (strcmp(operator, ">") == 0 || strcmp(operator, ">=") == 0 || strcmp(operator, "<") == 0 || strcmp(operator, "<=") == 0) { // >, >=, <, <=
+ get_mapkey(mapkey);
+ add_map(map, mapkey, value);
+ yaf_multi_memcpy_auto_realloc(where_query, 6, connector, column, operator, " ", mapkey, " ");
+ } else if (strcmp(operator, "!") == 0) { //not equal
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ yaf_multi_memcpy_auto_realloc(where_query, 3, connector, column, "IS NOT NULL ");
+ break;
+ case IS_ARRAY:
+ yaf_multi_memcpy_auto_realloc(where_query, 3, connector, column, "NOT IN (");
+ handle_where_not_in(value, where_query, map);
+ yaf_multi_memcpy_auto_realloc(where_query, 1, ") ");
+ break;
+ case IS_LONG:
+ case IS_STRING:
+ case IS_DOUBLE:
+#if PHP_MAJOR_VERSION < 7 /* PHP Version 5 */
+ case IS_BOOL:
+#else /* PHP Version 7 */
+ case IS_TRUE:
+ case IS_FALSE:
+#endif
+ get_mapkey(mapkey);
+ add_map(map, mapkey, value);
+ yaf_multi_memcpy_auto_realloc(where_query, 5, connector, column, "!= ", mapkey, " ");
+ break;
+ }
+ } else if (strcmp(operator, "~") == 0 || strcmp(operator, "!~") == 0) { //like
+ if (Z_TYPE_P(value) == IS_STRING) {
+ get_mapkey(mapkey);
+ add_map(map, mapkey, value);
+ yaf_multi_memcpy_auto_realloc(where_query, 5, connector, column, (strcmp(operator, "~") == 0 ? "LIKE " : "NOT LIKE "), mapkey, " ");
+ } else if (Z_TYPE_P(value) == IS_ARRAY) {
+ char* like_connector = yaf_get_array_key_index(value, 0);
+ if (like_connector != NULL && (strcmp(like_connector, "AND") == 0 || strcmp(like_connector, "OR") == 0)) {
+ //自定义LIKE连接符
+ zval* connetor_value = php_yaf_array_get_value(Z_ARRVAL_P(value), like_connector);
+
+ if (Z_TYPE_P(connetor_value) == IS_ARRAY) {
+ yaf_multi_memcpy_auto_realloc(where_query, 2, connector, " (");
+ handle_like_array(connetor_value, where_query, column, operator, map, like_connector);
+ yaf_multi_memcpy_auto_realloc(where_query, 1, ") ");
+ }
+ } else { //默认括号内LIKE连接符为 OR
+ yaf_multi_memcpy_auto_realloc(where_query, 2, connector, " (");
+ handle_like_array(value, where_query, column, operator, map, "OR");
+ yaf_multi_memcpy_auto_realloc(where_query, 1, ") ");
+ }
+ }
+ } else if (strcmp(operator, "<>") == 0 || strcmp(operator, "><") == 0) {
+ if (Z_TYPE_P(value) == IS_ARRAY) {
+ zval* between_a = yaf_get_element_by_hashtable_index(Z_ARRVAL_P(value), 0);
+ zval* between_b = yaf_get_element_by_hashtable_index(Z_ARRVAL_P(value), 1);
+ if (YAF_IS_NOT_EMPTY(between_a) && (Z_TYPE_P(between_a) == IS_LONG || Z_TYPE_P(between_a) == IS_STRING)
+ && YAF_IS_NOT_EMPTY(between_b) && (Z_TYPE_P(between_b) == IS_LONG || Z_TYPE_P(between_b) == IS_STRING)) {
+ yaf_multi_memcpy_auto_realloc(where_query, 2, connector, " ");
+ if (strcmp(operator, "><") == 0) {
+ yaf_multi_memcpy_auto_realloc(where_query, 1, "NOT ");
+ }
+ get_mapkey(mapkey);
+ add_map(map, mapkey, between_a);
+ yaf_multi_memcpy_auto_realloc(where_query, 5, "(", column, "BETWEEN ", mapkey, " ");
+ get_mapkey(mapkey);
+ add_map(map, mapkey, between_b);
+ yaf_multi_memcpy_auto_realloc(where_query, 3, "AND ", mapkey, ") ");
+ }
+ }
+ }
+ } else {
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ yaf_multi_memcpy_auto_realloc(where_query, 3, connector, column, "IS NULL ");
+ break;
+ case IS_ARRAY:
+ yaf_multi_memcpy_auto_realloc(where_query, 3, connector, column, "IN (");
+ handle_where_not_in(value, where_query, map);
+ yaf_multi_memcpy_auto_realloc(where_query, 1, ") ");
+ break;
+ case IS_LONG:
+ case IS_STRING:
+ case IS_DOUBLE:
+#if PHP_MAJOR_VERSION < 7 /* PHP Version 5 */
+ case IS_BOOL:
+#else /* PHP Version 7 */
+ case IS_TRUE:
+ case IS_FALSE:
+#endif
+ get_mapkey(mapkey);
+ add_map(map, mapkey, value);
+ yaf_multi_memcpy_auto_realloc(where_query, 5, connector, column, "= ", mapkey, " ");
+ break;
+ }
+ }
+ }
+
+ ltrim_str(*where_query, connector);
+ return *where_query;
+}
+
+//handle group by
+char* group_by_implode(zval* group, char** group_by_condition) {
+ if (YAF_IS_NOT_EMPTY(group)) {
+ if (Z_TYPE_P(group) == IS_STRING) {
+ yaf_multi_memcpy_auto_realloc(group_by_condition, 1, Z_STRVAL_P(group));
+ } else if (Z_TYPE_P(group) == IS_ARRAY) {
+ char* key;
+ zval* value;
+ uint32_t key_len;
+ int key_type;
+
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(group), key, key_len, key_type, value)
+ if (Z_TYPE_P(value) == IS_STRING) {
+ yaf_multi_memcpy_auto_realloc(group_by_condition, 2, Z_STRVAL_P(value), ",");
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ char* tmp = (*group_by_condition) + strlen(*group_by_condition) - 1;
+ if (*tmp == ',') {
+ *tmp = '\0';
+ }
+ }
+ }
+ return *group_by_condition;
+}
+
+//handle having
+char* having_implode(zval* having, zval* map, char** having_condition) {
+
+ if (YAF_IS_ARRAY(having)) {
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(having), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ continue;
+ } else {
+ where_implode(key, value, map, having_condition, "AND");
+ }
+ YAF_HASHTABLE_FOREACH_END();
+ }
+
+ strreplace(*having_condition, "( AND", "(");
+ trim(ltrim_str(ltrim(*having_condition), "AND"));
+ return *having_condition;
+}
+
+//order by
+char* order_implode(zval* order, char** order_condition) {
+ if (YAF_IS_NOT_EMPTY(order)) {
+ if (Z_TYPE_P(order) == IS_STRING) {
+ yaf_multi_memcpy_auto_realloc(order_condition, 1, Z_STRVAL_P(order));
+ } else if (Z_TYPE_P(order) == IS_ARRAY) {
+ char* key;
+ zval* value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(order), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) {
+ if (Z_TYPE_P(value) == IS_STRING) {
+ char column[MAX_TABLE_SIZE] = {0};
+ column_quote(Z_STRVAL_P(value), column);
+ yaf_multi_memcpy_auto_realloc(order_condition, 2, column, ",");
+ }
+ } else {
+ if (Z_TYPE_P(value) == IS_STRING && (strcmp(Z_STRVAL_P(value), "ASC") == 0 || strcmp(Z_STRVAL_P(value), "DESC") == 0)) {
+ char column[MAX_TABLE_SIZE] = {0};
+ column_quote(key, column);
+ yaf_multi_memcpy_auto_realloc(order_condition, 3, column, Z_STRVAL_P(value), ",");
+ }
+ }
+ YAF_HASHTABLE_FOREACH_END();
+ rtrim_str(*order_condition, ",");
+ }
+ }
+ return *order_condition;
+}
+
+//limit
+char* limit_implode(zval* limit, char** limit_condition) {
+ if (YAF_IS_NOT_EMPTY(limit)) {
+ if (Z_TYPE_P(limit) == IS_STRING || Z_TYPE_P(limit) == IS_LONG) {
+ convert_to_string(limit);
+ if (is_numeric_string(Z_STRVAL_P(limit), Z_STRLEN_P(limit), NULL, NULL, 0)) {
+ yaf_multi_memcpy_auto_realloc(limit_condition, 1, Z_STRVAL_P(limit));
+ }
+ } else if (Z_TYPE_P(limit) == IS_ARRAY) {
+ zval* offset_val = yaf_get_element_by_hashtable_index(Z_ARRVAL_P(limit), 0);
+ zval* limit_val = yaf_get_element_by_hashtable_index(Z_ARRVAL_P(limit), 1);
+ convert_to_string(limit_val);
+ convert_to_string(offset_val);
+
+ if (is_numeric_string(Z_STRVAL_P(limit_val), Z_STRLEN_P(limit_val), NULL, NULL, 0)
+ && is_numeric_string(Z_STRVAL_P(offset_val), Z_STRLEN_P(offset_val), NULL, NULL, 0)) {
+ yaf_multi_memcpy_auto_realloc(limit_condition, 3, Z_STRVAL_P(limit_val), " OFFSET ", Z_STRVAL_P(offset_val));
+ }
+ }
+ }
+
+ return *limit_condition;
+}
+
+//like array情况
+char* handle_like_array(zval* like_array, char** where_query, char* column, char* operator, zval* map, char* connector) {
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ char mapkey[MAP_KEY_SIZE] = {0};
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(like_array), key, key_len, key_type, value)
+ if (Z_TYPE_P(value) == IS_STRING || Z_TYPE_P(value) == IS_LONG) {
+ get_mapkey(mapkey);
+ add_map(map, mapkey, value);
+ yaf_multi_memcpy_auto_realloc(where_query, 5, column, strcmp(operator, "~") == 0 ? "LIKE " : "NOT LIKE ", mapkey, " ", connector);
+ }
+ YAF_HASHTABLE_FOREACH_END();
+ rtrim_str(rtrim(*where_query), connector);
+ return *where_query;
+}
+
+//not in 情况
+char* handle_where_not_in(zval* not_in_array, char** where_query, zval* map) {
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ char mapkey[MAP_KEY_SIZE] = {0};
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(not_in_array), key, key_len, key_type, value)
+ if (Z_TYPE_P(value) == IS_STRING || Z_TYPE_P(value) == IS_LONG) {
+ get_mapkey(mapkey);
+ add_map(map, mapkey, value);
+ yaf_multi_memcpy_auto_realloc(where_query, 3, " ", mapkey, ",");
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+ rtrim_str(rtrim(*where_query), ",");
+ return *where_query;
+}
+
+char* get_mapkey(char* mapkey) {
+ memset(mapkey, 0, MAP_KEY_SIZE);
+ zval* mapkey_index = zend_read_static_property(yaf_db_ce_ptr, ZEND_STRL("mapkey_index"), 1 TSRMLS_DC);
+ long l_mapkey_index = Z_LVAL_P(mapkey_index);
+ l_mapkey_index = (l_mapkey_index + 1) % 9999;
+ zend_update_static_property_long(yaf_db_ce_ptr, ZEND_STRL("mapkey_index"), l_mapkey_index TSRMLS_DC);
+ sprintf(mapkey, ":param_%d", l_mapkey_index);
+ return mapkey;
+}
+
+zval* add_map(zval* map, char* mapkey, zval* value) {
+ zval *copy = yaf_zval_copy(value);
+ add_assoc_zval(map, mapkey, copy);
+ return map;
+}
+
+//处理查询列
+char* column_push(zval* columns, zval* map, char** column_query) {
+ if (YAF_IS_EMPTY(columns) || (Z_TYPE_P(columns) == IS_STRING && strcmp(Z_STRVAL_P(columns), "*") == 0)) {
+ yaf_multi_memcpy_auto_realloc(column_query, 1, "*");
+ return *column_query;
+ }
+
+ if (Z_TYPE_P(columns) == IS_STRING) {
+ yaf_multi_memcpy_auto_realloc(column_query, 1, Z_STRVAL_P(columns));
+ return *column_query;
+ } else if (YAF_IS_ARRAY(columns)) {
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(columns), key, key_len, key_type, value)
+ if (Z_TYPE_P(value) != IS_STRING) {
+ continue;
+ }
+
+ char match_column[MAX_TABLE_SIZE] = {0};
+ char match_alias[MAX_TABLE_SIZE] = {0};
+ preg_table_match(Z_STRVAL_P(value), match_column, match_alias);
+
+ if (yaf_is_string_not_empty(match_column) && yaf_is_string_not_empty(match_alias)) {
+ yaf_multi_memcpy_auto_realloc(column_query, 4, match_column, " AS `", match_alias, "`,");
+ } else {
+ yaf_multi_memcpy_auto_realloc(column_query, 2, Z_STRVAL_P(value), ",");
+ }
+
+ YAF_HASHTABLE_FOREACH_END();
+
+ rtrim_str(rtrim(*column_query), ",");
+ return *column_query;
+ } else {
+ yaf_multi_memcpy_auto_realloc(column_query, 1, "*");
+ return *column_query;
+ }
+}
+
+//处理join
+char* handle_join(zval *join, char *table, char** table_query) {
+ char* sub_table;
+ zval* relation;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(join), sub_table, key_len, key_type, relation)
+ if (HASH_KEY_IS_STRING != key_type) { //非字符串
+ continue;
+ }
+
+ char join_join[MAX_TABLE_SIZE] = {0};
+ char join_table[MAX_TABLE_SIZE] = {0};
+ char join_alias[MAX_TABLE_SIZE] = {0};
+ preg_join_match(sub_table, join_join, join_table, join_alias);
+
+
+ if (yaf_is_string_not_empty(join_join) && yaf_is_string_not_empty(join_table)) {
+ yaf_multi_memcpy_auto_realloc(table_query, 5, " ", get_join_type(join_join), " JOIN `", join_table, "` ");
+ if (yaf_is_string_not_empty(join_alias)) {
+ yaf_multi_memcpy_auto_realloc(table_query, 3, "AS `", join_alias, "` ");
+ }
+
+ if (Z_TYPE_P(relation) == IS_STRING) {
+ yaf_multi_memcpy_auto_realloc(table_query, 3, "USING (`", Z_STRVAL_P(relation), "`) ");
+ } else if (Z_TYPE_P(relation) == IS_ARRAY) {
+ if (is_set_array_index(Z_ARRVAL_P(relation), 0)) { //relation 为数组
+ yaf_multi_memcpy_auto_realloc(table_query, 1, "USING (`");
+ yaf_implode(relation, "`,`", table_query);
+ yaf_multi_memcpy_auto_realloc(table_query, 1, "`) ");
+ } else { //relation 为 Key Hash
+ char *key;
+ zval *value;
+
+ yaf_multi_memcpy_auto_realloc(table_query, 1, "ON ");
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(relation), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) { //非字符串
+ continue;
+ }
+
+ char* table_column = NULL;
+ yaf_string_emalloc_32(&table_column, 0);
+ if (yaf_strpos(key, ".") >= 0) {
+ column_quote(key, table_column);
+ } else {
+ yaf_multi_memcpy_auto_realloc(&table_column, 5, "`", table, "`.`", key, "`");
+ }
+
+ //alias
+ if (yaf_is_string_not_empty(join_alias)) {
+ yaf_multi_memcpy_auto_realloc(table_query, 4, table_column, "=`", join_alias, "`");
+ } else {
+ yaf_multi_memcpy_auto_realloc(table_query, 4, table_column, "= `", join_table, "`");
+ }
+
+ yaf_string_efree_32(table_column);
+
+ yaf_multi_memcpy_auto_realloc(table_query, 3, ".`", Z_STRVAL_P(value), "` AND");
+ YAF_HASHTABLE_FOREACH_END();
+
+ rtrim_str(rtrim(*table_query), "AND");
+ }
+ }
+
+ }
+ YAF_HASHTABLE_FOREACH_END();
+
+
+ return *table_query;
+}
+
+char* column_quote(char* string, char* table_column) {
+ char tmp[MAX_TABLE_SIZE] = {0};
+
+ sprintf(tmp, " `%s` ", string);
+
+ if (strlen(tmp) >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "column size is too long, [%s]", string);
+ }
+
+ if (yaf_strpos(tmp, ".") >= 0) {
+ if (strlen(tmp) + 5 >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "column + alias size is too long, [%s]", string);
+ }
+ strreplace(tmp, ".", "`.`");
+ }
+
+ strcpy(table_column, tmp);
+ return table_column;
+}
+
+char* get_join_type(char* type) {
+ if (strcmp(type, "<") == 0) {
+ return "LEFT";
+ } else if (strcmp(type, ">") == 0) {
+ return "RIGHT";
+ } else if (strcmp(type, "<>") == 0) {
+ return "FULL";
+ } else if (strcmp(type, "><") == 0) {
+ return "INNER";
+ } else {
+ return "";
+ }
+}
+
+//匹配表和别名
+int preg_join_match(char* key, char* join, char* table, char* alias) {
+ int join_start = -1;
+ int join_end = -1;
+ int table_start = -1;
+ int table_end = -1;
+ int alias_start = -1;
+ int alias_end = -1;
+
+ int key_len = strlen(key);
+
+ join[0] = '\0';
+ table[0] = '\0';
+ alias[0] = '\0';
+
+ if (key_len == 0) {
+ return 0;
+ }
+
+ int i = -1;
+ while (i < key_len) {
+ i++;
+ char c_key = key[i];
+ if ( join_start == -1 && c_key == '[') {
+ join_start = i;
+ }
+
+ if (table_start == -1 && join_start == -1 && c_key != '[' && !yaf_is_space(c_key)) {
+ table_start = i;
+ }
+
+ if (join_end != -1 && table_start == -1 && !yaf_is_space(c_key)) {
+ table_start = i;
+ }
+
+ if ( join_start != -1 && c_key == ']') {
+ join_end = i;
+ }
+
+ if (table_start != -1 && c_key == '(') {
+ table_end = i;
+ }
+
+ if ( alias_start == -1 && c_key == '(') {
+ alias_start = i;
+ }
+
+ if ( alias_end == -1 && c_key == ')') {
+ alias_end = i;
+ }
+ }
+
+ if (alias_start == -1 || alias_end == -1 || alias_start > alias_end) {
+ table_end = key_len;
+ }
+
+ if (table_start != -1 && table_end != -1 && table_end > table_start) {
+ if (table_end - table_start >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "join table size is too long, [%s]", key);
+ }
+
+ memset(table, 0, MAX_TABLE_SIZE);
+ memcpy(table, key + table_start, table_end - table_start);
+ }
+
+ if (alias_start != -1 && alias_end != -1 && alias_end > alias_start) {
+ if (alias_end - alias_start >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "join alias size is too long, [%s]", key);
+ }
+
+ memset(alias, 0, MAX_TABLE_SIZE);
+ memcpy(alias, key + alias_start + 1, alias_end - alias_start - 1);
+ }
+
+ if (join_start != -1 && join_end != -1 && join_start < join_end) {
+ if (join_end - join_start >= MAX_OPERATOR_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "join operator size is too long, [%s]", key);
+ }
+
+ memset(join, 0, MAX_OPERATOR_SIZE);
+ memcpy(join, key + join_start + 1, join_end - join_start - 1);
+ if (!(strcmp(join, ">") == 0 || strcmp(join, "<") == 0 || strcmp(join, "<>") == 0 || strcmp(join, "><") == 0)) {
+ join[0] = '\0';
+ }
+ }
+ return 1;
+}
+
+//匹配表和别名
+int preg_table_match(char* key, char* table, char* alias) {
+ int table_start = -1;
+ int table_end = -1;
+ int alias_start = -1;
+ int alias_end = -1;
+
+ int key_len = strlen(key);
+
+ table[0] = '\0';
+ alias[0] = '\0';
+
+ if (key_len == 0) {
+ return 0;
+ }
+
+ int i = -1;
+ while (i < key_len) {
+ i++;
+ char c_key = key[i];
+ if ( table_start == -1 && !yaf_is_space(c_key)) {
+ table_start = i;
+ }
+
+ if (table_end == -1 && (c_key == '(' || yaf_is_space(c_key))) {
+ table_end = i;
+ }
+
+ if ( alias_start == -1 && c_key == '(') {
+ alias_start = i;
+ }
+
+ if ( alias_end == -1 && c_key == ')') {
+ alias_end = i;
+ }
+ }
+
+ if (alias_start == -1 || alias_end == -1 || alias_start > alias_end) {
+ table_end = key_len;
+ }
+
+ if (table_start != -1 && table_end != -1 && table_end > table_start) {
+ if (table_end - table_start >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "table size is too long, [%s]", key);
+ }
+
+ memset(table, 0, MAX_TABLE_SIZE);
+ memcpy(table, key + table_start, table_end - table_start);
+ }
+
+ if (alias_start != -1 && alias_end != -1 && alias_end > alias_start) {
+ if (alias_end - alias_start >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "alias size is too long, [%s]", key);
+ }
+
+ memset(alias, 0, MAX_TABLE_SIZE);
+ memcpy(alias, key + alias_start + 1, alias_end - alias_start - 1);
+ }
+
+ return 1;
+}
+
+//匹配列名和操作符
+int preg_operator_match(char* key, char* column, char* operator) {
+ int column_start = -1;
+ int column_end = -1;
+ int column_end_is_space = -1;
+ int operator_start = -1;
+ int operator_end = -1;
+
+ int key_len = strlen(key);
+
+ column[0] = '\0';
+ operator[0] = '\0';
+
+ if (key_len == 0) {
+ return 0;
+ }
+
+ int i = -1;
+ while (i < key_len) {
+ i++;
+ char c_key = key[i];
+ if ( column_start == -1 && !yaf_is_space(c_key)) {
+ column_start = i;
+ }
+
+ if (column_end == -1 && (c_key == '[' || yaf_is_space(c_key))) {
+ column_end = i;
+ }
+
+ if (column_end_is_space == -1 && yaf_is_space(c_key)) {
+ column_end_is_space = i;
+ }
+
+ if ( operator_start == -1 && c_key == '[') {
+ operator_start = i;
+ }
+
+ if ( operator_end == -1 && c_key == ']') {
+ operator_end = i;
+ }
+ }
+
+ if (operator_start == -1 || operator_end == -1 || operator_start > operator_end) {
+ column_end = column_end_is_space == -1 ? key_len : column_end_is_space;
+ }
+
+ if (column_start != -1 && column_end != -1 && column_end > column_start) {
+ if (column_end - column_start - 1 >= MAX_TABLE_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "column size is too long [%s]", key);
+ }
+
+ memset(column, 0, MAX_TABLE_SIZE);
+ memcpy(column, key + column_start, column_end - column_start);
+ }
+
+ if (operator_start != -1 && operator_end != -1 && operator_start < operator_end) {
+ if (operator_end - operator_start - 1 >= MAX_OPERATOR_SIZE) {
+ yaf_php_fatal_error(E_ERROR, "operator size is too long [%s]", key);
+ }
+
+ memset(operator, 0, MAX_OPERATOR_SIZE);
+ memcpy(operator, key + operator_start + 1, operator_end - operator_start - 1);
+ if (!(strcmp(operator, ">") == 0 || strcmp(operator, ">=") == 0 || strcmp(operator, "<") == 0 || strcmp(operator, "<=") == 0 ||
+ strcmp(operator, "!") == 0 || strcmp(operator, "~") == 0 || strcmp(operator, "!~") == 0 || strcmp(operator, "<>") == 0 || strcmp(operator, "><") == 0)) {
+ operator[0] = '\0';
+ }
+ }
+
+ return 1;
+}
+
+//匹配是否 AND 或者 OR
+int preg_and_or_match(char* key, char* relation) {
+ int relation_start = -1;
+ int relation_end = -1;
+
+ relation[0] = '\0';
+
+ int key_len = strlen(key);
+ if (key_len == 0) {
+ return 0;
+ }
+
+ int i = -1;
+ while (i < key_len) {
+ i++;
+ char c_key = key[i];
+
+ if ( relation_start == -1 && !yaf_is_space(c_key)) {
+ relation_start = i;
+ }
+
+ if (relation_end == -1 && ( c_key == '#' || yaf_is_space(c_key))) {
+ relation_end = i;
+ }
+
+ if (relation_end == -1 && i == key_len - 1) {
+ relation_end = key_len;
+ }
+ }
+
+ if (relation_start != -1 && relation_end != -1 && relation_end > relation_start && relation_end - relation_start - 1 < MAX_OPERATOR_SIZE) {
+ memset(relation, 0, MAX_OPERATOR_SIZE);
+ memcpy(relation, key + relation_start, relation_end - relation_start);
+ if (strcmp(relation, "AND") != 0 && strcmp(relation, "OR") != 0 && strcmp(relation, "and") != 0 && strcmp(relation, "or") != 0 ) {
+ relation[0] = '\0';
+ }
+ }
+
+ return 1;
+}
+
+zend_class_entry* get_pdo_ce() {
+ zend_class_entry* ce;
+ zend_string* pdo_class_name = zend_string_init("PDO", strlen("PDO"), 0);
+ ce = zend_fetch_class(pdo_class_name, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
+ zend_string_free(pdo_class_name);
+ return ce;
+}
+
+void update_error_info(zval* obj, char* code, char* errmsg) {
+ zend_update_property_string(yaf_db_ce_ptr, obj, ZEND_STRL("errcode"), code TSRMLS_CC);
+ zval* errorinfo = yaf_read_init_property(yaf_db_ce_ptr, obj, ZEND_STRL("errinfo") TSRMLS_CC);
+
+ if (errorinfo != NULL) {
+ zend_update_property_null(yaf_db_ce_ptr, obj, ZEND_STRL("errinfo"));
+ }
+
+ zval* error_array;
+ YAF_MAKE_STD_ZVAL(error_array);
+ array_init(error_array);
+
+ add_index_string(error_array, 0, code);
+ if (strcmp(code, "00000") == 0) {
+ add_index_long(error_array, 1, 0);
+ } else {
+ add_index_long(error_array, 1, -1);
+ }
+ add_index_string(error_array, 2, errmsg);
+
+ zend_update_property(yaf_db_ce_ptr, obj, ZEND_STRL("errinfo"), error_array TSRMLS_CC);
+ yaf_zval_ptr_dtor(&error_array);
+}
+
+void update_pdo_error(zval* obj, zval* errorcode, zval* errorinfo) {
+ zend_update_property(yaf_db_ce_ptr, obj, ZEND_STRL("errcode"), errorcode TSRMLS_CC);
+ zend_update_property(yaf_db_ce_ptr, obj, ZEND_STRL("errinfo"), errorinfo TSRMLS_CC);
+}
+
+int is_write_type(char* sql) {
+ char *start = sql;
+ int sql_len = strlen(sql);
+ int i=0, len=0;
+ char operator[10] = {0};
+
+ while (i < sql_len) {
+ i++;
+ if (!isspace(*start) && (*start) != '\n' && (*start) != '\r' && (*start) != '\t') {
+ break;
+ }
+ start++;
+ }
+
+ char* end = start;
+
+ while (i < sql_len && len < 8) {
+ if (isspace(*end) || (*end) == '\n' || (*end) == '\r' || (*end) == '\t') {
+ break;
+ }
+
+ end++;
+ i++;
+ len++;
+ }
+
+ memcpy(operator, start, len + 1);
+ rtrim(operator);
+ php_strtoupper(operator, strlen(operator));
+
+ if (strcmp(operator, "INSERT") == 0 || strcmp(operator, "UPDATE") == 0 || strcmp(operator, "DELETE") == 0 || strcmp(operator, "REPLACE") == 0
+ || strcmp(operator, "SET") == 0 || strcmp(operator, "CREATE") == 0 || strcmp(operator, "DROP") == 0 || strcmp(operator, "TRUNCATE") == 0
+ || strcmp(operator, "ALTER") == 0 || strcmp(operator, "LOCK") == 0 || strcmp(operator, "UNLOCK") == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int is_insert(char* sql) {
+ char *start = sql;
+ int sql_len = strlen(sql);
+ int i=0, len=0;
+ char operator[10] = {0};
+
+ while (i < sql_len) {
+ i++;
+ if (!isspace(*start) && (*start) != '\n' && (*start) != '\r' && (*start) != '\t') {
+ break;
+ }
+ start++;
+ }
+
+ char* end = start;
+
+ while (i < sql_len && len < 8) {
+ if (isspace(*end) || (*end) == '\n' || (*end) == '\r' || (*end) == '\t') {
+ break;
+ }
+
+ end++;
+ i++;
+ len++;
+ }
+
+ memcpy(operator, start, len + 1);
+ rtrim(operator);
+ php_strtoupper(operator, strlen(operator));
+
+ if (strcmp(operator, "INSERT") == 0 || strcmp(operator, "REPLACE") == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//根据数组下标从数组中获取字符串
+char* yaf_get_string_from_array_index(zval *array, ulong index)
+{
+ zval *pData = NULL;
+
+ yaf_zend_hash_index_find(Z_ARRVAL_P(array), index, (void**) &pData);
+
+ if(pData == NULL){
+ return NULL;
+ }
+
+ if(Z_TYPE_P(pData) != IS_STRING) {
+ return NULL;
+ }
+
+ char * str = Z_STRVAL_P(pData);
+ return str;
+}
+
+//获取数组的 array_keys ,注意不用了销毁返回的HashTable指针指向的内存地址
+HashTable* yaf_get_array_keys(zval *p) {
+ if(YAF_IS_NOT_ARRAY(p)) {
+ return NULL;
+ }
+
+ uint32_t array_size = zend_hash_num_elements(Z_ARRVAL_P(p));
+ if(array_size == 0) {
+ return NULL;
+ }
+
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+ ulong_t num = 0;
+
+ HashTable *new_hash;
+ ALLOC_HASHTABLE(new_hash);
+ zend_hash_init(new_hash, array_size, NULL, ZVAL_PTR_DTOR, 0);
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(p), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) { //非字符串
+ continue;
+ }
+
+ zval *zval_key;
+ YAF_MAKE_STD_ZVAL(zval_key);
+ YAF_ZVAL_STRING(zval_key, key, 1);
+ yaf_zend_hash_index_update(new_hash, num, (void*) zval_key, sizeof(zval *), NULL);
+ yaf_zval_ptr_dtor(&zval_key);
+ num++;
+ YAF_HASHTABLE_FOREACH_END();
+
+ if(zend_hash_num_elements(new_hash) == 0) {
+ yaf_free_hash(new_hash);
+ new_hash = NULL;
+ }
+
+ return new_hash;
+}
+
+//获取数组的第N个key
+char* yaf_get_array_key_index(zval *p, uint32_t index) {
+ if(YAF_IS_NOT_ARRAY(p)) {
+ return NULL;
+ }
+
+ uint32_t array_size = zend_hash_num_elements(Z_ARRVAL_P(p));
+ if(array_size < index) {
+ return NULL;
+ }
+
+ char * key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+ ulong_t num = 0;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(p), key, key_len, key_type, value)
+ if (HASH_KEY_IS_STRING != key_type) { //非字符串
+ continue;
+ }
+
+ if(num == index) {
+ return key;
+ }
+
+ num++;
+ YAF_HASHTABLE_FOREACH_END();
+ return NULL;
+}
+
+//根据 index 获取 hashtable 的元素
+zval* yaf_get_element_by_hashtable_index(HashTable *ht, int index) {
+ if(ht == NULL) {
+ return NULL;
+ }
+ zval *value;
+ yaf_zend_hash_index_find(ht, index, (void**) &value);
+ return value;
+}
+
+//根据 key 获取 hashtable 的元素
+zval* php_yaf_array_get_value(HashTable *ht, char *key) {
+ zval *v;
+ if( yaf_zend_hash_find(ht, key, strlen(key), (void **) &v) == SUCCESS ) {
+ if(ZVAL_IS_NULL(v)) {
+ return NULL;
+ } else {
+ return v;
+ }
+ } else {
+ return NULL;
+ }
+}
+
+//销毁 HashTable, 删除HashTable的数据, 并销毁释放 HashTable 内存
+void yaf_destroy_hash(HashTable *ht) {
+ uint32_t array_size = zend_hash_num_elements(ht);
+ if(array_size == 0) {
+ zend_hash_destroy(ht);
+ FREE_HASHTABLE(ht);
+ return;
+ }
+
+ char *key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(ht, key, key_len, key_type, value)
+ if(YAF_IS_ARRAY(value)) {
+ yaf_destroy_hash(Z_ARRVAL_P(value));
+ }
+
+ yaf_zval_ptr_dtor(&value);
+ YAF_HASHTABLE_FOREACH_END();
+
+ zend_hash_destroy(ht);
+ FREE_HASHTABLE(ht);
+}
+
+//销毁数组, 删除其中HashTable的数据, 并销毁释放 HashTable 内存,并销毁数组内存,将数组指针置为NULL
+void yaf_destroy_array(zval **array) {
+ yaf_destroy_hash(Z_ARRVAL_P(*array));
+ yaf_zval_ptr_dtor(array);
+ *array = NULL;
+}
+
+//清理 HashTable 内的数据元素。
+void yaf_clean_hash(HashTable *ht) {
+ uint32_t array_size = zend_hash_num_elements(ht);
+ if(array_size == 0) {
+ return;
+ }
+
+ char *key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(ht, key, key_len, key_type, value)
+ if(YAF_IS_ARRAY(value)) {
+ yaf_clean_hash(Z_ARRVAL_P(value));
+ }
+ yaf_zval_ptr_dtor(&value);
+ YAF_HASHTABLE_FOREACH_END();
+}
+
+int is_set_array_index(HashTable *ht, int index) {
+ zval* p = yaf_get_element_by_hashtable_index(ht, index);
+ if(YAF_IS_NOT_EMPTY(p)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+char* yaf_get_string_from_hashtable_index(HashTable *ht, int index) {
+ zval* val = yaf_get_element_by_hashtable_index(ht, index);
+ if(YAF_IS_EMPTY(val)) {
+ return NULL;
+ }
+
+ if(Z_TYPE_P(val) == IS_STRING) {
+ return Z_STRVAL_P(val);
+ } else {
+ return NULL;
+ }
+}
+
+char* yaf_get_string_from_hashtable(HashTable *ht, char* key) {
+ zval* val = php_yaf_array_get_value(ht, key);
+ if(YAF_IS_EMPTY(val)) {
+ return NULL;
+ }
+
+ if(Z_TYPE_P(val) == IS_STRING) {
+ return Z_STRVAL_P(val);
+ } else {
+ return NULL;
+ }
+}
+
+//php implode 功能
+char* yaf_implode(zval *arr, const char *delim_str, char** result)
+{
+ zval *return_value = NULL;
+ YAF_MAKE_STD_ZVAL(return_value);
+ zend_string *delim = zend_string_init(delim_str, strlen(delim_str), 0);
+
+ php_implode(delim, arr, return_value);
+
+ yaf_multi_memcpy_auto_realloc(result, 1, Z_STRVAL_P(return_value));
+
+ efree(delim);
+ yaf_zval_ptr_dtor(&return_value);
+
+ return *result;
+}
+
+//单元素数组重组
+void yaf_array_single_columns(zval** return_single_column_result, zval* data) {
+ array_init(*return_single_column_result);
+
+ char *key;
+ zval *value;
+ uint32_t key_len;
+ int key_type;
+
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(data), key, key_len, key_type, value)
+ char *key2;
+ zval *value2;
+ uint32_t key_len2;
+ int key_type2;
+ YAF_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(value), key2, key_len2, key_type2, value2)
+ zval *copy = yaf_zval_copy(value2);
+ add_next_index_zval(*return_single_column_result, copy);
+ break;
+ YAF_HASHTABLE_FOREACH_END();
+ YAF_HASHTABLE_FOREACH_END();
+}
+
+
+char* yaf_multi_memcpy(char* source, int n_value, ...) {
+ va_list var_arg;
+ int count=0;
+ va_start(var_arg, n_value);
+ while(count < n_value) {
+ char *tmp = va_arg(var_arg, char*);
+ memcpy(source + strlen(source), tmp, strlen(tmp));
+ count++;
+ }
+ va_end(var_arg);
+ return source;
+}
+
+static yaf_inline size_t get_string_emalloc_size(char* source) {
+ size_t source_size = 0;
+ memcpy(&source_size, source - 4, sizeof(size_t));
+ return source_size;
+}
+
+char* yaf_multi_memcpy_auto_realloc(char** source, int n_value, ...) {
+ int source_size = get_string_emalloc_size(*source);
+
+ va_list var_arg;
+ int count = 0;
+ int dest_len = strlen(*source) + 1;
+ va_start(var_arg, n_value);
+ while(count < n_value) {
+ char *tmp = va_arg(var_arg, char*);
+ dest_len += strlen(tmp);
+ count++;
+ }
+ va_end(var_arg);
+
+ //need realloc
+ char* dest = NULL;
+ if(source_size < MM_REAL_SIZE(dest_len)) {
+ yaf_string_emalloc_32(&dest, dest_len);
+ memcpy(dest, *source, strlen(*source));
+ yaf_string_efree_32(*source);
+ *source = dest;
+ } else {
+ dest = *source;
+ }
+
+ count=0;
+ va_start(var_arg, n_value);
+ while(count < n_value) {
+ char *tmp = va_arg(var_arg, char*);
+ memcpy(dest + strlen(dest), tmp, strlen(tmp));
+ count++;
+ }
+ va_end(var_arg);
+
+ //php_printf("====yaf_multi_memcpy_auto_alloc : source_size=[%d], dest_size=[%d], dest_size=[%d], \ndest_point=[%x] dest=[%s]\n", source_size, dest_len, MM_REAL_SIZE(dest_len), dest, dest);
+ return dest;
+}
+
+
+php_stream* unix_socket_conn(char *servername)
+{
+ char host[1024] = {0};
+ int host_len, err = 0;
+
+#if (PHP_MAJOR_VERSION < 7)
+ char *estr = NULL;
+#else
+ zend_string *estr = NULL;
+#endif
+ host_len = snprintf(host, sizeof(host), "unix://%s", servername);
+
+ //超时时间
+ struct timeval tv, read_tv;
+ tv.tv_sec = (time_t) 1; //连接超时
+ tv.tv_usec = (int) 0;
+
+ read_tv.tv_sec = (time_t) 5; //读取超时
+ read_tv.tv_usec = (int) 0;
+
+ php_stream *stream = php_stream_xport_create(host, host_len, STREAM_OPEN_PERSISTENT | STREAM_LOCATE_WRAPPERS_ONLY, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT_ASYNC, NULL, &tv, NULL, &estr, &err);
+
+ if (!stream) {
+ return NULL;
+ }
+
+ php_stream_auto_cleanup(stream);
+ php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &read_tv);
+ php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
+ php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
+
+ return stream;
+}
+
+
+int yaf_compare_strict_bool(zval *op1, zend_bool op2 TSRMLS_DC) {
+
+ int bool_result;
+ if(op1 == NULL) {
+ return 0 == op2;
+ }
+
+ switch (Z_TYPE_P(op1)) {
+ case IS_LONG:
+ return (Z_LVAL_P(op1) ? 1 : 0) == op2;
+ case IS_DOUBLE:
+ return (Z_DVAL_P(op1) ? 1 : 0) == op2;
+ case IS_NULL:
+ return 0 == op2;
+#if PHP_MAJOR_VERSION < 7
+ case IS_BOOL:
+ if (Z_BVAL_P(op1)) {
+ return 1 == op2;
+ } else {
+ return 0 == op2;
+ }
+#else
+ case IS_TRUE:
+ return 1 == op2;
+ case IS_FALSE:
+ return 0 == op2;
+#endif
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+
+//字符串复制
+#if defined(YAF_USE_JEMALLOC) || defined(YAF_USE_TCMALLOC)
+yaf_inline char* yaf_strdup(const char *s)
+{
+ size_t l = strlen(s) + 1;
+ char *p = yaf_malloc(l);
+ memcpy(p, s, l);
+ return p;
+}
+yaf_inline char* yaf_strndup(const char *s, size_t n)
+{
+ char *p = yaf_malloc(n + 1);
+ strncpy(p, s, n);
+ p[n] = '\0';
+ return p;
+}
+#endif
+
+//preg_match函数
+zval* yaf_preg_match(const char* regex_str, char* subject_str)
+{
+ //return NULL;
+ zval retval;
+ zval* matches;
+
+ if(regex_str == NULL || subject_str == NULL) {
+ return NULL;
+ }
+
+ pcre_cache_entry *pce;
+ zend_string *regex = zend_string_init(regex_str, strlen(regex_str), 0);
+ pce = pcre_get_compiled_regex_cache(regex);
+ zend_string_free(regex);
+
+ if (pce == NULL) {
+ return NULL;
+ }
+
+ YAF_ALLOC_INIT_ZVAL(matches);
+ ZVAL_NULL(matches);
+
+ //执行正则
+ php_pcre_match_impl(pce, subject_str, strlen(subject_str), &retval, matches, 0, 0, Z_L(0), Z_L(0));
+
+ if(Z_TYPE(retval) == IS_FALSE) {
+ return NULL;
+ } else {
+ return matches;
+ }
+}
+
+//找到 needle 在 haystack 中的位置, 找到则 >= 0,否则为 -1
+int yaf_strpos(const char* haystack,const char* needle)
+{
+ int ignorecase = 0;
+ register unsigned char c, needc;
+ unsigned char const *from, *end;
+ int len = strlen(haystack);
+ int needlen = strlen(needle);
+ from = (unsigned char *)haystack;
+ end = (unsigned char *)haystack + len;
+ const char *findreset = needle;
+
+ int i = 0;
+
+ while (from < end) {
+ c = *from++;
+ needc = *needle;
+ if (ignorecase) {
+ if (c >= 65 && c < 97)
+ c += 32;
+ if (needc >= 65 && needc < 97)
+ needc += 32;
+ }
+ if(c == needc) {
+ ++needle;
+ if(*needle == '\0') {
+ if (len == needlen)
+ return 0;
+ else
+ return i - needlen+1;
+ }
+ }
+ else {
+ if(*needle == '\0' && needlen > 0)
+ return i - needlen +1;
+ needle = findreset;
+ }
+ i++;
+ }
+ return -1;
+}
+
+//去除尾部空格
+char *rtrim(char *str)
+{
+ if (str == NULL || *str == '\0') {
+ return str;
+ }
+
+ int len = strlen(str);
+ char *p = str + len - 1;
+ while (p >= str && (isspace(*p) || (*p) == '\n' || (*p) == '\r' || (*p) == '\t')) {
+ *p = '\0';
+ --p;
+ }
+ return str;
+}
+
+//去除首部空格
+char *ltrim(char *str)
+{
+ if (str == NULL || *str == '\0') {
+ return str;
+ }
+
+ int len = 0;
+ char *p = str;
+ while (*p != '\0' && (isspace(*p) || (*p) == '\n' || (*p) == '\r' || (*p) == '\t')) {
+ ++p;
+ ++len;
+ }
+
+ memmove(str, p, strlen(str) - len + 1);
+
+ return str;
+}
+
+//去除首尾空格
+char *trim(char *str)
+{
+ str = rtrim(str);
+ str = ltrim(str);
+ return str;
+}
+
+//去除尾部字符串
+char* rtrim_str(char *str, char *remove)
+{
+ if (str == NULL || *str == '\0') {
+ return str;
+ }
+
+ int len = strlen(str);
+ int r_len = strlen(remove);
+
+ if(r_len > len) {
+ return str;
+ }
+
+ char *end = str + len - 1;
+ char *r_end = remove + r_len - 1;
+
+ int remove_flag = 1;
+
+ while (end >= str && r_end >= remove) {
+ if((*r_end) == (*end)) {
+ --r_end;
+ --end;
+ } else {
+ remove_flag = 0;
+ break;
+ }
+ }
+
+ if (remove_flag){
+ char *end = str + len - 1;
+ char *r_end = remove + r_len - 1;
+ while (end >= str && r_end >= remove) {
+ if((*r_end) == (*end)) {
+ *end = '\0';
+ --r_end;
+ --end;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return str;
+}
+
+//去除头部字符串
+char *ltrim_str(char *str, char *remove){
+ if (str == NULL || *str == '\0') {
+ return str;
+ }
+
+ int len = strlen(str);
+ int r_len = strlen(remove);
+
+ if(r_len > len) {
+ return str;
+ }
+
+ char *end = str + len - 1;
+ char *r_end = remove + r_len - 1;
+
+ char *start = str;
+ char *r_start = remove;
+
+ int remove_flag = 1;
+ while (start <= end && r_start <= r_end) {
+ if((*start) == (*r_start)) {
+ ++r_start;
+ ++start;
+ } else {
+ remove_flag = 0;
+ break;
+ }
+ }
+
+ if(remove_flag) {
+ memmove(str, start, len - r_len);
+ str[len - r_len] = '\0';
+ }
+
+ return str;
+}
+
+char* yaf_itoa(long num, char* str) {
+ int radix = 10; //十进制
+ memset(str, 0, MAP_ITOA_INT_SIZE);
+ char index[]="0123456789ABCDEF";
+ unsigned long unum;
+ int i=0,j,k;
+ if (radix==10&&num<0) {
+ unum=(unsigned long)-num;
+ str[i++]='-';
+ } else unum=(unsigned long)num;
+ do {
+ str[i++]=index[unum%(unsigned long)radix];
+ unum/=radix;
+ } while (unum);
+ str[i]='\0';
+ if (str[0]=='-')k=1;
+ else k=0;
+ char temp;
+ for (j=k;j<=(i-1)/2;j++) {
+ temp=str[j];
+ str[j]=str[i-1+k-j];
+ str[i-1+k-j]=temp;
+ }
+ return str;
+}
+
+char* strreplace(char* original, char const * const pattern, char const * const replacement)
+{
+ size_t const replen = strlen(replacement);
+ size_t const patlen = strlen(pattern);
+ size_t const orilen = strlen(original);
+
+ size_t patcnt = 0;
+ const char * oriptr;
+ const char * patloc;
+
+ for (oriptr = original; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen) {
+ patcnt++;
+ }
+ // allocate memory for the new string
+ size_t const retlen = orilen + patcnt * (replen - patlen);
+ char * const returned = (char *) emalloc( sizeof(char) * (retlen + 1) );
+
+ if (returned != NULL) {
+ // copy the original string,
+ // replacing all the instances of the pattern
+ char * retptr = returned;
+ for (oriptr = original; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen) {
+ size_t const skplen = patloc - oriptr;
+ // copy the section until the occurence of the pattern
+ strncpy(retptr, oriptr, skplen);
+ retptr += skplen;
+ // copy the replacement
+ strncpy(retptr, replacement, replen);
+ retptr += replen;
+ }
+ // copy the rest of the string.
+ strcpy(retptr, oriptr);
+ }
+
+ size_t val_len = strlen(returned);
+ strcpy(original, returned);
+ efree(returned);
+ return original;
+}
+
+/**
+ * Serializes php variables without using the PHP userland
+ */
+void yaf_serialize(zval *return_value, zval *var TSRMLS_DC)
+{
+ php_serialize_data_t var_hash;
+ smart_str buf = {0};
+
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+ yaf_php_var_serialize(&buf, var, &var_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+
+ if (EG(exception)) {
+ smart_str_free(&buf);
+ RETURN_FALSE;
+ }
+
+ if (buf.s) {
+ RETURN_STR(buf.s);
+ } else {
+ RETURN_NULL();
+ }
+}
+
+/**
+ * Unserializes php variables without using the PHP userland
+ */
+void yaf_unserialize(zval *return_value, zval *var TSRMLS_DC) {
+
+ const unsigned char *p;
+ php_unserialize_data_t var_hash;
+
+ if (Z_TYPE_P(var) != IS_STRING) {
+ RETURN_FALSE;
+ }
+
+ if (Z_STRLEN_P(var) == 0) {
+ RETURN_FALSE;
+ }
+
+ p = (const unsigned char*) Z_STRVAL_P(var);
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ if (!yaf_php_var_unserialize(&return_value, &p, p + Z_STRLEN_P(var), &var_hash TSRMLS_CC)) {
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ zval_dtor(return_value);
+ ZVAL_NULL(return_value);
+ if (!EG(exception)) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_P(var)), Z_STRLEN_P(var));
+ }
+ RETURN_FALSE;
+ }
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+}
\ No newline at end of file
diff --git a/yaf_db.h b/yaf_db.h
new file mode 100644
index 00000000..ece24806
--- /dev/null
+++ b/yaf_db.h
@@ -0,0 +1,799 @@
+/*
+ +----------------------------------------------------------------------+
+ | yaf_db / yaf_db |
+ +----------------------------------------------------------------------+
+ | yaf_db is a php database ORM extension for mysql written in c language |
+ +----------------------------------------------------------------------+
+ | LICENSE: https://github.com/caohao0730/yaf_db/blob/master/LICENSE|
+ +----------------------------------------------------------------------+
+ | Author: Cao Hao <649947921@qq.com> |
+ | CreateTime: 2018-11-19 |
+ +----------------------------------------------------------------------+
+*/
+#ifndef YAF_DB_H_
+#define YAF_DB_H_
+
+#include "zend_variables.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef YAF_STATIC_COMPILATION
+#include "php_config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+extern zend_class_entry * yaf_db_ce_ptr;
+
+YAF_STARTUP_FUNCTION(db);
+
+/////////////////////////////// 公共宏定义 //////////////////////////////////
+#ifdef _MSC_VER
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#else
+#include /* uint32_t */
+#endif
+
+#if defined(__GNUC__)
+#if __GNUC__ >= 3
+#define yaf_inline inline __attribute__((always_inline))
+#else
+#define yaf_inline inline
+#endif
+#elif defined(_MSC_VER)
+#define yaf_inline __forceinline
+#else
+#define yaf_inline inline
+#endif
+
+#define YAF_OK 0
+#define YAF_ERR -1
+#define YAF_AGAIN -2
+#define YAF_BUSY -3
+#define YAF_DONE -4
+#define YAF_DECLINED -5
+#define YAF_ABORT -6
+
+#define MAP_ITOA_INT_SIZE 16
+
+#ifndef ulong
+#define ulong unsigned long
+typedef unsigned long ulong_t;
+#endif
+
+//内存分配大小
+#define ALIGNED_SIZE_32 32
+#define MM_ALIGNED_SIZE_16(size) ((size + Z_L(16) - Z_L(1)) & (~(Z_L(16) - Z_L(1)))) //16位内存对齐
+#define MM_ALIGNED_SIZE_32(size) ((size + Z_L(32) - Z_L(1)) & (~(Z_L(32) - Z_L(1)))) //32位内存对齐
+#define MM_REAL_SIZE(len) (MM_ALIGNED_SIZE_32(len + 1 + sizeof(size_t)))
+
+enum yafErrorCode
+{
+ YAF_ERROR_PHP_FATAL_ERROR,
+ YAF_ERROR_PDO_CONNECT,
+ YAF_ERROR_PDO_CHARSET
+};
+
+#define PDO_PARAM_NULL 0
+#define PDO_PARAM_INT 1
+#define PDO_PARAM_STR 2
+#define PDO_PARAM_LOB 3
+#define PDO_PARAM_STMT 4
+#define PDO_PARAM_BOOL 5
+
+#define PDO_FETCH_ASSOC 2
+#define PDO_FETCH_COLUMN 7
+
+#define MAP_KEY_SIZE 16
+#define MAX_TABLE_SIZE 48
+#define MAX_OPERATOR_SIZE 4
+
+//php 7 wrapper
+#if PHP_MAJOR_VERSION < 7
+typedef zend_rsrc_list_entry zend_resource;
+#define YAF_RETURN_STRING RETURN_STRING
+#define YAF_Z_ARRVAL_P Z_ARRVAL_P
+#define IS_TRUE 1
+
+static inline int yaf_zend_hash_find(HashTable *ht, char *k, int len, void **v)
+{
+ zval **tmp = NULL;
+ if (zend_hash_find(ht, k, len, (void **) &tmp) == SUCCESS)
+ {
+ *v = *tmp;
+ return SUCCESS;
+ }
+ else
+ {
+ *v = NULL;
+ return FAILURE;
+ }
+}
+
+#define yaf_zend_hash_index_find zend_hash_index_find
+#define yaf_zend_hash_del zend_hash_del
+#define yaf_zend_hash_update zend_hash_update
+#define YAF_ZVAL_STRINGL ZVAL_STRINGL
+#define YAF_ZEND_FETCH_RESOURCE_NO_RETURN ZEND_FETCH_RESOURCE_NO_RETURN
+#define YAF_ZEND_FETCH_RESOURCE ZEND_FETCH_RESOURCE
+#define YAF_ZEND_REGISTER_RESOURCE ZEND_REGISTER_RESOURCE
+#define YAF_MAKE_STD_ZVAL(p) MAKE_STD_ZVAL(p)
+#define YAF_ALLOC_INIT_ZVAL(p) ALLOC_INIT_ZVAL(p)
+#define YAF_SEPARATE_ZVAL(p)
+#define YAF_ZVAL_STRING ZVAL_STRING
+#define YAF_RETVAL_STRINGL RETVAL_STRINGL
+#define yaf_smart_str smart_str
+#define yaf_php_var_unserialize php_var_unserialize
+#define yaf_zend_is_callable zend_is_callable
+#define yaf_zend_is_callable_ex zend_is_callable_ex
+#define yaf_zend_hash_add zend_hash_add
+#define yaf_zend_hash_index_update zend_hash_index_update
+#define yaf_call_user_function_ex call_user_function_ex
+
+static yaf_inline int yaf_call_user_function_fast(zval *function_name, zend_fcall_info_cache *fci_cache, zval **retval_ptr_ptr, uint32_t param_count, zval ***params TSRMLS_DC)
+{
+ zend_fcall_info fci;
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.object_ptr = NULL;
+ fci.function_name = function_name;
+ fci.retval_ptr_ptr = retval_ptr_ptr;
+ fci.param_count = param_count;
+ fci.params = params;
+ fci.no_separation = 0;
+ fci.symbol_table = NULL;
+
+ return zend_call_function(&fci, fci_cache TSRMLS_CC);
+}
+
+#define yaf_copy_to_stack(a, b)
+#define YAF_DB_GET_TSRMLS TSRMLS_FETCH_FROM_CTX(yaf_thread_ctx ? yaf_thread_ctx : NULL)
+
+#define yaf_add_assoc_string add_assoc_string
+#define yaf_add_assoc_stringl_ex add_assoc_stringl_ex
+#define yaf_add_assoc_stringl add_assoc_stringl
+#define yaf_add_assoc_double_ex add_assoc_double_ex
+#define yaf_add_assoc_long_ex add_assoc_long_ex
+#define yaf_add_next_index_stringl add_next_index_stringl
+
+#define yaf_zval_ptr_dtor zval_ptr_dtor
+#define yaf_zend_hash_copy zend_hash_copy
+#define yaf_zval_add_ref zval_add_ref
+#define yaf_zval_dup(val) (val)
+#define yaf_zval_free(val) (yaf_zval_ptr_dtor(&val))
+#define yaf_zend_hash_exists zend_hash_exists
+#define yaf_php_array_merge(dest,src) php_array_merge(dest,src,1 TSRMLS_CC)
+#define YAF_RETURN_STRINGL RETURN_STRINGL
+#define YAF_RETVAL_STRING RETVAL_STRING
+#define yaf_zend_register_internal_class_ex zend_register_internal_class_ex
+
+#define yaf_zend_call_method_with_0_params zend_call_method_with_0_params
+#define yaf_zend_call_method_with_1_params zend_call_method_with_1_params
+#define yaf_zend_call_method_with_2_params zend_call_method_with_2_params
+
+typedef int zend_size_t;
+
+#define YAF_HASHTABLE_FOREACH_START(ht, entry)\
+ zval **tmp = NULL;\
+ for (zend_hash_internal_pointer_reset(ht);\
+ zend_hash_has_more_elements(ht) == SUCCESS; \
+ zend_hash_move_forward(ht)) {\
+ if (zend_hash_get_current_data(ht, (void**)&tmp) == FAILURE) {\
+ continue;\
+ }\
+ entry = *tmp;
+
+#if defined(HASH_KEY_NON_EXISTANT) && !defined(HASH_KEY_NON_EXISTENT)
+#define HASH_KEY_NON_EXISTENT HASH_KEY_NON_EXISTANT
+#endif
+
+#define YAF_HASHTABLE_FOREACH_START2(ht, k, klen, ktype, entry)\
+ zval **tmp = NULL; ulong_t idx;\
+ for (zend_hash_internal_pointer_reset(ht); \
+ (ktype = zend_hash_get_current_key_ex(ht, &k, &klen, &idx, 0, NULL)) != HASH_KEY_NON_EXISTENT; \
+ zend_hash_move_forward(ht)\
+ ) { \
+ if (zend_hash_get_current_data(ht, (void**)&tmp) == FAILURE) {\
+ continue;\
+ }\
+ entry = *tmp;\
+ klen --;
+
+#define YAF_HASHTABLE_FOREACH_END() }
+#define yaf_zend_read_property zend_read_property
+#define yaf_zend_hash_get_current_key(a,b,c,d) zend_hash_get_current_key_ex(a,b,c,d,0,NULL)
+
+static inline int YAF_Z_TYPE_P(zval *z)
+{
+ if (Z_TYPE_P(z) == IS_BOOL)
+ {
+ if ((uint8_t) Z_BVAL_P(z) == 1)
+ {
+ return IS_TRUE;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return Z_TYPE_P(z);
+ }
+}
+
+#define yaf_php_var_serialize(a,b,c) php_var_serialize(a,&b,c)
+#define yaf_zend_get_executed_filename() zend_get_executed_filename(TSRMLS_C)
+#define IS_TRUE 1
+inline int YAF_Z_TYPE_P(zval *z);
+#define YAF_Z_TYPE_PP(z) YAF_Z_TYPE_P(*z)
+#define YAF_ZVAL_IS_NULL ZVAL_IS_NULL
+
+#else /*--------------------------------- PHP Version 7 --------------------------------------------*/
+#define yaf_php_var_serialize php_var_serialize
+typedef size_t zend_size_t;
+#define ZEND_SET_SYMBOL(ht,str,arr) zval_add_ref(arr); zend_hash_str_update(ht, str, sizeof(str)-1, arr);
+
+static yaf_inline int Z_BVAL_P(zval *v)
+{
+ if (Z_TYPE_P(v) == IS_TRUE)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#define yaf_add_assoc_stringl(__arg, __key, __str, __length, __duplicate) add_assoc_stringl_ex(__arg, __key, strlen(__key), __str, __length)
+static yaf_inline int yaf_add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, char *str, size_t length, int __duplicate)
+{
+ return add_assoc_stringl_ex(arg, key, key_len - 1, str, length);
+}
+
+#define yaf_add_next_index_stringl(arr, str, len, dup) add_next_index_stringl(arr, str, len)
+
+static yaf_inline int yaf_add_assoc_long_ex(zval *arg, const char *key, size_t key_len, long value)
+{
+ return add_assoc_long_ex(arg, key, key_len - 1, value);
+}
+
+static yaf_inline int yaf_add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double value)
+{
+ return add_assoc_double_ex(arg, key, key_len - 1, value);
+}
+
+#define YAF_Z_ARRVAL_P(z) Z_ARRVAL_P(z)->ht
+
+#define YAF_HASHTABLE_FOREACH_START(ht, _val) ZEND_HASH_FOREACH_VAL(ht, _val); {
+#define YAF_HASHTABLE_FOREACH_START2(ht, k, klen, ktype, _val) zend_string *_foreach_key;\
+ ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _foreach_key, _val);\
+ if (!_foreach_key) {k = NULL; klen = 0; ktype = 0;}\
+ else {k = _foreach_key->val, klen=_foreach_key->len; ktype = 1;} {
+
+#define YAF_HASHTABLE_FOREACH_END() } ZEND_HASH_FOREACH_END();
+
+#define Z_ARRVAL_PP(s) Z_ARRVAL_P(*s)
+#define YAF_Z_TYPE_P Z_TYPE_P
+#define YAF_Z_TYPE_PP(s) YAF_Z_TYPE_P(*s)
+#define Z_STRVAL_PP(s) Z_STRVAL_P(*s)
+#define Z_STRLEN_PP(s) Z_STRLEN_P(*s)
+#define Z_LVAL_PP(v) Z_LVAL_P(*v)
+
+#define yaf_zval_add_ref(p) Z_TRY_ADDREF_P(*p)
+#define yaf_zval_ptr_dtor(p) zval_ptr_dtor(*p)
+
+
+#define YAF_PHP_MAX_PARAMS_NUM 20
+
+static yaf_inline int yaf_call_user_function_ex(HashTable *function_table, zval** object_pp, zval *function_name, zval **retval_ptr_ptr, uint32_t param_count, zval ***params, int no_separation, HashTable* ymbol_table TSRMLS_CC)
+{
+ zval real_params[YAF_PHP_MAX_PARAMS_NUM];
+ int i = 0;
+ for (; i < param_count; i++)
+ {
+ real_params[i] = **params[i];
+ }
+
+ zval *object_p = (object_pp == NULL) ? NULL : *object_pp;
+ return call_user_function_ex(function_table, object_p, function_name, *retval_ptr_ptr, param_count, real_params, no_separation, NULL);
+}
+
+static yaf_inline int yaf_call_user_function_fast(zval *function_name, zend_fcall_info_cache *fci_cache, zval **retval_ptr_ptr, uint32_t param_count, zval ***params)
+{
+ zval real_params[YAF_PHP_MAX_PARAMS_NUM];
+ int i = 0;
+ for (; i < param_count; i++)
+ {
+ real_params[i] = **params[i];
+ }
+
+ zval phpng_retval;
+ *retval_ptr_ptr = &phpng_retval;
+
+ zend_fcall_info fci;
+ fci.size = sizeof(fci);
+#if PHP_MINOR_VERSION == 0
+ fci.function_table = EG(function_table);
+ fci.symbol_table = NULL;
+#endif
+ fci.object = NULL;
+ ZVAL_COPY_VALUE(&fci.function_name, function_name);
+ fci.retval = &phpng_retval;
+ fci.param_count = param_count;
+ fci.params = real_params;
+ fci.no_separation = 0;
+
+ return zend_call_function(&fci, fci_cache);
+}
+
+#define YAF_ZVAL_IS_NULL(z) (ZVAL_IS_NULL(z) || Z_TYPE_P(z) == IS_UNDEF)
+#define yaf_php_var_unserialize(rval, p, max, var_hash) php_var_unserialize(*rval, p, max, var_hash)
+#define YAF_MAKE_STD_ZVAL(p) zval _stack_zval_##p; p = &(_stack_zval_##p)
+#define YAF_ALLOC_INIT_ZVAL(p) do{p = (zval *)emalloc(sizeof(zval)); bzero(p, sizeof(zval));}while(0)
+#define YAF_SEPARATE_ZVAL(p) zval _##p;\
+ memcpy(&_##p, p, sizeof(_##p));\
+ p = &_##p
+#define YAF_RETURN_STRINGL(s, l, dup) do{RETVAL_STRINGL(s, l); if (dup == 0) efree(s);}while(0);return
+#define YAF_RETVAL_STRINGL(s, l, dup) do{RETVAL_STRINGL(s, l); if (dup == 0) efree(s);}while(0)
+#define YAF_RETVAL_STRING(s, dup) do{RETVAL_STRING(s); if (dup == 0) efree(s);}while(0)
+
+#define YAF_ZEND_FETCH_RESOURCE_NO_RETURN(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type) \
+ (rsrc = (rsrc_type) zend_fetch_resource(Z_RES_P(*passed_id), resource_type_name, resource_type))
+#define YAF_ZEND_REGISTER_RESOURCE(return_value, result, le_result) ZVAL_RES(return_value,zend_register_resource(result, le_result))
+
+#define YAF_RETURN_STRING(val, duplicate) RETURN_STRING(val)
+#define yaf_add_assoc_string(array, key, value, duplicate) add_assoc_string(array, key, value)
+#define yaf_zend_hash_copy(target,source,pCopyConstructor,tmp,size) zend_hash_copy(target,source,pCopyConstructor)
+#define yaf_php_array_merge php_array_merge
+#define yaf_zend_register_internal_class_ex(entry,parent_ptr,str) zend_register_internal_class_ex(entry,parent_ptr)
+#define yaf_zend_get_executed_filename() zend_get_executed_filename()
+
+#define yaf_zend_call_method_with_0_params(obj, ptr, what, method, retval) \
+ zval __retval;\
+ zend_call_method_with_0_params(*obj, ptr, what, method, &__retval);\
+ if (ZVAL_IS_NULL(&__retval)) *(retval) = NULL;\
+ else *(retval) = &__retval;
+
+#define yaf_zend_call_method_with_1_params(obj, ptr, what, method, retval, v1) \
+ zval __retval;\
+ zend_call_method_with_1_params(*obj, ptr, what, method, &__retval, v1);\
+ if (ZVAL_IS_NULL(&__retval)) *(retval) = NULL;\
+ else *(retval) = &__retval;
+
+#define yaf_zend_call_method_with_2_params(obj, ptr, what, method, retval, v1, v2) \
+ zval __retval;\
+ zend_call_method_with_2_params(*obj, ptr, what, method, &__retval, v1, v2);\
+ if (ZVAL_IS_NULL(&__retval)) *(retval) = NULL;\
+ else *(retval) = &__retval;
+
+#define yaf_get_object_handle(object) Z_OBJ_HANDLE(*object)
+#define YAF_DB_GET_TSRMLS
+#define YAF_ZVAL_STRINGL(z, s, l, dup) ZVAL_STRINGL(z, s, l)
+#define YAF_ZVAL_STRING(z,s,dup) ZVAL_STRING(z,s)
+#define yaf_smart_str smart_string
+#define zend_get_class_entry Z_OBJCE_P
+#define yaf_copy_to_stack(a, b) {zval *__tmp = a;\
+ a = &b;\
+ memcpy(a, __tmp, sizeof(zval));}
+
+static yaf_inline zval* yaf_zval_dup(zval *val)
+{
+ zval *dup;
+ YAF_ALLOC_INIT_ZVAL(dup);
+ memcpy(dup, val, sizeof(zval));
+ return dup;
+}
+
+static yaf_inline void yaf_zval_free(zval *val)
+{
+ yaf_zval_ptr_dtor(&val);
+ efree(val);
+}
+
+static yaf_inline zval* yaf_zend_read_property(zend_class_entry *class_ptr, zval *obj, char *s, int len, int silent)
+{
+ zval rv;
+ return zend_read_property(class_ptr, obj, s, len, silent, &rv);
+}
+
+static yaf_inline int yaf_zend_is_callable(zval *cb, int a, char **name)
+{
+ zend_string *key = NULL;
+ int ret = zend_is_callable(cb, a, &key);
+ char *tmp = estrndup(key->val, key->len);
+ zend_string_release(key);
+ *name = tmp;
+ return ret;
+}
+
+static inline int yaf_zend_is_callable_ex(zval *callable, zval *object, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC)
+{
+ zend_string *key = NULL;
+ int ret = zend_is_callable_ex(callable, NULL, check_flags, &key, fcc, error);
+ char *tmp = estrndup(key->val, key->len);
+ zend_string_release(key);
+ *callable_name = tmp;
+ return ret;
+}
+
+static inline int yaf_zend_hash_del(HashTable *ht, char *k, int len)
+{
+ return zend_hash_str_del(ht, k, len - 1);
+}
+
+static inline int yaf_zend_hash_add(HashTable *ht, char *k, int len, void *pData, int datasize, void **pDest)
+{
+ return zend_hash_str_add(ht, k, len - 1, pData) ? SUCCESS : FAILURE;
+}
+
+static inline int yaf_zend_hash_index_update(HashTable *ht, int key, void *pData, int datasize, void **pDest)
+{
+ return zend_hash_index_update(ht, key, pData) ? SUCCESS : FAILURE;
+}
+
+static inline int yaf_zend_hash_update(HashTable *ht, char *k, int len, zval *val, int size, void *ptr)
+{
+ return zend_hash_str_update(ht, (const char*)k, len -1, val) ? SUCCESS : FAILURE;
+}
+
+static inline int yaf_zend_hash_find(HashTable *ht, char *k, int len, void **v)
+{
+ zval *value = zend_hash_str_find(ht, k, len);
+ if (value == NULL)
+ {
+ return FAILURE;
+ }
+ else
+ {
+ *v = (void *) value;
+ return SUCCESS;
+ }
+}
+
+static inline int yaf_zend_hash_index_find(HashTable *ht, int index, void **pData)
+{
+ *pData = zend_hash_index_find(ht, index);
+ if (*pData == NULL)
+ {
+ return FAILURE;
+ }
+ else
+ {
+ return SUCCESS;
+ }
+}
+
+static inline int yaf_zend_hash_exists(HashTable *ht, char *k, int len)
+{
+ zval *value = zend_hash_str_find(ht, k, len - 1);
+ if (value == NULL)
+ {
+ return FAILURE;
+ }
+ else
+ {
+ return SUCCESS;
+ }
+ }
+
+#endif /* PHP Version */
+
+//函数参数
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_construct_oo, 0, 0, 1)
+ZEND_ARG_ARRAY_INFO(0, options, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_select_oo, 0, 0, 2)
+ZEND_ARG_INFO(0, table)
+ZEND_ARG_INFO(0, join)
+ZEND_ARG_INFO(0, columns)
+ZEND_ARG_INFO(0, where)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_exec_oo, 0, 0, 1)
+ZEND_ARG_INFO(0, query)
+ZEND_ARG_ARRAY_INFO(0, map, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_query_oo, 0, 0, 1)
+ZEND_ARG_INFO(0, query)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_insert_oo, 0, 0, 2)
+ZEND_ARG_INFO(0, table)
+ZEND_ARG_ARRAY_INFO(0, data, 0)
+ZEND_ARG_ARRAY_INFO(0, cache_info, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_replace_oo, 0, 0, 2)
+ZEND_ARG_INFO(0, table)
+ZEND_ARG_ARRAY_INFO(0, data, 0)
+ZEND_ARG_ARRAY_INFO(0, cache_info, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_update_oo, 0, 0, 2)
+ZEND_ARG_INFO(0, table)
+ZEND_ARG_ARRAY_INFO(0, data, 0)
+ZEND_ARG_INFO(0, where)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_yaf_db_delete_oo, 0, 0, 1)
+ZEND_ARG_INFO(0, table)
+ZEND_ARG_INFO(0, where)
+ZEND_END_ARG_INFO()
+
+/////////////////////// 类声明 ///////////////////////
+PHP_METHOD(yaf_db, __construct);
+PHP_METHOD(yaf_db, __destruct);
+PHP_METHOD(yaf_db, select);
+PHP_METHOD(yaf_db, initialize);
+PHP_METHOD(yaf_db, begin);
+PHP_METHOD(yaf_db, commit);
+PHP_METHOD(yaf_db, rollback);
+PHP_METHOD(yaf_db, exec);
+PHP_METHOD(yaf_db, query);
+PHP_METHOD(yaf_db, insert);
+PHP_METHOD(yaf_db, replace);
+PHP_METHOD(yaf_db, insert_id);
+PHP_METHOD(yaf_db, update);
+PHP_METHOD(yaf_db, delete);
+PHP_METHOD(yaf_db, errorCode);
+PHP_METHOD(yaf_db, errorInfo);
+
+//私有函数
+char* select_context(char* table, zval* map, zval* join, zval* columns, zval* where, char** sql, zval** cache_info);
+char* handle_join(zval* join, char* table, char** table_query);
+char* column_quote(char* string, char* table_column);
+char* get_join_type(char* type);
+char* column_push(zval* columns, zval* map, char** column_query);
+char* where_clause(zval* where, zval* map, char** where_query, zval** cache_info);
+char* where_implode(char* key, zval* data, zval* map, char** where_clause, char* connector);
+char* group_by_implode(zval* group, char** group_by_condition);
+char* having_implode(zval* having, zval* map, char** having_condition);
+char* order_implode(zval* order, char** order_condition);
+char* limit_implode(zval* limit, char** limit_condition);
+char* handle_where_not_in(zval* not_in_array, char** where_query, zval* map);
+char* handle_like_array(zval* like_array, char** where_query, char* column, char* operator, zval* map, char* connector);
+char* get_mapkey(char* mapkey);
+char* get_mapkey_like(char* mapkey);
+zval* add_map(zval* map, char* mapkey, zval* value);
+void update_error_info(zval* obj, char* code, char* errmsg);
+void update_pdo_error(zval* obj, zval* errorcode, zval* errorinfo);
+int is_write_type(char* sql);
+int is_insert(char* sql);
+int set_cache(zval* cache_obj, zval* cache_key, zval* cache_expire, zval* cache_value);
+zval* get_cache(zval* cache_obj, zval* cache_key);
+void del_cache(zval* cache_obj, zval* cache_info);
+
+//preg函数
+int preg_join_match(char* key, char* join, char* table, char* alias); //匹配join表
+int preg_operator_match(char* key, char* column, char* operator); //匹配列名和操作符
+int preg_and_or_match(char* key, char* relation); //匹配是否 AND 或者 OR
+int preg_table_match(char* key, char* table, char* alias); //匹配表名和别名
+
+//object函数
+zend_class_entry* get_pdo_ce();
+
+/////////////////////// 基础函数 ///////////////////////
+#define yaf_php_fatal_error(level, fmt_str, ...) php_error_docref(NULL TSRMLS_CC, level, fmt_str, ##__VA_ARGS__)
+static yaf_inline void zval_debug(char* name, zval* p) {
+ php_printf("----------%s----------\n", name);
+ php_debug_zval_dump(p, 1);
+}
+static yaf_inline void string_debug(char* name, char* str) {
+ php_printf("%s:[%s] (string)\n", name, str);
+}
+static yaf_inline void int_debug(char* name, int l) {
+ php_printf("%s:[%d] (int)\n", name, l);
+}
+static yaf_inline void float_debug(char* name, float l) {
+ php_printf("%s:[%f] (float)\n", name, l);
+}
+static yaf_inline void x_debug(char* name, void* l) {
+ php_printf("%s:[%x] (point)\n", name, l);
+}
+static yaf_inline void info_debug(char* name) {
+ php_printf("============%s============\n", name);
+}
+static yaf_inline void term_debug(char* term_info) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, term_info);
+}
+
+//////////////////// memory.c ///////////////////////////
+static yaf_inline void yaf_emalloc_and_init(void **tmp, size_t size) {
+ *tmp = emalloc(size); //分配空间,并初始化为 0
+ memset(*tmp, 0, size);
+}
+
+static yaf_inline zval* yaf_zval_copy(zval * source) {
+ zval *copy;
+ YAF_MAKE_STD_ZVAL(copy);
+ *copy = *source;
+ zval_copy_ctor(copy);
+ return copy;
+}
+
+extern char* yaf_multi_memcpy(char * source, int n_str, ...);
+
+//以32位对齐分配内存
+static yaf_inline void yaf_string_emalloc_32(char **tmp, int len) {
+ size_t real_size = MM_REAL_SIZE(len);
+ *tmp = emalloc(real_size);
+ memset(*tmp, 0, real_size);
+ memcpy(*tmp, &real_size, sizeof(size_t));
+ *tmp = *tmp + sizeof(size_t);
+}
+
+static yaf_inline void yaf_string_efree_32(char *tmp) {
+ efree(tmp - sizeof(size_t));
+}
+
+extern char* yaf_multi_memcpy_auto_realloc(char** source, int n_str, ...); //自动扩容
+
+//////////////////// string.c ///////////////////////////
+#define yaf_is_space(p) (p != '\0' && (isspace(p) || (p) == '\n' || (p) == '\r' || (p) == '\t'))
+#define yaf_is_string_not_empty(p) (p != NULL && p[0] != '\0')
+#define yaf_is_string_empty(p) !yaf_is_string_not_empty(p)
+#define yaf_init_stack_string(p, str) YAF_MAKE_STD_ZVAL(p); YAF_ZVAL_STRING(p, str, 1);
+
+#if defined(YAF_USE_JEMALLOC) || defined(YAF_USE_TCMALLOC)
+extern yaf_inline char* yaf_strdup(const char *s);
+extern yaf_inline char* yaf_strndup(const char *s, size_t n);
+#else
+#define yaf_strdup strdup
+#define yaf_strndup strndup
+#endif
+
+extern zval* yaf_preg_match(const char* regex_str, char* subject_str);
+extern int yaf_strpos(const char *haystack,const char *needle);
+extern char* rtrim(char *str);
+extern char* ltrim(char *str);
+extern char* trim(char *str);
+extern char* ltrim_str(char *str, char *remove);
+extern char* rtrim_str(char *str, char *remove);
+extern char* yaf_itoa(long num,char* str);
+extern char* yaf_escape(char* sql);
+extern char* strreplace(char* original, char const * const pattern, char const * const replacement);
+extern void yaf_serialize(zval *return_value, zval *var TSRMLS_DC);
+extern void yaf_unserialize(zval *return_value, zval *var TSRMLS_DC);
+
+/////////////////// array.c ////////////////////////////
+extern char* yaf_get_string_from_array_index(zval *array, ulong index);
+extern HashTable* yaf_get_array_keys(zval* p);
+extern char* yaf_get_array_key_index(zval* p, uint32_t index);
+extern zval * yaf_get_element_by_hashtable_index(HashTable *ht, int index);
+extern zval * php_yaf_array_get_value(HashTable *ht, char *key);
+static yaf_inline void yaf_free_hash(HashTable *ht) {
+ zend_hash_destroy(ht); //释放hash
+ FREE_HASHTABLE(ht);
+}
+extern void yaf_destroy_hash(HashTable *ht);
+extern void yaf_destroy_array(zval **array);
+extern void yaf_clean_hash(HashTable *ht);
+extern void yaf_clean_array(zval **array);
+extern int is_set_array_index(HashTable *ht, int index); //数组下标 index 是否为空
+extern char* yaf_get_string_from_hashtable_index(HashTable *ht, int index);
+extern char* yaf_get_string_from_hashtable(HashTable *ht, char* key);
+extern char* yaf_implode(zval *arr, const char *delim_str, char** result);
+extern void yaf_array_single_columns(zval** return_single_column_result, zval* data);
+
+/////////////////// operator.c ////////////////////////////
+extern int yaf_compare_strict_bool(zval *op1, zend_bool op2 TSRMLS_DC);
+
+/////////////////// net.c ////////////////////////////
+php_stream* unix_socket_conn(char *servername);
+
+//////////////////// 公共宏定义 /////////////////////
+#define YAF_IS_FALSE(var) yaf_compare_strict_bool(var, 0 TSRMLS_CC)
+#define YAF_IS_TRUE(var) yaf_compare_strict_bool(var, 1 TSRMLS_CC)
+#define YAF_IS_ARRAY(var) (var != NULL && Z_TYPE_P(var) == IS_ARRAY)
+#define YAF_IS_NOT_ARRAY(var) (!YAF_IS_ARRAY(var))
+#define YAF_IS_EMPTY(var) (var == NULL || Z_TYPE_P(var) == IS_NULL || YAF_IS_FALSE(var) || (Z_TYPE_P(var) == IS_STRING && !Z_STRLEN_P(var)) || !zend_is_true(var))
+#define YAF_IS_NOT_EMPTY(var) (!YAF_IS_EMPTY(var))
+#define YAF_IS_NULL(var) (var == NULL || Z_TYPE_P(var) == IS_NULL)
+#define YAF_IS_NOT_NULL(var) (!YAF_IS_NULL(var))
+#define YAF_HASHTABLE_IS_NOT_EMPTY(var) (var != NULL && zend_hash_num_elements(var))
+#define YAF_HASHTABLE_IS_EMPTY(var) (!YAF_HASHTABLE_IS_NOT_EMPTY(var))
+
+/////////////////// object.c ////////////////////////////
+static inline zval* yaf_read_init_property(zend_class_entry *scope, zval *object, char *p, size_t pl TSRMLS_DC) {
+ zval* property = yaf_zend_read_property(scope, object, p, pl, 1 TSRMLS_CC);
+ if (property == NULL) {
+ zend_update_property_null(scope, object, p, pl);
+ return yaf_zend_read_property(scope, object, p, pl, 1 TSRMLS_CC);
+ } else {
+ return property;
+ }
+}
+
+static inline int yaf_call_user_function_ex_fast(zval** object_pp, char* function_name, zval **retval_ptr_ptr, uint32_t param_count, zval ***params) {
+ zval* _function_name;
+
+ YAF_MAKE_STD_ZVAL(_function_name);
+ YAF_ZVAL_STRING(_function_name, function_name, 1);
+
+ if(*retval_ptr_ptr == NULL) YAF_ALLOC_INIT_ZVAL(*retval_ptr_ptr);
+
+ int ret = yaf_call_user_function_ex(EG(function_table), object_pp, _function_name, retval_ptr_ptr, param_count, params, 0, NULL TSRMLS_CC);
+
+ yaf_zval_ptr_dtor(&_function_name);
+
+ return ret;
+}
+
+static yaf_inline int yaf_call_user_function_return_bool_or_unsigned(zval** object_pp, char* function_name, uint32_t param_count, zval ***params) {
+ int result = 0;
+ zval tmp_point;
+ zval* retval = &tmp_point, *_function_name;
+
+ YAF_MAKE_STD_ZVAL(_function_name);
+ YAF_ZVAL_STRING(_function_name, function_name, 1);
+
+ int ret = yaf_call_user_function_ex(EG(function_table), object_pp, _function_name, &retval, param_count, params, 0, NULL TSRMLS_CC);
+ yaf_zval_ptr_dtor(&_function_name);
+ if (ret == FAILURE) {
+ yaf_zval_ptr_dtor(&retval);
+ return FAILURE;
+ }
+
+ //返回 true
+#if PHP_MAJOR_VERSION < 7
+ if (Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval))
+#else
+ if (Z_TYPE_P(retval) == IS_TRUE)
+#endif
+ {
+ result = 1;
+ } else if (Z_TYPE_P(retval) == IS_LONG) { //返回无符号整数
+ result = Z_LVAL_P(retval);
+ }
+
+ yaf_zval_ptr_dtor(&retval);
+ return result;
+}
+
+static yaf_inline int yaf_call_user_function_construct_fast(zval** object_pp, uint32_t param_count, zval ***params) {
+ zval tmp_point;
+ zval *construct_ret = &tmp_point;
+
+ zval* function_name;
+ YAF_MAKE_STD_ZVAL(function_name);
+ YAF_ZVAL_STRING(function_name, "__construct", 1);
+
+ int ret = yaf_call_user_function_ex(EG(function_table), object_pp, function_name, &construct_ret, param_count, params, 0, NULL TSRMLS_CC);
+
+ yaf_zval_ptr_dtor(&function_name);
+
+ yaf_zval_ptr_dtor(&construct_ret);
+ return ret;
+}
+
+//错误处理函数
+#define RETURN_MY_ERROR(errmsg) update_error_info(thisObject, "E0001", errmsg);yaf_php_fatal_error(E_WARNING, errmsg);RETURN_LONG(-1);
+
+#endif