Home  >  Article  >  Backend Development  >  PHP source code ext/mysql extension_PHP tutorial

PHP source code ext/mysql extension_PHP tutorial

WBOY
WBOYOriginal
2016-07-21 15:45:38944browse

I have written an external module extension, and now I am starting to look at the mysql extension in the PHP source code. It can be integrated into PHP, so it should be regarded as a built-in extension.
This extension needs to use some interfaces provided by the mysql database, so mysql needs to be installed and the location of mysql.h needs to be determined.
The location of this extension is generally under PHP-source-code/ext/mysql.
Under Linux, the main files to pay attention to are: config.m4, php_mysql.c, php_mysql_structs.h.
ps: There are tags files in this directory, so you can use the various features of ctags to directly find functions, macro definitions, etc.
ps: After starting mysql under Linux sudo mysql-dir/bin/mysqld_safe &
, there will be two processes running:

Copy code The code is as follows:

root 5297 0.0 0.0 5920 1416 pts/5 S 11:08 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe
mysql 5320 1.4 1.1 202728 23796 pts/5 Sl 11:08 1:47 /usr/local/mysql/libexec/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/var --user=mysql -- pid-file=/usr/local/mysql/var/tj1clnxweb0004.pid --skip-external-locking --port=3306 --socket=/tmp/mysql.sock

