mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Create hooks to let a loadable plugin monitor (or even replace) the planner
and/or create plans for hypothetical situations; in particular, investigate plans that would be generated using hypothetical indexes. This is a heavily-rewritten version of the hooks proposed by Gurjeet Singh for his Index Advisor project. In this formulation, the index advisor can be entirely a loadable module instead of requiring a significant part to be in the core backend, and plans can be generated for hypothetical indexes without requiring the creation and rolling-back of system catalog entries. The index advisor patch as-submitted is not compatible with these hooks, but it needs significant work anyway due to other 8.2-to-8.3 planner changes. With these hooks in the core backend, development of the advisor can proceed as a pgfoundry project.
This commit is contained in:
		
							parent
							
								
									ce5b24abed
								
							
						
					
					
						commit
						604ffd280b
					
				| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1994-5, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.163 2007/05/04 21:29:52 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.164 2007/05/25 17:54:24 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -33,6 +33,12 @@ | ||||
| #include "utils/tuplesort.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Hook for plugins to get control in ExplainOneQuery() */ | ||||
| ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL; | ||||
| /* Hook for plugins to get control in explain_get_index_name() */ | ||||
| explain_get_index_name_hook_type explain_get_index_name_hook = NULL; | ||||
| 
 | ||||
| 
 | ||||
| typedef struct ExplainState | ||||
| { | ||||
| 	/* options */ | ||||
| @ -61,6 +67,8 @@ static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, | ||||
| 			   StringInfo str, int indent, ExplainState *es); | ||||
| static void show_sort_info(SortState *sortstate, | ||||
| 			   StringInfo str, int indent, ExplainState *es); | ||||
| static const char *explain_get_index_name(Oid indexId); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * ExplainQuery - | ||||
| @ -140,9 +148,6 @@ static void | ||||
| ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString, | ||||
| 				ParamListInfo params, TupOutputState *tstate) | ||||
| { | ||||
| 	PlannedStmt *plan; | ||||
| 	QueryDesc  *queryDesc; | ||||
| 
 | ||||
| 	/* planner will not cope with utility statements */ | ||||
| 	if (query->commandType == CMD_UTILITY) | ||||
| 	{ | ||||
| @ -151,25 +156,19 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString, | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* plan the query */ | ||||
| 	plan = planner(query, 0, params); | ||||
| 	/* if an advisor plugin is present, let it manage things */ | ||||
| 	if (ExplainOneQuery_hook) | ||||
| 		(*ExplainOneQuery_hook) (query, stmt, queryString, params, tstate); | ||||
| 	else | ||||
| 	{ | ||||
| 		PlannedStmt *plan; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Update snapshot command ID to ensure this query sees results of any | ||||
| 	 * previously executed queries.  (It's a bit cheesy to modify | ||||
| 	 * ActiveSnapshot without making a copy, but for the limited ways in which | ||||
| 	 * EXPLAIN can be invoked, I think it's OK, because the active snapshot | ||||
| 	 * shouldn't be shared with anything else anyway.) | ||||
| 	 */ | ||||
| 	ActiveSnapshot->curcid = GetCurrentCommandId(); | ||||
| 		/* plan the query */ | ||||
| 		plan = planner(query, 0, params); | ||||
| 
 | ||||
| 	/* Create a QueryDesc requesting no output */ | ||||
| 	queryDesc = CreateQueryDesc(plan, | ||||
| 								ActiveSnapshot, InvalidSnapshot, | ||||
| 								None_Receiver, params, | ||||
| 								stmt->analyze); | ||||
| 
 | ||||
| 	ExplainOnePlan(queryDesc, stmt, tstate); | ||||
| 		/* run it (if needed) and produce output */ | ||||
| 		ExplainOnePlan(plan, params, stmt, tstate); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -210,20 +209,35 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt, | ||||
|  * not running the query.  No cursor will be created, however. | ||||
|  * | ||||
|  * This is exported because it's called back from prepare.c in the | ||||
|  * EXPLAIN EXECUTE case | ||||
|  * | ||||
|  * Note: the passed-in QueryDesc is freed when we're done with it | ||||
|  * EXPLAIN EXECUTE case, and because an index advisor plugin would need | ||||
|  * to call it. | ||||
|  */ | ||||
| void | ||||
| ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt, | ||||
| 			   TupOutputState *tstate) | ||||
| ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params, | ||||
| 			   ExplainStmt *stmt, TupOutputState *tstate) | ||||
| { | ||||
| 	QueryDesc  *queryDesc; | ||||
| 	instr_time	starttime; | ||||
| 	double		totaltime = 0; | ||||
| 	ExplainState *es; | ||||
| 	StringInfoData buf; | ||||
| 	int			eflags; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Update snapshot command ID to ensure this query sees results of any | ||||
| 	 * previously executed queries.  (It's a bit cheesy to modify | ||||
| 	 * ActiveSnapshot without making a copy, but for the limited ways in which | ||||
| 	 * EXPLAIN can be invoked, I think it's OK, because the active snapshot | ||||
| 	 * shouldn't be shared with anything else anyway.) | ||||
| 	 */ | ||||
| 	ActiveSnapshot->curcid = GetCurrentCommandId(); | ||||
| 
 | ||||
| 	/* Create a QueryDesc requesting no output */ | ||||
| 	queryDesc = CreateQueryDesc(plannedstmt, | ||||
| 								ActiveSnapshot, InvalidSnapshot, | ||||
| 								None_Receiver, params, | ||||
| 								stmt->analyze); | ||||
| 
 | ||||
| 	INSTR_TIME_SET_CURRENT(starttime); | ||||
| 
 | ||||
| 	/* If analyzing, we need to cope with queued triggers */ | ||||
| @ -592,7 +606,7 @@ explain_outNode(StringInfo str, | ||||
| 			if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir)) | ||||
| 				appendStringInfoString(str, " Backward"); | ||||
| 			appendStringInfo(str, " using %s", | ||||
| 			  quote_identifier(get_rel_name(((IndexScan *) plan)->indexid))); | ||||
| 					explain_get_index_name(((IndexScan *) plan)->indexid)); | ||||
| 			/* FALL THRU */ | ||||
| 		case T_SeqScan: | ||||
| 		case T_BitmapHeapScan: | ||||
| @ -618,7 +632,7 @@ explain_outNode(StringInfo str, | ||||
| 			break; | ||||
| 		case T_BitmapIndexScan: | ||||
| 			appendStringInfo(str, " on %s", | ||||
| 							 quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indexid))); | ||||
| 				explain_get_index_name(((BitmapIndexScan *) plan)->indexid)); | ||||
| 			break; | ||||
| 		case T_SubqueryScan: | ||||
| 			if (((Scan *) plan)->scanrelid > 0) | ||||
| @ -1150,3 +1164,29 @@ show_sort_info(SortState *sortstate, | ||||
| 		pfree(sortinfo); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Fetch the name of an index in an EXPLAIN | ||||
|  * | ||||
|  * We allow plugins to get control here so that plans involving hypothetical | ||||
|  * indexes can be explained. | ||||
|  */ | ||||
| static const char * | ||||
| explain_get_index_name(Oid indexId) | ||||
| { | ||||
| 	const char   *result; | ||||
| 
 | ||||
| 	if (explain_get_index_name_hook) | ||||
| 		result = (*explain_get_index_name_hook) (indexId); | ||||
| 	else | ||||
| 		result = NULL; | ||||
| 	if (result == NULL) | ||||
| 	{ | ||||
| 		/* default behavior: look in the catalogs and quote it */ | ||||
| 		result = get_rel_name(indexId); | ||||
| 		if (result == NULL) | ||||
| 			elog(ERROR, "cache lookup failed for index %u", indexId); | ||||
| 		result = quote_identifier(result); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
|  * Copyright (c) 2002-2007, PostgreSQL Global Development Group | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.75 2007/04/27 22:05:47 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.76 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -678,8 +678,6 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt, | ||||
| 
 | ||||
| 		if (IsA(pstmt, PlannedStmt)) | ||||
| 		{ | ||||
| 			QueryDesc  *qdesc; | ||||
| 
 | ||||
| 			if (execstmt->into) | ||||
| 			{ | ||||
| 				if (pstmt->commandType != CMD_SELECT || | ||||
| @ -694,22 +692,7 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt, | ||||
| 				pstmt->intoClause = execstmt->into; | ||||
| 			} | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * Update snapshot command ID to ensure this query sees results of | ||||
| 			 * any previously executed queries.  (It's a bit cheesy to modify | ||||
| 			 * ActiveSnapshot without making a copy, but for the limited ways | ||||
| 			 * in which EXPLAIN can be invoked, I think it's OK, because the | ||||
| 			 * active snapshot shouldn't be shared with anything else anyway.) | ||||
| 			 */ | ||||
| 			ActiveSnapshot->curcid = GetCurrentCommandId(); | ||||
| 
 | ||||
| 			/* Create a QueryDesc requesting no output */ | ||||
| 			qdesc = CreateQueryDesc(pstmt, | ||||
| 									ActiveSnapshot, InvalidSnapshot, | ||||
| 									None_Receiver, | ||||
| 									paramLI, stmt->analyze); | ||||
| 
 | ||||
| 			ExplainOnePlan(qdesc, stmt, tstate); | ||||
| 			ExplainOnePlan(pstmt, paramLI, stmt, tstate); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.22 2007/01/05 22:19:28 momjian Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.23 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -198,10 +198,12 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node) | ||||
| #endif | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * close the index relation | ||||
| 	 * close the index relation (no-op if we didn't open it) | ||||
| 	 */ | ||||
| 	index_endscan(indexScanDesc); | ||||
| 	index_close(indexRelationDesc, NoLock); | ||||
| 	if (indexScanDesc) | ||||
| 		index_endscan(indexScanDesc); | ||||
| 	if (indexRelationDesc) | ||||
| 		index_close(indexRelationDesc, NoLock); | ||||
| } | ||||
| 
 | ||||
| /* ----------------------------------------------------------------
 | ||||
| @ -256,6 +258,14 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) | ||||
| 	indexstate->ss.ss_currentRelation = NULL; | ||||
| 	indexstate->ss.ss_currentScanDesc = NULL; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If we are just doing EXPLAIN (ie, aren't going to run the plan), | ||||
| 	 * stop here.  This allows an index-advisor plugin to EXPLAIN a plan | ||||
| 	 * containing references to nonexistent indexes. | ||||
| 	 */ | ||||
| 	if (eflags & EXEC_FLAG_EXPLAIN_ONLY) | ||||
| 		return indexstate; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Open the index relation. | ||||
| 	 * | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.121 2007/04/06 22:33:42 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.122 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -415,10 +415,12 @@ ExecEndIndexScan(IndexScanState *node) | ||||
| 	ExecClearTuple(node->ss.ss_ScanTupleSlot); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * close the index relation | ||||
| 	 * close the index relation (no-op if we didn't open it) | ||||
| 	 */ | ||||
| 	index_endscan(indexScanDesc); | ||||
| 	index_close(indexRelationDesc, NoLock); | ||||
| 	if (indexScanDesc) | ||||
| 		index_endscan(indexScanDesc); | ||||
| 	if (indexRelationDesc) | ||||
| 		index_close(indexRelationDesc, NoLock); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * close the heap relation. | ||||
| @ -520,6 +522,14 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) | ||||
| 	 */ | ||||
| 	ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If we are just doing EXPLAIN (ie, aren't going to run the plan), | ||||
| 	 * stop here.  This allows an index-advisor plugin to EXPLAIN a plan | ||||
| 	 * containing references to nonexistent indexes. | ||||
| 	 */ | ||||
| 	if (eflags & EXEC_FLAG_EXPLAIN_ONLY) | ||||
| 		return indexstate; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Open the index relation. | ||||
| 	 * | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.219 2007/05/04 01:13:44 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.220 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -42,6 +42,10 @@ | ||||
| #include "utils/syscache.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Hook for plugins to get control in planner() */ | ||||
| planner_hook_type planner_hook = NULL; | ||||
| 
 | ||||
| 
 | ||||
| /* Expression kind codes for preprocess_expression */ | ||||
| #define EXPRKIND_QUAL		0 | ||||
| #define EXPRKIND_TARGET		1 | ||||
| @ -79,9 +83,29 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist); | ||||
|  * | ||||
|  *	   Query optimizer entry point | ||||
|  * | ||||
|  * To support loadable plugins that monitor or modify planner behavior, | ||||
|  * we provide a hook variable that lets a plugin get control before and | ||||
|  * after the standard planning process.  The plugin would normally call | ||||
|  * standard_planner(). | ||||
|  * | ||||
|  * Note to plugin authors: standard_planner() scribbles on its Query input, | ||||
|  * so you'd better copy that data structure if you want to plan more than once. | ||||
|  * | ||||
|  *****************************************************************************/ | ||||
| PlannedStmt * | ||||
| planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||||
| { | ||||
| 	PlannedStmt *result; | ||||
| 
 | ||||
| 	if (planner_hook) | ||||
| 		result = (*planner_hook) (parse, cursorOptions, boundParams); | ||||
| 	else | ||||
| 		result = standard_planner(parse, cursorOptions, boundParams); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| PlannedStmt * | ||||
| standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) | ||||
| { | ||||
| 	PlannedStmt *result; | ||||
| 	PlannerGlobal *glob; | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.134 2007/04/21 21:01:45 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.135 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -40,6 +40,9 @@ | ||||
| /* GUC parameter */ | ||||
| bool		constraint_exclusion = false; | ||||
| 
 | ||||
| /* Hook for plugins to get control in get_relation_info() */ | ||||
| get_relation_info_hook_type get_relation_info_hook = NULL; | ||||
| 
 | ||||
| 
 | ||||
| static void estimate_rel_size(Relation rel, int32 *attr_widths, | ||||
| 				  BlockNumber *pages, double *tuples); | ||||
| @ -279,6 +282,14 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, | ||||
| 	rel->indexlist = indexinfos; | ||||
| 
 | ||||
| 	heap_close(relation, NoLock); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Allow a plugin to editorialize on the info we obtained from the | ||||
| 	 * catalogs.  Actions might include altering the assumed relation size, | ||||
| 	 * removing an index, or adding a hypothetical index to the indexlist. | ||||
| 	 */ | ||||
| 	if (get_relation_info_hook) | ||||
| 		(*get_relation_info_hook) (root, relationObjectId, inhparent, rel); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994-5, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.30 2007/03/13 00:33:43 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.31 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -15,6 +15,18 @@ | ||||
| 
 | ||||
| #include "executor/executor.h" | ||||
| 
 | ||||
| /* Hook for plugins to get control in ExplainOneQuery() */ | ||||
| typedef void (*ExplainOneQuery_hook_type) (Query *query, | ||||
| 										   ExplainStmt *stmt, | ||||
| 										   const char *queryString, | ||||
| 										   ParamListInfo params, | ||||
| 										   TupOutputState *tstate); | ||||
| extern DLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook; | ||||
| 
 | ||||
| /* Hook for plugins to get control in explain_get_index_name() */ | ||||
| typedef const char * (*explain_get_index_name_hook_type) (Oid indexId); | ||||
| extern DLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook; | ||||
| 
 | ||||
| 
 | ||||
| extern void ExplainQuery(ExplainStmt *stmt, const char *queryString, | ||||
| 						 ParamListInfo params, DestReceiver *dest); | ||||
| @ -26,7 +38,7 @@ extern void ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt, | ||||
| 							  ParamListInfo params, | ||||
| 							  TupOutputState *tstate); | ||||
| 
 | ||||
| extern void ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt, | ||||
| 			   TupOutputState *tstate); | ||||
| extern void ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params, | ||||
| 						   ExplainStmt *stmt, TupOutputState *tstate); | ||||
| 
 | ||||
| #endif   /* EXPLAIN_H */ | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.43 2007/01/05 22:19:56 momjian Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.44 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -16,6 +16,13 @@ | ||||
| 
 | ||||
| #include "nodes/relation.h" | ||||
| 
 | ||||
| /* Hook for plugins to get control in get_relation_info() */ | ||||
| typedef void (*get_relation_info_hook_type) (PlannerInfo *root, | ||||
| 											 Oid relationObjectId, | ||||
| 											 bool inhparent, | ||||
| 											 RelOptInfo *rel); | ||||
| extern DLLIMPORT get_relation_info_hook_type get_relation_info_hook; | ||||
| 
 | ||||
| 
 | ||||
| extern void get_relation_info(PlannerInfo *root, Oid relationObjectId, | ||||
| 				  bool inhparent, RelOptInfo *rel); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.39 2007/04/16 01:14:58 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.40 2007/05/25 17:54:25 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -18,8 +18,17 @@ | ||||
| #include "nodes/relation.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Hook for plugins to get control in planner() */ | ||||
| typedef PlannedStmt * (*planner_hook_type) (Query *parse, | ||||
| 											int cursorOptions, | ||||
| 											ParamListInfo boundParams); | ||||
| extern DLLIMPORT planner_hook_type planner_hook; | ||||
| 
 | ||||
| 
 | ||||
| extern PlannedStmt *planner(Query *parse, int cursorOptions, | ||||
| 		ParamListInfo boundParams); | ||||
| extern PlannedStmt *standard_planner(Query *parse, int cursorOptions, | ||||
| 		ParamListInfo boundParams); | ||||
| extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse, | ||||
| 							  Index level, double tuple_fraction, | ||||
| 							  PlannerInfo **subroot); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user