[Groonga-commit] pgroonga/pgroonga at 67d2eab [master] Support composite primary key

Back to archive index

Kouhei Sutou null+****@clear*****
Fri Jan 29 01:48:29 JST 2016


Kouhei Sutou	2016-01-29 01:48:29 +0900 (Fri, 29 Jan 2016)

  New Revision: 67d2eab2a28209f1e7d285fc6577ebd5ddfefabb
  https://github.com/pgroonga/pgroonga/commit/67d2eab2a28209f1e7d285fc6577ebd5ddfefabb

  Message:
    Support composite primary key

  Added files:
    expected/full-text-search/text/single/score/composite-primary-key.out
    sql/full-text-search/text/single/score/composite-primary-key.sql
  Modified files:
    src/pgroonga.c

  Added: expected/full-text-search/text/single/score/composite-primary-key.out (+26 -0) 100644
===================================================================
--- /dev/null
+++ expected/full-text-search/text/single/score/composite-primary-key.out    2016-01-29 01:48:29 +0900 (601c528)
@@ -0,0 +1,26 @@
+CREATE TABLE memos (
+  created_date varchar(10),
+  slug varchar(100),
+  content text,
+  PRIMARY KEY (created_date, slug)
+);
+INSERT INTO memos VALUES
+  ('2015-11-19', 'postgresql', 'PostgreSQL is a RDBMS.');
+INSERT INTO memos VALUES
+  ('2015-11-19', 'groonga', 'Groonga is fast full text search engine.');
+INSERT INTO memos VALUES
+  ('2015-11-19', 'pgroonga', 'PGroonga is a PostgreSQL extension that uses Groonga.');
+CREATE INDEX grnindex ON memos USING pgroonga (created_date, slug, content);
+SET enable_seqscan = off;
+SET enable_indexscan = on;
+SET enable_bitmapscan = off;
+SELECT created_date, slug, content, pgroonga.score(memos)
+  FROM memos
+ WHERE content %% 'Groonga';
+ created_date |   slug   |                        content                        | score 
+--------------+----------+-------------------------------------------------------+-------
+ 2015-11-19   | groonga  | Groonga is fast full text search engine.              |     1
+ 2015-11-19   | pgroonga | PGroonga is a PostgreSQL extension that uses Groonga. |     1
+(2 rows)
+
+DROP TABLE memos;

  Added: sql/full-text-search/text/single/score/composite-primary-key.sql (+25 -0) 100644
===================================================================
--- /dev/null
+++ sql/full-text-search/text/single/score/composite-primary-key.sql    2016-01-29 01:48:29 +0900 (d9c94ee)
@@ -0,0 +1,25 @@
+CREATE TABLE memos (
+  created_date varchar(10),
+  slug varchar(100),
+  content text,
+  PRIMARY KEY (created_date, slug)
+);
+
+INSERT INTO memos VALUES
+  ('2015-11-19', 'postgresql', 'PostgreSQL is a RDBMS.');
+INSERT INTO memos VALUES
+  ('2015-11-19', 'groonga', 'Groonga is fast full text search engine.');
+INSERT INTO memos VALUES
+  ('2015-11-19', 'pgroonga', 'PGroonga is a PostgreSQL extension that uses Groonga.');
+
+CREATE INDEX grnindex ON memos USING pgroonga (created_date, slug, content);
+
+SET enable_seqscan = off;
+SET enable_indexscan = on;
+SET enable_bitmapscan = off;
+
+SELECT created_date, slug, content, pgroonga.score(memos)
+  FROM memos
+ WHERE content %% 'Groonga';
+
+DROP TABLE memos;

  Modified: src/pgroonga.c (+127 -93)
===================================================================
--- src/pgroonga.c    2016-01-29 01:03:25 +0900 (7aa7512)
+++ src/pgroonga.c    2016-01-29 01:48:29 +0900 (d953c98)
@@ -70,23 +70,24 @@ typedef struct PGrnBuildStateData
 
 typedef PGrnBuildStateData *PGrnBuildState;
 