--- ------------------------------------------------
Record the reading below first Some details in the process:
1. php_mysql_do_query_general function
The functions mysql_query and mysql_unbuffered_query provided by this extension will ultimately use php_mysql_do_query_general to perform core functions.
First look at the trace mode:
if (MySG(trace_mode)) { .... }
There is configuration in php.ini:
mysql.trace_mode = Off
And if configured is open, then the sentence in the if will be executed, and if the executed sentence is select, explain will be added in front to analyze the performance of the sql sentence.
Then take a look at the difference between mysql_use_result and mysql_store_result:
As you can see, mysql_query uses the mysql_store_result function, while mysql_unbuffered_query uses mysql_use_result.
Refer to the article (http://school.cnd8.com/mysql/jiaocheng/25143_8.htm) and summarize it as follows:
mysql_store_result queries and obtains all result sets, saves them on the client, and prepares them for the client Use, which requires greater memory and performance on the client.
mysql_use_result only queries, but delays getting the results. It is equivalent to maintaining a result set on the service front end.
After calling mysql_store_result and using mysql_fetch_row to obtain the result, the result is obtained directly from the client. If the return value is NULL, there is no result.
When mysql_use_result is called and the result is obtained using mysql_fetch_row, the result is obtained from the service front end. If the result is NULL, the result may be useless or there may be a network connection error or other reasons.
Due to the different maintenance places of the result set, the results of mysql_store_result can provide more processing functions, such as arbitrary seek, get the total number, non-sequential access, etc. The result set of mysql_use_result cannot be used.
In addition, since the result set of mysql_use_result is maintained on the server side, it puts forward a requirement: the client must call mysql_fetch_row for each row in the result set. Otherwise, the remaining records in the result set will become the next query result. part of the set, and an "out of sync" error occurs.
So, why do you still need to use mysql_use_result? Take a look at this situation:
mysql and mysqldump use mysql_store_result by default, but if the --quick option is specified, mysql_use_result is used.
That means mysql_use_result has an advantage in efficiency?
Look at the mysql help manual:
-q, --quick Don't cache result, print it row by row. This may slow
down the server if the output is suspended. Doesn't use
history file.
Mysqldump help manual:
-q, --quick Don't buffer query, dump directly to stdout.
Then I haven’t fully understood why quick corresponds to mysql_use_result. When doing this, first figure out when not to use mysql_use_result. Since the result set of mysql_use_result is maintained on the server side, do not use it if the client program may hang. Don't use it if there are too many operations between rows in the result set. In other words, if the query is completed and the results are not used up immediately and freed, then don't use mysql_use_result.
In order to try the effect, I wrote the following test code:
Copy the code The code is as follows:

$sql = sprintf ("select * from pet;");
$result = mysql_unbuffered_query($sql, $conn);
$rows = mysql_fetch_row($result);
var_dump($rows);
$ sql = sprintf("select * from shop");
$result = mysql_unbuffered_query($sql, $conn);
$rows = mysql_fetch_row($result);
var_dump($rows);

The result of the execution is that the second fetch will not display the first result, but PHP will report a notice:
PHP Notice: mysql_unbuffered_query(): Function called without first fetching all rows from a previous unbuffered query in /home/yicheng/test-all/mysqltest/test.php on line 28
Modify the test code:
Copy the code The code is as follows:

$i = 1000000;
while($i--){
$sql = sprintf("select * from pet;");
$result = mysql_query($sql, $conn);
#$result = mysql_unbuffered_query($sql, $conn);
while($rows = mysql_fetch_row($result)){

}
if ($result) {
mysql_free_result($result);
}
}

The result of using unbuffered:
:!time ./test.php
real 1m10.220s
user 0m17.853s
sys 0m9.541s
Result of using mysql_query:
:!time ./test.php
real 1m11.191s
user 0m19.297s
sys 0m10.133s
It seems that the time difference is not big
2. Some resource-related macro definitions
Copy the code The code is as follows:

#define ZEND_VERIFY_RESOURCE(rsrc)
if (!rsrc) {
RETURN_FALSE;
}
#define ZEND_FETCH_RESOURCE(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type)
rsrc = (rsrc_type) zend_fetch_resource(passed_id TSRMLS_CC, default_id, resource_type_name, NULL, 1, resource_type);
ZEND_VERIFY_RESOURCE(rsrc);
#define ZEND_FETCH_RESOURCE2(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_ type1 , resource_type2)
rsrc = (rsrc_type) zend_fetch_resource(passed_id TSRMLS_CC, default_id, resource_type_name, NULL, 2, resource_type1, resource_type2);
ZEND_VERIFY_RESOURCE(rsrc);
#define ZEND_REGISTER_RESOURCE(rsrc_result, rsrc_point er, rsrc_type)
zend_register_resource(rsrc_result, rsrc_pointer, rsrc_type);
#define ZEND_GET_RESOURCE_TYPE_ID(le_id, le_type_name)
if (le_id == 0) {
le_id = zend_fetch_list_dtor_id(le_type_name);
}

What we return from the mysql_connect function is actually a link id (resource(4) of type (mysql link)), which can be mapped to the corresponding mysql resource through the ZEND_FETCH_RESOURCE and ZEND_FETCH_RESOURCE2 macros. Both macros call the zend_fetch_resource method, so let's take a look at this method.
ZEND_API void *zend_fetch_resource(zval **passed_id TSRMLS_DC, int default_id, char *resource_type_name, int *found_resource_type, int num_resource_types, ...)
For example, call the ZEND_FETCH_RESOURCE2 macro in the mysql_list_dbs function:
ZEND_FETCH_RES OURCE2(mysql , php_mysql_conn *, mysql_link, id, "MySQL-Link", le_link, le_plink);
where mysql saves the returned valid resources, php_mysql_conn * defines the type of returned resources, mysql_link, id correspond to passed_id and default_id respectively ( Because many function calls do not pass in the specific conn, they just use the default value), "MySQL-Link" is the resource_type_name, le_link, le_plink are the... parts of zend_fetch_resource, and they are both static int type values.
As can be seen from zend_fetch_resource, value.lval of resource(4) of type (mysql link) contains long type id. If default_id is -1, then the id passed in by passed_id is used, otherwise default_id is used as the id, and zend_list_find is used to find the corresponding resource.
After looking at a few functions, I realized that this extension is just an encapsulation of the c interface provided by mysql. But the packaging is very standardized and stable!
If you want to know more, you still have to look at the source code of MYSQL. Several important data structures are posted below.
----------------------------------------
Some questions about checking Error may be useful php functions:
Copy code The code is as follows:

error_reporting(E_ALL);
#var_dump( mysql_get_host_info($conn));
#var_dump(mysql_get_proto_info($conn));
#var_dump(mysql_get_server_info($conn));
#var_dump(mysql_stat($conn));
# var_dump(mysql_errno($conn));
#var_dump(mysql_error($conn));
#var_dump(mysql_info($conn));

------ ---------------------------------------------
Some useful structs in MYSQL source code
Copy code The code is as follows:

typedef struct st_mysql
{
NET net; /* Communication parameters */
gptr connector_fd; /* ConnectorFd for SSL */
char *host,*user,*passwd,*unix_socket,*server_version,*host_info,*info;
char *db;
struct charset_info_st *charset;
MYSQL_FIELD *fields;
MEM_ROOT field_alloc;
my_ulonglong affected_rows;
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
my_ulonglong extra_info; /* Not used */
unsigned long thread_id; /* Id for connection in server */
unsigned long packet_length;
unsigned int port;
unsigned long client_flag,server_capabilities;
unsigned int protocol_version;
unsigned int field_count;
unsigned int server_status;
unsigned int server_language;
unsigned int warning_count;
struct st_mysql_options options;
enum mysql_status status;
my_bool free_me; /* If free in mysql_close */
my_bool reconnect; /* set to 1 if automatic reconnect */
/* session-wide random string */
char scramble[SCRAMBLE_LENGTH+1];
/*
Set if this is the original connection, not a master or a slave we have
added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave()
*/
my_bool rpl_pivot;
/*
Pointers to the master, and the next slave connections, points to
itself if lone connection.
*/
struct st_mysql* master, *next_slave;
struct st_mysql* last_used_slave; /* needed for round-robin slave pick */
/* needed for send/read/store/use result to work correctly with replication */
struct st_mysql* last_used_con;
LIST *stmts; /* list of all statements */
const struct st_mysql_methods *methods;
void *thd;
/*
Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag
from mysql_stmt_close if close had to cancel result set of this object.
*/
my_bool *unbuffered_fetch_owner;
#if defined(EMBEDDED_LIBRARY) || defined(EMBEDDED_LIBRARY_COMPATIBLE) || MYSQL_VERSION_ID >= 50100
/* needed for embedded server - no net buffer to store the 'info' */
char *info_buffer;
#endif
} MYSQL;
typedef struct st_mysql_methods
{
my_bool (*read_query_result)(MYSQL *mysql);
my_bool (*advanced_command)(MYSQL *mysql,
enum enum_server_command command,
const char *header,
unsigned long header_length,
const char *arg,
unsigned long arg_length,
my_bool skip_check,
MYSQL_STMT *stmt);
MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
unsigned int fields);
MYSQL_RES * (*use_result)(MYSQL *mysql);
void (*fetch_lengths)(unsigned long *to,
MYSQL_ROW column, unsigned int field_count);
void (*flush_use_result)(MYSQL *mysql);
#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
int (*stmt_execute)(MYSQL_STMT *stmt);
int (*read_binary_rows)(MYSQL_STMT *stmt);
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
void (*free_embedded_thd)(MYSQL *mysql);
const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql);
int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
#endif
} MYSQL_METHODS;

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/320292.htmlTechArticle我写过一个外部模块扩展,现在开始看PHP源码中的mysql扩展,它是可以被集成到PHP内部的,所以应该算是内置的扩展了。 该扩展需要用到...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn