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
...
@@ -7,5 +7,10 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${
CMAKE_SOURCE_DIR
}
/extra/yassl/include
${
CMAKE_SOURCE_DIR
}
/extra/yassl/include
${
CMAKE_SOURCE_DIR
}
/regex
)
${
CMAKE_SOURCE_DIR
}
/regex
)
SET
(
SPHINX_SOURCES ha_sphinx.cc
)
SET
(
SPHINX_SOURCES ha_sphinx.cc snippets_udf.cc
)
ADD_LIBRARY
(
sphinx ha_sphinx.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
#ifdef USE_PRAGMA_IMPLEMENTATION
...
@@ -13,7 +24,10 @@
...
@@ -13,7 +24,10 @@
#include <mysql_version.h>
#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_priv.h"
#include <mysql/plugin.h>
#include <mysql/plugin.h>
#else
#else
...
@@ -22,6 +36,7 @@
...
@@ -22,6 +36,7 @@
#include <mysys_err.h>
#include <mysys_err.h>
#include <my_sys.h>
#include <my_sys.h>
#include <mysql.h> // include client for INSERT table (sort of redoing federated..)
#ifndef __WIN__
#ifndef __WIN__
// UNIX-specific
// UNIX-specific
...
@@ -107,28 +122,48 @@ void sphUnalignedWrite ( void * pPtr, const T & tVal )
...
@@ -107,28 +122,48 @@ void sphUnalignedWrite ( void * pPtr, const T & tVal )
#endif
#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
// FIXME! make this all dynamic
#define SPHINXSE_MAX_FILTERS 32
#define SPHINXSE_MAX_FILTERS 32
#define SPHINXSE_DEFAULT_HOST "127.0.0.1"
#define SPHINXAPI_DEFAULT_HOST "127.0.0.1"
#define SPHINXSE_DEFAULT_PORT 9312
#define SPHINXAPI_DEFAULT_PORT 9312
#define SPHINXSE_DEFAULT_INDEX "*"
#define SPHINXAPI_DEFAULT_INDEX "*"
#define SPHINXQL_DEFAULT_PORT 9306
#define SPHINXSE_SYSTEM_COLUMNS 3
#define SPHINXSE_SYSTEM_COLUMNS 3
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
#define SPHINXSE_MAX_KEYWORDSTATS 4096
#define SPHINXSE_MAX_KEYWORDSTATS 4096
// FIXME! all the following is cut-n-paste from sphinx.h and searchd.cpp
#define SPHINXSE_VERSION "2.1.5-release"
#define SPHINX_VERSION "0.9.9"
// FIXME? the following is cut-n-paste from sphinx.h and searchd.cpp
// cut-n-paste is somewhat simpler that adding dependencies however..
enum
enum
{
{
SPHINX_SEARCHD_PROTO
=
1
,
SPHINX_SEARCHD_PROTO
=
1
,
SEARCHD_COMMAND_SEARCH
=
0
,
SEARCHD_COMMAND_SEARCH
=
0
,
VER_COMMAND_SEARCH
=
0x11
6
,
VER_COMMAND_SEARCH
=
0x11
9
,
};
};
/// search query sorting orders
/// search query sorting orders
...
@@ -168,6 +203,8 @@ enum ESphRankMode
...
@@ -168,6 +203,8 @@ enum ESphRankMode
SPH_RANK_PROXIMITY
=
4
,
///< phrase proximity
SPH_RANK_PROXIMITY
=
4
,
///< phrase proximity
SPH_RANK_MATCHANY
=
5
,
///< emulate old match-any weighting
SPH_RANK_MATCHANY
=
5
,
///< emulate old match-any weighting
SPH_RANK_FIELDMASK
=
6
,
///< sets bits where there were matches
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_TOTAL
,
SPH_RANK_DEFAULT
=
SPH_RANK_PROXIMITY_BM25
SPH_RANK_DEFAULT
=
SPH_RANK_PROXIMITY_BM25
...
@@ -193,8 +230,10 @@ enum
...
@@ -193,8 +230,10 @@ enum
SPH_ATTR_BOOL
=
4
,
///< this attr is a boolean bit field
SPH_ATTR_BOOL
=
4
,
///< this attr is a boolean bit field
SPH_ATTR_FLOAT
=
5
,
SPH_ATTR_FLOAT
=
5
,
SPH_ATTR_BIGINT
=
6
,
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
/// known answers
...
@@ -249,21 +288,26 @@ inline void SPH_DEBUG ( const char *, ... ) {}
...
@@ -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
struct
CSphSEShare
{
{
pthread_mutex_t
m_tMutex
;
pthread_mutex_t
m_tMutex
;
THR_LOCK
m_tLock
;
THR_LOCK
m_tLock
;
char
*
m_sTable
;
char
*
m_sTable
;
char
*
m_sScheme
;
char
*
m_sScheme
;
///< our connection string
char
*
m_sHost
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
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_sSocket
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sIndex
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
char
*
m_sIndex
;
///< points into m_sScheme buffer, DO NOT FREE EXPLICITLY
ushort
m_iPort
;
ushort
m_iPort
;
bool
m_bSphinxQL
;
///< is this read-only SphinxAPI table, or write-only SphinxQL table?
uint
m_iTableNameLen
;
uint
m_iTableNameLen
;
uint
m_iUseCount
;
uint
m_iUseCount
;
#if MYSQL_VERSION_ID<50610
CHARSET_INFO
*
m_pTableQueryCharset
;
CHARSET_INFO
*
m_pTableQueryCharset
;
#else
const
CHARSET_INFO
*
m_pTableQueryCharset
;
#endif
int
m_iTableFields
;
int
m_iTableFields
;
char
**
m_sTableField
;
char
**
m_sTableField
;
...
@@ -276,6 +320,7 @@ struct CSphSEShare
...
@@ -276,6 +320,7 @@ struct CSphSEShare
,
m_sSocket
(
NULL
)
,
m_sSocket
(
NULL
)
,
m_sIndex
(
NULL
)
,
m_sIndex
(
NULL
)
,
m_iPort
(
0
)
,
m_iPort
(
0
)
,
m_bSphinxQL
(
false
)
,
m_iTableNameLen
(
0
)
,
m_iTableNameLen
(
0
)
,
m_iUseCount
(
1
)
,
m_iUseCount
(
1
)
,
m_pTableQueryCharset
(
NULL
)
,
m_pTableQueryCharset
(
NULL
)
...
@@ -391,12 +436,26 @@ struct CSphSEThreadData
...
@@ -391,12 +436,26 @@ struct CSphSEThreadData
bool
m_bQuery
;
bool
m_bQuery
;
char
m_sQuery
[
MAX_QUERY_LEN
];
char
m_sQuery
[
MAX_QUERY_LEN
];
#if MYSQL_VERSION_ID<50610
CHARSET_INFO
*
m_pQueryCharset
;
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
()
CSphSEThreadData
()
:
m_bStats
(
false
)
:
m_bStats
(
false
)
,
m_bQuery
(
false
)
,
m_bQuery
(
false
)
,
m_pQueryCharset
(
NULL
)
,
m_pQueryCharset
(
NULL
)
,
m_bReplace
(
false
)
,
m_bCondId
(
false
)
,
m_iCondId
(
0
)
,
m_bCondDone
(
false
)
{}
{}
};
};
...
@@ -471,6 +530,7 @@ private:
...
@@ -471,6 +530,7 @@ private:
int
m_iWeights
;
int
m_iWeights
;
ESphMatchMode
m_eMode
;
ESphMatchMode
m_eMode
;
ESphRankMode
m_eRanker
;
ESphRankMode
m_eRanker
;
char
*
m_sRankExpr
;
ESphSortOrder
m_eSort
;
ESphSortOrder
m_eSort
;
char
*
m_sSortBy
;
char
*
m_sSortBy
;
int
m_iMaxMatches
;
int
m_iMaxMatches
;
...
@@ -502,6 +562,7 @@ private:
...
@@ -502,6 +562,7 @@ private:
float
m_fGeoLongitude
;
float
m_fGeoLongitude
;
char
*
m_sComment
;
char
*
m_sComment
;
char
*
m_sSelect
;
struct
Override_t
struct
Override_t
{
{
...
@@ -538,10 +599,10 @@ protected:
...
@@ -538,10 +599,10 @@ protected:
bool
ParseField
(
char
*
sField
);
bool
ParseField
(
char
*
sField
);
void
SendBytes
(
const
void
*
pBytes
,
int
iBytes
);
void
SendBytes
(
const
void
*
pBytes
,
int
iBytes
);
void
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
short
int
)
);
}
void
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
int
)
);
}
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendDword
(
uint
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
uint
)
);
}
void
SendDword
(
uint
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
uint
(
v
>>
32
)
);
SendDword
(
uint
(
v
&
0xFFFFFFFFUL
)
);
}
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
SendString
(
const
char
*
v
)
{
int
iLen
=
strlen
(
v
);
SendDword
(
iLen
);
SendBytes
(
v
,
iLen
);
}
void
SendFloat
(
float
v
)
{
SendDword
(
sphF2DW
(
v
)
);
}
void
SendFloat
(
float
v
)
{
SendDword
(
sphF2DW
(
v
)
);
}
};
};
...
@@ -574,7 +635,7 @@ bool sphinx_show_status ( THD * thd );
...
@@ -574,7 +635,7 @@ bool sphinx_show_status ( THD * thd );
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
const
char
sphinx_hton_name
[]
=
"SPHINX"
;
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
#if MYSQL_VERSION_ID<50100
handlerton
sphinx_hton
=
handlerton
sphinx_hton
=
...
@@ -643,19 +704,19 @@ static int sphinx_init_func ( void * p )
...
@@ -643,19 +704,19 @@ static int sphinx_init_func ( void * p )
if
(
!
sphinx_init
)
if
(
!
sphinx_init
)
{
{
sphinx_init
=
1
;
sphinx_init
=
1
;
VOID
(
pthread_mutex_init
(
&
sphinx_mutex
,
MY_MUTEX_INIT_FAST
)
);
void
(
pthread_mutex_init
(
&
sphinx_mutex
,
MY_MUTEX_INIT_FAST
)
);
hash_init
(
&
sphinx_open_tables
,
system_charset_info
,
32
,
0
,
0
,
sphinx_
hash_init
(
&
sphinx_open_tables
,
system_charset_info
,
32
,
0
,
0
,
sphinx_get_key
,
0
,
0
);
sphinx_get_key
,
0
,
0
);
#if MYSQL_VERSION_ID > 50100
#if MYSQL_VERSION_ID > 50100
handlerton
*
hton
=
(
handlerton
*
)
p
;
handlerton
*
hton
=
(
handlerton
*
)
p
;
hton
->
state
=
SHOW_OPTION_YES
;
hton
->
state
=
SHOW_OPTION_YES
;
hton
->
db_type
=
DB_TYPE_DEFAULT
;
hton
->
db_type
=
DB_TYPE_FIRST_DYNAMIC
;
hton
->
create
=
sphinx_create_handler
;
hton
->
create
=
sphinx_create_handler
;
hton
->
close_connection
=
sphinx_close_connection
;
hton
->
close_connection
=
sphinx_close_connection
;
hton
->
show_status
=
sphinx_show_status
;
hton
->
show_status
=
sphinx_show_status
;
hton
->
panic
=
sphinx_panic
;
hton
->
panic
=
sphinx_panic
;
hton
->
flags
=
HTON_CAN_RECREATE
;
hton
->
flags
=
HTON_CAN_RECREATE
;
#endif
#endif
}
}
SPH_RET
(
0
);
SPH_RET
(
0
);
...
@@ -694,7 +755,7 @@ static int sphinx_done_func ( void * )
...
@@ -694,7 +755,7 @@ static int sphinx_done_func ( void * )
sphinx_init
=
0
;
sphinx_init
=
0
;
if
(
sphinx_open_tables
.
records
)
if
(
sphinx_open_tables
.
records
)
error
=
1
;
error
=
1
;
hash_free
(
&
sphinx_open_tables
);
sphinx_
hash_free
(
&
sphinx_open_tables
);
pthread_mutex_destroy
(
&
sphinx_mutex
);
pthread_mutex_destroy
(
&
sphinx_mutex
);
}
}
...
@@ -742,15 +803,22 @@ bool sphinx_show_status ( THD * thd )
...
@@ -742,15 +803,22 @@ bool sphinx_show_status ( THD * thd )
char
buf1
[
IO_SIZE
];
char
buf1
[
IO_SIZE
];
uint
buf1len
;
uint
buf1len
;
char
buf2
[
IO_SIZE
];
char
buf2
[
IO_SIZE
];
uint
buf2len
=
0
;
uint
buf2len
=
0
;
String
words
;
String
words
;
buf1
[
0
]
=
'\0'
;
buf1
[
0
]
=
'\0'
;
buf2
[
0
]
=
'\0'
;
buf2
[
0
]
=
'\0'
;
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>50100
// 5.1.x style stats
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
(
*
thd_ha_data
(
thd
,
hton
)
);
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
#else
// 5.0.x style stats
if
(
have_sphinx_db
!=
SHOW_OPTION_YES
)
if
(
have_sphinx_db
!=
SHOW_OPTION_YES
)
{
{
my_message
(
ER_NOT_SUPPORTED_YET
,
my_message
(
ER_NOT_SUPPORTED_YET
,
...
@@ -759,32 +827,33 @@ bool sphinx_show_status ( THD * thd )
...
@@ -759,32 +827,33 @@ bool sphinx_show_status ( THD * thd )
SPH_RET
(
TRUE
);
SPH_RET
(
TRUE
);
}
}
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
thd
->
ha_data
[
sphinx_hton
.
slot
];
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
#endif
// show query stats
if
(
pTls
&&
pTls
->
m_bStats
)
if
(
pTls
&&
pTls
->
m_bStats
)
{
{
const
CSphSEStats
*
pStats
=
&
pTls
->
m_tStats
;
const
CSphSEStats
*
pStats
=
&
pTls
->
m_tStats
;
buf1len
=
my_snprintf
(
buf1
,
sizeof
(
buf1
),
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
);
pStats
->
m_iMatchesTotal
,
pStats
->
m_iMatchesFound
,
pStats
->
m_iQueryMsec
,
pStats
->
m_iWords
);
#if MYSQL_VERSION_ID>50100
LOC_STATS
(
"stats"
,
5
,
buf1
,
buf1len
);
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
if
(
pStats
->
m_iWords
)
if
(
pStats
->
m_iWords
)
{
{
...
@@ -808,58 +877,30 @@ bool sphinx_show_status ( THD * thd )
...
@@ -808,58 +877,30 @@ bool sphinx_show_status ( THD * thd )
iWord
=
sBuf3
.
length
();
iWord
=
sBuf3
.
length
();
}
}
#if MYSQL_VERSION_ID>50100
LOC_STATS
(
"words"
,
5
,
sWord
,
iWord
);
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
}
}
}
// send last error or warning
// show last error or warning (either in addition to stats, or on their own)
if
(
pStats
->
m_sLastMessage
&&
pStats
->
m_sLastMessage
[
0
]
)
if
(
pTls
&&
pTls
->
m_tStats
.
m_sLastMessage
&&
pTls
->
m_tStats
.
m_sLastMessage
[
0
]
)
{
{
const
char
*
sMessageType
=
pStats
->
m_bLastError
?
"error"
:
"warning"
;
const
char
*
sMessageType
=
pTls
->
m_tStats
.
m_bLastError
?
"error"
:
"warning"
;
#if MYSQL_VERSION_ID>50100
LOC_STATS
(
stat_print
(
thd
,
sphinx_hton_name
,
strlen
(
sphinx_hton_name
),
sMessageType
,
strlen
(
sMessageType
),
sMessageType
,
strlen
(
sMessageType
),
pStats
->
m_sLastMessage
,
strlen
(
pStats
->
m_sLastMessage
)
);
pTls
->
m_tStats
.
m_sLastMessage
,
strlen
(
pTls
->
m_tStats
.
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
}
}
else
}
else
{
{
#if MYSQL_VERSION_ID < 50100
// well, nothing to show just yet
field_list
.
push_back
(
new
Item_empty_string
(
"Type"
,
10
)
);
#if MYSQL_VERSION_ID < 50100
field_list
.
push_back
(
new
Item_empty_string
(
"Name"
,
FN_REFLEN
)
);
LOC_STATS
(
"stats"
,
5
,
"no query has been executed yet"
,
sizeof
(
"no query has been executed yet"
)
-
1
);
field_list
.
push_back
(
new
Item_empty_string
(
"Status"
,
10
)
);
#endif
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
}
}
#if MYSQL_VERSION_ID < 50100
#if MYSQL_VERSION_ID < 50100
send_eof
(
thd
);
send_eof
(
thd
);
#endif
#endif
SPH_RET
(
FALSE
);
SPH_RET
(
FALSE
);
}
}
...
@@ -926,10 +967,9 @@ static void sphLogError ( const char * sFmt, ... )
...
@@ -926,10 +967,9 @@ static void sphLogError ( const char * sFmt, ... )
// the following scheme variants are recognized
// the following scheme variants are recognized
//
//
// sphinx://host/index
// sphinx://host[:port]/index
// sphinx://host:port/index
// sphinxql://host[:port]/index
// unix://unix/domain/socket:index
// unix://unix/domain/socket[:index]
// unix://unix/domain/socket
static
bool
ParseUrl
(
CSphSEShare
*
share
,
TABLE
*
table
,
bool
bCreate
)
static
bool
ParseUrl
(
CSphSEShare
*
share
,
TABLE
*
table
,
bool
bCreate
)
{
{
SPH_ENTER_FUNC
();
SPH_ENTER_FUNC
();
...
@@ -939,12 +979,12 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
...
@@ -939,12 +979,12 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
// check incoming stuff
// check incoming stuff
if
(
!
table
)
if
(
!
table
)
{
{
sphLogError
(
"table==NULL in ParseUrl()"
);
sphLogError
(
"table==NULL in ParseUrl()"
);
return
false
;
return
false
;
}
}
if
(
!
table
->
s
)
if
(
!
table
->
s
)
{
{
sphLogError
(
"(table->s)==NULL in ParseUrl()"
);
sphLogError
(
"(table->s)==NULL in ParseUrl()"
);
return
false
;
return
false
;
}
}
...
@@ -966,69 +1006,121 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
...
@@ -966,69 +1006,121 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
}
}
}
}
// defaults
bool
bOk
=
true
;
bool
bQL
=
false
;
char
*
sScheme
=
NULL
;
char
*
sScheme
=
NULL
;
char
*
sHost
=
SPHINX
SE
_DEFAULT_HOST
;
char
*
sHost
=
SPHINX
API
_DEFAULT_HOST
;
char
*
sIndex
=
SPHINX
SE
_DEFAULT_INDEX
;
char
*
sIndex
=
SPHINX
API
_DEFAULT_INDEX
;
int
iPort
=
SPHINX
SE
_DEFAULT_PORT
;
int
iPort
=
SPHINX
API
_DEFAULT_PORT
;
bool
bOk
=
true
;
// parse connection string, if any
while
(
table
->
s
->
connect_string
.
length
!=
0
)
while
(
table
->
s
->
connect_string
.
length
!=
0
)
{
{
bOk
=
false
;
sScheme
=
sphDup
(
table
->
s
->
connect_string
.
str
,
table
->
s
->
connect_string
.
length
);
sScheme
=
sphDup
(
table
->
s
->
connect_string
.
str
,
table
->
s
->
connect_string
.
length
);
sHost
=
strstr
(
sScheme
,
"://"
);
sHost
=
strstr
(
sScheme
,
"://"
);
if
(
!
sHost
)
if
(
!
sHost
)
{
bOk
=
false
;
break
;
break
;
}
sHost
[
0
]
=
'\0'
;
sHost
[
0
]
=
'\0'
;
sHost
+=
2
;
sHost
+=
3
;
/////////////////////////////
// sphinxapi via unix socket
/////////////////////////////
if
(
!
strcmp
(
sScheme
,
"unix"
)
)
if
(
!
strcmp
(
sScheme
,
"unix"
)
)
{
{
// unix-domain socket
sHost
--
;
// reuse last slash
iPort
=
0
;
iPort
=
0
;
if
(
!
(
sIndex
=
strrchr
(
sHost
,
':'
)
))
if
(
!
(
sIndex
=
strrchr
(
sHost
,
':'
)
))
sIndex
=
SPHINX
SE
_DEFAULT_INDEX
;
sIndex
=
SPHINX
API
_DEFAULT_INDEX
;
else
else
{
{
*
sIndex
++
=
'\0'
;
*
sIndex
++
=
'\0'
;
if
(
!*
sIndex
)
if
(
!*
sIndex
)
sIndex
=
SPHINX
SE
_DEFAULT_INDEX
;
sIndex
=
SPHINX
API
_DEFAULT_INDEX
;
}
}
bOk
=
true
;
bOk
=
true
;
break
;
break
;
}
}
if
(
strcmp
(
sScheme
,
"sphinx"
)
!=
0
&&
strcmp
(
sScheme
,
"inet"
)
!=
0
)
break
;
// tcp
/////////////////////
sHost
++
;
// sphinxapi via tcp
char
*
sPort
=
strchr
(
sHost
,
':'
);
/////////////////////
if
(
sPort
)
if
(
!
strcmp
(
sScheme
,
"sphinx"
)
)
{
{
*
sPort
++
=
'\0'
;
char
*
sPort
=
strchr
(
sHost
,
':'
)
;
if
(
*
sPort
)
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
)
if
(
sIndex
)
*
sIndex
++
=
'\0'
;
*
sIndex
++
=
'\0'
;
else
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
);
iPort
=
atoi
(
sPort
);
if
(
!
iPort
)
if
(
!
iPort
)
iPort
=
SPHINXSE_DEFAULT_PORT
;
{
bOk
=
false
;
// invalid port; can report ER_FOREIGN_DATA_STRING_INVALID
break
;
}
}
}
}
else
{
// find index
sIndex
=
strchr
(
s
Host
,
'/'
);
sIndex
=
strchr
(
s
Index
,
'/'
);
if
(
sIndex
)
if
(
sIndex
)
*
sIndex
++
=
'\0'
;
*
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
;
break
;
}
}
...
@@ -1045,6 +1137,7 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
...
@@ -1045,6 +1137,7 @@ static bool ParseUrl ( CSphSEShare * share, TABLE * table, bool bCreate )
share
->
m_sHost
=
sHost
;
share
->
m_sHost
=
sHost
;
share
->
m_sIndex
=
sIndex
;
share
->
m_sIndex
=
sIndex
;
share
->
m_iPort
=
(
ushort
)
iPort
;
share
->
m_iPort
=
(
ushort
)
iPort
;
share
->
m_bSphinxQL
=
bQL
;
}
}
}
}
if
(
!
bOk
&&
!
share
)
if
(
!
bOk
&&
!
share
)
...
@@ -1067,12 +1160,12 @@ static CSphSEShare * get_share ( const char * table_name, TABLE * table )
...
@@ -1067,12 +1160,12 @@ static CSphSEShare * get_share ( const char * table_name, TABLE * table )
{
{
// check if we already have this share
// check if we already have this share
#if MYSQL_VERSION_ID>=50120
#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
#else
#ifdef __WIN__
#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
#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 // win
#endif // pre-5.1.20
#endif // pre-5.1.20
...
@@ -1088,13 +1181,15 @@ static CSphSEShare * get_share ( const char * table_name, TABLE * table )
...
@@ -1088,13 +1181,15 @@ static CSphSEShare * get_share ( const char * table_name, TABLE * table )
break
;
break
;
// try to setup it
// try to setup it
pShare
->
m_pTableQueryCharset
=
table
->
field
[
2
]
->
charset
();
if
(
!
ParseUrl
(
pShare
,
table
,
false
)
)
if
(
!
ParseUrl
(
pShare
,
table
,
false
)
)
{
{
SafeDelete
(
pShare
);
SafeDelete
(
pShare
);
break
;
break
;
}
}
if
(
!
pShare
->
m_bSphinxQL
)
pShare
->
m_pTableQueryCharset
=
table
->
field
[
2
]
->
charset
();
// try to hash it
// try to hash it
pShare
->
m_iTableNameLen
=
strlen
(
table_name
);
pShare
->
m_iTableNameLen
=
strlen
(
table_name
);
pShare
->
m_sTable
=
sphDup
(
table_name
);
pShare
->
m_sTable
=
sphDup
(
table_name
);
...
@@ -1122,7 +1217,7 @@ static int free_share ( CSphSEShare * pShare )
...
@@ -1122,7 +1217,7 @@ static int free_share ( CSphSEShare * pShare )
if
(
!--
pShare
->
m_iUseCount
)
if
(
!--
pShare
->
m_iUseCount
)
{
{
hash_delete
(
&
sphinx_open_tables
,
(
byte
*
)
pShare
);
sphinx_
hash_delete
(
&
sphinx_open_tables
,
(
byte
*
)
pShare
);
SafeDelete
(
pShare
);
SafeDelete
(
pShare
);
}
}
...
@@ -1155,6 +1250,7 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
...
@@ -1155,6 +1250,7 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
,
m_iWeights
(
0
)
,
m_iWeights
(
0
)
,
m_eMode
(
SPH_MATCH_ALL
)
,
m_eMode
(
SPH_MATCH_ALL
)
,
m_eRanker
(
SPH_RANK_PROXIMITY_BM25
)
,
m_eRanker
(
SPH_RANK_PROXIMITY_BM25
)
,
m_sRankExpr
(
NULL
)
,
m_eSort
(
SPH_SORT_RELEVANCE
)
,
m_eSort
(
SPH_SORT_RELEVANCE
)
,
m_sSortBy
(
""
)
,
m_sSortBy
(
""
)
,
m_iMaxMatches
(
1000
)
,
m_iMaxMatches
(
1000
)
...
@@ -1177,6 +1273,7 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
...
@@ -1177,6 +1273,7 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
,
m_fGeoLatitude
(
0.0
f
)
,
m_fGeoLatitude
(
0.0
f
)
,
m_fGeoLongitude
(
0.0
f
)
,
m_fGeoLongitude
(
0.0
f
)
,
m_sComment
(
""
)
,
m_sComment
(
""
)
,
m_sSelect
(
""
)
,
m_pBuf
(
NULL
)
,
m_pBuf
(
NULL
)
,
m_pCur
(
NULL
)
,
m_pCur
(
NULL
)
...
@@ -1185,8 +1282,8 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
...
@@ -1185,8 +1282,8 @@ CSphSEQuery::CSphSEQuery ( const char * sQuery, int iLength, const char * sIndex
{
{
m_sQueryBuffer
=
new
char
[
iLength
+
2
];
m_sQueryBuffer
=
new
char
[
iLength
+
2
];
memcpy
(
m_sQueryBuffer
,
sQuery
,
iLength
);
memcpy
(
m_sQueryBuffer
,
sQuery
,
iLength
);
m_sQueryBuffer
[
iLength
]
=
';'
;
m_sQueryBuffer
[
iLength
]
=
';'
;
m_sQueryBuffer
[
iLength
+
1
]
=
'\0'
;
m_sQueryBuffer
[
iLength
+
1
]
=
'\0'
;
}
}
...
@@ -1242,22 +1339,20 @@ int CSphSEQuery::ParseArray ( T ** ppValues, const char * sValue )
...
@@ -1242,22 +1339,20 @@ int CSphSEQuery::ParseArray ( T ** ppValues, const char * sValue )
if
(
!
bPrevDigit
)
if
(
!
bPrevDigit
)
uValue
=
0
;
uValue
=
0
;
uValue
=
uValue
*
10
+
(
(
*
pValue
)
-
'0'
);
uValue
=
uValue
*
10
+
(
(
*
pValue
)
-
'0'
);
}
}
else
if
(
bPrevDigit
)
else
if
(
bPrevDigit
)
{
{
assert
(
iIndex
<
iValues
);
assert
(
iIndex
<
iValues
);
pValues
[
iIndex
++
]
=
uValue
*
iSign
;
pValues
[
iIndex
++
]
=
uValue
*
iSign
;
iSign
=
1
;
iSign
=
1
;
}
}
else
if
(
*
pValue
==
'-'
)
else
if
(
*
pValue
==
'-'
)
iSign
=
-
1
;
iSign
=
-
1
;
bPrevDigit
=
bDigit
;
bPrevDigit
=
bDigit
;
if
(
!*
pValue
)
if
(
!*
pValue
)
break
;
break
;
}
}
SPH_RET
(
iValues
);
SPH_RET
(
iValues
);
}
}
...
@@ -1267,7 +1362,7 @@ static char * chop ( char * s )
...
@@ -1267,7 +1362,7 @@ static char * chop ( char * s )
s
++
;
s
++
;
char
*
p
=
s
+
strlen
(
s
);
char
*
p
=
s
+
strlen
(
s
);
while
(
p
>
s
&&
isspace
(
p
[
-
1
]
)
)
while
(
p
>
s
&&
isspace
(
p
[
-
1
]
)
)
p
--
;
p
--
;
*
p
=
'\0'
;
*
p
=
'\0'
;
...
@@ -1284,6 +1379,11 @@ static bool myisattr ( char c )
...
@@ -1284,6 +1379,11 @@ static bool myisattr ( char c )
c
==
'_'
;
c
==
'_'
;
}
}
static
bool
myismagic
(
char
c
)
{
return
c
==
'@'
;
}
bool
CSphSEQuery
::
ParseField
(
char
*
sField
)
bool
CSphSEQuery
::
ParseField
(
char
*
sField
)
{
{
...
@@ -1305,11 +1405,13 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1305,11 +1405,13 @@ bool CSphSEQuery::ParseField ( char * sField )
m_sQuery
=
sField
;
m_sQuery
=
sField
;
m_bQuery
=
true
;
m_bQuery
=
true
;
// unescape
// unescape
only 1st one
char
*
s
=
sField
,
*
d
=
sField
;
char
*
s
=
sField
,
*
d
=
sField
;
int
iSlashes
=
0
;
while
(
*
s
)
while
(
*
s
)
{
{
if
(
*
s
!=
'\\'
)
*
d
++
=
*
s
;
iSlashes
=
(
*
s
==
'\\'
)
?
iSlashes
+
1
:
0
;
if
(
(
iSlashes
%
2
)
==
0
)
*
d
++
=
*
s
;
s
++
;
s
++
;
}
}
*
d
=
'\0'
;
*
d
=
'\0'
;
...
@@ -1341,20 +1443,20 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1341,20 +1443,20 @@ bool CSphSEQuery::ParseField ( char * sField )
else
if
(
!
strcmp
(
sName
,
"distinct"
)
)
m_sGroupDistinct
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"distinct"
)
)
m_sGroupDistinct
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"cutoff"
)
)
m_iCutoff
=
iValue
;
else
if
(
!
strcmp
(
sName
,
"cutoff"
)
)
m_iCutoff
=
iValue
;
else
if
(
!
strcmp
(
sName
,
"comment"
)
)
m_sComment
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"comment"
)
)
m_sComment
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"select"
)
)
m_sSelect
=
sValue
;
else
if
(
!
strcmp
(
sName
,
"mode"
)
)
else
if
(
!
strcmp
(
sName
,
"mode"
)
)
{
{
m_eMode
=
SPH_MATCH_ALL
;
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
,
"phrase"
)
)
m_eMode
=
SPH_MATCH_PHRASE
;
else
if
(
!
strcmp
(
sValue
,
"boolean"
)
)
m_eMode
=
SPH_MATCH_BOOLEAN
;
else
if
(
!
strcmp
(
sValue
,
"boolean"
)
)
m_eMode
=
SPH_MATCH_BOOLEAN
;
else
if
(
!
strcmp
(
sValue
,
"ext"
)
)
m_eMode
=
SPH_MATCH_EXTENDED
;
else
if
(
!
strcmp
(
sValue
,
"ext"
)
)
m_eMode
=
SPH_MATCH_EXTENDED
;
else
if
(
!
strcmp
(
sValue
,
"extended"
)
)
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
,
"ext2"
)
)
m_eMode
=
SPH_MATCH_EXTENDED2
;
else
if
(
!
strcmp
(
sValue
,
"extended2"
)
)
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
,
"all"
)
)
m_eMode
=
SPH_MATCH_ALL
;
else
if
(
!
strcmp
(
sValue
,
"fullscan"
)
)
m_eMode
=
SPH_MATCH_FULLSCAN
;
else
if
(
!
strcmp
(
sValue
,
"fullscan"
)
)
m_eMode
=
SPH_MATCH_FULLSCAN
;
else
else
{
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown matching mode '%s'"
,
sValue
);
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown matching mode '%s'"
,
sValue
);
...
@@ -1362,27 +1464,31 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1362,27 +1464,31 @@ bool CSphSEQuery::ParseField ( char * sField )
}
}
}
else
if
(
!
strcmp
(
sName
,
"ranker"
)
)
}
else
if
(
!
strcmp
(
sName
,
"ranker"
)
)
{
{
m_eRanker
=
SPH_RANK_PROXIMITY_BM25
;
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
,
"bm25"
)
)
m_eRanker
=
SPH_RANK_BM25
;
else
if
(
!
strcmp
(
sValue
,
"none"
)
)
m_eRanker
=
SPH_RANK_NONE
;
else
if
(
!
strcmp
(
sValue
,
"none"
)
)
m_eRanker
=
SPH_RANK_NONE
;
else
if
(
!
strcmp
(
sValue
,
"wordcount"
)
)
m_eRanker
=
SPH_RANK_WORDCOUNT
;
else
if
(
!
strcmp
(
sValue
,
"wordcount"
)
)
m_eRanker
=
SPH_RANK_WORDCOUNT
;
else
if
(
!
strcmp
(
sValue
,
"proximity"
)
)
m_eRanker
=
SPH_RANK_PROXIMITY
;
else
if
(
!
strcmp
(
sValue
,
"proximity"
)
)
m_eRanker
=
SPH_RANK_PROXIMITY
;
else
if
(
!
strcmp
(
sValue
,
"matchany"
)
)
m_eRanker
=
SPH_RANK_MATCHANY
;
else
if
(
!
strcmp
(
sValue
,
"matchany"
)
)
m_eRanker
=
SPH_RANK_MATCHANY
;
else
if
(
!
strcmp
(
sValue
,
"fieldmask"
)
)
m_eRanker
=
SPH_RANK_FIELDMASK
;
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
);
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown ranking mode '%s'"
,
sValue
);
SPH_RET
(
false
);
SPH_RET
(
false
);
}
}
}
else
if
(
!
strcmp
(
sName
,
"sort"
)
)
}
else
if
(
!
strcmp
(
sName
,
"sort"
)
)
{
{
static
const
struct
static
const
struct
{
{
const
char
*
m_sName
;
const
char
*
m_sName
;
ESphSortOrder
m_eSort
;
ESphSortOrder
m_eSort
;
}
dSortModes
[]
=
}
dSortModes
[]
=
{
{
{
"relevance"
,
SPH_SORT_RELEVANCE
},
{
"relevance"
,
SPH_SORT_RELEVANCE
},
{
"attr_desc:"
,
SPH_SORT_ATTR_DESC
},
{
"attr_desc:"
,
SPH_SORT_ATTR_DESC
},
...
@@ -1395,10 +1501,10 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1395,10 +1501,10 @@ bool CSphSEQuery::ParseField ( char * sField )
int
i
;
int
i
;
const
int
nModes
=
sizeof
(
dSortModes
)
/
sizeof
(
dSortModes
[
0
]);
const
int
nModes
=
sizeof
(
dSortModes
)
/
sizeof
(
dSortModes
[
0
]);
for
(
i
=
0
;
i
<
nModes
;
i
++
)
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_eSort
=
dSortModes
[
i
].
m_eSort
;
m_sSortBy
=
sValue
+
strlen
(
dSortModes
[
i
].
m_sName
);
m_sSortBy
=
sValue
+
strlen
(
dSortModes
[
i
].
m_sName
);
break
;
break
;
}
}
if
(
i
==
nModes
)
if
(
i
==
nModes
)
...
@@ -1409,11 +1515,11 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1409,11 +1515,11 @@ bool CSphSEQuery::ParseField ( char * sField )
}
else
if
(
!
strcmp
(
sName
,
"groupby"
)
)
}
else
if
(
!
strcmp
(
sName
,
"groupby"
)
)
{
{
static
const
struct
static
const
struct
{
{
const
char
*
m_sName
;
const
char
*
m_sName
;
ESphGroupBy
m_eFunc
;
ESphGroupBy
m_eFunc
;
}
dGroupModes
[]
=
}
dGroupModes
[]
=
{
{
{
"day:"
,
SPH_GROUPBY_DAY
},
{
"day:"
,
SPH_GROUPBY_DAY
},
{
"week:"
,
SPH_GROUPBY_WEEK
},
{
"week:"
,
SPH_GROUPBY_WEEK
},
...
@@ -1425,10 +1531,10 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1425,10 +1531,10 @@ bool CSphSEQuery::ParseField ( char * sField )
int
i
;
int
i
;
const
int
nModes
=
sizeof
(
dGroupModes
)
/
sizeof
(
dGroupModes
[
0
]);
const
int
nModes
=
sizeof
(
dGroupModes
)
/
sizeof
(
dGroupModes
[
0
]);
for
(
i
=
0
;
i
<
nModes
;
i
++
)
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_eGroupFunc
=
dGroupModes
[
i
].
m_eFunc
;
m_sGroupBy
=
sValue
+
strlen
(
dGroupModes
[
i
].
m_sName
);
m_sGroupBy
=
sValue
+
strlen
(
dGroupModes
[
i
].
m_sName
);
break
;
break
;
}
}
if
(
i
==
nModes
)
if
(
i
==
nModes
)
...
@@ -1460,8 +1566,8 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1460,8 +1566,8 @@ bool CSphSEQuery::ParseField ( char * sField )
if
(
tFilter
.
m_eType
==
SPH_FILTER_RANGE
)
if
(
tFilter
.
m_eType
==
SPH_FILTER_RANGE
)
{
{
tFilter
.
m_uMinValue
=
strtoll
(
sValue
,
NULL
,
0
);
tFilter
.
m_uMinValue
=
strtoll
(
sValue
,
NULL
,
1
0
);
tFilter
.
m_uMaxValue
=
strtoll
(
p
,
NULL
,
0
);
tFilter
.
m_uMaxValue
=
strtoll
(
p
,
NULL
,
1
0
);
}
else
}
else
{
{
tFilter
.
m_fMinValue
=
(
float
)
atof
(
sValue
);
tFilter
.
m_fMinValue
=
(
float
)
atof
(
sValue
);
...
@@ -1480,16 +1586,16 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1480,16 +1586,16 @@ bool CSphSEQuery::ParseField ( char * sField )
{
{
CSphSEFilter
&
tFilter
=
m_dFilters
[
m_iFilters
];
CSphSEFilter
&
tFilter
=
m_dFilters
[
m_iFilters
];
tFilter
.
m_eType
=
SPH_FILTER_VALUES
;
tFilter
.
m_eType
=
SPH_FILTER_VALUES
;
tFilter
.
m_bExclude
=
(
strcmp
(
sName
,
"!filter"
)
==
0
);
tFilter
.
m_bExclude
=
(
strcmp
(
sName
,
"!filter"
)
==
0
);
// get the attr name
// get the attr name
while
(
(
*
sValue
)
&&
!
myisattr
(
*
sValue
)
)
while
(
(
*
sValue
)
&&
!
(
myisattr
(
*
sValue
)
||
myismagic
(
*
sValue
)
)
)
sValue
++
;
sValue
++
;
if
(
!*
sValue
)
if
(
!*
sValue
)
break
;
break
;
tFilter
.
m_sAttrName
=
sValue
;
tFilter
.
m_sAttrName
=
sValue
;
while
(
(
*
sValue
)
&&
myisattr
(
*
sValue
)
)
while
(
(
*
sValue
)
&&
(
myisattr
(
*
sValue
)
||
myismagic
(
*
sValue
)
)
)
sValue
++
;
sValue
++
;
if
(
!*
sValue
)
if
(
!*
sValue
)
break
;
break
;
...
@@ -1548,7 +1654,8 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1548,7 +1654,8 @@ bool CSphSEQuery::ParseField ( char * sField )
pWeights
[
*
pCount
]
=
atoi
(
sVal
);
pWeights
[
*
pCount
]
=
atoi
(
sVal
);
(
*
pCount
)
++
;
(
*
pCount
)
++
;
if
(
!*
p
)
break
;
if
(
!*
p
)
break
;
if
(
*
p
!=
','
)
if
(
*
p
!=
','
)
{
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"%s: comma expected near '%s'"
,
sName
,
p
);
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"%s: comma expected near '%s'"
,
sName
,
p
);
...
@@ -1576,8 +1683,8 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1576,8 +1683,8 @@ bool CSphSEQuery::ParseField ( char * sField )
m_sGeoLatAttr
=
chop
(
sLat
);
m_sGeoLatAttr
=
chop
(
sLat
);
m_sGeoLongAttr
=
chop
(
sLong
);
m_sGeoLongAttr
=
chop
(
sLong
);
m_fGeoLatitude
=
(
float
)
atof
(
sLatVal
);
m_fGeoLatitude
=
(
float
)
atof
(
sLatVal
);
m_fGeoLongitude
=
(
float
)
atof
(
sLongVal
);
m_fGeoLongitude
=
(
float
)
atof
(
sLongVal
);
m_bGeoAnchor
=
true
;
m_bGeoAnchor
=
true
;
break
;
break
;
}
}
...
@@ -1586,8 +1693,7 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1586,8 +1693,7 @@ bool CSphSEQuery::ParseField ( char * sField )
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"geoanchor: parse error, not enough comma-separated arguments"
);
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"geoanchor: parse error, not enough comma-separated arguments"
);
SPH_RET
(
false
);
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
;
char
*
sName
=
NULL
;
int
iType
=
0
;
int
iType
=
0
;
...
@@ -1600,11 +1706,13 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1600,11 +1706,13 @@ bool CSphSEQuery::ParseField ( char * sField )
sName
=
sRest
;
sName
=
sRest
;
if
(
!*
sName
)
if
(
!*
sName
)
break
;
break
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
*
sRest
++
=
'\0'
;
break
;
*
sRest
++
=
'\0'
;
char
*
sType
=
sRest
;
char
*
sType
=
sRest
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
if
(
!
(
sRest
=
strchr
(
sRest
,
','
)
))
break
;
static
const
struct
static
const
struct
{
{
const
char
*
m_sName
;
const
char
*
m_sName
;
...
@@ -1619,7 +1727,7 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1619,7 +1727,7 @@ bool CSphSEQuery::ParseField ( char * sField )
{
"bigint"
,
SPH_ATTR_BIGINT
}
{
"bigint"
,
SPH_ATTR_BIGINT
}
};
};
for
(
int
i
=
0
;
i
<
sizeof
(
dAttrTypes
)
/
sizeof
(
*
dAttrTypes
);
i
++
)
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
;
iType
=
dAttrTypes
[
i
].
m_iType
;
break
;
break
;
...
@@ -1628,7 +1736,7 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1628,7 +1736,7 @@ bool CSphSEQuery::ParseField ( char * sField )
}
}
// fail
// fail
if
(
!
sName
||
!*
sName
||
!
iType
)
if
(
!
sName
||
!*
sName
||
!
iType
)
{
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"override: malformed query"
);
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"override: malformed query"
);
SPH_RET
(
false
);
SPH_RET
(
false
);
...
@@ -1643,7 +1751,8 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1643,7 +1751,8 @@ bool CSphSEQuery::ParseField ( char * sField )
if
(
!
(
sRest
-
sId
))
break
;
if
(
!
(
sRest
-
sId
))
break
;
char
*
sValue
=
sRest
;
char
*
sValue
=
sRest
;
if
((
sRest
=
strchr
(
sRest
,
','
)
))
*
sRest
++
=
'\0'
;
if
(
(
sRest
=
strchr
(
sRest
,
','
)
)
!=
NULL
)
*
sRest
++
=
'\0'
;
if
(
!*
sValue
)
if
(
!*
sValue
)
break
;
break
;
...
@@ -1652,18 +1761,18 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1652,18 +1761,18 @@ bool CSphSEQuery::ParseField ( char * sField )
pOverride
=
new
CSphSEQuery
::
Override_t
;
pOverride
=
new
CSphSEQuery
::
Override_t
;
pOverride
->
m_sName
=
chop
(
sName
);
pOverride
->
m_sName
=
chop
(
sName
);
pOverride
->
m_iType
=
iType
;
pOverride
->
m_iType
=
iType
;
m_dOverrides
.
append
(
pOverride
);
m_dOverrides
.
append
(
pOverride
);
}
}
ulonglong
uId
=
strtoull
(
sId
,
NULL
,
10
);
ulonglong
uId
=
strtoull
(
sId
,
NULL
,
10
);
CSphSEQuery
::
Override_t
::
Value_t
tValue
;
CSphSEQuery
::
Override_t
::
Value_t
tValue
;
if
(
iType
==
SPH_ATTR_FLOAT
)
if
(
iType
==
SPH_ATTR_FLOAT
)
tValue
.
m_fValue
=
(
float
)
atof
(
sValue
);
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
);
tValue
.
m_iValue64
=
strtoll
(
sValue
,
NULL
,
10
);
else
else
tValue
.
m_uValue
=
(
uint32
)
strtoul
(
sValue
,
NULL
,
10
);
tValue
.
m_uValue
=
(
uint32
)
strtoul
(
sValue
,
NULL
,
10
);
pOverride
->
m_dIds
.
append
(
uId
);
pOverride
->
m_dIds
.
append
(
uId
);
pOverride
->
m_dValues
.
append
(
tValue
);
pOverride
->
m_dValues
.
append
(
tValue
);
}
}
...
@@ -1674,8 +1783,7 @@ bool CSphSEQuery::ParseField ( char * sField )
...
@@ -1674,8 +1783,7 @@ bool CSphSEQuery::ParseField ( char * sField )
SPH_RET
(
false
);
SPH_RET
(
false
);
}
}
SPH_RET
(
true
);
SPH_RET
(
true
);
}
}
else
else
{
{
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown parameter '%s'"
,
sName
);
snprintf
(
m_sParseError
,
sizeof
(
m_sParseError
),
"unknown parameter '%s'"
,
sName
);
SPH_RET
(
false
);
SPH_RET
(
false
);
...
@@ -1696,7 +1804,7 @@ bool CSphSEQuery::Parse ()
...
@@ -1696,7 +1804,7 @@ bool CSphSEQuery::Parse ()
char
*
pCur
=
m_sQueryBuffer
;
char
*
pCur
=
m_sQueryBuffer
;
char
*
pNext
=
pCur
;
char
*
pNext
=
pCur
;
while
(
(
pNext
=
strchr
(
pNext
,
';'
)
)
)
while
(
(
pNext
=
strchr
(
pNext
,
';'
)
)
!=
NULL
)
{
{
// handle escaped semicolons
// handle escaped semicolons
if
(
pNext
>
m_sQueryBuffer
&&
pNext
[
-
1
]
==
'\\'
&&
pNext
[
1
]
!=
'\0'
)
if
(
pNext
>
m_sQueryBuffer
&&
pNext
[
-
1
]
==
'\\'
&&
pNext
[
1
]
!=
'\0'
)
...
@@ -1712,6 +1820,8 @@ bool CSphSEQuery::Parse ()
...
@@ -1712,6 +1820,8 @@ bool CSphSEQuery::Parse ()
pCur
=
pNext
;
pCur
=
pNext
;
}
}
SPH_DEBUG
(
"q [[ %s ]]"
,
m_sQuery
);
SPH_RET
(
true
);
SPH_RET
(
true
);
}
}
...
@@ -1738,14 +1848,17 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
...
@@ -1738,14 +1848,17 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
SPH_ENTER_METHOD
();
SPH_ENTER_METHOD
();
// calc request length
// calc request length
int
iReqSize
=
12
4
+
4
*
m_iWeights
int
iReqSize
=
12
8
+
4
*
m_iWeights
+
strlen
(
m_sSortBy
)
+
strlen
(
m_sSortBy
)
+
strlen
(
m_sQuery
)
+
strlen
(
m_sQuery
)
+
strlen
(
m_sIndex
)
+
strlen
(
m_sIndex
)
+
strlen
(
m_sGroupBy
)
+
strlen
(
m_sGroupBy
)
+
strlen
(
m_sGroupSortBy
)
+
strlen
(
m_sGroupSortBy
)
+
strlen
(
m_sGroupDistinct
)
+
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
++
)
for
(
int
i
=
0
;
i
<
m_iFilters
;
i
++
)
{
{
const
CSphSEFilter
&
tFilter
=
m_dFilters
[
i
];
const
CSphSEFilter
&
tFilter
=
m_dFilters
[
i
];
...
@@ -1758,7 +1871,7 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
...
@@ -1758,7 +1871,7 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
}
}
}
}
if
(
m_bGeoAnchor
)
// 1.14+
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+
for
(
int
i
=
0
;
i
<
m_iIndexWeights
;
i
++
)
// 1.15+
iReqSize
+=
8
+
strlen
(
m_sIndexWeight
[
i
]
);
iReqSize
+=
8
+
strlen
(
m_sIndexWeight
[
i
]
);
for
(
int
i
=
0
;
i
<
m_iFieldWeights
;
i
++
)
// 1.18+
for
(
int
i
=
0
;
i
<
m_iFieldWeights
;
i
++
)
// 1.18+
...
@@ -1768,12 +1881,12 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
...
@@ -1768,12 +1881,12 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
for
(
int
i
=
0
;
i
<
m_dOverrides
.
elements
();
i
++
)
for
(
int
i
=
0
;
i
<
m_dOverrides
.
elements
();
i
++
)
{
{
CSphSEQuery
::
Override_t
*
pOverride
=
m_dOverrides
.
at
(
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
();
iReqSize
+=
strlen
(
pOverride
->
m_sName
)
+
12
+
uSize
*
pOverride
->
m_dIds
.
elements
();
}
}
// select
// select
iReqSize
+=
4
;
iReqSize
+=
4
;
m_iBufLeft
=
0
;
m_iBufLeft
=
0
;
SafeDeleteArray
(
m_pBuf
);
SafeDeleteArray
(
m_pBuf
);
...
@@ -1790,12 +1903,15 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
...
@@ -1790,12 +1903,15 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
SendWord
(
SEARCHD_COMMAND_SEARCH
);
// command id
SendWord
(
SEARCHD_COMMAND_SEARCH
);
// command id
SendWord
(
VER_COMMAND_SEARCH
);
// command version
SendWord
(
VER_COMMAND_SEARCH
);
// command version
SendInt
(
iReqSize
-
8
);
// packet body length
SendInt
(
iReqSize
-
8
);
// packet body length
SendInt
(
0
);
// its a client
SendInt
(
1
);
// number of queries
SendInt
(
1
);
// number of queries
SendInt
(
m_iOffset
);
SendInt
(
m_iOffset
);
SendInt
(
m_iLimit
);
SendInt
(
m_iLimit
);
SendInt
(
m_eMode
);
SendInt
(
m_eMode
);
SendInt
(
m_eRanker
);
// 1.16+
SendInt
(
m_eRanker
);
// 1.16+
if
(
m_eRanker
==
SPH_RANK_EXPR
)
SendString
(
m_sRankExpr
);
SendInt
(
m_eSort
);
SendInt
(
m_eSort
);
SendString
(
m_sSortBy
);
// sort attr
SendString
(
m_sSortBy
);
// sort attr
SendString
(
m_sQuery
);
// query
SendString
(
m_sQuery
);
// query
...
@@ -1878,9 +1994,9 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
...
@@ -1878,9 +1994,9 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
for
(
int
j
=
0
;
j
<
pOverride
->
m_dIds
.
elements
();
j
++
)
for
(
int
j
=
0
;
j
<
pOverride
->
m_dIds
.
elements
();
j
++
)
{
{
SendUint64
(
pOverride
->
m_dIds
.
at
(
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
);
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
);
SendUint64
(
pOverride
->
m_dValues
.
at
(
j
).
m_iValue64
);
else
else
SendDword
(
pOverride
->
m_dValues
.
at
(
j
).
m_uValue
);
SendDword
(
pOverride
->
m_dValues
.
at
(
j
).
m_uValue
);
...
@@ -1888,14 +2004,14 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
...
@@ -1888,14 +2004,14 @@ int CSphSEQuery::BuildRequest ( char ** ppBuffer )
}
}
// select
// select
SendString
(
""
);
SendString
(
m_sSelect
);
// detect buffer overruns and underruns, and report internal error
// detect buffer overruns and underruns, and report internal error
if
(
m_bBufOverrun
||
m_iBufLeft
!=
0
||
m_pCur
-
m_pBuf
!=
iReqSize
)
if
(
m_bBufOverrun
||
m_iBufLeft
!=
0
||
m_pCur
-
m_pBuf
!=
iReqSize
)
SPH_RET
(
-
1
);
SPH_RET
(
-
1
);
// all fine
// all fine
SPH_RET
(
iReqSize
);
SPH_RET
(
iReqSize
);
}
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
...
@@ -1970,10 +2086,8 @@ int ha_sphinx::open ( const char * name, int, uint )
...
@@ -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
;
struct
sockaddr_in
sin
;
#ifndef __WIN__
#ifndef __WIN__
struct
sockaddr_un
saun
;
struct
sockaddr_un
saun
;
...
@@ -1984,13 +2098,8 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
...
@@ -1984,13 +2098,8 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
struct
sockaddr
*
pSockaddr
=
NULL
;
struct
sockaddr
*
pSockaddr
=
NULL
;
in_addr_t
ip_addr
;
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
;
iDomain
=
AF_INET
;
iSockaddrSize
=
sizeof
(
sin
);
iSockaddrSize
=
sizeof
(
sin
);
...
@@ -1998,34 +2107,53 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
...
@@ -1998,34 +2107,53 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
sin
.
sin_family
=
AF_INET
;
sin
.
sin_family
=
AF_INET
;
sin
.
sin_port
=
htons
(
i
Port
);
sin
.
sin_port
=
htons
(
u
Port
);
// prepare host address
// 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
)
);
memcpy
(
&
sin
.
sin_addr
,
&
ip_addr
,
sizeof
(
ip_addr
)
);
}
else
}
else
{
{
int
tmp_errno
;
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
;
struct
hostent
tmp_hostent
,
*
hp
;
char
buff2
[
GETHOSTBYNAME_BUFF_SIZE
];
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
)
if
(
!
hp
)
{
{
my_gethostbyname_r_free
();
my_gethostbyname_r_free
();
bError
=
true
;
}
#endif
if
(
bError
)
{
char
sError
[
256
];
char
sError
[
256
];
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
sHost
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
sHost
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
SPH_RET
(
-
1
);
}
}
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
#if MYSQL_VERSION_ID>=50515
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
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
();
my_gethostbyname_r_free
();
#endif
}
}
}
else
}
else
{
{
...
@@ -2056,30 +2184,49 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
...
@@ -2056,30 +2184,49 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
{
{
sphSockClose
(
iSocket
);
sphSockClose
(
iSocket
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to connect to searchd (host=%s, errno=%d, port=%d)"
,
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
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
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
)
)
if
(
::
recv
(
iSocket
,
(
char
*
)
&
version
,
sizeof
(
version
),
0
)
!=
sizeof
(
version
)
)
{
{
sphSockClose
(
iSocket
);
sphSockClose
(
iSocket
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to receive searchd version (host=%s, port=%d)"
,
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
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
SPH_RET
(
-
1
);
}
}
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
if
(
::
send
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
),
0
)
!=
sizeof
(
uClientVersion
)
)
if
(
::
send
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
),
0
)
!=
sizeof
(
uClientVersion
)
)
{
{
sphSockClose
(
iSocket
);
sphSockClose
(
iSocket
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to send client version (host=%s, port=%d)"
,
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
);
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
SPH_RET
(
-
1
);
SPH_RET
(
-
1
);
}
}
SPH_RET
(
iSocket
);
SPH_RET
(
iSocket
);
}
}
...
@@ -2094,25 +2241,182 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
...
@@ -2094,25 +2241,182 @@ int ha_sphinx::ConnectToSearchd ( const char * sQueryHost, int iQueryPort )
int
ha_sphinx
::
close
()
int
ha_sphinx
::
close
()
{
{
SPH_ENTER_METHOD
();
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_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_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_ENTER_METHOD
();
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
SPH_RET
(
HA_ERR_WRONG_COMMAND
);
...
@@ -2125,6 +2429,11 @@ int ha_sphinx::index_init ( uint keynr, bool )
...
@@ -2125,6 +2429,11 @@ int ha_sphinx::index_init ( uint keynr, bool )
{
{
SPH_ENTER_METHOD
();
SPH_ENTER_METHOD
();
active_index
=
keynr
;
active_index
=
keynr
;
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
pTls
)
pTls
->
m_bCondDone
=
false
;
SPH_RET
(
0
);
SPH_RET
(
0
);
}
}
...
@@ -2136,17 +2445,28 @@ int ha_sphinx::index_end()
...
@@ -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_pCur
=
m_pResponseEnd
;
m_bUnpackError
=
true
;
m_bUnpackError
=
true
;
return
false
;
}
return
true
;
}
uint32
ha_sphinx
::
UnpackDword
()
{
if
(
!
CheckResponcePtr
(
sizeof
(
uint32
)
)
)
// NOLINT
{
return
0
;
return
0
;
}
}
uint32
uRes
=
ntohl
(
sphUnalignedRead
(
*
(
uint32
*
)
m_pCur
)
);
uint32
uRes
=
ntohl
(
sphUnalignedRead
(
*
(
uint32
*
)
m_pCur
)
);
m_pCur
+=
sizeof
(
uint32
);
m_pCur
+=
sizeof
(
uint32
);
// NOLINT
return
uRes
;
return
uRes
;
}
}
...
@@ -2157,10 +2477,8 @@ char * ha_sphinx::UnpackString ()
...
@@ -2157,10 +2477,8 @@ char * ha_sphinx::UnpackString ()
if
(
!
iLen
)
if
(
!
iLen
)
return
NULL
;
return
NULL
;
if
(
m_pCur
+
iLen
>
m_pResponseEnd
)
if
(
!
CheckResponcePtr
(
iLen
)
)
{
{
m_pCur
=
m_pResponseEnd
;
m_bUnpackError
=
true
;
return
NULL
;
return
NULL
;
}
}
...
@@ -2270,7 +2588,7 @@ bool ha_sphinx::UnpackSchema ()
...
@@ -2270,7 +2588,7 @@ bool ha_sphinx::UnpackSchema ()
m_iMatchesTotal
=
UnpackDword
();
m_iMatchesTotal
=
UnpackDword
();
m_bId64
=
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"
);
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
);
SPH_RET
(
false
);
...
@@ -2299,7 +2617,7 @@ bool ha_sphinx::UnpackSchema ()
...
@@ -2299,7 +2617,7 @@ bool ha_sphinx::UnpackSchema ()
if
(
m_bUnpackError
)
if
(
m_bUnpackError
)
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: UnpackSchema() failed (unpack error)"
);
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 )
...
@@ -2308,22 +2626,25 @@ bool ha_sphinx::UnpackStats ( CSphSEStats * pStats )
assert
(
pStats
);
assert
(
pStats
);
char
*
pCurSave
=
m_pCur
;
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
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
// skip MVA list
uint32
uCount
=
UnpackDword
();
uint32
uCount
=
UnpackDword
();
m_pCur
+=
uCount
*
4
;
m_pCur
+=
uCount
*
4
;
}
}
else
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_STRING
)
else
// skip normal value
{
m_pCur
+=
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_BIGINT
?
8
:
4
;
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_iMatchesTotal
=
UnpackDword
();
pStats
->
m_iMatchesFound
=
UnpackDword
();
pStats
->
m_iMatchesFound
=
UnpackDword
();
pStats
->
m_iQueryMsec
=
UnpackDword
();
pStats
->
m_iQueryMsec
=
UnpackDword
();
...
@@ -2356,37 +2677,61 @@ bool ha_sphinx::UnpackStats ( CSphSEStats * pStats )
...
@@ -2356,37 +2677,61 @@ bool ha_sphinx::UnpackStats ( CSphSEStats * pStats )
/// condition pushdown implementation, to properly intercept WHERE clauses on my columns
/// 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
)
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"
// catch the simplest case: query_column="some text"
for
(
;;
)
for
(
;;
)
{
{
if
(
cond
->
type
()
!=
COND
::
FUNC_ITEM
)
if
(
cond
->
type
()
!=
Item
::
FUNC_ITEM
)
break
;
break
;
Item_func
*
condf
=
(
Item_func
*
)
cond
;
Item_func
*
condf
=
(
Item_func
*
)
cond
;
if
(
condf
->
functype
()
!=
Item_func
::
EQ_FUNC
||
condf
->
argument_count
()
!=
2
)
if
(
condf
->
functype
()
!=
Item_func
::
EQ_FUNC
||
condf
->
argument_count
()
!=
2
)
break
;
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
// get my tls
CSphSEThreadData
*
pTls
=
GetTls
();
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
!
pTls
)
if
(
!
pTls
)
break
;
break
;
// copy the query, and let know that we intercepted this condition
Item
**
args
=
condf
->
arguments
();
Item_string
*
pString
=
(
Item_string
*
)
args
[
1
];
if
(
!
m_pShare
->
m_bSphinxQL
)
pTls
->
m_bQuery
=
true
;
{
strncpy
(
pTls
->
m_sQuery
,
pString
->
str_value
.
c_ptr
(),
sizeof
(
pTls
->
m_sQuery
)
);
// on non-QL tables, intercept query=value condition for SELECT
pTls
->
m_sQuery
[
sizeof
(
pTls
->
m_sQuery
)
-
1
]
=
'\0'
;
if
(
!
(
args
[
0
]
->
type
()
==
Item
::
FIELD_ITEM
&&
args
[
1
]
->
type
()
==
Item
::
STRING_ITEM
))
pTls
->
m_pQueryCharset
=
pString
->
str_value
.
charset
();
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
;
return
NULL
;
}
}
...
@@ -2399,9 +2744,8 @@ const COND * ha_sphinx::cond_push ( const COND * cond )
...
@@ -2399,9 +2744,8 @@ const COND * ha_sphinx::cond_push ( const COND * cond )
void
ha_sphinx
::
cond_pop
()
void
ha_sphinx
::
cond_pop
()
{
{
CSphSEThreadData
*
pTls
=
GetTls
();
CSphSEThreadData
*
pTls
=
GetTls
();
if
(
pTls
&&
pTls
->
m_bQuery
)
if
(
pTls
)
pTls
->
m_bQuery
=
false
;
pTls
->
m_bQuery
=
false
;
return
;
}
}
...
@@ -2442,6 +2786,38 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
...
@@ -2442,6 +2786,38 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
}
}
pTls
->
m_tStats
.
Reset
();
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
// parse query
if
(
pTls
->
m_bQuery
)
if
(
pTls
->
m_bQuery
)
{
{
...
@@ -2464,7 +2840,7 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
...
@@ -2464,7 +2840,7 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
}
}
// do connect
// 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
)
if
(
iSocket
<
0
)
SPH_RET
(
HA_ERR_END_OF_FILE
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
...
@@ -2602,7 +2978,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
...
@@ -2602,7 +2978,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
if
(
m_iCurrentPos
>=
m_iMatchesTotal
)
if
(
m_iCurrentPos
>=
m_iMatchesTotal
)
{
{
SafeDeleteArray
(
m_pResponse
);
SafeDeleteArray
(
m_pResponse
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
}
}
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>50100
...
@@ -2622,16 +2998,21 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
...
@@ -2622,16 +2998,21 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
for
(
uint32
i
=
0
;
i
<
m_iAttrs
;
i
++
)
for
(
uint32
i
=
0
;
i
<
m_iAttrs
;
i
++
)
{
{
longlong
iValue64
;
longlong
iValue64
=
0
;
uint32
uValue
=
UnpackDword
();
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
();
iValue64
=
(
(
longlong
)
uValue
<<
32
)
|
UnpackDword
();
if
(
m_dAttrs
[
i
].
m_iField
<
0
)
if
(
m_dAttrs
[
i
].
m_iField
<
0
)
{
{
// skip MVA
// skip MVA or String
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
)
{
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
UnpackDword
();
UnpackDword
();
}
else
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_STRING
&&
CheckResponcePtr
(
uValue
)
)
{
m_pCur
+=
uValue
;
}
continue
;
continue
;
}
}
...
@@ -2659,7 +3040,18 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
...
@@ -2659,7 +3040,18 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
af
->
store
(
iValue64
,
0
);
af
->
store
(
iValue64
,
0
);
break
;
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
)
if
(
uValue
<=
0
)
{
{
// shortcut, empty MVA set
// shortcut, empty MVA set
...
@@ -2671,15 +3063,32 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
...
@@ -2671,15 +3063,32 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
char
sBuf
[
1024
];
// FIXME! magic size
char
sBuf
[
1024
];
// FIXME! magic size
char
*
pCur
=
sBuf
;
char
*
pCur
=
sBuf
;
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
if
(
m_dAttrs
[
i
].
m_uType
==
SPH_ATTR_UINT32SET
)
{
{
uint32
uEntry
=
UnpackDword
();
for
(
;
uValue
>
0
&&
!
m_bUnpackError
;
uValue
--
)
if
(
pCur
<
sBuf
+
sizeof
(
sBuf
)
-
16
)
// 10 chars per 32bit value plus some safety bytes
{
{
sprintf
(
pCur
,
"%u"
,
uEntry
);
uint32
uEntry
=
UnpackDword
();
while
(
*
pCur
)
*
pCur
++
;
if
(
pCur
<
sBuf
+
sizeof
(
sBuf
)
-
16
)
// 10 chars per 32bit value plus some safety bytes
if
(
uValue
>
1
)
{
*
pCur
++
=
','
;
// non-trailing commas
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 )
...
@@ -2690,7 +3099,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
default:
default:
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: unhandled attr type"
);
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: unhandled attr type"
);
SafeDeleteArray
(
m_pResponse
);
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 )
...
@@ -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"
);
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: response unpacker failed"
);
SafeDeleteArray
(
m_pResponse
);
SafeDeleteArray
(
m_pResponse
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
SPH_RET
(
HA_ERR_END_OF_FILE
);
}
}
// zero out unmapped fields
// zero out unmapped fields
...
@@ -2719,7 +3128,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
...
@@ -2719,7 +3128,7 @@ int ha_sphinx::get_rec ( byte * buf, const byte *, uint )
m_iCurrentPos
++
;
m_iCurrentPos
++
;
#if MYSQL_VERSION_ID > 50100
#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
#endif
SPH_RET
(
0
);
SPH_RET
(
0
);
...
@@ -2859,7 +3268,7 @@ THR_LOCK_DATA ** ha_sphinx::store_lock ( THD *, THR_LOCK_DATA ** to,
...
@@ -2859,7 +3268,7 @@ THR_LOCK_DATA ** ha_sphinx::store_lock ( THD *, THR_LOCK_DATA ** to,
SPH_ENTER_METHOD
();
SPH_ENTER_METHOD
();
if
(
lock_type
!=
TL_IGNORE
&&
m_tLock
.
type
==
TL_UNLOCK
)
if
(
lock_type
!=
TL_IGNORE
&&
m_tLock
.
type
==
TL_UNLOCK
)
m_tLock
.
type
=
lock_type
;
m_tLock
.
type
=
lock_type
;
*
to
++
=
&
m_tLock
;
*
to
++
=
&
m_tLock
;
SPH_RET
(
to
);
SPH_RET
(
to
);
...
@@ -2898,12 +3307,9 @@ ha_rows ha_sphinx::records_in_range ( uint, key_range *, key_range * )
...
@@ -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
SPH_RET
(
3
);
// low number to force index usage
}
}
#if MYSQL_VERSION_ID < 50610
static
inline
bool
IsIntegerFieldType
(
enum_field_types
eType
)
#define user_defined_key_parts key_parts
{
#endif
return
eType
==
MYSQL_TYPE_LONG
||
eType
==
MYSQL_TYPE_LONGLONG
;
}
// create() is called to create a database. The variable name will have the name
// 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
// 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 * )
...
@@ -2918,10 +3324,12 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
SPH_ENTER_METHOD
();
SPH_ENTER_METHOD
();
char
sError
[
256
];
char
sError
[
256
];
if
(
!
ParseUrl
(
NULL
,
table
,
true
)
)
CSphSEShare
tInfo
;
if
(
!
ParseUrl
(
&
tInfo
,
table
,
true
)
)
SPH_RET
(
-
1
);
SPH_RET
(
-
1
);
for
(
;;
)
// check SphinxAPI table
for
(
;
!
tInfo
.
m_bSphinxQL
;
)
{
{
// check system fields (count and types)
// check system fields (count and types)
if
(
table
->
s
->
fields
<
SPHINXSE_SYSTEM_COLUMNS
)
if
(
table
->
s
->
fields
<
SPHINXSE_SYSTEM_COLUMNS
)
...
@@ -2931,7 +3339,7 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
...
@@ -2931,7 +3339,7 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
break
;
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
);
my_snprintf
(
sError
,
sizeof
(
sError
),
"%s: 1st column (docid) MUST be unsigned integer or bigint"
,
name
);
break
;
break
;
...
@@ -2970,7 +3378,7 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
...
@@ -2970,7 +3378,7 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
// check index
// check index
if
(
if
(
table
->
s
->
keys
!=
1
||
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
)
)
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"
,
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 * )
...
@@ -2982,6 +3390,54 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
sError
[
0
]
=
'\0'
;
sError
[
0
]
=
'\0'
;
break
;
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
]
)
if
(
sError
[
0
]
)
{
{
my_error
(
ER_CANT_CREATE_TABLE
,
MYF
(
0
),
sError
,
-
1
);
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 * )
...
@@ -2991,15 +3447,15 @@ int ha_sphinx::create ( const char * name, TABLE * table, HA_CREATE_INFO * )
SPH_RET
(
0
);
SPH_RET
(
0
);
}
}
//
//
show functions
// show functions
#if MYSQL_VERSION_ID<50100
#if MYSQL_VERSION_ID<50100
#define SHOW_VAR_FUNC_BUFF_SIZE 1024
#define SHOW_VAR_FUNC_BUFF_SIZE 1024
#endif
#endif
CSphSEStats
*
sphinx_get_stats
(
THD
*
thd
,
SHOW_VAR
*
out
)
CSphSEStats
*
sphinx_get_stats
(
THD
*
thd
,
SHOW_VAR
*
out
)
{
{
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>50100
if
(
sphinx_hton_ptr
)
if
(
sphinx_hton_ptr
)
{
{
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
*
thd_ha_data
(
thd
,
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 )
...
@@ -3012,7 +3468,7 @@ CSphSEStats * sphinx_get_stats ( THD * thd, SHOW_VAR * out )
if
(
pTls
&&
pTls
->
m_bStats
)
if
(
pTls
&&
pTls
->
m_bStats
)
return
&
pTls
->
m_tStats
;
return
&
pTls
->
m_tStats
;
#endif
#endif
out
->
type
=
SHOW_CHAR
;
out
->
type
=
SHOW_CHAR
;
out
->
value
=
""
;
out
->
value
=
""
;
return
0
;
return
0
;
...
@@ -3064,24 +3520,24 @@ int sphinx_showfunc_word_count ( THD * thd, SHOW_VAR * out, char * )
...
@@ -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
)
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
)
if
(
sphinx_hton_ptr
)
{
{
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
*
thd_ha_data
(
thd
,
sphinx_hton_ptr
);
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
*
thd_ha_data
(
thd
,
sphinx_hton_ptr
);
#else
#else
{
{
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
thd
->
ha_data
[
sphinx_hton
.
slot
];
CSphSEThreadData
*
pTls
=
(
CSphSEThreadData
*
)
thd
->
ha_data
[
sphinx_hton
.
slot
];
#endif
#endif
if
(
pTls
&&
pTls
->
m_bStats
)
if
(
pTls
&&
pTls
->
m_bStats
)
{
{
CSphSEStats
*
pStats
=
&
pTls
->
m_tStats
;
CSphSEStats
*
pStats
=
&
pTls
->
m_tStats
;
if
(
pStats
&&
pStats
->
m_iWords
)
if
(
pStats
&&
pStats
->
m_iWords
)
{
{
uint
uBuffLen
=
0
;
uint
uBuffLen
=
0
;
out
->
type
=
SHOW_CHAR
;
out
->
type
=
SHOW_CHAR
;
out
->
value
=
sBuffer
;
out
->
value
=
sBuffer
;
// the following is partially based on code in sphinx_show_status()
// the following is partially based on code in sphinx_show_status()
sBuffer
[
0
]
=
0
;
sBuffer
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
pStats
->
m_iWords
;
i
++
)
for
(
int
i
=
0
;
i
<
pStats
->
m_iWords
;
i
++
)
...
@@ -3095,13 +3551,13 @@ int sphinx_showfunc_words ( THD * thd, SHOW_VAR * out, char * sBuffer )
...
@@ -3095,13 +3551,13 @@ int sphinx_showfunc_words ( THD * thd, SHOW_VAR * out, char * sBuffer )
{
{
// trim last space
// trim last space
sBuffer
[
--
uBuffLen
]
=
0
;
sBuffer
[
--
uBuffLen
]
=
0
;
if
(
pTls
->
m_pQueryCharset
)
if
(
pTls
->
m_pQueryCharset
)
{
{
// String::c_ptr() will nul-terminate the buffer.
// String::c_ptr() will nul-terminate the buffer.
//
//
// NOTE: It's not entirely clear whether this conversion is necessary at all.
// NOTE: It's not entirely clear whether this conversion is necessary at all.
String
sConvert
;
String
sConvert
;
uint
iErrors
;
uint
iErrors
;
sConvert
.
copy
(
sBuffer
,
uBuffLen
,
pTls
->
m_pQueryCharset
,
system_charset_info
,
&
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 * )
...
@@ -3129,7 +3585,7 @@ int sphinx_showfunc_error ( THD * thd, SHOW_VAR * out, char * )
}
}
return
0
;
return
0
;
}
}
#if MYSQL_VERSION_ID>50100
#if MYSQL_VERSION_ID>50100
struct
st_mysql_storage_engine
sphinx_storage_engine
=
struct
st_mysql_storage_engine
sphinx_storage_engine
=
{
{
...
@@ -3168,5 +3624,5 @@ mysql_declare_plugin_end;
...
@@ -3168,5 +3624,5 @@ mysql_declare_plugin_end;
#endif // >50100
#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
#ifdef USE_PRAGMA_INTERFACE
...
@@ -7,7 +7,9 @@
...
@@ -7,7 +7,9 @@
#endif
#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
#define TABLE_ARG st_table_share
#else
#else
#define TABLE_ARG st_table
#define TABLE_ARG st_table
...
@@ -47,7 +49,7 @@ protected:
...
@@ -47,7 +49,7 @@ protected:
public:
public:
#if MYSQL_VERSION_ID<50100
#if MYSQL_VERSION_ID<50100
ha_sphinx
(
TABLE_ARG
*
table_arg
);
ha_sphinx
(
TABLE_ARG
*
table_arg
);
// NOLINT
#else
#else
ha_sphinx
(
handlerton
*
hton
,
TABLE_ARG
*
table_arg
);
ha_sphinx
(
handlerton
*
hton
,
TABLE_ARG
*
table_arg
);
#endif
#endif
...
@@ -82,14 +84,15 @@ public:
...
@@ -82,14 +84,15 @@ public:
int
open
(
const
char
*
name
,
int
mode
,
uint
test_if_locked
);
int
open
(
const
char
*
name
,
int
mode
,
uint
test_if_locked
);
int
close
();
int
close
();
int
write_row
(
uchar
*
buf
);
int
write_row
(
byte
*
buf
);
int
update_row
(
const
uchar
*
old_data
,
uchar
*
new_data
);
int
update_row
(
const
byte
*
old_data
,
byte
*
new_data
);
int
delete_row
(
const
uchar
*
buf
);
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
,
bool
sorted
);
// 5.1.x
int
index_init
(
uint
keynr
)
{
return
index_init
(
keynr
,
false
);
}
// 5.0.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
(
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_read_idx
(
byte
*
buf
,
uint
idx
,
const
byte
*
key
,
uint
key_len
,
enum
ha_rkey_function
find_flag
);
int
index_next
(
byte
*
buf
);
int
index_next
(
byte
*
buf
);
...
@@ -121,10 +124,14 @@ public:
...
@@ -121,10 +124,14 @@ public:
int
rename_table
(
const
char
*
from
,
const
char
*
to
);
int
rename_table
(
const
char
*
from
,
const
char
*
to
);
int
create
(
const
char
*
name
,
TABLE
*
form
,
HA_CREATE_INFO
*
create_info
);
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:
public:
#if MYSQL_VERSION_ID<50610
virtual
const
COND
*
cond_push
(
const
COND
*
cond
);
virtual
const
COND
*
cond_push
(
const
COND
*
cond
);
#else
virtual
const
Item
*
cond_push
(
const
Item
*
cond
);
#endif
virtual
void
cond_pop
();
virtual
void
cond_pop
();
private:
private:
...
@@ -138,12 +145,15 @@ private:
...
@@ -138,12 +145,15 @@ private:
int
*
m_dUnboundFields
;
int
*
m_dUnboundFields
;
private:
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
();
uint32
UnpackDword
();
char
*
UnpackString
();
char
*
UnpackString
();
bool
UnpackSchema
();
bool
UnpackSchema
();
bool
UnpackStats
(
CSphSEStats
*
pStats
);
bool
UnpackStats
(
CSphSEStats
*
pStats
);
bool
CheckResponcePtr
(
int
iLen
);
CSphSEThreadData
*
GetTls
();
CSphSEThreadData
*
GetTls
();
};
};
...
@@ -160,5 +170,5 @@ int sphinx_showfunc_word_count ( THD *, SHOW_VAR *, char * );
...
@@ -160,5 +170,5 @@ int sphinx_showfunc_word_count ( THD *, SHOW_VAR *, char * );
int
sphinx_showfunc_words
(
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$
// $Id: snippets_udf.cc 4505 2014-01-22 15:16:21Z deogar $
//
//
//
//
// Copyright (c) 2001-2008, Andrew Aksyonoff. All rights reserved.
// Copyright (c) 2001-2014, Andrew Aksyonoff
//
// Copyright (c) 2008-2014, Sphinx Technologies Inc
// This program is free software; you can redistribute it and/or modify
// All rights reserved
// 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
// This program is free software; you can redistribute it and/or modify
// did not, you can find it at http://www.gnu.org/
// 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 <stdio.h>
#include <string.h>
#include <sys/un.h>
#include <assert.h>
#include <netdb.h>
#include <sys/un.h>
#include <mysql_version.h>
#include <netdb.h>
#if MYSQL_VERSION_ID>50100
#include <mysql_version.h>
#include "mysql_priv.h"
#include <mysql/plugin.h>
#if MYSQL_VERSION_ID>=50515
#else
#include "sql_class.h"
#include "../mysql_priv.h"
#include "sql_array.h"
#endif
#elif MYSQL_VERSION_ID>50100
#include "mysql_priv.h"
#include <mysys_err.h>
#include <mysql/plugin.h>
#include <my_sys.h>
#else
#include "../mysql_priv.h"
#if MYSQL_VERSION_ID>=50120
#endif
typedef
uchar
byte
;
#endif
#include <mysys_err.h>
#include <my_sys.h>
/// partially copy-pasted stuff that should be moved elsewhere
#if MYSQL_VERSION_ID>=50120
#if UNALIGNED_RAM_ACCESS
typedef
uchar
byte
;
#endif
/// pass-through wrapper
template
<
typename
T
>
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
/// partially copy-pasted stuff that should be moved elsewhere
{
return
tRef
;
#if UNALIGNED_RAM_ACCESS
}
/// pass-through wrapper
/// pass-through wrapper
template
<
typename
T
>
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
template
<
typename
T
>
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
{
{
return
tRef
;
*
(
T
*
)
pPtr
=
tVal
;
}
}
/// pass-through wrapper
#else
template
<
typename
T
>
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
{
/// unaligned read wrapper for some architectures (eg. SPARC)
*
(
T
*
)
pPtr
=
tVal
;
template
<
typename
T
>
}
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
{
#else
T
uTmp
;
byte
*
pSrc
=
(
byte
*
)
&
tRef
;
/// unaligned read wrapper for some architectures (eg. SPARC)
byte
*
pDst
=
(
byte
*
)
&
uTmp
;
template
<
typename
T
>
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
inline
T
sphUnalignedRead
(
const
T
&
tRef
)
*
pDst
++
=
*
pSrc
++
;
{
return
uTmp
;
T
uTmp
;
}
byte
*
pSrc
=
(
byte
*
)
&
tRef
;
byte
*
pDst
=
(
byte
*
)
&
uTmp
;
/// unaligned write wrapper for some architectures (eg. SPARC)
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
template
<
typename
T
>
*
pDst
++
=
*
pSrc
++
;
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
return
uTmp
;
{
}
byte
*
pDst
=
(
byte
*
)
pPtr
;
byte
*
pSrc
=
(
byte
*
)
&
tVal
;
/// unaligned write wrapper for some architectures (eg. SPARC)
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
template
<
typename
T
>
*
pDst
++
=
*
pSrc
++
;
void
sphUnalignedWrite
(
void
*
pPtr
,
const
T
&
tVal
)
}
{
byte
*
pDst
=
(
byte
*
)
pPtr
;
#endif
byte
*
pSrc
=
(
byte
*
)
&
tVal
;
for
(
int
i
=
0
;
i
<
(
int
)
sizeof
(
T
);
i
++
)
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
*
pDst
++
=
*
pSrc
++
;
}
#define SafeDelete(_arg) { if ( _arg ) delete ( _arg ); (_arg) = NULL; }
#define SafeDeleteArray(_arg) { if ( _arg ) delete [] ( _arg ); (_arg) = NULL; }
#endif
#define Min(a,b) ((a)<(b)?(a):(b))
#define SPHINXSE_MAX_ALLOC (16*1024*1024)
typedef
unsigned
int
DWORD
;
#define SafeDelete(_arg) { if ( _arg ) delete ( _arg ); (_arg) = NULL; }
#define SafeDeleteArray(_arg) { if ( _arg ) delete [] ( _arg ); (_arg) = NULL; }
inline
DWORD
sphF2DW
(
float
f
)
{
union
{
float
f
;
uint32
d
;
}
u
;
u
.
f
=
f
;
return
u
.
d
;
}
#define Min(a,b) ((a)<(b)?(a):(b))
static
char
*
sphDup
(
const
char
*
sSrc
,
int
iLen
=-
1
)
{
typedef
unsigned
int
DWORD
;
if
(
!
sSrc
)
return
NULL
;
inline
DWORD
sphF2DW
(
float
f
)
{
union
{
float
f
;
uint32
d
;
}
u
;
u
.
f
=
f
;
return
u
.
d
;
}
if
(
iLen
<
0
)
static
char
*
sphDup
(
const
char
*
sSrc
,
int
iLen
=-
1
)
iLen
=
strlen
(
sSrc
);
{
if
(
!
sSrc
)
char
*
sRes
=
new
char
[
1
+
iLen
];
return
NULL
;
memcpy
(
sRes
,
sSrc
,
iLen
);
sRes
[
iLen
]
=
'\0'
;
if
(
iLen
<
0
)
return
sRes
;
iLen
=
strlen
(
sSrc
);
}
char
*
sRes
=
new
char
[
1
+
iLen
];
static
inline
void
sphShowErrno
(
const
char
*
sCall
)
memcpy
(
sRes
,
sSrc
,
iLen
);
{
sRes
[
iLen
]
=
'\0'
;
char
sError
[
256
];
return
sRes
;
snprintf
(
sError
,
sizeof
(
sError
),
"%s() failed: [%d] %s"
,
sCall
,
errno
,
strerror
(
errno
)
);
}
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
}
static
inline
void
sphShowErrno
(
const
char
*
sCall
)
{
static
const
bool
sphReportErrors
=
true
;
char
sError
[
256
];
snprintf
(
sError
,
sizeof
(
sError
),
"%s() failed: [%d] %s"
,
sCall
,
errno
,
strerror
(
errno
)
);
static
bool
sphSend
(
int
iFd
,
const
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
{
}
assert
(
pBuffer
);
assert
(
iSize
>
0
);
static
const
bool
sphReportErrors
=
true
;
const
int
iResult
=
send
(
iFd
,
pBuffer
,
iSize
,
0
);
static
bool
sphSend
(
int
iFd
,
const
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
if
(
iResult
!=
iSize
)
{
{
assert
(
pBuffer
);
if
(
bReportErrors
)
sphShowErrno
(
"send"
);
assert
(
iSize
>
0
);
return
false
;
}
const
int
iResult
=
send
(
iFd
,
pBuffer
,
iSize
,
0
);
return
true
;
if
(
iResult
!=
iSize
)
}
{
if
(
bReportErrors
)
sphShowErrno
(
"send"
);
static
bool
sphRecv
(
int
iFd
,
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
return
false
;
{
}
assert
(
pBuffer
);
return
true
;
assert
(
iSize
>
0
);
}
while
(
iSize
)
static
bool
sphRecv
(
int
iFd
,
char
*
pBuffer
,
int
iSize
,
bool
bReportErrors
=
false
)
{
{
const
int
iResult
=
recv
(
iFd
,
pBuffer
,
iSize
,
0
);
assert
(
pBuffer
);
if
(
iResult
>
0
)
assert
(
iSize
>
0
);
{
iSize
-=
iResult
;
while
(
iSize
)
pBuffer
+=
iSize
;
{
}
const
int
iResult
=
recv
(
iFd
,
pBuffer
,
iSize
,
0
);
else
if
(
iResult
==
0
)
if
(
iResult
>
0
)
{
{
if
(
bReportErrors
)
iSize
-=
iResult
;
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"recv() failed: disconnected"
);
pBuffer
+=
iSize
;
return
false
;
}
else
if
(
iResult
==
0
)
}
{
else
if
(
bReportErrors
)
{
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"recv() failed: disconnected"
);
if
(
bReportErrors
)
sphShowErrno
(
"recv"
);
return
false
;
return
false
;
}
else
}
{
}
if
(
bReportErrors
)
sphShowErrno
(
"recv"
);
return
true
;
return
false
;
}
}
}
enum
return
true
;
{
}
SPHINX_SEARCHD_PROTO
=
1
,
enum
SEARCHD_COMMAND_SEARCH
=
0
,
{
SEARCHD_COMMAND_EXCERPT
=
1
,
SPHINX_SEARCHD_PROTO
=
1
,
VER_COMMAND_SEARCH
=
0x116
,
SEARCHD_COMMAND_EXCERPT
=
1
,
VER_COMMAND_EXCERPT
=
0x100
,
};
VER_COMMAND_EXCERPT
=
0x104
,
};
/// known answers
enum
/// known answers
{
enum
SEARCHD_OK
=
0
,
///< general success, command-specific reply follows
{
SEARCHD_ERROR
=
1
,
///< general failure, error message follows
SEARCHD_OK
=
0
,
///< general success, command-specific reply follows
SEARCHD_RETRY
=
2
,
///< temporary failure, error message follows, client should retry later
SEARCHD_ERROR
=
1
,
///< general failure, error message follows
SEARCHD_WARNING
=
3
///< general success, warning message and command-specific reply follow
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_SCHEME "sphinx"
#define SPHINXSE_DEFAULT_PORT 9312
#define SPHINXSE_DEFAULT_HOST "127.0.0.1"
#define SPHINXSE_DEFAULT_INDEX "*"
#define SPHINXSE_DEFAULT_PORT 9312
#define SPHINXSE_DEFAULT_INDEX "*"
class
CSphBuffer
{
class
CSphBuffer
private:
{
bool
m_bOverrun
;
private:
int
m_iSize
;
bool
m_bOverrun
;
int
m_iLeft
;
int
m_iSize
;
char
*
m_pBuffer
;
int
m_iLeft
;
char
*
m_pCurrent
;
char
*
m_pBuffer
;
char
*
m_pCurrent
;
public:
CSphBuffer
(
const
int
iSize
)
public:
:
m_bOverrun
(
false
)
explicit
CSphBuffer
(
const
int
iSize
)
,
m_iSize
(
iSize
)
:
m_bOverrun
(
false
)
,
m_iLeft
(
iSize
)
,
m_iSize
(
iSize
)
{
,
m_iLeft
(
iSize
)
assert
(
iSize
>
0
);
{
m_pBuffer
=
new
char
[
iSize
];
assert
(
iSize
>
0
);
m_pCurrent
=
m_pBuffer
;
m_pBuffer
=
new
char
[
iSize
];
}
m_pCurrent
=
m_pBuffer
;
}
~
CSphBuffer
()
{
~
CSphBuffer
()
SafeDelete
(
m_pBuffer
);
{
}
SafeDeleteArray
(
m_pBuffer
);
}
const
char
*
Ptr
()
const
{
return
m_pBuffer
;
}
const
char
*
Ptr
()
const
{
return
m_pBuffer
;
}
bool
Finalize
()
{
bool
Finalize
()
return
!
(
m_bOverrun
||
m_iLeft
!=
0
||
m_pCurrent
-
m_pBuffer
!=
m_iSize
);
{
}
return
!
(
m_bOverrun
||
m_iLeft
!=
0
||
(
m_pCurrent
-
m_pBuffer
)
!=
m_iSize
);
}
void
SendBytes
(
const
void
*
pBytes
,
int
iBytes
);
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
SendWord
(
short
int
v
)
{
v
=
ntohs
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
// NOLINT
void
SendDword
(
DWORD
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendInt
(
int
v
)
{
v
=
ntohl
(
v
);
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
uint
(
v
>>
32
)
);
SendDword
(
uint
(
v
&
0xFFFFFFFFUL
)
);
}
void
SendDword
(
DWORD
v
)
{
v
=
ntohl
(
v
)
;
SendBytes
(
&
v
,
sizeof
(
v
)
);
}
void
SendString
(
const
char
*
v
)
{
SendString
(
v
,
strlen
(
v
)
);
}
void
SendUint64
(
ulonglong
v
)
{
SendDword
(
uint
(
v
>>
32
)
);
SendDword
(
uint
(
v
&
0xFFFFFFFFUL
)
);
}
void
SendString
(
const
char
*
v
,
int
iLen
)
{
SendDword
(
iLen
);
SendBytes
(
v
,
iLen
);
}
void
SendString
(
const
char
*
v
)
{
SendString
(
v
,
strlen
(
v
)
);
}
void
SendFloat
(
float
v
)
{
SendDword
(
sphF2DW
(
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
)
{
void
CSphBuffer
::
SendBytes
(
const
void
*
pBytes
,
int
iBytes
)
if
(
m_iLeft
<
iBytes
)
{
{
if
(
m_iLeft
<
iBytes
)
m_bOverrun
=
true
;
{
return
;
m_bOverrun
=
true
;
}
return
;
}
memcpy
(
m_pCurrent
,
pBytes
,
iBytes
);
memcpy
(
m_pCurrent
,
pBytes
,
iBytes
);
m_pCurrent
+=
iBytes
;
m_iLeft
-=
iBytes
;
m_pCurrent
+=
iBytes
;
}
m_iLeft
-=
iBytes
;
}
struct
CSphUrl
{
struct
CSphUrl
char
*
m_sBuffer
;
{
char
*
m_sFormatted
;
char
*
m_sBuffer
;
char
*
m_sFormatted
;
char
*
m_sScheme
;
char
*
m_sHost
;
char
*
m_sScheme
;
char
*
m_sIndex
;
char
*
m_sHost
;
char
*
m_sIndex
;
int
m_iPort
;
int
m_iPort
;
CSphUrl
()
:
m_sBuffer
(
NULL
)
CSphUrl
()
,
m_sFormatted
(
NULL
)
:
m_sBuffer
(
NULL
)
,
m_sScheme
(
SPHINXSE_DEFAULT_SCHEME
)
,
m_sFormatted
(
NULL
)
,
m_sHost
(
SPHINXSE_DEFAULT_HOST
)
,
m_sScheme
(
SPHINXSE_DEFAULT_SCHEME
)
,
m_sIndex
(
SPHINXSE_DEFAULT_INDEX
)
,
m_sHost
(
SPHINXSE_DEFAULT_HOST
)
,
m_iPort
(
SPHINXSE_DEFAULT_PORT
)
,
m_sIndex
(
SPHINXSE_DEFAULT_INDEX
)
{}
,
m_iPort
(
SPHINXSE_DEFAULT_PORT
)
{}
~
CSphUrl
()
{
~
CSphUrl
()
SafeDeleteArray
(
m_sFormatted
);
{
SafeDeleteArray
(
m_sBuffer
);
SafeDeleteArray
(
m_sFormatted
);
}
SafeDeleteArray
(
m_sBuffer
);
}
bool
Parse
(
const
char
*
sUrl
,
int
iLen
);
int
Connect
();
bool
Parse
(
const
char
*
sUrl
,
int
iLen
);
const
char
*
Format
();
int
Connect
();
};
const
char
*
Format
();
};
const
char
*
CSphUrl
::
Format
()
{
const
char
*
CSphUrl
::
Format
()
if
(
!
m_sFormatted
)
{
{
if
(
!
m_sFormatted
)
int
iSize
=
15
+
strlen
(
m_sHost
)
+
strlen
(
m_sIndex
);
{
m_sFormatted
=
new
char
[
iSize
];
int
iSize
=
15
+
strlen
(
m_sHost
)
+
strlen
(
m_sIndex
);
if
(
m_iPort
)
m_sFormatted
=
new
char
[
iSize
];
snprintf
(
m_sFormatted
,
iSize
,
"inet://%s:%d/%s"
,
m_sHost
,
m_iPort
,
m_sIndex
);
if
(
m_iPort
)
else
snprintf
(
m_sFormatted
,
iSize
,
"inet://%s:%d/%s"
,
m_sHost
,
m_iPort
,
m_sIndex
);
snprintf
(
m_sFormatted
,
iSize
,
"unix://%s/%s"
,
m_sHost
,
m_sIndex
);
else
}
snprintf
(
m_sFormatted
,
iSize
,
"unix://%s/%s"
,
m_sHost
,
m_sIndex
);
return
m_sFormatted
;
}
}
return
m_sFormatted
;
}
// the following scheme variants are recognized
//
// the following scheme variants are recognized
// inet://host/index
//
// inet://host:port/index
// inet://host/index
// unix://unix/domain/socket:index
// inet://host:port/index
// unix://unix/domain/socket
// unix://unix/domain/socket:index
bool
CSphUrl
::
Parse
(
const
char
*
sUrl
,
int
iLen
)
// unix://unix/domain/socket
{
bool
CSphUrl
::
Parse
(
const
char
*
sUrl
,
int
iLen
)
bool
bOk
=
true
;
{
while
(
iLen
)
bool
bOk
=
true
;
{
while
(
iLen
)
bOk
=
false
;
{
bOk
=
false
;
m_sBuffer
=
sphDup
(
sUrl
,
iLen
);
m_sScheme
=
m_sBuffer
;
m_sBuffer
=
sphDup
(
sUrl
,
iLen
);
m_sScheme
=
m_sBuffer
;
m_sHost
=
strstr
(
m_sBuffer
,
"://"
);
if
(
!
m_sHost
)
m_sHost
=
strstr
(
m_sBuffer
,
"://"
);
break
;
if
(
!
m_sHost
)
m_sHost
[
0
]
=
'\0'
;
break
;
m_sHost
+=
2
;
m_sHost
[
0
]
=
'\0'
;
m_sHost
+=
2
;
if
(
!
strcmp
(
m_sScheme
,
"unix"
)
)
{
if
(
!
strcmp
(
m_sScheme
,
"unix"
)
)
// unix-domain socket
{
m_iPort
=
0
;
// unix-domain socket
if
(
!
(
m_sIndex
=
strrchr
(
m_sHost
,
':'
)
))
m_iPort
=
0
;
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
if
(
!
(
m_sIndex
=
strrchr
(
m_sHost
,
':'
)
))
else
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
{
else
*
m_sIndex
++
=
'\0'
;
{
if
(
!*
m_sIndex
)
*
m_sIndex
++
=
'\0'
;
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
if
(
!*
m_sIndex
)
}
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
bOk
=
true
;
}
break
;
bOk
=
true
;
}
break
;
if
(
strcmp
(
m_sScheme
,
"sphinx"
)
!=
0
&&
strcmp
(
m_sScheme
,
"inet"
)
!=
0
)
}
break
;
if
(
strcmp
(
m_sScheme
,
"sphinx"
)
!=
0
&&
strcmp
(
m_sScheme
,
"inet"
)
!=
0
)
break
;
// inet
m_sHost
++
;
// inet
char
*
sPort
=
strchr
(
m_sHost
,
':'
);
m_sHost
++
;
if
(
sPort
)
char
*
sPort
=
strchr
(
m_sHost
,
':'
);
{
if
(
sPort
)
*
sPort
++
=
'\0'
;
{
if
(
*
sPort
)
*
sPort
++
=
'\0'
;
{
if
(
*
sPort
)
m_sIndex
=
strchr
(
sPort
,
'/'
);
{
if
(
m_sIndex
)
m_sIndex
=
strchr
(
sPort
,
'/'
);
*
m_sIndex
++
=
'\0'
;
if
(
m_sIndex
)
else
*
m_sIndex
++
=
'\0'
;
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
else
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
m_iPort
=
atoi
(
sPort
);
if
(
!
m_iPort
)
m_iPort
=
atoi
(
sPort
);
m_iPort
=
SPHINXSE_DEFAULT_PORT
;
if
(
!
m_iPort
)
}
m_iPort
=
SPHINXSE_DEFAULT_PORT
;
}
else
}
{
}
else
m_sIndex
=
strchr
(
m_sHost
,
'/'
);
{
if
(
m_sIndex
)
m_sIndex
=
strchr
(
m_sHost
,
'/'
);
*
m_sIndex
++
=
'\0'
;
if
(
m_sIndex
)
else
*
m_sIndex
++
=
'\0'
;
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
else
}
m_sIndex
=
SPHINXSE_DEFAULT_INDEX
;
}
bOk
=
true
;
break
;
bOk
=
true
;
}
break
;
}
return
bOk
;
}
return
bOk
;
}
int
CSphUrl
::
Connect
()
{
int
CSphUrl
::
Connect
()
struct
sockaddr_in
sin
;
{
#ifndef __WIN__
struct
sockaddr_in
sin
;
struct
sockaddr_un
saun
;
#ifndef __WIN__
#endif
struct
sockaddr_un
saun
;
#endif
int
iDomain
=
0
;
int
iSockaddrSize
=
0
;
int
iDomain
=
0
;
struct
sockaddr
*
pSockaddr
=
NULL
;
int
iSockaddrSize
=
0
;
struct
sockaddr
*
pSockaddr
=
NULL
;
in_addr_t
ip_addr
;
in_addr_t
ip_addr
;
if
(
m_iPort
)
{
if
(
m_iPort
)
iDomain
=
AF_INET
;
{
iSockaddrSize
=
sizeof
(
sin
);
iDomain
=
AF_INET
;
pSockaddr
=
(
struct
sockaddr
*
)
&
sin
;
iSockaddrSize
=
sizeof
(
sin
);
pSockaddr
=
(
struct
sockaddr
*
)
&
sin
;
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
sin
.
sin_family
=
AF_INET
;
memset
(
&
sin
,
0
,
sizeof
(
sin
)
);
sin
.
sin_port
=
htons
(
m_iPort
);
sin
.
sin_family
=
AF_INET
;
sin
.
sin_port
=
htons
(
m_iPort
);
// resolve address
if
(
(
int
)(
ip_addr
=
inet_addr
(
m_sHost
)
)
!=
(
int
)
INADDR_NONE
)
// resolve address
memcpy
(
&
sin
.
sin_addr
,
&
ip_addr
,
sizeof
(
ip_addr
)
);
if
(
(
int
)(
ip_addr
=
inet_addr
(
m_sHost
)
)
!=
(
int
)
INADDR_NONE
)
else
memcpy
(
&
sin
.
sin_addr
,
&
ip_addr
,
sizeof
(
ip_addr
)
);
{
else
int
tmp_errno
;
{
struct
hostent
tmp_hostent
,
*
hp
;
int
tmp_errno
;
char
buff2
[
GETHOSTBYNAME_BUFF_SIZE
];
bool
bError
=
false
;
hp
=
my_gethostbyname_r
(
m_sHost
,
&
tmp_hostent
,
#if MYSQL_VERSION_ID>=50515
buff2
,
sizeof
(
buff2
),
&
tmp_errno
);
struct
addrinfo
*
hp
=
NULL
;
if
(
!
hp
)
tmp_errno
=
getaddrinfo
(
m_sHost
,
NULL
,
NULL
,
&
hp
);
{
if
(
!
tmp_errno
||
!
hp
||
!
hp
->
ai_addr
)
my_gethostbyname_r_free
();
{
bError
=
true
;
char
sError
[
256
];
if
(
hp
)
snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
m_sHost
);
freeaddrinfo
(
hp
);
}
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
#else
return
-
1
;
struct
hostent
tmp_hostent
,
*
hp
;
}
char
buff2
[
GETHOSTBYNAME_BUFF_SIZE
];
hp
=
my_gethostbyname_r
(
m_sHost
,
&
tmp_hostent
,
buff2
,
sizeof
(
buff2
),
&
tmp_errno
);
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
if
(
!
hp
)
my_gethostbyname_r_free
();
{
}
my_gethostbyname_r_free
();
}
bError
=
true
;
else
}
{
#endif
#ifndef __WIN__
iDomain
=
AF_UNIX
;
if
(
bError
)
iSockaddrSize
=
sizeof
(
saun
);
{
pSockaddr
=
(
struct
sockaddr
*
)
&
saun
;
char
sError
[
256
];
my_snprintf
(
sError
,
sizeof
(
sError
),
"failed to resolve searchd host (name=%s)"
,
m_sHost
);
memset
(
&
saun
,
0
,
sizeof
(
saun
)
);
saun
.
sun_family
=
AF_UNIX
;
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sError
);
strncpy
(
saun
.
sun_path
,
m_sHost
,
sizeof
(
saun
.
sun_path
)
-
1
);
return
-
1
;
#else
}
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"Unix-domain sockets are not supported on Windows"
);
return
-
1
;
#if MYSQL_VERSION_ID>=50515
#endif
memcpy
(
&
sin
.
sin_addr
,
hp
->
ai_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
ai_addrlen
)
);
}
freeaddrinfo
(
hp
);
#else
// connect to searchd and exchange versions
memcpy
(
&
sin
.
sin_addr
,
hp
->
h_addr
,
Min
(
sizeof
(
sin
.
sin_addr
),
(
size_t
)
hp
->
h_length
)
);
uint
uServerVersion
;
my_gethostbyname_r_free
();
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
#endif
int
iSocket
=
-
1
;
}
char
*
pError
=
NULL
;
}
else
do
{
{
#ifndef __WIN__
iSocket
=
socket
(
iDomain
,
SOCK_STREAM
,
0
);
iDomain
=
AF_UNIX
;
if
(
iSocket
==
-
1
)
iSockaddrSize
=
sizeof
(
saun
);
{
pSockaddr
=
(
struct
sockaddr
*
)
&
saun
;
pError
=
"Failed to create client socket"
;
break
;
memset
(
&
saun
,
0
,
sizeof
(
saun
)
);
}
saun
.
sun_family
=
AF_UNIX
;
strncpy
(
saun
.
sun_path
,
m_sHost
,
sizeof
(
saun
.
sun_path
)
-
1
);
if
(
connect
(
iSocket
,
pSockaddr
,
iSockaddrSize
)
==
-
1
)
#else
{
my_error
(
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"Unix-domain sockets are not supported on Windows"
);
pError
=
"Failed to connect to searchd"
;
return
-
1
;
break
;
#endif
}
}
if
(
!
sphRecv
(
iSocket
,
(
char
*
)
&
uServerVersion
,
sizeof
(
uServerVersion
)
)
)
// connect to searchd and exchange versions
{
uint
uServerVersion
;
pError
=
"Failed to receive searchd version"
;
uint
uClientVersion
=
htonl
(
SPHINX_SEARCHD_PROTO
);
break
;
int
iSocket
=
-
1
;
}
char
*
pError
=
NULL
;
do
if
(
!
sphSend
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
)
)
)
{
{
iSocket
=
socket
(
iDomain
,
SOCK_STREAM
,
0
);
pError
=
"Failed to send client version"
;
if
(
iSocket
==-
1
)
break
;
{
}
pError
=
"Failed to create client socket"
;
}
break
;
while
(
0
);
}
// fixme: compare versions?
if
(
connect
(
iSocket
,
pSockaddr
,
iSockaddrSize
)
==-
1
)
{
if
(
pError
)
pError
=
"Failed to connect to searchd"
;
{
break
;
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
(
!
sphRecv
(
iSocket
,
(
char
*
)
&
uServerVersion
,
sizeof
(
uServerVersion
)
)
)
{
if
(
iSocket
!=
-
1
)
pError
=
"Failed to receive searchd version"
;
close
(
iSocket
);
break
;
}
return
-
1
;
}
if
(
!
sphSend
(
iSocket
,
(
char
*
)
&
uClientVersion
,
sizeof
(
uClientVersion
)
)
)
{
return
iSocket
;
pError
=
"Failed to send client version"
;
}
break
;
}
struct
CSphResponse
}
{
while
(
0
);
char
*
m_pBuffer
;
char
*
m_pBody
;
// fixme: compare versions?
CSphResponse
()
if
(
pError
)
:
m_pBuffer
(
NULL
)
{
,
m_pBody
(
NULL
)
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
);
CSphResponse
(
DWORD
uSize
)
:
m_pBody
(
NULL
)
if
(
iSocket
!=-
1
)
{
close
(
iSocket
);
m_pBuffer
=
new
char
[
uSize
];
}
return
-
1
;
}
~
CSphResponse
()
{
return
iSocket
;
SafeDeleteArray
(
m_pBuffer
);
}
}
struct
CSphResponse
static
CSphResponse
*
Read
(
int
iSocket
,
int
iClientVersion
);
{
};
char
*
m_pBuffer
;
char
*
m_pBody
;
CSphResponse
*
CSphResponse
::
Read
(
int
iSocket
,
int
iClientVersion
)
CSphResponse
()
{
:
m_pBuffer
(
NULL
)
char
sHeader
[
8
];
,
m_pBody
(
NULL
)
if
(
!
sphRecv
(
iSocket
,
sHeader
,
sizeof
(
sHeader
)
)
)
{}
return
NULL
;
explicit
CSphResponse
(
DWORD
uSize
)
int
iStatus
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
0
]
)
);
:
m_pBody
(
NULL
)
int
iVersion
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
2
]
)
);
{
DWORD
uLength
=
ntohl
(
sphUnalignedRead
(
*
(
DWORD
*
)
&
sHeader
[
4
]
)
);
m_pBuffer
=
new
char
[
uSize
];
}
if
(
iVersion
<
iClientVersion
)
// fixme: warn
;
~
CSphResponse
()
{
if
(
uLength
<=
SPHINXSE_MAX_ALLOC
)
SafeDeleteArray
(
m_pBuffer
);
{
}
CSphResponse
*
pResponse
=
new
CSphResponse
(
uLength
);
if
(
!
sphRecv
(
iSocket
,
pResponse
->
m_pBuffer
,
uLength
)
)
static
CSphResponse
*
Read
(
int
iSocket
,
int
iClientVersion
);
{
};
SafeDelete
(
pResponse
);
return
NULL
;
CSphResponse
*
}
CSphResponse
::
Read
(
int
iSocket
,
int
iClientVersion
)
{
pResponse
->
m_pBody
=
pResponse
->
m_pBuffer
;
char
sHeader
[
8
];
if
(
iStatus
!=
SEARCHD_OK
)
if
(
!
sphRecv
(
iSocket
,
sHeader
,
sizeof
(
sHeader
)
)
)
{
return
NULL
;
DWORD
uSize
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBuffer
);
if
(
iStatus
==
SEARCHD_WARNING
)
int
iStatus
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
0
]
)
);
pResponse
->
m_pBody
+=
uSize
;
// fixme: report the warning somehow
int
iVersion
=
ntohs
(
sphUnalignedRead
(
*
(
short
int
*
)
&
sHeader
[
2
]
)
);
else
DWORD
uLength
=
ntohl
(
sphUnalignedRead
(
*
(
DWORD
*
)
&
sHeader
[
4
]
)
);
{
char
*
sMessage
=
sphDup
(
pResponse
->
m_pBuffer
+
sizeof
(
DWORD
),
uSize
);
if
(
iVersion
<
iClientVersion
)
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sMessage
);
return
NULL
;
SafeDelete
(
sMessage
);
SafeDelete
(
pResponse
);
if
(
uLength
<=
SPHINXSE_MAX_ALLOC
)
return
NULL
;
{
}
CSphResponse
*
pResponse
=
new
CSphResponse
(
uLength
);
}
if
(
!
sphRecv
(
iSocket
,
pResponse
->
m_pBuffer
,
uLength
)
)
return
pResponse
;
{
}
SafeDelete
(
pResponse
);
return
NULL
;
return
NULL
;
}
}
/// udf
pResponse
->
m_pBody
=
pResponse
->
m_pBuffer
;
if
(
iStatus
!=
SEARCHD_OK
)
extern
"C"
{
{
DWORD
uSize
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBuffer
);
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
);
if
(
iStatus
==
SEARCHD_WARNING
)
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
);
pResponse
->
m_pBody
+=
uSize
;
// fixme: report the warning somehow
};
}
else
{
#define MAX_MESSAGE_LENGTH 255
char
*
sMessage
=
sphDup
(
pResponse
->
m_pBuffer
+
sizeof
(
DWORD
),
uSize
);
#define MAX_RESULT_LENGTH 255
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
sMessage
);
SafeDeleteArray
(
sMessage
);
struct
CSphSnippets
SafeDelete
(
pResponse
);
{
return
NULL
;
CSphUrl
m_tUrl
;
}
CSphResponse
*
m_pResponse
;
}
return
pResponse
;
int
m_iBeforeMatch
;
}
int
m_iAfterMatch
;
return
NULL
;
int
m_iChunkSeparator
;
}
int
m_iLimit
;
int
m_iAround
;
/// udf
int
m_iFlags
;
extern
"C"
CSphSnippets
()
{
:
m_pResponse
(
NULL
)
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
);
,
m_iBeforeMatch
(
0
)
void
sphinx_snippets_deinit
(
UDF_INIT
*
pUDF
);
,
m_iAfterMatch
(
0
)
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
sError
);
,
m_iChunkSeparator
(
0
)
};
// defaults
,
m_iLimit
(
256
)
#define MAX_MESSAGE_LENGTH 255
,
m_iAround
(
5
)
#define MAX_RESULT_LENGTH 255
,
m_iFlags
(
1
)
{
struct
CSphSnippets
}
{
CSphUrl
m_tUrl
;
~
CSphSnippets
()
CSphResponse
*
m_pResponse
;
{
SafeDelete
(
m_pResponse
);
int
m_iBeforeMatch
;
}
int
m_iAfterMatch
;
};
int
m_iChunkSeparator
;
int
m_iStripMode
;
#define KEYWORD(NAME) else if ( strncmp ( NAME, pArgs->attributes[i], pArgs->attribute_lengths[i] ) == 0 )
int
m_iPassageBoundary
;
int
m_iLimit
;
#define CHECK_TYPE(TYPE) \
int
m_iLimitWords
;
if
(
pArgs
->
arg_type
[
i
]
!=
TYPE
)
\
int
m_iLimitPassages
;
{
\
int
m_iAround
;
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
\
int
m_iPassageId
;
"%.*s argument must be a string"
,
\
int
m_iFlags
;
(
int
)
pArgs
->
attribute_lengths
[
i
],
\
pArgs
->
attributes
[
i
]
);
\
CSphSnippets
()
bFail
=
true
;
\
:
m_pResponse
(
NULL
)
break
;
\
,
m_iBeforeMatch
(
0
)
}
\
,
m_iAfterMatch
(
0
)
if
(
TYPE
==
STRING_RESULT
&&
!
pArgs
->
args
[
i
]
)
\
,
m_iChunkSeparator
(
0
)
{
\
,
m_iStripMode
(
0
)
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
\
,
m_iPassageBoundary
(
0
)
"%.*s argument must be constant (and not NULL)"
,
\
// defaults
(
int
)
pArgs
->
attribute_lengths
[
i
],
\
,
m_iLimit
(
256
)
pArgs
->
attributes
[
i
]
);
\
,
m_iLimitWords
(
0
)
bFail
=
true
;
\
,
m_iLimitPassages
(
0
)
break
;
\
,
m_iAround
(
5
)
}
,
m_iPassageId
(
1
)
,
m_iFlags
(
1
)
#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
)
~
CSphSnippets
()
{
{
if
(
pArgs
->
arg_count
<
3
)
SafeDelete
(
m_pResponse
);
{
}
strncpy
(
sMessage
,
"insufficient arguments"
,
MAX_MESSAGE_LENGTH
);
};
return
1
;
}
#define KEYWORD(NAME) else if ( strncmp ( NAME, pArgs->attributes[i], pArgs->attribute_lengths[i] )==0 )
bool
bFail
=
false
;
#define CHECK_TYPE(TYPE) \
CSphSnippets
*
pOpts
=
new
CSphSnippets
;
if ( pArgs->arg_type[i]!=TYPE ) \
for
(
uint
i
=
0
;
i
<
pArgs
->
arg_count
;
i
++
)
{ \
{
snprintf ( sMessage, MAX_MESSAGE_LENGTH, \
if
(
i
<
3
)
"%.*s argument must be a string", \
{
(int)pArgs->attribute_lengths[i], \
if
(
pArgs
->
arg_type
[
i
]
!=
STRING_RESULT
)
pArgs->attributes[i] ); \
{
bFail = true; \
strncpy
(
sMessage
,
"first three arguments must be of string type"
,
MAX_MESSAGE_LENGTH
);
break; \
bFail
=
true
;
} \
break
;
if ( TYPE==STRING_RESULT && !pArgs->args[i] ) \
}
{ \
}
snprintf ( sMessage, MAX_MESSAGE_LENGTH, \
KEYWORD
(
"sphinx"
)
"%.*s argument must be constant (and not NULL)", \
{
(int)pArgs->attribute_lengths[i], \
STRING
;
pArgs->attributes[i] ); \
if
(
!
pOpts
->
m_tUrl
.
Parse
(
pArgs
->
args
[
i
],
pArgs
->
lengths
[
i
]
)
)
bFail = true; \
{
break; \
strncpy
(
sMessage
,
"failed to parse connection string"
,
MAX_MESSAGE_LENGTH
);
}
bFail
=
true
;
break
;
#define STRING CHECK_TYPE(STRING_RESULT)
}
#define INT CHECK_TYPE(INT_RESULT); int iValue = *(long long *)pArgs->args[i]
}
KEYWORD
(
"before_match"
)
{
STRING
;
pOpts
->
m_iBeforeMatch
=
i
;
}
my_bool
sphinx_snippets_init
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sMessage
)
KEYWORD
(
"after_match"
)
{
STRING
;
pOpts
->
m_iAfterMatch
=
i
;
}
{
KEYWORD
(
"chunk_separator"
)
{
STRING
;
pOpts
->
m_iChunkSeparator
=
i
;
}
if
(
pArgs
->
arg_count
<
3
)
KEYWORD
(
"limit"
)
{
INT
;
pOpts
->
m_iLimit
=
iValue
;
}
{
KEYWORD
(
"around"
)
{
INT
;
pOpts
->
m_iAround
=
iValue
;
}
strncpy
(
sMessage
,
"insufficient arguments"
,
MAX_MESSAGE_LENGTH
);
KEYWORD
(
"exact_phrase"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
2
;
}
return
1
;
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
;
}
bool
bFail
=
false
;
else
CSphSnippets
*
pOpts
=
new
CSphSnippets
;
{
for
(
uint
i
=
0
;
i
<
pArgs
->
arg_count
;
i
++
)
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
"unrecognized argument: %.*s"
,
{
(
int
)
pArgs
->
attribute_lengths
[
i
],
pArgs
->
attributes
[
i
]
);
if
(
i
<
3
)
bFail
=
true
;
{
break
;
if
(
pArgs
->
arg_type
[
i
]
!=
STRING_RESULT
)
}
{
}
strncpy
(
sMessage
,
"first three arguments must be of string type"
,
MAX_MESSAGE_LENGTH
);
bFail
=
true
;
if
(
bFail
)
break
;
{
}
SafeDelete
(
pOpts
);
}
return
1
;
KEYWORD
(
"sphinx"
)
}
{
pUDF
->
ptr
=
(
char
*
)
pOpts
;
STRING
;
return
0
;
if
(
!
pOpts
->
m_tUrl
.
Parse
(
pArgs
->
args
[
i
],
pArgs
->
lengths
[
i
]
)
)
}
{
strncpy
(
sMessage
,
"failed to parse connection string"
,
MAX_MESSAGE_LENGTH
);
#undef STRING
bFail
=
true
;
#undef INT
break
;
#undef KEYWORD
}
#undef CHECK_TYPE
}
KEYWORD
(
"before_match"
)
{
STRING
;
pOpts
->
m_iBeforeMatch
=
i
;
}
#define ARG(i) pArgs->args[i], pArgs->lengths[i]
KEYWORD
(
"after_match"
)
{
STRING
;
pOpts
->
m_iAfterMatch
=
i
;
}
#define ARG_LEN(VAR, LEN) ( VAR ? pArgs->lengths[VAR] : LEN )
KEYWORD
(
"chunk_separator"
)
{
STRING
;
pOpts
->
m_iChunkSeparator
=
i
;
}
KEYWORD
(
"html_strip_mode"
)
{
STRING
;
pOpts
->
m_iStripMode
=
i
;
}
#define SEND_STRING(INDEX, DEFAULT) \
KEYWORD
(
"passage_boundary"
)
{
STRING
;
pOpts
->
m_iPassageBoundary
=
i
;
}
if
(
INDEX
)
\
tBuffer
.
SendString
(
ARG
(
INDEX
)
);
\
KEYWORD
(
"limit"
)
{
INT
;
pOpts
->
m_iLimit
=
iValue
;
}
else
\
KEYWORD
(
"limit_words"
)
{
INT
;
pOpts
->
m_iLimitWords
=
iValue
;
}
tBuffer
.
SendString
(
DEFAULT
,
sizeof
(
DEFAULT
)
-
1
);
KEYWORD
(
"limit_passages"
)
{
INT
;
pOpts
->
m_iLimitPassages
=
iValue
;
}
KEYWORD
(
"around"
)
{
INT
;
pOpts
->
m_iAround
=
iValue
;
}
KEYWORD
(
"start_passage_id"
)
{
INT
;
pOpts
->
m_iPassageId
=
iValue
;
}
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
pError
)
{
KEYWORD
(
"exact_phrase"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
2
;
}
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
KEYWORD
(
"single_passage"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
4
;
}
assert
(
pOpts
);
KEYWORD
(
"use_boundaries"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
8
;
}
KEYWORD
(
"weight_order"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
16
;
}
if
(
!
pArgs
->
args
[
0
]
||
!
pArgs
->
args
[
1
]
||
!
pArgs
->
args
[
2
]
)
KEYWORD
(
"query_mode"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
32
;
}
{
KEYWORD
(
"force_all_words"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
64
;
}
*
pIsNull
=
1
;
KEYWORD
(
"load_files"
)
{
INT
;
if
(
iValue
)
pOpts
->
m_iFlags
|=
128
;
}
return
sResult
;
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
;
}
const
int
iSize
=
else
8
+
// header
{
8
+
snprintf
(
sMessage
,
MAX_MESSAGE_LENGTH
,
"unrecognized argument: %.*s"
,
4
+
pArgs
->
lengths
[
1
]
+
// index
(
int
)
pArgs
->
attribute_lengths
[
i
],
pArgs
->
attributes
[
i
]
);
4
+
pArgs
->
lengths
[
2
]
+
// words
bFail
=
true
;
4
+
ARG_LEN
(
pOpts
->
m_iBeforeMatch
,
3
)
+
break
;
4
+
ARG_LEN
(
pOpts
->
m_iAfterMatch
,
4
)
+
}
4
+
ARG_LEN
(
pOpts
->
m_iChunkSeparator
,
5
)
+
}
12
+
4
+
pArgs
->
lengths
[
0
];
// document
if
(
bFail
)
{
CSphBuffer
tBuffer
(
iSize
);
SafeDelete
(
pOpts
);
return
1
;
tBuffer
.
SendWord
(
SEARCHD_COMMAND_EXCERPT
);
}
tBuffer
.
SendWord
(
VER_COMMAND_EXCERPT
);
pUDF
->
ptr
=
(
char
*
)
pOpts
;
tBuffer
.
SendDword
(
iSize
-
8
);
return
0
;
}
tBuffer
.
SendDword
(
0
);
tBuffer
.
SendDword
(
pOpts
->
m_iFlags
);
#undef STRING
#undef INT
tBuffer
.
SendString
(
ARG
(
1
)
);
// index
#undef KEYWORD
tBuffer
.
SendString
(
ARG
(
2
)
);
// words
#undef CHECK_TYPE
SEND_STRING
(
pOpts
->
m_iBeforeMatch
,
"<b>"
);
#define ARG(i) pArgs->args[i], pArgs->lengths[i]
SEND_STRING
(
pOpts
->
m_iAfterMatch
,
"</b>"
);
#define ARG_LEN(VAR, LEN) ( VAR ? pArgs->lengths[VAR] : LEN )
SEND_STRING
(
pOpts
->
m_iChunkSeparator
,
" ... "
);
#define SEND_STRING(INDEX, DEFAULT) \
tBuffer
.
SendInt
(
pOpts
->
m_iLimit
);
if ( INDEX ) \
tBuffer
.
SendInt
(
pOpts
->
m_iAround
);
tBuffer.SendString ( ARG(INDEX) ); \
else \
// single document
tBuffer.SendString ( DEFAULT, sizeof(DEFAULT) - 1 );
tBuffer
.
SendInt
(
1
);
tBuffer
.
SendString
(
ARG
(
0
)
);
char
*
sphinx_snippets
(
UDF_INIT
*
pUDF
,
UDF_ARGS
*
pArgs
,
char
*
sResult
,
unsigned
long
*
pLength
,
char
*
pIsNull
,
char
*
pError
)
int
iSocket
=
-
1
;
{
do
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
{
assert
(
pOpts
);
if
(
!
tBuffer
.
Finalize
()
)
{
if
(
!
pArgs
->
args
[
0
]
||
!
pArgs
->
args
[
1
]
||
!
pArgs
->
args
[
2
]
)
my_error
(
ER_QUERY_ON_FOREIGN_DATA_SOURCE
,
MYF
(
0
),
"INTERNAL ERROR: failed to build request"
);
{
break
;
*
pIsNull
=
1
;
}
return
sResult
;
}
iSocket
=
pOpts
->
m_tUrl
.
Connect
();
if
(
iSocket
==
-
1
)
break
;
const
int
iSize
=
68
+
if
(
!
sphSend
(
iSocket
,
tBuffer
.
Ptr
(),
iSize
,
sphReportErrors
)
)
break
;
pArgs
->
lengths
[
1
]
+
// index
pArgs
->
lengths
[
2
]
+
// words
CSphResponse
*
pResponse
=
CSphResponse
::
Read
(
iSocket
,
0x100
);
ARG_LEN
(
pOpts
->
m_iBeforeMatch
,
3
)
+
if
(
!
pResponse
)
break
;
ARG_LEN
(
pOpts
->
m_iAfterMatch
,
4
)
+
ARG_LEN
(
pOpts
->
m_iChunkSeparator
,
5
)
+
close
(
iSocket
);
ARG_LEN
(
pOpts
->
m_iStripMode
,
5
)
+
pOpts
->
m_pResponse
=
pResponse
;
ARG_LEN
(
pOpts
->
m_iPassageBoundary
,
0
)
+
*
pLength
=
ntohl
(
*
(
DWORD
*
)
pResponse
->
m_pBody
);
4
+
pArgs
->
lengths
[
0
];
// document
return
pResponse
->
m_pBody
+
sizeof
(
DWORD
);
}
CSphBuffer
tBuffer
(
iSize
);
while
(
0
);
tBuffer
.
SendWord
(
SEARCHD_COMMAND_EXCERPT
);
if
(
iSocket
!=
-
1
)
tBuffer
.
SendWord
(
VER_COMMAND_EXCERPT
);
close
(
iSocket
);
tBuffer
.
SendDword
(
iSize
-
8
);
*
pError
=
1
;
tBuffer
.
SendDword
(
0
);
return
sResult
;
tBuffer
.
SendDword
(
pOpts
->
m_iFlags
);
}
tBuffer
.
SendString
(
ARG
(
1
)
);
// index
#undef SEND_STRING
tBuffer
.
SendString
(
ARG
(
2
)
);
// words
#undef ARG_LEN
#undef ARG
SEND_STRING
(
pOpts
->
m_iBeforeMatch
,
"<b>"
);
SEND_STRING
(
pOpts
->
m_iAfterMatch
,
"</b>"
);
void
sphinx_snippets_deinit
(
UDF_INIT
*
pUDF
)
SEND_STRING
(
pOpts
->
m_iChunkSeparator
,
" ... "
);
{
CSphSnippets
*
pOpts
=
(
CSphSnippets
*
)
pUDF
->
ptr
;
tBuffer
.
SendInt
(
pOpts
->
m_iLimit
);
SafeDelete
(
pOpts
);
tBuffer
.
SendInt
(
pOpts
->
m_iAround
);
}
tBuffer
.
SendInt
(
pOpts
->
m_iLimitPassages
);
//
tBuffer
.
SendInt
(
pOpts
->
m_iLimitWords
);
// $Id$
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