SQL语句的解析和自动分表
解析SQL语句:
GPtrArray* sql_parse(network_mysqld_con* con, GPtrArray* tokens) {
//1. 解析库名和表名
gint db, table;
guint sql_type = get_table_index(tokens, &db, &table);
if (table == -1) return NULL;
//2. 解析列
gchar* table_name = NULL;
if (db == -1) {
table_name = g_strdup_printf("%s.%s",
con->client->default_db->str,
((sql_token*)tokens->pdata[table])->text->str);
} else {
table_name = g_strdup_printf("%s.%s",
((sql_token*)tokens->pdata[db])->text->str,
((sql_token*)tokens->pdata[table])->text->str);
}
db_table_t* dt = g_hash_table_lookup(con->config->dt_table, table_name);
if (dt == NULL) {
g_free(table_name);
return NULL;
}
GArray* columns = get_column_index(tokens, table_name,
dt->column_name, sql_type, table+1);
g_free(table_name);
if (columns->len == 0) {
g_array_free(columns, TRUE);
return NULL;
}
//3. 拼接SQL
GPtrArray* sqls = combine_sql(tokens, table, columns, dt->table_num);
g_array_free(columns, TRUE);
return sqls;
}
解析库名和表名的函数get_table_index,分为三种情况:
a、当为select或delete语句时,则找到下一个token ‘from’,在from后面的字面值token则为库名和表名;
SQL select语法:
SELECT列名称 FROM 表名称
SQL delete语法:
DELETEFROM 表名称 WHERE 列名称 = 值
b、当为update语句时,则从头寻找在token ‘set’之前的字面值token,其为库名和表名;
SQL update语法:
UPDATE表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
c、当为insert或replace语句时,则从头寻找在token ‘value’或‘values’之前的字面值token,其为库名和表名;
SQL insert语法:
INSERTINTO 表名称 VALUES (值1, 值2,....)
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
SQL replace语法:
replaceinto tbl_name(col_name, ...) values(...)
replace into tbl_name(col_name,...) select ...
replace into tbl_name setcol_name=value, ...
guint get_table_index(GPtrArray* tokens, gint* d, gint* t) {
*d = *t = -1;
sql_token** ts = (sql_token**)(tokens->pdata);
guint len = tokens->len;
guint i = 1, j;
while (ts[i]->token_id == TK_COMMENT && ++i < len);
sql_token_id token_id = ts[i]->token_id;
if (token_id == TK_SQL_SELECT || token_id == TK_SQL_DELETE) {
for (; i < len; ++i) {
if (ts[i]->token