[Groonga-commit] pgroonga/pgroonga at f7a0868 [master] Support ORDER BY LIMIT

Back to archive index

Kouhei Sutou null+****@clear*****
Fri Feb 6 00:17:31 JST 2015


Kouhei Sutou	2015-02-06 00:17:31 +0900 (Fri, 06 Feb 2015)

  New Revision: f7a0868a3bbc05ffc857ef84f5552e3b23272f5d
  https://github.com/pgroonga/pgroonga/commit/f7a0868a3bbc05ffc857ef84f5552e3b23272f5d

  Message:
    Support ORDER BY LIMIT

  Added files:
    expected/compare/integer/order_by_limit/asc.out
    sql/compare/integer/order_by_limit/asc.sql
  Modified files:
    Makefile
    pgroonga.c
    test.sql

  Modified: Makefile (+3 -0)
===================================================================
--- Makefile    2015-02-06 00:06:30 +0900 (8e1fbe2)
+++ Makefile    2015-02-06 00:17:31 +0900 (9159528)
@@ -33,6 +33,7 @@ installcheck: results/full-text-search/text/options/tokenizer
 installcheck: results/full-text-search/text/options/normalizer
 installcheck: results/compare/text/single/equal
 installcheck: results/compare/integer/single/less-than-equal
+installcheck: results/compare/integer/order_by_limit
 
 results/full-text-search/text/single/contain:
 	@mkdir -p $@
@@ -50,3 +51,5 @@ results/compare/text/single/equal:
 	@mkdir -p $@
 results/compare/integer/single/less-than-equal:
 	@mkdir -p $@
+results/compare/integer/order_by_limit:
+	@mkdir -p $@

  Added: expected/compare/integer/order_by_limit/asc.out (+30 -0) 100644
===================================================================
--- /dev/null
+++ expected/compare/integer/order_by_limit/asc.out    2015-02-06 00:17:31 +0900 (3e51cc0)
@@ -0,0 +1,30 @@
+CREATE TABLE ids (
+  id integer
+);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (10);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (9);
+CREATE INDEX grnindex ON ids USING pgroonga (id);
+SET enable_seqscan = off;
+SET enable_indexscan = on;
+SELECT id
+  FROM ids
+  ORDER BY id ASC
+  LIMIT 5;
+ id 
+----
+  1
+  2
+  3
+  4
+  5
+(5 rows)
+
+DROP TABLE ids;

  Modified: pgroonga.c (+177 -30)
===================================================================
--- pgroonga.c    2015-02-06 00:06:30 +0900 (3eee473)
+++ pgroonga.c    2015-02-06 00:17:31 +0900 (fb3a7db)
@@ -44,10 +44,13 @@ typedef PGrnBuildStateData *PGrnBuildState;
 typedef struct PGrnScanOpaqueData
 {
 	grn_obj *idsTable;
+	grn_obj *lexicon;
+	grn_obj *indexColumn;
 	grn_obj *searched;
 	grn_obj *sorted;
 	grn_obj *targetTable;
-	grn_table_cursor *cursor;
+	grn_obj *indexCursor;
+	grn_table_cursor *tableCursor;
 	grn_obj *keyAccessor;
 	grn_id currentID;
 } PGrnScanOpaqueData;
@@ -424,6 +427,17 @@ PGrnCreateColumn(grn_obj	*table,
 	return column;
 }
 
