ANALYZE command

Started by Fernando Nasserover 25 years ago5 messagespatches
Jump to latest
#1Fernando Nasser
fnasser@redhat.com

This patch is a follow-up to the split of the vacuum and analyze (done by Bruce Momjian last year).

It adds a separate SQL extension command ANALYZE that will only perform the analyze part and thus only use shared locks.

I will submit the doc and test changes in a separate patch, if you decide that we are really going ahead with the ANALYZE command.

This version still does not update pg_class. Those statistics are still tied in the vacuum part (num. of pages, tuples and indication if the relation has an index). The patch allows for analyze_rel() to work differently if run as part of a VACUUM or as an standalone ANALYZE, so the missing bits can be added without changes to the current behavior of VACUUM ANALYZE.

Possible future improvements:

1) Add the pg_class update to ANALYZE;

2) Add a VERBOSE option that prints information to gives the DBA a hint if it is worth of running VACUUM or not.

Thanks.

--
Fernando Nasser
Red Hat Inc. E-Mail: fnasser@redhat.com

Attachments:

ANALYZE.PATCHtext/plain; charset=us-ascii; name=ANALYZE.PATCHDownload+255-51
#2Fernando Nasser
fnasser@redhat.com
In reply to: Fernando Nasser (#1)
ANALYZE command [REPOST]

[My apologies: I forgot to tell to which sources the patch applies, as required and, which is worse, I attached the wrong patch; I have corrected it now.]

This patch is a follow-up to the split of the vacuum and analyze (done by Bruce Momjian last year). I applies to today's CVS sources.

It adds a separate SQL extension command ANALYZE that will only perform the analyze part and thus only use shared locks.

I will submit the doc and test changes in a separate patch, if you decide that we are really going ahead with the ANALYZE command.

This version still does not update pg_class. Those statistics are still tied in the vacuum part (num. of pages, tuples and indication if the relation has an index). The patch allows for analyze_rel() to work differently if run as part of a VACUUM or as an standalone ANALYZE, so the missing bits can be added without changes to the current
behavior of VACUUM ANALYZE.

Possible future improvements:

1) Add the pg_class update to ANALYZE;

2) Add a VERBOSE option that prints information to gives the DBA a hint if it is worth of running VACUUM or not.

Thanks.

--
Fernando Nasser
Red Hat Inc. E-Mail: fnasser@redhat.com

Attachments:

ANALYZE.PATCHtext/plain; charset=us-ascii; name=ANALYZE.PATCHDownload+259-55
#3Bruce Momjian
bruce@momjian.us
In reply to: Fernando Nasser (#2)
Re: ANALYZE command [REPOST]

I will keep this for possible inclusing in 7.2. Thanks.

[My apologies: I forgot to tell to which sources the patch applies, as required and, which is worse, I attached the wrong patch; I have corrected it now.]

This patch is a follow-up to the split of the vacuum and analyze (done by Bruce Momjian last year). I applies to today's CVS sources.

It adds a separate SQL extension command ANALYZE that will only perform the analyze part and thus only use shared locks.

I will submit the doc and test changes in a separate patch, if you decide that we are really going ahead with the ANALYZE command.

This version still does not update pg_class. Those statistics are still tied in the vacuum part (num. of pages, tuples and indication if the relation has an index). The patch allows for analyze_rel() to work differently if run as part of a VACUUM or as an standalone ANALYZE, so the missing bits can be added without changes to the current
behavior of VACUUM ANALYZE.

Possible future improvements:

1) Add the pg_class update to ANALYZE;

2) Add a VERBOSE option that prints information to gives the DBA a hint if it is worth of running VACUUM or not.

Thanks.

--
Fernando Nasser
Red Hat Inc. E-Mail: fnasser@redhat.com