-typedef struct PGrnScanOpaqueData
-{
-	Relation index;
 #ifdef PGRN_SUPPORT_SCORE
+typedef struct PGrnPrimaryKeyColumn
+{
 	slist_node node;
+	AttrNumber number;
+	Oid type;
+	grn_id domain;
+	unsigned char flags;
+	grn_obj *column;
+} PGrnPrimaryKeyColumn;
 #endif
+
+typedef struct PGrnScanOpaqueData
+{
+	Relation index;
 	Oid dataTableID;
 	grn_obj *sourcesTable;
 	grn_obj *sourcesCtidColumn;
-	struct
-	{
-		AttrNumber number;
-		Oid type;
-		grn_id domain;
-		unsigned char flags;
-		grn_obj *column;
-	} primaryKey;
 	grn_obj minBorderValue;
 	grn_obj maxBorderValue;
 	grn_obj *searched;
@@ -97,6 +98,11 @@ typedef struct PGrnScanOpaqueData
 	grn_obj *ctidAccessor;
 	grn_obj *scoreAccessor;
 	grn_id currentID;
+
+#ifdef PGRN_SUPPORT_SCORE
+	slist_node node;
+	slist_head primaryKeyColumns;
+#endif
 } PGrnScanOpaqueData;
 
 typedef PGrnScanOpaqueData *PGrnScanOpaque;
@@ -737,8 +743,11 @@ PGrnCollectScoreScanOpaque(Relation table, HeapTuple tuple, PGrnScanOpaque so)
 {
 	double score = 0.0;
 	TupleDesc desc;
-	bool isNULL;
 	grn_obj *records;
+	grn_obj *expression;
+	grn_obj *variable;
+	slist_iter iter;
+	unsigned int nPrimaryKeyColumns = 0;
 
 	if (so->dataTableID != tuple->t_tableOid)
 		return 0.0;
@@ -746,45 +755,54 @@ PGrnCollectScoreScanOpaque(Relation table, HeapTuple tuple, PGrnScanOpaque so)
 	if (!so->scoreAccessor)
 		return 0.0;
 
-	if (!OidIsValid(so->primaryKey.type))
+	if (slist_is_empty(&(so->primaryKeyColumns)))
 		return 0.0;
 
+	desc = RelationGetDescr(table);
+
+	records = grn_table_create(ctx, NULL, 0, NULL,
+							   GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
+							   so->sourcesTable, 0);
+	GRN_EXPR_CREATE_FOR_QUERY(ctx, so->sourcesTable, expression, variable);
+
+	slist_foreach(iter, &(so->primaryKeyColumns))
 	{
-		grn_obj *expression;
-		grn_obj *variable;
+		PGrnPrimaryKeyColumn *primaryKeyColumn;
+		bool isNULL;
 		Datum primaryKeyValue;
 
-		GRN_EXPR_CREATE_FOR_QUERY(ctx, so->sourcesTable, expression, variable);
+		primaryKeyColumn = slist_container(PGrnPrimaryKeyColumn, node, iter.cur);
 
-		grn_obj_reinit(ctx, &(buffers->general),
-					   so->primaryKey.domain, so->primaryKey.flags);
+		grn_obj_reinit(ctx,
+					   &(buffers->general),
+					   primaryKeyColumn->domain,
+					   primaryKeyColumn->flags);
 
-		desc = RelationGetDescr(table);
 		primaryKeyValue = heap_getattr(tuple,
-									   so->primaryKey.number,
+									   primaryKeyColumn->number,
 									   desc,
 									   &isNULL);
 		PGrnConvertFromData(primaryKeyValue,
-							so->primaryKey.type,
+							primaryKeyColumn->type,
 							&(buffers->general));
 
-		grn_expr_append_obj(ctx, expression, so->primaryKey.column,
-							GRN_OP_PUSH, 1);
+		grn_expr_append_obj(ctx, expression,
+							primaryKeyColumn->column, GRN_OP_PUSH, 1);
 		grn_expr_append_op(ctx, expression, GRN_OP_GET_VALUE, 1);
-		grn_expr_append_const(ctx, expression, &(buffers->general),
-							  GRN_OP_PUSH, 1);
+		grn_expr_append_const(ctx, expression,
+							  &(buffers->general), GRN_OP_PUSH, 1);
 		grn_expr_append_op(ctx, expression, GRN_OP_EQUAL, 2);
 
-		records = grn_table_create(ctx, NULL, 0, NULL,
-								   GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
-								   so->sourcesTable, 0);
-		grn_table_select(ctx,
-						 so->sourcesTable,
-						 expression,
-						 records,
-						 GRN_OP_OR);
-		grn_obj_close(ctx, expression);
+		if (nPrimaryKeyColumns > 0)
+			grn_expr_append_op(ctx, expression, GRN_OP_AND, 2);
+		nPrimaryKeyColumns++;
 	}
+	grn_table_select(ctx,
+					 so->sourcesTable,
+					 expression,
+					 records,
+					 GRN_OP_OR);
+	grn_obj_close(ctx, expression);
 
 	{
 		grn_table_cursor *tableCursor;
@@ -1587,88 +1605,102 @@ pgroonga_insert(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(true);
 }
 
-static bool
-PGrnFindPrimaryKey(Relation table,
-				   PGrnScanOpaque so)
+#ifdef PGRN_SUPPORT_SCORE
+static void
+PGrnPrimaryKeyColumnsFin(slist_head *columns)
+{
+	while (!slist_is_empty(columns))
+	{
+		slist_node *current;
+		PGrnPrimaryKeyColumn *column;
+
+		current = slist_pop_head_node(columns);
+		column = slist_container(PGrnPrimaryKeyColumn, node, current);
+		pfree(column);
+	}
+}
+
+static void
+PGrnPrimaryKeyColumnsInit(slist_head *columns,
+						  PGrnScanOpaque so)
 {
+	Relation table;
 	List *indexOIDList;
 	ListCell *cell;
-	bool havePrimaryKey = false;
 
+	table = RelationIdGetRelation(so->dataTableID);
 	indexOIDList = RelationGetIndexList(table);
-	if (indexOIDList == NIL)
-	{
-		return false;
-	}
-
 	foreach(cell, indexOIDList)
 	{
 		Oid indexOID = lfirst_oid(cell);
-		Relation index;
-		Oid primaryKeyNumber;
-		int i, nColumns;
-		TupleDesc desc;
-
-		index = index_open(indexOID, NoLock);
-		if (!index->rd_index->indisprimary) {
-			index_close(index, NoLock);
+		Relation primaryKeyIndex;
+		int i;
+
+		primaryKeyIndex = index_open(indexOID, NoLock);
+		if (!primaryKeyIndex->rd_index->indisprimary) {
+			index_close(primaryKeyIndex, NoLock);
 			continue;
 		}
 
-		// TODO: Support multiple column primary key
-		primaryKeyNumber = index->rd_index->indkey.values[0];
+		for (i = 0; i < primaryKeyIndex->rd_index->indnatts; i++)
+		{
+			Oid primaryKeyNumber;
+			int j;
+			bool havePrimaryKey = false;
 
-		desc = RelationGetDescr(table);
+			primaryKeyNumber = primaryKeyIndex->rd_index->indkey.values[i];
 
-		nColumns = so->index->rd_index->indnatts;
-		for (i = 0; i < nColumns; i++)
-		{
-			const char *columnName;
+			for (j = 0; j < so->index->rd_index->indnatts; j++)
+			{
+				TupleDesc desc;
+				const char *columnName;
+				PGrnPrimaryKeyColumn *primaryKeyColumn;
 
-			if (so->index->rd_index->indkey.values[i] != primaryKeyNumber)
-				continue;
+				if (so->index->rd_index->indkey.values[j] != primaryKeyNumber)
+					continue;
 
-			columnName = so->index->rd_att->attrs[0]->attname.data;
-
-			so->primaryKey.number = primaryKeyNumber;
-			so->primaryKey.type = desc->attrs[primaryKeyNumber - 1]->atttypid;
-			so->primaryKey.domain = PGrnGetType(index,
-												primaryKeyNumber - 1,
-												&(so->primaryKey.flags));
-			so->primaryKey.column = grn_obj_column(ctx,
-												   so->sourcesTable,
-												   columnName,
-												   strlen(columnName));
-			havePrimaryKey = true;
-			break;
-		}
+				primaryKeyColumn =
+					(PGrnPrimaryKeyColumn *) palloc(sizeof(PGrnPrimaryKeyColumn));
+
+				desc = RelationGetDescr(table);
+				columnName = so->index->rd_att->attrs[j]->attname.data;
+
+				primaryKeyColumn->number = primaryKeyNumber;
+				primaryKeyColumn->type =
+					desc->attrs[primaryKeyNumber - 1]->atttypid;
+				primaryKeyColumn->domain = PGrnGetType(primaryKeyIndex,
+													   primaryKeyNumber - 1,
+													   &(primaryKeyColumn->flags));
+				primaryKeyColumn->column = grn_obj_column(ctx,
+														  so->sourcesTable,
+														  columnName,
+														  strlen(columnName));
+				slist_push_head(columns, &(primaryKeyColumn->node));
+				havePrimaryKey = true;
+				break;
+			}
 
-		index_close(index, NoLock);
+			if (!havePrimaryKey)
+			{
+				PGrnPrimaryKeyColumnsFin(columns);
+				break;
+			}
+		}
 
-		if (havePrimaryKey)
-			break;
+		index_close(primaryKeyIndex, NoLock);
+		break;
 	}
 	list_free(indexOIDList);
-
-	return havePrimaryKey;
+	RelationClose(table);
 }
 
 static void
-PGrnScanOpaqueInitPrimaryKey(PGrnScanOpaque so)
+PGrnScanOpaqueInitPrimaryKeyColumns(PGrnScanOpaque so)
 {
-	Relation table;
-
-	table = RelationIdGetRelation(so->dataTableID);
-	if (!PGrnFindPrimaryKey(table, so))
-	{
-		so->primaryKey.number = InvalidAttrNumber;
-		so->primaryKey.type = InvalidOid;
-		so->primaryKey.domain = GRN_ID_NIL;
-		so->primaryKey.flags = 0;
-		so->primaryKey.column = NULL;
-	}
-	RelationClose(table);
+	slist_init(&(so->primaryKeyColumns));
+	PGrnPrimaryKeyColumnsInit(&(so->primaryKeyColumns), so);
 }
+#endif
 
 static void
 PGrnScanOpaqueInit(PGrnScanOpaque so, Relation index)
@@ -1677,7 +1709,6 @@ PGrnScanOpaqueInit(PGrnScanOpaque so, Relation index)
 	so->dataTableID = index->rd_index->indrelid;
 	so->sourcesTable = PGrnLookupSourcesTable(index, ERROR);
 	so->sourcesCtidColumn = PGrnLookupSourcesCtidColumn(index, ERROR);
-	PGrnScanOpaqueInitPrimaryKey(so);
 	GRN_VOID_INIT(&(so->minBorderValue));
 	GRN_VOID_INIT(&(so->maxBorderValue));
 	so->searched = NULL;
@@ -1691,6 +1722,7 @@ PGrnScanOpaqueInit(PGrnScanOpaque so, Relation index)
 
 #ifdef PGRN_SUPPORT_SCORE
 	slist_push_head(&PGrnScanOpaques, &(so->node));
+	PGrnScanOpaqueInitPrimaryKeyColumns(so);
 #endif
 }
 
@@ -1749,6 +1781,8 @@ PGrnScanOpaqueFin(PGrnScanOpaque so)
 			break;
 		}
 	}
+
+	PGrnPrimaryKeyColumnsFin(&(so->primaryKeyColumns));
 #endif
 
 	PGrnScanOpaqueReinit(so);
-------------- next part --------------
HTML����������������������������...
Download 



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