+static bool
+PGrnIsForFullTextSearchIndex(Relation index)
+{
+	Oid containStrategyOID;
+	containStrategyOID = get_opfamily_member(index->rd_opfamily[0],
+											 index->rd_opcintype[0],
+											 index->rd_opcintype[0],
+											 PGrnContainStrategyNumber);
+	return (containStrategyOID != InvalidOid);
+}
+
 /**
  * PGrnCreate
  *
@@ -486,14 +500,7 @@ PGrnCreate(Relation index, grn_obj **idsTable,
 						 grn_ctx_at(ctx, attributeTypeID));
 	}
 
-	{
-		Oid containStrategyOID;
-		containStrategyOID = get_opfamily_member(index->rd_opfamily[0],
-												 index->rd_opcintype[0],
-												 index->rd_opcintype[0],
-												 PGrnContainStrategyNumber);
-		forFullTextSearch = (containStrategyOID != InvalidOid);
-	}
+	forFullTextSearch = PGrnIsForFullTextSearchIndex(index);
 
 	switch (typeID)
 	{
@@ -734,10 +741,13 @@ static void
 PGrnScanOpaqueInit(PGrnScanOpaque so, Relation index)
 {
 	so->idsTable = PGrnLookupIDsTable(index, ERROR);
+	so->indexColumn = PGrnLookupIndexColumn(index, ERROR);
+	so->lexicon = grn_column_table(ctx, so->indexColumn);
 	so->searched = NULL;
 	so->sorted = NULL;
 	so->targetTable = NULL;
-	so->cursor = NULL;
+	so->indexCursor = NULL;
+	so->tableCursor = NULL;
 	so->keyAccessor = NULL;
 	so->currentID = GRN_ID_NIL;
 }
@@ -751,10 +761,15 @@ PGrnScanOpaqueReinit(PGrnScanOpaque so)
 		grn_obj_unlink(ctx, so->keyAccessor);
 		so->keyAccessor = NULL;
 	}
-	if (so->cursor)
+	if (so->indexCursor)
 	{
-		grn_table_cursor_close(ctx, so->cursor);
-		so->cursor = NULL;
+		grn_obj_close(ctx, so->indexCursor);
+		so->indexCursor = NULL;
+	}
+	if (so->tableCursor)
+	{
+		grn_table_cursor_close(ctx, so->tableCursor);
+		so->tableCursor = NULL;
 	}
 	if (so->sorted)
 	{
@@ -958,7 +973,7 @@ PGrnSort(IndexScanDesc scan)
 }
 
 static void
-PGrnOpenCursor(IndexScanDesc scan, ScanDirection dir)
+PGrnOpenTableCursor(IndexScanDesc scan, ScanDirection dir)
 {
 	PGrnScanOpaque so = (PGrnScanOpaque) scan->opaque;
 	grn_obj *table;
@@ -977,25 +992,125 @@ PGrnOpenCursor(IndexScanDesc scan, ScanDirection dir)
 	else
 		flags |= GRN_CURSOR_ASCENDING;
 
-	so->cursor = grn_table_cursor_open(ctx, table,
-									   NULL, 0, NULL, 0,
-									   offset, limit, flags);
+	so->tableCursor = grn_table_cursor_open(ctx, table,
+											NULL, 0, NULL, 0,
+											offset, limit, flags);
 	so->keyAccessor = grn_obj_column(ctx, table,
 									 GRN_COLUMN_NAME_KEY,
 									 GRN_COLUMN_NAME_KEY_LEN);
 }
 
 static void
+PGrnFillBorder(IndexScanDesc scan,
+			   void **min, unsigned int *minSize,
+			   void **max, unsigned int *maxSize,
+			   int *flags)
+{
+	Relation index = scan->indexRelation;
+	int i;
+
+	for (i = 0; i < scan->numberOfKeys; i++)
+	{
+		ScanKey key = &(scan->keyData[i]);
+
+		/* TODO: Use buffer for min and max */
+		grn_obj_reinit(ctx, &buffer, PGrnGetType(index, key->sk_attno - 1), 0);
+		PGrnGetValue(index, key->sk_attno - 1, &buffer, key->sk_argument);
+
+		switch (key->sk_strategy)
+		{
+		case PGrnLessStrategyNumber:
+			*max = GRN_BULK_HEAD(&buffer);
+			*maxSize = GRN_BULK_VSIZE(&buffer);
+			*flags |= GRN_CURSOR_LT;
+			break;
+		case PGrnLessEqualStrategyNumber:
+			*max = GRN_BULK_HEAD(&buffer);
+			*maxSize = GRN_BULK_VSIZE(&buffer);
+			*flags |= GRN_CURSOR_LE;
+			break;
+		case PGrnEqualStrategyNumber:
+			*min = GRN_BULK_HEAD(&buffer);
+			*minSize = GRN_BULK_VSIZE(&buffer);
+			*max = GRN_BULK_HEAD(&buffer);
+			*maxSize = GRN_BULK_VSIZE(&buffer);
+			*flags |= GRN_CURSOR_LE | GRN_CURSOR_GE;
+			break;
+		case PGrnGreaterEqualStrategyNumber:
+			*min = GRN_BULK_HEAD(&buffer);
+			*minSize = GRN_BULK_VSIZE(&buffer);
+			*flags |= GRN_CURSOR_GE;
+			break;
+		case PGrnGreaterStrategyNumber:
+			*min = GRN_BULK_HEAD(&buffer);
+			*minSize = GRN_BULK_VSIZE(&buffer);
+			*flags |= GRN_CURSOR_GT;
+			break;
+		case PGrnNotEqualStrategyNumber:
+			/* TODO */
+			break;
+		}
+	}
+}
+
+static void
+PGrnOpenIndexCursor(IndexScanDesc scan, ScanDirection dir)
+{
+	PGrnScanOpaque so = (PGrnScanOpaque) scan->opaque;
+	void *min = NULL;
+	unsigned int minSize = 0;
+	void *max = NULL;
+	unsigned int maxSize = 0;
+	int offset = 0;
+	int limit = -1;
+	int flags = 0;
+	grn_id indexCursorMin = GRN_ID_NIL;
+	grn_id indexCursorMax = GRN_ID_MAX;
+	int indexCursorFlags = 0;
+
+	PGrnFillBorder(scan, &min, &minSize, &max, &maxSize, &flags);
+
+	if (dir == BackwardScanDirection)
+		flags |= GRN_CURSOR_DESCENDING;
+	else
+		flags |= GRN_CURSOR_ASCENDING;
+
+	so->tableCursor = grn_table_cursor_open(ctx, so->lexicon,
+											min, minSize,
+											max, maxSize,
+											offset, limit, flags);
+	so->indexCursor = grn_index_cursor_open(ctx,
+											so->tableCursor, so->indexColumn,
+											indexCursorMin,
+											indexCursorMax,
+											indexCursorFlags);
+	so->keyAccessor = grn_obj_column(ctx, so->idsTable,
+									 GRN_COLUMN_NAME_KEY,
+									 GRN_COLUMN_NAME_KEY_LEN);
+}
+
+static void
 PGrnEnsureCursorOpened(IndexScanDesc scan, ScanDirection dir)
 {
 	PGrnScanOpaque so = (PGrnScanOpaque) scan->opaque;
+	bool forFullTextSearch = false;
 
-	if (so->cursor)
+	if (so->indexCursor)
+		return;
+	if (so->tableCursor)
 		return;
 
-	PGrnSearch(scan);
-	PGrnSort(scan);
-	PGrnOpenCursor(scan, dir);
+	forFullTextSearch = PGrnIsForFullTextSearchIndex(scan->indexRelation);
+	if (forFullTextSearch)
+	{
+		PGrnSearch(scan);
+		PGrnSort(scan);
+		PGrnOpenTableCursor(scan, dir);
+	}
+	else
+	{
+		PGrnOpenIndexCursor(scan, dir);
+	}
 }
 
 
