[Groonga-commit] pgroonga/pgroonga at 7598568 [master] Support index only scan

Back to archive index

Kouhei Sutou null+****@clear*****
Sun Oct 4 13:04:36 JST 2015


Kouhei Sutou	2015-10-04 13:04:36 +0900 (Sun, 04 Oct 2015)

  New Revision: 75985689259e2f24dc6358ef797a930bb0ba87e5
  https://github.com/pgroonga/pgroonga/commit/75985689259e2f24dc6358ef797a930bb0ba87e5

  Message:
    Support index only scan

  Added files:
    pgroonga--0.9.0--1.0.0.sql
  Modified files:
    pgroonga.c
    pgroonga.h
    pgroonga.sql

  Added: pgroonga--0.9.0--1.0.0.sql (+8 -0) 100644
===================================================================
--- /dev/null
+++ pgroonga--0.9.0--1.0.0.sql    2015-10-04 13:04:36 +0900 (8cadded)
@@ -0,0 +1,8 @@
+CREATE FUNCTION pgroonga.canreturn(internal)
+	RETURNS internal
+	AS 'MODULE_PATHNAME', 'pgroonga_canreturn'
+	LANGUAGE C;
+
+UPDATE pg_catalog.pg_am
+   SET amcanreturn = 'pgroonga.canreturn'
+ WHERE amname = 'pgroonga';

  Modified: pgroonga.c (+206 -0)
===================================================================
--- pgroonga.c    2015-10-04 11:17:08 +0900 (220a514)
+++ pgroonga.c    2015-10-04 13:04:36 +0900 (ca6daef)
@@ -124,6 +124,7 @@ typedef PGrnBuildStateData *PGrnBuildState;
 
 typedef struct PGrnScanOpaqueData
 {
+	Relation index;
 	slist_node node;
 	Oid dataTableID;
 	struct
@@ -184,6 +185,7 @@ PG_FUNCTION_INFO_V1(pgroonga_build);
 PG_FUNCTION_INFO_V1(pgroonga_buildempty);
 PG_FUNCTION_INFO_V1(pgroonga_bulkdelete);
 PG_FUNCTION_INFO_V1(pgroonga_vacuumcleanup);
+PG_FUNCTION_INFO_V1(pgroonga_canreturn);
 PG_FUNCTION_INFO_V1(pgroonga_costestimate);
 PG_FUNCTION_INFO_V1(pgroonga_options);
 
@@ -828,6 +830,130 @@ PGrnConvertDatum(Datum datum, Oid typeID, grn_obj *buffer)
 	}
 }
 
