Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
edce6934
提交
edce6934
authored
16 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fulltext search refactoring
上级
a35fdf7d
master
noel-pr1
plus33-master
pr/267
stumc-Issue#576
version-1.1.x
version-1.4.198
version-1.4.197
version-1.4.196
version-1.4.195
version-1.4.194
version-1.4.193
version-1.4.192
version-1.4.191
version-1.4.190
version-1.4.188
version-1.4.187
version-1.4.186
version-1.4.185
version-1.4.184
version-1.4.183
version-1.4.182
version-1.4.181
version-1.4.178
version-1.4.177
version-1.3
version-1.2
version-1.1
version-1.0
无相关合并请求
隐藏空白字符变更
内嵌
并排
正在显示
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
;
}
}
}
}
}
This diff is collapsed.
Click to expand it.
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 ##
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
...
...
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论