mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
A little further progress on schemas: push down RangeVars into
addRangeTableEntry calls. Remove relname field from RTEs, since it will no longer be a useful unique identifier of relations; we want to encourage people to rely on the relation OID instead. Further work on dumping qual expressions in EXPLAIN, too.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.163 2002/03/21 23:27:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.164 2002/03/22 02:56:31 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The PerformAddAttribute() code, like most of the relation
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "executor/execdefs.h"
|
||||
#include "executor/executor.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/prep.h"
|
||||
@@ -1262,8 +1263,11 @@ AlterTableAddConstraint(char *relationName,
|
||||
* expression we can pass to ExecQual
|
||||
*/
|
||||
pstate = make_parsestate(NULL);
|
||||
rte = addRangeTableEntry(pstate, relationName, NULL,
|
||||
false, true);
|
||||
rte = addRangeTableEntryForRelation(pstate,
|
||||
myrelid,
|
||||
makeAlias(relationName, NIL),
|
||||
false,
|
||||
true);
|
||||
addRTEtoQuery(pstate, rte, true, true);
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.90 2002/03/21 23:27:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.91 2002/03/22 02:56:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -46,9 +46,11 @@ static List *MergeDomainAttributes(List *schema);
|
||||
/* ----------------------------------------------------------------
|
||||
* DefineRelation
|
||||
* Creates a new relation.
|
||||
*
|
||||
* If successful, returns the OID of the new relation.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
Oid
|
||||
DefineRelation(CreateStmt *stmt, char relkind)
|
||||
{
|
||||
char *relname = palloc(NAMEDATALEN);
|
||||
@@ -165,7 +167,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
* see the new rel anyway until we commit), but it keeps the lock
|
||||
* manager from complaining about deadlock risks.
|
||||
*/
|
||||
rel = heap_openr(relname, AccessExclusiveLock);
|
||||
rel = heap_open(relationId, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* Now add any newly specified column default values and CHECK
|
||||
@@ -210,11 +212,13 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
* visible to anyone else anyway, until commit).
|
||||
*/
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
return relationId;
|
||||
}
|
||||
|
||||
/*
|
||||
* RemoveRelation
|
||||
* Deletes a new relation.
|
||||
* Deletes a relation.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if name is invalid.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.72 2002/03/21 16:00:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.73 2002/03/22 02:56:31 tgl Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
#include "nodes/print.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
#include "tcop/pquery.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/relcache.h"
|
||||
|
||||
|
||||
@@ -34,9 +36,12 @@ typedef struct ExplainState
|
||||
} ExplainState;
|
||||
|
||||
static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
|
||||
static void ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest);
|
||||
static void ExplainOneQuery(Query *query, bool verbose, bool analyze,
|
||||
CommandDest dest);
|
||||
static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
||||
int indent, ExplainState *es);
|
||||
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
|
||||
int scanrelid,
|
||||
int scanrelid, Plan *outer_plan,
|
||||
StringInfo str, int indent, ExplainState *es);
|
||||
static void show_upper_qual(List *qual, const char *qlabel,
|
||||
const char *outer_name, int outer_varno, Plan *outer_plan,
|
||||
@@ -188,10 +193,15 @@ ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest)
|
||||
|
||||
/*
|
||||
* explain_outNode -
|
||||
* converts a Node into ascii string and append it to 'str'
|
||||
* converts a Plan node into ascii string and appends it to 'str'
|
||||
*
|
||||
* outer_plan, if not null, references another plan node that is the outer
|
||||
* side of a join with the current node. This is only interesting for
|
||||
* deciphering runtime keys of an inner indexscan.
|
||||
*/
|
||||
static void
|
||||
explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
||||
int indent, ExplainState *es)
|
||||
{
|
||||
List *l;
|
||||
Relation relation;
|
||||
@@ -304,15 +314,19 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
{
|
||||
RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
|
||||
es->rtable);
|
||||
char *relname;
|
||||
|
||||
/* Assume it's on a real relation */
|
||||
Assert(rte->relname);
|
||||
Assert(rte->relid);
|
||||
|
||||
/* We only show the rel name, not schema name */
|
||||
relname = get_rel_name(rte->relid);
|
||||
|
||||
appendStringInfo(str, " on %s",
|
||||
stringStringInfo(rte->relname));
|
||||
if (strcmp(rte->eref->aliasname, rte->relname) != 0)
|
||||
stringStringInfo(relname));
|
||||
if (strcmp(rte->eref->aliasname, relname) != 0)
|
||||
appendStringInfo(str, " %s",
|
||||
stringStringInfo(rte->eref->aliasname));
|
||||
stringStringInfo(rte->eref->aliasname));
|
||||
}
|
||||
break;
|
||||
case T_SubqueryScan:
|
||||
@@ -352,77 +366,93 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
{
|
||||
case T_IndexScan:
|
||||
show_scan_qual(((IndexScan *) plan)->indxqualorig, true,
|
||||
"indxqual",
|
||||
"Index Filter",
|
||||
((Scan *) plan)->scanrelid,
|
||||
outer_plan,
|
||||
str, indent, es);
|
||||
show_scan_qual(plan->qual, false, "qual",
|
||||
show_scan_qual(plan->qual, false,
|
||||
"Filter",
|
||||
((Scan *) plan)->scanrelid,
|
||||
outer_plan,
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_SeqScan:
|
||||
case T_TidScan:
|
||||
show_scan_qual(plan->qual, false, "qual",
|
||||
show_scan_qual(plan->qual, false,
|
||||
"Filter",
|
||||
((Scan *) plan)->scanrelid,
|
||||
outer_plan,
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_NestLoop:
|
||||
show_upper_qual(((NestLoop *) plan)->join.joinqual, "joinqual",
|
||||
show_upper_qual(((NestLoop *) plan)->join.joinqual,
|
||||
"Join Cond",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
show_upper_qual(plan->qual, "qual",
|
||||
show_upper_qual(plan->qual,
|
||||
"Filter",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_MergeJoin:
|
||||
show_upper_qual(((MergeJoin *) plan)->mergeclauses, "merge",
|
||||
show_upper_qual(((MergeJoin *) plan)->mergeclauses,
|
||||
"Merge Cond",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
show_upper_qual(((MergeJoin *) plan)->join.joinqual, "joinqual",
|
||||
show_upper_qual(((MergeJoin *) plan)->join.joinqual,
|
||||
"Join Cond",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
show_upper_qual(plan->qual, "qual",
|
||||
show_upper_qual(plan->qual,
|
||||
"Filter",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_HashJoin:
|
||||
show_upper_qual(((HashJoin *) plan)->hashclauses, "hash",
|
||||
show_upper_qual(((HashJoin *) plan)->hashclauses,
|
||||
"Hash Cond",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
show_upper_qual(((HashJoin *) plan)->join.joinqual, "joinqual",
|
||||
show_upper_qual(((HashJoin *) plan)->join.joinqual,
|
||||
"Join Cond",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
show_upper_qual(plan->qual, "qual",
|
||||
show_upper_qual(plan->qual,
|
||||
"Filter",
|
||||
"outer", OUTER, outerPlan(plan),
|
||||
"inner", INNER, innerPlan(plan),
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_SubqueryScan:
|
||||
show_upper_qual(plan->qual, "qual",
|
||||
show_upper_qual(plan->qual,
|
||||
"Filter",
|
||||
"subplan", 1, ((SubqueryScan *) plan)->subplan,
|
||||
"", 0, NULL,
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_Agg:
|
||||
case T_Group:
|
||||
show_upper_qual(plan->qual, "qual",
|
||||
show_upper_qual(plan->qual,
|
||||
"Filter",
|
||||
"subplan", 0, outerPlan(plan),
|
||||
"", 0, NULL,
|
||||
str, indent, es);
|
||||
break;
|
||||
case T_Result:
|
||||
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
|
||||
"constqual",
|
||||
"One-Time Filter",
|
||||
"subplan", OUTER, outerPlan(plan),
|
||||
"", 0, NULL,
|
||||
str, indent, es);
|
||||
show_upper_qual(plan->qual, "qual",
|
||||
show_upper_qual(plan->qual,
|
||||
"Filter",
|
||||
"subplan", OUTER, outerPlan(plan),
|
||||
"", 0, NULL,
|
||||
str, indent, es);
|
||||
@@ -446,7 +476,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
|
||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
|
||||
indent + 4, es);
|
||||
}
|
||||
es->rtable = saved_rtable;
|
||||
@@ -458,7 +488,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, outerPlan(plan), indent + 3, es);
|
||||
explain_outNode(str, outerPlan(plan), NULL, indent + 3, es);
|
||||
}
|
||||
|
||||
/* righttree */
|
||||
@@ -467,7 +497,8 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, innerPlan(plan), indent + 3, es);
|
||||
explain_outNode(str, innerPlan(plan), outerPlan(plan),
|
||||
indent + 3, es);
|
||||
}
|
||||
|
||||
if (IsA(plan, Append))
|
||||
@@ -483,7 +514,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
|
||||
explain_outNode(str, subnode, indent + 3, es);
|
||||
explain_outNode(str, subnode, NULL, indent + 3, es);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +533,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
|
||||
explain_outNode(str, subnode, indent + 3, es);
|
||||
explain_outNode(str, subnode, NULL, indent + 3, es);
|
||||
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
@@ -522,7 +553,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
|
||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
|
||||
indent + 4, es);
|
||||
}
|
||||
es->rtable = saved_rtable;
|
||||
@@ -535,7 +566,7 @@ Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||
StringInfo str = makeStringInfo();
|
||||
|
||||
if (plan != NULL)
|
||||
explain_outNode(str, plan, 0, es);
|
||||
explain_outNode(str, plan, NULL, 0, es);
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -544,10 +575,12 @@ Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||
*/
|
||||
static void
|
||||
show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
|
||||
int scanrelid,
|
||||
int scanrelid, Plan *outer_plan,
|
||||
StringInfo str, int indent, ExplainState *es)
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
Node *scancontext;
|
||||
Node *outercontext;
|
||||
List *context;
|
||||
Node *node;
|
||||
char *exprstr;
|
||||
@@ -562,23 +595,43 @@ show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate deparse context */
|
||||
Assert(scanrelid > 0 && scanrelid <= length(es->rtable));
|
||||
rte = rt_fetch(scanrelid, es->rtable);
|
||||
|
||||
/* Assume it's on a real relation */
|
||||
Assert(rte->relname);
|
||||
|
||||
context = deparse_context_for(rte->relname, rte->relid);
|
||||
|
||||
/* Fix qual --- indexqual requires different processing */
|
||||
if (is_or_qual)
|
||||
node = make_ors_ands_explicit(qual);
|
||||
else
|
||||
node = (Node *) make_ands_explicit(qual);
|
||||
|
||||
/* Generate deparse context */
|
||||
Assert(scanrelid > 0 && scanrelid <= length(es->rtable));
|
||||
rte = rt_fetch(scanrelid, es->rtable);
|
||||
|
||||
/* Assume it's on a real relation */
|
||||
Assert(rte->relid);
|
||||
scancontext = deparse_context_for_relation(rte->eref->aliasname,
|
||||
rte->relid);
|
||||
|
||||
/*
|
||||
* If we have an outer plan that is referenced by the qual, add it to
|
||||
* the deparse context. If not, don't (so that we don't force prefixes
|
||||
* unnecessarily).
|
||||
*/
|
||||
if (outer_plan)
|
||||
{
|
||||
if (intMember(OUTER, pull_varnos(node)))
|
||||
outercontext = deparse_context_for_subplan("outer",
|
||||
outer_plan->targetlist,
|
||||
es->rtable);
|
||||
else
|
||||
outercontext = NULL;
|
||||
}
|
||||
else
|
||||
outercontext = NULL;
|
||||
|
||||
context = deparse_context_for_plan(scanrelid, scancontext,
|
||||
OUTER, outercontext);
|
||||
|
||||
/* Deparse the expression */
|
||||
exprstr = deparse_expression(node, context, false);
|
||||
exprstr = deparse_expression(node, context, (outercontext != NULL));
|
||||
|
||||
/* And add to str */
|
||||
for (i = 0; i < indent; i++)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.73 2002/03/21 23:27:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.74 2002/03/22 02:56:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -87,6 +87,7 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
CreateStmt *stmt = makeNode(CreateStmt);
|
||||
ColumnDef *coldef;
|
||||
TypeName *typnam;
|
||||
Oid seqoid;
|
||||
Relation rel;
|
||||
Buffer buf;
|
||||
PageHeader page;
|
||||
@@ -175,9 +176,9 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
stmt->constraints = NIL;
|
||||
stmt->hasoids = false;
|
||||
|
||||
DefineRelation(stmt, RELKIND_SEQUENCE);
|
||||
seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
|
||||
|
||||
rel = heap_openr(seq->sequence->relname, AccessExclusiveLock);
|
||||
rel = heap_open(seqoid, AccessExclusiveLock);
|
||||
tupDesc = RelationGetDescr(rel);
|
||||
|
||||
/* Initialize first page of relation with special magic number */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: view.c,v 1.59 2002/03/21 16:00:36 tgl Exp $
|
||||
* $Id: view.c,v 1.60 2002/03/22 02:56:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,7 +37,7 @@
|
||||
* the xact...
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
static Oid
|
||||
DefineVirtualRelation(char *relname, List *tlist)
|
||||
{
|
||||
CreateStmt *createStmt = makeNode(CreateStmt);
|
||||
@@ -96,7 +96,7 @@ DefineVirtualRelation(char *relname, List *tlist)
|
||||
/*
|
||||
* finally create the relation...
|
||||
*/
|
||||
DefineRelation(createStmt, RELKIND_VIEW);
|
||||
return DefineRelation(createStmt, RELKIND_VIEW);
|
||||
}
|
||||
|
||||
static RuleStmt *
|
||||
@@ -176,7 +176,7 @@ DefineViewRules(char *viewName, Query *viewParse)
|
||||
*---------------------------------------------------------------
|
||||
*/
|
||||
static Query *
|
||||
UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
|
||||
UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
|
||||
{
|
||||
List *new_rt;
|
||||
RangeTblEntry *rt_entry1,
|
||||
@@ -196,12 +196,12 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
|
||||
* Create the 2 new range table entries and form the new range
|
||||
* table... OLD first, then NEW....
|
||||
*/
|
||||
rt_entry1 = addRangeTableEntry(NULL, viewName,
|
||||
makeAlias("*OLD*", NIL),
|
||||
false, false);
|
||||
rt_entry2 = addRangeTableEntry(NULL, viewName,
|
||||
makeAlias("*NEW*", NIL),
|
||||
false, false);
|
||||
rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
|
||||
makeAlias("*OLD*", NIL),
|
||||
false, false);
|
||||
rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
|
||||
makeAlias("*NEW*", NIL),
|
||||
false, false);
|
||||
/* Must override addRangeTableEntry's default access-check flags */
|
||||
rt_entry1->checkForRead = false;
|
||||
rt_entry2->checkForRead = false;
|
||||
@@ -233,11 +233,14 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
|
||||
void
|
||||
DefineView(char *viewName, Query *viewParse)
|
||||
{
|
||||
Oid viewOid;
|
||||
|
||||
/*
|
||||
* Create the "view" relation NOTE: if it already exists, the xact
|
||||
* will be aborted.
|
||||
* Create the view relation
|
||||
*
|
||||
* NOTE: if it already exists, the xact will be aborted.
|
||||
*/
|
||||
DefineVirtualRelation(viewName, viewParse->targetList);
|
||||
viewOid = DefineVirtualRelation(viewName, viewParse->targetList);
|
||||
|
||||
/*
|
||||
* The relation we have just created is not visible to any other
|
||||
@@ -250,7 +253,7 @@ DefineView(char *viewName, Query *viewParse)
|
||||
* The range table of 'viewParse' does not contain entries for the
|
||||
* "OLD" and "NEW" relations. So... add them!
|
||||
*/
|
||||
viewParse = UpdateRangeTableOfViewParse(viewName, viewParse);
|
||||
viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
|
||||
|
||||
/*
|
||||
* Now create the rules associated with the view.
|
||||
|
||||
Reference in New Issue
Block a user