+static Datum
+PGrnConvertToDatumArrayType(grn_obj *vector, Oid typeID)
+{
+	Oid elementTypeID;
+	int i, n;
+	Datum *values;
+
+	if (typeID == VARCHARARRAYOID)
+		elementTypeID = VARCHAROID;
+	else
+		elementTypeID = TEXTOID;
+
+	n = grn_vector_size(ctx, vector);
+	if (n == 0)
+		PG_RETURN_POINTER(construct_empty_array(elementTypeID));
+
+	values = palloc(sizeof(Datum) * n);
+	for (i = 0; i < n; i++)
+	{
+		const char *element;
+		unsigned int elementSize;
+		text *value;
+
+		elementSize = grn_vector_get_element(ctx, vector, i,
+											 &element,
+											 NULL,
+											 NULL);
+		value = cstring_to_text_with_len(element, elementSize);
+		values[i] = PointerGetDatum(value);
+	}
+
+	{
+		int	dims[1];
+		int	lbs[1];
+
+		dims[0] = n;
+		lbs[0] = 1;
+		PG_RETURN_POINTER(construct_md_array(values, NULL,
+											 1, dims, lbs,
+											 elementTypeID,
+											 -1, false, 'i'));
+	}
+}
+
+static Datum
+PGrnConvertToDatum(grn_obj *value, Oid typeID)
+{
+	switch (typeID)
+	{
+	case BOOLOID:
+		PG_RETURN_BOOL(GRN_BOOL_VALUE(value));
+		break;
+	case INT2OID:
+		PG_RETURN_INT16(GRN_INT16_VALUE(value));
+		break;
+	case INT4OID:
+		PG_RETURN_INT32(GRN_INT32_VALUE(value));
+		break;
+	case INT8OID:
+		PG_RETURN_INT64(GRN_INT64_VALUE(value));
+		break;
+	case FLOAT4OID:
+		PG_RETURN_FLOAT4(GRN_FLOAT_VALUE(value));
+		break;
+	case FLOAT8OID:
+		PG_RETURN_FLOAT8(GRN_FLOAT_VALUE(value));
+		break;
+	case TIMESTAMPOID:
+	case TIMESTAMPTZOID:
+	{
+		int64 grnTime;
+		int64 sec;
+		int64 usec;
+		pg_time_t unixTime;
+		TimestampTz timestamp;
+
+		grnTime = GRN_TIME_VALUE(value);
+		GRN_TIME_UNPACK(grnTime, sec, usec);
+		unixTime = sec;
+		timestamp = time_t_to_timestamptz(unixTime);
+#ifdef HAVE_INT64_TIMESTAMP
+		timestamp += usec;
+#else
+		timestamp += ((double) used) / USECS_PER_SEC;
+#endif
+		if (typeID == TIMESTAMPOID)
+			PG_RETURN_TIMESTAMP(timestamp);
+		else
+			PG_RETURN_TIMESTAMPTZ(timestamp);
+		break;
+	}
+	case TEXTOID:
+	case XMLOID:
+	{
+		text *text = cstring_to_text_with_len(GRN_TEXT_VALUE(value),
+											  GRN_TEXT_LEN(value));
+		PG_RETURN_TEXT_P(text);
+		break;
+	}
+	case VARCHAROID:
+	{
+		text *text = cstring_to_text_with_len(GRN_TEXT_VALUE(value),
+											  GRN_TEXT_LEN(value));
+		PG_RETURN_VARCHAR_P((VarChar *) text);
+		break;
+	}
+#ifdef NOT_USED
+	case POINTOID:
+		/* GRN_DB_TOKYO_GEO_POINT or GRN_DB_WGS84_GEO_POINT; */
+		break;
+#endif
+	case VARCHARARRAYOID:
+	case TEXTARRAYOID:
+		return PGrnConvertToDatumArrayType(value, typeID);
+		break;
+	default:
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("pgroonga: unsupported datum type: %u",
+						typeID)));
+		break;
+	}
+}
+
 #ifdef JSONBOID
 
 static const unsigned int PGRN_JSON_GENERATE_PATH_IS_ABSOLUTE   = 1 << 0;
@@ -2685,6 +2811,7 @@ PGrnScanOpaqueInitPrimaryKey(PGrnScanOpaque so, Relation index)
 static void
 PGrnScanOpaqueInit(PGrnScanOpaque so, Relation index)
 {
+	so->index = index;
 	so->dataTableID = index->rd_index->indrelid;
 	PGrnScanOpaqueInitPrimaryKey(so, index);
 	so->sourcesTable = PGrnLookupSourcesTable(index, ERROR);
@@ -3544,6 +3671,57 @@ PGrnEnsureCursorOpened(IndexScanDesc scan, ScanDirection dir)
 	}
 }
 
