diff -c -r -N src.orig/backend/commands/explain.c src/backend/commands/explain.c
*** src.orig/backend/commands/explain.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/commands/explain.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 987,992 ****
--- 987,994 ----
  		case T_IndexScan:
  			show_scan_qual(((IndexScan *) plan)->indexqualorig,
  						   "Index Cond", plan, outer_plan, es);
+ 			show_scan_qual(((IndexScan *) plan)->indexsortqualorig,
+ 						   "Sort Cond", plan, outer_plan, es);
  			show_scan_qual(plan->qual, "Filter", plan, outer_plan, es);
  			break;
  		case T_BitmapIndexScan:
diff -c -r -N src.orig/backend/commands/opclasscmds.c src/backend/commands/opclasscmds.c
*** src.orig/backend/commands/opclasscmds.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/commands/opclasscmds.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 1073,1088 ****
  	opform = (Form_pg_operator) GETSTRUCT(optup);
  
  	/*
! 	 * Opfamily operators must be binary ops returning boolean.
  	 */
  	if (opform->oprkind != 'b')
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  				 errmsg("index operators must be binary")));
  	if (opform->oprresult != BOOLOID)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 				 errmsg("index operators must return boolean")));
  
  	/*
  	 * If lefttype/righttype isn't specified, use the operator's input types
--- 1073,1106 ----
  	opform = (Form_pg_operator) GETSTRUCT(optup);
  
  	/*
! 	 * Opfamily operators must be binary ops returning boolean or 
! 	 * btree indexable type (for pg_am->amcanorderbyop indexes).
  	 */
  	if (opform->oprkind != 'b')
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  				 errmsg("index operators must be binary")));
  	if (opform->oprresult != BOOLOID)
! 	{
! 		Form_pg_am pg_am;
! 		HeapTuple  amtup;
! 
! 		amtup = SearchSysCache(AMOID, ObjectIdGetDatum(amoid), 0, 0, 0);
! 		Assert(HeapTupleIsValid(amtup));
! 		pg_am = (Form_pg_am) GETSTRUCT(amtup);
! 
! 		if (!pg_am->amcanorderbyop)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 					 errmsg("index operators must return boolean")));
! 
! 		ReleaseSysCache(amtup);
! 
! 		if (GetDefaultOpClass(opform->oprresult, BTREE_AM_OID) == InvalidOid)	
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 					 errmsg("index operators must return boolean or type with default btree operator class")));
! 	}
  
  	/*
  	 * If lefttype/righttype isn't specified, use the operator's input types
diff -c -r -N src.orig/backend/nodes/copyfuncs.c src/backend/nodes/copyfuncs.c
*** src.orig/backend/nodes/copyfuncs.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/nodes/copyfuncs.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 337,342 ****
--- 337,343 ----
  	COPY_SCALAR_FIELD(indexid);
  	COPY_NODE_FIELD(indexqual);
  	COPY_NODE_FIELD(indexqualorig);
+ 	COPY_NODE_FIELD(indexsortqualorig);
  	COPY_SCALAR_FIELD(indexorderdir);
  
  	return newnode;
diff -c -r -N src.orig/backend/nodes/outfuncs.c src/backend/nodes/outfuncs.c
*** src.orig/backend/nodes/outfuncs.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/nodes/outfuncs.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 412,417 ****
--- 412,418 ----
  	WRITE_OID_FIELD(indexid);
  	WRITE_NODE_FIELD(indexqual);
  	WRITE_NODE_FIELD(indexqualorig);
+ 	WRITE_NODE_FIELD(indexsortqualorig);
  	WRITE_ENUM_FIELD(indexorderdir, ScanDirection);
  }
  
***************
*** 1381,1386 ****
--- 1382,1388 ----
  	WRITE_NODE_FIELD(indexinfo);
  	WRITE_NODE_FIELD(indexclauses);
  	WRITE_NODE_FIELD(indexquals);
+ 	WRITE_NODE_FIELD(indexsortquals);
  	WRITE_BOOL_FIELD(isjoininner);
  	WRITE_ENUM_FIELD(indexscandir, ScanDirection);
  	WRITE_FLOAT_FIELD(indextotalcost, "%.2f");
diff -c -r -N src.orig/backend/optimizer/path/indxpath.c src/backend/optimizer/path/indxpath.c
*** src.orig/backend/optimizer/path/indxpath.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/optimizer/path/indxpath.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 103,108 ****
--- 103,110 ----
  						   IndexOptInfo *index);
  static bool match_special_index_operator(Expr *clause, Oid opfamily,
  							 bool indexkey_on_left);
+ static void match_pathkey_to_index(IndexOptInfo *index, List *pathkeys, List *restrictclauses, 
+ 	                               /* out: */ List **matched_pathkeys, List **sortclauses);
  static Expr *expand_boolean_index_clause(Node *clause, int indexcol,
  							IndexOptInfo *index);
  static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily);
***************
*** 200,206 ****
--- 202,222 ----
  		if (ipath->indexinfo->amhasgetbitmap &&
  			ipath->indexselectivity < 1.0 &&
  			!ScanDirectionIsBackward(ipath->indexscandir))
+ 		{
+ 			/*
+ 			 * remove indexsortquals if it present, because sorting
+ 			 * clauses are not applicable to bitmap scan
+ 			 */
+ 			if (ipath->indexsortquals)
+ 			{
+ 				IndexPath	*newipath = makeNode(IndexPath); 
+ 
+ 				*newipath = *ipath;
+ 				newipath->indexsortquals = NIL;
+ 				ipath = newipath;
+ 			}
  			bitindexpaths = lappend(bitindexpaths, ipath);
+ 		}
  	}
  
  	/*
***************
*** 291,296 ****
--- 307,313 ----
  		IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
  		IndexPath  *ipath;
  		List	   *restrictclauses;
+ 		List	   *sortclauses;
  		List	   *index_pathkeys;
  		List	   *useful_pathkeys;
  		bool		useful_predicate;
***************
*** 393,401 ****
--- 410,430 ----
  												  ForwardScanDirection);
  			useful_pathkeys = truncate_useless_pathkeys(root, rel,
  														index_pathkeys);
+ 			sortclauses = NIL;
+ 		}
+ 		else if (index->amcanorderbyop && possibly_useful_pathkeys &&
+ 				 istoplevel && outer_rel == NULL && scantype != ST_BITMAPSCAN) 
+ 		{
+ 			useful_pathkeys = NIL;
+ 			sortclauses = NIL;
+ 			match_pathkey_to_index(index, root->query_pathkeys, restrictclauses,
+ 									&useful_pathkeys, &sortclauses);
  		}
  		else
+ 		{
  			useful_pathkeys = NIL;
+ 			sortclauses = NIL;
+ 		}
  
  		/*
  		 * 3. Generate an indexscan path if there are relevant restriction
***************
*** 407,412 ****
--- 436,442 ----
  		{
  			ipath = create_index_path(root, index,
  									  restrictclauses,
+ 									  sortclauses,
  									  useful_pathkeys,
  									  index_is_ordered ?
  									  ForwardScanDirection :
***************
*** 430,435 ****
--- 460,466 ----
  			{
  				ipath = create_index_path(root, index,
  										  restrictclauses,
+ 									  	  sortclauses,
  										  useful_pathkeys,
  										  BackwardScanDirection,
  										  outer_rel);
***************
*** 1605,1610 ****
--- 1636,1706 ----
  }
  
  /*
+  * Choose first relevant pathkeys for indexes which supports
+  * order by operation
+  */
+ static void
+ match_pathkey_to_index(IndexOptInfo *index, List *pathkeys, List *restrictclauses, 
+ 	/* out: */ List **matched_pathkeys, List **sortclauses)
+ {
+ 	ListCell	*l1, *l2;
+ 
+ 	if (!index->amcanorderbyop)
+ 		return;
+ 
+ 	foreach(l1, pathkeys)
+ 	{
+ 		PathKey *pathkey = lfirst(l1);
+ 		bool	 found = false;
+ 
+ 		/*
+ 		 * Currently, only descending and nulls last ordering is supported
+ 		 */
+ 		if (!(pathkey->pk_strategy == BTLessStrategyNumber && pathkey->pk_nulls_first == false))
+ 			return;
+ 
+ 		foreach(l2, pathkey->pk_eclass->ec_members)
+ 		{
+ 			EquivalenceMember	*member = lfirst(l2);
+ 			int					 indexcol = 0;
+ 			Oid			   		*families = index->opfamily;
+ 			RestrictInfo		*rinfo = make_simple_restrictinfo(member->em_expr); 
+ 
+ 			do
+ 			{
+ 				Oid			curFamily = families[0];
+ 
+ 				if (list_length(restrictclauses) < indexcol && !index->amoptionalkey)
+ 					break;
+ 
+ 				if (match_clause_to_indexcol(index,
+ 											 indexcol,
+ 											 curFamily,
+ 											 rinfo,
+ 											 NULL,
+ 											 SAOP_FORBID))
+ 				{
+ 					*matched_pathkeys = lappend(*matched_pathkeys, pathkey);
+ 					*sortclauses = lappend(*sortclauses, rinfo);
+ 
+ 					found = true;
+ 					break;
+ 				}
+ 
+ 				indexcol++;
+ 				families++;
+ 			} while (!DoneMatchingIndexKeys(families));
+ 
+ 			if (found) /* not need to check other members */
+ 				break;
+ 		}
+ 
+ 		if (!found) /* go away if we don't have index match */
+ 			return;
+ 	}
+ }
+ 
+ /*
   * eclass_matches_any_index
   *	  Workhorse for indexable_outerrelids: see if an EquivalenceClass member
   *	  can be matched to any index column of the given rel.
***************
*** 1788,1793 ****
--- 1884,1891 ----
  	{
  		IndexPath  *ipath = (IndexPath *) lfirst(l);
  
+ 		Assert( ipath->indexsortquals == NIL ); /* join! */
+ 
  		if (ipath->indexinfo->amhasgettuple)
  			indexpaths = lappend(indexpaths, ipath);
  
