Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
01673997
Commit
01673997
authored
Feb 01, 2014
by
Sergei Golubchik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sphinxse 2.1.5-release
parent
6c9c8d56
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
2044 additions
and
1075 deletions
+2044
-1075
CMakeLists.txt
CMakeLists.txt
+7
-2
INSTALL
INSTALL
+48
-0
ha_sphinx.cc
ha_sphinx.cc
+753
-297
ha_sphinx.h
ha_sphinx.h
+20
-10
make-patch.sh
make-patch.sh
+0
-0
snippets_udf.cc
snippets_udf.cc
+816
-766
sphinx.5.0.91.diff
sphinx.5.0.91.diff
+400
-0
No files found.
CMakeLists.txt
View file @
01673997
...
...
@@ -7,5 +7,10 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${
CMAKE_SOURCE_DIR
}
/extra/yassl/include
${
CMAKE_SOURCE_DIR
}
/regex
)
SET
(
SPHINX_SOURCES ha_sphinx.cc
)
ADD_LIBRARY
(
sphinx ha_sphinx.cc
)
SET
(
SPHINX_SOURCES ha_sphinx.cc snippets_udf.cc
)
IF
(
MYSQL_VERSION_ID LESS 50515
)
ADD_LIBRARY
(
sphinx ha_sphinx.cc snippets_udf.cc
)
ELSE
()
SET
(
SPHINX_PLUGIN_DYNAMIC
"ha_sphinx"
)
MYSQL_ADD_PLUGIN
(
sphinx
${
SPHINX_SOURCES
}
STORAGE_ENGINE MODULE_ONLY LINK_LIBRARIES mysys
)
ENDIF
()
INSTALL
0 → 100644
View file @
01673997
Building MySQL with SphinxSE
=============================
Note: BUILD/autorun.sh step on Linux might malfunction with some
versions of automake; autorun.sh will not fail but the build will.
automake 1.9.6 is known to work.
MySQL 5.0.x on Linux
---------------------
tar zxvf mysql-5.0.91.tar.gz
cp -R mysqlse mysql-5.0.91/sql/sphinx
cd mysql-5.0.91
patch -p1 -i sql/sphinx/sphinx.5.0.91.diff
sh BUILD/autorun.sh
./configure --with-sphinx-storage-engine
make
MySQL 5.1.x on Linux
---------------------
tar zxvf mysql-5.1.47.tar.gz
cp -R -p mysqlse mysql-5.1.47/storage/sphinx
cd mysql-5.1.47
sh BUILD/autorun.sh
./configure --with-plugins=sphinx
make
MySQL 5.0.x on Windows
-----------------------
tar zxvf mysql-5.0.91.tar.gz
cp -R mysqlse mysql-5.0.91/sql/sphinx
cd mysql-5.0.91
patch -p1 -i sql/sphinx/sphinx.5.0.91.diff
win\configure.js WITH_SPHINX_STORAGE_ENGINE
win\build-vs8
--eof--
ha_sphinx.cc
View file @
01673997
//
// $Id$
// $Id: ha_sphinx.cc 4507 2014-01-22 15:24:34Z deogar $
//
//
// Copyright (c) 2001-2014, Andrew Aksyonoff
// Copyright (c) 2008-2014, Sphinx Technologies Inc
// All rights reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License. You should have
// received a copy of the GPL license along with this program; if you
// did not, you can find it at http://www.gnu.org/
//
#ifdef USE_PRAGMA_IMPLEMENTATION
...
...
@@ -13,7 +24,10 @@
#include <mysql_version.h>
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>=50515
#include "sql_class.h"
#include "sql_array.h"
#elif MYSQL_VERSION_ID>50100
#include "mysql_priv.h"
#include <mysql/plugin.h>
#else
...
...
@@ -22,6 +36,7 @@
#include <mysys_err.h>
#include <my_sys.h>
#include <mysql.h> // include client for INSERT table (sort of redoing federated..)
#ifndef __WIN__
// UNIX-specific
...
...
@@ -107,28 +122,48 @@ void sphUnalignedWrite ( void * pPtr, const T & tVal )
#endif
#if MYSQL_VERSION_ID>=50515
#define sphinx_hash_init my_hash_init
#define sphinx_hash_free my_hash_free
#define sphinx_hash_search my_hash_search
#define sphinx_hash_delete my_hash_delete
#else
#define sphinx_hash_init hash_init
#define sphinx_hash_free hash_free
#define sphinx_hash_search hash_search
#define sphinx_hash_delete hash_delete
#endif
/////////////////////////////////////////////////////////////////////////////
// FIXME! make this all dynamic
#define SPHINXSE_MAX_FILTERS 32
#define SPHINXSE_DEFAULT_HOST "127.0.0.1"
#define SPHINXSE_DEFAULT_PORT 9312
#define SPHINXSE_DEFAULT_INDEX "*"
#define SPHINXAPI_DEFAULT_HOST "127.0.0.1"
#define SPHINXAPI_DEFAULT_PORT 9312
#define SPHINXAPI_DEFAULT_INDEX "*"
#define SPHINXQL_DEFAULT_PORT 9306
#define SPHINXSE_SYSTEM_COLUMNS 3
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
#define SPHINXSE_MAX_KEYWORDSTATS 4096
// FIXME! all the following is cut-n-paste from sphinx.h and searchd.cpp
#define SPHINX_VERSION "0.9.9"
#define SPHINXSE_VERSION "2.1.5-release"
// FIXME? the following is cut-n-paste from sphinx.h and searchd.cpp
// cut-n-paste is somewhat simpler that adding dependencies however..
enum
{
SPHINX_SEARCHD_PROTO
=
1
,
SEARCHD_COMMAND_SEARCH
=
0
,
VER_COMMAND_SEARCH
=
0x11
6
,
VER_COMMAND_SEARCH
=
0x11
9
,
};
/// search query sorting orders
...
...
@@ -168,6 +203,8 @@ enum ESphRankMode
SPH_RANK_PROXIMITY
=
4
,
///< phrase proximity
SPH_RANK_MATCHANY
=
5
,
///< emulate old match-any weighting
SPH_RANK_FIELDMASK
=
6
,
///< sets bits where there were matches
SPH_RANK_SPH04
=
7
,
///< codename SPH04, phrase proximity + bm25 + head/exact boost
SPH_RANK_EXPR
=
8
,
///< expression based ranker
SPH_RANK_TOTAL
,
SPH_RANK_DEFAULT
=
SPH_RANK_PROXIMITY_BM25
...
...
@@ -193,8 +230,10 @@ enum
SPH_ATTR_BOOL
=
4
,
///< this attr is a boolean bit field
SPH_ATTR_FLOAT
=
5
,
SPH_ATTR_BIGINT
=
6
,
SPH_ATTR_STRING
=
7
,
///< string (binary; in-memory)
SPH_ATTR_MULTI
=
0x40000000UL
///< this attr has multiple values (0 or more)
SPH_ATTR_UINT32SET
=
0x40000001UL
,
///< this attr is multiple int32 values (0 or more)
SPH_ATTR_UINT64SET
=
0x40000002UL
///< this attr is multiple int64 values (0 or more)
};
/// known answers
...
...
@@ -249,21 +288,26 @@ inline void SPH_DEBUG ( const char *, ... ) {}
//////////////////////////////////////////////////////////////////////////////
///
a
structure that will be shared among all open Sphinx SE handlers
///
per-table
structure that will be shared among all open Sphinx SE handlers
struct
CSphSEShare
{
pthread_mutex_t
m_tMutex
;
THR_LOCK
m_tLock
;
char
*
m_sTable
;
char
*
m_sScheme
;
char
*
m_sHost
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sSocket
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sIndex
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sScheme
;
///< our connection string
char
*
m_sHost
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sSocket
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sIndex
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
ushort
m_iPort
;
bool
m_bSphinxQL
;
///< is this read-only SphinxAPI table, or write-only SphinxQL table?
uint
m_iTableNameLen
;
uint
m_iUseCount
;
#if MYSQL_VERSION_ID<50610
CHARSET_INFO
*
m_pTableQueryCharset
;
#else
const
CHARSET_INFO
*
m_pTableQueryCharset
;
#endif
int
m_iTableFields
;
char
**
m_sTableField
;
...
...
@@ -276,6 +320,7 @@ struct CSphSEShare
,
m_sSocket
(
NULL
)
,
m_sIndex
(
NULL
)
,
m_iPort
(
0
)
,
m_bSphinxQL
(
false
)
,
m_iTableNameLen
(
0
)
,
m_iUseCount
(
1
)
,
m_pTableQueryCharset
(
NULL
)
...
...
@@ -391,12 +436,26 @@ struct CSphSEThreadData
bool
m_bQuery
;
char
m_sQuery
[
MAX_QUERY_LEN
];
#if MYSQL_VERSION_ID<50610
CHARSET_INFO
*
m_pQueryCharset
;
#else
const
CHARSET_INFO
*
m_pQueryCharset
;
#endif
bool
m_bReplace
;
///< are we doing an INSERT or REPLACE
bool
m_bCondId
;
///< got a value from condition pushdown
longlong
m_iCondId
;
///< value acquired from id=value condition pushdown
bool
m_bCondDone
;
///< index_read() is now over
CSphSEThreadData
()
:
m_bStats
(
false
)
,
m_bQuery
(
false
)
,
m_pQueryCharset
(
NULL
)
,
m_bReplace
(
false
)
,
m_bCondId
(
false
)
,
m_iCondId
(
0
)
,
m_bCondDone
(
false
)
{}
};
...
...
@@ -471,6 +530,7 @@ private:
int
m_iWeights
;
ESphMatchMode
m_eMode
;
ESphRankMode
m_eRanker
;
char
*
m_sRankExpr
;
ESphSortOrder
m_eSort
;
char
*
m_sSortBy
;
int
m_iMaxMatches
;
...
...
@@ -502,6 +562,7 @@ private:
float
m_fGeoLongitude
;
char
*
m_sComment
;
char
*
m_sSelect
;
struct
Override_t
{
...
...
@@ -538,10 +599,10 @@ protected:
bool
ParseField
(
char
*
sField
);
void
SendBytes
(
const
void
*
pBytes
,
int
iBytes
);
void
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
short
int
)
);
}
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
int
)
);
}
void
SendDword
(
uint
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
uint
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
uint
(
v
>>
32
)
);
SendDword
(
uint
(
v
&
0xFFFFFFFFUL
)
);
}
void
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendDword
(
uint
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
(
uint
)(
v
>>
32
)
);
SendDword
(
(
uint
)
(
v
&
0xFFFFFFFFUL
)
);
}
void
SendString
(
const
char
*
v
)
{
int
iLen
=
strlen
(
v
);
SendDword
(
iLen
);
SendBytes
(
v
,
iLen
);
}
void
SendFloat
(
float
v
)
{
SendDword
(
sphF2DW
(
v
)
);
}
};
...
...
@@ -574,7 +635,7 @@ bool sphinx_show_status ( THD * thd );
//////////////////////////////////////////////////////////////////////////////
static
const
char
sphinx_hton_name
[]
=
"SPHINX"
;
static
const
char
sphinx_hton_comment
[]
=
"Sphinx storage engine "
SPHINX_VERSION
;
static
const
char
sphinx_hton_comment
[]
=
"Sphinx storage engine "
SPHINX
SE
_VERSION
;
#if MYSQL_VERSION_ID<50100
handlerton
sphinx_hton
=
...
...
@@ -643,19 +704,19 @@ static int sphinx_init_func ( void * p )
if
(
!
sphinx_init
)
{
sphinx_init
=
1
;
VOID
(
pthread_mutex_init
(
&
sphinx_mutex
,
MY_MUTEX_INIT_FAST
)
);
hash_init
(
&
sphinx_open_tables
,
system_charset_info
,
32
,
0
,
0
,
void
(
pthread_mutex_init
(
&
sphinx_mutex
,
MY_MUTEX_INIT_FAST
)
);
sphinx_
hash_init
(
&
sphinx_open_tables
,
system_charset_info
,
32
,
0
,
0
,
sphinx_get_key
,
0
,
0
);
#if MYSQL_VERSION_ID > 50100
handlerton
*
hton
=
(
handlerton
*
)
p
;
hton
->
state
=
SHOW_OPTION_YES
;
hton
->
db_type
=
DB_TYPE_DEFAULT
;
hton
->
create
=
sphinx_create_handler
;
hton
->
close_connection
=
sphinx_close_connection
;
hton
->
show_status
=
sphinx_show_status
;
hton
->
panic
=
sphinx_panic
;
hton
->
flags
=
HTON_CAN_RECREATE
;
hton
->
state
=
SHOW_OPTION_YES
;
hton
->
db_type
=
DB_TYPE_FIRST_DYNAMIC
;
hton
->
create
=
sphinx_create_handler
;
hton
->
close_connection
=
sphinx_close_connection
;
hton
->
show_status
=
sphinx_show_status
;
hton
->
panic
=
sphinx_panic
;
hton
->
flags
=
HTON_CAN_RECREATE
;
#endif
}
SPH_RET
(
0
);
...
...
@@ -694,7 +755,7 @@ static int sphinx_done_func ( void * )
sphinx_init
=
0
;
if
(
sphinx_open_tables
.
records
)
error
=
1
;
hash_free
(
&
sphinx_open_tables
);
sphinx_
hash_free
(
&
sphinx_open_tables
);
pthread_mutex_destroy
(
&
sphinx_mutex
);
}
...
...
@@ -742,15 +803,22 @@ bool sphinx_show_status ( THD * thd )
char
buf1
[
IO_SIZE
];
uint
buf1len
;
char
buf2
[
IO_SIZE
];
uint
buf2len
=
0
;
uint
buf2len
=
0
;
String
words
;
buf1
[
0
]
=
'\0'
;
buf2
[
0
]
=
'\0'
;
#if MYSQL_VERSION_ID>50100
// 5.1.x style stats
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
(
*
thd_ha_data
(
thd
,
hton
)
);
#define LOC_STATS(_key,_keylen,_val,_vallen) \
stat_print ( thd, sphinx_hton_name, strlen(sphinx_hton_name), _key, _keylen, _val, _vallen );
#else
// 5.0.x style stats
if
(
have_sphinx_db
!=
SHOW_OPTION_YES
)
{
my_message
(
ER_NOT_SUPPORTED_YET
,
...
...
@@ -759,32 +827,33 @@ bool sphinx_show_status ( THD * thd )
SPH_RET
(
TRUE
);
}
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
thd
->
ha_data
[
sphinx_hton
.
slot
];
field_list
.
push_back
(
new
Item_empty_string
(
"Type"
,
10
)
);
field_list
.
push_back
(
new
Item_empty_string
(
"Name"
,
FN_REFLEN
)
);
field_list
.
push_back
(
new
Item_empty_string
(
"Status"
,
10
)
);
if
(
protocol
->
send_fields
(
&
field_list
,
Protocol
::
SEND_NUM_ROWS
|
Protocol
::
SEND_EOF
)
)
SPH_RET
(
TRUE
);
#define LOC_STATS(_key,_keylen,_val,_vallen) \
protocol->prepare_for_resend (); \
protocol->store ( "SPHINX", 6, system_charset_info ); \
protocol->store ( _key, _keylen, system_charset_info ); \
protocol->store ( _val, _vallen, system_charset_info ); \
if ( protocol->write() ) \
SPH_RET(TRUE);
#endif
// show query stats
if
(
pTls
&&
pTls
->
m_bStats
)
{
const
CSphSEStats
*
pStats
=
&
pTls
->
m_tStats
;
buf1len
=
my_snprintf
(
buf1
,
sizeof
(
buf1
),
"total: %d, total found: %d, time: %d, words: %d"
,
"total: %d, total found: %d, time: %d, words: %d"
,
pStats
->
m_iMatchesTotal
,
pStats
->
m_iMatchesFound
,
pStats
->
m_iQueryMsec
,
pStats
->
m_iWords
);
#if MYSQL_VERSION_ID>50100
stat_print
(
thd
,
sphinx_hton_name
,
strlen
(
sphinx_hton_name
),
STRING_WITH_LEN
(
"stats"
),
buf1
,
buf1len
);
#else
field_list
.
push_back
(
new
Item_empty_string
(
"Type"
,
10
)
);
field_list
.
push_back
(
new
Item_empty_string
(
"Name"
,
FN_REFLEN
)
);
field_list
.
push_back
(
new
Item_empty_string
(
"Status"
,
10
)
);
if
(
protocol
->
send_fields
(
&
field_list
,
Protocol
::
SEND_NUM_ROWS
|
Protocol
::
SEND_EOF
)
)
SPH_RET
(
TRUE
);
protocol
->
prepare_for_resend
();
protocol
->
store
(
STRING_WITH_LEN
(
"SPHINX"
),
system_charset_info
);
protocol
->
store
(
STRING_WITH_LEN
(
"stats"
),
system_charset_info
);
protocol
->
store
(
buf1
,
buf1len
,
system_charset_info
);
if
(
protocol
->
write
()
)
SPH_RET
(
TRUE
);
#endif
LOC_STATS
(
"stats"
,
5
,
buf1
,
buf1len
);
if
(
pStats
->
m_iWords
)
{
...
...
@@ -808,58 +877,30 @@ bool sphinx_show_status ( THD * thd )
iWord
=
sBuf3
.
length
();
}
#if MYSQL_VERSION_ID>50100
stat_print
(
thd
,
sphinx_hton_name
,
strlen
(
sphinx_hton_name
),
STRING_WITH_LEN
(
"words"
),
sWord
,
iWord
);
#else
protocol
->
prepare_for_resend
();
protocol
->
store
(
STRING_WITH_LEN
(
"SPHINX"
),
system_charset_info
);
protocol
->
store
(
STRING_WITH_LEN
(
"words"
),
system_charset_info
);
protocol
->
store
(
sWord
,
iWord
,
system_charset_info
);
if
(
protocol
->
write
()
)
SPH_RET
(
TRUE
);
#endif
LOC_STATS
(
"words"
,
5
,
sWord
,
iWord
);
}
}
// send last error or warning
if
(
pStats
->
m_sLastMessage
&&
pStats
->
m_sLastMessage
[
0
]
)
{
const
char
*
sMessageType
=
pStats
->
m_bLastError
?
"error"
:
"warning"
;
// show last error or warning (either in addition to stats, or on their own)
if
(
pTls
&&
pTls
->
m_tStats
.
m_sLastMessage
&&
pTls
->
m_tStats
.
m_sLastMessage
[
0
]
)
{
const
char
*
sMessageType
=
pTls
->
m_tStats
.
m_bLastError
?
"error"
:
"warning"
;
#if MYSQL_VERSION_ID>50100
stat_print
(
thd
,
sphinx_hton_name
,
strlen
(
sphinx_hton_name
),
sMessageType
,
strlen
(
sMessageType
),
pStats
->
m_sLastMessage
,
strlen
(
pStats
->
m_sLastMessage
)
);
#else
protocol
->
prepare_for_resend
();
protocol
->
store
(
STRING_WITH_LEN
(
"SPHINX"
),
system_charset_info
);
protocol
->
store
(
sMessageType
,
strlen
(
sMessageType
),
system_charset_info
);
protocol
->
store
(
pStats
->
m_sLastMessage
,
strlen
(
pStats
->
m_sLastMessage
),
system_charset_info
);
if
(
protocol
->
write
()
)
SPH_RET
(
TRUE
);
#endif
}
LOC_STATS
(
sMessageType
,
strlen
(
sMessageType
),
pTls
->
m_tStats
.
m_sLastMessage
,
strlen
(
pTls
->
m_tStats
.
m_sLastMessage
)
);
}
else
{
#if MYSQL_VERSION_ID < 50100
field_list
.
push_back
(
new
Item_empty_string
(
"Type"
,
10
)
);
field_list
.
push_back
(
new
Item_empty_string
(
"Name"
,
FN_REFLEN
)
);
field_list
.
push_back
(
new
Item_empty_string
(
"Status"
,
10
)
);
if
(
protocol
->
send_fields
(
&
field_list
,
Protocol
::
SEND_NUM_ROWS
|
Protocol
::
SEND_EOF
)
)
SPH_RET
(
TRUE
);
protocol
->
prepare_for_resend
();
protocol
->
store
(
STRING_WITH_LEN
(
"SPHINX"
),
system_charset_info
);
protocol
->
store
(
STRING_WITH_LEN
(
"stats"
),
system_charset_info
);
protocol
->
store
(
STRING_WITH_LEN
(
"no query has been executed yet"
),
system_charset_info
);
if
(
protocol
->
write
()
)
SPH_RET
(
TRUE
);
#endif
// well, nothing to show just yet
#if MYSQL_VERSION_ID < 50100
LOC_STATS
(
"stats"
,
5
,
"no query has been executed yet"
,
sizeof
(
"no query has been executed yet"
)
-
1
);
#endif
}
#if MYSQL_VERSION_ID < 50100
#if MYSQL_VERSION_ID < 50100
send_eof
(
thd
);
#endif
#endif
SPH_RET
(
FALSE
);
}
...
...
@@ -926,10 +967,9 @@ static void sphLogError ( const char * sFmt, ... )
// the following scheme variants are recognized
//
// sphinx://host/index
// sphinx://host:port/index
// unix://unix/domain/socket:index
// unix://unix/domain/socket
// sphinx://host[:port]/index
// sphinxql://host[:port]/index
// unix://unix/domain/socket[:index]
static
bool
ParseUrl
(
CSphSEShare
*
share
,
TABLE
*
table
,
bool
bCreate
)
{
SPH_ENTER_FUNC
();
...
...
@@ -939,12 +979,12 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
// check incoming stuff
if
(
!
table
)
{
sphLogError
(
"table==NULL in ParseUrl()"
);
sphLogError
(
"table==NULL in ParseUrl()"
);
return
false
;
}
if
(
!
table
->
s
)
{
sphLogError
(
"(table->s)==NULL in ParseUrl()"
);
sphLogError
(
"(table->s)==NULL in ParseUrl()"
);
return
false
;
}
...
...
@@ -966,69 +1006,121 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
}
}
// defaults
bool
bOk
=
true
;
bool
bQL
=
false
;
char
*
sScheme
=
NULL
;
char
*
sHost
=
SPHINX
SE
_DEFAULT_HOST
;
char
*
sIndex
=
SPHINX
SE
_DEFAULT_INDEX
;
int
iPort
=
SPHINX
SE
_DEFAULT_PORT
;
char
*
sHost
=
SPHINX
API
_DEFAULT_HOST
;
char
*
sIndex
=
SPHINX
API
_DEFAULT_INDEX
;
int
iPort
=
SPHINX
API
_DEFAULT_PORT
;
bool
bOk
=
true
;
// parse connection string, if any
while
(
table
->
s
->
connect_string
.
length
!=
0
)
{
bOk
=
false
;
sScheme
=
sphDup
(
table
->
s
->
connect_string
.
str
,
table
->
s
->
connect_string
.
length
);
sHost
=
strstr
(
sScheme
,
"://"
);
if
(
!
sHost
)
{
bOk
=
false
;
break
;
}
sHost
[
0
]
=
'\0'
;
sHost
+=
2
;
sHost
+=
3
;
/////////////////////////////
// sphinxapi via unix socket
/////////////////////////////
if
(
!
strcmp
(
sScheme
,
"unix"
)
)
{
// unix-domain socket
sHost
--
;
// reuse last slash
iPort
=
0
;
if
(
!
(
sIndex
=
strrchr
(
sHost
,
':'
)
))
sIndex
=
SPHINX
SE
_DEFAULT_INDEX
;
sIndex
=
SPHINX
API
_DEFAULT_INDEX
;
else
{
*
sIndex
++
=
'\0'
;
if
(
!*
sIndex
)
sIndex
=
SPHINX
SE
_DEFAULT_INDEX
;
sIndex
=
SPHINX
API
_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
}
if
(
strcmp
(
sScheme
,
"sphinx"
)
!=
0
&&
strcmp
(
sScheme
,
"inet"
)
!=
0
)
break
;
// tcp
sHost
++
;
char
*
sPort
=
strchr
(
sHost
,
':'
);
if
(
sPort
)
/////////////////////
// sphinxapi via tcp
/////////////////////
if
(
!
strcmp
(
sScheme
,
"sphinx"
)
)
{
*
sPort
++
=
'\0'
;
if
(
*
sPort
)
char
*
sPort
=
strchr
(
sHost
,
':'
)
;
if
(
sPort
)
{
sIndex
=
strchr
(
sPort
,
'/'
);
*
sPort
++
=
'\0'
;
if
(
*
sPort
)
{
sIndex
=
strchr
(
sPort
,
'/'
);
if
(
sIndex
)
*
sIndex
++
=
'\0'
;
else
sIndex
=
SPHINXAPI_DEFAULT_INDEX
;
iPort
=
atoi
(
sPort
);
if
(
!
iPort
)
iPort
=
SPHINXAPI_DEFAULT_PORT
;
}
}
else
{
sIndex
=
strchr
(
sHost
,
'/'
);
if
(
sIndex
)
*
sIndex
++
=
'\0'
;
*
sIndex
++
=
'\0'
;
else
sIndex
=
SPHINXSE_DEFAULT_INDEX
;
sIndex
=
SPHINXAPI_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
}
////////////
// sphinxql
////////////
if
(
!
strcmp
(
sScheme
,
"sphinxql"
)
)
{
bQL
=
true
;
iPort
=
SPHINXQL_DEFAULT_PORT
;
// handle port
char
*
sPort
=
strchr
(
sHost
,
':'
);
sIndex
=
sHost
;
// starting point for index name search
if
(
sPort
)
{
*
sPort
++
=
'\0'
;
sIndex
=
sPort
;
iPort
=
atoi
(
sPort
);
if
(
!
iPort
)
iPort
=
SPHINXSE_DEFAULT_PORT
;
{
bOk
=
false
;
// invalid port; can report ER_FOREIGN_DATA_STRING_INVALID
break
;
}
}
}
else
{
sIndex
=
strchr
(
s
Host
,
'/'
);
// find index
sIndex
=
strchr
(
s
Index
,
'/'
);
if
(
sIndex
)
*
sIndex
++
=
'\0'
;
else
sIndex
=
SPHINXSE_DEFAULT_INDEX
;
// final checks
// host and index names are required
bOk
=
(
sHost
&&
*
sHost
&&
sIndex
&&
*
sIndex
);
break
;
}
bOk
=
true
;
// unknown case
bOk
=
false
;
break
;
}
...
...
@@ -1045,6 +1137,7 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
share
->
m_sHost
=
sHost
;
share
->
m_sIndex
=
sIndex
;
share
->
m_iPort
=
(
ushort
)
iPort
;
share
->
m_bSphinxQL
=
bQL
;
}
}
if
(
!
bOk
&&
!
share
)
...
...
@@ -1067,12 +1160,12 @@ static CSphSEShare * get_share ( const char * table_name, TABLE * table )
{
// check if we already have this share
#if MYSQL_VERSION_ID>=50120
pShare
=
(
CSphSEShare
*
)
hash_search
(
&
sphinx_open_tables
,
(
const
uchar
*
)
table_name
,
strlen
(
table_name
)
);
pShare
=
(
CSphSEShare
*
)
sphinx_
hash_search
(
&
sphinx_open_tables
,
(
const
uchar
*
)
table_name
,
strlen
(
table_name
)
);
#else
#ifdef __WIN__
pShare
=
(
CSphSEShare
*
)
hash_search
(
&
sphinx_open_tables
,
(
const
byte
*
)
table_name
,
strlen
(
table_name
)
);
pShare
=
(
CSphSEShare
*
)
sphinx_
hash_search
(
&
sphinx_open_tables
,
(
const
byte
*
)
table_name
,
strlen
(
table_name
)
);
#else
pShare
=
(
CSphSEShare
*
)
hash_search
(
&
sphinx_open_tables
,
table_name
,
strlen
(
table_name
)
);
pShare
=
(
CSphSEShare
*
)
sphinx_
hash_search
(
&
sphinx_open_tables
,
table_name
,
strlen
(
table_name
)
);
#endif // win
#endif // pre-5.1.20
...
...
@@ -1088,13 +1181,15 @@ static CSphSEShare * get_share ( const char * table_name, TABLE * table )
break
;
// try to setup it
pShare
->
m_pTableQueryCharset
=
table
->
field
[
2
]
->
charset
();
if
(
!
ParseUrl
(
pShare
,
table
,
false
)
)
{
SafeDelete
(
pShare
);
break
;
}
if
(
!
pShare
->
m_bSphinxQL
)
pShare
->
m_pTableQueryCharset
=
table
->
field
[
2
]
->
charset
();
// try to hash it
pShare
->
m_iTableNameLen
=
strlen
(
table_name
);
pShare
->
m_sTable
=
sphDup
(
table_name
);
...
...
@@ -1122,7 +1217,7 @@ static int free_share ( CSphSEShare * pShare )
if
(
!--
pShare
->
m_iUseCount
)
{
hash_delete
(
&
sphinx_open_tables
,
(
byte
*
)
pShare
);
sphinx_
hash_delete
(
&
sphinx_open_tables
,
(
byte
*
)
pShare
);
SafeDelete
(
pShare
);
}
...
...
@@ -1155,6 +1250,7 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
,
m_iWeights
(
0
)
,
m_eMode
(
SPH_MATCH_ALL
)
,
m_eRanker
(
SPH_RANK_PROXIMITY_BM25
)
,
m_sRankExpr
(
NULL
)
,
m_eSort
(
SPH_SORT_RELEVANCE
)
,
m_sSortBy
(
""
)
,
m_iMaxMatches
(
1000
)
...
...
@@ -1177,6 +1273,7 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
,
m_fGeoLatitude
(
0.0
f
)
,
m_fGeoLongitude
(
0.0
f
)
,
m_sComment
(
""
)
,
m_sSelect
(
""
)
,
m_pBuf
(
NULL
)
,
m_pCur
(
NULL
)
...
...
@@ -1185,8 +1282,8 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
{
m_sQueryBuffer
=
new
char
[
iLength
+
2
];
memcpy
(
m_sQueryBuffer
,
sQuery
,
iLength
);
m_sQueryBuffer
[
iLength
]
=
';'
;
m_sQueryBuffer
[
iLength
+
1
]
=
'\0'
;
m_sQueryBuffer
[
iLength
]
=
';'
;
m_sQueryBuffer
[
iLength
+
1
]
=
'\0'
;
}
...
...
@@ -1242,22 +1339,20 @@ int CSphSEQuery::ParseArray ( T ** ppValues, const char * sValue )
if
(
!
bPrevDigit
)
uValue
=
0
;
uValue
=
uValue
*
10
+
(
(
*
pValue
)
-
'0'
);
}
else
if
(
bPrevDigit
)
}
else
if
(
bPrevDigit
)
{
assert
(
iIndex
<
iValues
);
pValues
[
iIndex
++
]
=
uValue
*
iSign
;
iSign
=
1
;
}
else
if
(
*
pValue
==
'-'
)
}
else
if
(
*
pValue
==
'-'
)
iSign
=
-
1
;
bPrevDigit
=
bDigit
;
bPrevDigit
=
bDigit
;
if
(
!*
pValue
)
break
;
}
SPH_RET
(
iValues
);
SPH_RET
(
iValues
);
}
...
...
@@ -1267,7 +1362,7 @@ static char * chop ( char * s )
s
++
;
char
*
p
=
s
+
strlen
(
s
);
while
(
p
>
s
&&
isspace
(
p
[
-
1
]
)
)
while
(
p
>
s
&&
isspace
(
p
[
-
1
]
)
)
p
--
;
*
p
=
'\0'
;
...
...
@@ -1284,6 +1379,11 @@ static bool myisattr ( char c )
c
==
'_'
;
}
static
bool
myismagic
(
char
c
)
{
return
c
==
'@'
;
}
bool
CSphSEQuery
::
ParseField
(
char
*
sField
)
{
...
...
@@ -1305,11 +1405,13 @@ bool CSphSEQuery::ParseField ( char * sField )
m_sQuery
=
sField
;
m_bQuery
=
true
;
// unescape
// unescape
only 1st one
char
*
s
=
sField
,
*
d
=
sField
;
int
iSlashes
=
0
;
while
(
*
s
)
{
if
(
*
s
!=
'\\'
)
*
d
++
=
*
s
;
iSlashes
=
(
*
s
==
'\\'
)
?
iSlashes
+
1
:
0
;
if
(
(
iSlashes
%
2
)
==
0
)
*
d
++
=
*
s
;
s
++
;
}
*
d
=
'\0'
;
...
...
@@ -1341,20 +1443,20 @@ bool CSphSEQuery::ParseField ( char * sField )
else
if
(
!
strcmp
(
sName
,
"distinct"
)
)
m_sGroupDistinct
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"cutoff"
)
)
m_iCutoff
=
iValue
;
else
if
(
!
strcmp
(
sName
,
"comment"
)
)
m_sComment
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"select"
)
)
m_sSelect
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"mode"
)
)
{
m_eMode
=
SPH_MATCH_ALL
;
if
(
!
strcmp
(
sValue
,
"any"
)
)
m_eMode
=
SPH_MATCH_ANY
;
if
(
!
strcmp
(
sValue
,
"any"
)
)
m_eMode
=
SPH_MATCH_ANY
;
else
if
(
!
strcmp
(
sValue
,
"phrase"
)
)
m_eMode
=
SPH_MATCH_PHRASE
;
else
if
(
!
strcmp
(
sValue
,
"boolean"
)
)
m_eMode
=
SPH_MATCH_BOOLEAN
;
else
if
(
!
strcmp
(
sValue
,
"ext"
)
)
m_eMode
=
SPH_MATCH_EXTENDED
;
else
if
(
!
strcmp
(
sValue
,
"extended"
)
)
m_eMode
=
SPH_MATCH_EXTENDED
;
else
if
(
!
strcmp
(
sValue
,
"ext2"
)
)
m_eMode
=
SPH_MATCH_EXTENDED2
;
else
if
(
!
strcmp
(
sValue
,
"extended2"
)
)
m_eMode
=
SPH_MATCH_EXTENDED2
;
else
if
(
!
strcmp
(
sValue
,
"all"
)
)
m_eMode
=
SPH_MATCH_ALL
;
else
if
(
!
strcmp
(
sValue
,
"fullscan"
)
)
m_eMode
=
SPH_MATCH_FULLSCAN
;
else
if
(
!
strcmp
(
sValue
,
"boolean"
)
)
m_eMode
=
SPH_MATCH_BOOLEAN
;
else
if
(
!
strcmp
(
sValue
,
"ext"
)
)
m_eMode
=
SPH_MATCH_EXTENDED
;
else
if
(
!
strcmp
(
sValue
,
"extended"
)
)
m_eMode
=
SPH_MATCH_EXTENDED
;
else
if
(
!
strcmp
(
sValue
,
"ext2"
)
)
m_eMode
=
SPH_MATCH_EXTENDED2
;
else
if
(
!
strcmp
(
sValue
,
"extended2"
)
)
m_eMode
=
SPH_MATCH_EXTENDED2
;
else
if
(
!
strcmp
(
sValue
,
"all"
)
)
m_eMode
=
SPH_MATCH_ALL
;
else
if
(
!
strcmp
(
sValue
,
"fullscan"
)
)
m_eMode
=
SPH_MATCH_FULLSCAN
;
else
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown matching mode '%s'"
,
sValue
);
...
...
@@ -1362,27 +1464,31 @@ bool CSphSEQuery::ParseField ( char * sField )
}
}
else
if
(
!
strcmp
(
sName
,
"ranker"
)
)
{
m_eRanker
=
SPH_RANK_PROXIMITY_BM25
;
if
(
!
strcmp
(
sValue
,
"proximity_bm25"
)
)
m_eRanker
=
SPH_RANK_PROXIMITY_BM25
;
if
(
!
strcmp
(
sValue
,
"proximity_bm25"
)
)
m_eRanker
=
SPH_RANK_PROXIMITY_BM25
;
else
if
(
!
strcmp
(
sValue
,
"bm25"
)
)
m_eRanker
=
SPH_RANK_BM25
;
else
if
(
!
strcmp
(
sValue
,
"none"
)
)
m_eRanker
=
SPH_RANK_NONE
;
else
if
(
!
strcmp
(
sValue
,
"wordcount"
)
)
m_eRanker
=
SPH_RANK_WORDCOUNT
;
else
if
(
!
strcmp
(
sValue
,
"proximity"
)
)
m_eRanker
=
SPH_RANK_PROXIMITY
;
else
if
(
!
strcmp
(
sValue
,
"matchany"
)
)
m_eRanker
=
SPH_RANK_MATCHANY
;
else
if
(
!
strcmp
(
sValue
,
"fieldmask"
)
)
m_eRanker
=
SPH_RANK_FIELDMASK
;
else
else
if
(
!
strcmp
(
sValue
,
"sph04"
)
)
m_eRanker
=
SPH_RANK_SPH04
;
else
if
(
!
strncmp
(
sValue
,
"expr:"
,
5
)
)
{
m_eRanker
=
SPH_RANK_EXPR
;
m_sRankExpr
=
sValue
+
5
;
}
else
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown ranking mode '%s'"
,
sValue
);
SPH_RET
(
false
);
}
}
else
if
(
!
strcmp
(
sName
,
"sort"
)
)
{
static
const
struct
static
const
struct
{
const
char
*
m_sName
;
ESphSortOrder
m_eSort
;
}
dSortModes
[]
=
}
dSortModes
[]
=
{
{
"relevance"
,
SPH_SORT_RELEVANCE
},
{
"attr_desc:"
,
SPH_SORT_ATTR_DESC
},
...
...
@@ -1395,10 +1501,10 @@ bool CSphSEQuery::ParseField ( char * sField )
int
i
;
const
int
nModes
=
sizeof
(
dSortModes
)
/
sizeof
(
dSortModes
[
0
]);
for
(
i
=
0
;
i
<
nModes
;
i
++
)
if
(
!
strncmp
(
sValue
,
dSortModes
[
i
].
m_sName
,
strlen
(
dSortModes
[
i
].
m_sName
)
)
)
if
(
!
strncmp
(
sValue
,
dSortModes
[
i
].
m_sName
,
strlen
(
dSortModes
[
i
].
m_sName
)
)
)
{
m_eSort
=
dSortModes
[
i
].
m_eSort
;
m_sSortBy
=
sValue
+
strlen
(
dSortModes
[
i
].
m_sName
);
m_sSortBy
=
sValue
+
strlen
(
dSortModes
[
i
].
m_sName
);
break
;
}
if
(
i
==
nModes
)
...
...
@@ -1409,11 +1515,11 @@ bool CSphSEQuery::ParseField ( char * sField )
}
else
if
(
!
strcmp
(
sName
,
"groupby"
)
)
{
static
const
struct
static
const
struct
{
const
char
*
m_sName
;
ESphGroupBy
m_eFunc
;
}
dGroupModes
[]
=
}
dGroupModes
[]
=
{
{
"day:"
,
SPH_GROUPBY_DAY
},
{
"week:"
,
SPH_GROUPBY_WEEK
},
...
...
@@ -1425,10 +1531,10 @@ bool CSphSEQuery::ParseField ( char * sField )
int
i
;
const
int
nModes
=
sizeof
(
dGroupModes
)
/
sizeof
(
dGroupModes
[
0
]);
for
(
i
=
0
;
i
<
nModes
;
i
++
)
if
(
!
strncmp
(
sValue
,
dGroupModes
[
i
].
m_sName
,
strlen
(
dGroupModes
[
i
].
m_sName
)
)
)
if
(
!
strncmp
(
sValue
,
dGroupModes
[
i
].
m_sName
,
strlen
(
dGroupModes
[
i
].
m_sName
)
)
)
{
m_eGroupFunc
=
dGroupModes
[
i
].
m_eFunc
;
m_sGroupBy
=
sValue
+
strlen
(
dGroupModes
[
i
].
m_sName
);
m_sGroupBy
=
sValue
+
strlen
(
dGroupModes
[
i
].
m_sName
);
break
;
}
if
(
i
==
nModes
)
...
...
@@ -1460,8 +1566,8 @@ bool CSphSEQuery::ParseField ( char * sField )
if
(
tFilter
.
m_eType
==
SPH_FILTER_RANGE
)
{
tFilter
.
m_uMinValue
=
strtoll
(
sValue
,
NULL
,
0
);
tFilter
.
m_uMaxValue
=
strtoll
(
p
,
NULL
,
0
);
tFilter
.
m_uMinValue
=
strtoll
(
sValue
,
NULL
,
1
0
);
tFilter
.
m_uMaxValue
=
strtoll
(
p
,
NULL
,
1
0
);
}
else
{
tFilter
.
m_fMinValue
=
(
float
)
atof
(
sValue
);
...
...
@@ -1480,16 +1586,16 @@ bool CSphSEQuery::ParseField ( char * sField )
{
CSphSEFilter
&
tFilter
=
m_dFilters
[
m_iFilters
];
tFilter
.
m_eType
=
SPH_FILTER_VALUES
;
tFilter
.
m_bExclude
=
(
strcmp
(
sName
,
"!filter"
)
==
0
);
tFilter
.
m_bExclude
=
(
strcmp
(
sName
,
"!filter"
)
==
0
);
// get the attr name
while
(
(
*
sValue
)
&&
!
myisattr
(
*
sValue
)
)
while
(
(
*
sValue
)
&&
!
(
myisattr
(
*
sValue
)
||
myismagic
(
*
sValue
)
)
)
sValue
++
;
if
(
!*
sValue
)
break
;
tFilter
.
m_sAttrName
=
sValue
;
while
(
(
*
sValue
)
&&
myisattr
(
*
sValue
)
)
while
(
(
*
sValue
)
&&
(
myisattr
(
*
sValue
)
||
myismagic
(
*
sValue
)
)
)
sValue
++
;
if
(
!*
sValue
)
break
;
...
...
@@ -1548,7 +1654,8 @@ bool CSphSEQuery::ParseField ( char * sField )
pWeights
[
*
pCount
]
=
atoi
(
sVal
);
(
*
pCount
)
++
;
if
(
!*
p
)
break
;
if
(
!*
p
)
break
;
if
(
*
p
!=
','
)
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"%s: comma expected near '%s'"
,
sName
,
p
);
...
...
@@ -1576,8 +1683,8 @@ bool CSphSEQuery::ParseField ( char * sField )
m_sGeoLatAttr
=
chop
(
sLat
);
m_sGeoLongAttr
=
chop
(
sLong
);
m_fGeoLatitude
=
(
float
)
atof
(
sLatVal
);
m_fGeoLongitude
=
(
float
)
atof
(
sLongVal
);
m_fGeoLatitude
=
(
float
)
atof
(
sLatVal
);
m_fGeoLongitude
=
(
float
)
atof
(
sLongVal
);
m_bGeoAnchor
=
true
;
break
;
}
...
...
@@ -1586,8 +1693,7 @@ bool CSphSEQuery::ParseField ( char * sField )
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"geoanchor: parse error, not enough comma-separated arguments"
);
SPH_RET
(
false
);
}
}
else
if
(
!
strcmp
(
sName
,
"override"
)
)
// name,type,id:value,id:value,...
}
else
if
(
!
strcmp
(
sName
,
"override"
)
)
// name,type,id:value,id:value,...
{
char
*
sName
=
NULL
;
int
iType
=
0
;
...
...
@@ -1600,11 +1706,13 @@ bool CSphSEQuery::ParseField ( char * sField )
sName
=
sRest
;
if
(
!*
sName
)
break
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
*
sRest
++
=
'\0'
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
*
sRest
++
=
'\0'
;
char
*
sType
=
sRest
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
static
const
struct
{
const
char
*
m_sName
;
...
...
@@ -1619,7 +1727,7 @@ bool CSphSEQuery::ParseField ( char * sField )
{
"bigint"
,
SPH_ATTR_BIGINT
}
};
for
(
int
i
=
0
;
i
<
sizeof
(
dAttrTypes
)
/
sizeof
(
*
dAttrTypes
);
i
++
)
if
(
!
strncmp
(
sType
,
dAttrTypes
[
i
].
m_sName
,
sRest
-
sType
)
)
if
(
!
strncmp
(
sType
,
dAttrTypes
[
i
].
m_sName
,
sRest
-
sType
)
)
{
iType
=
dAttrTypes
[
i
].
m_iType
;
break
;
...
...
@@ -1628,7 +1736,7 @@ bool CSphSEQuery::ParseField ( char * sField )
}
// fail
if
(
!
sName
||
!*
sName
||
!
iType
)
if
(
!
sName
||
!*
sName
||
!
iType
)
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"override: malformed query"
);
SPH_RET
(
false
);
...
...
@@ -1643,7 +1751,8 @@ bool CSphSEQuery::ParseField ( char * sField )
if
(
!
(
sRest
-
sId
))
break
;
char
*
sValue
=
sRest
;
if
((
sRest
=
strchr
(
sRest
,
','
)
))
*
sRest
++
=
'\0'
;
if
(
(
sRest
=
strchr
(
sRest
,
','
)
)
!=
NULL
)
*
sRest
++
=
'\0'
;
if
(
!*
sValue
)
break
;
...
...
@@ -1652,18 +1761,18 @@ bool CSphSEQuery::ParseField ( char * sField )
pOverride
=
new
CSphSEQuery
::
Override_t
;
pOverride
->
m_sName
=
chop
(
sName
);
pOverride
->
m_iType
=
iType
;
m_dOverrides
.
append
(
pOverride
);
m_dOverrides
.
append
(
pOverride
);
}
ulonglong
uId
=
strtoull
(
sId
,
NULL
,
10
);
CSphSEQuery
::
Override_t
::
Value_t
tValue
;
if
(
iType
==
SPH_ATTR_FLOAT
)
if
(
iType
==
SPH_ATTR_FLOAT
)
tValue
.
m_fValue
=
(
float
)
atof
(
sValue
);
else
if
(
iType
==
SPH_ATTR_BIGINT
)
else
if
(
iType
==
SPH_ATTR_BIGINT
)
tValue
.
m_iValue64
=
strtoll
(
sValue
,
NULL
,
10
);
else
tValue
.
m_uValue
=
(
uint32
)
strtoul
(
sValue
,
NULL
,
10
);
pOverride
->
m_dIds
.
append
(
uId
);
pOverride
->
m_dValues
.
append
(
tValue
);
}
...
...
@@ -1674,8 +1783,7 @@ bool CSphSEQuery::ParseField ( char * sField )
SPH_RET
(
false
);
}
SPH_RET
(
true
);
}
else
}
else
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown parameter '%s'"
,
sName
);
SPH_RET
(
false
);
...
...
@@ -1696,7 +1804,7 @@ bool CSphSEQuery::Parse ()
char
*
pCur
=
m_sQueryBuffer
;
char
*
pNext
=
pCur
;
while
(
(
pNext
=
strchr
(
pNext
,
';'
)
)
)
while
(
(
pNext
=
strchr
(
pNext
,
';'
)
)
!=
NULL
)
{
// handle escaped semicolons
if
(
pNext
>
m_sQueryBuffer
&&
pNext
[
-
1
]
==
'\\'
&&
pNext
[
1
]
!=
'\0'
)
...
...
@@ -1712,6 +1820,8 @@ bool CSphSEQuery::Parse ()
pCur
=
pNext
;
}
SPH_DEBUG
(
"q [[ %s ]]"
,
m_sQuery
);
SPH_RET
(
true
);
}
...
...
@@ -1738,14 +1848,17 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
SPH_ENTER_METHOD
();
// calc request length
int
iReqSize
=
12
4
+
4
*
m_iWeights
int
iReqSize
=
12
8
+
4
*
m_iWeights
+
strlen
(
m_sSortBy
)
+
strlen
(
m_sQuery
)
+
strlen
(
m_sIndex
)
+
strlen
(
m_sGroupBy
)
+
strlen
(
m_sGroupSortBy
)
+
strlen
(
m_sGroupDistinct
)
+
strlen
(
m_sComment
);
+
strlen
(
m_sComment
)
+
strlen
(
m_sSelect
);
if
(
m_eRanker
==
SPH_RANK_EXPR
)
iReqSize
+=
4
+
strlen
(
m_sRankExpr
);
for
(
int
i
=
0
;
i
<
m_iFilters
;
i
++
)
{
const
CSphSEFilter
&
tFilter
=
m_dFilters
[
i
];
...
...
@@ -1758,7 +1871,7 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
}
}
if
(
m_bGeoAnchor
)
// 1.14+
iReqSize
+=
16
+
strlen
(
m_sGeoLatAttr
)
+
strlen
(
m_sGeoLongAttr
);
iReqSize
+=
16
+
strlen
(
m_sGeoLatAttr
)
+
strlen
(
m_sGeoLongAttr
);
for
(
int
i
=
0
;
i
<
m_iIndexWeights
;
i
++
)
// 1.15+
iReqSize
+=
8
+
strlen
(
m_sIndexWeight
[
i
]
);
for
(
int
i
=
0
;
i
<
m_iFieldWeights
;
i
++
)
// 1.18+
...
...
@@ -1768,12 +1881,12 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
for
(
int
i
=
0
;
i
<
m_dOverrides
.
elements
();
i
++
)
{
CSphSEQuery
::
Override_t
*
pOverride
=
m_dOverrides
.
at
(
i
);
const
uint32
uSize
=
pOverride
->
m_iType
==
SPH_ATTR_BIGINT
?
16
:
12
;
// id64 + value
const
uint32
uSize
=
pOverride
->
m_iType
==
SPH_ATTR_BIGINT
?
16
:
12
;
// id64 + value
iReqSize
+=
strlen
(
pOverride
->
m_sName
)
+
12
+
uSize
*
pOverride
->
m_dIds
.
elements
();
}
// select
iReqSize
+=
4
;
m_iBufLeft
=
0
;
SafeDeleteArray
(
m_pBuf
);
...
...
@@ -1790,12 +1903,15 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
SendWord
(
SEARCHD_COMMAND_SEARCH
);
// command id
SendWord
(
VER_COMMAND_SEARCH
);
// command version
SendInt
(
iReqSize
-
8
);
// packet body length
SendInt
(
0
);
// its a client
SendInt
(
1
);
// number of queries
SendInt
(
m_iOffset
);
SendInt
(
m_iLimit
);
SendInt
(
m_eMode
);
SendInt
(
m_eRanker
);
// 1.16+
if
(
m_eRanker
==
SPH_RANK_EXPR
)
SendString
(
m_sRankExpr
);
SendInt
(
m_eSort
);
SendString
(
m_sSortBy
);
// sort attr
SendString
(
m_sQuery
);
// query
...
...
@@ -1878,9 +1994,9 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
for
(
int
j
=
0
;
j
<
pOverride
->
m_dIds
.
elements
();
j
++
)
{
SendUint64
(
pOverride
->
m_dIds
.
at
(
j
)
);
if
(
pOverride
->
m_iType
==
SPH_ATTR_FLOAT
)
if
(
pOverride
->
m_iType
==
SPH_ATTR_FLOAT
)
SendFloat
(
pOverride
->
m_dValues
.
at
(
j
).
m_fValue
);
else
if
(
pOverride
->
m_iType
==
SPH_ATTR_BIGINT
)
else
if
(
pOverride
->
m_iType
==
SPH_ATTR_BIGINT
)
SendUint64
(
pOverride
->
m_dValues
.
at
(
j
).
m_iValue64
);
else
SendDword
(
pOverride
->
m_dValues
.
at
(
j
).
m_uValue
);
...
...
@@ -1888,14 +2004,14 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
}
// select
SendString
(
""
);
SendString
(
m_sSelect
);
// detect buffer overruns and underruns, and report internal error
if
(
m_bBufOverrun
||
m_iBufLeft
!=
0
||
m_pCur
-
m_pBuf
!=
iReqSize
)
SPH_RET
(
-
1
);
// all fine
SPH_RET
(
iReqSize
);
SPH_RET
(
iReqSize
);
}
//////////////////////////////////////////////////////////////////////////////
...
...
@@ -1970,10 +2086,8 @@ int ha_sphinx::open ( const char * name, int, uint )
}
int
ha_sphinx
::
Connect
ToSearchd
(
const
char
*
sQueryHost
,
int
iQuery
Port
)
int
ha_sphinx
::
Connect
(
const
char
*
sHost
,
ushort
u
Port
)
{
SPH_ENTER_METHOD
();
struct
sockaddr_in
sin
;
#ifndef __WIN__
struct
sockaddr_un
saun
;
...
...
@@ -1984,13 +2098,8 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
struct
sockaddr
*
pSockaddr
=
NULL
;
in_addr_t
ip_addr
;
int
version
;
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
const
char
*
sHost
=
(
sQueryHost
&&
*
sQueryHost
)
?
sQueryHost
:
m_pShare
->
m_sHost
;
ushort
iPort
=
iQueryPort
?
(
ushort
)
iQueryPort
:
m_pShare
->
m_iPort
;
if
(
i
Port
)
if
(
u
Port
)
{
iDomain
=
AF_INET
;
iSockaddrSize
=
sizeof
(
sin
);
...
...
@@ -1998,34 +2107,53 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
sin
.
sin_family
=
AF_INET
;
sin
.
sin_port
=
htons
(
i
Port
);
sin
.
sin_port
=
htons
(
u
Port
);
// prepare host address
if
(
(
int
)(
ip_addr
=
inet_addr
(
sHost
)
)
!=
(
int
)
INADDR_NONE
)
{
if
(
(
int
)(
ip_addr
=
inet_addr
(
sHost
)
)
!=
(
int
)
INADDR_NONE
)
{
memcpy
(
&
sin
.
sin_addr
,
&
ip_addr
,
sizeof
(
ip_addr
)
);
}
else
{
int
tmp_errno
;
bool
bError
=
false
;
#if MYSQL_VERSION_ID>=50515
struct
addrinfo
*
hp
=
NULL
;
tmp_errno
=
getaddrinfo
(
sHost
,
NULL
,
NULL
,
&
hp
);
if
(
!
tmp_errno
||
!
hp
||
!
hp
->
ai_addr
)
{
bError
=
true
;
if
(
hp
)
freeaddrinfo
(
hp
);
}
#else
struct
hostent
tmp_hostent
,
*
hp
;
char
buff2
[
GETHOSTBYNAME_BUFF_SIZE
];
hp
=
my_gethostbyname_r
(
sHost
,
&
tmp_hostent
,
buff2
,
sizeof
(
buff2
),
&
tmp_errno
);
hp
=
my_gethostbyname_r
(
sHost
,
&
tmp_hostent
,
buff2
,
sizeof
(
buff2
),
&
tmp_errno
);
if
(
!
hp
)
{
{
my_gethostbyname_r_free
();
bError
=
true
;
}
#endif
if
(
bError
)
{
char
sError
[
256
];
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
sHost
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
}
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
#if MYSQL_VERSION_ID>=50515
memcpy
(
&
sin
.
sin_addr
,
hp
->
ai_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
ai_addrlen
)
);
freeaddrinfo
(
hp
);
#else
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
my_gethostbyname_r_free
();
#endif
}
}
else
{
...
...
@@ -2056,30 +2184,49 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
{
sphSockClose
(
iSocket
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to connect to searchd (host=%s, errno=%d, port=%d)"
,
sHost
,
errno
,
i
Port
);
sHost
,
errno
,
(
int
)
u
Port
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
}
return
iSocket
;
}
int
ha_sphinx
::
ConnectAPI
(
const
char
*
sQueryHost
,
int
iQueryPort
)
{
SPH_ENTER_METHOD
();
const
char
*
sHost
=
(
sQueryHost
&&
*
sQueryHost
)
?
sQueryHost
:
m_pShare
->
m_sHost
;
ushort
uPort
=
iQueryPort
?
(
ushort
)
iQueryPort
:
m_pShare
->
m_iPort
;
int
iSocket
=
Connect
(
sHost
,
uPort
);
if
(
iSocket
<
0
)
SPH_RET
(
iSocket
);
char
sError
[
512
];
int
version
;
if
(
::
recv
(
iSocket
,
(
char
*
)
&
version
,
sizeof
(
version
),
0
)
!=
sizeof
(
version
)
)
{
sphSockClose
(
iSocket
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to receive searchd version (host=%s, port=%d)"
,
sHost
,
i
Port
);
sHost
,
(
int
)
u
Port
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
}
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
if
(
::
send
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
),
0
)
!=
sizeof
(
uClientVersion
)
)
{
sphSockClose
(
iSocket
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to send client version (host=%s, port=%d)"
,
sHost
,
i
Port
);
sHost
,
(
int
)
u
Port
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
}
SPH_RET
(
iSocket
);
SPH_RET
(
iSocket
);
}
...
...
@@ -2094,25 +2241,182 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
int
ha_sphinx
::
close
()
{
SPH_ENTER_METHOD
();
SPH_RET
(
free_share
(
m_pShare
)
);
SPH_RET
(
free_share
(
m_pShare
)
);
}
int
ha_sphinx
::
HandleMysqlError
(
MYSQL
*
pConn
,
int
iErrCode
)
{
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
pTls
)
{
strncpy
(
pTls
->
m_tStats
.
m_sLastMessage
,
mysql_error
(
pConn
),
sizeof
(
pTls
->
m_tStats
.
m_sLastMessage
)
);
pTls
->
m_tStats
.
m_bLastError
=
true
;
}
mysql_close
(
pConn
);
my_error
(
iErrCode
,
MYF
(
0
),
pTls
->
m_tStats
.
m_sLastMessage
);
return
-
1
;
}
int
ha_sphinx
::
extra
(
enum
ha_extra_function
op
)
{
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
pTls
)
{
if
(
op
==
HA_EXTRA_WRITE_CAN_REPLACE
)
pTls
->
m_bReplace
=
true
;
else
if
(
op
==
HA_EXTRA_WRITE_CANNOT_REPLACE
)
pTls
->
m_bReplace
=
false
;
}
return
0
;
}
int
ha_sphinx
::
write_row
(
uchar
*
)
int
ha_sphinx
::
write_row
(
byte
*
)
{
SPH_ENTER_METHOD
();
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
if
(
!
m_pShare
||
!
m_pShare
->
m_bSphinxQL
)
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
// SphinxQL inserts only, pretty much similar to abandoned federated
char
sQueryBuf
[
1024
];
char
sValueBuf
[
1024
];
String
sQuery
(
sQueryBuf
,
sizeof
(
sQueryBuf
),
&
my_charset_bin
);
String
sValue
(
sValueBuf
,
sizeof
(
sQueryBuf
),
&
my_charset_bin
);
sQuery
.
length
(
0
);
sValue
.
length
(
0
);
CSphSEThreadData
*
pTls
=
GetTls
();
sQuery
.
append
(
pTls
&&
pTls
->
m_bReplace
?
"REPLACE INTO "
:
"INSERT INTO "
);
sQuery
.
append
(
m_pShare
->
m_sIndex
);
sQuery
.
append
(
" ("
);
for
(
Field
**
ppField
=
table
->
field
;
*
ppField
;
ppField
++
)
{
sQuery
.
append
(
(
*
ppField
)
->
field_name
);
if
(
ppField
[
1
]
)
sQuery
.
append
(
", "
);
}
sQuery
.
append
(
") VALUES ("
);
for
(
Field
**
ppField
=
table
->
field
;
*
ppField
;
ppField
++
)
{
if
(
(
*
ppField
)
->
is_null
()
)
{
sQuery
.
append
(
"''"
);
}
else
{
if
(
(
*
ppField
)
->
type
()
==
MYSQL_TYPE_TIMESTAMP
)
{
Item_field
*
pWrap
=
new
Item_field
(
*
ppField
);
// autofreed by query arena, I assume
Item_func_unix_timestamp
*
pConv
=
new
Item_func_unix_timestamp
(
pWrap
);
pConv
->
quick_fix_field
();
unsigned
int
uTs
=
(
unsigned
int
)
pConv
->
val_int
();
snprintf
(
sValueBuf
,
sizeof
(
sValueBuf
),
"'%u'"
,
uTs
);
sQuery
.
append
(
sValueBuf
);
}
else
{
(
*
ppField
)
->
val_str
(
&
sValue
);
sQuery
.
append
(
"'"
);
sValue
.
print
(
&
sQuery
);
sQuery
.
append
(
"'"
);
sValue
.
length
(
0
);
}
}
if
(
ppField
[
1
]
)
sQuery
.
append
(
", "
);
}
sQuery
.
append
(
")"
);
// FIXME? pretty inefficient to reconnect every time under high load,
// but this was intentionally written for a low load scenario..
MYSQL
*
pConn
=
mysql_init
(
NULL
);
if
(
!
pConn
)
SPH_RET
(
ER_OUT_OF_RESOURCES
);
unsigned
int
uTimeout
=
1
;
mysql_options
(
pConn
,
MYSQL_OPT_CONNECT_TIMEOUT
,
(
const
char
*
)
&
uTimeout
);
if
(
!
mysql_real_connect
(
pConn
,
m_pShare
->
m_sHost
,
"root"
,
""
,
""
,
m_pShare
->
m_iPort
,
m_pShare
->
m_sSocket
,
0
)
)
SPH_RET
(
HandleMysqlError
(
pConn
,
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
)
);
if
(
mysql_real_query
(
pConn
,
sQuery
.
ptr
(),
sQuery
.
length
()
)
)
SPH_RET
(
HandleMysqlError
(
pConn
,
ER_QUERY_ON_FOREIGN_DATA_SOURCE
)
);
// all ok!
mysql_close
(
pConn
);
SPH_RET
(
0
);
}
int
ha_sphinx
::
update_row
(
const
uchar
*
,
uchar
*
)
static
inline
bool
IsIntegerFieldType
(
enum_field_types
eType
)
{
return
eType
==
MYSQL_TYPE_LONG
||
eType
==
MYSQL_TYPE_LONGLONG
;
}
static
inline
bool
IsIDField
(
Field
*
pField
)
{
enum_field_types
eType
=
pField
->
type
();
if
(
eType
==
MYSQL_TYPE_LONGLONG
)
return
true
;
if
(
eType
==
MYSQL_TYPE_LONG
&&
((
Field_num
*
)
pField
)
->
unsigned_flag
)
return
true
;
return
false
;
}
int
ha_sphinx
::
delete_row
(
const
byte
*
)
{
SPH_ENTER_METHOD
();
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
if
(
!
m_pShare
||
!
m_pShare
->
m_bSphinxQL
)
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
char
sQueryBuf
[
1024
];
String
sQuery
(
sQueryBuf
,
sizeof
(
sQueryBuf
),
&
my_charset_bin
);
sQuery
.
length
(
0
);
sQuery
.
append
(
"DELETE FROM "
);
sQuery
.
append
(
m_pShare
->
m_sIndex
);
sQuery
.
append
(
" WHERE id="
);
char
sValue
[
32
];
snprintf
(
sValue
,
sizeof
(
sValue
),
"%lld"
,
table
->
field
[
0
]
->
val_int
()
);
sQuery
.
append
(
sValue
);
// FIXME? pretty inefficient to reconnect every time under high load,
// but this was intentionally written for a low load scenario..
MYSQL
*
pConn
=
mysql_init
(
NULL
);
if
(
!
pConn
)
SPH_RET
(
ER_OUT_OF_RESOURCES
);
unsigned
int
uTimeout
=
1
;
mysql_options
(
pConn
,
MYSQL_OPT_CONNECT_TIMEOUT
,
(
const
char
*
)
&
uTimeout
);
if
(
!
mysql_real_connect
(
pConn
,
m_pShare
->
m_sHost
,
"root"
,
""
,
""
,
m_pShare
->
m_iPort
,
m_pShare
->
m_sSocket
,
0
)
)
SPH_RET
(
HandleMysqlError
(
pConn
,
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
)
);
if
(
mysql_real_query
(
pConn
,
sQuery
.
ptr
(),
sQuery
.
length
()
)
)
SPH_RET
(
HandleMysqlError
(
pConn
,
ER_QUERY_ON_FOREIGN_DATA_SOURCE
)
);
// all ok!
mysql_close
(
pConn
);
SPH_RET
(
0
);
}
int
ha_sphinx
::
delete_row
(
const
uchar
*
)
int
ha_sphinx
::
update_row
(
const
byte
*
,
byte
*
)
{
SPH_ENTER_METHOD
();
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
...
...
@@ -2125,6 +2429,11 @@ int ha_sphinx::index_init ( uint keynr, bool )
{
SPH_ENTER_METHOD
();
active_index
=
keynr
;
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
pTls
)
pTls
->
m_bCondDone
=
false
;
SPH_RET
(
0
);
}
...
...
@@ -2136,17 +2445,28 @@ int ha_sphinx::index_end()
}
uint32
ha_sphinx
::
UnpackDword
(
)
bool
ha_sphinx
::
CheckResponcePtr
(
int
iLen
)
{
if
(
m_pCur
+
sizeof
(
uint32
)
>
m_pResponseEnd
)
if
(
m_pCur
+
iLen
>
m_pResponseEnd
)
{
m_pCur
=
m_pResponseEnd
;
m_bUnpackError
=
true
;
return
false
;
}
return
true
;
}
uint32
ha_sphinx
::
UnpackDword
()
{
if
(
!
CheckResponcePtr
(
sizeof
(
uint32
)
)
)
// NOLINT
{
return
0
;
}
uint32
uRes
=
ntohl
(
sphUnalignedRead
(
*
(
uint32
*
)
m_pCur
)
);
m_pCur
+=
sizeof
(
uint32
);
m_pCur
+=
sizeof
(
uint32
);
// NOLINT
return
uRes
;
}
...
...
@@ -2157,10 +2477,8 @@ char * ha_sphinx::UnpackString ()
if
(
!
iLen
)
return
NULL
;
if
(
m_pCur
+
iLen
>
m_pResponseEnd
)
if
(
!
CheckResponcePtr
(
iLen
)
)
{
m_pCur
=
m_pResponseEnd
;
m_bUnpackError
=
true
;
return
NULL
;
}
...
...
@@ -2270,7 +2588,7 @@ bool ha_sphinx::UnpackSchema ()
m_iMatchesTotal
=
UnpackDword
();
m_bId64
=
UnpackDword
();
if
(
m_bId64
&&
m_pShare
->
m_eTableFieldType
[
0
]
!=
MYSQL_TYPE_LONGLONG
)
if
(
m_bId64
&&
m_pShare
->
m_eTableFieldType
[
0
]
!=
MYSQL_TYPE_LONGLONG
)
{
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: 1st column must be bigint to accept 64-bit DOCIDs"
);
SPH_RET
(
false
);
...
...
@@ -2299,7 +2617,7 @@ bool ha_sphinx::UnpackSchema ()
if
(
m_bUnpackError
)
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: UnpackSchema() failed (unpack error)"
);
SPH_RET
(
!
m_bUnpackError
);
SPH_RET
(
!
m_bUnpackError
);
}
...
...
@@ -2308,22 +2626,25 @@ bool ha_sphinx::UnpackStats ( CSphSEStats * pStats )
assert
(
pStats
);
char
*
pCurSave
=
m_pCur
;
for
(
uint
i
=
0
;
i
<
m_iMatchesTotal
&&
m_pCur
<
m_pResponseEnd
-
sizeof
(
uint32
);
i
++
)
for
(
uint
i
=
0
;
i
<
m_iMatchesTotal
&&
m_pCur
<
m_pResponseEnd
-
sizeof
(
uint32
);
i
++
)
// NOLINT
{
m_pCur
+=
m_bId64
?
12
:
8
;
// skip id+weight
for
(
uint32
i
=
0
;
i
<
m_iAttrs
&&
m_pCur
<
m_pResponseEnd
-
sizeof
(
uint32
);
i
++
)
for
(
uint32
i
=
0
;
i
<
m_iAttrs
&&
m_pCur
<
m_pResponseEnd
-
sizeof
(
uint32
);
i
++
)
// NOLINT
{
if
(
m_dAttrs
[
i
].
m_uType
&
SPH_ATTR_MULTI
)
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_UINT32SET
||
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_UINT64SET
)
{
// skip MVA list
uint32
uCount
=
UnpackDword
();
m_pCur
+=
uCount
*
4
;
}
else
// skip normal value
m_pCur
+=
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_BIGINT
?
8
:
4
;
}
else
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_STRING
)
{
uint32
iLen
=
UnpackDword
();
m_pCur
+=
iLen
;
}
else
// skip normal value
m_pCur
+=
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_BIGINT
?
8
:
4
;
}
}
pStats
->
m_iMatchesTotal
=
UnpackDword
();
pStats
->
m_iMatchesFound
=
UnpackDword
();
pStats
->
m_iQueryMsec
=
UnpackDword
();
...
...
@@ -2356,37 +2677,61 @@ bool ha_sphinx::UnpackStats ( CSphSEStats * pStats )
/// condition pushdown implementation, to properly intercept WHERE clauses on my columns
#if MYSQL_VERSION_ID<50610
const
COND
*
ha_sphinx
::
cond_push
(
const
COND
*
cond
)
#else
const
Item
*
ha_sphinx
::
cond_push
(
const
Item
*
cond
)
#endif
{
// catch the simplest case: query_column="some text"
for
(
;;
)
{
if
(
cond
->
type
()
!=
COND
::
FUNC_ITEM
)
if
(
cond
->
type
()
!=
Item
::
FUNC_ITEM
)
break
;
Item_func
*
condf
=
(
Item_func
*
)
cond
;
if
(
condf
->
functype
()
!=
Item_func
::
EQ_FUNC
||
condf
->
argument_count
()
!=
2
)
break
;
Item
**
args
=
condf
->
arguments
();
if
(
args
[
0
]
->
type
()
!=
COND
::
FIELD_ITEM
||
args
[
1
]
->
type
()
!=
COND
::
STRING_ITEM
)
break
;
Item_field
*
pField
=
(
Item_field
*
)
args
[
0
];
if
(
pField
->
field
->
field_index
!=
2
)
// FIXME! magic key index
break
;
// get my tls
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
!
pTls
)
break
;
// copy the query, and let know that we intercepted this condition
Item_string
*
pString
=
(
Item_string
*
)
args
[
1
];
pTls
->
m_bQuery
=
true
;
strncpy
(
pTls
->
m_sQuery
,
pString
->
str_value
.
c_ptr
(),
sizeof
(
pTls
->
m_sQuery
)
);
pTls
->
m_sQuery
[
sizeof
(
pTls
->
m_sQuery
)
-
1
]
=
'\0'
;
pTls
->
m_pQueryCharset
=
pString
->
str_value
.
charset
();
Item
**
args
=
condf
->
arguments
();
if
(
!
m_pShare
->
m_bSphinxQL
)
{
// on non-QL tables, intercept query=value condition for SELECT
if
(
!
(
args
[
0
]
->
type
()
==
Item
::
FIELD_ITEM
&&
args
[
1
]
->
type
()
==
Item
::
STRING_ITEM
))
break
;
Item_field
*
pField
=
(
Item_field
*
)
args
[
0
];
if
(
pField
->
field
->
field_index
!=
2
)
// FIXME! magic key index
break
;
// copy the query, and let know that we intercepted this condition
Item_string
*
pString
=
(
Item_string
*
)
args
[
1
];
pTls
->
m_bQuery
=
true
;
strncpy
(
pTls
->
m_sQuery
,
pString
->
str_value
.
c_ptr
(),
sizeof
(
pTls
->
m_sQuery
)
);
pTls
->
m_sQuery
[
sizeof
(
pTls
->
m_sQuery
)
-
1
]
=
'\0'
;
pTls
->
m_pQueryCharset
=
pString
->
str_value
.
charset
();
}
else
{
if
(
!
(
args
[
0
]
->
type
()
==
Item
::
FIELD_ITEM
&&
args
[
1
]
->
type
()
==
Item
::
INT_ITEM
))
break
;
// on QL tables, intercept id=value condition for DELETE
Item_field
*
pField
=
(
Item_field
*
)
args
[
0
];
if
(
pField
->
field
->
field_index
!=
0
)
// FIXME! magic key index
break
;
Item_int
*
pVal
=
(
Item_int
*
)
args
[
1
];
pTls
->
m_iCondId
=
pVal
->
val_int
();
pTls
->
m_bCondId
=
true
;
}
// we intercepted this condition
return
NULL
;
}
...
...
@@ -2399,9 +2744,8 @@ const COND * ha_sphinx::cond_push ( const COND * cond )
void
ha_sphinx
::
cond_pop
()
{
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
pTls
&&
pTls
->
m_bQuery
)
if
(
pTls
)
pTls
->
m_bQuery
=
false
;
return
;
}
...
...
@@ -2442,6 +2786,38 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
}
pTls
->
m_tStats
.
Reset
();
// sphinxql table, just return the key once
if
(
m_pShare
->
m_bSphinxQL
)
{
// over and out
if
(
pTls
->
m_bCondDone
)
SPH_RET
(
HA_ERR_END_OF_FILE
);
// return a value from pushdown, if any
if
(
pTls
->
m_bCondId
)
{
table
->
field
[
0
]
->
store
(
pTls
->
m_iCondId
,
1
);
pTls
->
m_bCondDone
=
true
;
SPH_RET
(
0
);
}
// return a value from key
longlong
iRef
=
0
;
if
(
key_len
==
4
)
iRef
=
uint4korr
(
key
);
else
if
(
key_len
==
8
)
iRef
=
uint8korr
(
key
);
else
{
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: unexpected key length"
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
}
table
->
field
[
0
]
->
store
(
iRef
,
1
);
pTls
->
m_bCondDone
=
true
;
SPH_RET
(
0
);
}
// parse query
if
(
pTls
->
m_bQuery
)
{
...
...
@@ -2464,7 +2840,7 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
}
// do connect
int
iSocket
=
Connect
ToSearchd
(
q
.
m_sHost
,
q
.
m_iPort
);
int
iSocket
=
Connect
API
(
q
.
m_sHost
,
q
.
m_iPort
);
if
(
iSocket
<
0
)
SPH_RET
(
HA_ERR_END_OF_FILE
);
...
...
@@ -2602,7 +2978,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
if
(
m_iCurrentPos
>=
m_iMatchesTotal
)
{
SafeDeleteArray
(
m_pResponse
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
}
#if MYSQL_VERSION_ID>50100
...
...
@@ -2622,16 +2998,21 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
for
(
uint32
i
=
0
;
i
<
m_iAttrs
;
i
++
)
{
longlong
iValue64
;
longlong
iValue64
=
0
;
uint32
uValue
=
UnpackDword
();
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_BIGINT
)
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_BIGINT
)
iValue64
=
(
(
longlong
)
uValue
<<
32
)
|
UnpackDword
();
if
(
m_dAttrs
[
i
].
m_iField
<
0
)
{
// skip MVA
if
(
m_dAttrs
[
i
].
m_uType
&
SPH_ATTR_MULTI
)
// skip MVA or String
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_UINT32SET
||
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_UINT64SET
)
{
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
UnpackDword
();
}
else
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_STRING
&&
CheckResponcePtr
(
uValue
)
)
{
m_pCur
+=
uValue
;
}
continue
;
}
...
...
@@ -2659,7 +3040,18 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
af
->
store
(
iValue64
,
0
);
break
;
case
(
SPH_ATTR_MULTI
|
SPH_ATTR_INTEGER
):
case
SPH_ATTR_STRING
:
if
(
!
uValue
)
af
->
store
(
""
,
0
,
&
my_charset_bin
);
else
if
(
CheckResponcePtr
(
uValue
)
)
{
af
->
store
(
m_pCur
,
uValue
,
&
my_charset_bin
);
m_pCur
+=
uValue
;
}
break
;
case
SPH_ATTR_UINT64SET
:
case
SPH_ATTR_UINT32SET
:
if
(
uValue
<=
0
)
{
// shortcut, empty MVA set
...
...
@@ -2671,15 +3063,32 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
char
sBuf
[
1024
];
// FIXME! magic size
char
*
pCur
=
sBuf
;
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_UINT32SET
)
{
uint32
uEntry
=
UnpackDword
();
if
(
pCur
<
sBuf
+
sizeof
(
sBuf
)
-
16
)
// 10 chars per 32bit value plus some safety bytes
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
{
sprintf
(
pCur
,
"%u"
,
uEntry
);
while
(
*
pCur
)
*
pCur
++
;
if
(
uValue
>
1
)
*
pCur
++
=
','
;
// non-trailing commas
uint32
uEntry
=
UnpackDword
();
if
(
pCur
<
sBuf
+
sizeof
(
sBuf
)
-
16
)
// 10 chars per 32bit value plus some safety bytes
{
snprintf
(
pCur
,
sBuf
+
sizeof
(
sBuf
)
-
pCur
,
"%u"
,
uEntry
);
while
(
*
pCur
)
*
pCur
++
;
if
(
uValue
>
1
)
*
pCur
++
=
','
;
// non-trailing commas
}
}
}
else
{
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
-=
2
)
{
uint32
uEntryLo
=
UnpackDword
();
uint32
uEntryHi
=
UnpackDword
();
if
(
pCur
<
sBuf
+
sizeof
(
sBuf
)
-
24
)
// 20 chars per 64bit value plus some safety bytes
{
snprintf
(
pCur
,
sBuf
+
sizeof
(
sBuf
)
-
pCur
,
"%u%u"
,
uEntryHi
,
uEntryLo
);
while
(
*
pCur
)
*
pCur
++
;
if
(
uValue
>
2
)
*
pCur
++
=
','
;
// non-trailing commas
}
}
}
...
...
@@ -2690,7 +3099,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
default:
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: unhandled attr type"
);
SafeDeleteArray
(
m_pResponse
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
}
}
...
...
@@ -2698,7 +3107,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
{
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: response unpacker failed"
);
SafeDeleteArray
(
m_pResponse
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
}
// zero out unmapped fields
...
...
@@ -2719,7 +3128,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
m_iCurrentPos
++
;
#if MYSQL_VERSION_ID > 50100
dbug_tmp_restore_column_map
(
table
->
write_set
,
org_bitmap
);
dbug_tmp_restore_column_map
(
table
->
write_set
,
org_bitmap
);
#endif
SPH_RET
(
0
);
...
...
@@ -2859,7 +3268,7 @@ THR_LOCK_DATA ** ha_sphinx::store_lock ( THD *, THR_LOCK_DATA ** to,
SPH_ENTER_METHOD
();
if
(
lock_type
!=
TL_IGNORE
&&
m_tLock
.
type
==
TL_UNLOCK
)
m_tLock
.
type
=
lock_type
;
m_tLock
.
type
=
lock_type
;
*
to
++
=
&
m_tLock
;
SPH_RET
(
to
);
...
...
@@ -2898,12 +3307,9 @@ ha_rows ha_sphinx::records_in_range ( uint, key_range *, key_range * )
SPH_RET
(
3
);
// low number to force index usage
}
static
inline
bool
IsIntegerFieldType
(
enum_field_types
eType
)
{
return
eType
==
MYSQL_TYPE_LONG
||
eType
==
MYSQL_TYPE_LONGLONG
;
}
#if MYSQL_VERSION_ID < 50610
#define user_defined_key_parts key_parts
#endif
// create() is called to create a database. The variable name will have the name
// of the table. When create() is called you do not need to worry about opening
...
...
@@ -2918,10 +3324,12 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
SPH_ENTER_METHOD
();
char
sError
[
256
];
if
(
!
ParseUrl
(
NULL
,
table
,
true
)
)
CSphSEShare
tInfo
;
if
(
!
ParseUrl
(
&
tInfo
,
table
,
true
)
)
SPH_RET
(
-
1
);
for
(
;;
)
// check SphinxAPI table
for
(
;
!
tInfo
.
m_bSphinxQL
;
)
{
// check system fields (count and types)
if
(
table
->
s
->
fields
<
SPHINXSE_SYSTEM_COLUMNS
)
...
...
@@ -2931,7 +3339,7 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
break
;
}
if
(
!
IsI
ntegerFieldType
(
table
->
field
[
0
]
->
type
()
)
||
!
((
Field_num
*
)
table
->
field
[
0
])
->
unsigned_flag
)
if
(
!
IsI
DField
(
table
->
field
[
0
]
)
)
{
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: 1st column (docid) MUST be unsigned integer or bigint"
,
name
);
break
;
...
...
@@ -2970,7 +3378,7 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
// check index
if
(
table
->
s
->
keys
!=
1
||
table
->
key_info
[
0
].
key_parts
!=
1
||
table
->
key_info
[
0
].
user_defined_
key_parts
!=
1
||
strcasecmp
(
table
->
key_info
[
0
].
key_part
[
0
].
field
->
field_name
,
table
->
field
[
2
]
->
field_name
)
)
{
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: there must be an index on '%s' column"
,
...
...
@@ -2982,6 +3390,54 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
sError
[
0
]
=
'\0'
;
break
;
}
// check SphinxQL table
for
(
;
tInfo
.
m_bSphinxQL
;
)
{
sError
[
0
]
=
'\0'
;
// check that 1st column is id, is of int type, and has an index
if
(
strcmp
(
table
->
field
[
0
]
->
field_name
,
"id"
)
)
{
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: 1st column must be called 'id'"
,
name
);
break
;
}
if
(
!
IsIDField
(
table
->
field
[
0
]
)
)
{
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: 'id' column must be INT UNSIGNED or BIGINT"
,
name
);
break
;
}
// check index
if
(
table
->
s
->
keys
!=
1
||
table
->
key_info
[
0
].
user_defined_key_parts
!=
1
||
strcasecmp
(
table
->
key_info
[
0
].
key_part
[
0
].
field
->
field_name
,
"id"
)
)
{
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: 'id' column must be indexed"
,
name
);
break
;
}
// check column types
for
(
int
i
=
1
;
i
<
(
int
)
table
->
s
->
fields
;
i
++
)
{
enum_field_types
eType
=
table
->
field
[
i
]
->
type
();
if
(
eType
!=
MYSQL_TYPE_TIMESTAMP
&&
!
IsIntegerFieldType
(
eType
)
&&
eType
!=
MYSQL_TYPE_VARCHAR
&&
eType
!=
MYSQL_TYPE_FLOAT
)
{
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: column %d(%s) is of unsupported type (use int/bigint/timestamp/varchar/float)"
,
name
,
i
+
1
,
table
->
field
[
i
]
->
field_name
);
break
;
}
}
if
(
sError
[
0
]
)
break
;
// all good
break
;
}
// report and bail
if
(
sError
[
0
]
)
{
my_error
(
ER_CANT_CREATE_TABLE
,
MYF
(
0
),
sError
,
-
1
);
...
...
@@ -2991,15 +3447,15 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
SPH_RET
(
0
);
}
//
//
show functions
// show functions
#if MYSQL_VERSION_ID<50100
#if MYSQL_VERSION_ID<50100
#define SHOW_VAR_FUNC_BUFF_SIZE 1024
#endif
CSphSEStats
*
sphinx_get_stats
(
THD
*
thd
,
SHOW_VAR
*
out
)
{
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>50100
if
(
sphinx_hton_ptr
)
{
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
*
thd_ha_data
(
thd
,
sphinx_hton_ptr
);
...
...
@@ -3012,7 +3468,7 @@ CSphSEStats * sphinx_get_stats ( THD * thd, SHOW_VAR * out )
if
(
pTls
&&
pTls
->
m_bStats
)
return
&
pTls
->
m_tStats
;
#endif
out
->
type
=
SHOW_CHAR
;
out
->
value
=
""
;
return
0
;
...
...
@@ -3064,24 +3520,24 @@ int sphinx_showfunc_word_count ( THD * thd, SHOW_VAR * out, char * )
int
sphinx_showfunc_words
(
THD
*
thd
,
SHOW_VAR
*
out
,
char
*
sBuffer
)
{
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>50100
if
(
sphinx_hton_ptr
)
{
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
*
thd_ha_data
(
thd
,
sphinx_hton_ptr
);
#else
{
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
thd
->
ha_data
[
sphinx_hton
.
slot
];
#endif
#endif
if
(
pTls
&&
pTls
->
m_bStats
)
{
CSphSEStats
*
pStats
=
&
pTls
->
m_tStats
;
if
(
pStats
&&
pStats
->
m_iWords
)
{
uint
uBuffLen
=
0
;
out
->
type
=
SHOW_CHAR
;
out
->
value
=
sBuffer
;
// the following is partially based on code in sphinx_show_status()
sBuffer
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
pStats
->
m_iWords
;
i
++
)
...
...
@@ -3095,13 +3551,13 @@ int sphinx_showfunc_words ( THD * thd, SHOW_VAR * out, char * sBuffer )
{
// trim last space
sBuffer
[
--
uBuffLen
]
=
0
;
if
(
pTls
->
m_pQueryCharset
)
{
// String::c_ptr() will nul-terminate the buffer.
//
// NOTE: It's not entirely clear whether this conversion is necessary at all.
String
sConvert
;
uint
iErrors
;
sConvert
.
copy
(
sBuffer
,
uBuffLen
,
pTls
->
m_pQueryCharset
,
system_charset_info
,
&
iErrors
);
...
...
@@ -3129,7 +3585,7 @@ int sphinx_showfunc_error ( THD * thd, SHOW_VAR * out, char * )
}
return
0
;
}
#if MYSQL_VERSION_ID>50100
struct
st_mysql_storage_engine
sphinx_storage_engine
=
{
...
...
@@ -3168,5 +3624,5 @@ mysql_declare_plugin_end;
#endif // >50100
//
// $Id$
// $Id
: ha_sphinx.cc 4507 2014-01-22 15:24:34Z deogar
$
//
ha_sphinx.h
View file @
01673997
//
// $Id$
// $Id
: ha_sphinx.h 3866 2013-05-22 11:54:20Z kevg
$
//
#ifdef USE_PRAGMA_INTERFACE
...
...
@@ -7,7 +7,9 @@
#endif
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>=50515
#define TABLE_ARG TABLE_SHARE
#elif MYSQL_VERSION_ID>50100
#define TABLE_ARG st_table_share
#else
#define TABLE_ARG st_table
...
...
@@ -47,7 +49,7 @@ protected:
public:
#if MYSQL_VERSION_ID<50100
ha_sphinx
(
TABLE_ARG
*
table_arg
);
ha_sphinx
(
TABLE_ARG
*
table_arg
);
// NOLINT
#else
ha_sphinx
(
handlerton
*
hton
,
TABLE_ARG
*
table_arg
);
#endif
...
...
@@ -82,14 +84,15 @@ public:
int
open
(
const
char
*
name
,
int
mode
,
uint
test_if_locked
);
int
close
();
int
write_row
(
uchar
*
buf
);
int
update_row
(
const
uchar
*
old_data
,
uchar
*
new_data
);
int
delete_row
(
const
uchar
*
buf
);
int
write_row
(
byte
*
buf
);
int
update_row
(
const
byte
*
old_data
,
byte
*
new_data
);
int
delete_row
(
const
byte
*
buf
);
int
extra
(
enum
ha_extra_function
op
);
int
index_init
(
uint
keynr
,
bool
sorted
);
// 5.1.x
int
index_init
(
uint
keynr
)
{
return
index_init
(
keynr
,
false
);
}
// 5.0.x
int
index_end
();
int
index_end
();
int
index_read
(
byte
*
buf
,
const
byte
*
key
,
uint
key_len
,
enum
ha_rkey_function
find_flag
);
int
index_read_idx
(
byte
*
buf
,
uint
idx
,
const
byte
*
key
,
uint
key_len
,
enum
ha_rkey_function
find_flag
);
int
index_next
(
byte
*
buf
);
...
...
@@ -121,10 +124,14 @@ public:
int
rename_table
(
const
char
*
from
,
const
char
*
to
);
int
create
(
const
char
*
name
,
TABLE
*
form
,
HA_CREATE_INFO
*
create_info
);
THR_LOCK_DATA
**
store_lock
(
THD
*
thd
,
THR_LOCK_DATA
**
to
,
enum
thr_lock_type
lock_type
);
THR_LOCK_DATA
**
store_lock
(
THD
*
thd
,
THR_LOCK_DATA
**
to
,
enum
thr_lock_type
lock_type
);
public:
#if MYSQL_VERSION_ID<50610
virtual
const
COND
*
cond_push
(
const
COND
*
cond
);
#else
virtual
const
Item
*
cond_push
(
const
Item
*
cond
);
#endif
virtual
void
cond_pop
();
private:
...
...
@@ -138,12 +145,15 @@ private:
int
*
m_dUnboundFields
;
private:
int
ConnectToSearchd
(
const
char
*
sQueryHost
,
int
iQueryPort
);
int
Connect
(
const
char
*
sQueryHost
,
ushort
uPort
);
int
ConnectAPI
(
const
char
*
sQueryHost
,
int
iQueryPort
);
int
HandleMysqlError
(
struct
st_mysql
*
pConn
,
int
iErrCode
);
uint32
UnpackDword
();
char
*
UnpackString
();
bool
UnpackSchema
();
bool
UnpackStats
(
CSphSEStats
*
pStats
);
bool
CheckResponcePtr
(
int
iLen
);
CSphSEThreadData
*
GetTls
();
};
...
...
@@ -160,5 +170,5 @@ int sphinx_showfunc_word_count ( THD *, SHOW_VAR *, char * );
int
sphinx_showfunc_words
(
THD
*
,
SHOW_VAR
*
,
char
*
);
//
// $Id$
// $Id
: ha_sphinx.h 3866 2013-05-22 11:54:20Z kevg
$
//
make-patch.sh
100644 → 100755
View file @
01673997
File mode changed from 100644 to 100755
snippets_udf.cc
View file @
01673997
//
// $Id$
//
//
// Copyright (c) 2001-2008, Andrew Aksyonoff. All rights reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License. You should have
// received a copy of the GPL license along with this program; if you
// did not, you can find it at http://www.gnu.org/
//
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/un.h>
#include <netdb.h>
#include <mysql_version.h>
#if MYSQL_VERSION_ID>50100
#include "mysql_priv.h"
#include <mysql/plugin.h>
#else
#include "../mysql_priv.h"
#endif
#include <mysys_err.h>
#include <my_sys.h>
#if MYSQL_VERSION_ID>=50120
typedef
uchar
byte
;
#endif
/// partially copy-pasted stuff that should be moved elsewhere
#if UNALIGNED_RAM_ACCESS
/// pass-through wrapper
template
<
typename
T
>
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
{
return
tRef
;
}
/// pass-through wrapper
template
<
typename
T
>
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
{
*
(
T
*
)
pPtr
=
tVal
;
}
#else
/// unaligned read wrapper for some architectures (eg. SPARC)
template
<
typename
T
>
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
{
T
uTmp
;
byte
*
pSrc
=
(
byte
*
)
&
tRef
;
byte
*
pDst
=
(
byte
*
)
&
uTmp
;
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
*
pDst
++
=
*
pSrc
++
;
return
uTmp
;
}
/// unaligned write wrapper for some architectures (eg. SPARC)
template
<
typename
T
>
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
{
byte
*
pDst
=
(
byte
*
)
pPtr
;
byte
*
pSrc
=
(
byte
*
)
&
tVal
;
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
*
pDst
++
=
*
pSrc
++
;
}
#endif
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
#define SafeDelete(_arg) { if ( _arg ) delete ( _arg ); (_arg) = NULL; }
#define SafeDeleteArray(_arg) { if ( _arg ) delete [] ( _arg ); (_arg) = NULL; }
#define Min(a,b) ((a)<(b)?(a):(b))
typedef
unsigned
int
DWORD
;
inline
DWORD
sphF2DW
(
float
f
)
{
union
{
float
f
;
uint32
d
;
}
u
;
u
.
f
=
f
;
return
u
.
d
;
}
static
char
*
sphDup
(
const
char
*
sSrc
,
int
iLen
=-
1
)
{
if
(
!
sSrc
)
return
NULL
;
if
(
iLen
<
0
)
iLen
=
strlen
(
sSrc
);
char
*
sRes
=
new
char
[
1
+
iLen
];
memcpy
(
sRes
,
sSrc
,
iLen
);
sRes
[
iLen
]
=
'\0'
;
return
sRes
;
}
static
inline
void
sphShowErrno
(
const
char
*
sCall
)
{
char
sError
[
256
];
snprintf
(
sError
,
sizeof
(
sError
),
"%s() failed: [%d] %s"
,
sCall
,
errno
,
strerror
(
errno
)
);
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
}
static
const
bool
sphReportErrors
=
true
;
static
bool
sphSend
(
int
iFd
,
const
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
{
assert
(
pBuffer
);
assert
(
iSize
>
0
);
const
int
iResult
=
send
(
iFd
,
pBuffer
,
iSize
,
0
);
if
(
iResult
!=
iSize
)
{
if
(
bReportErrors
)
sphShowErrno
(
"send"
);
return
false
;
}
return
true
;
}
static
bool
sphRecv
(
int
iFd
,
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
{
assert
(
pBuffer
);
assert
(
iSize
>
0
);
while
(
iSize
)
{
const
int
iResult
=
recv
(
iFd
,
pBuffer
,
iSize
,
0
);
if
(
iResult
>
0
)
{
iSize
-=
iResult
;
pBuffer
+=
iSize
;
}
else
if
(
iResult
==
0
)
{
if
(
bReportErrors
)
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"recv() failed: disconnected"
);
return
false
;
}
else
{
if
(
bReportErrors
)
sphShowErrno
(
"recv"
);
return
false
;
}
}
return
true
;
}
enum
{
SPHINX_SEARCHD_PROTO
=
1
,
SEARCHD_COMMAND_SEARCH
=
0
,
SEARCHD_COMMAND_EXCERPT
=
1
,
VER_COMMAND_SEARCH
=
0x116
,
VER_COMMAND_EXCERPT
=
0x100
,
};
/// known answers
enum
{
SEARCHD_OK
=
0
,
///< general success, command-specific reply follows
SEARCHD_ERROR
=
1
,
///< general failure, error message follows
SEARCHD_RETRY
=
2
,
///< temporary failure, error message follows, client should retry later
SEARCHD_WARNING
=
3
///< general success, warning message and command-specific reply follow
};
#define SPHINXSE_DEFAULT_SCHEME "sphinx"
#define SPHINXSE_DEFAULT_HOST "127.0.0.1"
#define SPHINXSE_DEFAULT_PORT 9312
#define SPHINXSE_DEFAULT_INDEX "*"
class
CSphBuffer
{
private:
bool
m_bOverrun
;
int
m_iSize
;
int
m_iLeft
;
char
*
m_pBuffer
;
char
*
m_pCurrent
;
public:
CSphBuffer
(
const
int
iSize
)
:
m_bOverrun
(
false
)
,
m_iSize
(
iSize
)
,
m_iLeft
(
iSize
)
{
assert
(
iSize
>
0
);
m_pBuffer
=
new
char
[
iSize
];
m_pCurrent
=
m_pBuffer
;
}
~
CSphBuffer
()
{
SafeDelete
(
m_pBuffer
);
}
const
char
*
Ptr
()
const
{
return
m_pBuffer
;
}
bool
Finalize
()
{
return
!
(
m_bOverrun
||
m_iLeft
!=
0
||
m_pCurrent
-
m_pBuffer
!=
m_iSize
);
}
void
SendBytes
(
const
void
*
pBytes
,
int
iBytes
);
void
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendDword
(
DWORD
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
uint
(
v
>>
32
)
);
SendDword
(
uint
(
v
&
0xFFFFFFFFUL
)
);
}
void
SendString
(
const
char
*
v
)
{
SendString
(
v
,
strlen
(
v
)
);
}
void
SendString
(
const
char
*
v
,
int
iLen
)
{
SendDword
(
iLen
);
SendBytes
(
v
,
iLen
);
}
void
SendFloat
(
float
v
)
{
SendDword
(
sphF2DW
(
v
)
);
}
};
void
CSphBuffer
::
SendBytes
(
const
void
*
pBytes
,
int
iBytes
)
{
if
(
m_iLeft
<
iBytes
)
{
m_bOverrun
=
true
;
return
;
}
memcpy
(
m_pCurrent
,
pBytes
,
iBytes
);
m_pCurrent
+=
iBytes
;
m_iLeft
-=
iBytes
;
}
struct
CSphUrl
{
char
*
m_sBuffer
;
char
*
m_sFormatted
;
char
*
m_sScheme
;
char
*
m_sHost
;
char
*
m_sIndex
;
int
m_iPort
;
CSphUrl
()
:
m_sBuffer
(
NULL
)
,
m_sFormatted
(
NULL
)
,
m_sScheme
(
SPHINXSE_DEFAULT_SCHEME
)
,
m_sHost
(
SPHINXSE_DEFAULT_HOST
)
,
m_sIndex
(
SPHINXSE_DEFAULT_INDEX
)
,
m_iPort
(
SPHINXSE_DEFAULT_PORT
)
{}
~
CSphUrl
()
{
SafeDeleteArray
(
m_sFormatted
);
SafeDeleteArray
(
m_sBuffer
);
}
bool
Parse
(
const
char
*
sUrl
,
int
iLen
);
int
Connect
();
const
char
*
Format
();
};
const
char
*
CSphUrl
::
Format
()
{
if
(
!
m_sFormatted
)
{
int
iSize
=
15
+
strlen
(
m_sHost
)
+
strlen
(
m_sIndex
);
m_sFormatted
=
new
char
[
iSize
];
if
(
m_iPort
)
snprintf
(
m_sFormatted
,
iSize
,
"inet://%s:%d/%s"
,
m_sHost
,
m_iPort
,
m_sIndex
);
else
snprintf
(
m_sFormatted
,
iSize
,
"unix://%s/%s"
,
m_sHost
,
m_sIndex
);
}
return
m_sFormatted
;
}
// the following scheme variants are recognized
//
// inet://host/index
// inet://host:port/index
// unix://unix/domain/socket:index
// unix://unix/domain/socket
bool
CSphUrl
::
Parse
(
const
char
*
sUrl
,
int
iLen
)
{
bool
bOk
=
true
;
while
(
iLen
)
{
bOk
=
false
;
m_sBuffer
=
sphDup
(
sUrl
,
iLen
);
m_sScheme
=
m_sBuffer
;
m_sHost
=
strstr
(
m_sBuffer
,
"://"
);
if
(
!
m_sHost
)
break
;
m_sHost
[
0
]
=
'\0'
;
m_sHost
+=
2
;
if
(
!
strcmp
(
m_sScheme
,
"unix"
)
)
{
// unix-domain socket
m_iPort
=
0
;
if
(
!
(
m_sIndex
=
strrchr
(
m_sHost
,
':'
)
))
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
else
{
*
m_sIndex
++
=
'\0'
;
if
(
!*
m_sIndex
)
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
}
if
(
strcmp
(
m_sScheme
,
"sphinx"
)
!=
0
&&
strcmp
(
m_sScheme
,
"inet"
)
!=
0
)
break
;
// inet
m_sHost
++
;
char
*
sPort
=
strchr
(
m_sHost
,
':'
);
if
(
sPort
)
{
*
sPort
++
=
'\0'
;
if
(
*
sPort
)
{
m_sIndex
=
strchr
(
sPort
,
'/'
);
if
(
m_sIndex
)
*
m_sIndex
++
=
'\0'
;
else
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
m_iPort
=
atoi
(
sPort
);
if
(
!
m_iPort
)
m_iPort
=
SPHINXSE_DEFAULT_PORT
;
}
}
else
{
m_sIndex
=
strchr
(
m_sHost
,
'/'
);
if
(
m_sIndex
)
*
m_sIndex
++
=
'\0'
;
else
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
}
return
bOk
;
}
int
CSphUrl
::
Connect
()
{
struct
sockaddr_in
sin
;
#ifndef __WIN__
struct
sockaddr_un
saun
;
#endif
int
iDomain
=
0
;
int
iSockaddrSize
=
0
;
struct
sockaddr
*
pSockaddr
=
NULL
;
in_addr_t
ip_addr
;
if
(
m_iPort
)
{
iDomain
=
AF_INET
;
iSockaddrSize
=
sizeof
(
sin
);
pSockaddr
=
(
struct
sockaddr
*
)
&
sin
;
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
sin
.
sin_family
=
AF_INET
;
sin
.
sin_port
=
htons
(
m_iPort
);
// resolve address
if
(
(
int
)(
ip_addr
=
inet_addr
(
m_sHost
)
)
!=
(
int
)
INADDR_NONE
)
memcpy
(
&
sin
.
sin_addr
,
&
ip_addr
,
sizeof
(
ip_addr
)
);
else
{
int
tmp_errno
;
struct
hostent
tmp_hostent
,
*
hp
;
char
buff2
[
GETHOSTBYNAME_BUFF_SIZE
];
hp
=
my_gethostbyname_r
(
m_sHost
,
&
tmp_hostent
,
buff2
,
sizeof
(
buff2
),
&
tmp_errno
);
if
(
!
hp
)
{
my_gethostbyname_r_free
();
char
sError
[
256
];
snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
m_sHost
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
return
-
1
;
}
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
my_gethostbyname_r_free
();
}
}
else
{
#ifndef __WIN__
iDomain
=
AF_UNIX
;
iSockaddrSize
=
sizeof
(
saun
);
pSockaddr
=
(
struct
sockaddr
*
)
&
saun
;
memset
(
&
saun
,
0
,
sizeof
(
saun
)
);
saun
.
sun_family
=
AF_UNIX
;
strncpy
(
saun
.
sun_path
,
m_sHost
,
sizeof
(
saun
.
sun_path
)
-
1
);
#else
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"Unix-domain sockets are not supported on Windows"
);
return
-
1
;
#endif
}
// connect to searchd and exchange versions
uint
uServerVersion
;
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
int
iSocket
=
-
1
;
char
*
pError
=
NULL
;
do
{
iSocket
=
socket
(
iDomain
,
SOCK_STREAM
,
0
);
if
(
iSocket
==
-
1
)
{
pError
=
"Failed to create client socket"
;
break
;
}
if
(
connect
(
iSocket
,
pSockaddr
,
iSockaddrSize
)
==
-
1
)
{
pError
=
"Failed to connect to searchd"
;
break
;
}
if
(
!
sphRecv
(
iSocket
,
(
char
*
)
&
uServerVersion
,
sizeof
(
uServerVersion
)
)
)
{
pError
=
"Failed to receive searchd version"
;
break
;
}
if
(
!
sphSend
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
)
)
)
{
pError
=
"Failed to send client version"
;
break
;
}
}
while
(
0
);
// fixme: compare versions?
if
(
pError
)
{
char
sError
[
1024
];
snprintf
(
sError
,
sizeof
(
sError
),
"%s [%d] %s"
,
Format
(),
errno
,
strerror
(
errno
)
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
if
(
iSocket
!=
-
1
)
close
(
iSocket
);
return
-
1
;
}
return
iSocket
;
}
struct
CSphResponse
{
char
*
m_pBuffer
;
char
*
m_pBody
;
CSphResponse
()
:
m_pBuffer
(
NULL
)
,
m_pBody
(
NULL
)
{}
CSphResponse
(
DWORD
uSize
)
:
m_pBody
(
NULL
)
{
m_pBuffer
=
new
char
[
uSize
];
}
~
CSphResponse
()
{
SafeDeleteArray
(
m_pBuffer
);
}
static
CSphResponse
*
Read
(
int
iSocket
,
int
iClientVersion
);
};
CSphResponse
*
CSphResponse
::
Read
(
int
iSocket
,
int
iClientVersion
)
{
char
sHeader
[
8
];
if
(
!
sphRecv
(
iSocket
,
sHeader
,
sizeof
(
sHeader
)
)
)
return
NULL
;
int
iStatus
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
0
]
)
);
int
iVersion
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
2
]
)
);
DWORD
uLength
=
ntohl
(
sphUnalignedRead
(
*
(
DWORD
*
)
&
sHeader
[
4
]
)
);
if
(
iVersion
<
iClientVersion
)
// fixme: warn
;
if
(
uLength
<=
SPHINXSE_MAX_ALLOC
)
{
CSphResponse
*
pResponse
=
new
CSphResponse
(
uLength
);
if
(
!
sphRecv
(
iSocket
,
pResponse
->
m_pBuffer
,
uLength
)
)
{
SafeDelete
(
pResponse
);
return
NULL
;
}
pResponse
->
m_pBody
=
pResponse
->
m_pBuffer
;
if
(
iStatus
!=
SEARCHD_OK
)
{
DWORD
uSize
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBuffer
);
if
(
iStatus
==
SEARCHD_WARNING
)
pResponse
->
m_pBody
+=
uSize
;
// fixme: report the warning somehow
else
{
char
*
sMessage
=
sphDup
(
pResponse
->
m_pBuffer
+
sizeof
(
DWORD
),
uSize
);
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sMessage
);
SafeDelete
(
sMessage
);
SafeDelete
(
pResponse
);
return
NULL
;
}
}
return
pResponse
;
}
return
NULL
;
}
/// udf
extern
"C"
{
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
);
void
sphinx_snippets_deinit
(
UDF_INIT
*
pUDF
);
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
sError
);
};
#define MAX_MESSAGE_LENGTH 255
#define MAX_RESULT_LENGTH 255
struct
CSphSnippets
{
CSphUrl
m_tUrl
;
CSphResponse
*
m_pResponse
;
int
m_iBeforeMatch
;
int
m_iAfterMatch
;
int
m_iChunkSeparator
;
int
m_iLimit
;
int
m_iAround
;
int
m_iFlags
;
CSphSnippets
()
:
m_pResponse
(
NULL
)
,
m_iBeforeMatch
(
0
)
,
m_iAfterMatch
(
0
)
,
m_iChunkSeparator
(
0
)
// defaults
,
m_iLimit
(
256
)
,
m_iAround
(
5
)
,
m_iFlags
(
1
)
{
}
~
CSphSnippets
()
{
SafeDelete
(
m_pResponse
);
}
};
#define KEYWORD(NAME) else if ( strncmp ( NAME, pArgs->attributes[i], pArgs->attribute_lengths[i] ) == 0 )
#define CHECK_TYPE(TYPE) \
if
(
pArgs
->
arg_type
[
i
]
!=
TYPE
)
\
{
\
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
\
"%.*s argument must be a string"
,
\
(
int
)
pArgs
->
attribute_lengths
[
i
],
\
pArgs
->
attributes
[
i
]
);
\
bFail
=
true
;
\
break
;
\
}
\
if
(
TYPE
==
STRING_RESULT
&&
!
pArgs
->
args
[
i
]
)
\
{
\
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
\
"%.*s argument must be constant (and not NULL)"
,
\
(
int
)
pArgs
->
attribute_lengths
[
i
],
\
pArgs
->
attributes
[
i
]
);
\
bFail
=
true
;
\
break
;
\
}
#define STRING CHECK_TYPE(STRING_RESULT)
#define INT CHECK_TYPE(INT_RESULT); int iValue = *(long long *)pArgs->args[i]
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
)
{
if
(
pArgs
->
arg_count
<
3
)
{
strncpy
(
sMessage
,
"insufficient arguments"
,
MAX_MESSAGE_LENGTH
);
return
1
;
}
bool
bFail
=
false
;
CSphSnippets
*
pOpts
=
new
CSphSnippets
;
for
(
uint
i
=
0
;
i
<
pArgs
->
arg_count
;
i
++
)
{
if
(
i
<
3
)
{
if
(
pArgs
->
arg_type
[
i
]
!=
STRING_RESULT
)
{
strncpy
(
sMessage
,
"first three arguments must be of string type"
,
MAX_MESSAGE_LENGTH
);
bFail
=
true
;
break
;
}
}
KEYWORD
(
"sphinx"
)
{
STRING
;
if
(
!
pOpts
->
m_tUrl
.
Parse
(
pArgs
->
args
[
i
],
pArgs
->
lengths
[
i
]
)
)
{
strncpy
(
sMessage
,
"failed to parse connection string"
,
MAX_MESSAGE_LENGTH
);
bFail
=
true
;
break
;
}
}
KEYWORD
(
"before_match"
)
{
STRING
;
pOpts
->
m_iBeforeMatch
=
i
;
}
KEYWORD
(
"after_match"
)
{
STRING
;
pOpts
->
m_iAfterMatch
=
i
;
}
KEYWORD
(
"chunk_separator"
)
{
STRING
;
pOpts
->
m_iChunkSeparator
=
i
;
}
KEYWORD
(
"limit"
)
{
INT
;
pOpts
->
m_iLimit
=
iValue
;
}
KEYWORD
(
"around"
)
{
INT
;
pOpts
->
m_iAround
=
iValue
;
}
KEYWORD
(
"exact_phrase"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
2
;
}
KEYWORD
(
"single_passage"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
4
;
}
KEYWORD
(
"use_boundaries"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
8
;
}
KEYWORD
(
"weight_order"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
16
;
}
else
{
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
"unrecognized argument: %.*s"
,
(
int
)
pArgs
->
attribute_lengths
[
i
],
pArgs
->
attributes
[
i
]
);
bFail
=
true
;
break
;
}
}
if
(
bFail
)
{
SafeDelete
(
pOpts
);
return
1
;
}
pUDF
->
ptr
=
(
char
*
)
pOpts
;
return
0
;
}
#undef STRING
#undef INT
#undef KEYWORD
#undef CHECK_TYPE
#define ARG(i) pArgs->args[i], pArgs->lengths[i]
#define ARG_LEN(VAR, LEN) ( VAR ? pArgs->lengths[VAR] : LEN )
#define SEND_STRING(INDEX, DEFAULT) \
if
(
INDEX
)
\
tBuffer
.
SendString
(
ARG
(
INDEX
)
);
\
else
\
tBuffer
.
SendString
(
DEFAULT
,
sizeof
(
DEFAULT
)
-
1
);
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
pError
)
{
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
assert
(
pOpts
);
if
(
!
pArgs
->
args
[
0
]
||
!
pArgs
->
args
[
1
]
||
!
pArgs
->
args
[
2
]
)
{
*
pIsNull
=
1
;
return
sResult
;
}
const
int
iSize
=
8
+
// header
8
+
4
+
pArgs
->
lengths
[
1
]
+
// index
4
+
pArgs
->
lengths
[
2
]
+
// words
4
+
ARG_LEN
(
pOpts
->
m_iBeforeMatch
,
3
)
+
4
+
ARG_LEN
(
pOpts
->
m_iAfterMatch
,
4
)
+
4
+
ARG_LEN
(
pOpts
->
m_iChunkSeparator
,
5
)
+
12
+
4
+
pArgs
->
lengths
[
0
];
// document
CSphBuffer
tBuffer
(
iSize
);
tBuffer
.
SendWord
(
SEARCHD_COMMAND_EXCERPT
);
tBuffer
.
SendWord
(
VER_COMMAND_EXCERPT
);
tBuffer
.
SendDword
(
iSize
-
8
);
tBuffer
.
SendDword
(
0
);
tBuffer
.
SendDword
(
pOpts
->
m_iFlags
);
tBuffer
.
SendString
(
ARG
(
1
)
);
// index
tBuffer
.
SendString
(
ARG
(
2
)
);
// words
SEND_STRING
(
pOpts
->
m_iBeforeMatch
,
"<b>"
);
SEND_STRING
(
pOpts
->
m_iAfterMatch
,
"</b>"
);
SEND_STRING
(
pOpts
->
m_iChunkSeparator
,
" ... "
);
tBuffer
.
SendInt
(
pOpts
->
m_iLimit
);
tBuffer
.
SendInt
(
pOpts
->
m_iAround
);
// single document
tBuffer
.
SendInt
(
1
);
tBuffer
.
SendString
(
ARG
(
0
)
);
int
iSocket
=
-
1
;
do
{
if
(
!
tBuffer
.
Finalize
()
)
{
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: failed to build request"
);
break
;
}
iSocket
=
pOpts
->
m_tUrl
.
Connect
();
if
(
iSocket
==
-
1
)
break
;
if
(
!
sphSend
(
iSocket
,
tBuffer
.
Ptr
(),
iSize
,
sphReportErrors
)
)
break
;
CSphResponse
*
pResponse
=
CSphResponse
::
Read
(
iSocket
,
0x100
);
if
(
!
pResponse
)
break
;
close
(
iSocket
);
pOpts
->
m_pResponse
=
pResponse
;
*
pLength
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBody
);
return
pResponse
->
m_pBody
+
sizeof
(
DWORD
);
}
while
(
0
);
if
(
iSocket
!=
-
1
)
close
(
iSocket
);
*
pError
=
1
;
return
sResult
;
}
#undef SEND_STRING
#undef ARG_LEN
#undef ARG
void
sphinx_snippets_deinit
(
UDF_INIT
*
pUDF
)
{
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
SafeDelete
(
pOpts
);
}
//
// $Id$
//
//
// $Id: snippets_udf.cc 4505 2014-01-22 15:16:21Z deogar $
//
//
// Copyright (c) 2001-2014, Andrew Aksyonoff
// Copyright (c) 2008-2014, Sphinx Technologies Inc
// All rights reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License. You should have
// received a copy of the GPL license along with this program; if you
// did not, you can find it at http://www.gnu.org/
//
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/un.h>
#include <netdb.h>
#include <mysql_version.h>
#if MYSQL_VERSION_ID>=50515
#include "sql_class.h"
#include "sql_array.h"
#elif MYSQL_VERSION_ID>50100
#include "mysql_priv.h"
#include <mysql/plugin.h>
#else
#include "../mysql_priv.h"
#endif
#include <mysys_err.h>
#include <my_sys.h>
#if MYSQL_VERSION_ID>=50120
typedef
uchar
byte
;
#endif
/// partially copy-pasted stuff that should be moved elsewhere
#if UNALIGNED_RAM_ACCESS
/// pass-through wrapper
template
<
typename
T
>
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
{
return
tRef
;
}
/// pass-through wrapper
template
<
typename
T
>
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
{
*
(
T
*
)
pPtr
=
tVal
;
}
#else
/// unaligned read wrapper for some architectures (eg. SPARC)
template
<
typename
T
>
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
{
T
uTmp
;
byte
*
pSrc
=
(
byte
*
)
&
tRef
;
byte
*
pDst
=
(
byte
*
)
&
uTmp
;
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
*
pDst
++
=
*
pSrc
++
;
return
uTmp
;
}
/// unaligned write wrapper for some architectures (eg. SPARC)
template
<
typename
T
>
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
{
byte
*
pDst
=
(
byte
*
)
pPtr
;
byte
*
pSrc
=
(
byte
*
)
&
tVal
;
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
*
pDst
++
=
*
pSrc
++
;
}
#endif
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
#define SafeDelete(_arg) { if ( _arg ) delete ( _arg ); (_arg) = NULL; }
#define SafeDeleteArray(_arg) { if ( _arg ) delete [] ( _arg ); (_arg) = NULL; }
#define Min(a,b) ((a)<(b)?(a):(b))
typedef
unsigned
int
DWORD
;
inline
DWORD
sphF2DW
(
float
f
)
{
union
{
float
f
;
uint32
d
;
}
u
;
u
.
f
=
f
;
return
u
.
d
;
}
static
char
*
sphDup
(
const
char
*
sSrc
,
int
iLen
=-
1
)
{
if
(
!
sSrc
)
return
NULL
;
if
(
iLen
<
0
)
iLen
=
strlen
(
sSrc
);
char
*
sRes
=
new
char
[
1
+
iLen
];
memcpy
(
sRes
,
sSrc
,
iLen
);
sRes
[
iLen
]
=
'\0'
;
return
sRes
;
}
static
inline
void
sphShowErrno
(
const
char
*
sCall
)
{
char
sError
[
256
];
snprintf
(
sError
,
sizeof
(
sError
),
"%s() failed: [%d] %s"
,
sCall
,
errno
,
strerror
(
errno
)
);
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
}
static
const
bool
sphReportErrors
=
true
;
static
bool
sphSend
(
int
iFd
,
const
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
{
assert
(
pBuffer
);
assert
(
iSize
>
0
);
const
int
iResult
=
send
(
iFd
,
pBuffer
,
iSize
,
0
);
if
(
iResult
!=
iSize
)
{
if
(
bReportErrors
)
sphShowErrno
(
"send"
);
return
false
;
}
return
true
;
}
static
bool
sphRecv
(
int
iFd
,
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
{
assert
(
pBuffer
);
assert
(
iSize
>
0
);
while
(
iSize
)
{
const
int
iResult
=
recv
(
iFd
,
pBuffer
,
iSize
,
0
);
if
(
iResult
>
0
)
{
iSize
-=
iResult
;
pBuffer
+=
iSize
;
}
else
if
(
iResult
==
0
)
{
if
(
bReportErrors
)
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"recv() failed: disconnected"
);
return
false
;
}
else
{
if
(
bReportErrors
)
sphShowErrno
(
"recv"
);
return
false
;
}
}
return
true
;
}
enum
{
SPHINX_SEARCHD_PROTO
=
1
,
SEARCHD_COMMAND_EXCERPT
=
1
,
VER_COMMAND_EXCERPT
=
0x104
,
};
/// known answers
enum
{
SEARCHD_OK
=
0
,
///< general success, command-specific reply follows
SEARCHD_ERROR
=
1
,
///< general failure, error message follows
SEARCHD_RETRY
=
2
,
///< temporary failure, error message follows, client should retry later
SEARCHD_WARNING
=
3
///< general success, warning message and command-specific reply follow
};
#define SPHINXSE_DEFAULT_SCHEME "sphinx"
#define SPHINXSE_DEFAULT_HOST "127.0.0.1"
#define SPHINXSE_DEFAULT_PORT 9312
#define SPHINXSE_DEFAULT_INDEX "*"
class
CSphBuffer
{
private:
bool
m_bOverrun
;
int
m_iSize
;
int
m_iLeft
;
char
*
m_pBuffer
;
char
*
m_pCurrent
;
public:
explicit
CSphBuffer
(
const
int
iSize
)
:
m_bOverrun
(
false
)
,
m_iSize
(
iSize
)
,
m_iLeft
(
iSize
)
{
assert
(
iSize
>
0
);
m_pBuffer
=
new
char
[
iSize
];
m_pCurrent
=
m_pBuffer
;
}
~
CSphBuffer
()
{
SafeDeleteArray
(
m_pBuffer
);
}
const
char
*
Ptr
()
const
{
return
m_pBuffer
;
}
bool
Finalize
()
{
return
!
(
m_bOverrun
||
m_iLeft
!=
0
||
(
m_pCurrent
-
m_pBuffer
)
!=
m_iSize
);
}
void
SendBytes
(
const
void
*
pBytes
,
int
iBytes
);
void
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
// NOLINT
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendDword
(
DWORD
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
uint
(
v
>>
32
)
);
SendDword
(
uint
(
v
&
0xFFFFFFFFUL
)
);
}
void
SendString
(
const
char
*
v
)
{
SendString
(
v
,
strlen
(
v
)
);
}
void
SendString
(
const
char
*
v
,
int
iLen
)
{
SendDword
(
iLen
);
SendBytes
(
v
,
iLen
);
}
void
SendFloat
(
float
v
)
{
SendDword
(
sphF2DW
(
v
)
);
}
};
void
CSphBuffer
::
SendBytes
(
const
void
*
pBytes
,
int
iBytes
)
{
if
(
m_iLeft
<
iBytes
)
{
m_bOverrun
=
true
;
return
;
}
memcpy
(
m_pCurrent
,
pBytes
,
iBytes
);
m_pCurrent
+=
iBytes
;
m_iLeft
-=
iBytes
;
}
struct
CSphUrl
{
char
*
m_sBuffer
;
char
*
m_sFormatted
;
char
*
m_sScheme
;
char
*
m_sHost
;
char
*
m_sIndex
;
int
m_iPort
;
CSphUrl
()
:
m_sBuffer
(
NULL
)
,
m_sFormatted
(
NULL
)
,
m_sScheme
(
SPHINXSE_DEFAULT_SCHEME
)
,
m_sHost
(
SPHINXSE_DEFAULT_HOST
)
,
m_sIndex
(
SPHINXSE_DEFAULT_INDEX
)
,
m_iPort
(
SPHINXSE_DEFAULT_PORT
)
{}
~
CSphUrl
()
{
SafeDeleteArray
(
m_sFormatted
);
SafeDeleteArray
(
m_sBuffer
);
}
bool
Parse
(
const
char
*
sUrl
,
int
iLen
);
int
Connect
();
const
char
*
Format
();
};
const
char
*
CSphUrl
::
Format
()
{
if
(
!
m_sFormatted
)
{
int
iSize
=
15
+
strlen
(
m_sHost
)
+
strlen
(
m_sIndex
);
m_sFormatted
=
new
char
[
iSize
];
if
(
m_iPort
)
snprintf
(
m_sFormatted
,
iSize
,
"inet://%s:%d/%s"
,
m_sHost
,
m_iPort
,
m_sIndex
);
else
snprintf
(
m_sFormatted
,
iSize
,
"unix://%s/%s"
,
m_sHost
,
m_sIndex
);
}
return
m_sFormatted
;
}
// the following scheme variants are recognized
//
// inet://host/index
// inet://host:port/index
// unix://unix/domain/socket:index
// unix://unix/domain/socket
bool
CSphUrl
::
Parse
(
const
char
*
sUrl
,
int
iLen
)
{
bool
bOk
=
true
;
while
(
iLen
)
{
bOk
=
false
;
m_sBuffer
=
sphDup
(
sUrl
,
iLen
);
m_sScheme
=
m_sBuffer
;
m_sHost
=
strstr
(
m_sBuffer
,
"://"
);
if
(
!
m_sHost
)
break
;
m_sHost
[
0
]
=
'\0'
;
m_sHost
+=
2
;
if
(
!
strcmp
(
m_sScheme
,
"unix"
)
)
{
// unix-domain socket
m_iPort
=
0
;
if
(
!
(
m_sIndex
=
strrchr
(
m_sHost
,
':'
)
))
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
else
{
*
m_sIndex
++
=
'\0'
;
if
(
!*
m_sIndex
)
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
}
if
(
strcmp
(
m_sScheme
,
"sphinx"
)
!=
0
&&
strcmp
(
m_sScheme
,
"inet"
)
!=
0
)
break
;
// inet
m_sHost
++
;
char
*
sPort
=
strchr
(
m_sHost
,
':'
);
if
(
sPort
)
{
*
sPort
++
=
'\0'
;
if
(
*
sPort
)
{
m_sIndex
=
strchr
(
sPort
,
'/'
);
if
(
m_sIndex
)
*
m_sIndex
++
=
'\0'
;
else
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
m_iPort
=
atoi
(
sPort
);
if
(
!
m_iPort
)
m_iPort
=
SPHINXSE_DEFAULT_PORT
;
}
}
else
{
m_sIndex
=
strchr
(
m_sHost
,
'/'
);
if
(
m_sIndex
)
*
m_sIndex
++
=
'\0'
;
else
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
}
return
bOk
;
}
int
CSphUrl
::
Connect
()
{
struct
sockaddr_in
sin
;
#ifndef __WIN__
struct
sockaddr_un
saun
;
#endif
int
iDomain
=
0
;
int
iSockaddrSize
=
0
;
struct
sockaddr
*
pSockaddr
=
NULL
;
in_addr_t
ip_addr
;
if
(
m_iPort
)
{
iDomain
=
AF_INET
;
iSockaddrSize
=
sizeof
(
sin
);
pSockaddr
=
(
struct
sockaddr
*
)
&
sin
;
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
sin
.
sin_family
=
AF_INET
;
sin
.
sin_port
=
htons
(
m_iPort
);
// resolve address
if
(
(
int
)(
ip_addr
=
inet_addr
(
m_sHost
)
)
!=
(
int
)
INADDR_NONE
)
memcpy
(
&
sin
.
sin_addr
,
&
ip_addr
,
sizeof
(
ip_addr
)
);
else
{
int
tmp_errno
;
bool
bError
=
false
;
#if MYSQL_VERSION_ID>=50515
struct
addrinfo
*
hp
=
NULL
;
tmp_errno
=
getaddrinfo
(
m_sHost
,
NULL
,
NULL
,
&
hp
);
if
(
!
tmp_errno
||
!
hp
||
!
hp
->
ai_addr
)
{
bError
=
true
;
if
(
hp
)
freeaddrinfo
(
hp
);
}
#else
struct
hostent
tmp_hostent
,
*
hp
;
char
buff2
[
GETHOSTBYNAME_BUFF_SIZE
];
hp
=
my_gethostbyname_r
(
m_sHost
,
&
tmp_hostent
,
buff2
,
sizeof
(
buff2
),
&
tmp_errno
);
if
(
!
hp
)
{
my_gethostbyname_r_free
();
bError
=
true
;
}
#endif
if
(
bError
)
{
char
sError
[
256
];
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
m_sHost
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
return
-
1
;
}
#if MYSQL_VERSION_ID>=50515
memcpy
(
&
sin
.
sin_addr
,
hp
->
ai_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
ai_addrlen
)
);
freeaddrinfo
(
hp
);
#else
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
my_gethostbyname_r_free
();
#endif
}
}
else
{
#ifndef __WIN__
iDomain
=
AF_UNIX
;
iSockaddrSize
=
sizeof
(
saun
);
pSockaddr
=
(
struct
sockaddr
*
)
&
saun
;
memset
(
&
saun
,
0
,
sizeof
(
saun
)
);
saun
.
sun_family
=
AF_UNIX
;
strncpy
(
saun
.
sun_path
,
m_sHost
,
sizeof
(
saun
.
sun_path
)
-
1
);
#else
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"Unix-domain sockets are not supported on Windows"
);
return
-
1
;
#endif
}
// connect to searchd and exchange versions
uint
uServerVersion
;
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
int
iSocket
=
-
1
;
char
*
pError
=
NULL
;
do
{
iSocket
=
socket
(
iDomain
,
SOCK_STREAM
,
0
);
if
(
iSocket
==-
1
)
{
pError
=
"Failed to create client socket"
;
break
;
}
if
(
connect
(
iSocket
,
pSockaddr
,
iSockaddrSize
)
==-
1
)
{
pError
=
"Failed to connect to searchd"
;
break
;
}
if
(
!
sphRecv
(
iSocket
,
(
char
*
)
&
uServerVersion
,
sizeof
(
uServerVersion
)
)
)
{
pError
=
"Failed to receive searchd version"
;
break
;
}
if
(
!
sphSend
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
)
)
)
{
pError
=
"Failed to send client version"
;
break
;
}
}
while
(
0
);
// fixme: compare versions?
if
(
pError
)
{
char
sError
[
1024
];
snprintf
(
sError
,
sizeof
(
sError
),
"%s [%d] %s"
,
Format
(),
errno
,
strerror
(
errno
)
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
if
(
iSocket
!=-
1
)
close
(
iSocket
);
return
-
1
;
}
return
iSocket
;
}
struct
CSphResponse
{
char
*
m_pBuffer
;
char
*
m_pBody
;
CSphResponse
()
:
m_pBuffer
(
NULL
)
,
m_pBody
(
NULL
)
{}
explicit
CSphResponse
(
DWORD
uSize
)
:
m_pBody
(
NULL
)
{
m_pBuffer
=
new
char
[
uSize
];
}
~
CSphResponse
()
{
SafeDeleteArray
(
m_pBuffer
);
}
static
CSphResponse
*
Read
(
int
iSocket
,
int
iClientVersion
);
};
CSphResponse
*
CSphResponse
::
Read
(
int
iSocket
,
int
iClientVersion
)
{
char
sHeader
[
8
];
if
(
!
sphRecv
(
iSocket
,
sHeader
,
sizeof
(
sHeader
)
)
)
return
NULL
;
int
iStatus
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
0
]
)
);
int
iVersion
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
2
]
)
);
DWORD
uLength
=
ntohl
(
sphUnalignedRead
(
*
(
DWORD
*
)
&
sHeader
[
4
]
)
);
if
(
iVersion
<
iClientVersion
)
return
NULL
;
if
(
uLength
<=
SPHINXSE_MAX_ALLOC
)
{
CSphResponse
*
pResponse
=
new
CSphResponse
(
uLength
);
if
(
!
sphRecv
(
iSocket
,
pResponse
->
m_pBuffer
,
uLength
)
)
{
SafeDelete
(
pResponse
);
return
NULL
;
}
pResponse
->
m_pBody
=
pResponse
->
m_pBuffer
;
if
(
iStatus
!=
SEARCHD_OK
)
{
DWORD
uSize
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBuffer
);
if
(
iStatus
==
SEARCHD_WARNING
)
{
pResponse
->
m_pBody
+=
uSize
;
// fixme: report the warning somehow
}
else
{
char
*
sMessage
=
sphDup
(
pResponse
->
m_pBuffer
+
sizeof
(
DWORD
),
uSize
);
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sMessage
);
SafeDeleteArray
(
sMessage
);
SafeDelete
(
pResponse
);
return
NULL
;
}
}
return
pResponse
;
}
return
NULL
;
}
/// udf
extern
"C"
{
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
);
void
sphinx_snippets_deinit
(
UDF_INIT
*
pUDF
);
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
sError
);
};
#define MAX_MESSAGE_LENGTH 255
#define MAX_RESULT_LENGTH 255
struct
CSphSnippets
{
CSphUrl
m_tUrl
;
CSphResponse
*
m_pResponse
;
int
m_iBeforeMatch
;
int
m_iAfterMatch
;
int
m_iChunkSeparator
;
int
m_iStripMode
;
int
m_iPassageBoundary
;
int
m_iLimit
;
int
m_iLimitWords
;
int
m_iLimitPassages
;
int
m_iAround
;
int
m_iPassageId
;
int
m_iFlags
;
CSphSnippets
()
:
m_pResponse
(
NULL
)
,
m_iBeforeMatch
(
0
)
,
m_iAfterMatch
(
0
)
,
m_iChunkSeparator
(
0
)
,
m_iStripMode
(
0
)
,
m_iPassageBoundary
(
0
)
// defaults
,
m_iLimit
(
256
)
,
m_iLimitWords
(
0
)
,
m_iLimitPassages
(
0
)
,
m_iAround
(
5
)
,
m_iPassageId
(
1
)
,
m_iFlags
(
1
)
{
}
~
CSphSnippets
()
{
SafeDelete
(
m_pResponse
);
}
};
#define KEYWORD(NAME) else if ( strncmp ( NAME, pArgs->attributes[i], pArgs->attribute_lengths[i] )==0 )
#define CHECK_TYPE(TYPE) \
if ( pArgs->arg_type[i]!=TYPE ) \
{ \
snprintf ( sMessage, MAX_MESSAGE_LENGTH, \
"%.*s argument must be a string", \
(int)pArgs->attribute_lengths[i], \
pArgs->attributes[i] ); \
bFail = true; \
break; \
} \
if ( TYPE==STRING_RESULT && !pArgs->args[i] ) \
{ \
snprintf ( sMessage, MAX_MESSAGE_LENGTH, \
"%.*s argument must be constant (and not NULL)", \
(int)pArgs->attribute_lengths[i], \
pArgs->attributes[i] ); \
bFail = true; \
break; \
}
#define STRING CHECK_TYPE(STRING_RESULT)
#define INT CHECK_TYPE(INT_RESULT); int iValue = *(long long *)pArgs->args[i]
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
)
{
if
(
pArgs
->
arg_count
<
3
)
{
strncpy
(
sMessage
,
"insufficient arguments"
,
MAX_MESSAGE_LENGTH
);
return
1
;
}
bool
bFail
=
false
;
CSphSnippets
*
pOpts
=
new
CSphSnippets
;
for
(
uint
i
=
0
;
i
<
pArgs
->
arg_count
;
i
++
)
{
if
(
i
<
3
)
{
if
(
pArgs
->
arg_type
[
i
]
!=
STRING_RESULT
)
{
strncpy
(
sMessage
,
"first three arguments must be of string type"
,
MAX_MESSAGE_LENGTH
);
bFail
=
true
;
break
;
}
}
KEYWORD
(
"sphinx"
)
{
STRING
;
if
(
!
pOpts
->
m_tUrl
.
Parse
(
pArgs
->
args
[
i
],
pArgs
->
lengths
[
i
]
)
)
{
strncpy
(
sMessage
,
"failed to parse connection string"
,
MAX_MESSAGE_LENGTH
);
bFail
=
true
;
break
;
}
}
KEYWORD
(
"before_match"
)
{
STRING
;
pOpts
->
m_iBeforeMatch
=
i
;
}
KEYWORD
(
"after_match"
)
{
STRING
;
pOpts
->
m_iAfterMatch
=
i
;
}
KEYWORD
(
"chunk_separator"
)
{
STRING
;
pOpts
->
m_iChunkSeparator
=
i
;
}
KEYWORD
(
"html_strip_mode"
)
{
STRING
;
pOpts
->
m_iStripMode
=
i
;
}
KEYWORD
(
"passage_boundary"
)
{
STRING
;
pOpts
->
m_iPassageBoundary
=
i
;
}
KEYWORD
(
"limit"
)
{
INT
;
pOpts
->
m_iLimit
=
iValue
;
}
KEYWORD
(
"limit_words"
)
{
INT
;
pOpts
->
m_iLimitWords
=
iValue
;
}
KEYWORD
(
"limit_passages"
)
{
INT
;
pOpts
->
m_iLimitPassages
=
iValue
;
}
KEYWORD
(
"around"
)
{
INT
;
pOpts
->
m_iAround
=
iValue
;
}
KEYWORD
(
"start_passage_id"
)
{
INT
;
pOpts
->
m_iPassageId
=
iValue
;
}
KEYWORD
(
"exact_phrase"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
2
;
}
KEYWORD
(
"single_passage"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
4
;
}
KEYWORD
(
"use_boundaries"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
8
;
}
KEYWORD
(
"weight_order"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
16
;
}
KEYWORD
(
"query_mode"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
32
;
}
KEYWORD
(
"force_all_words"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
64
;
}
KEYWORD
(
"load_files"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
128
;
}
KEYWORD
(
"allow_empty"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
256
;
}
KEYWORD
(
"emit_zones"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
512
;
}
KEYWORD
(
"load_files_scattered"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
1024
;
}
else
{
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
"unrecognized argument: %.*s"
,
(
int
)
pArgs
->
attribute_lengths
[
i
],
pArgs
->
attributes
[
i
]
);
bFail
=
true
;
break
;
}
}
if
(
bFail
)
{
SafeDelete
(
pOpts
);
return
1
;
}
pUDF
->
ptr
=
(
char
*
)
pOpts
;
return
0
;
}
#undef STRING
#undef INT
#undef KEYWORD
#undef CHECK_TYPE
#define ARG(i) pArgs->args[i], pArgs->lengths[i]
#define ARG_LEN(VAR, LEN) ( VAR ? pArgs->lengths[VAR] : LEN )
#define SEND_STRING(INDEX, DEFAULT) \
if ( INDEX ) \
tBuffer.SendString ( ARG(INDEX) ); \
else \
tBuffer.SendString ( DEFAULT, sizeof(DEFAULT) - 1 );
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
pError
)
{
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
assert
(
pOpts
);
if
(
!
pArgs
->
args
[
0
]
||
!
pArgs
->
args
[
1
]
||
!
pArgs
->
args
[
2
]
)
{
*
pIsNull
=
1
;
return
sResult
;
}
const
int
iSize
=
68
+
pArgs
->
lengths
[
1
]
+
// index
pArgs
->
lengths
[
2
]
+
// words
ARG_LEN
(
pOpts
->
m_iBeforeMatch
,
3
)
+
ARG_LEN
(
pOpts
->
m_iAfterMatch
,
4
)
+
ARG_LEN
(
pOpts
->
m_iChunkSeparator
,
5
)
+
ARG_LEN
(
pOpts
->
m_iStripMode
,
5
)
+
ARG_LEN
(
pOpts
->
m_iPassageBoundary
,
0
)
+
4
+
pArgs
->
lengths
[
0
];
// document
CSphBuffer
tBuffer
(
iSize
);
tBuffer
.
SendWord
(
SEARCHD_COMMAND_EXCERPT
);
tBuffer
.
SendWord
(
VER_COMMAND_EXCERPT
);
tBuffer
.
SendDword
(
iSize
-
8
);
tBuffer
.
SendDword
(
0
);
tBuffer
.
SendDword
(
pOpts
->
m_iFlags
);
tBuffer
.
SendString
(
ARG
(
1
)
);
// index
tBuffer
.
SendString
(
ARG
(
2
)
);
// words
SEND_STRING
(
pOpts
->
m_iBeforeMatch
,
"<b>"
);
SEND_STRING
(
pOpts
->
m_iAfterMatch
,
"</b>"
);
SEND_STRING
(
pOpts
->
m_iChunkSeparator
,
" ... "
);
tBuffer
.
SendInt
(
pOpts
->
m_iLimit
);
tBuffer
.
SendInt
(
pOpts
->
m_iAround
);
tBuffer
.
SendInt
(
pOpts
->
m_iLimitPassages
);
tBuffer
.
SendInt
(
pOpts
->
m_iLimitWords
);
tBuffer
.
SendInt
(
pOpts
->
m_iPassageId
);
SEND_STRING
(
pOpts
->
m_iStripMode
,
"index"
);
SEND_STRING
(
pOpts
->
m_iPassageBoundary
,
""
);
// single document
tBuffer
.
SendInt
(
1
);
tBuffer
.
SendString
(
ARG
(
0
)
);
int
iSocket
=
-
1
;
do
{
if
(
!
tBuffer
.
Finalize
()
)
{
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: failed to build request"
);
break
;
}
iSocket
=
pOpts
->
m_tUrl
.
Connect
();
if
(
iSocket
==-
1
)
break
;
if
(
!
sphSend
(
iSocket
,
tBuffer
.
Ptr
(),
iSize
,
sphReportErrors
)
)
break
;
CSphResponse
*
pResponse
=
CSphResponse
::
Read
(
iSocket
,
VER_COMMAND_EXCERPT
);
if
(
!
pResponse
)
break
;
close
(
iSocket
);
pOpts
->
m_pResponse
=
pResponse
;
*
pLength
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBody
);
return
pResponse
->
m_pBody
+
sizeof
(
DWORD
);
}
while
(
0
);
if
(
iSocket
!=-
1
)
close
(
iSocket
);
*
pError
=
1
;
return
sResult
;
}
#undef SEND_STRING
#undef ARG_LEN
#undef ARG
void
sphinx_snippets_deinit
(
UDF_INIT
*
pUDF
)
{
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
SafeDelete
(
pOpts
);
}
//
// $Id: snippets_udf.cc 4505 2014-01-22 15:16:21Z deogar $
//
sphinx.5.0.91.diff
0 → 100644
View file @
01673997
diff -r 319c65835581 CMakeLists.txt
--- a/CMakeLists.txt Sun Jun 20 15:15:01 2010 +0400
+++ b/CMakeLists.txt Sun Jun 20 15:59:31 2010 +0400
@@ -70,6 +70,10 @@
ADD_DEFINITIONS(-DHAVE_INNOBASE_DB)
ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
+IF(WITH_SPHINX_STORAGE_ENGINE)
+ ADD_DEFINITIONS(-DHAVE_SPHINX_DB)
+ENDIF(WITH_SPHINX_STORAGE_ENGINE)
+
SET(localstatedir "C:\\mysql\\data")
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/support-files/my-huge.cnf.sh
${CMAKE_SOURCE_DIR}/support-files/my-huge.ini @ONLY)
diff -r 319c65835581 configure.in
--- a/configure.in Sun Jun 20 15:15:01 2010 +0400
+++ b/configure.in Sun Jun 20 15:59:31 2010 +0400
@@ -60,6 +60,7 @@
sinclude(config/ac-macros/ha_berkeley.m4)
sinclude(config/ac-macros/ha_blackhole.m4)
sinclude(config/ac-macros/ha_example.m4)
+sinclude(config/ac-macros/ha_sphinx.m4)
sinclude(config/ac-macros/ha_federated.m4)
sinclude(config/ac-macros/ha_innodb.m4)
sinclude(config/ac-macros/ha_ndbcluster.m4)
@@ -2696,6 +2697,7 @@
MYSQL_CHECK_BDB
MYSQL_CHECK_INNODB
MYSQL_CHECK_EXAMPLEDB
+MYSQL_CHECK_SPHINXDB
MYSQL_CHECK_ARCHIVEDB
MYSQL_CHECK_CSVDB
MYSQL_CHECK_BLACKHOLEDB
diff -r 319c65835581 libmysqld/Makefile.am
--- a/libmysqld/Makefile.am Sun Jun 20 15:15:01 2010 +0400
+++ b/libmysqld/Makefile.am Sun Jun 20 15:59:31 2010 +0400
@@ -29,6 +29,7 @@
-I$(top_builddir)/include -I$(top_srcdir)/include \
-I$(top_builddir)/sql -I$(top_srcdir)/sql \
-I$(top_srcdir)/sql/examples \
+ -I$(top_srcdir)/sql/sphinx \
-I$(top_srcdir)/regex \
$(openssl_includes) @ZLIB_INCLUDES@
@@ -39,6 +40,7 @@
libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c \
my_time.c
sqlexamplessources = ha_example.cc ha_tina.cc
+sqlsphinxsources = ha_sphinx.cc
noinst_HEADERS = embedded_priv.h emb_qcache.h
@@ -67,7 +69,7 @@
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
ha_blackhole.cc ha_archive.cc my_user.c
-libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources)
+libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources) $(sqlsphinxsources)
libmysqld_a_SOURCES=
# automake misses these
@@ -147,12 +149,16 @@
rm -f $$f; \
@LN_CP_F@ $(top_srcdir)/sql/examples/$$f $$f; \
done; \
+ for f in $(sqlsphinxsources); do \
+ rm -f $$f; \
+ @LN_CP_F@ $(top_srcdir)/sql/sphinx/$$f $$f; \
+ done; \
rm -f client_settings.h; \
@LN_CP_F@ $(top_srcdir)/libmysql/client_settings.h client_settings.h
clean-local:
- rm -f `echo $(sqlsources) $(libmysqlsources) $(sqlexamplessources) | sed "s;\.lo;.c;g"` \
+ rm -f `echo $(sqlsources) $(libmysqlsources) $(sqlexamplessources) $(sqlsphinxsources) | sed "s;\.lo;.c;g"` \
$(top_srcdir)/linked_libmysqld_sources; \
rm -f client_settings.h
diff -r 319c65835581 sql/CMakeLists.txt
--- a/sql/CMakeLists.txt Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/CMakeLists.txt Sun Jun 20 15:59:31 2010 +0400
@@ -50,6 +50,7 @@
filesort.cc gstream.cc ha_blackhole.cc
ha_archive.cc ha_heap.cc ha_myisam.cc ha_myisammrg.cc
ha_innodb.cc ha_federated.cc ha_berkeley.cc
+ sphinx/ha_sphinx.cc
handler.cc hash_filo.cc hash_filo.h
hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
item_create.cc item_func.cc item_geofunc.cc item_row.cc
diff -r 319c65835581 sql/Makefile.am
--- a/sql/Makefile.am Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/Makefile.am Sun Jun 20 15:59:31 2010 +0400
@@ -68,6 +68,7 @@
sql_array.h sql_cursor.h \
examples/ha_example.h ha_archive.h \
examples/ha_tina.h ha_blackhole.h \
+ sphinx/ha_sphinx.h \
ha_federated.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -105,6 +106,7 @@
sp_cache.cc parse_file.cc sql_trigger.cc \
examples/ha_example.cc ha_archive.cc \
examples/ha_tina.cc ha_blackhole.cc \
+ sphinx/ha_sphinx.cc \
ha_federated.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
@@ -175,6 +177,10 @@
udf_example_la_SOURCES= udf_example.c
udf_example_la_LDFLAGS= -module -rpath $(pkglibdir)
+pkglib_LTLIBRARIES = sphinx/sphinx.la
+sphinx_sphinx_la_SOURCES = sphinx/snippets_udf.cc
+sphinx_sphinx_la_LDFLAGS = -module
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff -r 319c65835581 sql/handler.cc
--- a/sql/handler.cc Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/handler.cc Sun Jun 20 15:59:31 2010 +0400
@@ -77,6 +77,15 @@
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
HTON_NO_FLAGS };
#endif
+#ifdef HAVE_SPHINX_DB
+#include "sphinx/ha_sphinx.h"
+extern handlerton sphinx_hton;
+#else
+handlerton sphinx_hton = { "SPHINX", SHOW_OPTION_NO, "SPHINX storage engine",
+ DB_TYPE_SPHINX_DB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
+#endif
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
extern handlerton innobase_hton;
@@ -141,6 +150,7 @@
&example_hton,
&archive_hton,
&tina_hton,
+ &sphinx_hton,
&ndbcluster_hton,
&federated_hton,
&myisammrg_hton,
@@ -342,6 +352,12 @@
return new (alloc) ha_tina(table);
return NULL;
#endif
+#ifdef HAVE_SPHINX_DB
+ case DB_TYPE_SPHINX_DB:
+ if (have_sphinx_db == SHOW_OPTION_YES)
+ return new (alloc) ha_sphinx(table);
+ return NULL;
+#endif
#ifdef HAVE_NDBCLUSTER_DB
case DB_TYPE_NDBCLUSTER:
if (have_ndbcluster == SHOW_OPTION_YES)
diff -r 319c65835581 sql/handler.h
--- a/sql/handler.h Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/handler.h Sun Jun 20 15:59:31 2010 +0400
@@ -186,8 +186,9 @@
DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB,
DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER,
DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB, DB_TYPE_CSV_DB,
- DB_TYPE_FEDERATED_DB,
+ DB_TYPE_FEDERATED_DB,
DB_TYPE_BLACKHOLE_DB,
+ DB_TYPE_SPHINX_DB,
DB_TYPE_DEFAULT // Must be last
};
diff -r 319c65835581 sql/mysql_priv.h
--- a/sql/mysql_priv.h Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/mysql_priv.h Sun Jun 20 15:59:31 2010 +0400
@@ -1462,6 +1462,12 @@
#else
extern SHOW_COMP_OPTION have_csv_db;
#endif
+#ifdef HAVE_SPHINX_DB
+extern handlerton sphinx_hton;
+#define have_sphinx_db sphinx_hton.state
+#else
+extern SHOW_COMP_OPTION have_sphinx_db;
+#endif
#ifdef HAVE_FEDERATED_DB
extern handlerton federated_hton;
#define have_federated_db federated_hton.state
diff -r 319c65835581 sql/mysqld.cc
--- a/sql/mysqld.cc Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/mysqld.cc Sun Jun 20 15:59:31 2010 +0400
@@ -36,6 +36,10 @@
#include <sys/prctl.h>
#endif
+#ifdef HAVE_SPHINX_DB
+#include "sphinx/ha_sphinx.h"
+#endif
+
#ifdef HAVE_INNOBASE_DB
#define OPT_INNODB_DEFAULT 1
#else
@@ -6721,6 +6725,13 @@
#ifdef COMMUNITY_SERVER
{"Uptime_since_flush_status",(char*) 0, SHOW_FLUSHTIME},
#endif
+#ifdef HAVE_SPHINX_DB
+ {"sphinx_total", (char *)sphinx_showfunc_total, SHOW_SPHINX_FUNC},
+ {"sphinx_total_found", (char *)sphinx_showfunc_total_found, SHOW_SPHINX_FUNC},
+ {"sphinx_time", (char *)sphinx_showfunc_time, SHOW_SPHINX_FUNC},
+ {"sphinx_word_count", (char *)sphinx_showfunc_word_count, SHOW_SPHINX_FUNC},
+ {"sphinx_words", (char *)sphinx_showfunc_words, SHOW_SPHINX_FUNC},
+#endif
{NullS, NullS, SHOW_LONG}
};
@@ -6964,6 +6975,11 @@
#else
have_csv_db= SHOW_OPTION_NO;
#endif
+#ifdef HAVE_SPHINX_DB
+ have_sphinx_db= SHOW_OPTION_YES;
+#else
+ have_sphinx_db= SHOW_OPTION_NO;
+#endif
#ifdef HAVE_NDBCLUSTER_DB
have_ndbcluster=SHOW_OPTION_DISABLED;
#else
@@ -8087,6 +8103,7 @@
#undef have_example_db
#undef have_archive_db
#undef have_csv_db
+#undef have_sphinx_db
#undef have_federated_db
#undef have_partition_db
#undef have_blackhole_db
@@ -8097,6 +8114,7 @@
SHOW_COMP_OPTION have_example_db= SHOW_OPTION_NO;
SHOW_COMP_OPTION have_archive_db= SHOW_OPTION_NO;
SHOW_COMP_OPTION have_csv_db= SHOW_OPTION_NO;
+SHOW_COMP_OPTION have_sphinx_db= SHOW_OPTION_NO;
SHOW_COMP_OPTION have_federated_db= SHOW_OPTION_NO;
SHOW_COMP_OPTION have_partition_db= SHOW_OPTION_NO;
SHOW_COMP_OPTION have_blackhole_db= SHOW_OPTION_NO;
diff -r 319c65835581 sql/set_var.cc
--- a/sql/set_var.cc Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/set_var.cc Sun Jun 20 15:59:31 2010 +0400
@@ -913,6 +913,7 @@
{"have_profiling", (char*) &have_profiling, SHOW_HAVE},
{"have_crypt", (char*) &have_crypt, SHOW_HAVE},
{"have_csv", (char*) &have_csv_db, SHOW_HAVE},
+ {"have_sphinx", (char*) &have_sphinx_db, SHOW_HAVE},
{"have_dynamic_loading", (char*) &have_dlopen, SHOW_HAVE},
{"have_example_engine", (char*) &have_example_db, SHOW_HAVE},
{"have_federated_engine", (char*) &have_federated_db, SHOW_HAVE},
diff -r 319c65835581 sql/sql_lex.h
--- a/sql/sql_lex.h Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/sql_lex.h Sun Jun 20 15:59:31 2010 +0400
@@ -57,6 +57,7 @@
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_NDBCLUSTER_STATUS, SQLCOM_SHOW_MUTEX_STATUS,
+ SQLCOM_SHOW_SPHINX_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
diff -r 319c65835581 sql/sql_parse.cc
--- a/sql/sql_parse.cc Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/sql_parse.cc Sun Jun 20 15:59:31 2010 +0400
@@ -24,6 +24,9 @@
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
#endif
+#ifdef HAVE_SPHINX_DB
+#include "sphinx/ha_sphinx.h"
+#endif
#ifdef HAVE_NDBCLUSTER_DB
#include "ha_ndbcluster.h"
@@ -3166,6 +3169,15 @@
break;
}
#endif
+#ifdef HAVE_SPHINX_DB
+ case SQLCOM_SHOW_SPHINX_STATUS:
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ goto error;
+ res = sphinx_show_status(thd);
+ break;
+ }
+#endif
#ifdef HAVE_REPLICATION
case SQLCOM_LOAD_MASTER_TABLE:
{
diff -r 319c65835581 sql/sql_show.cc
--- a/sql/sql_show.cc Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/sql_show.cc Sun Jun 20 15:59:31 2010 +0400
@@ -1500,6 +1500,16 @@
value= (char*) var->value_ptr(thd, value_type, &null_lex_str);
charset= var->charset(thd);
}
+ #ifdef HAVE_SPHINX_DB
+ else if (show_type == SHOW_SPHINX_FUNC)
+ {
+ SHOW_VAR var;
+ ((int (*)(THD *, SHOW_VAR *, char *))value)(thd, &var, buff);
+
+ value = var.value;
+ show_type = var.type;
+ }
+ #endif /* HAVE_SPHINX_DB */
pos= end= buff;
switch (show_type) {
diff -r 319c65835581 sql/sql_yacc.yy
--- a/sql/sql_yacc.yy Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/sql_yacc.yy Sun Jun 20 15:59:31 2010 +0400
@@ -8342,6 +8342,9 @@
case DB_TYPE_INNODB:
Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS;
break;
+ case DB_TYPE_SPHINX_DB:
+ Lex->sql_command = SQLCOM_SHOW_SPHINX_STATUS;
+ break;
default:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "STATUS");
MYSQL_YYABORT;
diff -r 319c65835581 sql/sql_yacc.cc
--- a/sql/sql_yacc.cc Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/sql_yacc.cc Sun Jun 20 15:59:31 2010 +0400
@@ -27003,6 +27003,9 @@
case DB_TYPE_INNODB:
Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS;
break;
+ case DB_TYPE_SPHINX_DB:
+ Lex->sql_command = SQLCOM_SHOW_SPHINX_STATUS;
+ break;
default:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "STATUS");
MYSQL_YYABORT;
diff -r 319c65835581 sql/structs.h
--- a/sql/structs.h Sun Jun 20 15:15:01 2010 +0400
+++ b/sql/structs.h Sun Jun 20 15:59:31 2010 +0400
@@ -194,6 +194,9 @@
SHOW_SSL_CTX_SESS_TIMEOUTS, SHOW_SSL_CTX_SESS_CACHE_FULL,
SHOW_SSL_GET_CIPHER_LIST,
#endif /* HAVE_OPENSSL */
+#ifdef HAVE_SPHINX_DB
+ SHOW_SPHINX_FUNC,
+#endif
SHOW_NET_COMPRESSION,
SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS,
SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG, SHOW_KEY_CACHE_LONGLONG,
diff -r 319c65835581 win/configure.js
--- a/win/configure.js Sun Jun 20 15:15:01 2010 +0400
+++ b/win/configure.js Sun Jun 20 15:59:31 2010 +0400
@@ -45,6 +45,7 @@
case "WITH_EXAMPLE_STORAGE_ENGINE":
case "WITH_FEDERATED_STORAGE_ENGINE":
case "WITH_INNOBASE_STORAGE_ENGINE":
+ case "WITH_SPHINX_STORAGE_ENGINE":
case "__NT__":
case "DISABLE_GRANT_OPTIONS":
case "EMBED_MANIFESTS":
--- mysql-5.0.67/config/ac-macros/ha_sphinx.m4 1970-01-01 10:00:00.000000000 +1000
+++ mysql-5.0.67-sphinx/config/ac-macros/ha_sphinx.m4 2009-02-14 09:15:48.000000000 +1000
@@ -0,0 +1,30 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_EXAMPLEDB
+dnl Sets HAVE_SPHINX_DB if --with-sphinx-storage-engine is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_SPHINXDB], [
+ AC_ARG_WITH([sphinx-storage-engine],
+ [
+ --with-sphinx-storage-engine
+ Enable the Sphinx Storage Engine],
+ [sphinxdb="$withval"],
+ [sphinxdb=no])
+ AC_MSG_CHECKING([for example storage engine])
+
+ case "$sphinxdb" in
+ yes )
+ AC_DEFINE([HAVE_SPHINX_DB], [1], [Builds Sphinx Engine])
+ AC_MSG_RESULT([yes])
+ [sphinxdb=yes]
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ [sphinxdb=no]
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_EXAMPLE SECTION
+dnl ---------------------------------------------------------------------------
+
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment