88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.133 2004/12/31 21:59:45 pgsql Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.134 2005/02/10 20:36:27 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -832,22 +832,35 @@ SPI_cursor_open(const char *name, void *plan,
832832Portal portal ;
833833int k ;
834834
835- /* Ensure that the plan contains only oneregular SELECT query */
835+ /* Ensure that the plan contains only one query */
836836if (list_length (ptlist )!= 1 || list_length (qtlist )!= 1 )
837837ereport (ERROR ,
838838(errcode (ERRCODE_INVALID_CURSOR_DEFINITION ),
839839errmsg ("cannot open multi-query plan as cursor" )));
840840queryTree = (Query * )linitial ((List * )linitial (qtlist ));
841841planTree = (Plan * )linitial (ptlist );
842842
843- if (queryTree -> commandType != CMD_SELECT )
844- ereport (ERROR ,
845- (errcode (ERRCODE_INVALID_CURSOR_DEFINITION ),
846- errmsg ("cannot open non-SELECT query as cursor" )));
847- if (queryTree -> into != NULL )
848- ereport (ERROR ,
849- (errcode (ERRCODE_INVALID_CURSOR_DEFINITION ),
850- errmsg ("cannot open SELECT INTO query as cursor" )));
843+ /* Must be a query that returns tuples */
844+ switch (queryTree -> commandType )
845+ {
846+ case CMD_SELECT :
847+ if (queryTree -> into != NULL )
848+ ereport (ERROR ,
849+ (errcode (ERRCODE_INVALID_CURSOR_DEFINITION ),
850+ errmsg ("cannot open SELECT INTO query as cursor" )));
851+ break ;
852+ case CMD_UTILITY :
853+ if (!UtilityReturnsTuples (queryTree -> utilityStmt ))
854+ ereport (ERROR ,
855+ (errcode (ERRCODE_INVALID_CURSOR_DEFINITION ),
856+ errmsg ("cannot open non-SELECT query as cursor" )));
857+ break ;
858+ default :
859+ ereport (ERROR ,
860+ (errcode (ERRCODE_INVALID_CURSOR_DEFINITION ),
861+ errmsg ("cannot open non-SELECT query as cursor" )));
862+ break ;
863+ }
851864
852865/* Reset SPI result */
853866SPI_processed = 0 ;
@@ -911,7 +924,7 @@ SPI_cursor_open(const char *name, void *plan,
911924 */
912925PortalDefineQuery (portal ,
913926NULL ,/* unfortunately don't have sourceText */
914- "SELECT" ,/*cursor's query is always a SELECT */
927+ "SELECT" ,/*nor the raw parse tree... */
915928list_make1 (queryTree ),
916929list_make1 (planTree ),
917930PortalGetHeapMemory (portal ));
@@ -922,7 +935,7 @@ SPI_cursor_open(const char *name, void *plan,
922935 * Set up options for portal.
923936 */
924937portal -> cursorOptions &= ~(CURSOR_OPT_SCROLL |CURSOR_OPT_NO_SCROLL );
925- if (ExecSupportsBackwardScan (plan ))
938+ if (planTree == NULL || ExecSupportsBackwardScan (planTree ))
926939portal -> cursorOptions |=CURSOR_OPT_SCROLL ;
927940else
928941portal -> cursorOptions |=CURSOR_OPT_NO_SCROLL ;
@@ -944,7 +957,8 @@ SPI_cursor_open(const char *name, void *plan,
944957 */
945958PortalStart (portal ,paramLI ,snapshot );
946959
947- Assert (portal -> strategy == PORTAL_ONE_SELECT );
960+ Assert (portal -> strategy == PORTAL_ONE_SELECT ||
961+ portal -> strategy == PORTAL_UTIL_SELECT );
948962
949963/* Return the created portal */
950964return portal ;