Index: src/backend/commands/analyze.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/commands/analyze.c,v
retrieving revision 1.16
diff -c -p -r1.16 analyze.c
*** src/backend/commands/analyze.c	2001/03/22 06:16:11	1.16
--- src/backend/commands/analyze.c	2001/04/24 22:22:24
***************
*** 35,41 ****
--- 35,46 ----
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/syscache.h"
+ #include "utils/temprel.h"
+ static MemoryContext vac_context = NULL;
+ 
+ static int	MESSAGE_LEVEL;		/* message level */
+ 
#define swapLong(a,b)	{long tmp; tmp=a; a=b; b=tmp;}
#define swapInt(a,b)	{int tmp; tmp=a; a=b; b=tmp;}
#define swapDatum(a,b)	{Datum tmp; tmp=a; a=b; b=tmp;}
*************** static void attr_stats(Relation onerel, 
*** 49,61 ****
static void bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len);
static void update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats);
static void del_stats(Oid relid, int attcnt, int *attnums);
/*
*	analyze_rel() -- analyze relation
*/
void
! analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
{
HeapTuple	tuple;
Relation	onerel;
--- 54,175 ----
static void bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len);
static void update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats);
static void del_stats(Oid relid, int attcnt, int *attnums);
+ static void do_analyze(NameData *VacRelP, List *anal_cols2);
+ static void analyze_rel_1(Oid relid, List *anal_cols2, int vacuum);
+ 
+ 
+ void
+ analyze(char *vacrel, List *anal_cols)
+ {
+ 	NameData	VacRel;
+ 	Name		VacRelName;
+ 	MemoryContext old;
+ 	List	   *le;
+ 	List	   *anal_cols2 = NIL;
+ 
+ 	/*
+ 	 * We cannot run ANALYZE inside a user transaction block; if we were
+ 	 * inside a transaction, then our commit- and
+ 	 * start-transaction-command calls would not have the intended effect!
+ 	 */
+ 	if (IsTransactionBlock())
+ 		elog(ERROR, "ANALYZE cannot run inside a BEGIN/END block");
+ 
+ 	MESSAGE_LEVEL = DEBUG;
+ 	/*
+ 	 * Create special memory context for cross-transaction storage.
+ 	 *
+ 	 * Since it is a child of QueryContext, it will go away eventually even
+ 	 * if we suffer an error; there's no need for special abort cleanup
+ 	 * logic.
+ 	 */
+ 	vac_context = AllocSetContextCreate(QueryContext,
+ 										"Analyze",
+ 										ALLOCSET_DEFAULT_MINSIZE,
+ 										ALLOCSET_DEFAULT_INITSIZE,
+ 										ALLOCSET_DEFAULT_MAXSIZE);
+ 
+ 	/* vacrel gets de-allocated on xact commit, so copy it to safe storage */
+ 	if (vacrel)
+ 	{
+ 		namestrcpy(&VacRel, vacrel);
+ 		VacRelName = &VacRel;
+ 	}
+ 	else
+ 		VacRelName = NULL;
+ 	/* must also copy the column list, if any, to safe storage */
+ 	old = MemoryContextSwitchTo(vac_context);
+ 	foreach(le, anal_cols)
+ 	{
+ 		char	   *col = (char *) lfirst(le);
+ 
+ 		anal_cols2 = lappend(anal_cols2, pstrdup(col));
+ 	}
+ 	MemoryContextSwitchTo(old);
+ 
+ 	/*
+ 	 * Start up the analyzer.
+ 	 *
+ 	 * NOTE: since this commits the current transaction, the memory holding
+ 	 * any passed-in parameters gets freed here.  We must have already
+ 	 * copied pass-by-reference parameters to safe storage.  Don't make me
+ 	 * fix this again!
+ 	 */
+ 	vacuum_init();
+ 
+ 	/* analyze the database */
+ 	do_analyze(VacRelName, anal_cols2);
+ 
+ 	vacuum_shutdown(vac_context);
+ }
+ 
/*
+  *	do_analyze() -- analyze the database.
+  *
+  *		This routine builds a list of relations to analyze, and then calls
+  *		code that analyze them one at a time.
+  */
+ static void
+ do_analyze(NameData *VacRelP, List *anal_cols2)
+ {
+ 	VRelList	vrl,
+ 				cur;
+ 
+ 	/* get list of relations */
+ 	vrl = vacuum_getrels(VacRelP, vac_context);
+ 
+ 	/* analyze each heap relation */
+ 	for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
+ 	{
+ 		analyze_rel_1(cur->vrl_relid, anal_cols2, 0 /* not vacuum */);
+ 	}
+ }
+ 
+ /*
*	analyze_rel() -- analyze relation
+  *	
+  *	Called through here when doing vacuum
*/
void
! analyze_rel(Oid relid, List *anal_cols2, int msg_level)
! {
! 	/*
! 	 * Use the MESSAGE_LEVEL as set on vacuum.
! 	 */
! 	MESSAGE_LEVEL = msg_level;
! 	analyze_rel_1(relid, anal_cols2, 1 /* vacuum */);
! }
! 
! /*
!  *	analyze_rel_1() -- analyze relation
!  *	
!  *	Do the job for ANALYZE or VACUUM ANALYSE in one relation
!  */
! 
! static void
! analyze_rel_1(Oid relid, List *anal_cols2, int vacuum)
{
HeapTuple	tuple;
Relation	onerel;
*************** analyze_rel(Oid relid, List *anal_cols2,
*** 107,116 ****
{
/*
! 		 * we already did an elog during vacuum elog(NOTICE, "Skipping
! 		 * \"%s\" --- only table owner can VACUUM it",
! 		 * RelationGetRelationName(onerel));
*/
heap_close(onerel, NoLock);
CommitTransactionCommand();
return;
--- 221,231 ----
{
/*
! 		 * we already did an elog during vacuum 
*/
+ 		if (!vacuum)
+ 			elog(NOTICE, "Skipping \"%s\" --- only table owner can ANALYZE it",
+ 			     RelationGetRelationName(onerel));
heap_close(onerel, NoLock);
CommitTransactionCommand();
return;
*************** analyze_rel(Oid relid, List *anal_cols2,
*** 127,133 ****
List	   *le;
if (length(anal_cols2) > attr_cnt)
! 			elog(ERROR, "vacuum: too many attributes specified for relation %s",
RelationGetRelationName(onerel));
attnums = (int *) palloc(attr_cnt * sizeof(int));
foreach(le, anal_cols2)
--- 242,248 ----
List	   *le;
if (length(anal_cols2) > attr_cnt)
! 			elog(ERROR, "analyze: too many attributes specified for relation %s",
RelationGetRelationName(onerel));
attnums = (int *) palloc(attr_cnt * sizeof(int));
foreach(le, anal_cols2)
*************** analyze_rel(Oid relid, List *anal_cols2,
*** 143,149 ****
attnums[tcnt++] = i;
else
{
! 				elog(ERROR, "vacuum: there is no attribute %s in %s",
col, RelationGetRelationName(onerel));
}
}
--- 258,264 ----
attnums[tcnt++] = i;
else
{
! 				elog(ERROR, "analyze: there is no attribute %s in %s",
col, RelationGetRelationName(onerel));
}
}
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.189
diff -c -p -r1.189 vacuum.c
*** src/backend/commands/vacuum.c	2001/03/25 23:23:58	1.189
--- src/backend/commands/vacuum.c	2001/04/24 22:22:25
*************** static int	MESSAGE_LEVEL;		/* message le
*** 60,69 ****
static TransactionId XmaxRecent;
/* non-export function prototypes */
- static void vacuum_init(void);
- static void vacuum_shutdown(void);
static void vac_vacuum(NameData *VacRelP, bool analyze, List *anal_cols2);
- static VRelList getrels(NameData *VacRelP);
static void vacuum_rel(Oid relid);
static void scan_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages, VacPageList fraged_pages);
static void repair_frag(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages, VacPageList fraged_pages, int nindices, Relation *Irel);
--- 60,66 ----
*************** vacuum(char *vacrel, bool verbose, bool 
*** 163,169 ****
vac_vacuum(VacRelName, analyze, anal_cols2);

/* clean up */
! vacuum_shutdown();
}

/*
--- 160,166 ----
vac_vacuum(VacRelName, analyze, anal_cols2);

/* clean up */
! vacuum_shutdown(vac_context);
}

/*
*************** vacuum(char *vacrel, bool verbose, bool
*** 186,200 ****
* vacuum_shutdown() to match the commit waiting for us back in
* PostgresMain().
*/
! static void
vacuum_init()
{
/* matches the StartTransaction in PostgresMain() */
CommitTransactionCommand();
}

! static void
! vacuum_shutdown()
{
/* on entry, we are not in a transaction */

--- 183,197 ----
*		vacuum_shutdown() to match the commit waiting for us back in
*		PostgresMain().
*/
! void
vacuum_init()
{
/* matches the StartTransaction in PostgresMain() */
CommitTransactionCommand();
}

! void
! vacuum_shutdown(MemoryContext context)
{
/* on entry, we are not in a transaction */

*************** vacuum_shutdown()
*** 218,224 ****
* StartTransactionCommand, else we might be trying to delete the
* active context!
*/
! MemoryContextDelete(vac_context);
vac_context = NULL;
}

--- 215,221 ----
* StartTransactionCommand, else we might be trying to delete the
* active context!
*/
! 	MemoryContextDelete(context);
vac_context = NULL;
}

*************** vac_vacuum(NameData *VacRelP, bool analy
*** 237,243 ****
cur;

/* get list of relations */
! vrl = getrels(VacRelP);

/* vacuum each heap relation */
for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
--- 234,240 ----
cur;

/* get list of relations */
! vrl = vacuum_getrels(VacRelP, vac_context);

/* vacuum each heap relation */
for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
*************** vac_vacuum(NameData *VacRelP, bool analy
*** 249,256 ****
}
}

! static VRelList
! getrels(NameData *VacRelP)
{
Relation	rel;
TupleDesc	tupdesc;
--- 246,253 ----
}
}

! VRelList
! vacuum_getrels(NameData *VacRelP, MemoryContext context)
{
Relation rel;
TupleDesc tupdesc;
*************** getrels(NameData *VacRelP)
*** 317,327 ****
/* get a relation list entry for this guy */
if (vrl == (VRelList) NULL)
vrl = cur = (VRelList)
! MemoryContextAlloc(vac_context, sizeof(VRelListData));
else
{
cur->vrl_next = (VRelList)
! MemoryContextAlloc(vac_context, sizeof(VRelListData));
cur = cur->vrl_next;
}

--- 314,324 ----
/* get a relation list entry for this guy */
if (vrl == (VRelList) NULL)
vrl = cur = (VRelList)
! 				MemoryContextAlloc(context, sizeof(VRelListData));
else
{
cur->vrl_next = (VRelList)
! 				MemoryContextAlloc(context, sizeof(VRelListData));
cur = cur->vrl_next;
}
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.140
diff -c -p -r1.140 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	2001/03/22 06:16:14	1.140
--- src/backend/nodes/copyfuncs.c	2001/04/24 22:22:25
*************** _copyVacuumStmt(VacuumStmt *from)
*** 2218,2223 ****
--- 2218,2235 ----
return newnode;
}
+ static AnalyzeStmt *
+ _copyAnalyzeStmt(AnalyzeStmt *from)
+ {
+ 	AnalyzeStmt *newnode = makeNode(AnalyzeStmt);
+ 
+ 	if (from->anarel)
+ 		newnode->anarel = pstrdup(from->anarel);
+ 	Node_Copy(from, newnode, va_spec);
+ 
+ 	return newnode;
+ }
+ 
static ExplainStmt *
_copyExplainStmt(ExplainStmt *from)
{
*************** copyObject(void *from)
*** 2780,2785 ****
--- 2792,2800 ----
break;
case T_RemoveOperStmt:
retval = _copyRemoveOperStmt(from);
+ 			break;
+ 		case T_AnalyzeStmt:
+ 			retval = _copyAnalyzeStmt(from);
break;
case T_RenameStmt:
retval = _copyRenameStmt(from);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.88
diff -c -p -r1.88 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	2001/03/22 03:59:31	1.88
--- src/backend/nodes/equalfuncs.c	2001/04/24 22:22:25
*************** _equalVacuumStmt(VacuumStmt *a, VacuumSt
*** 1126,1131 ****
--- 1126,1142 ----
}
static bool
+ _equalAnalyzeStmt(AnalyzeStmt *a, AnalyzeStmt *b)
+ {
+ 	if (!equalstr(a->anarel, b->anarel))
+ 		return false;
+ 	if (!equal(a->va_spec, b->va_spec))
+ 		return false;
+ 
+ 	return true;
+ }
+ 
+ static bool
_equalExplainStmt(ExplainStmt *a, ExplainStmt *b)
{
if (!equal(a->query, b->query))
*************** equal(void *a, void *b)
*** 1946,1951 ****
--- 1957,1965 ----
break;
case T_RemoveOperStmt:
retval = _equalRemoveOperStmt(a, b);
+ 			break;
+ 		case T_AnalyzeStmt:
+ 			retval = _equalAnalyzeStmt(a, b);
break;
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.221
diff -c -p -r2.221 gram.y
*** src/backend/parser/gram.y	2001/02/18 18:06:10	2.221
--- src/backend/parser/gram.y	2001/04/24 22:22:26
*************** static void doNegateFloat(Value *v);
*** 130,135 ****
--- 130,136 ----

%type <node> stmt,
AlterGroupStmt, AlterSchemaStmt, AlterTableStmt, AlterUserStmt,
+ AnalyzeStmt, CheckPointStmt,
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
*************** static void doNegateFloat(Value *v);
*** 142,148 ****
RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
RuleStmt, SelectStmt, TransactionStmt, TruncateStmt,
UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt,
! VariableSetStmt, VariableShowStmt, ViewStmt, CheckPointStmt

%type <node>	select_no_parens, select_with_parens, select_clause,
simple_select
--- 143,149 ----
RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
RuleStmt, SelectStmt, TransactionStmt, TruncateStmt,
UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt,
! 		VariableSetStmt, VariableShowStmt, ViewStmt
%type <node>	select_no_parens, select_with_parens, select_clause,
simple_select
*************** stmt :	AlterSchemaStmt
*** 426,431 ****
--- 427,433 ----
| AlterTableStmt
| AlterGroupStmt
| AlterUserStmt
+ 		| AnalyzeStmt
| ClosePortalStmt
| CopyStmt
| CreateStmt
*************** va_list:  name
*** 3037,3042 ****
--- 3039,3074 ----
{ $$ = makeList1($1); }
| va_list ',' name
{ $$ = lappend($1, $3); }
+ 		;
+ 
+ 
+ /*****************************************************************************
+  *
+  *		QUERY:
+  *				analyze
+  *
+  *****************************************************************************/
+ 
+ /* We use opt_va_list and va_list defined for vacuum. */
+ 
+ AnalyzeStmt:  ANALYZE
+                                 {
+                                         AnalyzeStmt *n = makeNode(AnalyzeStmt);
+                                         n->anarel = NULL;
+                                         n->va_spec = NIL;
+                                         $$ = (Node *)n;
+                                 }
+                 | ANALYZE relation_name opt_va_list
+ 				{
+ 					AnalyzeStmt *n = makeNode(AnalyzeStmt);
+ 					n->anarel = $2;
+ 					n->va_spec = $3;
+ 					if ( $3 != NIL && !$2 )
+ 						elog(ERROR,"ANALYZE syntax error at or near \"(\""
+ 							"\n\tRelation name must be specified");
+ 
+ 					$$ = (Node *)n;
+ 				}
;
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.109
diff -c -p -r1.109 utility.c
*** src/backend/tcop/utility.c	2001/03/22 06:16:17	1.109
--- src/backend/tcop/utility.c	2001/04/24 22:22:26
*************** ProcessUtility(Node *parsetree,
*** 711,716 ****
--- 711,723 ----
((VacuumStmt *) parsetree)->va_spec);
break;
+ 		case T_AnalyzeStmt:
+ 			set_ps_display(commandTag = "ANALYZE");
+ 
+ 			analyze(((AnalyzeStmt *) parsetree)->anarel,
+ 				   ((AnalyzeStmt *) parsetree)->va_spec);
+ 			break;
+ 
case T_ExplainStmt:
{
ExplainStmt *stmt = (ExplainStmt *) parsetree;
Index: src/include/commands/vacuum.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/commands/vacuum.h,v
retrieving revision 1.34
diff -c -p -r1.34 vacuum.h
*** src/include/commands/vacuum.h	2001/03/22 04:00:43	1.34
--- src/include/commands/vacuum.h	2001/04/24 22:22:29
*************** extern bool VacuumRunning;
*** 122,127 ****
--- 122,131 ----
extern void vc_abort(void);
extern void vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols);
+ extern void vacuum_init(void);
+ extern void vacuum_shutdown(MemoryContext vac_context);
+ extern VRelList vacuum_getrels(NameData *VacRelP, MemoryContext vac_context);
+ extern void analyze(char *vacrel, List *anal_cols);
extern void analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL);
#define ATTNVALS_SCALE	1000000000		/* XXX so it can act as a float4 */
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.89
diff -c -p -r1.89 nodes.h
*** src/include/nodes/nodes.h	2001/04/24 00:08:38	1.89
--- src/include/nodes/nodes.h	2001/04/24 22:22:29
*************** typedef enum NodeTag
*** 165,171 ****
T_RemoveAggrStmt,
T_RemoveFuncStmt,
T_RemoveOperStmt,
! 	T_RemoveStmt_XXX,			/* not used anymore; tag# available */
T_RenameStmt,
T_RuleStmt,
T_NotifyStmt,
--- 165,171 ----
T_RemoveAggrStmt,
T_RemoveFuncStmt,
T_RemoveOperStmt,
! 	T_AnalyzeStmt,
T_RenameStmt,
T_RuleStmt,
T_NotifyStmt,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.126
diff -c -p -r1.126 parsenodes.h
*** src/include/nodes/parsenodes.h	2001/03/23 04:49:56	1.126
--- src/include/nodes/parsenodes.h	2001/04/24 22:22:29
*************** typedef struct VacuumStmt
*** 703,708 ****
--- 703,719 ----
} VacuumStmt;
/* ----------------------
+  *		Analyze Statement
+  * ----------------------
+  */
+ typedef struct AnalyzeStmt
+ {
+ 	NodeTag		type;
+ 	char	   *anarel;			/* table to analyze */
+ 	List	   *va_spec;		/* columns to analyse */
+ } AnalyzeStmt;
+ 
+ /* ----------------------
*		Explain Statement
* ----------------------
*/
Index: src/interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.136
diff -c -p -r1.136 preproc.y
*** src/interfaces/ecpg/preproc/preproc.y	2001/04/05 08:21:14	1.136
--- src/interfaces/ecpg/preproc/preproc.y	2001/04/24 22:22:30
*************** make_name(void)
*** 302,308 ****
%type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
%type  <str>    opt_with_copy FetchStmt direction fetch_how_many from_in
%type  <str>    ClosePortalStmt DropStmt VacuumStmt opt_verbose func_arg
! %type  <str>    opt_analyze opt_va_list va_list ExplainStmt index_params
%type  <str>    index_list func_index index_elem opt_class access_method_clause
%type  <str>    index_opt_unique IndexStmt func_return ConstInterval
%type  <str>    func_args_list func_args opt_with ProcedureStmt def_arg
--- 302,308 ----
%type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
%type  <str>    opt_with_copy FetchStmt direction fetch_how_many from_in
%type  <str>    ClosePortalStmt DropStmt VacuumStmt opt_verbose func_arg
! %type  <str>    opt_analyze opt_va_list va_list AnalyzeStmt ExplainStmt index_params
%type  <str>    index_list func_index index_elem opt_class access_method_clause
%type  <str>    index_opt_unique IndexStmt func_return ConstInterval
%type  <str>    func_args_list func_args opt_with ProcedureStmt def_arg
*************** stmt:  AlterSchemaStmt 			{ output_state
*** 447,452 ****
--- 447,453 ----
| CreatedbStmt		{ output_statement($1, 0, NULL, connection); }
| DropdbStmt		{ output_statement($1, 0, NULL, connection); }
| VacuumStmt		{ output_statement($1, 0, NULL, connection); }
+ 		| AnalyzeStmt		{ output_statement($1, 0, NULL, connection); }
| VariableSetStmt	{ output_statement($1, 0, NULL, connection); }
| VariableShowStmt	{ output_statement($1, 0, NULL, connection); }
| VariableResetStmt	{ output_statement($1, 0, NULL, connection); }
*************** va_list:  name
*** 2282,2287 ****
--- 2283,2310 ----
{ $$=$1; }
| va_list ',' name
{ $$=cat_str(3, $1, make_str(","), $3); }
+ 		;
+ 
+ 
+ /*****************************************************************************
+  *
+  *		QUERY:
+  *				analyze
+  *
+  *****************************************************************************/
+ 
+ /* We use opt_va_list and va_list defined for vacuum. */
+ 
+ AnalyzeStmt:  ANALYZE
+ 				{
+ 					$$ = cat_str(1, make_str("analyze"));
+ 				}
+ 		| ANALYZE relation_name opt_va_list
+ 				{
+ 					if ( strlen($3) > 0 && strlen($2) == 0 )
+ 						mmerror(ET_ERROR, "ANALYZE syntax error at or near \"(\"\n\tRelations name must be specified");
+ 					$$ = cat_str(3, make_str("analyze"), $2, $3);
+ 				}
;

---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Fernando Nasser (#2)
Re: ANALYZE command [REPOST]

Fernando Nasser <fnasser@cygnus.com> writes:

It adds a separate SQL extension command ANALYZE that will only perform the analyze part and thus only use shared locks.

I will submit the doc and test changes in a separate patch, if you decide that we are really going ahead with the ANALYZE command.

I've already done this as part of work discussed recently on pghackers.
However, I haven't got round to writing the doc changes yet, so if you
have those then please send 'em along ;-)

regards, tom lane

#5Bruce Momjian
bruce@momjian.us
In reply to: Fernando Nasser (#2)
Re: ANALYZE command [REPOST]

Seems this has already been done by Tom Lane. Thanks.

[My apologies: I forgot to tell to which sources the patch
applies, as required and, which is worse, I attached the wrong
patch; I have corrected it now.]

This patch is a follow-up to the split of the vacuum and analyze
(done by Bruce Momjian last year). I applies to today's CVS
sources.

It adds a separate SQL extension command ANALYZE that will only
perform the analyze part and thus only use shared locks.

I will submit the doc and test changes in a separate patch, if
you decide that we are really going ahead with the ANALYZE
command.

This version still does not update pg_class. Those statistics
are still tied in the vacuum part (num. of pages, tuples and
indication if the relation has an index). The patch allows for
analyze_rel() to work differently if run as part of a VACUUM or
as an standalone ANALYZE, so the missing bits can be added
without changes to the current behavior of VACUUM ANALYZE.

Possible future improvements:

1) Add the pg_class update to ANALYZE;

2) Add a VERBOSE option that prints information to gives the
DBA a hint if it is worth of running VACUUM or not.

Thanks.

-- Fernando Nasser Red Hat Inc. E-Mail:
fnasser@redhat.com

Index: src/backend/commands/analyze.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/commands/analyze.c,v
retrieving revision 1.16 diff -c -p -r1.16 analyze.c ***
src/backend/commands/analyze.c   2001/03/22 06:16:11     1.16
--- src/backend/commands/analyze.c   2001/04/24 22:22:24
*************** *** 35,41 **** --- 35,46 ----
#include "utils/fmgroids.h" #include "utils/inval.h" #include
"utils/syscache.h" + #include "utils/temprel.h"

+ static MemoryContext vac_context = NULL; + + static int
MESSAGE_LEVEL; /* message level */ +
#define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
#define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
#define swapDatum(a,b) {Datum tmp; tmp=a; a=b; b=tmp;}
*************** static void attr_stats(Relation onerel, ***
49,61 ****
static void bucketcpy(Form_pg_attribute attr, Datum value,
Datum *bucket, int *bucket_len); static void update_attstats(Oid
relid, int natts, VacAttrStats *vacattrstats); static void
del_stats(Oid relid, int attcnt, int *attnums);

/*
* analyze_rel() -- analyze relation */ void ! analyze_rel(Oid
relid, List *anal_cols2, int MESSAGE_LEVEL)
{
HeapTuple       tuple; Relation        onerel; --- 54,175
----
static void bucketcpy(Form_pg_attribute attr, Datum value,
Datum *bucket, int *bucket_len); static void update_attstats(Oid
relid, int natts, VacAttrStats *vacattrstats); static void
del_stats(Oid relid, int attcnt, int *attnums); + static void
do_analyze(NameData *VacRelP, List *anal_cols2); + static void
analyze_rel_1(Oid relid, List *anal_cols2, int vacuum); + + +
void + analyze(char *vacrel, List *anal_cols) + { +    NameData
VacRel; +    Name            VacRelName; +    MemoryContext old;
+    List       *le; +    List       *anal_cols2 = NIL; + +
/* +     * We cannot run ANALYZE inside a user transaction block;
if we were +     * inside a transaction, then our commit- and
+     * start-transaction-command calls would not have the
intended effect!  +     */ +    if (IsTransactionBlock()) +
elog(ERROR, "ANALYZE cannot run inside a BEGIN/END block"); +
+    MESSAGE_LEVEL = DEBUG;
+    /* +     * Create special memory context for cross-transaction
storage.  +     * +     * Since it is a child of QueryContext,
it will go away eventually even +     * if we suffer an error;
there's no need for special abort cleanup +     * logic.  +
*/ +    vac_context = AllocSetContextCreate(QueryContext, +
"Analyze", +
ALLOCSET_DEFAULT_MINSIZE, +
ALLOCSET_DEFAULT_INITSIZE, +
ALLOCSET_DEFAULT_MAXSIZE); + +    /* vacrel gets de-allocated
on xact commit, so copy it to safe storage */ +    if (vacrel)
+    { +            namestrcpy(&VacRel, vacrel); +
VacRelName = &VacRel; +    } +    else +            VacRelName
= NULL;
+    /* must also copy the column list, if any, to safe storage
*/ +    old = MemoryContextSwitchTo(vac_context); +    foreach(le,
anal_cols) +    { +            char       *col = (char *)
lfirst(le); + +            anal_cols2 = lappend(anal_cols2,
pstrdup(col)); +    } +    MemoryContextSwitchTo(old); + +
/* +     * Start up the analyzer.  +     * +     * NOTE: since
this commits the current transaction, the memory holding +
* any passed-in parameters gets freed here.  We must have already
+     * copied pass-by-reference parameters to safe storage.
Don't make me +     * fix this again!  +     */ +    vacuum_init();
+ +    /* analyze the database */ +    do_analyze(VacRelName,
anal_cols2); + +    vacuum_shutdown(vac_context); + } +
/* +  * do_analyze() -- analyze the database.  +  * +  *
This routine builds a list of relations to analyze, and then
calls +  *         code that analyze them one at a time.  +  */
+ static void + do_analyze(NameData *VacRelP, List *anal_cols2)
+ { +    VRelList        vrl, +                            cur;
+ +    /* get list of relations */ +    vrl = vacuum_getrels(VacRelP,
vac_context); + +    /* analyze each heap relation */ +    for
(cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next) +
{ +            analyze_rel_1(cur->vrl_relid, anal_cols2, 0 /*
not vacuum */); +    } + } + + /*
* analyze_rel() -- analyze relation +  * +  * Called through
here when doing vacuum
*/ void ! analyze_rel(Oid relid, List *anal_cols2, int
msg_level) ! { !    /* !     * Use the MESSAGE_LEVEL as set on
vacuum.  !     */ !    MESSAGE_LEVEL = msg_level; !
analyze_rel_1(relid, anal_cols2, 1 /* vacuum */); ! } !  ! /*
!  * analyze_rel_1() -- analyze relation !  * !  * Do the job
for ANALYZE or VACUUM ANALYSE in one relation !  */ !  ! static
void ! analyze_rel_1(Oid relid, List *anal_cols2, int vacuum)
{
HeapTuple       tuple; Relation        onerel; ***************
analyze_rel(Oid relid, List *anal_cols2, *** 107,116 ****
{
/*
!             * we already did an elog during vacuum elog(NOTICE,
"Skipping !             * \"%s\" --- only table owner can VACUUM
it", !             * RelationGetRelationName(onerel));
*/ heap_close(onerel, NoLock); CommitTransactionCommand();
return;
--- 221,231 ----
{

/*
! * we already did an elog during vacuum
*/
+ if (!vacuum) + elog(NOTICE,
"Skipping \"%s\" --- only table owner can ANALYZE it", +
RelationGetRelationName(onerel));
heap_close(onerel, NoLock); CommitTransactionCommand();
return;
*************** analyze_rel(Oid relid, List *anal_cols2, ***
127,133 ****
List *le;

if (length(anal_cols2) > attr_cnt)
!                    elog(ERROR, "vacuum: too many attributes
specified for relation %s",
RelationGetRelationName(onerel));
attnums = (int *) palloc(attr_cnt * sizeof(int));
foreach(le, anal_cols2)
--- 242,248 ----
List       *le;
if (length(anal_cols2) > attr_cnt)
!                    elog(ERROR, "analyze: too many attributes
specified for relation %s",
RelationGetRelationName(onerel));
attnums = (int *) palloc(attr_cnt * sizeof(int));
foreach(le, anal_cols2)
*************** analyze_rel(Oid relid, List *anal_cols2, ***
143,149 ****
attnums[tcnt++] = i; else {
!                            elog(ERROR, "vacuum: there is no
attribute %s in %s",
col,
RelationGetRelationName(onerel));
} }
--- 258,264 ----
attnums[tcnt++] = i; else {
!                            elog(ERROR, "analyze: there is no
attribute %s in %s",
col,
RelationGetRelationName(onerel));
} }
Index: src/backend/commands/vacuum.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.189 diff -c -p -r1.189 vacuum.c ***
src/backend/commands/vacuum.c    2001/03/25 23:23:58     1.189
--- src/backend/commands/vacuum.c    2001/04/24 22:22:25
*************** static int   MESSAGE_LEVEL;          /* message
le *** 60,69 ****
static TransactionId XmaxRecent;

/* non-export function prototypes */ - static void vacuum_init(void);
- static void vacuum_shutdown(void);
static void vac_vacuum(NameData *VacRelP, bool analyze, List
*anal_cols2); - static VRelList getrels(NameData *VacRelP);
static void vacuum_rel(Oid relid); static void scan_heap(VRelStats
*vacrelstats, Relation onerel, VacPageList vacuum_pages,
VacPageList fraged_pages); static void repair_frag(VRelStats
*vacrelstats, Relation onerel, VacPageList vacuum_pages,
VacPageList fraged_pages, int nindices, Relation *Irel); ---
60,66 ---- *************** vacuum(char *vacrel, bool verbose,
bool *** 163,169 ****
vac_vacuum(VacRelName, analyze, anal_cols2);

/* clean up */ ! vacuum_shutdown();
}

/* --- 160,166 ----
vac_vacuum(VacRelName, analyze, anal_cols2);

/* clean up */ ! vacuum_shutdown(vac_context);
}

/* *************** vacuum(char *vacrel, bool verbose, bool
*** 186,200 ****
* vacuum_shutdown() to match the commit waiting for
us back in * PostgresMain(). */ ! static void
vacuum_init() {
/* matches the StartTransaction in PostgresMain() */
CommitTransactionCommand(); }

! static void ! vacuum_shutdown()
{
/* on entry, we are not in a transaction */

--- 183,197 ----
*         vacuum_shutdown() to match the commit waiting for
us back in *         PostgresMain().  */ ! void
vacuum_init() {
/* matches the StartTransaction in PostgresMain() */
CommitTransactionCommand(); }

! void ! vacuum_shutdown(MemoryContext context)
{
/* on entry, we are not in a transaction */

*************** vacuum_shutdown() *** 218,224 ****
* StartTransactionCommand, else we might be trying to
delete the * active context! */ !
MemoryContextDelete(vac_context);
vac_context = NULL; }

--- 215,221 ----
* StartTransactionCommand, else we might be trying to
delete the * active context!  */ !
MemoryContextDelete(context);
vac_context = NULL; }

*************** vac_vacuum(NameData *VacRelP, bool analy ***
237,243 ****
cur;

/* get list of relations */ ! vrl = getrels(VacRelP);

/* vacuum each heap relation */ for (cur = vrl; cur !=
(VRelList) NULL; cur = cur->vrl_next) --- 234,240 ----
cur;

/* get list of relations */ ! vrl = vacuum_getrels(VacRelP,
vac_context);

/* vacuum each heap relation */ for (cur = vrl; cur !=
(VRelList) NULL; cur = cur->vrl_next) ***************
vac_vacuum(NameData *VacRelP, bool analy *** 249,256 ****
} }

! static VRelList ! getrels(NameData *VacRelP)
{
Relation rel; TupleDesc tupdesc; --- 246,253
----
} }

! VRelList ! vacuum_getrels(NameData *VacRelP, MemoryContext
context)
{
Relation rel; TupleDesc tupdesc; ***************
getrels(NameData *VacRelP) *** 317,327 ****
/* get a relation list entry for this guy */ if
(vrl == (VRelList) NULL)
vrl = cur = (VRelList)
! MemoryContextAlloc(vac_context,
sizeof(VRelListData));
else {
cur->vrl_next = (VRelList)
! MemoryContextAlloc(vac_context,
sizeof(VRelListData));
cur = cur->vrl_next; }

--- 314,324 ----
/* get a relation list entry for this guy */ if
(vrl == (VRelList) NULL)
vrl = cur = (VRelList)
!                            MemoryContextAlloc(context,
sizeof(VRelListData));
else {
cur->vrl_next = (VRelList)
!                            MemoryContextAlloc(context,
sizeof(VRelListData));
cur = cur->vrl_next; }
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.140 diff -c -p -r1.140 copyfuncs.c ***
src/backend/nodes/copyfuncs.c    2001/03/22 06:16:14     1.140
--- src/backend/nodes/copyfuncs.c    2001/04/24 22:22:25
*************** _copyVacuumStmt(VacuumStmt *from) *** 2218,2223
**** --- 2218,2235 ----
return newnode; }
+ static AnalyzeStmt * + _copyAnalyzeStmt(AnalyzeStmt *from) +
{ +    AnalyzeStmt *newnode = makeNode(AnalyzeStmt); + +    if
(from->anarel) +            newnode->anarel = pstrdup(from->anarel);
+    Node_Copy(from, newnode, va_spec); + +    return newnode;
+ } +
static ExplainStmt * _copyExplainStmt(ExplainStmt *from) {
*************** copyObject(void *from) *** 2780,2785 **** ---
2792,2800 ----
break; case T_RemoveOperStmt:
retval = _copyRemoveOperStmt(from);
+                    break; +            case T_AnalyzeStmt:
+                    retval = _copyAnalyzeStmt(from);
break; case T_RenameStmt:
retval = _copyRenameStmt(from);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.88 diff -c -p -r1.88 equalfuncs.c ***
src/backend/nodes/equalfuncs.c   2001/03/22 03:59:31     1.88
--- src/backend/nodes/equalfuncs.c   2001/04/24 22:22:25
*************** _equalVacuumStmt(VacuumStmt *a, VacuumSt ***
1126,1131 **** --- 1126,1142 ----
}
static bool + _equalAnalyzeStmt(AnalyzeStmt *a, AnalyzeStmt
*b) + { +    if (!equalstr(a->anarel, b->anarel)) +
return false; +    if (!equal(a->va_spec, b->va_spec)) +
return false; + +    return true; + } + + static bool
_equalExplainStmt(ExplainStmt *a, ExplainStmt *b) {
if (!equal(a->query, b->query)) *************** equal(void
*a, void *b) *** 1946,1951 **** --- 1957,1965 ----
break; case T_RemoveOperStmt:
retval = _equalRemoveOperStmt(a, b);
+                    break; +            case T_AnalyzeStmt:
+                    retval = _equalAnalyzeStmt(a, b);
break; case T_RenameStmt:
retval = _equalRenameStmt(a, b);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.221 diff -c -p -r2.221 gram.y ***
src/backend/parser/gram.y        2001/02/18 18:06:10     2.221
--- src/backend/parser/gram.y        2001/04/24 22:22:26
*************** static void doNegateFloat(Value *v); *** 130,135
**** --- 130,136 ----

%type <node> stmt,
AlterGroupStmt, AlterSchemaStmt, AlterTableStmt,
AlterUserStmt,
+ AnalyzeStmt, CheckPointStmt,
ClosePortalStmt, ClusterStmt, CommentStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt,
CreateGroupStmt, CreatePLangStmt, CreateSchemaStmt,
CreateSeqStmt, CreateStmt, CreateTrigStmt,
*************** static void doNegateFloat(Value *v); *** 142,148
****
RenameStmt, RevokeStmt, RuleActionStmt,
RuleActionStmtOrEmpty, RuleStmt, SelectStmt,
TransactionStmt, TruncateStmt, UnlistenStmt,
UpdateStmt, VacuumStmt, VariableResetStmt,
! VariableSetStmt, VariableShowStmt, ViewStmt,
CheckPointStmt

%type <node>       select_no_parens, select_with_parens,
select_clause,
simple_select
--- 143,149 ----
RenameStmt, RevokeStmt, RuleActionStmt,
RuleActionStmtOrEmpty, RuleStmt, SelectStmt,
TransactionStmt, TruncateStmt, UnlistenStmt,
UpdateStmt, VacuumStmt, VariableResetStmt,
!            VariableSetStmt, VariableShowStmt, ViewStmt
%type <node>       select_no_parens, select_with_parens,
select_clause,
simple_select
*************** stmt :       AlterSchemaStmt *** 426,431 ****
--- 427,433 ----
| AlterTableStmt | AlterGroupStmt | AlterUserStmt
+            | AnalyzeStmt
| ClosePortalStmt | CopyStmt | CreateStmt
*************** va_list:  name *** 3037,3042 **** --- 3039,3074
----
{ $$ = makeList1($1); }
| va_list ',' name
{ $$ = lappend($1, $3); }
+            ; + + +
/*****************************************************************************
+  * +  *         QUERY:  +  *                         analyze
+  * +
*****************************************************************************/
+ + /* We use opt_va_list and va_list defined for vacuum. */ +
+ AnalyzeStmt:  ANALYZE +                                 { +
AnalyzeStmt *n = makeNode(AnalyzeStmt); +
n->anarel = NULL; +
n->va_spec = NIL; +                                         $$
= (Node *)n; +                                 } +
| ANALYZE relation_name opt_va_list +
{ +                                    AnalyzeStmt *n =
makeNode(AnalyzeStmt); +
n->anarel = $2; +                                    n->va_spec
= $3; +                                    if ( $3 != NIL &&
!$2 ) +                                            elog(ERROR,"ANALYZE
syntax error at or near \"(\"" +
"\n\tRelation name must be specified"); + +
$$ = (Node *)n; +                            }
;
Index: src/backend/tcop/utility.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.109 diff -c -p -r1.109 utility.c ***
src/backend/tcop/utility.c       2001/03/22 06:16:17     1.109
--- src/backend/tcop/utility.c       2001/04/24 22:22:26
*************** ProcessUtility(Node *parsetree, *** 711,716 ****
--- 711,723 ----
((VacuumStmt *) parsetree)->va_spec);
break;
+            case T_AnalyzeStmt:  +
set_ps_display(commandTag = "ANALYZE"); + +
analyze(((AnalyzeStmt *) parsetree)->anarel, +
((AnalyzeStmt *) parsetree)->va_spec); +
break; +
case T_ExplainStmt:
{
ExplainStmt *stmt = (ExplainStmt
*) parsetree;
Index: src/include/commands/vacuum.h
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/include/commands/vacuum.h,v
retrieving revision 1.34 diff -c -p -r1.34 vacuum.h ***
src/include/commands/vacuum.h    2001/03/22 04:00:43     1.34
--- src/include/commands/vacuum.h    2001/04/24 22:22:29
*************** extern bool VacuumRunning; *** 122,127 **** ---
122,131 ----

extern void vc_abort(void); extern void vacuum(char *vacrel,
bool verbose, bool analyze, List *anal_cols); + extern void
vacuum_init(void); + extern void vacuum_shutdown(MemoryContext
vac_context); + extern VRelList vacuum_getrels(NameData *VacRelP,
MemoryContext vac_context); + extern void analyze(char *vacrel,
List *anal_cols);
extern void analyze_rel(Oid relid, List *anal_cols2, int
MESSAGE_LEVEL);

#define ATTNVALS_SCALE     1000000000              /* XXX so
it can act as a float4 */ Index: src/include/nodes/nodes.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.89 diff -c -p -r1.89 nodes.h ***
src/include/nodes/nodes.h        2001/04/24 00:08:38     1.89
--- src/include/nodes/nodes.h        2001/04/24 22:22:29
*************** typedef enum NodeTag *** 165,171 ****
T_RemoveAggrStmt, T_RemoveFuncStmt, T_RemoveOperStmt, !
T_RemoveStmt_XXX,                       /* not used anymore;
tag# available */
T_RenameStmt, T_RuleStmt, T_NotifyStmt, --- 165,171 ----
T_RemoveAggrStmt, T_RemoveFuncStmt, T_RemoveOperStmt, !
T_AnalyzeStmt,
T_RenameStmt, T_RuleStmt, T_NotifyStmt, Index:
src/include/nodes/parsenodes.h
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.126 diff -c -p -r1.126 parsenodes.h ***
src/include/nodes/parsenodes.h   2001/03/23 04:49:56     1.126
--- src/include/nodes/parsenodes.h   2001/04/24 22:22:29
*************** typedef struct VacuumStmt *** 703,708 **** ---
703,719 ----
} VacuumStmt;
/* ---------------------- +  *         Analyze Statement +
* ---------------------- +  */ + typedef struct AnalyzeStmt +
{ +    NodeTag         type; +    char       *anarel;
/* table to analyze */ +    List       *va_spec;            /*
columns to analyse */ + } AnalyzeStmt; + + /* ----------------------
*         Explain Statement * ---------------------- */ Index:
src/interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.136 diff -c -p -r1.136 preproc.y ***
src/interfaces/ecpg/preproc/preproc.y    2001/04/05 08:21:14
1.136 --- src/interfaces/ecpg/preproc/preproc.y    2001/04/24
22:22:30 *************** make_name(void) *** 302,308 ****
%type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name
opt_binary %type  <str>    opt_with_copy FetchStmt direction
fetch_how_many from_in %type  <str>    ClosePortalStmt DropStmt
VacuumStmt opt_verbose func_arg ! %type  <str>    opt_analyze
opt_va_list va_list ExplainStmt index_params
%type  <str>    index_list func_index index_elem opt_class
access_method_clause %type  <str>    index_opt_unique IndexStmt
func_return ConstInterval %type  <str>    func_args_list
func_args opt_with ProcedureStmt def_arg --- 302,308 ----
%type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name
opt_binary %type  <str>    opt_with_copy FetchStmt direction
fetch_how_many from_in %type  <str>    ClosePortalStmt DropStmt
VacuumStmt opt_verbose func_arg ! %type  <str>    opt_analyze
opt_va_list va_list AnalyzeStmt ExplainStmt index_params
%type  <str>    index_list func_index index_elem opt_class
access_method_clause %type  <str>    index_opt_unique IndexStmt
func_return ConstInterval %type  <str>    func_args_list
func_args opt_with ProcedureStmt def_arg *************** stmt:
AlterSchemaStmt                       { output_state *** 447,452
**** --- 447,453 ----
| CreatedbStmt          { output_statement($1, 0,
NULL, connection); } | DropdbStmt            {
output_statement($1, 0, NULL, connection); } |
VacuumStmt            { output_statement($1, 0,
NULL, connection); }
+            | AnalyzeStmt           { output_statement($1, 0,
NULL, connection); }
| VariableSetStmt       { output_statement($1, 0,
NULL, connection); } | VariableShowStmt      {
output_statement($1, 0, NULL, connection); } |
VariableResetStmt     { output_statement($1, 0,
NULL, connection); }
*************** va_list:  name *** 2282,2287 **** --- 2283,2310
----
{ $$=$1; }
| va_list ',' name
{ $$=cat_str(3, $1, make_str(","),
$3); }
+            ; + + +
/*****************************************************************************
+  * +  *         QUERY:  +  *                         analyze
+  * +
*****************************************************************************/
+ + /* We use opt_va_list and va_list defined for vacuum. */ +
+ AnalyzeStmt:  ANALYZE +                            { +
$$ = cat_str(1, make_str("analyze")); +
} +            | ANALYZE relation_name opt_va_list +
{ +                                    if ( strlen($3) > 0 &&
strlen($2) == 0 ) +
mmerror(ET_ERROR, "ANALYZE syntax error at or near \"(\"\n\tRelations
name must be specified"); +
$$ = cat_str(3, make_str("analyze"), $2, $3); +
}
;

---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026