Kouhei Sutou
null+****@clear*****
Wed Oct 28 21:03:37 JST 2015
Kouhei Sutou 2015-10-28 21:03:37 +0900 (Wed, 28 Oct 2015) New Revision: e089ebe7f77e865026a172b42acf657c992bfaa9 https://github.com/pgroonga/pgroonga/commit/e089ebe7f77e865026a172b42acf657c992bfaa9 Message: Support sequential scan against @@ Added files: expected/array/text/single/query/bitmapscan.out expected/array/text/single/query/indexscan.out expected/array/text/single/query/seqscan.out sql/array/text/single/query/bitmapscan.sql sql/array/text/single/query/indexscan.sql sql/array/text/single/query/seqscan.sql Modified files: expected/full-text-search/text/single/match/seqscan.out pgroonga.c pgroonga.h pgroonga.sql sql/full-text-search/text/single/match/seqscan.sql Added: expected/array/text/single/query/bitmapscan.out (+29 -0) 100644 =================================================================== --- /dev/null +++ expected/array/text/single/query/bitmapscan.out 2015-10-28 21:03:37 +0900 (f7353bf) @@ -0,0 +1,29 @@ +CREATE TABLE memos ( + title text, + contents text[] +); +INSERT INTO memos + VALUES ('PostgreSQL', + ARRAY['PostgreSQL is an OSS RDBMS', + 'PostgreSQL has partial full-text search support']); +INSERT INTO memos + VALUES ('Groonga', ARRAY['Groonga is an OSS full-text search engine', + 'Groonga has full full-text search support']); +INSERT INTO memos + VALUES ('PGroonga', + ARRAY['PGroonga is an OSS PostgreSQL extension', + 'PGroonga adds full full-text search support based on Groonga to PostgreSQL']); +CREATE INDEX pgroonga_memos_index ON memos USING pgroonga (contents); +SET enable_seqscan = off; +SET enable_indexscan = off; +SET enable_bitmapscan = on; +SELECT title, contents + FROM memos + WHERE contents @@ 'rdbms OR engine'; + title | contents +------------+------------------------------------------------------------------------------------------- + PostgreSQL | {"PostgreSQL is an OSS RDBMS","PostgreSQL has partial full-text search support"} + Groonga | {"Groonga is an OSS full-text search engine","Groonga has full full-text search support"} +(2 rows) + +DROP TABLE memos; Added: expected/array/text/single/query/indexscan.out (+29 -0) 100644 =================================================================== --- /dev/null +++ expected/array/text/single/query/indexscan.out 2015-10-28 21:03:37 +0900 (ab54ab7) @@ -0,0 +1,29 @@ +CREATE TABLE memos ( + title text, + contents text[] +); +INSERT INTO memos + VALUES ('PostgreSQL', + ARRAY['PostgreSQL is an OSS RDBMS', + 'PostgreSQL has partial full-text search support']); +INSERT INTO memos + VALUES ('Groonga', ARRAY['Groonga is an OSS full-text search engine', + 'Groonga has full full-text search support']); +INSERT INTO memos + VALUES ('PGroonga', + ARRAY['PGroonga is an OSS PostgreSQL extension', + 'PGroonga adds full full-text search support based on Groonga to PostgreSQL']); +CREATE INDEX pgroonga_memos_index ON memos USING pgroonga (contents); +SET enable_seqscan = off; +SET enable_indexscan = on; +SET enable_bitmapscan = off; +SELECT title, contents + FROM memos + WHERE contents @@ 'rdbms OR engine'; + title | contents +------------+------------------------------------------------------------------------------------------- + PostgreSQL | {"PostgreSQL is an OSS RDBMS","PostgreSQL has partial full-text search support"} + Groonga | {"Groonga is an OSS full-text search engine","Groonga has full full-text search support"} +(2 rows) + +DROP TABLE memos; Added: expected/array/text/single/query/seqscan.out (+29 -0) 100644 =================================================================== --- /dev/null +++ expected/array/text/single/query/seqscan.out 2015-10-28 21:03:37 +0900 (dcab8f5) @@ -0,0 +1,29 @@ +CREATE TABLE memos ( + title text, + contents text[] +); +INSERT INTO memos + VALUES ('PostgreSQL', + ARRAY['PostgreSQL is an OSS RDBMS', + 'PostgreSQL has partial full-text search support']); +INSERT INTO memos + VALUES ('Groonga', ARRAY['Groonga is an OSS full-text search engine', + 'Groonga has full full-text search support']); +INSERT INTO memos + VALUES ('PGroonga', + ARRAY['PGroonga is an OSS PostgreSQL extension', + 'PGroonga adds full full-text search support based on Groonga to PostgreSQL']); +CREATE INDEX pgroonga_memos_index ON memos USING pgroonga (contents); +SET enable_seqscan = on; +SET enable_indexscan = off; +SET enable_bitmapscan = off; +SELECT title, contents + FROM memos + WHERE contents @@ 'rdbms OR engine'; + title | contents +------------+------------------------------------------------------------------------------------------- + PostgreSQL | {"PostgreSQL is an OSS RDBMS","PostgreSQL has partial full-text search support"} + Groonga | {"Groonga is an OSS full-text search engine","Groonga has full full-text search support"} +(2 rows) + +DROP TABLE memos; Modified: expected/full-text-search/text/single/match/seqscan.out (+1 -0) =================================================================== --- expected/full-text-search/text/single/match/seqscan.out 2015-10-25 22:52:27 +0900 (7a10793) +++ expected/full-text-search/text/single/match/seqscan.out 2015-10-28 21:03:37 +0900 (c8f22b2) @@ -1,3 +1,4 @@ +SET search_path = "$user",public,pgroonga,pg_catalog; CREATE TABLE memos ( id integer, content text Modified: pgroonga.c (+168 -10) =================================================================== --- pgroonga.c 2015-10-25 22:52:27 +0900 (66c39b1) +++ pgroonga.c 2015-10-28 21:03:37 +0900 (dd3eba0) @@ -32,6 +32,7 @@ #include <xxhash.h> #include <stdlib.h> +#include <string.h> #include <math.h> #include <sys/types.h> #include <sys/stat.h> @@ -163,6 +164,13 @@ typedef struct PGrnSearchData bool isEmptyCondition; } PGrnSearchData; +typedef struct PGrnSequentialSearchData +{ + grn_obj *table; + grn_obj *textColumn; + grn_id recordID; +} PGrnSequentialSearchData; + static slist_head PGrnScanOpaques = SLIST_STATIC_INIT(PGrnScanOpaques); PG_FUNCTION_INFO_V1(pgroonga_score); @@ -174,7 +182,9 @@ PG_FUNCTION_INFO_V1(pgroonga_contain_text); PG_FUNCTION_INFO_V1(pgroonga_contain_text_array); PG_FUNCTION_INFO_V1(pgroonga_contain_varchar); PG_FUNCTION_INFO_V1(pgroonga_contain_varchar_array); -PG_FUNCTION_INFO_V1(pgroonga_match); +PG_FUNCTION_INFO_V1(pgroonga_match_text); +PG_FUNCTION_INFO_V1(pgroonga_match_text_array); +PG_FUNCTION_INFO_V1(pgroonga_match_varchar); PG_FUNCTION_INFO_V1(pgroonga_match_regexp_text); PG_FUNCTION_INFO_V1(pgroonga_match_regexp_varchar); @@ -203,6 +213,7 @@ static grn_obj headBuffer; static grn_obj bodyBuffer; static grn_obj footBuffer; static grn_obj inspectBuffer; +static PGrnSequentialSearchData sequentialSearchData; static const char * PGrnInspect(grn_obj *object) @@ -416,12 +427,21 @@ PGrnEnsureDatabase(void) } static void +PGrnFinalizeSequentialSearchData(void) +{ + grn_obj_close(ctx, sequentialSearchData.textColumn); + grn_obj_close(ctx, sequentialSearchData.table); +} + +static void PGrnOnProcExit(int code, Datum arg) { if (ctx) { grn_obj *db; + PGrnFinalizeSequentialSearchData(); + GRN_OBJ_FIN(ctx, &inspectBuffer); GRN_OBJ_FIN(ctx, &footBuffer); GRN_OBJ_FIN(ctx, &bodyBuffer); @@ -550,6 +570,28 @@ PGrnInitializeOptions(void) PGrnOptionValidateNormalizer); } +static void +PGrnInitializeSequentialSearchData(void) +{ + sequentialSearchData.table = grn_table_create(ctx, + NULL, 0, + NULL, + GRN_OBJ_TABLE_NO_KEY, + NULL, NULL); + sequentialSearchData.textColumn = + grn_column_create(ctx, + sequentialSearchData.table, + "text", strlen("text"), + NULL, + GRN_OBJ_COLUMN_SCALAR, + grn_ctx_at(ctx, GRN_DB_TEXT)); + sequentialSearchData.recordID = + grn_table_add(ctx, + sequentialSearchData.table, + NULL, 0, + NULL); +} + void _PG_init(void) { @@ -591,6 +633,8 @@ _PG_init(void) PGrnInitializeGroongaInformation(); PGrnInitializeOptions(); + + PGrnInitializeSequentialSearchData(); } static int @@ -2261,22 +2305,136 @@ pgroonga_contain_varchar_array(PG_FUNCTION_ARGS) PG_RETURN_BOOL(contained); } +static grn_bool +pgroonga_match_text_raw(const char *target, unsigned int targetSize, + const char *query, unsigned int querySize) +{ + grn_obj *expression; + grn_obj *variable; + grn_expr_flags flags = + GRN_EXPR_SYNTAX_QUERY | GRN_EXPR_ALLOW_LEADING_NOT; + grn_rc rc; + grn_obj *result; + bool matched = false; + + GRN_EXPR_CREATE_FOR_QUERY(ctx, + sequentialSearchData.table, + expression, + variable); + if (!expression) + { + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("pgroonga: failed to create expression: %s", + ctx->errbuf))); + } + + rc = grn_expr_parse(ctx, + expression, + query, querySize, + sequentialSearchData.textColumn, + GRN_OP_MATCH, GRN_OP_AND, + flags); + if (rc != GRN_SUCCESS) + { + char message[GRN_CTX_MSGSIZE]; + grn_strncpy(message, GRN_CTX_MSGSIZE, + ctx->errbuf, GRN_CTX_MSGSIZE); + + grn_obj_close(ctx, expression); + ereport(ERROR, + (errcode(PGrnRCToPgErrorCode(rc)), + errmsg("pgroonga: failed to parse expression: %s", + message))); + } + + grn_obj_reinit(ctx, &buffer, GRN_DB_TEXT, 0); + GRN_TEXT_SET(ctx, &buffer, target, targetSize); + grn_obj_set_value(ctx, + sequentialSearchData.textColumn, + sequentialSearchData.recordID, + &buffer, + GRN_OBJ_SET); + GRN_RECORD_SET(ctx, variable, sequentialSearchData.recordID); + + result = grn_expr_exec(ctx, expression, 0); + GRN_OBJ_IS_TRUE(ctx, result, matched); + + grn_obj_close(ctx, expression); + + return matched; +} + /** - * pgroonga.match(text, query) : bool + * pgroonga.match_text(target text, query text) : bool */ Datum -pgroonga_match(PG_FUNCTION_ARGS) +pgroonga_match_text(PG_FUNCTION_ARGS) { -#ifdef NOT_USED - text *text = PG_GETARG_TEXT_PP(0); + text *target = PG_GETARG_TEXT_PP(0); text *query = PG_GETARG_TEXT_PP(1); -#endif + bool matched = false; - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("pgroonga: operator @@ is available only in index scans"))); + matched = pgroonga_match_text_raw(VARDATA_ANY(target), + VARSIZE_ANY_EXHDR(target), + VARDATA_ANY(query), + VARSIZE_ANY_EXHDR(query)); - PG_RETURN_BOOL(false); + PG_RETURN_BOOL(matched); +} + +/** + * pgroonga.match_text(targets text[], query text) : bool + */ +Datum +pgroonga_match_text_array(PG_FUNCTION_ARGS) +{ + ArrayType *targets = PG_GETARG_ARRAYTYPE_P(0); + text *query = PG_GETARG_TEXT_PP(1); + bool matched = false; + int i, n; + + n = ARR_DIMS(targets)[0]; + for (i = 1; i <= n; i++) + { + Datum targetDatum; + text *target; + bool isNULL; + + targetDatum = array_ref(targets, 1, &i, -1, -1, false, 'i', &isNULL); + if (isNULL) + continue; + + target = DatumGetTextPP(targetDatum); + matched = pgroonga_match_text_raw(VARDATA_ANY(target), + VARSIZE_ANY_EXHDR(target), + VARDATA_ANY(query), + VARSIZE_ANY_EXHDR(query)); + if (matched) + { + break; + } + } + + PG_RETURN_BOOL(matched); +} + +/** + * pgroonga.match_varchar(target varchar, query varchar) : bool + */ +Datum +pgroonga_match_varchar(PG_FUNCTION_ARGS) +{ + VarChar *target = PG_GETARG_VARCHAR_PP(0); + VarChar *query = PG_GETARG_VARCHAR_PP(1); + bool matched = false; + + matched = pgroonga_match_text_raw(VARDATA_ANY(target), + VARSIZE_ANY_EXHDR(target), + VARDATA_ANY(query), + VARSIZE_ANY_EXHDR(query)); + + PG_RETURN_BOOL(matched); } /** Modified: pgroonga.h (+3 -1) =================================================================== --- pgroonga.h 2015-10-25 22:52:27 +0900 (469c2ae) +++ pgroonga.h 2015-10-28 21:03:37 +0900 (ca694b7) @@ -52,7 +52,9 @@ extern Datum PGDLLEXPORT pgroonga_contain_text(PG_FUNCTION_ARGS); extern Datum PGDLLEXPORT pgroonga_contain_text_array(PG_FUNCTION_ARGS); extern Datum PGDLLEXPORT pgroonga_contain_varchar(PG_FUNCTION_ARGS); extern Datum PGDLLEXPORT pgroonga_contain_varchar_array(PG_FUNCTION_ARGS); -extern Datum PGDLLEXPORT pgroonga_match(PG_FUNCTION_ARGS); +extern Datum PGDLLEXPORT pgroonga_match_text(PG_FUNCTION_ARGS); +extern Datum PGDLLEXPORT pgroonga_match_text_array(PG_FUNCTION_ARGS); +extern Datum PGDLLEXPORT pgroonga_match_varchar(PG_FUNCTION_ARGS); extern Datum PGDLLEXPORT pgroonga_match_jsonb(PG_FUNCTION_ARGS); extern Datum PGDLLEXPORT pgroonga_insert(PG_FUNCTION_ARGS); Modified: pgroonga.sql (+3 -3) =================================================================== --- pgroonga.sql 2015-10-25 22:52:27 +0900 (f4898c9) +++ pgroonga.sql 2015-10-28 21:03:37 +0900 (6b47394) @@ -85,21 +85,21 @@ CREATE OPERATOR %% ( CREATE FUNCTION pgroonga.match(text, text) RETURNS bool - AS 'MODULE_PATHNAME', 'pgroonga_match' + AS 'MODULE_PATHNAME', 'pgroonga_match_text' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION pgroonga.match(text[], text) RETURNS bool - AS 'MODULE_PATHNAME', 'pgroonga_match' + AS 'MODULE_PATHNAME', 'pgroonga_match_text_array' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION pgroonga.match(varchar, varchar) RETURNS bool - AS 'MODULE_PATHNAME', 'pgroonga_match' + AS 'MODULE_PATHNAME', 'pgroonga_match_varchar' LANGUAGE C IMMUTABLE STRICT; Added: sql/array/text/single/query/bitmapscan.sql (+28 -0) 100644 =================================================================== --- /dev/null +++ sql/array/text/single/query/bitmapscan.sql 2015-10-28 21:03:37 +0900 (864d135) @@ -0,0 +1,28 @@ +CREATE TABLE memos ( + title text, + contents text[] +); + +INSERT INTO memos + VALUES ('PostgreSQL', + ARRAY['PostgreSQL is an OSS RDBMS', + 'PostgreSQL has partial full-text search support']); +INSERT INTO memos + VALUES ('Groonga', ARRAY['Groonga is an OSS full-text search engine', + 'Groonga has full full-text search support']); +INSERT INTO memos + VALUES ('PGroonga', + ARRAY['PGroonga is an OSS PostgreSQL extension', + 'PGroonga adds full full-text search support based on Groonga to PostgreSQL']); + +CREATE INDEX pgroonga_memos_index ON memos USING pgroonga (contents); + +SET enable_seqscan = off; +SET enable_indexscan = off; +SET enable_bitmapscan = on; + +SELECT title, contents + FROM memos + WHERE contents @@ 'rdbms OR engine'; + +DROP TABLE memos; Added: sql/array/text/single/query/indexscan.sql (+28 -0) 100644 =================================================================== --- /dev/null +++ sql/array/text/single/query/indexscan.sql 2015-10-28 21:03:37 +0900 (2fcbd11) @@ -0,0 +1,28 @@ +CREATE TABLE memos ( + title text, + contents text[] +); + +INSERT INTO memos + VALUES ('PostgreSQL', + ARRAY['PostgreSQL is an OSS RDBMS', + 'PostgreSQL has partial full-text search support']); +INSERT INTO memos + VALUES ('Groonga', ARRAY['Groonga is an OSS full-text search engine', + 'Groonga has full full-text search support']); +INSERT INTO memos + VALUES ('PGroonga', + ARRAY['PGroonga is an OSS PostgreSQL extension', + 'PGroonga adds full full-text search support based on Groonga to PostgreSQL']); + +CREATE INDEX pgroonga_memos_index ON memos USING pgroonga (contents); + +SET enable_seqscan = off; +SET enable_indexscan = on; +SET enable_bitmapscan = off; + +SELECT title, contents + FROM memos + WHERE contents @@ 'rdbms OR engine'; + +DROP TABLE memos; Added: sql/array/text/single/query/seqscan.sql (+28 -0) 100644 =================================================================== --- /dev/null +++ sql/array/text/single/query/seqscan.sql 2015-10-28 21:03:37 +0900 (bbc0ab6) @@ -0,0 +1,28 @@ +CREATE TABLE memos ( + title text, + contents text[] +); + +INSERT INTO memos + VALUES ('PostgreSQL', + ARRAY['PostgreSQL is an OSS RDBMS', + 'PostgreSQL has partial full-text search support']); +INSERT INTO memos + VALUES ('Groonga', ARRAY['Groonga is an OSS full-text search engine', + 'Groonga has full full-text search support']); +INSERT INTO memos + VALUES ('PGroonga', + ARRAY['PGroonga is an OSS PostgreSQL extension', + 'PGroonga adds full full-text search support based on Groonga to PostgreSQL']); + +CREATE INDEX pgroonga_memos_index ON memos USING pgroonga (contents); + +SET enable_seqscan = on; +SET enable_indexscan = off; +SET enable_bitmapscan = off; + +SELECT title, contents + FROM memos + WHERE contents @@ 'rdbms OR engine'; + +DROP TABLE memos; Modified: sql/full-text-search/text/single/match/seqscan.sql (+2 -0) =================================================================== --- sql/full-text-search/text/single/match/seqscan.sql 2015-10-25 22:52:27 +0900 (222f87a) +++ sql/full-text-search/text/single/match/seqscan.sql 2015-10-28 21:03:37 +0900 (3346413) @@ -1,3 +1,5 @@ +SET search_path = "$user",public,pgroonga,pg_catalog; + CREATE TABLE memos ( id integer, content text -------------- next part -------------- HTML����������������������������...Download