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

数据库系统

开发平台:

Unix_Linux

  1. /**********************************************************************
  2.  * pl_funcs.c - Misc functins for the PL/pgSQL
  3.  *   procedural language
  4.  *
  5.  * IDENTIFICATION
  6.  *   $Header: /usr/local/cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.5 1999/05/25 16:15:18 momjian Exp $
  7.  *
  8.  *   This software is copyrighted by Jan Wieck - Hamburg.
  9.  *
  10.  *   The author hereby grants permission  to  use,  copy, modify,
  11.  *   distribute,  and license this software and its documentation
  12.  *   for any purpose, provided that existing copyright notices are
  13.  *   retained in all  copies  and  that this notice is included
  14.  *   verbatim in any distributions. No written agreement, license,
  15.  *   or  royalty  fee is required for any of the authorized uses.
  16.  *   Modifications to this software may be  copyrighted  by  their
  17.  *   author  and  need  not  follow  the licensing terms described
  18.  *   here, provided that the new terms are  clearly  indicated  on
  19.  *   the first page of each file where they apply.
  20.  *
  21.  *   IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
  22.  *   PARTY  FOR  DIRECT, INDIRECT, SPECIAL,   INCIDENTAL,  OR
  23.  *   CONSEQUENTIAL   DAMAGES  ARISING OUT  OF  THE  USE  OF  THIS
  24.  *   SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
  25.  *   IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
  26.  *   DAMAGE.
  27.  *
  28.  *   THE  AUTHOR  AND DISTRIBUTORS  SPECIFICALLY  DISCLAIM ANY
  29.  *   WARRANTIES,  INCLUDING,  BUT NOT  LIMITED  TO,  THE IMPLIED
  30.  *   WARRANTIES  OF  MERCHANTABILITY, FITNESS  FOR  A  PARTICULAR
  31.  *   PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
  32.  *   AN "AS IS" BASIS, AND THE AUTHOR AND  DISTRIBUTORS  HAVE  NO
  33.  *   OBLIGATION   TO PROVIDE   MAINTENANCE,  SUPPORT,  UPDATES,
  34.  *   ENHANCEMENTS, OR MODIFICATIONS.
  35.  *
  36.  **********************************************************************/
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <stdarg.h>
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #include <string.h>
  43. #include <ctype.h>
  44. #include "plpgsql.h"
  45. #include "pl.tab.h"
  46. /* ----------
  47.  * Local variables for the namestack handling
  48.  * ----------
  49.  */
  50. static PLpgSQL_ns *ns_current = NULL;
  51. static bool ns_localmode = false;
  52. /* ----------
  53.  * plpgsql_dstring_init Dynamic string initialization
  54.  * ----------
  55.  */
  56. void
  57. plpgsql_dstring_init(PLpgSQL_dstring * ds)
  58. {
  59. ds->value = palloc(ds->alloc = 512);
  60. ds->used = 0;
  61. }
  62. /* ----------
  63.  * plpgsql_dstring_free Dynamic string destruction
  64.  * ----------
  65.  */
  66. void
  67. plpgsql_dstring_free(PLpgSQL_dstring * ds)
  68. {
  69. pfree(ds->value);
  70. }
  71. /* ----------
  72.  * plpgsql_dstring_append Dynamic string extending
  73.  * ----------
  74.  */
  75. void
  76. plpgsql_dstring_append(PLpgSQL_dstring * ds, char *str)
  77. {
  78. int len = strlen(str);
  79. if (ds->used + len + 1 > ds->alloc)
  80. {
  81. ds->alloc *= 2;
  82. ds->value = repalloc(ds->value, ds->alloc);
  83. }
  84. strcpy(&(ds->value[ds->used]), str);
  85. ds->used += len;
  86. }
  87. /* ----------
  88.  * plpgsql_dstring_get Dynamic string get value
  89.  * ----------
  90.  */
  91. char *
  92. plpgsql_dstring_get(PLpgSQL_dstring * ds)
  93. {
  94. return ds->value;
  95. }
  96. /* ----------
  97.  * plpgsql_ns_init Initialize the namestack
  98.  * ----------
  99.  */
  100. void
  101. plpgsql_ns_init(void)
  102. {
  103. ns_current = NULL;
  104. ns_localmode = false;
  105. }
  106. /* ----------
  107.  * plpgsql_ns_setlocal Tell plpgsql_ns_lookup to or to
  108.  * not look into the current level
  109.  * only.
  110.  * ----------
  111.  */
  112. bool
  113. plpgsql_ns_setlocal(bool flag)
  114. {
  115. bool oldstate;
  116. oldstate = ns_localmode;
  117. ns_localmode = flag;
  118. return oldstate;
  119. }
  120. /* ----------
  121.  * plpgsql_ns_push Enter a new namestack level
  122.  * ----------
  123.  */
  124. void
  125. plpgsql_ns_push(char *label)
  126. {
  127. PLpgSQL_ns *new;
  128. new = palloc(sizeof(PLpgSQL_ns));
  129. memset(new, 0, sizeof(PLpgSQL_ns));
  130. new->upper = ns_current;
  131. ns_current = new;
  132. plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);
  133. }
  134. /* ----------
  135.  * plpgsql_ns_pop Return to the previous level
  136.  * ----------
  137.  */
  138. void
  139. plpgsql_ns_pop()
  140. {
  141. int i;
  142. PLpgSQL_ns *old;
  143. old = ns_current;
  144. ns_current = old->upper;
  145. for (i = 0; i < old->items_used; i++)
  146. pfree(old->items[i]);
  147. pfree(old->items);
  148. pfree(old);
  149. }
  150. /* ----------
  151.  * plpgsql_ns_additem Add an item to the current
  152.  * namestack level
  153.  * ----------
  154.  */
  155. void
  156. plpgsql_ns_additem(int itemtype, int itemno, char *name)
  157. {
  158. PLpgSQL_ns *ns = ns_current;
  159. PLpgSQL_nsitem *nse;
  160. if (name == NULL)
  161. name = "";
  162. name = plpgsql_tolower(name);
  163. if (ns->items_used == ns->items_alloc)
  164. {
  165. if (ns->items_alloc == 0)
  166. {
  167. ns->items_alloc = 32;
  168. ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
  169. }
  170. else
  171. {
  172. ns->items_alloc *= 2;
  173. ns->items = repalloc(ns->items,
  174.  sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
  175. }
  176. }
  177. nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));
  178. nse->itemtype = itemtype;
  179. nse->itemno = itemno;
  180. strcpy(nse->name, name);
  181. ns->items[ns->items_used++] = nse;
  182. }
  183. /* ----------
  184.  * plpgsql_ns_lookup Lookup for a word in the namestack
  185.  * ----------
  186.  */
  187. PLpgSQL_nsitem *
  188. plpgsql_ns_lookup(char *name, char *label)
  189. {
  190. PLpgSQL_ns *ns;
  191. int i;
  192. /* ----------
  193.  * If a label is specified, lookup only in that
  194.  * ----------
  195.  */
  196. if (label != NULL)
  197. {
  198. for (ns = ns_current; ns != NULL; ns = ns->upper)
  199. {
  200. if (!strcmp(ns->items[0]->name, label))
  201. {
  202. for (i = 1; i < ns->items_used; i++)
  203. {
  204. if (!strcmp(ns->items[i]->name, name))
  205. return ns->items[i];
  206. }
  207. return NULL; /* name not found in specified label */
  208. }
  209. }
  210. return NULL; /* label not found */
  211. }
  212. /* ----------
  213.  * No label given, lookup for visible labels ignoring localmode
  214.  * ----------
  215.  */
  216. for (ns = ns_current; ns != NULL; ns = ns->upper)
  217. {
  218. if (!strcmp(ns->items[0]->name, name))
  219. return ns->items[0];
  220. }
  221. /* ----------
  222.  * Finally lookup name in the namestack
  223.  * ----------
  224.  */
  225. for (ns = ns_current; ns != NULL; ns = ns->upper)
  226. {
  227. for (i = 1; i < ns->items_used; i++)
  228. {
  229. if (!strcmp(ns->items[i]->name, name))
  230. return ns->items[i];
  231. }
  232. if (ns_localmode)
  233. {
  234. return NULL; /* name not found in current namespace */
  235. }
  236. }
  237. return NULL;
  238. }
  239. /* ----------
  240.  * plpgsql_ns_rename Rename a namespace entry
  241.  * ----------
  242.  */
  243. void
  244. plpgsql_ns_rename(char *oldname, char *newname)
  245. {
  246. PLpgSQL_ns *ns;
  247. PLpgSQL_nsitem *newitem;
  248. int i;
  249. /* ----------
  250.  * Lookup in the current namespace only
  251.  * ----------
  252.  */
  253. /* ----------
  254.  * Lookup name in the namestack
  255.  * ----------
  256.  */
  257. for (ns = ns_current; ns != NULL; ns = ns->upper)
  258. {
  259. for (i = 1; i < ns->items_used; i++)
  260. {
  261. if (!strcmp(ns->items[i]->name, oldname))
  262. {
  263. newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname));
  264. newitem->itemtype = ns->items[i]->itemtype;
  265. newitem->itemno = ns->items[i]->itemno;
  266. strcpy(newitem->name, newname);
  267. pfree(oldname);
  268. pfree(newname);
  269. pfree(ns->items[i]);
  270. ns->items[i] = newitem;
  271. return;
  272. }
  273. }
  274. }
  275. elog(ERROR, "there is no variable '%s' in the current block", oldname);
  276. }
  277. /* ----------
  278.  * plpgsql_tolower Translate a string to lower case
  279.  * but honor "" escaping.
  280.  * ----------
  281.  */
  282. char *
  283. plpgsql_tolower(char *s)
  284. {
  285. char    *ret;
  286. char    *cp;
  287. ret = palloc(strlen(s) + 1);
  288. cp = ret;
  289. while (*s)
  290. {
  291. if (*s == '"')
  292. {
  293. s++;
  294. while (*s)
  295. {
  296. if (*s == '"')
  297. break;
  298. *cp++ = *s++;
  299. }
  300. if (*s != '"')
  301. {
  302. plpgsql_comperrinfo();
  303. elog(ERROR, "unterminated "");
  304. }
  305. s++;
  306. }
  307. else
  308. {
  309. if (isupper(*s))
  310. *cp++ = tolower(*s++);
  311. else
  312. *cp++ = *s++;
  313. }
  314. }
  315. *cp = '';
  316. return ret;
  317. }
  318. /**********************************************************************
  319.  * Debug functions for analyzing the compiled code
  320.  **********************************************************************/
  321. static int dump_indent;
  322. static void dump_ind();
  323. static void dump_stmt(PLpgSQL_stmt * stmt);
  324. static void dump_block(PLpgSQL_stmt_block * block);
  325. static void dump_assign(PLpgSQL_stmt_assign * stmt);
  326. static void dump_if(PLpgSQL_stmt_if * stmt);
  327. static void dump_loop(PLpgSQL_stmt_loop * stmt);
  328. static void dump_while(PLpgSQL_stmt_while * stmt);
  329. static void dump_fori(PLpgSQL_stmt_fori * stmt);
  330. static void dump_fors(PLpgSQL_stmt_fors * stmt);
  331. static void dump_select(PLpgSQL_stmt_select * stmt);
  332. static void dump_exit(PLpgSQL_stmt_exit * stmt);
  333. static void dump_return(PLpgSQL_stmt_return * stmt);
  334. static void dump_raise(PLpgSQL_stmt_raise * stmt);
  335. static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
  336. static void dump_expr(PLpgSQL_expr * expr);
  337. static void
  338. dump_ind()
  339. {
  340. int i;
  341. for (i = 0; i < dump_indent; i++)
  342. printf(" ");
  343. }
  344. static void
  345. dump_stmt(PLpgSQL_stmt * stmt)
  346. {
  347. printf("%3d:", stmt->lineno);
  348. switch (stmt->cmd_type)
  349. {
  350. case PLPGSQL_STMT_BLOCK:
  351. dump_block((PLpgSQL_stmt_block *) stmt);
  352. break;
  353. case PLPGSQL_STMT_ASSIGN:
  354. dump_assign((PLpgSQL_stmt_assign *) stmt);
  355. break;
  356. case PLPGSQL_STMT_IF:
  357. dump_if((PLpgSQL_stmt_if *) stmt);
  358. break;
  359. case PLPGSQL_STMT_LOOP:
  360. dump_loop((PLpgSQL_stmt_loop *) stmt);
  361. break;
  362. case PLPGSQL_STMT_WHILE:
  363. dump_while((PLpgSQL_stmt_while *) stmt);
  364. break;
  365. case PLPGSQL_STMT_FORI:
  366. dump_fori((PLpgSQL_stmt_fori *) stmt);
  367. break;
  368. case PLPGSQL_STMT_FORS:
  369. dump_fors((PLpgSQL_stmt_fors *) stmt);
  370. break;
  371. case PLPGSQL_STMT_SELECT:
  372. dump_select((PLpgSQL_stmt_select *) stmt);
  373. break;
  374. case PLPGSQL_STMT_EXIT:
  375. dump_exit((PLpgSQL_stmt_exit *) stmt);
  376. break;
  377. case PLPGSQL_STMT_RETURN:
  378. dump_return((PLpgSQL_stmt_return *) stmt);
  379. break;
  380. case PLPGSQL_STMT_RAISE:
  381. dump_raise((PLpgSQL_stmt_raise *) stmt);
  382. break;
  383. case PLPGSQL_STMT_EXECSQL:
  384. dump_execsql((PLpgSQL_stmt_execsql *) stmt);
  385. break;
  386. default:
  387. elog(ERROR, "plpgsql_dump: unknown cmd_type %dn", stmt->cmd_type);
  388. break;
  389. }
  390. }
  391. static void
  392. dump_block(PLpgSQL_stmt_block * block)
  393. {
  394. int i;
  395. char    *name;
  396. if (block->label == NULL)
  397. name = "*unnamed*";
  398. else
  399. name = block->label;
  400. dump_ind();
  401. printf("BLOCK <<%s>>n", name);
  402. dump_indent += 2;
  403. for (i = 0; i < block->body->stmts_used; i++)
  404. dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i]));
  405. dump_indent -= 2;
  406. dump_ind();
  407. printf("    END -- %sn", name);
  408. }
  409. static void
  410. dump_assign(PLpgSQL_stmt_assign * stmt)
  411. {
  412. dump_ind();
  413. printf("ASSIGN var %d := ", stmt->varno);
  414. dump_expr(stmt->expr);
  415. printf("n");
  416. }
  417. static void
  418. dump_if(PLpgSQL_stmt_if * stmt)
  419. {
  420. int i;
  421. dump_ind();
  422. printf("IF ");
  423. dump_expr(stmt->cond);
  424. printf(" THENn");
  425. dump_indent += 2;
  426. for (i = 0; i < stmt->true_body->stmts_used; i++)
  427. dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i]));
  428. dump_indent -= 2;
  429. dump_ind();
  430. printf("    ELSEn");
  431. dump_indent += 2;
  432. for (i = 0; i < stmt->false_body->stmts_used; i++)
  433. dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i]));
  434. dump_indent -= 2;
  435. dump_ind();
  436. printf("    ENDIFn");
  437. }
  438. static void
  439. dump_loop(PLpgSQL_stmt_loop * stmt)
  440. {
  441. int i;
  442. dump_ind();
  443. printf("LOOPn");
  444. dump_indent += 2;
  445. for (i = 0; i < stmt->body->stmts_used; i++)
  446. dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
  447. dump_indent -= 2;
  448. dump_ind();
  449. printf("    ENDLOOPn");
  450. }
  451. static void
  452. dump_while(PLpgSQL_stmt_while * stmt)
  453. {
  454. int i;
  455. dump_ind();
  456. printf("WHILE ");
  457. dump_expr(stmt->cond);
  458. printf("n");
  459. dump_indent += 2;
  460. for (i = 0; i < stmt->body->stmts_used; i++)
  461. dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
  462. dump_indent -= 2;
  463. dump_ind();
  464. printf("    ENDWHILEn");
  465. }
  466. static void
  467. dump_fori(PLpgSQL_stmt_fori * stmt)
  468. {
  469. int i;
  470. dump_ind();
  471. printf("FORI %s %sn", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
  472. dump_indent += 2;
  473. dump_ind();
  474. printf("    lower = ");
  475. dump_expr(stmt->lower);
  476. printf("n");
  477. dump_ind();
  478. printf("    upper = ");
  479. dump_expr(stmt->upper);
  480. printf("n");
  481. for (i = 0; i < stmt->body->stmts_used; i++)
  482. dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
  483. dump_indent -= 2;
  484. dump_ind();
  485. printf("    ENDFORIn");
  486. }
  487. static void
  488. dump_fors(PLpgSQL_stmt_fors * stmt)
  489. {
  490. int i;
  491. dump_ind();
  492. printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
  493. dump_expr(stmt->query);
  494. printf("n");
  495. dump_indent += 2;
  496. for (i = 0; i < stmt->body->stmts_used; i++)
  497. dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
  498. dump_indent -= 2;
  499. dump_ind();
  500. printf("    ENDFORSn");
  501. }
  502. static void
  503. dump_select(PLpgSQL_stmt_select * stmt)
  504. {
  505. dump_ind();
  506. printf("SELECT ");
  507. dump_expr(stmt->query);
  508. printf("n");
  509. dump_indent += 2;
  510. if (stmt->rec != NULL)
  511. {
  512. dump_ind();
  513. printf("    target = %d %sn", stmt->rec->recno, stmt->rec->refname);
  514. }
  515. if (stmt->row != NULL)
  516. {
  517. dump_ind();
  518. printf("    target = %d %sn", stmt->row->rowno, stmt->row->refname);
  519. }
  520. dump_indent -= 2;
  521. }
  522. static void
  523. dump_exit(PLpgSQL_stmt_exit * stmt)
  524. {
  525. dump_ind();
  526. printf("EXIT lbl='%s'", stmt->label);
  527. if (stmt->cond != NULL)
  528. {
  529. printf(" WHEN ");
  530. dump_expr(stmt->cond);
  531. }
  532. printf("n");
  533. }
  534. static void
  535. dump_return(PLpgSQL_stmt_return * stmt)
  536. {
  537. dump_ind();
  538. printf("RETURN ");
  539. if (stmt->retrecno >= 0)
  540. printf("record %d", stmt->retrecno);
  541. else
  542. {
  543. if (stmt->expr == NULL)
  544. printf("NULL");
  545. else
  546. dump_expr(stmt->expr);
  547. }
  548. printf("n");
  549. }
  550. static void
  551. dump_raise(PLpgSQL_stmt_raise * stmt)
  552. {
  553. int i;
  554. dump_ind();
  555. printf("RAISE '%s'", stmt->message);
  556. for (i = 0; i < stmt->nparams; i++)
  557. printf(" %d", stmt->params[i]);
  558. printf("n");
  559. }
  560. static void
  561. dump_execsql(PLpgSQL_stmt_execsql * stmt)
  562. {
  563. dump_ind();
  564. printf("EXECSQL ");
  565. dump_expr(stmt->sqlstmt);
  566. printf("n");
  567. }
  568. static void
  569. dump_expr(PLpgSQL_expr * expr)
  570. {
  571. int i;
  572. printf("'%s", expr->query);
  573. if (expr->nparams > 0)
  574. {
  575. printf(" {");
  576. for (i = 0; i < expr->nparams; i++)
  577. {
  578. if (i > 0)
  579. printf(", ");
  580. printf("$%d=%d", i + 1, expr->params[i]);
  581. }
  582. printf("}");
  583. }
  584. printf("'");
  585. }
  586. void
  587. plpgsql_dumptree(PLpgSQL_function * func)
  588. {
  589. int i;
  590. PLpgSQL_datum *d;
  591. printf("nExecution tree of successfully compiled PL/pgSQL function %s:n",
  592.    func->fn_name);
  593. printf("nFunctions data area:n");
  594. for (i = 0; i < func->ndatums; i++)
  595. {
  596. d = func->datums[i];
  597. printf("    entry %d: ", i);
  598. switch (d->dtype)
  599. {
  600. case PLPGSQL_DTYPE_VAR:
  601. {
  602. PLpgSQL_var *var = (PLpgSQL_var *) d;
  603. printf("VAR %-16s type %s (typoid %u) atttypmod %dn",
  604.    var->refname, var->datatype->typname,
  605.    var->datatype->typoid,
  606.    var->datatype->atttypmod);
  607. }
  608. break;
  609. case PLPGSQL_DTYPE_ROW:
  610. {
  611. PLpgSQL_row *row = (PLpgSQL_row *) d;
  612. int i;
  613. printf("ROW %-16s fields", row->refname);
  614. for (i = 0; i < row->nfields; i++)
  615. {
  616. printf(" %s=var %d", row->fieldnames[i],
  617.    row->varnos[i]);
  618. }
  619. printf("n");
  620. }
  621. break;
  622. case PLPGSQL_DTYPE_REC:
  623. printf("REC %sn", ((PLpgSQL_rec *) d)->refname);
  624. break;
  625. case PLPGSQL_DTYPE_RECFIELD:
  626. printf("RECFIELD %-16s of REC %dn", ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recno);
  627. break;
  628. case PLPGSQL_DTYPE_TRIGARG:
  629. printf("TRIGARG ");
  630. dump_expr(((PLpgSQL_trigarg *) d)->argnum);
  631. printf("n");
  632. break;
  633. default:
  634. printf("??? unknown data type %dn", d->dtype);
  635. }
  636. }
  637. printf("nFunctions statements:n");
  638. dump_indent = 0;
  639. printf("%3d:", func->action->lineno);
  640. dump_block(func->action);
  641. printf("nEnd of execution tree of function %snn", func->fn_name);
  642. }