+static void
+PGrnGetTupleFillIndexTuple(PGrnScanOpaque so,
+						   IndexScanDesc scan)
+{
+	TupleDesc desc;
+	Datum *values;
+	bool *isNulls;
+	grn_id recordID;
+	unsigned int i;
+
+	desc = RelationGetDescr(so->index);
+	scan->xs_itupdesc = desc;
+
+	values = palloc(sizeof(Datum) * desc->natts);
+	isNulls = palloc(sizeof(bool) * desc->natts);
+
+	recordID = so->currentID;
+	if (so->sorted)
+	{
+		GRN_BULK_REWIND(&buffer);
+		grn_obj_get_value(ctx, so->sorted, recordID, &buffer);
+		recordID = GRN_RECORD_VALUE(&buffer);
+	}
+	if (so->searched)
+	{
+		grn_table_get_key(ctx, so->searched, recordID,
+						  &recordID, sizeof(grn_id));
+	}
+
+	for (i = 0; i < desc->natts; i++)
+	{
+		Form_pg_attribute attribute = desc->attrs[i];
+		NameData *name;
+		grn_obj *dataColumn;
+
+		name = &(attribute->attname);
+		dataColumn = PGrnLookupColumn(so->sourcesTable, name->data, ERROR);
+		GRN_BULK_REWIND(&buffer);
+		grn_obj_get_value(ctx, dataColumn, recordID, &buffer);
+		values[i] = PGrnConvertToDatum(&buffer, attribute->atttypid);
+		isNulls[i] = false;
+		grn_obj_unlink(ctx, dataColumn);
+	}
+
+	scan->xs_itup = index_form_tuple(scan->xs_itupdesc,
+									 values,
+									 isNulls);
+
+	pfree(values);
+	pfree(isNulls);
+}
 
 /**
  * pgroonga.gettuple() -- amgettuple
@@ -3589,6 +3767,9 @@ pgroonga_gettuple(PG_FUNCTION_ARGS)
 		grn_obj_get_value(ctx, so->ctidAccessor, so->currentID, &ctidBuffer);
 		scan->xs_ctup.t_self = UInt64ToCtid(GRN_UINT64_VALUE(&ctidBuffer));
 
+		if (scan->xs_want_itup)
+			PGrnGetTupleFillIndexTuple(so, scan);
+
 		PG_RETURN_BOOL(true);
 	}
 
@@ -4186,6 +4367,31 @@ pgroonga_vacuumcleanup(PG_FUNCTION_ARGS)
 }
 
 /**
+ * pgroonga.canreturn() -- amcanreturn
+ */
+Datum
+pgroonga_canreturn(PG_FUNCTION_ARGS)
+{
+#ifdef JSONBOID
+	Relation index = (Relation) PG_GETARG_POINTER(0);
+	TupleDesc desc;
+	unsigned int i;
+
+	desc = RelationGetDescr(index);
+	for (i = 0; i < desc->natts; i++)
+	{
+		Form_pg_attribute attribute = desc->attrs[i];
+		if (attribute->atttypid == JSONBOID)
+		{
+			PG_RETURN_BOOL(false);
+		}
+	}
+#endif
+
+	PG_RETURN_BOOL(true);
+}
+
+/**
  * pgroonga.costestimate() -- amcostestimate
  */
 Datum

  Modified: pgroonga.h (+1 -0)
===================================================================
--- pgroonga.h    2015-10-04 11:17:08 +0900 (929caa9)
+++ pgroonga.h    2015-10-04 13:04:36 +0900 (2239bac)
@@ -64,6 +64,7 @@ extern Datum PGDLLEXPORT pgroonga_build(PG_FUNCTION_ARGS);
 extern Datum PGDLLEXPORT pgroonga_buildempty(PG_FUNCTION_ARGS);
 extern Datum PGDLLEXPORT pgroonga_bulkdelete(PG_FUNCTION_ARGS);
 extern Datum PGDLLEXPORT pgroonga_vacuumcleanup(PG_FUNCTION_ARGS);
+extern Datum PGDLLEXPORT pgroonga_canreturn(PG_FUNCTION_ARGS);
 extern Datum PGDLLEXPORT pgroonga_costestimate(PG_FUNCTION_ARGS);
 extern Datum PGDLLEXPORT pgroonga_options(PG_FUNCTION_ARGS);
 

  Modified: pgroonga.sql (+5 -1)
===================================================================
--- pgroonga.sql    2015-10-04 11:17:08 +0900 (28d34fe)
+++ pgroonga.sql    2015-10-04 13:04:36 +0900 (b15ea6b)
@@ -163,6 +163,10 @@ CREATE FUNCTION pgroonga.vacuumcleanup(internal)
 	RETURNS internal
 	AS 'MODULE_PATHNAME', 'pgroonga_vacuumcleanup'
 	LANGUAGE C;
+CREATE FUNCTION pgroonga.canreturn(internal)
+	RETURNS internal
+	AS 'MODULE_PATHNAME', 'pgroonga_canreturn'
+	LANGUAGE C;
 CREATE FUNCTION pgroonga.costestimate(internal)
 	RETURNS internal
 	AS 'MODULE_PATHNAME', 'pgroonga_costestimate'
@@ -201,7 +205,7 @@ INSERT INTO pg_catalog.pg_am VALUES(
 	'pgroonga.buildempty',	-- ambuildempty
 	'pgroonga.bulkdelete',	-- ambulkdelete
 	'pgroonga.vacuumcleanup',	-- amvacuumcleanup
-	0,		-- amcanreturn
+	'pgroonga.canreturn',		-- amcanreturn
 	'pgroonga.costestimate',	-- amcostestimate
 	'pgroonga.options'	-- amoptions
 );
-------------- next part --------------
HTML����������������������������...
Download 



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