diff -c -r -N src.orig/backend/optimizer/plan/createplan.c src/backend/optimizer/plan/createplan.c
*** src.orig/backend/optimizer/plan/createplan.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/optimizer/plan/createplan.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 79,85 ****
  static void copy_plan_costsize(Plan *dest, Plan *src);
  static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
  static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
! 			   Oid indexid, List *indexqual, List *indexqualorig,
  			   ScanDirection indexscandir);
  static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
  					  List *indexqual,
--- 79,85 ----
  static void copy_plan_costsize(Plan *dest, Plan *src);
  static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
  static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
! 			   Oid indexid, List *indexqual, List *indexqualorig, List *indexsortqualorig,
  			   ScanDirection indexscandir);
  static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
  					  List *indexqual,
***************
*** 873,883 ****
--- 873,886 ----
  					  List *scan_clauses)
  {
  	List	   *indexquals = best_path->indexquals;
+ 	List	   *indexsortquals = best_path->indexsortquals;
  	Index		baserelid = best_path->path.parent->relid;
  	Oid			indexoid = best_path->indexinfo->indexoid;
  	List	   *qpqual;
  	List	   *stripped_indexquals;
  	List	   *fixed_indexquals;
+ 	List	   *stripped_indexsortquals;
+ 	List	   *fixed_indexsortquals;
  	ListCell   *l;
  	IndexScan  *scan_plan;
  
***************
*** 890,901 ****
--- 893,906 ----
  	 * executor as indexqualorig
  	 */
  	stripped_indexquals = get_actual_clauses(indexquals);
+ 	stripped_indexsortquals = get_actual_clauses(indexsortquals);
  
  	/*
  	 * The executor needs a copy with the indexkey on the left of each clause
  	 * and with index attr numbers substituted for table ones.
  	 */
  	fixed_indexquals = fix_indexqual_references(indexquals, best_path);
+ 	fixed_indexsortquals = fix_indexqual_references(indexsortquals, best_path);
  
  	/*
  	 * If this is an innerjoin scan, the indexclauses will contain join
***************
*** 971,978 ****
  							   qpqual,
  							   baserelid,
  							   indexoid,
! 							   fixed_indexquals,
  							   stripped_indexquals,
  							   best_path->indexscandir);
  
  	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
--- 976,984 ----
  							   qpqual,
  							   baserelid,
  							   indexoid,
! 							   list_concat(fixed_indexquals, fixed_indexsortquals), 
  							   stripped_indexquals,
+ 							   stripped_indexsortquals,
  							   best_path->indexscandir);
  
  	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
***************
*** 2424,2429 ****
--- 2430,2436 ----
  			   Oid indexid,
  			   List *indexqual,
  			   List *indexqualorig,
+ 			   List *indexsortqualorig,
  			   ScanDirection indexscandir)
  {
  	IndexScan  *node = makeNode(IndexScan);
***************
*** 2438,2443 ****
--- 2445,2451 ----
  	node->indexid = indexid;
  	node->indexqual = indexqual;
  	node->indexqualorig = indexqualorig;
+ 	node->indexsortqualorig = indexsortqualorig;
  	node->indexorderdir = indexscandir;
  
  	return node;
diff -c -r -N src.orig/backend/optimizer/plan/planagg.c src/backend/optimizer/plan/planagg.c
*** src.orig/backend/optimizer/plan/planagg.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/optimizer/plan/planagg.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 405,410 ****
--- 405,411 ----
  		new_path = create_index_path(root, index,
  									 restrictclauses,
  									 NIL,
+ 									 NIL,
  									 indexscandir,
  									 NULL);
  
diff -c -r -N src.orig/backend/optimizer/plan/setrefs.c src/backend/optimizer/plan/setrefs.c
*** src.orig/backend/optimizer/plan/setrefs.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/optimizer/plan/setrefs.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 303,308 ****
--- 303,314 ----
  					fix_scan_list(glob, splan->indexqual, rtoffset);
  				splan->indexqualorig =
  					fix_scan_list(glob, splan->indexqualorig, rtoffset);
+ 				/* 
+ 				 * Fix indexsortqualorig only for explain purpose, because 
+ 				 * it could not be lossy
+ 				 */
+ 				splan->indexsortqualorig =
+ 					fix_scan_list(glob, splan->indexsortqualorig, rtoffset);
  			}
  			break;
  		case T_BitmapIndexScan:
