/* * Copyright (c) 2006 Teodor Sigaev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "ftsbench.h" typedef struct ftsMY { ftsDB db; MYSQL *conn; int flags; MYSQL_STMT *prepareStmt; StringBuf b; } ftsMY; static void execQuery(ftsDB *adb, char **words, int flags) { ftsMY *db = (ftsMY*)adb; static MYSQL_BIND datain, dataout; static int intout; static my_bool isnull, my_error; static unsigned long length; MYSQL_RES *res; if ( db->prepareStmt == NULL ) { db->prepareStmt = mysql_stmt_init(db->conn); if ( db->prepareStmt == NULL ) fatal("mysql_stmt_init failed: %s\n", mysql_error(db->conn)); #define SEARCH_QUERY "SELECT count(*) FROM ftsbench WHERE MATCH(body) AGAINST ( ? IN BOOLEAN MODE);" if ( mysql_stmt_prepare( db->prepareStmt, SEARCH_QUERY, strlen(SEARCH_QUERY) ) != 0 ) fatal("mysql_stmt_init failed: %s\n", mysql_error(db->conn)); if ( mysql_stmt_param_count(db->prepareStmt) != 1 ) fatal("mysql_stmt_param_count: invalid parameter count\n"); memset(&datain, 0, sizeof(MYSQL_BIND)); datain.buffer_type = MYSQL_TYPE_BLOB; datain.length = (unsigned long*)&(db->b.strlen); memset(&dataout, 0, sizeof(MYSQL_BIND)); dataout.buffer_type= MYSQL_TYPE_LONG; dataout.buffer= (char *)&intout; dataout.is_null= &isnull; dataout.length= &length; dataout.error= &my_error; db->flags = flags; } db->b.strlen = 0; while( *words ) { sb_addchar(&db->b, ' '); if ( db->flags & FLG_AND) sb_addchar(&db->b, '+'); sb_add(&db->b, *words, -1); words++; } datain.buffer = db->b.str; datain.buffer_length = db->b.strlen; if ( mysql_stmt_bind_param(db->prepareStmt, &datain) ) fatal("mysql_stmt_bind_param failed: %s\n", mysql_error(db->conn)); res = mysql_stmt_result_metadata(db->prepareStmt); if ( !res ) fatal("mysql_stmt_result_metadata failed: %s\n", mysql_error(db->conn)); if ( mysql_stmt_execute( db->prepareStmt ) ) fatal("mysql_stmt_execute failed: %s\n", mysql_error(db->conn)); if (mysql_stmt_bind_result( db->prepareStmt, &dataout)) fatal("mysql_stmt_bind_result failed: %s\n", mysql_error(db->conn)); if ( mysql_stmt_store_result( db->prepareStmt ) ) fatal("mysql_stmt_store_result failed: %s\n", mysql_error(db->conn)); if ( !mysql_stmt_fetch( db->prepareStmt) ) { db->db.nres += intout; } else { fatal("mysql_stmt_fetch returns void result\n"); } mysql_free_result(res); pthread_mutex_lock(&(db->db.nqueryMutex)); db->db.nquery ++; pthread_mutex_unlock(&(db->db.nqueryMutex)); } static void startCreateScheme(ftsDB *adb, int flags) { ftsMY *db = (ftsMY*)adb; db->flags = flags; if ( flags & FLG_FUNC ) report("Flag 'func' is ignored by MySQL\n"); if ( flags & (FLG_GIN | FLG_GIST) ) report("MySQL doesn't distinguish 'gin' and 'gist' flags\n"); if ( mysql_query(db->conn, "DROP TABLE IF EXISTS ftsbench CASCADE;")!= 0 ) fatal("mysql_query failed: %s\n", mysql_error(db->conn)); if ( mysql_query(db->conn, "CREATE TABLE ftsbench (id int not null, body text) ENGINE MyISAM;")!= 0 ) fatal("mysql_query failed: %s\n", mysql_error(db->conn)); } static void finishCreateScheme(ftsDB *adb) { ftsMY *db = (ftsMY*)adb; if ( db->flags & (FLG_GIN | FLG_GIST) ) { report("(create index, "); if ( mysql_query(db->conn, "CREATE FULLTEXT INDEX fts ON ftsbench (body);")!= 0 ) fatal("mysql_query failed: %s\n", mysql_error(db->conn)); } else report("("); report("optimize"); if ( mysql_query(db->conn, "OPTIMIZE TABLE ftsbench;")!= 0 ) fatal("mysql_query failed: %s\n", mysql_error(db->conn)); report(") "); } static void InsertRow(ftsDB *adb, int id, char *txt) { ftsMY *db = (ftsMY*)adb; static MYSQL_BIND data[2]; static unsigned long txtlen; if ( db->prepareStmt == NULL ) { db->prepareStmt = mysql_stmt_init(db->conn); if ( db->prepareStmt == NULL ) fatal("mysql_stmt_init failed: %s\n", mysql_error(db->conn)); #define INSERT_QUERY "INSERT INTO ftsbench (id, body) VALUES ( ? , ? );" if ( mysql_stmt_prepare( db->prepareStmt, INSERT_QUERY, strlen(INSERT_QUERY) ) != 0 ) fatal("mysql_stmt_init failed: %s\n", mysql_error(db->conn)); if ( mysql_stmt_param_count(db->prepareStmt) != 2 ) fatal("mysql_stmt_param_count: invalid parameter count\n"); memset(data, 0, sizeof(data)); data[0].buffer_type = MYSQL_TYPE_LONG; data[1].buffer_type = MYSQL_TYPE_BLOB; data[1].length = &txtlen; } data[0].buffer = &id; txtlen = (unsigned long) strlen(txt); data[1].buffer = txt; data[1].buffer_length = txtlen; if ( mysql_stmt_bind_param(db->prepareStmt, data) ) fatal("mysql_stmt_bind_param failed: %s\n", mysql_error(db->conn)); if ( mysql_stmt_execute( db->prepareStmt ) ) fatal("mysql_stmt_execute failed: %s\n", mysql_error(db->conn)); } static void Close(ftsDB* adb) { ftsMY *db = (ftsMY*)adb; mysql_close(db->conn); } ftsDB* MYInit(char * connstr) { ftsMY *db = (ftsMY*)malloc(sizeof(ftsMY)); memset(db,0,sizeof(ftsMY)); db->conn = mysql_init(NULL); if ( !mysql_real_connect(db->conn, NULL, NULL, NULL, connstr, 0, NULL, 0) ) fatal("mysql_real_connect failed: %s\n", mysql_error(db->conn)); db->db.execQuery = execQuery; db->db.startCreateScheme = startCreateScheme; db->db.finishCreateScheme = finishCreateScheme; db->db.InsertRow = InsertRow; db->db.Close = Close; return (ftsDB*)db; }