@@ -1023,7 +1138,21 @@ pgroonga_gettuple(PG_FUNCTION_ARGS)
 		GRN_OBJ_FIN(ctx, &key);
 	}
 
-	so->currentID = grn_table_cursor_next(ctx, so->cursor);
+	if (so->indexCursor)
+	{
+		grn_posting *posting;
+		grn_id termID;
+		grn_id id = GRN_ID_NIL;
+		posting = grn_index_cursor_next(ctx, so->indexCursor, &termID);
+		if (posting)
+			id = posting->rid;
+		so->currentID = id;
+	}
+	else
+	{
+		so->currentID = grn_table_cursor_next(ctx, so->tableCursor);
+	}
+
 	if (so->currentID == GRN_ID_NIL)
 	{
 		PG_RETURN_BOOL(false);
@@ -1052,19 +1181,37 @@ pgroonga_getbitmap(PG_FUNCTION_ARGS)
 	TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
 	PGrnScanOpaque so = (PGrnScanOpaque) scan->opaque;
 	int64 nRecords = 0;
-	grn_id id;
 	grn_obj key;
 
 	PGrnEnsureCursorOpened(scan, ForwardScanDirection);
 
 	GRN_UINT64_INIT(&key, 0);
-	while ((id = grn_table_cursor_next(ctx, so->cursor)) != GRN_ID_NIL) {
-		ItemPointerData ctid;
-		GRN_BULK_REWIND(&key);
-		grn_obj_get_value(ctx, so->keyAccessor, id, &key);
-		ctid = UInt64ToCtid(GRN_UINT64_VALUE(&key));
-		tbm_add_tuples(tbm, &ctid, 1, false);
-		nRecords++;
+	if (so->indexCursor)
+	{
+		grn_posting *posting;
+		grn_id termID;
+		while ((posting = grn_index_cursor_next(ctx, so->indexCursor, &termID)))
+		{
+			ItemPointerData ctid;
+			GRN_BULK_REWIND(&key);
+			grn_obj_get_value(ctx, so->keyAccessor, posting->rid, &key);
+			ctid = UInt64ToCtid(GRN_UINT64_VALUE(&key));
+			tbm_add_tuples(tbm, &ctid, 1, false);
+			nRecords++;
+		}
+	}
+	else
+	{
+		grn_id id;
+		while ((id = grn_table_cursor_next(ctx, so->tableCursor)) != GRN_ID_NIL)
+		{
+			ItemPointerData ctid;
+			GRN_BULK_REWIND(&key);
+			grn_obj_get_value(ctx, so->keyAccessor, id, &key);
+			ctid = UInt64ToCtid(GRN_UINT64_VALUE(&key));
+			tbm_add_tuples(tbm, &ctid, 1, false);
+			nRecords++;
+		}
 	}
 	GRN_OBJ_FIN(ctx, &key);
 

  Added: sql/compare/integer/order_by_limit/asc.sql (+26 -0) 100644
===================================================================
--- /dev/null
+++ sql/compare/integer/order_by_limit/asc.sql    2015-02-06 00:17:31 +0900 (71954e6)
@@ -0,0 +1,26 @@
+CREATE TABLE ids (
+  id integer
+);
+
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (10);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (9);
+
+CREATE INDEX grnindex ON ids USING pgroonga (id);
+
+SET enable_seqscan = off;
+SET enable_indexscan = on;
+
+SELECT id
+  FROM ids
+  ORDER BY id ASC
+  LIMIT 5;
+
+DROP TABLE ids;

  Modified: test.sql (+4 -4)
===================================================================
--- test.sql    2015-02-06 00:06:30 +0900 (5038978)
+++ test.sql    2015-02-06 00:17:31 +0900 (985c8ff)
@@ -4,19 +4,19 @@ CREATE TABLE memos (
   title text
 );
 
-INSERT INTO memos VALUES (1, 'PostgreSQL');
 INSERT INTO memos VALUES (2, 'Groonga');
 INSERT INTO memos VALUES (3, 'PGroonga');
+INSERT INTO memos VALUES (1, 'PostgreSQL');
 
-CREATE INDEX grnindex ON memos USING pgroonga (title pgroonga.text_ops);
+CREATE INDEX grnindex ON memos USING pgroonga (id);
 
 SET enable_seqscan = off;
 SET enable_indexscan = on;
-SET enable_bitmapscan = off;
+SET enable_bitmapscan = on;
 
 SELECT id, title
   FROM memos
- WHERE title = 'Groonga';
+ ORDER BY id DESC LIMIT 2;
 
 DROP TABLE memos;
 
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index