Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
edce6934
提交
edce6934
authored
12月 29, 2008
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fulltext search refactoring
上级
a35fdf7d
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
811 行增加
和
868 行删除
+811
-868
FullText.java
h2/src/main/org/h2/fulltext/FullText.java
+506
-478
FullTextLucene.java
h2/src/main/org/h2/fulltext/FullTextLucene.java
+299
-384
FullTextSettings.java
h2/src/main/org/h2/fulltext/FullTextSettings.java
+3
-3
IndexInfo.java
h2/src/main/org/h2/fulltext/IndexInfo.java
+3
-3
没有找到文件。
h2/src/main/org/h2/fulltext/FullText.java
浏览文件 @
edce6934
...
@@ -46,16 +46,11 @@ import org.h2.value.DataType;
...
@@ -46,16 +46,11 @@ import org.h2.value.DataType;
* This class implements the native full text search.
* This class implements the native full text search.
* Most methods can be called using SQL statements as well.
* Most methods can be called using SQL statements as well.
*/
*/
public
class
FullText
implements
Trigger
,
CloseListener
{
public
class
FullText
{
private
static
final
String
TRIGGER_PREFIX
=
"FT_"
;
private
static
final
String
TRIGGER_PREFIX
=
"FT_"
;
private
static
final
String
SCHEMA
=
"FT"
;
private
static
final
String
SCHEMA
=
"FT"
;
/**
* The column name of the result set returned by the search method.
*/
private
static
final
String
FIELD_QUERY
=
"QUERY"
;
/**
/**
* A column name of the result set returned by the searchData method.
* A column name of the result set returned by the searchData method.
*/
*/
...
@@ -76,12 +71,70 @@ public class FullText implements Trigger, CloseListener {
...
@@ -76,12 +71,70 @@ public class FullText implements Trigger, CloseListener {
*/
*/
private
static
final
String
FIELD_KEYS
=
"KEYS"
;
private
static
final
String
FIELD_KEYS
=
"KEYS"
;
private
FullTextSettings
setting
;
/**
private
IndexInfo
index
;
* The column name of the result set returned by the search method.
private
int
[]
dataTypes
;
*/
private
PreparedStatement
prepInsertWord
,
prepInsertRow
,
prepInsertMap
;
private
static
final
String
FIELD_QUERY
=
"QUERY"
;
private
PreparedStatement
prepDeleteRow
,
prepDeleteMap
;
private
PreparedStatement
prepSelectRow
;
/**
* Initializes full text search functionality for this database. This adds
* the following Java functions to the database:
* <ul>
* <li>FT_CREATE_INDEX(schemaNameString, tableNameString,
* columnListString)</li>
* <li>FT_SEARCH(queryString, limitInt, offsetInt): result set</li>
* <li>FT_REINDEX()</li>
* <li>FT_DROP_ALL()</li>
* </ul>
* It also adds a schema FT to the database where bookkeeping information
* is stored. This function may be called from a Java application, or by
* using the SQL statements:
*
* <pre>
* CREATE ALIAS IF NOT EXISTS FT_INIT FOR
* "org.h2.fulltext.FullText.init";
* CALL FT_INIT();
* </pre>
*
* @param conn the connection
*/
public
static
void
init
(
Connection
conn
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE SCHEMA IF NOT EXISTS "
+
SCHEMA
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".INDEXES(ID INT AUTO_INCREMENT PRIMARY KEY, SCHEMA VARCHAR, TABLE VARCHAR, COLUMNS VARCHAR, UNIQUE(SCHEMA, TABLE))"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".WORDS(ID INT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR, UNIQUE(NAME))"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".ROWS(ID IDENTITY, HASH INT, INDEXID INT, KEY VARCHAR, UNIQUE(HASH, INDEXID, KEY))"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".MAP(ROWID INT, WORDID INT, PRIMARY KEY(WORDID, ROWID))"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".IGNORELIST(LIST VARCHAR)"
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_CREATE_INDEX FOR \""
+
FullText
.
class
.
getName
()
+
".createIndex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_DROP_INDEX FOR \""
+
FullText
.
class
.
getName
()
+
".dropIndex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_SEARCH FOR \""
+
FullText
.
class
.
getName
()
+
".search\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_SEARCH_DATA FOR \""
+
FullText
.
class
.
getName
()
+
".searchData\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_REINDEX FOR \""
+
FullText
.
class
.
getName
()
+
".reindex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_DROP_ALL FOR \""
+
FullText
.
class
.
getName
()
+
".dropAll\""
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".IGNORELIST"
);
while
(
rs
.
next
())
{
String
commaSeparatedList
=
rs
.
getString
(
1
);
setIgnoreList
(
setting
,
commaSeparatedList
);
}
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".WORDS"
);
HashMap
map
=
setting
.
getWordList
();
while
(
rs
.
next
())
{
String
word
=
rs
.
getString
(
"NAME"
);
int
id
=
rs
.
getInt
(
"ID"
);
word
=
setting
.
convertWord
(
word
);
if
(
word
!=
null
)
{
map
.
put
(
word
,
ObjectUtils
.
getInteger
(
id
));
}
}
}
/**
/**
* Create a new full text index for a table and column list. Each table may
* Create a new full text index for a table and column list. Each table may
...
@@ -104,6 +157,29 @@ public class FullText implements Trigger, CloseListener {
...
@@ -104,6 +157,29 @@ public class FullText implements Trigger, CloseListener {
indexExistingRows
(
conn
,
schema
,
table
);
indexExistingRows
(
conn
,
schema
,
table
);
}
}
/**
* Re-creates the full text index for this database
*
* @param conn the connection
*/
public
static
void
reindex
(
Connection
conn
)
throws
SQLException
{
init
(
conn
);
removeAllTriggers
(
conn
,
TRIGGER_PREFIX
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
setting
.
getWordList
().
clear
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"TRUNCATE TABLE "
+
SCHEMA
+
".WORDS"
);
stat
.
execute
(
"TRUNCATE TABLE "
+
SCHEMA
+
".ROWS"
);
stat
.
execute
(
"TRUNCATE TABLE "
+
SCHEMA
+
".MAP"
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".INDEXES"
);
while
(
rs
.
next
())
{
String
schema
=
rs
.
getString
(
"SCHEMA"
);
String
table
=
rs
.
getString
(
"TABLE"
);
createTrigger
(
conn
,
schema
,
table
);
indexExistingRows
(
conn
,
schema
,
table
);
}
}
/**
/**
* Drop an existing full text index for a table. This method returns
* Drop an existing full text index for a table. This method returns
* silently if no index for this table exists.
* silently if no index for this table exists.
...
@@ -147,64 +223,61 @@ public class FullText implements Trigger, CloseListener {
...
@@ -147,64 +223,61 @@ public class FullText implements Trigger, CloseListener {
}
}
}
}
private
static
void
createTrigger
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
/**
createOrDropTrigger
(
conn
,
schema
,
table
,
true
);
* Drops all full text indexes from the database.
}
*
* @param conn the connection
private
static
void
createOrDropTrigger
(
Connection
conn
,
String
schema
,
String
table
,
boolean
create
)
throws
SQLException
{
*/
public
static
void
dropAll
(
Connection
conn
)
throws
SQLException
{
init
(
conn
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
String
trigger
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
stat
.
execute
(
"DROP SCHEMA IF EXISTS "
+
SCHEMA
);
+
StringUtils
.
quoteIdentifier
(
TRIGGER_PREFIX
+
table
);
removeAllTriggers
(
conn
,
TRIGGER_PREFIX
);
stat
.
execute
(
"DROP TRIGGER IF EXISTS "
+
trigger
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
if
(
create
)
{
setting
.
removeAllIndexes
();
StringBuffer
buff
=
new
StringBuffer
(
"CREATE TRIGGER IF NOT EXISTS "
);
setting
.
getIgnoreList
().
clear
();
buff
.
append
(
trigger
);
setting
.
getWordList
().
clear
();
buff
.
append
(
" AFTER INSERT, UPDATE, DELETE ON "
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
buff
.
append
(
" FOR EACH ROW CALL \""
);
buff
.
append
(
FullText
.
class
.
getName
());
buff
.
append
(
"\""
);
stat
.
execute
(
buff
.
toString
());
}
}
}
private
static
void
indexExistingRows
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
/**
FullText
existing
=
new
FullText
();
* Searches from the full text index for this database.
existing
.
init
(
conn
,
schema
,
null
,
table
,
false
,
INSERT
);
* The returned result set has the following column:
StringBuffer
buff
=
new
StringBuffer
(
"SELECT * FROM "
);
* <ul><li>QUERY (varchar): The query to use to get the data.
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
* The query does not include 'SELECT * FROM '. Example:
ResultSet
rs
=
conn
.
createStatement
().
executeQuery
(
buff
.
toString
());
* PUBLIC.TEST WHERE ID = 1
int
columnCount
=
rs
.
getMetaData
().
getColumnCount
();
* </li></ul>
while
(
rs
.
next
())
{
*
Object
[]
row
=
new
Object
[
columnCount
];
* @param conn the connection
for
(
int
i
=
0
;
i
<
columnCount
;
i
++)
{
* @param text the search query
row
[
i
]
=
rs
.
getObject
(
i
+
1
);
* @param limit the maximum number of rows or 0 for no limit
}
* @param offset the offset or 0 for no offset
existing
.
fire
(
conn
,
null
,
row
);
* @return the result set
}
*/
public
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
return
search
(
conn
,
text
,
limit
,
offset
,
false
);
}
}
/**
/**
* Re-creates the full text index for this database
* Searches from the full text index for this database. The result contains
* the primary key data as an array. The returned result set has the
* following columns:
* <ul>
* <li>SCHEMA (varchar): The schema name. Example: PUBLIC </li>
* <li>TABLE (varchar): The table name. Example: TEST </li>
* <li>COLUMNS (array of varchar): Comma separated list of quoted column
* names. The column names are quoted if necessary. Example: (ID) </li>
* <li>KEYS (array of values): Comma separated list of values. Example: (1)
* </li>
* </ul>
*
*
* @param conn the connection
* @param conn the connection
* @param text the search query
* @param limit the maximum number of rows or 0 for no limit
* @param offset the offset or 0 for no offset
* @return the result set
*/
*/
public
static
void
reindex
(
Connection
conn
)
throws
SQLException
{
public
static
ResultSet
searchData
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
init
(
conn
);
return
search
(
conn
,
text
,
limit
,
offset
,
true
);
removeAllTriggers
(
conn
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
setting
.
getWordList
().
clear
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"TRUNCATE TABLE "
+
SCHEMA
+
".WORDS"
);
stat
.
execute
(
"TRUNCATE TABLE "
+
SCHEMA
+
".ROWS"
);
stat
.
execute
(
"TRUNCATE TABLE "
+
SCHEMA
+
".MAP"
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".INDEXES"
);
while
(
rs
.
next
())
{
String
schema
=
rs
.
getString
(
"SCHEMA"
);
String
table
=
rs
.
getString
(
"TABLE"
);
createTrigger
(
conn
,
schema
,
table
);
indexExistingRows
(
conn
,
schema
,
table
);
}
}
}
/**
/**
...
@@ -227,110 +300,396 @@ public class FullText implements Trigger, CloseListener {
...
@@ -227,110 +300,396 @@ public class FullText implements Trigger, CloseListener {
prep
.
execute
();
prep
.
execute
();
}
}
private
static
void
setIgnoreList
(
FullTextSettings
setting
,
String
commaSeparatedList
)
{
/**
String
[]
list
=
StringUtils
.
arraySplit
(
commaSeparatedList
,
','
,
true
);
* INTERNAL.
HashSet
set
=
setting
.
getIgnoreList
();
* Convert the object to a string.
for
(
int
i
=
0
;
i
<
list
.
length
;
i
++)
{
*
String
word
=
list
[
i
];
* @param data the object
word
=
setting
.
convertWord
(
word
);
* @param type the SQL type
if
(
word
!=
null
)
{
* @return the string
set
.
add
(
list
[
i
]);
*/
}
protected
static
String
asString
(
Object
data
,
int
type
)
throws
SQLException
{
if
(
data
==
null
)
{
return
"NULL"
;
}
}
switch
(
type
)
{
case
Types
.
BIT
:
case
DataType
.
TYPE_BOOLEAN
:
case
Types
.
INTEGER
:
case
Types
.
BIGINT
:
case
Types
.
DECIMAL
:
case
Types
.
DOUBLE
:
case
Types
.
FLOAT
:
case
Types
.
NUMERIC
:
case
Types
.
REAL
:
case
Types
.
SMALLINT
:
case
Types
.
TINYINT
:
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
case
Types
.
LONGVARCHAR
:
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
data
.
toString
();
case
Types
.
CLOB
:
try
{
if
(
data
instanceof
Clob
)
{
data
=
((
Clob
)
data
).
getCharacterStream
();
}
}
return
IOUtils
.
readStringAndClose
((
Reader
)
data
,
-
1
);
private
static
void
removeAllTriggers
(
Connection
conn
)
throws
SQLException
{
}
catch
(
IOException
e
)
{
Statement
stat
=
conn
.
createStatement
();
throw
Message
.
convert
(
e
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM INFORMATION_SCHEMA.TRIGGERS"
);
Statement
stat2
=
conn
.
createStatement
();
while
(
rs
.
next
())
{
String
schema
=
rs
.
getString
(
"TRIGGER_SCHEMA"
);
String
name
=
rs
.
getString
(
"TRIGGER_NAME"
);
if
(
name
.
startsWith
(
TRIGGER_PREFIX
))
{
name
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
name
);
stat2
.
execute
(
"DROP TRIGGER "
+
name
);
}
}
case
Types
.
VARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
BINARY
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
OTHER
:
case
Types
.
BLOB
:
case
Types
.
STRUCT
:
case
Types
.
REF
:
case
Types
.
NULL
:
case
Types
.
ARRAY
:
case
DataType
.
TYPE_DATALINK
:
case
Types
.
DISTINCT
:
throw
new
SQLException
(
"FULLTEXT"
,
"Unsupported column data type: "
+
type
);
default
:
return
""
;
}
}
}
}
/**
/**
*
Drops all full text indexes from the database
.
*
Create an empty search result and initialize the columns
.
*
*
* @param conn the connection
* @param data true if the result set should contain the primary key data as
* an array.
* @return the empty result set
*/
*/
public
static
void
dropAll
(
Connection
conn
)
throws
SQLException
{
protected
static
SimpleResultSet
createResultSet
(
boolean
data
)
throws
SQLException
{
init
(
conn
);
SimpleResultSet
result
=
new
SimpleResultSet
();
Statement
stat
=
conn
.
createStatement
();
if
(
data
)
{
stat
.
execute
(
"DROP SCHEMA IF EXISTS "
+
SCHEMA
);
result
.
addColumn
(
FullText
.
FIELD_SCHEMA
,
Types
.
VARCHAR
,
0
,
0
);
removeAllTriggers
(
conn
);
result
.
addColumn
(
FullText
.
FIELD_TABLE
,
Types
.
VARCHAR
,
0
,
0
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
result
.
addColumn
(
FullText
.
FIELD_COLUMNS
,
Types
.
ARRAY
,
0
,
0
);
setting
.
removeAllIndexes
();
result
.
addColumn
(
FullText
.
FIELD_KEYS
,
Types
.
ARRAY
,
0
,
0
);
setting
.
getIgnoreList
().
clear
();
}
else
{
setting
.
getWordList
().
clear
();
result
.
addColumn
(
FullText
.
FIELD_QUERY
,
Types
.
VARCHAR
,
0
,
0
);
}
return
result
;
}
}
/**
/**
* Initializes full text search functionality for this database. This adds
* Parse a primary key condition into the primary key columns.
* the following Java functions to the database:
* <ul>
* <li>FT_CREATE_INDEX(schemaNameString, tableNameString, columnListString)
* </li><li>FT_SEARCH(queryString, limitInt, offsetInt): result set
* </li><li>FT_REINDEX()
* </li><li>FT_DROP_ALL()
* </li></ul>
* It also adds a schema FULLTEXT to the database where bookkeeping
* information is stored. This function may be called from a Java
* application, or by using the SQL statements:
* <pre>
* CREATE ALIAS IF NOT EXISTS FULLTEXT_INIT FOR
* "org.h2.fulltext.FullText.init";
* CALL FULLTEXT_INIT();
* </pre>
*
*
* @param conn the connection
* @param conn the database connection
* @param key the primary key condition as a string
* @return an array containing the column name list and the data list
*/
*/
public
static
void
init
(
Connection
conn
)
throws
SQLException
{
protected
static
Object
[][]
parseKey
(
Connection
conn
,
String
key
)
throws
SQLException
{
ArrayList
columns
=
new
ArrayList
();
ArrayList
data
=
new
ArrayList
();
JdbcConnection
c
=
(
JdbcConnection
)
conn
;
Session
session
=
(
Session
)
c
.
getSession
();
Parser
p
=
new
Parser
(
session
);
Expression
expr
=
p
.
parseExpression
(
key
);
addColumnData
(
columns
,
data
,
expr
);
Object
[]
col
=
new
Object
[
columns
.
size
()];
columns
.
toArray
(
col
);
Object
[]
dat
=
new
Object
[
columns
.
size
()];
data
.
toArray
(
dat
);
Object
[][]
columnData
=
new
Object
[][]
{
col
,
dat
};
return
columnData
;
}
/**
* INTERNAL.
* Convert an object to a String as used in a SQL statement.
*
* @param data the object
* @param type the SQL type
* @return the SQL String
*/
protected
static
String
quoteSQL
(
Object
data
,
int
type
)
throws
SQLException
{
if
(
data
==
null
)
{
return
"NULL"
;
}
switch
(
type
)
{
case
Types
.
BIT
:
case
DataType
.
TYPE_BOOLEAN
:
case
Types
.
INTEGER
:
case
Types
.
BIGINT
:
case
Types
.
DECIMAL
:
case
Types
.
DOUBLE
:
case
Types
.
FLOAT
:
case
Types
.
NUMERIC
:
case
Types
.
REAL
:
case
Types
.
SMALLINT
:
case
Types
.
TINYINT
:
return
data
.
toString
();
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
case
Types
.
LONGVARCHAR
:
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
quoteString
(
data
.
toString
());
case
Types
.
VARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
BINARY
:
return
"'"
+
ByteUtils
.
convertBytesToString
((
byte
[])
data
)
+
"'"
;
case
Types
.
CLOB
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
OTHER
:
case
Types
.
BLOB
:
case
Types
.
STRUCT
:
case
Types
.
REF
:
case
Types
.
NULL
:
case
Types
.
ARRAY
:
case
DataType
.
TYPE_DATALINK
:
case
Types
.
DISTINCT
:
throw
new
SQLException
(
"FULLTEXT"
,
"Unsupported key data type: "
+
type
);
default
:
return
""
;
}
}
/**
* Remove all triggers that start with the given prefix.
*
* @param conn the database connection
* @param prefix the prefix
*/
protected
static
void
removeAllTriggers
(
Connection
conn
,
String
prefix
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE SCHEMA IF NOT EXISTS "
+
SCHEMA
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM INFORMATION_SCHEMA.TRIGGERS"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
Statement
stat2
=
conn
.
createStatement
();
+
".INDEXES(ID INT AUTO_INCREMENT PRIMARY KEY, SCHEMA VARCHAR, TABLE VARCHAR, COLUMNS VARCHAR, UNIQUE(SCHEMA, TABLE))"
);
while
(
rs
.
next
())
{
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
String
schema
=
rs
.
getString
(
"TRIGGER_SCHEMA"
);
+
".WORDS(ID INT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR, UNIQUE(NAME))"
);
String
name
=
rs
.
getString
(
"TRIGGER_NAME"
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
if
(
name
.
startsWith
(
TRIGGER_PREFIX
))
{
+
".ROWS(ID IDENTITY, HASH INT, INDEXID INT, KEY VARCHAR, UNIQUE(HASH, INDEXID, KEY))"
);
name
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
name
);
stat2
.
execute
(
"DROP TRIGGER "
+
name
);
}
}
}
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
/**
+
".MAP(ROWID INT, WORDID INT, PRIMARY KEY(WORDID, ROWID))"
);
* Set the column indices of a set of keys.
*
* @param index the column indices (will be modified)
* @param keys the key list
* @param columns the column list
*/
protected
static
void
setColumns
(
int
[]
index
,
ArrayList
keys
,
ArrayList
columns
)
throws
SQLException
{
for
(
int
i
=
0
;
i
<
keys
.
size
();
i
++)
{
String
key
=
(
String
)
keys
.
get
(
i
);
int
found
=
-
1
;
for
(
int
j
=
0
;
found
==
-
1
&&
j
<
columns
.
size
();
j
++)
{
String
column
=
(
String
)
columns
.
get
(
j
);
if
(
column
.
equals
(
key
))
{
found
=
j
;
}
}
if
(
found
<
0
)
{
throw
new
SQLException
(
"FULLTEXT"
,
"Column not found: "
+
key
);
}
index
[
i
]
=
found
;
}
}
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".IGNORELIST(LIST VARCHAR)"
);
private
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
,
boolean
data
)
throws
SQLException
{
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_CREATE_INDEX FOR \""
+
FullText
.
class
.
getName
()
+
".createIndex\""
);
SimpleResultSet
result
=
createResultSet
(
data
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_DROP_INDEX FOR \""
+
FullText
.
class
.
getName
()
+
".dropIndex\""
);
if
(
conn
.
getMetaData
().
getURL
().
startsWith
(
"jdbc:columnlist:"
))
{
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_SEARCH FOR \""
+
FullText
.
class
.
getName
()
+
".search\""
);
// this is just to query the result set columns
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_SEARCH_DATA FOR \""
+
FullText
.
class
.
getName
()
+
".searchData\""
);
return
result
;
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_REINDEX FOR \""
+
FullText
.
class
.
getName
()
+
".reindex\""
);
}
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FT_DROP_ALL FOR \""
+
FullText
.
class
.
getName
()
+
".dropAll\""
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".IGNORELIST"
);
HashSet
words
=
new
HashSet
();
addWords
(
setting
,
words
,
text
);
HashSet
rIds
=
null
,
lastRowIds
=
null
;
HashMap
allWords
=
setting
.
getWordList
();
PreparedStatement
prepSelectMapByWordId
=
setting
.
getPrepSelectMapByWordId
();
for
(
Iterator
it
=
words
.
iterator
();
it
.
hasNext
();)
{
lastRowIds
=
rIds
;
rIds
=
new
HashSet
();
String
word
=
(
String
)
it
.
next
();
Integer
wId
=
(
Integer
)
allWords
.
get
(
word
);
if
(
wId
==
null
)
{
continue
;
}
prepSelectMapByWordId
.
setInt
(
1
,
wId
.
intValue
());
ResultSet
rs
=
prepSelectMapByWordId
.
executeQuery
();
while
(
rs
.
next
())
{
while
(
rs
.
next
())
{
String
commaSeparatedList
=
rs
.
getString
(
1
);
Integer
rId
=
ObjectUtils
.
getInteger
(
rs
.
getInt
(
1
));
setIgnoreList
(
setting
,
commaSeparatedList
);
if
(
lastRowIds
==
null
||
lastRowIds
.
contains
(
rId
))
{
rIds
.
add
(
rId
);
}
}
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".WORDS"
);
}
HashMap
map
=
setting
.
getWordList
();
}
if
(
rIds
==
null
||
rIds
.
size
()
==
0
)
{
return
result
;
}
PreparedStatement
prepSelectRowById
=
setting
.
getPrepSelectRowById
();
int
rowCount
=
0
;
for
(
Iterator
it
=
rIds
.
iterator
();
it
.
hasNext
();)
{
int
rowId
=
((
Integer
)
it
.
next
()).
intValue
();
prepSelectRowById
.
setInt
(
1
,
rowId
);
ResultSet
rs
=
prepSelectRowById
.
executeQuery
();
if
(!
rs
.
next
())
{
continue
;
}
if
(
offset
>
0
)
{
offset
--;
}
else
{
String
key
=
rs
.
getString
(
1
);
int
indexId
=
rs
.
getInt
(
2
);
IndexInfo
index
=
setting
.
getIndexInfo
(
indexId
);
if
(
data
)
{
Object
[][]
columnData
=
parseKey
(
conn
,
key
);
Object
[]
row
=
new
Object
[]
{
index
.
schema
,
index
.
table
,
columnData
[
0
],
columnData
[
1
]
};
result
.
addRow
(
row
);
}
else
{
StringBuffer
buff
=
new
StringBuffer
();
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
schema
));
buff
.
append
(
'.'
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
table
));
buff
.
append
(
" WHERE "
);
buff
.
append
(
key
);
String
query
=
buff
.
toString
();
result
.
addRow
(
new
String
[]
{
query
});
}
rowCount
++;
if
(
limit
>
0
&&
rowCount
>=
limit
)
{
break
;
}
}
}
return
result
;
}
private
static
void
addColumnData
(
ArrayList
columns
,
ArrayList
data
,
Expression
expr
)
{
if
(
expr
instanceof
ConditionAndOr
)
{
ConditionAndOr
and
=
(
ConditionAndOr
)
expr
;
Expression
left
=
and
.
getExpression
(
true
);
Expression
right
=
and
.
getExpression
(
false
);
addColumnData
(
columns
,
data
,
left
);
addColumnData
(
columns
,
data
,
right
);
}
else
{
Comparison
comp
=
(
Comparison
)
expr
;
ExpressionColumn
ec
=
(
ExpressionColumn
)
comp
.
getExpression
(
true
);
ValueExpression
ev
=
(
ValueExpression
)
comp
.
getExpression
(
false
);
String
columnName
=
ec
.
getColumnName
();
columns
.
add
(
columnName
);
if
(
ev
==
null
)
{
data
.
add
(
null
);
}
else
{
data
.
add
(
ev
.
getValue
(
null
).
getString
());
}
}
}
private
static
void
addWords
(
FullTextSettings
setting
,
HashSet
set
,
String
text
)
{
StringTokenizer
tokenizer
=
new
StringTokenizer
(
text
,
" \t\n\r\f+\"*%&/()=?'!,.;:-_#@|^~`{}[]"
);
while
(
tokenizer
.
hasMoreTokens
())
{
String
word
=
tokenizer
.
nextToken
();
word
=
setting
.
convertWord
(
word
);
if
(
word
!=
null
)
{
set
.
add
(
word
);
}
}
}
private
static
void
createTrigger
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
createOrDropTrigger
(
conn
,
schema
,
table
,
true
);
}
private
static
void
createOrDropTrigger
(
Connection
conn
,
String
schema
,
String
table
,
boolean
create
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
String
trigger
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
TRIGGER_PREFIX
+
table
);
stat
.
execute
(
"DROP TRIGGER IF EXISTS "
+
trigger
);
if
(
create
)
{
StringBuffer
buff
=
new
StringBuffer
(
"CREATE TRIGGER IF NOT EXISTS "
);
buff
.
append
(
trigger
);
buff
.
append
(
" AFTER INSERT, UPDATE, DELETE ON "
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
buff
.
append
(
" FOR EACH ROW CALL \""
);
buff
.
append
(
FullText
.
FullTextTrigger
.
class
.
getName
());
buff
.
append
(
"\""
);
stat
.
execute
(
buff
.
toString
());
}
}
private
static
void
indexExistingRows
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
FullText
.
FullTextTrigger
existing
=
new
FullText
.
FullTextTrigger
();
existing
.
init
(
conn
,
schema
,
null
,
table
,
false
,
Trigger
.
INSERT
);
StringBuffer
buff
=
new
StringBuffer
(
"SELECT * FROM "
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
ResultSet
rs
=
conn
.
createStatement
().
executeQuery
(
buff
.
toString
());
int
columnCount
=
rs
.
getMetaData
().
getColumnCount
();
while
(
rs
.
next
())
{
while
(
rs
.
next
())
{
String
word
=
rs
.
getString
(
"NAME"
);
Object
[]
row
=
new
Object
[
columnCount
];
int
id
=
rs
.
getInt
(
"ID"
);
for
(
int
i
=
0
;
i
<
columnCount
;
i
++)
{
row
[
i
]
=
rs
.
getObject
(
i
+
1
);
}
existing
.
fire
(
conn
,
null
,
row
);
}
}
private
static
String
quoteString
(
String
data
)
{
if
(
data
.
indexOf
(
'\''
)
<
0
)
{
return
"'"
+
data
+
"'"
;
}
StringBuffer
buff
=
new
StringBuffer
(
data
.
length
()
+
2
);
buff
.
append
(
'\''
);
for
(
int
i
=
0
;
i
<
data
.
length
();
i
++)
{
char
ch
=
data
.
charAt
(
i
);
if
(
ch
==
'\''
)
{
buff
.
append
(
ch
);
}
buff
.
append
(
ch
);
}
buff
.
append
(
'\''
);
return
buff
.
toString
();
}
private
static
void
setIgnoreList
(
FullTextSettings
setting
,
String
commaSeparatedList
)
{
String
[]
list
=
StringUtils
.
arraySplit
(
commaSeparatedList
,
','
,
true
);
HashSet
set
=
setting
.
getIgnoreList
();
for
(
int
i
=
0
;
i
<
list
.
length
;
i
++)
{
String
word
=
list
[
i
];
word
=
setting
.
convertWord
(
word
);
word
=
setting
.
convertWord
(
word
);
if
(
word
!=
null
)
{
if
(
word
!=
null
)
{
map
.
put
(
word
,
ObjectUtils
.
getInteger
(
id
)
);
set
.
add
(
list
[
i
]
);
}
}
}
}
}
}
/**
* Trigger updates the index when a inserting, updating, or deleting a row.
*/
public
static
class
FullTextTrigger
implements
Trigger
,
CloseListener
{
private
FullTextSettings
setting
;
private
IndexInfo
index
;
private
int
[]
columnTypes
;
private
PreparedStatement
prepInsertWord
,
prepInsertRow
,
prepInsertMap
;
private
PreparedStatement
prepDeleteRow
,
prepDeleteMap
;
private
PreparedStatement
prepSelectRow
;
/**
/**
* INTERNAL
* INTERNAL
*/
*/
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
setting
=
FullTextSettings
.
getInstance
(
conn
);
setting
=
FullTextSettings
.
getInstance
(
conn
);
ArrayList
keyList
=
new
ArrayList
();
ArrayList
keyList
=
new
ArrayList
();
DatabaseMetaData
meta
=
conn
.
getMetaData
();
DatabaseMetaData
meta
=
conn
.
getMetaData
();
...
@@ -339,15 +698,15 @@ public class FullText implements Trigger, CloseListener {
...
@@ -339,15 +698,15 @@ public class FullText implements Trigger, CloseListener {
while
(
rs
.
next
())
{
while
(
rs
.
next
())
{
columnList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
columnList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
}
}
data
Types
=
new
int
[
columnList
.
size
()];
column
Types
=
new
int
[
columnList
.
size
()];
index
=
new
IndexInfo
();
index
=
new
IndexInfo
();
index
.
schemaName
=
schemaName
;
index
.
schema
=
schemaName
;
index
.
tableNam
e
=
tableName
;
index
.
tabl
e
=
tableName
;
index
.
columnName
s
=
new
String
[
columnList
.
size
()];
index
.
column
s
=
new
String
[
columnList
.
size
()];
columnList
.
toArray
(
index
.
columnName
s
);
columnList
.
toArray
(
index
.
column
s
);
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
for
(
int
i
=
0
;
rs
.
next
();
i
++)
{
for
(
int
i
=
0
;
rs
.
next
();
i
++)
{
data
Types
[
i
]
=
rs
.
getInt
(
"DATA_TYPE"
);
column
Types
[
i
]
=
rs
.
getInt
(
"DATA_TYPE"
);
}
}
if
(
keyList
.
size
()
==
0
)
{
if
(
keyList
.
size
()
==
0
)
{
rs
=
meta
.
getPrimaryKeys
(
null
,
schemaName
,
tableName
);
rs
=
meta
.
getPrimaryKeys
(
null
,
schemaName
,
tableName
);
...
@@ -400,220 +759,34 @@ public class FullText implements Trigger, CloseListener {
...
@@ -400,220 +759,34 @@ public class FullText implements Trigger, CloseListener {
PreparedStatement
prepSelectRowById
=
conn
.
prepareStatement
(
PreparedStatement
prepSelectRowById
=
conn
.
prepareStatement
(
"SELECT KEY, INDEXID FROM "
+
SCHEMA
+
".ROWS WHERE ID=?"
);
"SELECT KEY, INDEXID FROM "
+
SCHEMA
+
".ROWS WHERE ID=?"
);
setting
.
setPrepSelectMapByWordId
(
prepSelectMapByWordId
);
setting
.
setPrepSelectMapByWordId
(
prepSelectMapByWordId
);
setting
.
setPrepSelectRowById
(
prepSelectRowById
);
setting
.
setPrepSelectRowById
(
prepSelectRowById
);
}
private
void
setColumns
(
int
[]
index
,
ArrayList
keys
,
ArrayList
columns
)
throws
SQLException
{
for
(
int
i
=
0
;
i
<
keys
.
size
();
i
++)
{
String
key
=
(
String
)
keys
.
get
(
i
);
int
found
=
-
1
;
for
(
int
j
=
0
;
found
==
-
1
&&
j
<
columns
.
size
();
j
++)
{
String
column
=
(
String
)
columns
.
get
(
j
);
if
(
column
.
equals
(
key
))
{
found
=
j
;
}
}
if
(
found
<
0
)
{
throw
new
SQLException
(
"FULLTEXT"
,
"Column not found: "
+
key
);
}
index
[
i
]
=
found
;
}
}
/**
* INTERNAL
*/
public
void
fire
(
Connection
conn
,
Object
[]
oldRow
,
Object
[]
newRow
)
throws
SQLException
{
if
(
oldRow
!=
null
)
{
delete
(
setting
,
oldRow
);
}
if
(
newRow
!=
null
)
{
insert
(
setting
,
newRow
);
}
}
private
String
getKey
(
Object
[]
row
)
throws
SQLException
{
StringBuffer
buff
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
index
.
keys
.
length
;
i
++)
{
if
(
i
>
0
)
{
buff
.
append
(
" AND "
);
}
int
columnIndex
=
index
.
keys
[
i
];
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
columnNames
[
columnIndex
]));
Object
o
=
row
[
columnIndex
];
if
(
o
==
null
)
{
buff
.
append
(
" IS NULL"
);
}
else
{
buff
.
append
(
"="
);
buff
.
append
(
quoteSQL
(
o
,
dataTypes
[
columnIndex
]));
}
}
String
key
=
buff
.
toString
();
return
key
;
}
private
String
quoteString
(
String
data
)
{
if
(
data
.
indexOf
(
'\''
)
<
0
)
{
return
"'"
+
data
+
"'"
;
}
StringBuffer
buff
=
new
StringBuffer
(
data
.
length
()
+
2
);
buff
.
append
(
'\''
);
for
(
int
i
=
0
;
i
<
data
.
length
();
i
++)
{
char
ch
=
data
.
charAt
(
i
);
if
(
ch
==
'\''
)
{
buff
.
append
(
ch
);
}
buff
.
append
(
ch
);
}
buff
.
append
(
'\''
);
return
buff
.
toString
();
}
private
String
quoteBinary
(
byte
[]
data
)
{
return
"'"
+
ByteUtils
.
convertBytesToString
(
data
)
+
"'"
;
}
/**
* INTERNAL.
* Convert the object to a string.
*
* @param data the object
* @param type the SQL type
* @return the string
*/
protected
static
String
asString
(
Object
data
,
int
type
)
throws
SQLException
{
if
(
data
==
null
)
{
return
"NULL"
;
}
switch
(
type
)
{
case
Types
.
BIT
:
case
DataType
.
TYPE_BOOLEAN
:
case
Types
.
INTEGER
:
case
Types
.
BIGINT
:
case
Types
.
DECIMAL
:
case
Types
.
DOUBLE
:
case
Types
.
FLOAT
:
case
Types
.
NUMERIC
:
case
Types
.
REAL
:
case
Types
.
SMALLINT
:
case
Types
.
TINYINT
:
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
case
Types
.
LONGVARCHAR
:
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
data
.
toString
();
case
Types
.
CLOB
:
try
{
if
(
data
instanceof
Clob
)
{
data
=
((
Clob
)
data
).
getCharacterStream
();
}
return
IOUtils
.
readStringAndClose
((
Reader
)
data
,
-
1
);
}
catch
(
IOException
e
)
{
throw
Message
.
convert
(
e
);
}
case
Types
.
VARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
BINARY
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
OTHER
:
case
Types
.
BLOB
:
case
Types
.
STRUCT
:
case
Types
.
REF
:
case
Types
.
NULL
:
case
Types
.
ARRAY
:
case
DataType
.
TYPE_DATALINK
:
case
Types
.
DISTINCT
:
throw
new
SQLException
(
"FULLTEXT"
,
"Unsupported column data type: "
+
type
);
default
:
return
""
;
}
}
private
String
quoteSQL
(
Object
data
,
int
type
)
throws
SQLException
{
if
(
data
==
null
)
{
return
"NULL"
;
}
switch
(
type
)
{
case
Types
.
BIT
:
case
DataType
.
TYPE_BOOLEAN
:
case
Types
.
INTEGER
:
case
Types
.
BIGINT
:
case
Types
.
DECIMAL
:
case
Types
.
DOUBLE
:
case
Types
.
FLOAT
:
case
Types
.
NUMERIC
:
case
Types
.
REAL
:
case
Types
.
SMALLINT
:
case
Types
.
TINYINT
:
return
data
.
toString
();
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
case
Types
.
LONGVARCHAR
:
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
quoteString
(
data
.
toString
());
case
Types
.
VARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
BINARY
:
return
quoteBinary
((
byte
[])
data
);
case
Types
.
CLOB
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
OTHER
:
case
Types
.
BLOB
:
case
Types
.
STRUCT
:
case
Types
.
REF
:
case
Types
.
NULL
:
case
Types
.
ARRAY
:
case
DataType
.
TYPE_DATALINK
:
case
Types
.
DISTINCT
:
throw
new
SQLException
(
"FULLTEXT"
,
"Unsupported key data type: "
+
type
);
default
:
return
""
;
}
}
}
private
static
void
addWords
(
FullTextSettings
setting
,
HashSet
set
,
String
text
)
{
/**
StringTokenizer
tokenizer
=
new
StringTokenizer
(
text
,
" \t\n\r\f+\"*%&/()=?'!,.;:-_#@|^~`{}[]"
);
* INTERNAL
while
(
tokenizer
.
hasMoreTokens
())
{
*/
String
word
=
tokenizer
.
nextToken
();
public
void
fire
(
Connection
conn
,
Object
[]
oldRow
,
Object
[]
newRow
)
word
=
setting
.
convertWord
(
word
);
throws
SQLException
{
if
(
word
!=
null
)
{
if
(
oldRow
!=
null
)
{
set
.
add
(
word
);
delete
(
setting
,
oldRow
);
}
}
if
(
newRow
!=
null
)
{
insert
(
setting
,
newRow
);
}
}
}
}
private
int
[]
getWordIds
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
/**
HashSet
words
=
new
HashSet
();
* INTERNAL
for
(
int
i
=
0
;
i
<
index
.
indexColumns
.
length
;
i
++)
{
*/
int
idx
=
index
.
indexColumns
[
i
];
public
void
close
()
throws
SQLException
{
String
data
=
asString
(
row
[
idx
],
dataTypes
[
idx
]);
setting
.
removeIndexInfo
(
index
);
addWords
(
setting
,
words
,
data
);
}
HashMap
allWords
=
setting
.
getWordList
();
int
[]
wordIds
=
new
int
[
words
.
size
()];
Iterator
it
=
words
.
iterator
();
for
(
int
i
=
0
;
it
.
hasNext
();
i
++)
{
String
word
=
(
String
)
it
.
next
();
Integer
wId
=
(
Integer
)
allWords
.
get
(
word
);
int
wordId
;
if
(
wId
==
null
)
{
prepInsertWord
.
setString
(
1
,
word
);
prepInsertWord
.
execute
();
ResultSet
rs
=
JdbcUtils
.
getGeneratedKeys
(
prepInsertWord
);
rs
.
next
();
wordId
=
rs
.
getInt
(
1
);
allWords
.
put
(
word
,
ObjectUtils
.
getInteger
(
wordId
));
}
else
{
wordId
=
wId
.
intValue
();
}
wordIds
[
i
]
=
wordId
;
}
}
Arrays
.
sort
(
wordIds
);
return
wordIds
;
/**
* INTERNAL
*/
public
void
remove
()
throws
SQLException
{
setting
.
removeIndexInfo
(
index
);
}
}
private
void
insert
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
private
void
insert
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
...
@@ -656,201 +829,56 @@ public class FullText implements Trigger, CloseListener {
...
@@ -656,201 +829,56 @@ public class FullText implements Trigger, CloseListener {
}
}
}
}
/**
private
int
[]
getWordIds
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
* Searches from the full text index for this database. The result contains
* the primary key data as an array. The returned result set has the
* following columns:
* <ul>
* <li>SCHEMA (varchar): The schema name. Example: PUBLIC </li>
* <li>TABLE (varchar): The table name. Example: TEST </li>
* <li>COLUMNS (array of varchar): Comma separated list of quoted column
* names. The column names are quoted if necessary. Example: (ID) </li>
* <li>KEYS (array of values): Comma separated list of values. Example: (1)
* </li>
* </ul>
*
* @param conn the connection
* @param text the search query
* @param limit the maximum number of rows or 0 for no limit
* @param offset the offset or 0 for no offset
* @return the result set
*/
public
static
ResultSet
searchData
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
return
search
(
conn
,
text
,
limit
,
offset
,
true
);
}
/**
* Searches from the full text index for this database.
* The returned result set has the following column:
* <ul><li>QUERY (varchar): The query to use to get the data.
* The query does not include 'SELECT * FROM '. Example:
* PUBLIC.TEST WHERE ID = 1
* </li></ul>
*
* @param conn the connection
* @param text the search query
* @param limit the maximum number of rows or 0 for no limit
* @param offset the offset or 0 for no offset
* @return the result set
*/
public
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
return
search
(
conn
,
text
,
limit
,
offset
,
false
);
}
/**
* Create an empty search result and initialize the columns.
*
* @param data true if the result set should contain the primary key data as
* an array.
* @return the empty result set
*/
static
SimpleResultSet
createResultSet
(
boolean
data
)
throws
SQLException
{
SimpleResultSet
result
=
new
SimpleResultSet
();
if
(
data
)
{
result
.
addColumn
(
FullText
.
FIELD_SCHEMA
,
Types
.
VARCHAR
,
0
,
0
);
result
.
addColumn
(
FullText
.
FIELD_TABLE
,
Types
.
VARCHAR
,
0
,
0
);
result
.
addColumn
(
FullText
.
FIELD_COLUMNS
,
Types
.
ARRAY
,
0
,
0
);
result
.
addColumn
(
FullText
.
FIELD_KEYS
,
Types
.
ARRAY
,
0
,
0
);
}
else
{
result
.
addColumn
(
FullText
.
FIELD_QUERY
,
Types
.
VARCHAR
,
0
,
0
);
}
return
result
;
}
private
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
,
boolean
data
)
throws
SQLException
{
SimpleResultSet
result
=
createResultSet
(
data
);
if
(
conn
.
getMetaData
().
getURL
().
startsWith
(
"jdbc:columnlist:"
))
{
// this is just to query the result set columns
return
result
;
}
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
HashSet
words
=
new
HashSet
();
HashSet
words
=
new
HashSet
();
addWords
(
setting
,
words
,
text
);
for
(
int
i
=
0
;
i
<
index
.
indexColumns
.
length
;
i
++)
{
HashSet
rIds
=
null
,
lastRowIds
=
null
;
int
idx
=
index
.
indexColumns
[
i
];
String
data
=
asString
(
row
[
idx
],
columnTypes
[
idx
]);
addWords
(
setting
,
words
,
data
);
}
HashMap
allWords
=
setting
.
getWordList
();
HashMap
allWords
=
setting
.
getWordList
();
int
[]
wordIds
=
new
int
[
words
.
size
()];
PreparedStatement
prepSelectMapByWordId
=
setting
.
getPrepSelectMapByWordId
();
Iterator
it
=
words
.
iterator
();
for
(
Iterator
it
=
words
.
iterator
();
it
.
hasNext
();)
{
for
(
int
i
=
0
;
it
.
hasNext
();
i
++)
{
lastRowIds
=
rIds
;
rIds
=
new
HashSet
();
String
word
=
(
String
)
it
.
next
();
String
word
=
(
String
)
it
.
next
();
Integer
wId
=
(
Integer
)
allWords
.
get
(
word
);
Integer
wId
=
(
Integer
)
allWords
.
get
(
word
);
int
wordId
;
if
(
wId
==
null
)
{
if
(
wId
==
null
)
{
continue
;
prepInsertWord
.
setString
(
1
,
word
);
}
prepInsertWord
.
execute
();
prepSelectMapByWordId
.
setInt
(
1
,
wId
.
intValue
());
ResultSet
rs
=
JdbcUtils
.
getGeneratedKeys
(
prepInsertWord
);
ResultSet
rs
=
prepSelectMapByWordId
.
executeQuery
();
rs
.
next
();
while
(
rs
.
next
())
{
wordId
=
rs
.
getInt
(
1
);
Integer
rId
=
ObjectUtils
.
getInteger
(
rs
.
getInt
(
1
));
allWords
.
put
(
word
,
ObjectUtils
.
getInteger
(
wordId
));
if
(
lastRowIds
==
null
||
lastRowIds
.
contains
(
rId
))
{
rIds
.
add
(
rId
);
}
}
}
if
(
rIds
==
null
||
rIds
.
size
()
==
0
)
{
return
result
;
}
PreparedStatement
prepSelectRowById
=
setting
.
getPrepSelectRowById
();
int
rowCount
=
0
;
for
(
Iterator
it
=
rIds
.
iterator
();
it
.
hasNext
();)
{
int
rowId
=
((
Integer
)
it
.
next
()).
intValue
();
prepSelectRowById
.
setInt
(
1
,
rowId
);
ResultSet
rs
=
prepSelectRowById
.
executeQuery
();
if
(!
rs
.
next
())
{
continue
;
}
if
(
offset
>
0
)
{
offset
--;
}
else
{
String
key
=
rs
.
getString
(
1
);
int
indexId
=
rs
.
getInt
(
2
);
IndexInfo
index
=
setting
.
getIndexInfo
(
indexId
);
if
(
data
)
{
Object
[][]
columnData
=
parseKey
(
conn
,
key
);
Object
[]
row
=
new
Object
[]
{
index
.
schemaName
,
index
.
tableName
,
columnData
[
0
],
columnData
[
1
]
};
result
.
addRow
(
row
);
}
else
{
}
else
{
StringBuffer
buff
=
new
StringBuffer
();
wordId
=
wId
.
intValue
();
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
schemaName
));
buff
.
append
(
'.'
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
tableName
));
buff
.
append
(
" WHERE "
);
buff
.
append
(
key
);
String
query
=
buff
.
toString
();
result
.
addRow
(
new
String
[]
{
query
});
}
rowCount
++;
if
(
limit
>
0
&&
rowCount
>=
limit
)
{
break
;
}
}
}
wordIds
[
i
]
=
wordId
;
}
}
return
result
;
Arrays
.
sort
(
wordIds
);
return
wordIds
;
}
}
/**
private
String
getKey
(
Object
[]
row
)
throws
SQLException
{
* Parse a primary key condition into the primary key columns.
StringBuffer
buff
=
new
StringBuffer
();
*
for
(
int
i
=
0
;
i
<
index
.
keys
.
length
;
i
++)
{
* @param conn the database connection
if
(
i
>
0
)
{
* @param key the primary key condition as a string
buff
.
append
(
" AND "
);
* @return an array containing the column name list and the data list
*/
static
Object
[][]
parseKey
(
Connection
conn
,
String
key
)
throws
SQLException
{
ArrayList
columns
=
new
ArrayList
();
ArrayList
data
=
new
ArrayList
();
JdbcConnection
c
=
(
JdbcConnection
)
conn
;
Session
session
=
(
Session
)
c
.
getSession
();
Parser
p
=
new
Parser
(
session
);
Expression
expr
=
p
.
parseExpression
(
key
);
addColumnData
(
columns
,
data
,
expr
);
Object
[]
col
=
new
Object
[
columns
.
size
()];
columns
.
toArray
(
col
);
Object
[]
dat
=
new
Object
[
columns
.
size
()];
data
.
toArray
(
dat
);
Object
[][]
columnData
=
new
Object
[][]
{
col
,
dat
};
return
columnData
;
}
}
int
columnIndex
=
index
.
keys
[
i
];
private
static
void
addColumnData
(
ArrayList
columns
,
ArrayList
data
,
Expression
expr
)
{
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
columns
[
columnIndex
]));
if
(
expr
instanceof
ConditionAndOr
)
{
Object
o
=
row
[
columnIndex
];
ConditionAndOr
and
=
(
ConditionAndOr
)
expr
;
if
(
o
==
null
)
{
Expression
left
=
and
.
getExpression
(
true
);
buff
.
append
(
" IS NULL"
);
Expression
right
=
and
.
getExpression
(
false
);
addColumnData
(
columns
,
data
,
left
);
addColumnData
(
columns
,
data
,
right
);
}
else
{
Comparison
comp
=
(
Comparison
)
expr
;
ExpressionColumn
ec
=
(
ExpressionColumn
)
comp
.
getExpression
(
true
);
ValueExpression
ev
=
(
ValueExpression
)
comp
.
getExpression
(
false
);
String
columnName
=
ec
.
getColumnName
();
columns
.
add
(
columnName
);
if
(
ev
==
null
)
{
data
.
add
(
null
);
}
else
{
}
else
{
data
.
add
(
ev
.
getValue
(
null
).
getString
()
);
buff
.
append
(
"="
);
}
buff
.
append
(
quoteSQL
(
o
,
columnTypes
[
columnIndex
]));
}
}
}
}
String
key
=
buff
.
toString
();
/**
return
key
;
* INTERNAL
*/
public
void
close
()
throws
SQLException
{
setting
.
removeIndexInfo
(
index
);
}
}
/**
* INTERNAL
*/
public
void
remove
()
throws
SQLException
{
setting
.
removeIndexInfo
(
index
);
}
}
}
}
h2/src/main/org/h2/fulltext/FullTextLucene.java
浏览文件 @
edce6934
...
@@ -14,7 +14,6 @@ import java.sql.PreparedStatement;
...
@@ -14,7 +14,6 @@ import java.sql.PreparedStatement;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
java.sql.Types
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashMap
;
...
@@ -39,7 +38,6 @@ import org.h2.expression.ExpressionColumn;
...
@@ -39,7 +38,6 @@ import org.h2.expression.ExpressionColumn;
import
org.h2.jdbc.JdbcConnection
;
import
org.h2.jdbc.JdbcConnection
;
import
org.h2.store.fs.FileSystem
;
import
org.h2.store.fs.FileSystem
;
import
org.h2.tools.SimpleResultSet
;
import
org.h2.tools.SimpleResultSet
;
import
org.h2.util.ByteUtils
;
import
org.h2.util.StringUtils
;
import
org.h2.util.StringUtils
;
//## Java 1.4 end ##
//## Java 1.4 end ##
...
@@ -47,28 +45,57 @@ import org.h2.util.StringUtils;
...
@@ -47,28 +45,57 @@ import org.h2.util.StringUtils;
* This class implements the full text search based on Apache Lucene.
* This class implements the full text search based on Apache Lucene.
* Most methods can be called using SQL statements as well.
* Most methods can be called using SQL statements as well.
*/
*/
public
class
FullTextLucene
extends
FullText
public
class
FullTextLucene
extends
FullText
{
//## Java 1.4 begin ##
implements
Trigger
,
CloseListener
//## Java 1.4 end ##
{
//## Java 1.4 begin ##
//## Java 1.4 begin ##
private
static
final
String
TRIGGER_PREFIX
=
"FTL_"
;
private
static
final
String
SCHEMA
=
"FTL"
;
private
static
final
boolean
STORE_DOCUMENT_TEXT_IN_INDEX
=
Boolean
.
getBoolean
(
"h2.storeDocumentTextInIndex"
);
private
static
final
boolean
STORE_DOCUMENT_TEXT_IN_INDEX
=
Boolean
.
getBoolean
(
"h2.storeDocumentTextInIndex"
);
private
static
HashMap
indexers
=
new
HashMap
();
private
static
final
HashMap
INDEX_MODIFIERS
=
new
HashMap
();
private
static
final
String
FIELD_DATA
=
"DATA"
;
private
static
final
String
FIELD_DATA
=
"DATA"
;
private
static
final
String
FIELD_QUERY
=
"QUERY"
;
private
static
final
String
FIELD_COLUMN_PREFIX
=
"_"
;
private
static
final
String
FIELD_COLUMN_PREFIX
=
"_"
;
private
static
final
String
TRIGGER_PREFIX
=
"FTL_"
;
private
static
final
String
FIELD_QUERY
=
"QUERY"
;
private
static
final
String
SCHEMA
=
"FTL"
;
//## Java 1.4 end ##
private
String
schemaName
;
private
String
tableName
;
/**
private
int
[]
keys
;
* Initializes full text search functionality for this database. This adds
private
int
[]
indexColumns
;
* the following Java functions to the database:
private
String
[]
columnNames
;
* <ul>
private
int
[]
dataTypes
;
* <li>FTL_CREATE_INDEX(schemaNameString, tableNameString,
private
String
indexPath
;
* columnListString)</li>
private
IndexModifier
indexer
;
* <li>FTL_SEARCH(queryString, limitInt, offsetInt): result set</li>
* <li>FTL_REINDEX()</li>
* <li>FTL_DROP_ALL()</li>
* </ul>
* It also adds a schema FTL to the database where bookkeeping information
* is stored. This function may be called from a Java application, or by
* using the SQL statements:
*
* <pre>
* CREATE ALIAS IF NOT EXISTS FTL_INIT FOR
* "org.h2.fulltext.FullTextLucene.init";
* CALL FTL_INIT();
* </pre>
*
* @param conn the connection
*/
//## Java 1.4 begin ##
public
static
void
init
(
Connection
conn
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE SCHEMA IF NOT EXISTS "
+
SCHEMA
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".INDEXES(SCHEMA VARCHAR, TABLE VARCHAR, COLUMNS VARCHAR, PRIMARY KEY(SCHEMA, TABLE))"
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_CREATE_INDEX FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".createIndex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_SEARCH FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".search\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_SEARCH_DATA FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".searchData\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_REINDEX FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".reindex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_DROP_ALL FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".dropAll\""
);
try
{
getIndexModifier
(
conn
);
}
catch
(
Exception
e
)
{
throw
convertException
(
e
);
}
}
//## Java 1.4 end ##
//## Java 1.4 end ##
/**
/**
...
@@ -76,14 +103,15 @@ implements Trigger, CloseListener
...
@@ -76,14 +103,15 @@ implements Trigger, CloseListener
* only have one index at any time.
* only have one index at any time.
*
*
* @param conn the connection
* @param conn the connection
* @param schema the schema name of the table
* @param schema the schema name of the table
(case sensitive)
* @param table the table name
* @param table the table name
(case sensitive)
* @param columnList the column list (null for all columns)
* @param columnList the column list (null for all columns)
*/
*/
//## Java 1.4 begin ##
//## Java 1.4 begin ##
public
static
void
createIndex
(
Connection
conn
,
String
schema
,
String
table
,
String
columnList
)
throws
SQLException
{
public
static
void
createIndex
(
Connection
conn
,
String
schema
,
String
table
,
String
columnList
)
throws
SQLException
{
init
(
conn
);
init
(
conn
);
PreparedStatement
prep
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".INDEXES(SCHEMA, TABLE, COLUMNS) VALUES(?, ?, ?)"
);
PreparedStatement
prep
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".INDEXES(SCHEMA, TABLE, COLUMNS) VALUES(?, ?, ?)"
);
prep
.
setString
(
1
,
schema
);
prep
.
setString
(
1
,
schema
);
prep
.
setString
(
2
,
table
);
prep
.
setString
(
2
,
table
);
prep
.
setString
(
3
,
columnList
);
prep
.
setString
(
3
,
columnList
);
...
@@ -94,14 +122,14 @@ implements Trigger, CloseListener
...
@@ -94,14 +122,14 @@ implements Trigger, CloseListener
//## Java 1.4 end ##
//## Java 1.4 end ##
/**
/**
* Re-creates the full text index for this database
* Re-creates the full text index for this database
.
*
*
* @param conn the connection
* @param conn the connection
*/
*/
//## Java 1.4 begin ##
//## Java 1.4 begin ##
public
static
void
reindex
(
Connection
conn
)
throws
SQLException
{
public
static
void
reindex
(
Connection
conn
)
throws
SQLException
{
init
(
conn
);
init
(
conn
);
removeAllTriggers
(
conn
);
removeAllTriggers
(
conn
,
TRIGGER_PREFIX
);
removeIndexFiles
(
conn
);
removeIndexFiles
(
conn
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".INDEXES"
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM "
+
SCHEMA
+
".INDEXES"
);
...
@@ -123,118 +151,28 @@ implements Trigger, CloseListener
...
@@ -123,118 +151,28 @@ implements Trigger, CloseListener
public
static
void
dropAll
(
Connection
conn
)
throws
SQLException
{
public
static
void
dropAll
(
Connection
conn
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"DROP SCHEMA IF EXISTS "
+
SCHEMA
);
stat
.
execute
(
"DROP SCHEMA IF EXISTS "
+
SCHEMA
);
removeAllTriggers
(
conn
);
removeAllTriggers
(
conn
,
TRIGGER_PREFIX
);
removeIndexFiles
(
conn
);
removeIndexFiles
(
conn
);
}
}
//## Java 1.4 end ##
//## Java 1.4 end ##
/**
/**
* Initializes full text search functionality for this database. This adds
* Searches from the full text index for this database.
* the following Java functions to the database:
* The returned result set has the following column:
* <ul>
* <ul><li>QUERY (varchar): The query to use to get the data.
* <li>FTL_CREATE_INDEX(schemaNameString, tableNameString,
* The query does not include 'SELECT * FROM '. Example:
* columnListString) </li>
* PUBLIC.TEST WHERE ID = 1
* <li>FTL_SEARCH(queryString, limitInt, offsetInt): result set </li>
* </li></ul>
* <li>FTL_REINDEX() </li>
* <li>FTL_DROP_ALL() </li>
* </ul>
* It also adds a schema FTL to the database where bookkeeping information
* is stored. This function may be called from a Java application, or by
* using the SQL statements:
*
* <pre>
* CREATE ALIAS IF NOT EXISTS FTL_INIT FOR
* "org.h2.fulltext.FullTextLucene.init";
* CALL FTL_INIT();
* </pre>
*
*
* @param conn the connection
* @param conn the connection
* @param text the search query
* @param limit the maximum number of rows or 0 for no limit
* @param offset the offset or 0 for no offset
* @return the result set
*/
*/
//## Java 1.4 begin ##
//## Java 1.4 begin ##
public
static
void
init
(
Connection
conn
)
throws
SQLException
{
public
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
return
search
(
conn
,
text
,
limit
,
offset
,
false
);
stat
.
execute
(
"CREATE SCHEMA IF NOT EXISTS "
+
SCHEMA
);
stat
.
execute
(
"CREATE TABLE IF NOT EXISTS "
+
SCHEMA
+
".INDEXES(SCHEMA VARCHAR, TABLE VARCHAR, COLUMNS VARCHAR, PRIMARY KEY(SCHEMA, TABLE))"
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_CREATE_INDEX FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".createIndex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_SEARCH FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".search\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_SEARCH_DATA FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".searchData\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_REINDEX FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".reindex\""
);
stat
.
execute
(
"CREATE ALIAS IF NOT EXISTS FTL_DROP_ALL FOR \""
+
FullTextLucene
.
class
.
getName
()
+
".dropAll\""
);
try
{
getIndexModifier
(
conn
);
}
catch
(
Exception
e
)
{
throw
convertException
(
e
);
}
}
//## Java 1.4 end ##
/**
* INTERNAL
*/
//## Java 1.4 begin ##
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
this
.
schemaName
=
schemaName
;
this
.
tableName
=
tableName
;
this
.
indexPath
=
getIndexPath
(
conn
);
this
.
indexer
=
getIndexModifier
(
conn
);
ArrayList
keyList
=
new
ArrayList
();
DatabaseMetaData
meta
=
conn
.
getMetaData
();
ResultSet
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
ArrayList
columnList
=
new
ArrayList
();
while
(
rs
.
next
())
{
columnList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
}
dataTypes
=
new
int
[
columnList
.
size
()];
columnNames
=
new
String
[
columnList
.
size
()];
columnList
.
toArray
(
columnNames
);
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
for
(
int
i
=
0
;
rs
.
next
();
i
++)
{
dataTypes
[
i
]
=
rs
.
getInt
(
"DATA_TYPE"
);
}
if
(
keyList
.
size
()
==
0
)
{
rs
=
meta
.
getPrimaryKeys
(
null
,
schemaName
,
tableName
);
while
(
rs
.
next
())
{
keyList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
}
}
if
(
keyList
.
size
()
==
0
)
{
throw
new
SQLException
(
"No primary key for table "
+
tableName
);
}
ArrayList
indexList
=
new
ArrayList
();
PreparedStatement
prep
=
conn
.
prepareStatement
(
"SELECT COLUMNS FROM "
+
SCHEMA
+
".INDEXES WHERE SCHEMA=? AND TABLE=?"
);
prep
.
setString
(
1
,
schemaName
);
prep
.
setString
(
2
,
tableName
);
rs
=
prep
.
executeQuery
();
if
(
rs
.
next
())
{
String
columns
=
rs
.
getString
(
1
);
if
(
columns
!=
null
)
{
String
[]
list
=
StringUtils
.
arraySplit
(
columns
,
','
,
true
);
for
(
int
i
=
0
;
i
<
list
.
length
;
i
++)
{
indexList
.
add
(
list
[
i
]);
}
}
}
if
(
indexList
.
size
()
==
0
)
{
indexList
.
addAll
(
columnList
);
}
keys
=
new
int
[
keyList
.
size
()];
setColumns
(
keys
,
keyList
,
columnList
);
indexColumns
=
new
int
[
indexList
.
size
()];
setColumns
(
indexColumns
,
indexList
,
columnList
);
}
//## Java 1.4 end ##
/**
* INTERNAL
*/
//## Java 1.4 begin ##
public
void
fire
(
Connection
conn
,
Object
[]
oldRow
,
Object
[]
newRow
)
throws
SQLException
{
if
(
oldRow
!=
null
)
{
delete
(
oldRow
);
}
if
(
newRow
!=
null
)
{
insert
(
newRow
);
}
}
}
//## Java 1.4 end ##
//## Java 1.4 end ##
...
@@ -261,25 +199,87 @@ implements Trigger, CloseListener
...
@@ -261,25 +199,87 @@ implements Trigger, CloseListener
public
static
ResultSet
searchData
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
public
static
ResultSet
searchData
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
return
search
(
conn
,
text
,
limit
,
offset
,
true
);
return
search
(
conn
,
text
,
limit
,
offset
,
true
);
}
}
//## Java 1.4 end ##
/**
private
static
SQLException
convertException
(
Exception
e
)
{
* Searches from the full text index for this database.
SQLException
e2
=
new
SQLException
(
"FULLTEXT"
,
"Error while indexing document"
);
* The returned result set has the following column:
e2
.
initCause
(
e
);
* <ul><li>QUERY (varchar): The query to use to get the data.
return
e2
;
* The query does not include 'SELECT * FROM '. Example:
}
* PUBLIC.TEST WHERE ID = 1
* </li></ul>
private
static
void
createTrigger
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
*
Statement
stat
=
conn
.
createStatement
();
* @param conn the connection
String
trigger
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
TRIGGER_PREFIX
+
table
);
* @param text the search query
stat
.
execute
(
"DROP TRIGGER IF EXISTS "
+
trigger
);
* @param limit the maximum number of rows or 0 for no limit
StringBuffer
buff
=
new
StringBuffer
(
"CREATE TRIGGER IF NOT EXISTS "
);
* @param offset the offset or 0 for no offset
buff
.
append
(
trigger
);
* @return the result set
buff
.
append
(
" AFTER INSERT, UPDATE, DELETE ON "
);
*/
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
//## Java 1.4 begin ##
buff
.
append
(
" FOR EACH ROW CALL \""
);
public
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
)
throws
SQLException
{
buff
.
append
(
FullTextLucene
.
FullTextTrigger
.
class
.
getName
());
return
search
(
conn
,
text
,
limit
,
offset
,
false
);
buff
.
append
(
"\""
);
stat
.
execute
(
buff
.
toString
());
}
private
static
IndexModifier
getIndexModifier
(
Connection
conn
)
throws
SQLException
{
String
path
=
getIndexPath
(
conn
);
IndexModifier
indexer
;
synchronized
(
INDEX_MODIFIERS
)
{
indexer
=
(
IndexModifier
)
INDEX_MODIFIERS
.
get
(
path
);
if
(
indexer
==
null
)
{
try
{
boolean
recreate
=
!
IndexReader
.
indexExists
(
path
);
Analyzer
analyzer
=
new
StandardAnalyzer
();
indexer
=
new
IndexModifier
(
path
,
analyzer
,
recreate
);
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
}
INDEX_MODIFIERS
.
put
(
path
,
indexer
);
}
}
return
indexer
;
}
private
static
String
getIndexPath
(
Connection
conn
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
ResultSet
rs
=
stat
.
executeQuery
(
"CALL DATABASE_PATH()"
);
rs
.
next
();
String
path
=
rs
.
getString
(
1
);
if
(
path
==
null
)
{
throw
new
SQLException
(
"FULLTEXT"
,
"Fulltext search for in-memory databases is not supported."
);
}
rs
.
close
();
return
path
;
}
private
static
void
indexExistingRows
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
FullTextLucene
.
FullTextTrigger
existing
=
new
FullTextLucene
.
FullTextTrigger
();
existing
.
init
(
conn
,
schema
,
null
,
table
,
false
,
Trigger
.
INSERT
);
StringBuffer
buff
=
new
StringBuffer
(
"SELECT * FROM "
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
ResultSet
rs
=
conn
.
createStatement
().
executeQuery
(
buff
.
toString
());
int
columnCount
=
rs
.
getMetaData
().
getColumnCount
();
while
(
rs
.
next
())
{
Object
[]
row
=
new
Object
[
columnCount
];
for
(
int
i
=
0
;
i
<
columnCount
;
i
++)
{
row
[
i
]
=
rs
.
getObject
(
i
+
1
);
}
existing
.
fire
(
conn
,
null
,
row
);
}
}
private
static
void
removeIndexFiles
(
Connection
conn
)
throws
SQLException
{
String
path
=
getIndexPath
(
conn
);
IndexModifier
index
=
(
IndexModifier
)
INDEX_MODIFIERS
.
get
(
path
);
if
(
index
!=
null
)
{
INDEX_MODIFIERS
.
remove
(
path
);
try
{
index
.
flush
();
index
.
close
();
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
}
}
FileSystem
.
getInstance
(
path
).
deleteRecursive
(
path
);
}
}
private
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
,
boolean
data
)
throws
SQLException
{
private
static
ResultSet
search
(
Connection
conn
,
String
text
,
int
limit
,
int
offset
,
boolean
data
)
throws
SQLException
{
...
@@ -334,126 +334,124 @@ implements Trigger, CloseListener
...
@@ -334,126 +334,124 @@ implements Trigger, CloseListener
}
}
return
result
;
return
result
;
}
}
//## Java 1.4 end ##
private
static
void
removeAllTriggers
(
Connection
conn
)
throws
SQLException
{
/**
Statement
stat
=
conn
.
createStatement
();
* Trigger updates the index when a inserting, updating, or deleting a row.
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT * FROM INFORMATION_SCHEMA.TRIGGERS"
);
*/
Statement
stat2
=
conn
.
createStatement
();
public
static
class
FullTextTrigger
//## Java 1.4 begin ##
implements
Trigger
,
CloseListener
//## Java 1.4 end ##
{
//## Java 1.4 begin ##
private
String
schema
;
private
String
table
;
private
int
[]
keys
;
private
int
[]
indexColumns
;
private
String
[]
columns
;
private
int
[]
columnTypes
;
private
String
indexPath
;
private
IndexModifier
indexModifier
;
//## Java 1.4 end ##
/**
* INTERNAL
*/
//## Java 1.4 begin ##
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
this
.
schema
=
schemaName
;
this
.
table
=
tableName
;
this
.
indexPath
=
getIndexPath
(
conn
);
this
.
indexModifier
=
getIndexModifier
(
conn
);
ArrayList
keyList
=
new
ArrayList
();
DatabaseMetaData
meta
=
conn
.
getMetaData
();
ResultSet
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
ArrayList
columnList
=
new
ArrayList
();
while
(
rs
.
next
())
{
while
(
rs
.
next
())
{
String
schema
=
rs
.
getString
(
"TRIGGER_SCHEMA"
);
columnList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
String
name
=
rs
.
getString
(
"TRIGGER_NAME"
);
if
(
name
.
startsWith
(
TRIGGER_PREFIX
))
{
name
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
name
);
stat2
.
execute
(
"DROP TRIGGER "
+
name
);
}
}
}
columnTypes
=
new
int
[
columnList
.
size
()];
columns
=
new
String
[
columnList
.
size
()];
columnList
.
toArray
(
columns
);
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
for
(
int
i
=
0
;
rs
.
next
();
i
++)
{
columnTypes
[
i
]
=
rs
.
getInt
(
"DATA_TYPE"
);
}
}
if
(
keyList
.
size
()
==
0
)
{
private
static
void
removeIndexFiles
(
Connection
conn
)
throws
SQLException
{
rs
=
meta
.
getPrimaryKeys
(
null
,
schemaName
,
tableName
);
String
path
=
getIndexPath
(
conn
);
while
(
rs
.
next
())
{
IndexModifier
index
=
(
IndexModifier
)
indexers
.
get
(
path
);
keyList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
if
(
index
!=
null
)
{
indexers
.
remove
(
path
);
try
{
index
.
flush
();
index
.
close
();
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
}
}
}
}
FileSystem
.
getInstance
(
path
).
deleteRecursive
(
path
);
if
(
keyList
.
size
()
==
0
)
{
throw
new
SQLException
(
"No primary key for table "
+
tableName
);
}
}
ArrayList
indexList
=
new
ArrayList
();
private
String
getQuery
(
Object
[]
row
)
throws
SQLException
{
PreparedStatement
prep
=
conn
.
prepareStatement
(
"SELECT COLUMNS FROM "
+
SCHEMA
+
".INDEXES WHERE SCHEMA=? AND TABLE=?"
);
StringBuffer
buff
=
new
StringBuffer
();
prep
.
setString
(
1
,
schemaName
);
if
(
schemaName
!=
null
)
{
prep
.
setString
(
2
,
tableName
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schemaName
));
rs
=
prep
.
executeQuery
();
buff
.
append
(
"."
);
if
(
rs
.
next
())
{
String
columns
=
rs
.
getString
(
1
);
if
(
columns
!=
null
)
{
String
[]
list
=
StringUtils
.
arraySplit
(
columns
,
','
,
true
);
for
(
int
i
=
0
;
i
<
list
.
length
;
i
++)
{
indexList
.
add
(
list
[
i
]);
}
}
buff
.
append
(
StringUtils
.
quoteIdentifier
(
tableName
));
buff
.
append
(
" WHERE "
);
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
if
(
i
>
0
)
{
buff
.
append
(
" AND "
);
}
}
int
columnIndex
=
keys
[
i
];
buff
.
append
(
StringUtils
.
quoteIdentifier
(
columnNames
[
columnIndex
]));
Object
o
=
row
[
columnIndex
];
if
(
o
==
null
)
{
buff
.
append
(
" IS NULL"
);
}
else
{
buff
.
append
(
"="
);
buff
.
append
(
quoteSQL
(
o
,
dataTypes
[
columnIndex
]));
}
}
if
(
indexList
.
size
()
==
0
)
{
indexList
.
addAll
(
columnList
);
}
}
String
key
=
buff
.
toString
();
keys
=
new
int
[
keyList
.
size
()];
return
key
;
setColumns
(
keys
,
keyList
,
columnList
);
indexColumns
=
new
int
[
indexList
.
size
()];
setColumns
(
indexColumns
,
indexList
,
columnList
);
}
}
//## Java 1.4 end ##
private
String
quoteString
(
String
data
)
{
/**
if
(
data
.
indexOf
(
'\''
)
<
0
)
{
* INTERNAL
return
"'"
+
data
+
"'"
;
*/
}
//## Java 1.4 begin ##
StringBuffer
buff
=
new
StringBuffer
(
data
.
length
()
+
2
);
public
void
fire
(
Connection
conn
,
Object
[]
oldRow
,
Object
[]
newRow
)
buff
.
append
(
'\''
);
throws
SQLException
{
for
(
int
i
=
0
;
i
<
data
.
length
();
i
++)
{
if
(
oldRow
!=
null
)
{
char
ch
=
data
.
charAt
(
i
);
delete
(
oldRow
);
if
(
ch
==
'\''
)
{
buff
.
append
(
ch
);
}
}
buff
.
append
(
ch
);
if
(
newRow
!=
null
)
{
insert
(
newRow
);
}
}
buff
.
append
(
'\''
);
return
buff
.
toString
();
}
}
//## Java 1.4 end ##
private
String
quoteBinary
(
byte
[]
data
)
{
/**
return
"'"
+
ByteUtils
.
convertBytesToString
(
data
)
+
"'"
;
* INTERNAL
*/
//## Java 1.4 begin ##
public
void
close
()
throws
SQLException
{
if
(
indexModifier
!=
null
)
{
try
{
indexModifier
.
flush
();
indexModifier
.
close
();
INDEX_MODIFIERS
.
remove
(
indexPath
);
indexModifier
=
null
;
}
catch
(
Exception
e
)
{
throw
convertException
(
e
);
}
}
private
String
quoteSQL
(
Object
data
,
int
type
)
throws
SQLException
{
if
(
data
==
null
)
{
return
"NULL"
;
}
switch
(
type
)
{
case
Types
.
BIT
:
case
Types
.
BOOLEAN
:
case
Types
.
INTEGER
:
case
Types
.
BIGINT
:
case
Types
.
DECIMAL
:
case
Types
.
DOUBLE
:
case
Types
.
FLOAT
:
case
Types
.
NUMERIC
:
case
Types
.
REAL
:
case
Types
.
SMALLINT
:
case
Types
.
TINYINT
:
return
data
.
toString
();
case
Types
.
DATE
:
case
Types
.
TIME
:
case
Types
.
TIMESTAMP
:
case
Types
.
LONGVARCHAR
:
case
Types
.
CHAR
:
case
Types
.
VARCHAR
:
return
quoteString
(
data
.
toString
());
case
Types
.
VARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
BINARY
:
return
quoteBinary
((
byte
[])
data
);
case
Types
.
CLOB
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
OTHER
:
case
Types
.
BLOB
:
case
Types
.
STRUCT
:
case
Types
.
REF
:
case
Types
.
NULL
:
case
Types
.
ARRAY
:
case
Types
.
DATALINK
:
case
Types
.
DISTINCT
:
throw
new
SQLException
(
"FULLTEXT"
,
"Unsupported key data type: "
+
type
);
default
:
return
""
;
}
}
}
}
//## Java 1.4 end ##
/**
* INTERNAL
*/
public
void
remove
()
{
// ignore
}
private
void
insert
(
Object
[]
row
)
throws
SQLException
{
private
void
insert
(
Object
[]
row
)
throws
SQLException
{
String
query
=
getQuery
(
row
);
String
query
=
getQuery
(
row
);
...
@@ -464,8 +462,8 @@ implements Trigger, CloseListener
...
@@ -464,8 +462,8 @@ implements Trigger, CloseListener
StringBuffer
allData
=
new
StringBuffer
();
StringBuffer
allData
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
indexColumns
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
indexColumns
.
length
;
i
++)
{
int
index
=
indexColumns
[
i
];
int
index
=
indexColumns
[
i
];
String
columnName
=
columnName
s
[
index
];
String
columnName
=
column
s
[
index
];
String
data
=
asString
(
row
[
index
],
data
Types
[
index
]);
String
data
=
asString
(
row
[
index
],
column
Types
[
index
]);
doc
.
add
(
new
Field
(
FIELD_COLUMN_PREFIX
+
columnName
,
data
,
Field
.
Store
.
NO
,
Field
.
Index
.
TOKENIZED
));
doc
.
add
(
new
Field
(
FIELD_COLUMN_PREFIX
+
columnName
,
data
,
Field
.
Store
.
NO
,
Field
.
Index
.
TOKENIZED
));
if
(
i
>
0
)
{
if
(
i
>
0
)
{
allData
.
append
(
" "
);
allData
.
append
(
" "
);
...
@@ -473,9 +471,10 @@ implements Trigger, CloseListener
...
@@ -473,9 +471,10 @@ implements Trigger, CloseListener
allData
.
append
(
data
);
allData
.
append
(
data
);
}
}
Field
.
Store
storeText
=
STORE_DOCUMENT_TEXT_IN_INDEX
?
Field
.
Store
.
YES
:
Field
.
Store
.
NO
;
Field
.
Store
storeText
=
STORE_DOCUMENT_TEXT_IN_INDEX
?
Field
.
Store
.
YES
:
Field
.
Store
.
NO
;
doc
.
add
(
new
Field
(
FIELD_DATA
,
allData
.
toString
(),
storeText
,
Field
.
Index
.
TOKENIZED
));
doc
.
add
(
new
Field
(
FIELD_DATA
,
allData
.
toString
(),
storeText
,
Field
.
Index
.
TOKENIZED
));
try
{
try
{
index
er
.
addDocument
(
doc
);
indexModifi
er
.
addDocument
(
doc
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
throw
convertException
(
e
);
}
}
...
@@ -485,122 +484,38 @@ implements Trigger, CloseListener
...
@@ -485,122 +484,38 @@ implements Trigger, CloseListener
String
query
=
getQuery
(
row
);
String
query
=
getQuery
(
row
);
try
{
try
{
Term
term
=
new
Term
(
FIELD_QUERY
,
query
);
Term
term
=
new
Term
(
FIELD_QUERY
,
query
);
indexer
.
deleteDocuments
(
term
);
indexModifier
.
deleteDocuments
(
term
);
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
}
}
private
static
SQLException
convertException
(
Exception
e
)
{
SQLException
e2
=
new
SQLException
(
"FULLTEXT"
,
"Error while indexing document"
);
e2
.
initCause
(
e
);
return
e2
;
}
private
static
void
createTrigger
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
String
trigger
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
TRIGGER_PREFIX
+
table
);
stat
.
execute
(
"DROP TRIGGER IF EXISTS "
+
trigger
);
StringBuffer
buff
=
new
StringBuffer
(
"CREATE TRIGGER IF NOT EXISTS "
);
buff
.
append
(
trigger
);
buff
.
append
(
" AFTER INSERT, UPDATE, DELETE ON "
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
buff
.
append
(
" FOR EACH ROW CALL \""
);
buff
.
append
(
FullTextLucene
.
class
.
getName
());
buff
.
append
(
"\""
);
stat
.
execute
(
buff
.
toString
());
}
private
static
void
indexExistingRows
(
Connection
conn
,
String
schema
,
String
table
)
throws
SQLException
{
FullTextLucene
existing
=
new
FullTextLucene
();
existing
.
init
(
conn
,
schema
,
null
,
table
,
false
,
INSERT
);
StringBuffer
buff
=
new
StringBuffer
(
"SELECT * FROM "
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
ResultSet
rs
=
conn
.
createStatement
().
executeQuery
(
buff
.
toString
());
int
columnCount
=
rs
.
getMetaData
().
getColumnCount
();
while
(
rs
.
next
())
{
Object
[]
row
=
new
Object
[
columnCount
];
for
(
int
i
=
0
;
i
<
columnCount
;
i
++)
{
row
[
i
]
=
rs
.
getObject
(
i
+
1
);
}
existing
.
fire
(
conn
,
null
,
row
);
}
}
private
static
IndexModifier
getIndexModifier
(
Connection
conn
)
throws
SQLException
{
String
path
=
getIndexPath
(
conn
);
IndexModifier
indexer
;
synchronized
(
indexers
)
{
indexer
=
(
IndexModifier
)
indexers
.
get
(
path
);
if
(
indexer
==
null
)
{
try
{
boolean
recreate
=
!
IndexReader
.
indexExists
(
path
);
Analyzer
analyzer
=
new
StandardAnalyzer
();
indexer
=
new
IndexModifier
(
path
,
analyzer
,
recreate
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
throw
convertException
(
e
);
}
}
indexers
.
put
(
path
,
indexer
);
}
}
return
indexer
;
}
}
private
static
String
getIndexPath
(
Connection
conn
)
throws
SQLException
{
private
String
getQuery
(
Object
[]
row
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
StringBuffer
buff
=
new
StringBuffer
();
ResultSet
rs
=
stat
.
executeQuery
(
"CALL DATABASE_PATH()"
);
if
(
schema
!=
null
)
{
rs
.
next
();
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
));
String
path
=
rs
.
getString
(
1
);
buff
.
append
(
"."
);
if
(
path
==
null
)
{
throw
new
SQLException
(
"FULLTEXT"
,
"Fulltext search for in-memory databases is not supported."
);
}
rs
.
close
();
return
path
;
}
private
void
setColumns
(
int
[]
index
,
ArrayList
keys
,
ArrayList
columns
)
throws
SQLException
{
for
(
int
i
=
0
;
i
<
keys
.
size
();
i
++)
{
String
key
=
(
String
)
keys
.
get
(
i
);
int
found
=
-
1
;
for
(
int
j
=
0
;
found
==
-
1
&&
j
<
columns
.
size
();
j
++)
{
String
column
=
(
String
)
columns
.
get
(
j
);
if
(
column
.
equals
(
key
))
{
found
=
j
;
}
}
if
(
found
<
0
)
{
throw
new
SQLException
(
"FULLTEXT"
,
"Column not found: "
+
key
);
}
index
[
i
]
=
found
;
}
}
buff
.
append
(
StringUtils
.
quoteIdentifier
(
table
));
buff
.
append
(
" WHERE "
);
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
if
(
i
>
0
)
{
buff
.
append
(
" AND "
);
}
}
//## Java 1.4 end ##
int
columnIndex
=
keys
[
i
];
buff
.
append
(
StringUtils
.
quoteIdentifier
(
columns
[
columnIndex
]));
/**
Object
o
=
row
[
columnIndex
];
* INTERNAL
if
(
o
==
null
)
{
*/
buff
.
append
(
" IS NULL"
);
//## Java 1.4 begin ##
}
else
{
public
void
close
()
throws
SQLException
{
buff
.
append
(
"="
);
try
{
buff
.
append
(
FullText
.
quoteSQL
(
o
,
columnTypes
[
columnIndex
]));
if
(
indexer
!=
null
)
{
indexer
.
flush
();
indexer
.
close
();
indexers
.
remove
(
indexPath
);
indexer
=
null
;
}
}
}
catch
(
Exception
e
)
{
throw
convertException
(
e
);
}
}
String
key
=
buff
.
toString
();
return
key
;
}
}
//## Java 1.4 end ##
/**
* INTERNAL
*/
//## Java 1.4 begin ##
public
void
remove
()
throws
SQLException
{
// ignore
}
}
//## Java 1.4 end ##
}
}
h2/src/main/org/h2/fulltext/FullTextSettings.java
浏览文件 @
edce6934
...
@@ -21,7 +21,7 @@ import org.h2.util.ObjectUtils;
...
@@ -21,7 +21,7 @@ import org.h2.util.ObjectUtils;
*/
*/
class
FullTextSettings
{
class
FullTextSettings
{
private
static
HashMap
settings
=
new
HashMap
();
private
static
final
HashMap
SETTINGS
=
new
HashMap
();
private
HashSet
ignoreList
=
new
HashSet
();
private
HashSet
ignoreList
=
new
HashSet
();
private
HashMap
words
=
new
HashMap
();
private
HashMap
words
=
new
HashMap
();
...
@@ -84,10 +84,10 @@ class FullTextSettings {
...
@@ -84,10 +84,10 @@ class FullTextSettings {
*/
*/
static
FullTextSettings
getInstance
(
Connection
conn
)
throws
SQLException
{
static
FullTextSettings
getInstance
(
Connection
conn
)
throws
SQLException
{
String
path
=
getIndexPath
(
conn
);
String
path
=
getIndexPath
(
conn
);
FullTextSettings
setting
=
(
FullTextSettings
)
settings
.
get
(
path
);
FullTextSettings
setting
=
(
FullTextSettings
)
SETTINGS
.
get
(
path
);
if
(
setting
==
null
)
{
if
(
setting
==
null
)
{
setting
=
new
FullTextSettings
();
setting
=
new
FullTextSettings
();
settings
.
put
(
path
,
setting
);
SETTINGS
.
put
(
path
,
setting
);
}
}
return
setting
;
return
setting
;
}
}
...
...
h2/src/main/org/h2/fulltext/IndexInfo.java
浏览文件 @
edce6934
...
@@ -19,12 +19,12 @@ class IndexInfo {
...
@@ -19,12 +19,12 @@ class IndexInfo {
/**
/**
* The schema name.
* The schema name.
*/
*/
String
schema
Name
;
String
schema
;
/**
/**
* The table name.
* The table name.
*/
*/
String
table
Name
;
String
table
;
/**
/**
* The column indexes of the key columns.
* The column indexes of the key columns.
...
@@ -39,5 +39,5 @@ class IndexInfo {
...
@@ -39,5 +39,5 @@ class IndexInfo {
/**
/**
* The column names.
* The column names.
*/
*/
String
[]
column
Name
s
;
String
[]
columns
;
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论