diff -c -r -N src.orig/backend/optimizer/util/pathnode.c src/backend/optimizer/util/pathnode.c
*** src.orig/backend/optimizer/util/pathnode.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/optimizer/util/pathnode.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 413,418 ****
--- 413,420 ----
   * 'index' is a usable index.
   * 'clause_groups' is a list of lists of RestrictInfo nodes
   *			to be used as index qual conditions in the scan.
+  * 'sort_clauses' is a list of RestrictInfo nodes 
+  *          to be used as index qual sort conditions
   * 'pathkeys' describes the ordering of the path.
   * 'indexscandir' is ForwardScanDirection or BackwardScanDirection
   *			for an ordered index, or NoMovementScanDirection for
***************
*** 426,431 ****
--- 428,434 ----
  create_index_path(PlannerInfo *root,
  				  IndexOptInfo *index,
  				  List *clause_groups,
+ 				  List *sort_clauses,
  				  List *pathkeys,
  				  ScanDirection indexscandir,
  				  RelOptInfo *outer_rel)
***************
*** 462,467 ****
--- 465,472 ----
  	pathnode->indexinfo = index;
  	pathnode->indexclauses = allclauses;
  	pathnode->indexquals = indexquals;
+ 	/* XXX do we need to expand sort_clauses ? */ 
+ 	pathnode->indexsortquals = sort_clauses;
  
  	pathnode->isjoininner = (outer_rel != NULL);
  	pathnode->indexscandir = indexscandir;
diff -c -r -N src.orig/backend/optimizer/util/plancat.c src/backend/optimizer/util/plancat.c
*** src.orig/backend/optimizer/util/plancat.c	2010-01-12 21:42:46.000000000 +0300
--- src/backend/optimizer/util/plancat.c	2010-01-12 21:49:42.000000000 +0300
***************
*** 215,220 ****
--- 215,221 ----
  			info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
  			info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
  			info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap);
