utility.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:18k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * utility.c
  4.  *   Contains functions which control the execution of the POSTGRES utility
  5.  *   commands.  At one time acted as an interface between the Lisp and C
  6.  *   systems.
  7.  *
  8.  * Copyright (c) 1994, Regents of the University of California
  9.  *
  10.  *
  11.  * IDENTIFICATION
  12.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/tcop/utility.c,v 1.61 1999/05/25 16:11:43 momjian Exp $
  13.  *
  14.  *-------------------------------------------------------------------------
  15.  */
  16. #include "postgres.h"
  17. #include "access/xact.h"
  18. #include "access/heapam.h"
  19. #include "catalog/catalog.h"
  20. #include "catalog/pg_type.h"
  21. #include "commands/async.h"
  22. #include "commands/cluster.h"
  23. #include "commands/command.h"
  24. #include "commands/copy.h"
  25. #include "commands/creatinh.h"
  26. #include "commands/dbcommands.h"
  27. #include "commands/sequence.h"
  28. #include "commands/defrem.h"
  29. #include "commands/rename.h"
  30. #include "commands/view.h"
  31. #include "commands/version.h"
  32. #include "commands/vacuum.h"
  33. #include "commands/explain.h"
  34. #include "commands/trigger.h"
  35. #include "commands/proclang.h"
  36. #include "commands/variable.h"
  37. #include "nodes/parsenodes.h"
  38. #include "../backend/parser/parse.h"
  39. #include "utils/builtins.h"
  40. #include "utils/acl.h"
  41. #include "utils/palloc.h"
  42. #include "rewrite/rewriteRemove.h"
  43. #include "rewrite/rewriteDefine.h"
  44. #include "tcop/tcopdebug.h"
  45. #include "tcop/dest.h"
  46. #include "tcop/utility.h"
  47. #include "fmgr.h" /* For load_file() */
  48. #include "storage/fd.h"
  49. #include "utils/ps_status.h"
  50. #ifndef NO_SECURITY
  51. #include "miscadmin.h"
  52. #include "utils/acl.h"
  53. #include "utils/syscache.h"
  54. #endif
  55. void DefineUser(CreateUserStmt *stmt, CommandDest);
  56. void AlterUser(AlterUserStmt *stmt, CommandDest);
  57. void RemoveUser(char *username, CommandDest);
  58. /* ----------------
  59.  * CHECK_IF_ABORTED() is used to avoid doing unnecessary
  60.  * processing within an aborted transaction block.
  61.  * ----------------
  62.  */
  63.  /* we have to use IF because of the 'break' */
  64. #define CHECK_IF_ABORTED() 
  65. if (1) 
  66. if (IsAbortedTransactionBlockState()) 
  67. elog(NOTICE, "(transaction aborted): %s", 
  68.  "all queries ignored until end of transaction block"); 
  69. commandTag = "*ABORT STATE*"; 
  70. break; 
  71. } else
  72. /* ----------------
  73.  * general utility function invoker
  74.  * ----------------
  75.  */
  76. void
  77. ProcessUtility(Node *parsetree,
  78.    CommandDest dest)
  79. {
  80. char    *commandTag = NULL;
  81. char    *relname;
  82. char    *relationName;
  83. char    *userName;
  84. userName = GetPgUserName();
  85. switch (nodeTag(parsetree))
  86. {
  87. /*
  88.  * ******************************** transactions ********************************
  89.  *
  90.  */
  91. case T_TransactionStmt:
  92. {
  93. TransactionStmt *stmt = (TransactionStmt *) parsetree;
  94. switch (stmt->command)
  95. {
  96. case BEGIN_TRANS:
  97. PS_SET_STATUS(commandTag = "BEGIN");
  98. CHECK_IF_ABORTED();
  99. BeginTransactionBlock();
  100. break;
  101. case END_TRANS:
  102. PS_SET_STATUS(commandTag = "END");
  103. EndTransactionBlock();
  104. break;
  105. case ABORT_TRANS:
  106. PS_SET_STATUS(commandTag = "ABORT");
  107. UserAbortTransactionBlock();
  108. break;
  109. }
  110. }
  111. break;
  112. /*
  113.  * ******************************** portal manipulation ********************************
  114.  *
  115.  */
  116. case T_ClosePortalStmt:
  117. {
  118. ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
  119. PS_SET_STATUS(commandTag = "CLOSE");
  120. CHECK_IF_ABORTED();
  121. PerformPortalClose(stmt->portalname, dest);
  122. }
  123. break;
  124. case T_FetchStmt:
  125. {
  126. FetchStmt  *stmt = (FetchStmt *) parsetree;
  127. char    *portalName = stmt->portalname;
  128. bool forward;
  129. int count;
  130. PS_SET_STATUS(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
  131. CHECK_IF_ABORTED();
  132. forward = (bool) (stmt->direction == FORWARD);
  133. /*
  134.  * parser ensures that count is >= 0 and 'fetch ALL' -> 0
  135.  */
  136. count = stmt->howMany;
  137. PerformPortalFetch(portalName, forward, count, commandTag,
  138.    (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
  139. }
  140. break;
  141. /*
  142.  * ******************************** relation and attribute
  143.  * manipulation ********************************
  144.  *
  145.  */
  146. case T_CreateStmt:
  147. PS_SET_STATUS(commandTag = "CREATE");
  148. CHECK_IF_ABORTED();
  149. DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
  150. break;
  151. case T_DestroyStmt:
  152. {
  153. DestroyStmt *stmt = (DestroyStmt *) parsetree;
  154. List    *arg;
  155. List    *args = stmt->relNames;
  156. Relation rel;
  157. PS_SET_STATUS(commandTag = "DROP");
  158. CHECK_IF_ABORTED();
  159. foreach(arg, args)
  160. {
  161. relname = strVal(lfirst(arg));
  162. if (!allowSystemTableMods && IsSystemRelationName(relname))
  163. elog(ERROR, "class "%s" is a system catalog",
  164.  relname);
  165. rel = heap_openr(relname);
  166. if (RelationIsValid(rel))
  167. {
  168. if (stmt->sequence &&
  169. rel->rd_rel->relkind != RELKIND_SEQUENCE)
  170. elog(ERROR, "Use DROP TABLE to drop table '%s'",
  171.  relname);
  172. if (!(stmt->sequence) &&
  173. rel->rd_rel->relkind == RELKIND_SEQUENCE)
  174. elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
  175.  relname);
  176. heap_close(rel);
  177. }
  178. #ifndef NO_SECURITY
  179. if (!pg_ownercheck(userName, relname, RELNAME))
  180. elog(ERROR, "you do not own class "%s"",
  181.  relname);
  182. #endif
  183. }
  184. foreach(arg, args)
  185. {
  186. relname = strVal(lfirst(arg));
  187. RemoveRelation(relname);
  188. }
  189. }
  190. break;
  191. case T_CopyStmt:
  192. {
  193. CopyStmt   *stmt = (CopyStmt *) parsetree;
  194. PS_SET_STATUS(commandTag = "COPY");
  195. CHECK_IF_ABORTED();
  196. DoCopy(stmt->relname,
  197.    stmt->binary,
  198.    stmt->oids,
  199.    (bool) (stmt->direction == FROM),
  200.    (bool) (stmt->filename == NULL),
  201. /*
  202.  * null filename means copy to/from stdout/stdin, rather
  203.  * than to/from a file.
  204.  */
  205.    stmt->filename,
  206.    stmt->delimiter);
  207. }
  208. break;
  209. case T_AddAttrStmt:
  210. {
  211. AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
  212. PS_SET_STATUS(commandTag = "ADD");
  213. CHECK_IF_ABORTED();
  214. /*
  215.  * owner checking done in PerformAddAttribute (now
  216.  * recursive)
  217.  */
  218. PerformAddAttribute(stmt->relname,
  219. userName,
  220. stmt->inh,
  221. (ColumnDef *) stmt->colDef);
  222. }
  223. break;
  224. /*
  225.  * schema
  226.  */
  227. case T_RenameStmt:
  228. {
  229. RenameStmt *stmt = (RenameStmt *) parsetree;
  230. PS_SET_STATUS(commandTag = "RENAME");
  231. CHECK_IF_ABORTED();
  232. relname = stmt->relname;
  233. if (!allowSystemTableMods && IsSystemRelationName(relname))
  234. elog(ERROR, "class "%s" is a system catalog",
  235.  relname);
  236. #ifndef NO_SECURITY
  237. if (!pg_ownercheck(userName, relname, RELNAME))
  238. elog(ERROR, "you do not own class "%s"",
  239.  relname);
  240. #endif
  241. /* ----------------
  242.  * XXX using len == 3 to tell the difference
  243.  * between "rename rel to newrel" and
  244.  * "rename att in rel to newatt" will not
  245.  * work soon because "rename type/operator/rule"
  246.  * stuff is being added. - cim 10/24/90
  247.  * ----------------
  248.  * [another piece of amuzing but useless anecdote -- ay]
  249.  */
  250. if (stmt->column == NULL)
  251. {
  252. /* ----------------
  253.  * rename relation
  254.  *
  255.  * Note: we also rename the "type" tuple
  256.  * corresponding to the relation.
  257.  * ----------------
  258.  */
  259. renamerel(relname, /* old name */
  260.   stmt->newname); /* new name */
  261. TypeRename(relname, /* old name */
  262.    stmt->newname); /* new name */
  263. }
  264. else
  265. {
  266. /* ----------------
  267.  * rename attribute
  268.  * ----------------
  269.  */
  270. renameatt(relname, /* relname */
  271.   stmt->column, /* old att name */
  272.   stmt->newname, /* new att name */
  273.   userName,
  274.   stmt->inh); /* recursive? */
  275. }
  276. }
  277. break;
  278. case T_ChangeACLStmt:
  279. {
  280. ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
  281. List    *i;
  282. AclItem    *aip;
  283. unsigned modechg;
  284. PS_SET_STATUS(commandTag = "CHANGE");
  285. CHECK_IF_ABORTED();
  286. aip = stmt->aclitem;
  287. modechg = stmt->modechg;
  288. #ifndef NO_SECURITY
  289. foreach(i, stmt->relNames)
  290. {
  291. relname = strVal(lfirst(i));
  292. if (!pg_ownercheck(userName, relname, RELNAME))
  293. elog(ERROR, "you do not own class "%s"",
  294.  relname);
  295. }
  296. #endif
  297. foreach(i, stmt->relNames)
  298. {
  299. relname = strVal(lfirst(i));
  300. ChangeAcl(relname, aip, modechg);
  301. }
  302. }
  303. break;
  304. /*
  305.  * ******************************** object creation /
  306.  * destruction ********************************
  307.  *
  308.  */
  309. case T_DefineStmt:
  310. {
  311. DefineStmt *stmt = (DefineStmt *) parsetree;
  312. PS_SET_STATUS(commandTag = "CREATE");
  313. CHECK_IF_ABORTED();
  314. switch (stmt->defType)
  315. {
  316. case OPERATOR:
  317. DefineOperator(stmt->defname, /* operator name */
  318.    stmt->definition); /* rest */
  319. break;
  320. case TYPE_P:
  321. DefineType(stmt->defname, stmt->definition);
  322. break;
  323. case AGGREGATE:
  324. DefineAggregate(stmt->defname, /* aggregate name */
  325. stmt->definition); /* rest */
  326. break;
  327. }
  328. }
  329. break;
  330. case T_ViewStmt: /* CREATE VIEW */
  331. {
  332. ViewStmt   *stmt = (ViewStmt *) parsetree;
  333. PS_SET_STATUS(commandTag = "CREATE");
  334. CHECK_IF_ABORTED();
  335. DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
  336. }
  337. break;
  338. case T_ProcedureStmt: /* CREATE FUNCTION */
  339. PS_SET_STATUS(commandTag = "CREATE");
  340. CHECK_IF_ABORTED();
  341. CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
  342. break;
  343. case T_IndexStmt: /* CREATE INDEX */
  344. {
  345. IndexStmt  *stmt = (IndexStmt *) parsetree;
  346. PS_SET_STATUS(commandTag = "CREATE");
  347. CHECK_IF_ABORTED();
  348. DefineIndex(stmt->relname, /* relation name */
  349. stmt->idxname, /* index name */
  350. stmt->accessMethod, /* am name */
  351. stmt->indexParams, /* parameters */
  352. stmt->withClause,
  353. stmt->unique,
  354. stmt->primary,
  355. (Expr *) stmt->whereClause,
  356. stmt->rangetable);
  357. }
  358. break;
  359. case T_RuleStmt: /* CREATE RULE */
  360. {
  361. RuleStmt   *stmt = (RuleStmt *) parsetree;
  362. int aclcheck_result;
  363. #ifndef NO_SECURITY
  364. relname = stmt->object->relname;
  365. aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
  366. if (aclcheck_result != ACLCHECK_OK)
  367. elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
  368. #endif
  369. PS_SET_STATUS(commandTag = "CREATE");
  370. CHECK_IF_ABORTED();
  371. DefineQueryRewrite(stmt);
  372. }
  373. break;
  374. case T_CreateSeqStmt:
  375. PS_SET_STATUS(commandTag = "CREATE");
  376. CHECK_IF_ABORTED();
  377. DefineSequence((CreateSeqStmt *) parsetree);
  378. break;
  379. case T_ExtendStmt:
  380. {
  381. ExtendStmt *stmt = (ExtendStmt *) parsetree;
  382. PS_SET_STATUS(commandTag = "EXTEND");
  383. CHECK_IF_ABORTED();
  384. ExtendIndex(stmt->idxname, /* index name */
  385. (Expr *) stmt->whereClause, /* where */
  386. stmt->rangetable);
  387. }
  388. break;
  389. case T_RemoveStmt:
  390. {
  391. RemoveStmt *stmt = (RemoveStmt *) parsetree;
  392. PS_SET_STATUS(commandTag = "DROP");
  393. CHECK_IF_ABORTED();
  394. switch (stmt->removeType)
  395. {
  396. case INDEX:
  397. relname = stmt->name;
  398. if (!allowSystemTableMods && IsSystemRelationName(relname))
  399. elog(ERROR, "class "%s" is a system catalog index",
  400.  relname);
  401. #ifndef NO_SECURITY
  402. if (!pg_ownercheck(userName, relname, RELNAME))
  403. elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
  404. #endif
  405. RemoveIndex(relname);
  406. break;
  407. case RULE:
  408. {
  409. char    *rulename = stmt->name;
  410. int aclcheck_result;
  411. #ifndef NO_SECURITY
  412. relationName = RewriteGetRuleEventRel(rulename);
  413. aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
  414. if (aclcheck_result != ACLCHECK_OK)
  415. elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
  416. #endif
  417. RemoveRewriteRule(rulename);
  418. }
  419. break;
  420. case TYPE_P:
  421. #ifndef NO_SECURITY
  422. /* XXX moved to remove.c */
  423. #endif
  424. RemoveType(stmt->name);
  425. break;
  426. case VIEW:
  427. {
  428. char    *viewName = stmt->name;
  429. char    *ruleName;
  430. #ifndef NO_SECURITY
  431. ruleName = MakeRetrieveViewRuleName(viewName);
  432. relationName = RewriteGetRuleEventRel(ruleName);
  433. if (!pg_ownercheck(userName, relationName, RELNAME))
  434. elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
  435. pfree(ruleName);
  436. #endif
  437. RemoveView(viewName);
  438. }
  439. break;
  440. }
  441. break;
  442. }
  443. break;
  444. case T_RemoveAggrStmt:
  445. {
  446. RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
  447. PS_SET_STATUS(commandTag = "DROP");
  448. CHECK_IF_ABORTED();
  449. RemoveAggregate(stmt->aggname, stmt->aggtype);
  450. }
  451. break;
  452. case T_RemoveFuncStmt:
  453. {
  454. RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
  455. PS_SET_STATUS(commandTag = "DROP");
  456. CHECK_IF_ABORTED();
  457. RemoveFunction(stmt->funcname,
  458.    length(stmt->args),
  459.    stmt->args);
  460. }
  461. break;
  462. case T_RemoveOperStmt:
  463. {
  464. RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
  465. char    *type1 = (char *) NULL;
  466. char    *type2 = (char *) NULL;
  467. PS_SET_STATUS(commandTag = "DROP");
  468. CHECK_IF_ABORTED();
  469. if (lfirst(stmt->args) != NULL)
  470. type1 = strVal(lfirst(stmt->args));
  471. if (lsecond(stmt->args) != NULL)
  472. type2 = strVal(lsecond(stmt->args));
  473. RemoveOperator(stmt->opname, type1, type2);
  474. }
  475. break;
  476. case T_VersionStmt:
  477. elog(ERROR, "CREATE VERSION is not currently implemented");
  478. break;
  479. case T_CreatedbStmt:
  480. {
  481. CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
  482. PS_SET_STATUS(commandTag = "CREATEDB");
  483. CHECK_IF_ABORTED();
  484. createdb(stmt->dbname, stmt->dbpath, stmt->encoding, dest);
  485. }
  486. break;
  487. case T_DestroydbStmt:
  488. {
  489. DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
  490. PS_SET_STATUS(commandTag = "DESTROYDB");
  491. CHECK_IF_ABORTED();
  492. destroydb(stmt->dbname, dest);
  493. }
  494. break;
  495. /* Query-level asynchronous notification */
  496. case T_NotifyStmt:
  497. {
  498. NotifyStmt *stmt = (NotifyStmt *) parsetree;
  499. PS_SET_STATUS(commandTag = "NOTIFY");
  500. CHECK_IF_ABORTED();
  501. Async_Notify(stmt->relname);
  502. }
  503. break;
  504. case T_ListenStmt:
  505. {
  506. ListenStmt *stmt = (ListenStmt *) parsetree;
  507. PS_SET_STATUS(commandTag = "LISTEN");
  508. CHECK_IF_ABORTED();
  509. Async_Listen(stmt->relname, MyProcPid);
  510. }
  511. break;
  512. case T_UnlistenStmt:
  513. {
  514. UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
  515. PS_SET_STATUS(commandTag = "UNLISTEN");
  516. CHECK_IF_ABORTED();
  517. Async_Unlisten(stmt->relname, MyProcPid);
  518. }
  519. break;
  520. /*
  521.  * ******************************** dynamic loader ********************************
  522.  *
  523.  */
  524. case T_LoadStmt:
  525. {
  526. LoadStmt   *stmt = (LoadStmt *) parsetree;
  527. PS_SET_STATUS(commandTag = "LOAD");
  528. CHECK_IF_ABORTED();
  529. closeAllVfds(); /* probably not necessary... */
  530. load_file(stmt->filename);
  531. }
  532. break;
  533. case T_ClusterStmt:
  534. {
  535. ClusterStmt *stmt = (ClusterStmt *) parsetree;
  536. PS_SET_STATUS(commandTag = "CLUSTER");
  537. CHECK_IF_ABORTED();
  538. cluster(stmt->relname, stmt->indexname);
  539. }
  540. break;
  541. case T_VacuumStmt:
  542. PS_SET_STATUS(commandTag = "VACUUM");
  543. CHECK_IF_ABORTED();
  544. vacuum(((VacuumStmt *) parsetree)->vacrel,
  545.    ((VacuumStmt *) parsetree)->verbose,
  546.    ((VacuumStmt *) parsetree)->analyze,
  547.    ((VacuumStmt *) parsetree)->va_spec);
  548. break;
  549. case T_ExplainStmt:
  550. {
  551. ExplainStmt *stmt = (ExplainStmt *) parsetree;
  552. PS_SET_STATUS(commandTag = "EXPLAIN");
  553. CHECK_IF_ABORTED();
  554. ExplainQuery(stmt->query, stmt->verbose, dest);
  555. }
  556. break;
  557. #ifdef NOT_USED
  558. /*
  559.  * ******************************** Tioga-related statements *******************************
  560.  */
  561. case T_RecipeStmt:
  562. {
  563. RecipeStmt *stmt = (RecipeStmt *) parsetree;
  564. PS_SET_STATUS(commandTag = "EXECUTE RECIPE");
  565. CHECK_IF_ABORTED();
  566. beginRecipe(stmt);
  567. }
  568. break;
  569. #endif
  570. /*
  571.  * ******************************** set variable statements *******************************
  572.  */
  573. case T_VariableSetStmt:
  574. {
  575. VariableSetStmt *n = (VariableSetStmt *) parsetree;
  576. SetPGVariable(n->name, n->value);
  577. PS_SET_STATUS(commandTag = "SET VARIABLE");
  578. }
  579. break;
  580. case T_VariableShowStmt:
  581. {
  582. VariableShowStmt *n = (VariableShowStmt *) parsetree;
  583. GetPGVariable(n->name);
  584. PS_SET_STATUS(commandTag = "SHOW VARIABLE");
  585. }
  586. break;
  587. case T_VariableResetStmt:
  588. {
  589. VariableResetStmt *n = (VariableResetStmt *) parsetree;
  590. ResetPGVariable(n->name);
  591. PS_SET_STATUS(commandTag = "RESET VARIABLE");
  592. }
  593. break;
  594. /*
  595.  * ******************************** TRIGGER statements *******************************
  596.  */
  597. case T_CreateTrigStmt:
  598. PS_SET_STATUS(commandTag = "CREATE");
  599. CHECK_IF_ABORTED();
  600. CreateTrigger((CreateTrigStmt *) parsetree);
  601. break;
  602. case T_DropTrigStmt:
  603. PS_SET_STATUS(commandTag = "DROP");
  604. CHECK_IF_ABORTED();
  605. DropTrigger((DropTrigStmt *) parsetree);
  606. break;
  607. /*
  608.  * ************* PROCEDURAL LANGUAGE statements *****************
  609.  */
  610. case T_CreatePLangStmt:
  611. PS_SET_STATUS(commandTag = "CREATE");
  612. CHECK_IF_ABORTED();
  613. CreateProceduralLanguage((CreatePLangStmt *) parsetree);
  614. break;
  615. case T_DropPLangStmt:
  616. PS_SET_STATUS(commandTag = "DROP");
  617. CHECK_IF_ABORTED();
  618. DropProceduralLanguage((DropPLangStmt *) parsetree);
  619. break;
  620. /*
  621.  * ******************************** USER statements ****
  622.  *
  623.  */
  624. case T_CreateUserStmt:
  625. PS_SET_STATUS(commandTag = "CREATE USER");
  626. CHECK_IF_ABORTED();
  627. DefineUser((CreateUserStmt *) parsetree, dest);
  628. break;
  629. case T_AlterUserStmt:
  630. PS_SET_STATUS(commandTag = "ALTER USER");
  631. CHECK_IF_ABORTED();
  632. AlterUser((AlterUserStmt *) parsetree, dest);
  633. break;
  634. case T_DropUserStmt:
  635. PS_SET_STATUS(commandTag = "DROP USER");
  636. CHECK_IF_ABORTED();
  637. RemoveUser(((DropUserStmt *) parsetree)->user, dest);
  638. break;
  639. case T_LockStmt:
  640. PS_SET_STATUS(commandTag = "LOCK TABLE");
  641. CHECK_IF_ABORTED();
  642. LockTableCommand((LockStmt *) parsetree);
  643. break;
  644. /*
  645.  * ******************************** default ********************************
  646.  *
  647.  */
  648. default:
  649. elog(ERROR, "ProcessUtility: command #%d unsupported",
  650.  nodeTag(parsetree));
  651. break;
  652. }
  653. /* ----------------
  654.  * tell fe/be or whatever that we're done.
  655.  * ----------------
  656.  */
  657. EndCommand(commandTag, dest);
  658. }