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,14 +71,72 @@ public class FullText implements Trigger, CloseListener {
...
@@ -76,14 +71,72 @@ 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
* only have one index at any time.
* only have one index at any time.
*
*
...
@@ -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,252 +300,6 @@ public class FullText implements Trigger, CloseListener {
...
@@ -227,252 +300,6 @@ public class FullText implements Trigger, CloseListener {
prep
.
execute
();
prep
.
execute
();
}
}
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
);
if
(
word
!=
null
)
{
set
.
add
(
list
[
i
]);
}
}
}
private
static
void
removeAllTriggers
(
Connection
conn
)
throws
SQLException
{
Statement
stat
=
conn
.
createStatement
();
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
);
}
}
}
/**
* Drops all full text indexes from the database.
*
* @param conn the connection
*/
public
static
void
dropAll
(
Connection
conn
)
throws
SQLException
{
init
(
conn
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"DROP SCHEMA IF EXISTS "
+
SCHEMA
);
removeAllTriggers
(
conn
);
FullTextSettings
setting
=
FullTextSettings
.
getInstance
(
conn
);
setting
.
removeAllIndexes
();
setting
.
getIgnoreList
().
clear
();
setting
.
getWordList
().
clear
();
}
/**
* 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 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
*/
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
));
}
}
}
/**
* INTERNAL
*/
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
setting
=
FullTextSettings
.
getInstance
(
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
()];
index
=
new
IndexInfo
();
index
.
schemaName
=
schemaName
;
index
.
tableName
=
tableName
;
index
.
columnNames
=
new
String
[
columnList
.
size
()];
columnList
.
toArray
(
index
.
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 ID, COLUMNS FROM "
+
SCHEMA
+
".INDEXES WHERE SCHEMA=? AND TABLE=?"
);
prep
.
setString
(
1
,
schemaName
);
prep
.
setString
(
2
,
tableName
);
rs
=
prep
.
executeQuery
();
if
(
rs
.
next
())
{
index
.
id
=
rs
.
getInt
(
1
);
String
columns
=
rs
.
getString
(
2
);
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
);
}
index
.
keys
=
new
int
[
keyList
.
size
()];
setColumns
(
index
.
keys
,
keyList
,
columnList
);
index
.
indexColumns
=
new
int
[
indexList
.
size
()];
setColumns
(
index
.
indexColumns
,
indexList
,
columnList
);
setting
.
addIndexInfo
(
index
);
prepInsertWord
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".WORDS(NAME) VALUES(?)"
);
prepInsertRow
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".ROWS(HASH, INDEXID, KEY) VALUES(?, ?, ?)"
);
prepInsertMap
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".MAP(ROWID, WORDID) VALUES(?, ?)"
);
prepDeleteRow
=
conn
.
prepareStatement
(
"DELETE FROM "
+
SCHEMA
+
".ROWS WHERE HASH=? AND INDEXID=? AND KEY=?"
);
prepDeleteMap
=
conn
.
prepareStatement
(
"DELETE FROM "
+
SCHEMA
+
".MAP WHERE ROWID=? AND WORDID=?"
);
prepSelectRow
=
conn
.
prepareStatement
(
"SELECT ID FROM "
+
SCHEMA
+
".ROWS WHERE HASH=? AND INDEXID=? AND KEY=?"
);
PreparedStatement
prepSelectMapByWordId
=
conn
.
prepareStatement
(
"SELECT ROWID FROM "
+
SCHEMA
+
".MAP WHERE WORDID=?"
);
PreparedStatement
prepSelectRowById
=
conn
.
prepareStatement
(
"SELECT KEY, INDEXID FROM "
+
SCHEMA
+
".ROWS WHERE ID=?"
);
setting
.
setPrepSelectMapByWordId
(
prepSelectMapByWordId
);
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.
* INTERNAL.
* Convert the object to a string.
* Convert the object to a string.
...
@@ -531,7 +358,60 @@ public class FullText implements Trigger, CloseListener {
...
@@ -531,7 +358,60 @@ public class FullText implements Trigger, CloseListener {
}
}
}
}
private
String
quoteSQL
(
Object
data
,
int
type
)
throws
SQLException
{
/**
* 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
*/
protected
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
;
}
/**
* Parse a primary key condition into the primary key columns.
*
* @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
*/
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
)
{
if
(
data
==
null
)
{
return
"NULL"
;
return
"NULL"
;
}
}
...
@@ -558,7 +438,7 @@ public class FullText implements Trigger, CloseListener {
...
@@ -558,7 +438,7 @@ public class FullText implements Trigger, CloseListener {
case
Types
.
VARBINARY
:
case
Types
.
VARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
LONGVARBINARY
:
case
Types
.
BINARY
:
case
Types
.
BINARY
:
return
quoteBinary
((
byte
[])
data
)
;
return
"'"
+
ByteUtils
.
convertBytesToString
((
byte
[])
data
)
+
"'"
;
case
Types
.
CLOB
:
case
Types
.
CLOB
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
JAVA_OBJECT
:
case
Types
.
OTHER
:
case
Types
.
OTHER
:
...
@@ -575,146 +455,48 @@ public class FullText implements Trigger, CloseListener {
...
@@ -575,146 +455,48 @@ public class FullText implements Trigger, CloseListener {
}
}
}
}
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
int
[]
getWordIds
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
HashSet
words
=
new
HashSet
();
for
(
int
i
=
0
;
i
<
index
.
indexColumns
.
length
;
i
++)
{
int
idx
=
index
.
indexColumns
[
i
];
String
data
=
asString
(
row
[
idx
],
dataTypes
[
idx
]);
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
;
}
private
void
insert
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
String
key
=
getKey
(
row
);
int
hash
=
key
.
hashCode
();
prepInsertRow
.
setInt
(
1
,
hash
);
prepInsertRow
.
setInt
(
2
,
index
.
id
);
prepInsertRow
.
setString
(
3
,
key
);
prepInsertRow
.
execute
();
ResultSet
rs
=
JdbcUtils
.
getGeneratedKeys
(
prepInsertRow
);
rs
.
next
();
int
rowId
=
rs
.
getInt
(
1
);
prepInsertMap
.
setInt
(
1
,
rowId
);
int
[]
wordIds
=
getWordIds
(
setting
,
row
);
for
(
int
i
=
0
;
i
<
wordIds
.
length
;
i
++)
{
prepInsertMap
.
setInt
(
2
,
wordIds
[
i
]);
prepInsertMap
.
execute
();
}
}
private
void
delete
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
String
key
=
getKey
(
row
);
int
hash
=
key
.
hashCode
();
prepSelectRow
.
setInt
(
1
,
hash
);
prepSelectRow
.
setInt
(
2
,
index
.
id
);
prepSelectRow
.
setString
(
3
,
key
);
ResultSet
rs
=
prepSelectRow
.
executeQuery
();
if
(
rs
.
next
())
{
int
rowId
=
rs
.
getInt
(
1
);
prepDeleteMap
.
setInt
(
1
,
rowId
);
int
[]
wordIds
=
getWordIds
(
setting
,
row
);
for
(
int
i
=
0
;
i
<
wordIds
.
length
;
i
++)
{
prepDeleteMap
.
setInt
(
2
,
wordIds
[
i
]);
prepDeleteMap
.
executeUpdate
();
}
prepDeleteRow
.
setInt
(
1
,
hash
);
prepDeleteRow
.
setInt
(
2
,
index
.
id
);
prepDeleteRow
.
setString
(
3
,
key
);
prepDeleteRow
.
executeUpdate
();
}
}
/**
* 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.
* Remove all triggers that start with the given prefix.
* 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 conn the database connection
* @param text the search query
* @param prefix the prefix
* @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
{
protected
static
void
removeAllTriggers
(
Connection
conn
,
String
prefix
)
throws
SQLException
{
return
search
(
conn
,
text
,
limit
,
offset
,
false
);
Statement
stat
=
conn
.
createStatement
();
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
);
}
}
}
}
/**
/**
*
Create an empty search result and initialize the column
s.
*
Set the column indices of a set of key
s.
*
*
* @param
data true if the result set should contain the primary key data as
* @param
index the column indices (will be modified)
*
an array.
*
@param keys the key list
* @
return the empty result se
t
* @
param columns the column lis
t
*/
*/
static
SimpleResultSet
createResultSet
(
boolean
data
)
throws
SQLException
{
protected
static
void
setColumns
(
int
[]
index
,
ArrayList
keys
,
ArrayList
columns
)
throws
SQLException
{
SimpleResultSet
result
=
new
SimpleResultSet
();
for
(
int
i
=
0
;
i
<
keys
.
size
();
i
++)
{
if
(
data
)
{
String
key
=
(
String
)
keys
.
get
(
i
);
result
.
addColumn
(
FullText
.
FIELD_SCHEMA
,
Types
.
VARCHAR
,
0
,
0
);
int
found
=
-
1
;
result
.
addColumn
(
FullText
.
FIELD_TABLE
,
Types
.
VARCHAR
,
0
,
0
);
for
(
int
j
=
0
;
found
==
-
1
&&
j
<
columns
.
size
();
j
++)
{
result
.
addColumn
(
FullText
.
FIELD_COLUMNS
,
Types
.
ARRAY
,
0
,
0
);
String
column
=
(
String
)
columns
.
get
(
j
);
result
.
addColumn
(
FullText
.
FIELD_KEYS
,
Types
.
ARRAY
,
0
,
0
);
if
(
column
.
equals
(
key
))
{
}
else
{
found
=
j
;
result
.
addColumn
(
FullText
.
FIELD_QUERY
,
Types
.
VARCHAR
,
0
,
0
);
}
}
if
(
found
<
0
)
{
throw
new
SQLException
(
"FULLTEXT"
,
"Column not found: "
+
key
);
}
index
[
i
]
=
found
;
}
}
return
result
;
}
}
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
{
...
@@ -768,17 +550,17 @@ public class FullText implements Trigger, CloseListener {
...
@@ -768,17 +550,17 @@ public class FullText implements Trigger, CloseListener {
if
(
data
)
{
if
(
data
)
{
Object
[][]
columnData
=
parseKey
(
conn
,
key
);
Object
[][]
columnData
=
parseKey
(
conn
,
key
);
Object
[]
row
=
new
Object
[]
{
Object
[]
row
=
new
Object
[]
{
index
.
schema
Name
,
index
.
schema
,
index
.
table
Name
,
index
.
table
,
columnData
[
0
],
columnData
[
0
],
columnData
[
1
]
columnData
[
1
]
};
};
result
.
addRow
(
row
);
result
.
addRow
(
row
);
}
else
{
}
else
{
StringBuffer
buff
=
new
StringBuffer
();
StringBuffer
buff
=
new
StringBuffer
();
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
schema
Name
));
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
schema
));
buff
.
append
(
'.'
);
buff
.
append
(
'.'
);
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
table
Name
));
buff
.
append
(
StringUtils
.
quoteIdentifier
(
index
.
table
));
buff
.
append
(
" WHERE "
);
buff
.
append
(
" WHERE "
);
buff
.
append
(
key
);
buff
.
append
(
key
);
String
query
=
buff
.
toString
();
String
query
=
buff
.
toString
();
...
@@ -793,31 +575,6 @@ public class FullText implements Trigger, CloseListener {
...
@@ -793,31 +575,6 @@ public class FullText implements Trigger, CloseListener {
return
result
;
return
result
;
}
}
/**
* Parse a primary key condition into the primary key columns.
*
* @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
*/
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
;
}
private
static
void
addColumnData
(
ArrayList
columns
,
ArrayList
data
,
Expression
expr
)
{
private
static
void
addColumnData
(
ArrayList
columns
,
ArrayList
data
,
Expression
expr
)
{
if
(
expr
instanceof
ConditionAndOr
)
{
if
(
expr
instanceof
ConditionAndOr
)
{
ConditionAndOr
and
=
(
ConditionAndOr
)
expr
;
ConditionAndOr
and
=
(
ConditionAndOr
)
expr
;
...
@@ -839,18 +596,289 @@ public class FullText implements Trigger, CloseListener {
...
@@ -839,18 +596,289 @@ public class FullText implements Trigger, CloseListener {
}
}
}
}
/**
private
static
void
addWords
(
FullTextSettings
setting
,
HashSet
set
,
String
text
)
{
* INTERNAL
StringTokenizer
tokenizer
=
new
StringTokenizer
(
text
,
" \t\n\r\f+\"*%&/()=?'!,.;:-_#@|^~`{}[]"
);
*/
while
(
tokenizer
.
hasMoreTokens
())
{
public
void
close
()
throws
SQLException
{
String
word
=
tokenizer
.
nextToken
();
setting
.
removeIndexInfo
(
index
);
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
())
{
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
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
);
if
(
word
!=
null
)
{
set
.
add
(
list
[
i
]);
}
}
}
}
/**
/**
*
INTERNAL
*
Trigger updates the index when a inserting, updating, or deleting a row.
*/
*/
public
void
remove
()
throws
SQLException
{
public
static
class
FullTextTrigger
implements
Trigger
,
CloseListener
{
setting
.
removeIndexInfo
(
index
);
private
FullTextSettings
setting
;
private
IndexInfo
index
;
private
int
[]
columnTypes
;
private
PreparedStatement
prepInsertWord
,
prepInsertRow
,
prepInsertMap
;
private
PreparedStatement
prepDeleteRow
,
prepDeleteMap
;
private
PreparedStatement
prepSelectRow
;
/**
* INTERNAL
*/
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
setting
=
FullTextSettings
.
getInstance
(
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"
));
}
columnTypes
=
new
int
[
columnList
.
size
()];
index
=
new
IndexInfo
();
index
.
schema
=
schemaName
;
index
.
table
=
tableName
;
index
.
columns
=
new
String
[
columnList
.
size
()];
columnList
.
toArray
(
index
.
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
)
{
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 ID, COLUMNS FROM "
+
SCHEMA
+
".INDEXES WHERE SCHEMA=? AND TABLE=?"
);
prep
.
setString
(
1
,
schemaName
);
prep
.
setString
(
2
,
tableName
);
rs
=
prep
.
executeQuery
();
if
(
rs
.
next
())
{
index
.
id
=
rs
.
getInt
(
1
);
String
columns
=
rs
.
getString
(
2
);
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
);
}
index
.
keys
=
new
int
[
keyList
.
size
()];
setColumns
(
index
.
keys
,
keyList
,
columnList
);
index
.
indexColumns
=
new
int
[
indexList
.
size
()];
setColumns
(
index
.
indexColumns
,
indexList
,
columnList
);
setting
.
addIndexInfo
(
index
);
prepInsertWord
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".WORDS(NAME) VALUES(?)"
);
prepInsertRow
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".ROWS(HASH, INDEXID, KEY) VALUES(?, ?, ?)"
);
prepInsertMap
=
conn
.
prepareStatement
(
"INSERT INTO "
+
SCHEMA
+
".MAP(ROWID, WORDID) VALUES(?, ?)"
);
prepDeleteRow
=
conn
.
prepareStatement
(
"DELETE FROM "
+
SCHEMA
+
".ROWS WHERE HASH=? AND INDEXID=? AND KEY=?"
);
prepDeleteMap
=
conn
.
prepareStatement
(
"DELETE FROM "
+
SCHEMA
+
".MAP WHERE ROWID=? AND WORDID=?"
);
prepSelectRow
=
conn
.
prepareStatement
(
"SELECT ID FROM "
+
SCHEMA
+
".ROWS WHERE HASH=? AND INDEXID=? AND KEY=?"
);
PreparedStatement
prepSelectMapByWordId
=
conn
.
prepareStatement
(
"SELECT ROWID FROM "
+
SCHEMA
+
".MAP WHERE WORDID=?"
);
PreparedStatement
prepSelectRowById
=
conn
.
prepareStatement
(
"SELECT KEY, INDEXID FROM "
+
SCHEMA
+
".ROWS WHERE ID=?"
);
setting
.
setPrepSelectMapByWordId
(
prepSelectMapByWordId
);
setting
.
setPrepSelectRowById
(
prepSelectRowById
);
}
/**
* INTERNAL
*/
public
void
fire
(
Connection
conn
,
Object
[]
oldRow
,
Object
[]
newRow
)
throws
SQLException
{
if
(
oldRow
!=
null
)
{
delete
(
setting
,
oldRow
);
}
if
(
newRow
!=
null
)
{
insert
(
setting
,
newRow
);
}
}
/**
* INTERNAL
*/
public
void
close
()
throws
SQLException
{
setting
.
removeIndexInfo
(
index
);
}
/**
* INTERNAL
*/
public
void
remove
()
throws
SQLException
{
setting
.
removeIndexInfo
(
index
);
}
private
void
insert
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
String
key
=
getKey
(
row
);
int
hash
=
key
.
hashCode
();
prepInsertRow
.
setInt
(
1
,
hash
);
prepInsertRow
.
setInt
(
2
,
index
.
id
);
prepInsertRow
.
setString
(
3
,
key
);
prepInsertRow
.
execute
();
ResultSet
rs
=
JdbcUtils
.
getGeneratedKeys
(
prepInsertRow
);
rs
.
next
();
int
rowId
=
rs
.
getInt
(
1
);
prepInsertMap
.
setInt
(
1
,
rowId
);
int
[]
wordIds
=
getWordIds
(
setting
,
row
);
for
(
int
i
=
0
;
i
<
wordIds
.
length
;
i
++)
{
prepInsertMap
.
setInt
(
2
,
wordIds
[
i
]);
prepInsertMap
.
execute
();
}
}
private
void
delete
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
String
key
=
getKey
(
row
);
int
hash
=
key
.
hashCode
();
prepSelectRow
.
setInt
(
1
,
hash
);
prepSelectRow
.
setInt
(
2
,
index
.
id
);
prepSelectRow
.
setString
(
3
,
key
);
ResultSet
rs
=
prepSelectRow
.
executeQuery
();
if
(
rs
.
next
())
{
int
rowId
=
rs
.
getInt
(
1
);
prepDeleteMap
.
setInt
(
1
,
rowId
);
int
[]
wordIds
=
getWordIds
(
setting
,
row
);
for
(
int
i
=
0
;
i
<
wordIds
.
length
;
i
++)
{
prepDeleteMap
.
setInt
(
2
,
wordIds
[
i
]);
prepDeleteMap
.
executeUpdate
();
}
prepDeleteRow
.
setInt
(
1
,
hash
);
prepDeleteRow
.
setInt
(
2
,
index
.
id
);
prepDeleteRow
.
setString
(
3
,
key
);
prepDeleteRow
.
executeUpdate
();
}
}
private
int
[]
getWordIds
(
FullTextSettings
setting
,
Object
[]
row
)
throws
SQLException
{
HashSet
words
=
new
HashSet
();
for
(
int
i
=
0
;
i
<
index
.
indexColumns
.
length
;
i
++)
{
int
idx
=
index
.
indexColumns
[
i
];
String
data
=
asString
(
row
[
idx
],
columnTypes
[
idx
]);
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
;
}
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
.
columns
[
columnIndex
]));
Object
o
=
row
[
columnIndex
];
if
(
o
==
null
)
{
buff
.
append
(
" IS NULL"
);
}
else
{
buff
.
append
(
"="
);
buff
.
append
(
quoteSQL
(
o
,
columnTypes
[
columnIndex
]));
}
}
String
key
=
buff
.
toString
();
return
key
;
}
}
}
}
}
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,273 +334,188 @@ implements Trigger, CloseListener
...
@@ -334,273 +334,188 @@ 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
while
(
rs
.
next
())
{
//## Java 1.4 begin ##
String
schema
=
rs
.
getString
(
"TRIGGER_SCHEMA"
);
implements
Trigger
,
CloseListener
String
name
=
rs
.
getString
(
"TRIGGER_NAME"
);
//## Java 1.4 end ##
if
(
name
.
startsWith
(
TRIGGER_PREFIX
))
{
{
name
=
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
name
);
stat2
.
execute
(
"DROP TRIGGER "
+
name
);
}
}
}
private
static
void
removeIndexFiles
(
Connection
conn
)
throws
SQLException
{
//## Java 1.4 begin ##
String
path
=
getIndexPath
(
conn
);
private
String
schema
;
IndexModifier
index
=
(
IndexModifier
)
indexers
.
get
(
path
);
private
String
table
;
if
(
index
!=
null
)
{
private
int
[]
keys
;
indexers
.
remove
(
path
);
private
int
[]
indexColumns
;
try
{
private
String
[]
columns
;
index
.
flush
();
private
int
[]
columnTypes
;
index
.
close
();
private
String
indexPath
;
}
catch
(
IOException
e
)
{
private
IndexModifier
indexModifier
;
throw
convertException
(
e
);
//## Java 1.4 end ##
}
}
FileSystem
.
getInstance
(
path
).
deleteRecursive
(
path
);
}
private
String
getQuery
(
Object
[]
row
)
throws
SQLException
{
/**
StringBuffer
buff
=
new
StringBuffer
();
* INTERNAL
if
(
schemaName
!=
null
)
{
*/
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schemaName
));
//## Java 1.4 begin ##
buff
.
append
(
"."
);
public
void
init
(
Connection
conn
,
String
schemaName
,
String
triggerName
,
}
String
tableName
,
boolean
before
,
int
type
)
throws
SQLException
{
buff
.
append
(
StringUtils
.
quoteIdentifier
(
tableName
));
this
.
schema
=
schemaName
;
buff
.
append
(
" WHERE "
);
this
.
table
=
tableName
;
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
this
.
indexPath
=
getIndexPath
(
conn
);
if
(
i
>
0
)
{
this
.
indexModifier
=
getIndexModifier
(
conn
);
buff
.
append
(
" AND "
);
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"
));
}
}
int
columnIndex
=
keys
[
i
];
columnTypes
=
new
int
[
columnList
.
size
()];
buff
.
append
(
StringUtils
.
quoteIdentifier
(
columnNames
[
columnIndex
]));
columns
=
new
String
[
columnList
.
size
()];
Object
o
=
row
[
columnIndex
];
columnList
.
toArray
(
columns
);
if
(
o
==
null
)
{
rs
=
meta
.
getColumns
(
null
,
schemaName
,
tableName
,
null
);
buff
.
append
(
" IS NULL"
);
for
(
int
i
=
0
;
rs
.
next
();
i
++)
{
}
else
{
columnTypes
[
i
]
=
rs
.
getInt
(
"DATA_TYPE"
);
buff
.
append
(
"="
);
buff
.
append
(
quoteSQL
(
o
,
dataTypes
[
columnIndex
]));
}
}
}
if
(
keyList
.
size
()
==
0
)
{
String
key
=
buff
.
toString
();
rs
=
meta
.
getPrimaryKeys
(
null
,
schemaName
,
tableName
);
return
key
;
while
(
rs
.
next
())
{
}
keyList
.
add
(
rs
.
getString
(
"COLUMN_NAME"
));
}
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
);
if
(
keyList
.
size
()
==
0
)
{
}
throw
new
SQLException
(
"No primary key for table "
+
tableName
);
buff
.
append
(
'\''
);
return
buff
.
toString
();
}
private
String
quoteBinary
(
byte
[]
data
)
{
return
"'"
+
ByteUtils
.
convertBytesToString
(
data
)
+
"'"
;
}
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
""
;
}
}
private
void
insert
(
Object
[]
row
)
throws
SQLException
{
String
query
=
getQuery
(
row
);
Document
doc
=
new
Document
();
doc
.
add
(
new
Field
(
FIELD_QUERY
,
query
,
Field
.
Store
.
YES
,
Field
.
Index
.
UN_TOKENIZED
));
long
time
=
System
.
currentTimeMillis
();
doc
.
add
(
new
Field
(
"modified"
,
DateTools
.
timeToString
(
time
,
DateTools
.
Resolution
.
SECOND
),
Field
.
Store
.
YES
,
Field
.
Index
.
UN_TOKENIZED
));
StringBuffer
allData
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
indexColumns
.
length
;
i
++)
{
int
index
=
indexColumns
[
i
];
String
columnName
=
columnNames
[
index
];
String
data
=
asString
(
row
[
index
],
dataTypes
[
index
]);
doc
.
add
(
new
Field
(
FIELD_COLUMN_PREFIX
+
columnName
,
data
,
Field
.
Store
.
NO
,
Field
.
Index
.
TOKENIZED
));
if
(
i
>
0
)
{
allData
.
append
(
" "
);
}
}
allData
.
append
(
data
);
ArrayList
indexList
=
new
ArrayList
();
}
PreparedStatement
prep
=
conn
.
prepareStatement
(
"SELECT COLUMNS FROM "
+
SCHEMA
+
".INDEXES WHERE SCHEMA=? AND TABLE=?"
);
Field
.
Store
storeText
=
STORE_DOCUMENT_TEXT_IN_INDEX
?
Field
.
Store
.
YES
:
Field
.
Store
.
NO
;
prep
.
setString
(
1
,
schemaName
);
doc
.
add
(
new
Field
(
FIELD_DATA
,
allData
.
toString
(),
storeText
,
Field
.
Index
.
TOKENIZED
));
prep
.
setString
(
2
,
tableName
);
try
{
rs
=
prep
.
executeQuery
();
indexer
.
addDocument
(
doc
);
if
(
rs
.
next
())
{
}
catch
(
IOException
e
)
{
String
columns
=
rs
.
getString
(
1
);
throw
convertException
(
e
);
if
(
columns
!=
null
)
{
}
String
[]
list
=
StringUtils
.
arraySplit
(
columns
,
','
,
true
);
}
for
(
int
i
=
0
;
i
<
list
.
length
;
i
++)
{
indexList
.
add
(
list
[
i
]);
private
void
delete
(
Object
[]
row
)
throws
SQLException
{
}
String
query
=
getQuery
(
row
);
}
try
{
}
Term
term
=
new
Term
(
FIELD_QUERY
,
query
);
if
(
indexList
.
size
()
==
0
)
{
indexer
.
deleteDocuments
(
term
);
indexList
.
addAll
(
columnList
);
}
catch
(
IOException
e
)
{
}
throw
convertException
(
e
);
keys
=
new
int
[
keyList
.
size
()];
setColumns
(
keys
,
keyList
,
columnList
);
indexColumns
=
new
int
[
indexList
.
size
()];
setColumns
(
indexColumns
,
indexList
,
columnList
);
}
}
}
//## Java 1.4 end ##
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
();
* INTERNAL
existing
.
init
(
conn
,
schema
,
null
,
table
,
false
,
INSERT
);
*/
StringBuffer
buff
=
new
StringBuffer
(
"SELECT * FROM "
);
//## Java 1.4 begin ##
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
)
+
"."
+
StringUtils
.
quoteIdentifier
(
table
));
public
void
fire
(
Connection
conn
,
Object
[]
oldRow
,
Object
[]
newRow
)
ResultSet
rs
=
conn
.
createStatement
().
executeQuery
(
buff
.
toString
());
throws
SQLException
{
int
columnCount
=
rs
.
getMetaData
().
getColumnCount
();
if
(
oldRow
!=
null
)
{
while
(
rs
.
next
())
{
delete
(
oldRow
);
Object
[]
row
=
new
Object
[
columnCount
];
}
for
(
int
i
=
0
;
i
<
columnCount
;
i
++
)
{
if
(
newRow
!=
null
)
{
row
[
i
]
=
rs
.
getObject
(
i
+
1
);
insert
(
newRow
);
}
}
existing
.
fire
(
conn
,
null
,
row
);
}
}
}
//## Java 1.4 end ##
private
static
IndexModifier
getIndexModifier
(
Connection
conn
)
throws
SQLException
{
/**
String
path
=
getIndexPath
(
conn
);
* INTERNAL
IndexModifier
indexer
;
*/
synchronized
(
indexers
)
{
//## Java 1.4 begin ##
indexer
=
(
IndexModifier
)
indexers
.
get
(
path
);
public
void
close
()
throws
SQLException
{
if
(
index
er
=
=
null
)
{
if
(
index
Modifier
!
=
null
)
{
try
{
try
{
boolean
recreate
=
!
IndexReader
.
indexExists
(
path
);
indexModifier
.
flush
();
Analyzer
analyzer
=
new
StandardAnalyzer
();
indexModifier
.
close
();
indexer
=
new
IndexModifier
(
path
,
analyzer
,
recreate
);
INDEX_MODIFIERS
.
remove
(
indexPath
);
}
catch
(
IOException
e
)
{
indexModifier
=
null
;
}
catch
(
Exception
e
)
{
throw
convertException
(
e
);
throw
convertException
(
e
);
}
}
indexers
.
put
(
path
,
indexer
);
}
}
}
}
return
indexer
;
//## Java 1.4 end ##
}
private
static
String
getIndexPath
(
Connection
conn
)
throws
SQLException
{
/**
Statement
stat
=
conn
.
createStatement
();
* INTERNAL
ResultSet
rs
=
stat
.
executeQuery
(
"CALL DATABASE_PATH()"
);
*/
rs
.
next
();
public
void
remove
()
{
String
path
=
rs
.
getString
(
1
);
// ignore
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
{
private
void
insert
(
Object
[]
row
)
throws
SQLException
{
for
(
int
i
=
0
;
i
<
keys
.
size
();
i
++)
{
String
query
=
getQuery
(
row
);
String
key
=
(
String
)
keys
.
get
(
i
);
Document
doc
=
new
Document
();
int
found
=
-
1
;
doc
.
add
(
new
Field
(
FIELD_QUERY
,
query
,
Field
.
Store
.
YES
,
Field
.
Index
.
UN_TOKENIZED
));
for
(
int
j
=
0
;
found
==
-
1
&&
j
<
columns
.
size
();
j
++)
{
long
time
=
System
.
currentTimeMillis
();
String
column
=
(
String
)
columns
.
get
(
j
);
doc
.
add
(
new
Field
(
"modified"
,
DateTools
.
timeToString
(
time
,
DateTools
.
Resolution
.
SECOND
),
Field
.
Store
.
YES
,
Field
.
Index
.
UN_TOKENIZED
));
if
(
column
.
equals
(
key
))
{
StringBuffer
allData
=
new
StringBuffer
();
found
=
j
;
for
(
int
i
=
0
;
i
<
indexColumns
.
length
;
i
++)
{
int
index
=
indexColumns
[
i
];
String
columnName
=
columns
[
index
];
String
data
=
asString
(
row
[
index
],
columnTypes
[
index
]);
doc
.
add
(
new
Field
(
FIELD_COLUMN_PREFIX
+
columnName
,
data
,
Field
.
Store
.
NO
,
Field
.
Index
.
TOKENIZED
));
if
(
i
>
0
)
{
allData
.
append
(
" "
);
}
}
allData
.
append
(
data
);
}
}
if
(
found
<
0
)
{
Field
.
Store
storeText
=
STORE_DOCUMENT_TEXT_IN_INDEX
?
Field
.
Store
.
YES
:
Field
.
Store
.
NO
;
throw
new
SQLException
(
"FULLTEXT"
,
"Column not found: "
+
key
);
doc
.
add
(
new
Field
(
FIELD_DATA
,
allData
.
toString
(),
storeText
,
Field
.
Index
.
TOKENIZED
));
try
{
indexModifier
.
addDocument
(
doc
);
}
catch
(
IOException
e
)
{
throw
convertException
(
e
);
}
}
index
[
i
]
=
found
;
}
}
}
//## Java 1.4 end ##
/**
private
void
delete
(
Object
[]
row
)
throws
SQLException
{
* INTERNAL
String
query
=
getQuery
(
row
);
*/
try
{
//## Java 1.4 begin ##
Term
term
=
new
Term
(
FIELD_QUERY
,
query
);
public
void
close
()
throws
SQLException
{
indexModifier
.
deleteDocuments
(
term
);
try
{
}
catch
(
IOException
e
)
{
if
(
indexer
!=
null
)
{
throw
convertException
(
e
);
indexer
.
flush
();
indexer
.
close
();
indexers
.
remove
(
indexPath
);
indexer
=
null
;
}
}
}
catch
(
Exception
e
)
{
throw
convertException
(
e
);
}
}
}
//## Java 1.4 end ##
/**
private
String
getQuery
(
Object
[]
row
)
throws
SQLException
{
* INTERNAL
StringBuffer
buff
=
new
StringBuffer
();
*/
if
(
schema
!=
null
)
{
//## Java 1.4 begin ##
buff
.
append
(
StringUtils
.
quoteIdentifier
(
schema
));
public
void
remove
()
throws
SQLException
{
buff
.
append
(
"."
);
// ignore
}
buff
.
append
(
StringUtils
.
quoteIdentifier
(
table
));
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
(
columns
[
columnIndex
]));
Object
o
=
row
[
columnIndex
];
if
(
o
==
null
)
{
buff
.
append
(
" IS NULL"
);
}
else
{
buff
.
append
(
"="
);
buff
.
append
(
FullText
.
quoteSQL
(
o
,
columnTypes
[
columnIndex
]));
}
}
String
key
=
buff
.
toString
();
return
key
;
}
}
}
//## 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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论