+ 			info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
  
  			/*
  			 * Fetch the ordering operators associated with the index, if any.
diff -c -r -N src.orig/include/nodes/plannodes.h src/include/nodes/plannodes.h
*** src.orig/include/nodes/plannodes.h	2010-01-12 21:42:48.000000000 +0300
--- src/include/nodes/plannodes.h	2010-01-12 21:49:42.000000000 +0300
***************
*** 270,277 ****
  {
  	Scan		scan;
  	Oid			indexid;		/* OID of index to scan */
! 	List	   *indexqual;		/* list of index quals (OpExprs) */
! 	List	   *indexqualorig;	/* the same in original form */
  	ScanDirection indexorderdir;	/* forward or backward or don't care */
  } IndexScan;
  
--- 270,278 ----
  {
  	Scan		scan;
  	Oid			indexid;		/* OID of index to scan */
! 	List	   *indexqual;		/* list of index quals (OpExprs) and sort quals */
! 	List	   *indexqualorig;	/* the same in original form without sort */
! 	List	   *indexsortqualorig;	/* sort quals in original form */
  	ScanDirection indexorderdir;	/* forward or backward or don't care */
  } IndexScan;
  
diff -c -r -N src.orig/include/nodes/relation.h src/include/nodes/relation.h
*** src.orig/include/nodes/relation.h	2010-01-12 21:42:48.000000000 +0300
--- src/include/nodes/relation.h	2010-01-12 21:49:42.000000000 +0300
***************
*** 464,469 ****
--- 464,470 ----
  	bool		amsearchnulls;	/* can AM search for NULL/NOT NULL entries? */
  	bool		amhasgettuple;	/* does AM have amgettuple interface? */
  	bool		amhasgetbitmap; /* does AM have amgetbitmap interface? */
+ 	bool		amcanorderbyop; /* does AM support ordering operations? */
  } IndexOptInfo;
  
  
***************
*** 623,628 ****
--- 624,631 ----
   * indexable operators appear in 'indexclauses', they are replaced by the
   * derived indexscannable conditions in 'indexquals'.
   *
+  * 'indexsortquals' is a list of actual conditions to order 
+  *
   * 'isjoininner' is TRUE if the path is a nestloop inner scan (that is,
   * some of the index conditions are join rather than restriction clauses).
   * Note that the path costs will be calculated differently from a plain
***************
*** 655,660 ****
--- 658,664 ----
  	IndexOptInfo *indexinfo;
  	List	   *indexclauses;
  	List	   *indexquals;
+ 	List	   *indexsortquals;
  	bool		isjoininner;
  	ScanDirection indexscandir;
  	Cost		indextotalcost;
diff -c -r -N src.orig/include/optimizer/pathnode.h src/include/optimizer/pathnode.h
*** src.orig/include/optimizer/pathnode.h	2010-01-12 21:42:48.000000000 +0300
--- src/include/optimizer/pathnode.h	2010-01-12 21:49:42.000000000 +0300
***************
*** 31,36 ****
--- 31,37 ----
  extern IndexPath *create_index_path(PlannerInfo *root,
  				  IndexOptInfo *index,
  				  List *clause_groups,
+ 				  List *sort_clauses,
  				  List *pathkeys,
  				  ScanDirection indexscandir,
  				  RelOptInfo *outer_rel);
diff -c -r -N src.orig/test/regress/expected/create_index.out src/test/regress/expected/create_index.out
*** src.orig/test/regress/expected/create_index.out	2010-01-12 21:42:50.000000000 +0300
--- src/test/regress/expected/create_index.out	2010-01-12 21:58:10.000000000 +0300
***************
*** 51,56 ****
--- 51,57 ----
  CREATE INDEX grect2ind ON fast_emp4000 USING gist (home_base);
  CREATE INDEX gpolygonind ON polygon_tbl USING gist (f1);
  CREATE INDEX gcircleind ON circle_tbl USING gist (f1);
+ INSERT INTO POINT_TBL(f1) VALUES (NULL);
  CREATE INDEX gpointind ON point_tbl USING gist (f1);
  CREATE TEMP TABLE gpolygon_tbl AS
      SELECT polygon(home_base) AS f1 FROM slow_emp4000;
***************
*** 167,172 ****
--- 168,211 ----
       1
  (1 row)
  
+ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+      f1     
+ ------------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+  (-5,-12)
+  (5.1,34.5)
+  
+ (7 rows)
+ 
+ SELECT * FROM point_tbl WHERE f1 IS NULL;
+  f1 
+ ----
+  
+ (1 row)
+ 
+ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+      f1     
+ ------------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+  (-5,-12)
+  (5.1,34.5)
+ (6 rows)
+ 
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+    f1    
+ ---------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+ (4 rows)
+ 
  SET enable_seqscan = OFF;
  SET enable_indexscan = ON;
  SET enable_bitmapscan = ON;
***************
*** 435,440 ****
--- 474,575 ----
       1
  (1 row)
  
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+                QUERY PLAN                
+ -----------------------------------------
+  Index Scan using gpointind on point_tbl
+    Sort Cond: (f1 <-> '(0,1)'::point)
+ (2 rows)
+ 
+ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+      f1     
+ ------------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+  (-5,-12)
+  (5.1,34.5)
+  
+ (7 rows)
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 IS NULL;
+                QUERY PLAN                
+ -----------------------------------------
+  Index Scan using gpointind on point_tbl
+    Index Cond: (f1 IS NULL)
+ (2 rows)
+ 
+ SELECT * FROM point_tbl WHERE f1 IS NULL;
+  f1 
+ ----
+  
+ (1 row)
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+                QUERY PLAN                
+ -----------------------------------------
+  Index Scan using gpointind on point_tbl
+    Index Cond: (f1 IS NOT NULL)
+    Sort Cond: (f1 <-> '(0,1)'::point)
+ (3 rows)
+ 
+ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+      f1     
+ ------------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+  (-5,-12)
+  (5.1,34.5)
+ (6 rows)
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+                    QUERY PLAN                   
+ ------------------------------------------------
+  Index Scan using gpointind on point_tbl
+    Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
+    Sort Cond: (f1 <-> '(0,1)'::point)
+ (3 rows)
+ 
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+    f1    
+ ---------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+ (4 rows)
+ 
+ SET enable_seqscan = OFF;
+ SET enable_indexscan = OFF;
+ SET enable_bitmapscan = ON;
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+                          QUERY PLAN                         
+ ------------------------------------------------------------
+  Sort
+    Sort Key: ((f1 <-> '(0,1)'::point))
+    ->  Bitmap Heap Scan on point_tbl
+          Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
+          ->  Bitmap Index Scan on gpointind
+                Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
+ (6 rows)
+ 
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+    f1    
+ ---------
+  (0,0)
+  (-3,4)
+  (-10,0)
+  (10,10)
+ (4 rows)
+ 
  RESET enable_seqscan;
  RESET enable_indexscan;
  RESET enable_bitmapscan;
diff -c -r -N src.orig/test/regress/sql/create_index.sql src/test/regress/sql/create_index.sql
*** src.orig/test/regress/sql/create_index.sql	2010-01-12 21:42:50.000000000 +0300
--- src/test/regress/sql/create_index.sql	2010-01-12 21:49:42.000000000 +0300
***************
*** 76,81 ****
--- 76,82 ----
  
  CREATE INDEX gcircleind ON circle_tbl USING gist (f1);
  
+ INSERT INTO POINT_TBL(f1) VALUES (NULL);
  CREATE INDEX gpointind ON point_tbl USING gist (f1);
  
  CREATE TEMP TABLE gpolygon_tbl AS
***************
*** 130,135 ****
--- 131,144 ----
  
  SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  
+ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+ 
+ SELECT * FROM point_tbl WHERE f1 IS NULL;
+ 
+ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+ 
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ 
  SET enable_seqscan = OFF;
  SET enable_indexscan = ON;
  SET enable_bitmapscan = ON;
***************
*** 206,211 ****
--- 215,244 ----
  SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
  
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 IS NULL;
+ SELECT * FROM point_tbl WHERE f1 IS NULL;
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ 
+ SET enable_seqscan = OFF;
+ SET enable_indexscan = OFF;
+ SET enable_bitmapscan = ON;
+ 
+ EXPLAIN (COSTS OFF)
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ 
  RESET enable_seqscan;
  RESET enable_indexscan;
  RESET enable_bitmapscan;
