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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * pg_dump.c
  4.  *   pg_dump is an utility for dumping out a postgres database
  5.  * into a script file.
  6.  *
  7.  * pg_dump will read the system catalogs in a database and
  8.  * dump out a script that reproduces
  9.  * the schema of the database in terms of
  10.  *   user-defined types
  11.  *   user-defined functions
  12.  *   tables
  13.  *   indices
  14.  *   aggregates
  15.  *   operators
  16.  *   ACL - grant/revoke
  17.  *
  18.  * the output script is SQL that is understood by PostgreSQL
  19.  *
  20.  * Copyright (c) 1994, Regents of the University of California
  21.  *
  22.  *
  23.  * IDENTIFICATION
  24.  *   $Header: /usr/local/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.115.2.1 1999/09/01 23:06:26 momjian Exp $
  25.  *
  26.  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  27.  *
  28.  *  Applied 'insert string' patch from "Marc G. Fournier" <scrappy@ki.net>
  29.  *  Added '-t table' option
  30.  *  Added '-a' option
  31.  *  Added '-da' option
  32.  *
  33.  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
  34.  *
  35.  *  - Fixed dumpTable output to output lengths for char and varchar types!
  36.  *  - Added single. quote to twin single quote expansion for 'insert' string
  37.  *    mode.
  38.  *
  39.  * Modifications - 7/26/96 - asussman@vidya.com
  40.  *
  41.  *  - Fixed ouput lengths for char and varchar type where the length is variable (-1)
  42.  *
  43.  * Modifications - 6/1/97 - igor@sba.miami.edu
  44.  * - Added functions to free allocated memory used for retrieving
  45.  *  indices,tables,inheritance,types,functions and aggregates.
  46.  *  No more leaks reported by Purify.
  47.  *
  48.  *
  49.  * Modifications - 1/26/98 - pjlobo@euitt.upm.es
  50.  *  - Added support for password authentication
  51.  *-------------------------------------------------------------------------
  52.  */
  53. #include <stdlib.h>
  54. #include <unistd.h> /* for getopt() */
  55. #include <stdio.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58. #include <sys/param.h> /* for MAXHOSTNAMELEN on most */
  59. #ifdef solaris_sparc
  60. #include <netdb.h> /* for MAXHOSTNAMELEN on some */
  61. #endif
  62. #include "postgres.h"
  63. #include "access/htup.h"
  64. #include "catalog/pg_type.h"
  65. #include "catalog/pg_language.h"
  66. #include "catalog/pg_index.h"
  67. #include "catalog/pg_trigger.h"
  68. #include "libpq-fe.h"
  69. #ifndef HAVE_STRDUP
  70. #include "strdup.h"
  71. #endif
  72. #ifdef HAVE_TERMIOS_H
  73. #include <termios.h>
  74. #endif
  75. #ifdef __CYGWIN32__
  76. #include <getopt.h>
  77. #endif
  78. #include "pg_dump.h"
  79. static void dumpSequence(FILE *fout, TableInfo tbinfo);
  80. static void dumpACL(FILE *fout, TableInfo tbinfo);
  81. static void dumpTriggers(FILE *fout, const char *tablename,
  82.  TableInfo *tblinfo, int numTables);
  83. static void dumpRules(FILE *fout, const char *tablename,
  84.   TableInfo *tblinfo, int numTables);
  85. static char *checkForQuote(const char *s);
  86. static void clearTableInfo(TableInfo *, int);
  87. static void dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
  88. TypeInfo *tinfo, int numTypes);
  89. static int findLastBuiltinOid(void);
  90. static bool isViewRule(char *relname);
  91. static void setMaxOid(FILE *fout);
  92. static void AddAcl(char *aclbuf, const char *keyword);
  93. static char *GetPrivileges(const char *s);
  94. static void becomeUser(FILE *fout, const char *username);
  95. extern char *optarg;
  96. extern int optind,
  97. opterr;
  98. /* global decls */
  99. bool g_verbose; /* User wants verbose narration of our
  100.  * activities. */
  101. int g_last_builtin_oid; /* value of the last builtin oid */
  102. FILE    *g_fout; /* the script file */
  103. PGconn    *g_conn; /* the database connection */
  104. bool force_quotes; /* User wants to suppress double-quotes */
  105. bool dumpData; /* dump data using proper insert strings */
  106. bool attrNames; /* put attr names into insert strings */
  107. bool schemaOnly;
  108. bool dataOnly;
  109. bool aclsSkip;
  110. bool dropSchema;
  111. char g_opaque_type[10]; /* name for the opaque type */
  112. /* placeholders for the delimiters for comments */
  113. char g_comment_start[10];
  114. char g_comment_end[10];
  115. static void
  116. usage(const char *progname)
  117. {
  118. fprintf(stderr,
  119. "usage:  %s [options] dbnamen", progname);
  120. fprintf(stderr,
  121. "t -a          tt dump out only the data, no scheman");
  122. fprintf(stderr,
  123. "t -c          tt clean(drop) schema prior to createn");
  124. fprintf(stderr,
  125. "t -d          tt dump data as proper insert stringsn");
  126. fprintf(stderr,
  127. "t -D          tt dump data as inserts"
  128. " with attribute namesn");
  129. fprintf(stderr,
  130. "t -f filename tt script output filenamen");
  131. fprintf(stderr,
  132. "t -h hostname tt server host namen");
  133. fprintf(stderr,
  134. "t -n          tt suppress most quotes around identifiersn");
  135. fprintf(stderr,
  136.   "t -N          tt enable most quotes around identifiersn");
  137. fprintf(stderr,
  138. "t -o          tt dump object id's (oids)n");
  139. fprintf(stderr,
  140. "t -p port     tt server port numbern");
  141. fprintf(stderr,
  142. "t -s          tt dump out only the schema, no datan");
  143. fprintf(stderr,
  144. "t -t table    tt dump for this table onlyn");
  145. fprintf(stderr,
  146. "t -u          tt use password authenticationn");
  147. fprintf(stderr,
  148. "t -v          tt verbosen");
  149. fprintf(stderr,
  150. "t -x          tt do not dump ACL's (grant/revoke)n");
  151. fprintf(stderr,
  152. "nIf dbname is not supplied, then the DATABASE environment "
  153. "variable value is used.n");
  154. fprintf(stderr, "n");
  155. exit(1);
  156. }
  157. static void
  158. exit_nicely(PGconn *conn)
  159. {
  160. PQfinish(conn);
  161. exit(1);
  162. }
  163. /*
  164.  * isViewRule
  165.  * Determine if the relation is a VIEW
  166.  *
  167.  */
  168. static bool
  169. isViewRule(char *relname)
  170. {
  171. PGresult   *res;
  172. int ntups;
  173. char query[MAX_QUERY_SIZE];
  174. sprintf(query, "select relname from pg_class, pg_rewrite "
  175. "where pg_class.oid = ev_class "
  176. "and pg_rewrite.ev_type = '1' "
  177. "and rulename = '_RET%s'", relname);
  178. res = PQexec(g_conn, query);
  179. if (!res ||
  180. PQresultStatus(res) != PGRES_TUPLES_OK)
  181. {
  182. fprintf(stderr, "isViewRule(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  183. exit_nicely(g_conn);
  184. }
  185. ntups = PQntuples(res);
  186. PQclear(res);
  187. return ntups > 0 ? TRUE : FALSE;
  188. }
  189. #define COPYBUFSIZ 8192
  190. static void
  191. dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
  192. {
  193. PGresult   *res;
  194. char query[255];
  195. int ret;
  196. bool copydone;
  197. char copybuf[COPYBUFSIZ];
  198. if (oids == true)
  199. {
  200. fprintf(fout, "COPY %s WITH OIDS FROM stdin;n",
  201. fmtId(classname, force_quotes));
  202. sprintf(query, "COPY %s WITH OIDS TO stdout;n",
  203. fmtId(classname, force_quotes));
  204. }
  205. else
  206. {
  207. fprintf(fout, "COPY %s FROM stdin;n", fmtId(classname, force_quotes));
  208. sprintf(query, "COPY %s TO stdout;n", fmtId(classname, force_quotes));
  209. }
  210. res = PQexec(g_conn, query);
  211. if (!res ||
  212. PQresultStatus(res) == PGRES_FATAL_ERROR)
  213. {
  214. fprintf(stderr, "SQL query to dump the contents of Table '%s' "
  215. "did not execute.  Explanation from backend: '%s'.n"
  216. "The query was: '%s'.n",
  217. classname, PQerrorMessage(g_conn), query);
  218. exit_nicely(g_conn);
  219. }
  220. else
  221. {
  222. if (PQresultStatus(res) != PGRES_COPY_OUT)
  223. {
  224. fprintf(stderr, "SQL query to dump the contents of Table '%s' "
  225. "executed abnormally.n"
  226. "PQexec() returned status %d when %d was expected.n"
  227. "The query was: '%s'.n",
  228.   classname, PQresultStatus(res), PGRES_COPY_OUT, query);
  229. exit_nicely(g_conn);
  230. }
  231. else
  232. {
  233. copydone = false;
  234. while (!copydone)
  235. {
  236. ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
  237. if (copybuf[0] == '\' &&
  238. copybuf[1] == '.' &&
  239. copybuf[2] == '')
  240. {
  241. copydone = true; /* don't print this... */
  242. }
  243. else
  244. {
  245. fputs(copybuf, fout);
  246. switch (ret)
  247. {
  248. case EOF:
  249. copydone = true;
  250. /* FALLTHROUGH */
  251. case 0:
  252. fputc('n', fout);
  253. break;
  254. case 1:
  255. break;
  256. }
  257. }
  258. }
  259. fprintf(fout, "\.n");
  260. }
  261. ret = PQendcopy(g_conn);
  262. if (ret != 0)
  263. {
  264. fprintf(stderr, "SQL query to dump the contents of Table '%s' "
  265. "did not execute correctly.  After we read all the "
  266.  "table contents from the backend, PQendcopy() failed.  "
  267. "Explanation from backend: '%s'.n"
  268. "The query was: '%s'.n",
  269. classname, PQerrorMessage(g_conn), query);
  270. PQclear(res);
  271. exit_nicely(g_conn);
  272. }
  273. }
  274. }
  275. static void
  276. dumpClasses_dumpData(FILE *fout, const char *classname,
  277.  const TableInfo tblinfo, bool oids)
  278. {
  279. PGresult   *res;
  280. char q[MAX_QUERY_SIZE];
  281. int tuple;
  282. int field;
  283. char    *expsrc;
  284. sprintf(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
  285. res = PQexec(g_conn, q);
  286. if (!res ||
  287. PQresultStatus(res) != PGRES_TUPLES_OK)
  288. {
  289. fprintf(stderr, "dumpClasses(): command failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  290. exit_nicely(g_conn);
  291. }
  292. for (tuple = 0; tuple < PQntuples(res); tuple++)
  293. {
  294. fprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
  295. if (attrNames == true)
  296. {
  297. sprintf(q, "(");
  298. for (field = 0; field < PQnfields(res); field++)
  299. {
  300. if (field > 0)
  301. strcat(q, ",");
  302. strcat(q, fmtId(PQfname(res, field), force_quotes));
  303. }
  304. strcat(q, ") ");
  305. fprintf(fout, "%s", q);
  306. }
  307. fprintf(fout, "VALUES (");
  308. for (field = 0; field < PQnfields(res); field++)
  309. {
  310. if (field > 0)
  311. fprintf(fout, ",");
  312. if (PQgetisnull(res, tuple, field))
  313. {
  314. fprintf(fout, "NULL");
  315. continue;
  316. }
  317. switch (PQftype(res, field))
  318. {
  319. case INT2OID:
  320. case INT4OID:
  321. case OIDOID: /* int types */
  322. case FLOAT4OID:
  323. case FLOAT8OID: /* float types */
  324. /* These types are printed without quotes */
  325. fprintf(fout, "%s",
  326. PQgetvalue(res, tuple, field));
  327. break;
  328. default:
  329. /*
  330.  * All other types are printed as string literals,
  331.  * with appropriate escaping of special
  332.  * characters. Quote mark ' goes to '' per SQL
  333.  * standard, other stuff goes to  sequences.
  334.  */
  335. putc(''', fout);
  336. expsrc = PQgetvalue(res, tuple, field);
  337. while (*expsrc)
  338. {
  339. char ch = *expsrc++;
  340. if (ch == '\' || ch == ''')
  341. {
  342. putc(ch, fout); /* double these */
  343. putc(ch, fout);
  344. }
  345. else if (ch < '40')
  346. {
  347. /* generate octal escape for control chars */
  348. putc('\', fout);
  349. putc(((ch >> 6) & 3) + '0', fout);
  350. putc(((ch >> 3) & 7) + '0', fout);
  351. putc((ch & 7) + '0', fout);
  352. }
  353. else
  354. putc(ch, fout);
  355. }
  356. putc(''', fout);
  357. break;
  358. }
  359. }
  360. fprintf(fout, ");n");
  361. }
  362. PQclear(res);
  363. }
  364. /*
  365.  * DumpClasses -
  366.  *   dump the contents of all the classes.
  367.  */
  368. static void
  369. dumpClasses(const TableInfo *tblinfo, const int numTables, FILE *fout,
  370. const char *onlytable, const bool oids)
  371. {
  372. int i;
  373. char    *all_only;
  374. if (onlytable == NULL)
  375. all_only = "all";
  376. else
  377. all_only = "only";
  378. if (g_verbose)
  379. fprintf(stderr, "%s dumping out the contents of %s %d table%s/sequence%s %sn",
  380. g_comment_start, all_only,
  381. (onlytable == NULL) ? numTables : 1,
  382. (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
  383. g_comment_end);
  384. /* Dump SEQUENCEs first (if dataOnly) */
  385. if (dataOnly)
  386. {
  387. for (i = 0; i < numTables; i++)
  388. {
  389. if (!(tblinfo[i].sequence))
  390. continue;
  391. if (!onlytable || (!strcmp(tblinfo[i].relname, onlytable)))
  392. {
  393. if (g_verbose)
  394. fprintf(stderr, "%s dumping out schema of sequence '%s' %sn",
  395.  g_comment_start, tblinfo[i].relname, g_comment_end);
  396. becomeUser(fout, tblinfo[i].usename);
  397. dumpSequence(fout, tblinfo[i]);
  398. }
  399. }
  400. }
  401. for (i = 0; i < numTables; i++)
  402. {
  403. const char *classname = tblinfo[i].relname;
  404. /* Skip VIEW relations */
  405. if (isViewRule(tblinfo[i].relname))
  406. continue;
  407. if (tblinfo[i].sequence)/* already dumped */
  408. continue;
  409. if (!onlytable || (!strcmp(classname, onlytable)))
  410. {
  411. if (g_verbose)
  412. fprintf(stderr, "%s dumping out the contents of Table '%s' %sn",
  413. g_comment_start, classname, g_comment_end);
  414. becomeUser(fout, tblinfo[i].usename);
  415. if (!dumpData)
  416. dumpClasses_nodumpData(fout, classname, oids);
  417. else
  418. dumpClasses_dumpData(fout, classname, tblinfo[i], oids);
  419. }
  420. }
  421. }
  422. static void
  423. prompt_for_password(char *username, char *password)
  424. {
  425. char buf[512];
  426. int length;
  427. #ifdef HAVE_TERMIOS_H
  428. struct termios t_orig,
  429. t;
  430. #endif
  431. printf("Username: ");
  432. fgets(username, 100, stdin);
  433. length = strlen(username);
  434. /* skip rest of the line */
  435. if (length > 0 && username[length - 1] != 'n')
  436. {
  437. do
  438. {
  439. fgets(buf, 512, stdin);
  440. } while (buf[strlen(buf) - 1] != 'n');
  441. }
  442. if (length > 0 && username[length - 1] == 'n')
  443. username[length - 1] = '';
  444. printf("Password: ");
  445. #ifdef HAVE_TERMIOS_H
  446. tcgetattr(0, &t);
  447. t_orig = t;
  448. t.c_lflag &= ~ECHO;
  449. tcsetattr(0, TCSADRAIN, &t);
  450. #endif
  451. fgets(password, 100, stdin);
  452. #ifdef HAVE_TERMIOS_H
  453. tcsetattr(0, TCSADRAIN, &t_orig);
  454. #endif
  455. length = strlen(password);
  456. /* skip rest of the line */
  457. if (length > 0 && password[length - 1] != 'n')
  458. {
  459. do
  460. {
  461. fgets(buf, 512, stdin);
  462. } while (buf[strlen(buf) - 1] != 'n');
  463. }
  464. if (length > 0 && password[length - 1] == 'n')
  465. password[length - 1] = '';
  466. printf("nn");
  467. }
  468. int
  469. main(int argc, char **argv)
  470. {
  471. int c;
  472. const char *progname;
  473. const char *filename = NULL;
  474. const char *dbname = NULL;
  475. const char *pghost = NULL;
  476. const char *pgport = NULL;
  477. char    *tablename = NULL;
  478. bool oids = false;
  479. TableInfo  *tblinfo;
  480. int numTables;
  481. char connect_string[512] = "";
  482. char tmp_string[128];
  483. char username[100];
  484. char password[100];
  485. bool use_password = false;
  486. g_verbose = false;
  487. force_quotes = true;
  488. dropSchema = false;
  489. strcpy(g_comment_start, "-- ");
  490. g_comment_end[0] = '';
  491. strcpy(g_opaque_type, "opaque");
  492. dataOnly = schemaOnly = dumpData = attrNames = false;
  493. progname = *argv;
  494. while ((c = getopt(argc, argv, "acdDf:h:nNop:st:uvxz")) != EOF)
  495. {
  496. switch (c)
  497. {
  498. case 'a': /* Dump data only */
  499. dataOnly = true;
  500. break;
  501. case 'c': /* clean (i.e., drop) schema prior to
  502.  * create */
  503. dropSchema = true;
  504. break;
  505. case 'd': /* dump data as proper insert strings */
  506. dumpData = true;
  507. break;
  508. case 'D': /* dump data as proper insert strings with
  509.  * attr names */
  510. dumpData = true;
  511. attrNames = true;
  512. break;
  513. case 'f': /* output file name */
  514. filename = optarg;
  515. break;
  516. case 'h': /* server host */
  517. pghost = optarg;
  518. break;
  519. case 'n': /* Do not force double-quotes on
  520.  * identifiers */
  521. force_quotes = false;
  522. break;
  523. case 'N': /* Force double-quotes on identifiers */
  524. force_quotes = true;
  525. break;
  526. case 'o': /* Dump oids */
  527. oids = true;
  528. break;
  529. case 'p': /* server port */
  530. pgport = optarg;
  531. break;
  532. case 's': /* dump schema only */
  533. schemaOnly = true;
  534. break;
  535. case 't': /* Dump data for this table only */
  536. {
  537. int i;
  538. tablename = strdup(optarg);
  539. /*
  540.  * quoted string? Then strip quotes and preserve
  541.  * case...
  542.  */
  543. if (tablename[0] == '"')
  544. {
  545. strcpy(tablename, &tablename[1]);
  546. if (*(tablename + strlen(tablename) - 1) == '"')
  547. *(tablename + strlen(tablename) - 1) = '';
  548. }
  549. /* otherwise, convert table name to lowercase... */
  550. else
  551. {
  552. for (i = 0; tablename[i]; i++)
  553. if (isascii((unsigned char) tablename[i]) &&
  554. isupper(tablename[i]))
  555. tablename[i] = tolower(tablename[i]);
  556. }
  557. }
  558. break;
  559. case 'u':
  560. use_password = true;
  561. break;
  562. case 'v': /* verbose */
  563. g_verbose = true;
  564. break;
  565. case 'x': /* skip ACL dump */
  566. aclsSkip = true;
  567. break;
  568. case 'z': /* Old ACL option bjm 1999/05/27 */
  569. fprintf(stderr,
  570.  "%s: The -z option(dump ACLs) is now the default, continuing.n",
  571. progname);
  572. break;
  573. default:
  574. usage(progname);
  575. break;
  576. }
  577. }
  578. if (dumpData == true && oids == true)
  579. {
  580. fprintf(stderr,
  581.  "%s: INSERT's can not set oids, so INSERT and OID options can not be used together.n",
  582. progname);
  583. exit(2);
  584. }
  585. /* open the output file */
  586. if (filename == NULL)
  587. g_fout = stdout;
  588. else
  589. {
  590. #ifndef __CYGWIN32__
  591. g_fout = fopen(filename, "w");
  592. #else
  593. g_fout = fopen(filename, "wb");
  594. #endif
  595. if (g_fout == NULL)
  596. {
  597. fprintf(stderr,
  598.  "%s: could not open output file named %s for writingn",
  599. progname, filename);
  600. exit(2);
  601. }
  602. }
  603. /* find database */
  604. if (!(dbname = argv[optind]) &&
  605. !(dbname = getenv("DATABASE")))
  606. {
  607. fprintf(stderr, "%s: no database name specifiedn", progname);
  608. exit(2);
  609. }
  610. /* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
  611. if (pghost != NULL)
  612. {
  613. sprintf(tmp_string, "host=%s ", pghost);
  614. strcat(connect_string, tmp_string);
  615. }
  616. if (pgport != NULL)
  617. {
  618. sprintf(tmp_string, "port=%s ", pgport);
  619. strcat(connect_string, tmp_string);
  620. }
  621. if (dbname != NULL)
  622. {
  623. sprintf(tmp_string, "dbname=%s ", dbname);
  624. strcat(connect_string, tmp_string);
  625. }
  626. if (use_password)
  627. {
  628. prompt_for_password(username, password);
  629. strcat(connect_string, "authtype=password ");
  630. sprintf(tmp_string, "user=%s ", username);
  631. strcat(connect_string, tmp_string);
  632. sprintf(tmp_string, "password=%s ", password);
  633. strcat(connect_string, tmp_string);
  634. MemSet(tmp_string, 0, sizeof(tmp_string));
  635. MemSet(password, 0, sizeof(password));
  636. }
  637. g_conn = PQconnectdb(connect_string);
  638. MemSet(connect_string, 0, sizeof(connect_string));
  639. /* check to see that the backend connection was successfully made */
  640. if (PQstatus(g_conn) == CONNECTION_BAD)
  641. {
  642. fprintf(stderr, "Connection to database '%s' failed.n", dbname);
  643. fprintf(stderr, "%sn", PQerrorMessage(g_conn));
  644. exit_nicely(g_conn);
  645. }
  646. /*
  647.  * Start serializable transaction to dump consistent data
  648.  */
  649. {
  650. PGresult   *res;
  651. res = PQexec(g_conn, "begin");
  652. if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
  653. {
  654. fprintf(stderr, "BEGIN command failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  655. exit_nicely(g_conn);
  656. }
  657. PQclear(res);
  658. res = PQexec(g_conn, "set transaction isolation level serializable");
  659. if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
  660. {
  661. fprintf(stderr, "SET TRANSACTION command failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  662. exit_nicely(g_conn);
  663. }
  664. PQclear(res);
  665. }
  666. g_last_builtin_oid = findLastBuiltinOid();
  667. if (oids == true)
  668. setMaxOid(g_fout);
  669. if (!dataOnly)
  670. {
  671. if (g_verbose)
  672. fprintf(stderr, "%s last builtin oid is %u %sn",
  673. g_comment_start, g_last_builtin_oid, g_comment_end);
  674. tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip);
  675. }
  676. else
  677. tblinfo = dumpSchema(NULL, &numTables, tablename, aclsSkip);
  678. if (!schemaOnly)
  679. dumpClasses(tblinfo, numTables, g_fout, tablename, oids);
  680. if (!dataOnly) /* dump indexes and triggers at the end
  681.  * for performance */
  682. {
  683. dumpSchemaIdx(g_fout, tablename, tblinfo, numTables);
  684. dumpTriggers(g_fout, tablename, tblinfo, numTables);
  685. dumpRules(g_fout, tablename, tblinfo, numTables);
  686. }
  687. fflush(g_fout);
  688. if (g_fout != stdout)
  689. fclose(g_fout);
  690. clearTableInfo(tblinfo, numTables);
  691. PQfinish(g_conn);
  692. exit(0);
  693. }
  694. /*
  695.  * getTypes:
  696.  *   read all base types in the system catalogs and return them in the
  697.  * TypeInfo* structure
  698.  *
  699.  * numTypes is set to the number of types read in
  700.  *
  701.  */
  702. TypeInfo   *
  703. getTypes(int *numTypes)
  704. {
  705. PGresult   *res;
  706. int ntups;
  707. int i;
  708. char query[MAX_QUERY_SIZE];
  709. TypeInfo   *tinfo;
  710. int i_oid;
  711. int i_typowner;
  712. int i_typname;
  713. int i_typlen;
  714. int i_typprtlen;
  715. int i_typinput;
  716. int i_typoutput;
  717. int i_typreceive;
  718. int i_typsend;
  719. int i_typelem;
  720. int i_typdelim;
  721. int i_typdefault;
  722. int i_typrelid;
  723. int i_typbyval;
  724. int i_usename;
  725. /* find all base types */
  726. /*
  727.  * we include even the built-in types because those may be used as
  728.  * array elements by user-defined types
  729.  */
  730. /*
  731.  * we filter out the built-in types when we dump out the types
  732.  */
  733. sprintf(query, "SELECT pg_type.oid, typowner,typname, typlen, typprtlen, "
  734.   "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
  735.   "typdefault, typrelid,typbyval, usename from pg_type, pg_user "
  736. "where typowner = usesysid");
  737. res = PQexec(g_conn, query);
  738. if (!res ||
  739. PQresultStatus(res) != PGRES_TUPLES_OK)
  740. {
  741. fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  742. exit_nicely(g_conn);
  743. }
  744. ntups = PQntuples(res);
  745. tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
  746. i_oid = PQfnumber(res, "oid");
  747. i_typowner = PQfnumber(res, "typowner");
  748. i_typname = PQfnumber(res, "typname");
  749. i_typlen = PQfnumber(res, "typlen");
  750. i_typprtlen = PQfnumber(res, "typprtlen");
  751. i_typinput = PQfnumber(res, "typinput");
  752. i_typoutput = PQfnumber(res, "typoutput");
  753. i_typreceive = PQfnumber(res, "typreceive");
  754. i_typsend = PQfnumber(res, "typsend");
  755. i_typelem = PQfnumber(res, "typelem");
  756. i_typdelim = PQfnumber(res, "typdelim");
  757. i_typdefault = PQfnumber(res, "typdefault");
  758. i_typrelid = PQfnumber(res, "typrelid");
  759. i_typbyval = PQfnumber(res, "typbyval");
  760. i_usename = PQfnumber(res, "usename");
  761. for (i = 0; i < ntups; i++)
  762. {
  763. tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
  764. tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
  765. tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
  766. tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
  767. tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
  768. tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
  769. tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
  770. tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
  771. tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
  772. tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
  773. tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
  774. tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
  775. tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
  776. tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
  777. if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
  778. tinfo[i].passedbyvalue = 0;
  779. else
  780. tinfo[i].passedbyvalue = 1;
  781. /*
  782.  * check for user-defined array types, omit system generated ones
  783.  */
  784. if ((strcmp(tinfo[i].typelem, "0") != 0) &&
  785. tinfo[i].typname[0] != '_')
  786. tinfo[i].isArray = 1;
  787. else
  788. tinfo[i].isArray = 0;
  789. }
  790. *numTypes = ntups;
  791. PQclear(res);
  792. return tinfo;
  793. }
  794. /*
  795.  * getOperators:
  796.  *   read all operators in the system catalogs and return them in the
  797.  * OprInfo* structure
  798.  *
  799.  * numOprs is set to the number of operators read in
  800.  *
  801.  *
  802.  */
  803. OprInfo    *
  804. getOperators(int *numOprs)
  805. {
  806. PGresult   *res;
  807. int ntups;
  808. int i;
  809. char query[MAX_QUERY_SIZE];
  810. OprInfo    *oprinfo;
  811. int i_oid;
  812. int i_oprname;
  813. int i_oprkind;
  814. int i_oprcode;
  815. int i_oprleft;
  816. int i_oprright;
  817. int i_oprcom;
  818. int i_oprnegate;
  819. int i_oprrest;
  820. int i_oprjoin;
  821. int i_oprcanhash;
  822. int i_oprlsortop;
  823. int i_oprrsortop;
  824. int i_usename;
  825. /*
  826.  * find all operators, including builtin operators, filter out
  827.  * system-defined operators at dump-out time
  828.  */
  829. sprintf(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
  830. "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
  831. "oprcanhash, oprlsortop, oprrsortop, usename "
  832. "from pg_operator, pg_user "
  833. "where oprowner = usesysid");
  834. res = PQexec(g_conn, query);
  835. if (!res ||
  836. PQresultStatus(res) != PGRES_TUPLES_OK)
  837. {
  838. fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  839. exit_nicely(g_conn);
  840. }
  841. ntups = PQntuples(res);
  842. *numOprs = ntups;
  843. oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
  844. i_oid = PQfnumber(res, "oid");
  845. i_oprname = PQfnumber(res, "oprname");
  846. i_oprkind = PQfnumber(res, "oprkind");
  847. i_oprcode = PQfnumber(res, "oprcode");
  848. i_oprleft = PQfnumber(res, "oprleft");
  849. i_oprright = PQfnumber(res, "oprright");
  850. i_oprcom = PQfnumber(res, "oprcom");
  851. i_oprnegate = PQfnumber(res, "oprnegate");
  852. i_oprrest = PQfnumber(res, "oprrest");
  853. i_oprjoin = PQfnumber(res, "oprjoin");
  854. i_oprcanhash = PQfnumber(res, "oprcanhash");
  855. i_oprlsortop = PQfnumber(res, "oprlsortop");
  856. i_oprrsortop = PQfnumber(res, "oprrsortop");
  857. i_usename = PQfnumber(res, "usename");
  858. for (i = 0; i < ntups; i++)
  859. {
  860. oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
  861. oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
  862. oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
  863. oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
  864. oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
  865. oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
  866. oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
  867. oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
  868. oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
  869. oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
  870. oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
  871. oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
  872. oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
  873. oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
  874. }
  875. PQclear(res);
  876. return oprinfo;
  877. }
  878. void
  879. clearTypeInfo(TypeInfo *tp, int numTypes)
  880. {
  881. int i;
  882. for (i = 0; i < numTypes; ++i)
  883. {
  884. if (tp[i].oid)
  885. free(tp[i].oid);
  886. if (tp[i].typowner)
  887. free(tp[i].typowner);
  888. if (tp[i].typname)
  889. free(tp[i].typname);
  890. if (tp[i].typlen)
  891. free(tp[i].typlen);
  892. if (tp[i].typprtlen)
  893. free(tp[i].typprtlen);
  894. if (tp[i].typinput)
  895. free(tp[i].typinput);
  896. if (tp[i].typoutput)
  897. free(tp[i].typoutput);
  898. if (tp[i].typreceive)
  899. free(tp[i].typreceive);
  900. if (tp[i].typsend)
  901. free(tp[i].typsend);
  902. if (tp[i].typelem)
  903. free(tp[i].typelem);
  904. if (tp[i].typdelim)
  905. free(tp[i].typdelim);
  906. if (tp[i].typdefault)
  907. free(tp[i].typdefault);
  908. if (tp[i].typrelid)
  909. free(tp[i].typrelid);
  910. if (tp[i].usename)
  911. free(tp[i].usename);
  912. }
  913. free(tp);
  914. }
  915. void
  916. clearFuncInfo(FuncInfo *fun, int numFuncs)
  917. {
  918. int i,
  919. a;
  920. if (!fun)
  921. return;
  922. for (i = 0; i < numFuncs; ++i)
  923. {
  924. if (fun[i].oid)
  925. free(fun[i].oid);
  926. if (fun[i].proname)
  927. free(fun[i].proname);
  928. if (fun[i].usename)
  929. free(fun[i].usename);
  930. for (a = 0; a < 8; ++a)
  931. if (fun[i].argtypes[a])
  932. free(fun[i].argtypes[a]);
  933. if (fun[i].prorettype)
  934. free(fun[i].prorettype);
  935. if (fun[i].prosrc)
  936. free(fun[i].prosrc);
  937. if (fun[i].probin)
  938. free(fun[i].probin);
  939. }
  940. free(fun);
  941. }
  942. static void
  943. clearTableInfo(TableInfo *tblinfo, int numTables)
  944. {
  945. int i,
  946. j;
  947. for (i = 0; i < numTables; ++i)
  948. {
  949. if (tblinfo[i].oid)
  950. free(tblinfo[i].oid);
  951. if (tblinfo[i].relacl)
  952. free(tblinfo[i].relacl);
  953. if (tblinfo[i].usename)
  954. free(tblinfo[i].usename);
  955. if (tblinfo[i].relname)
  956. free(tblinfo[i].relname);
  957. if (tblinfo[i].sequence)
  958. continue;
  959. /* Process Attributes */
  960. for (j = 0; j < tblinfo[i].numatts; j++)
  961. {
  962. if (tblinfo[i].attnames[j])
  963. free(tblinfo[i].attnames[j]);
  964. if (tblinfo[i].typnames[j])
  965. free(tblinfo[i].typnames[j]);
  966. }
  967. if (tblinfo[i].atttypmod)
  968. free((int *) tblinfo[i].atttypmod);
  969. if (tblinfo[i].inhAttrs)
  970. free((int *) tblinfo[i].inhAttrs);
  971. if (tblinfo[i].attnames)
  972. free(tblinfo[i].attnames);
  973. if (tblinfo[i].typnames)
  974. free(tblinfo[i].typnames);
  975. if (tblinfo[i].notnull)
  976. free(tblinfo[i].notnull);
  977. }
  978. free(tblinfo);
  979. }
  980. void
  981. clearInhInfo(InhInfo *inh, int numInherits)
  982. {
  983. int i;
  984. if (!inh)
  985. return;
  986. for (i = 0; i < numInherits; ++i)
  987. {
  988. if (inh[i].inhrel)
  989. free(inh[i].inhrel);
  990. if (inh[i].inhparent)
  991. free(inh[i].inhparent);
  992. }
  993. free(inh);
  994. }
  995. void
  996. clearOprInfo(OprInfo *opr, int numOprs)
  997. {
  998. int i;
  999. if (!opr)
  1000. return;
  1001. for (i = 0; i < numOprs; ++i)
  1002. {
  1003. if (opr[i].oid)
  1004. free(opr[i].oid);
  1005. if (opr[i].oprname)
  1006. free(opr[i].oprname);
  1007. if (opr[i].oprkind)
  1008. free(opr[i].oprkind);
  1009. if (opr[i].oprcode)
  1010. free(opr[i].oprcode);
  1011. if (opr[i].oprleft)
  1012. free(opr[i].oprleft);
  1013. if (opr[i].oprright)
  1014. free(opr[i].oprright);
  1015. if (opr[i].oprcom)
  1016. free(opr[i].oprcom);
  1017. if (opr[i].oprnegate)
  1018. free(opr[i].oprnegate);
  1019. if (opr[i].oprrest)
  1020. free(opr[i].oprrest);
  1021. if (opr[i].oprjoin)
  1022. free(opr[i].oprjoin);
  1023. if (opr[i].oprcanhash)
  1024. free(opr[i].oprcanhash);
  1025. if (opr[i].oprlsortop)
  1026. free(opr[i].oprlsortop);
  1027. if (opr[i].oprrsortop)
  1028. free(opr[i].oprrsortop);
  1029. if (opr[i].usename)
  1030. free(opr[i].usename);
  1031. }
  1032. free(opr);
  1033. }
  1034. void
  1035. clearIndInfo(IndInfo *ind, int numIndices)
  1036. {
  1037. int i,
  1038. a;
  1039. if (!ind)
  1040. return;
  1041. for (i = 0; i < numIndices; ++i)
  1042. {
  1043. if (ind[i].indexrelname)
  1044. free(ind[i].indexrelname);
  1045. if (ind[i].indrelname)
  1046. free(ind[i].indrelname);
  1047. if (ind[i].indamname)
  1048. free(ind[i].indamname);
  1049. if (ind[i].indproc)
  1050. free(ind[i].indproc);
  1051. if (ind[i].indisunique)
  1052. free(ind[i].indisunique);
  1053. for (a = 0; a < INDEX_MAX_KEYS; ++a)
  1054. {
  1055. if (ind[i].indkey[a])
  1056. free(ind[i].indkey[a]);
  1057. if (ind[i].indclass[a])
  1058. free(ind[i].indclass[a]);
  1059. }
  1060. }
  1061. free(ind);
  1062. }
  1063. void
  1064. clearAggInfo(AggInfo *agginfo, int numArgs)
  1065. {
  1066. int i;
  1067. if (!agginfo)
  1068. return;
  1069. for (i = 0; i < numArgs; ++i)
  1070. {
  1071. if (agginfo[i].oid)
  1072. free(agginfo[i].oid);
  1073. if (agginfo[i].aggname)
  1074. free(agginfo[i].aggname);
  1075. if (agginfo[i].aggtransfn1)
  1076. free(agginfo[i].aggtransfn1);
  1077. if (agginfo[i].aggtransfn2)
  1078. free(agginfo[i].aggtransfn2);
  1079. if (agginfo[i].aggfinalfn)
  1080. free(agginfo[i].aggfinalfn);
  1081. if (agginfo[i].aggtranstype1)
  1082. free(agginfo[i].aggtranstype1);
  1083. if (agginfo[i].aggbasetype)
  1084. free(agginfo[i].aggbasetype);
  1085. if (agginfo[i].aggtranstype2)
  1086. free(agginfo[i].aggtranstype2);
  1087. if (agginfo[i].agginitval1)
  1088. free(agginfo[i].agginitval1);
  1089. if (agginfo[i].agginitval2)
  1090. free(agginfo[i].agginitval2);
  1091. if (agginfo[i].usename)
  1092. free(agginfo[i].usename);
  1093. }
  1094. free(agginfo);
  1095. }
  1096. /*
  1097.  * getAggregates:
  1098.  *   read all the user-defined aggregates in the system catalogs and
  1099.  * return them in the AggInfo* structure
  1100.  *
  1101.  * numAggs is set to the number of aggregates read in
  1102.  *
  1103.  *
  1104.  */
  1105. AggInfo    *
  1106. getAggregates(int *numAggs)
  1107. {
  1108. PGresult   *res;
  1109. int ntups;
  1110. int i;
  1111. char query[MAX_QUERY_SIZE];
  1112. AggInfo    *agginfo;
  1113. int i_oid;
  1114. int i_aggname;
  1115. int i_aggtransfn1;
  1116. int i_aggtransfn2;
  1117. int i_aggfinalfn;
  1118. int i_aggtranstype1;
  1119. int i_aggbasetype;
  1120. int i_aggtranstype2;
  1121. int i_agginitval1;
  1122. int i_agginitval2;
  1123. int i_usename;
  1124. /* find all user-defined aggregates */
  1125. sprintf(query,
  1126. "SELECT pg_aggregate.oid, aggname, aggtransfn1, aggtransfn2, "
  1127. "aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, "
  1128.   "agginitval1, agginitval2, usename from pg_aggregate, pg_user "
  1129. "where aggowner = usesysid");
  1130. res = PQexec(g_conn, query);
  1131. if (!res ||
  1132. PQresultStatus(res) != PGRES_TUPLES_OK)
  1133. {
  1134. fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1135. exit_nicely(g_conn);
  1136. }
  1137. ntups = PQntuples(res);
  1138. *numAggs = ntups;
  1139. agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
  1140. i_oid = PQfnumber(res, "oid");
  1141. i_aggname = PQfnumber(res, "aggname");
  1142. i_aggtransfn1 = PQfnumber(res, "aggtransfn1");
  1143. i_aggtransfn2 = PQfnumber(res, "aggtransfn2");
  1144. i_aggfinalfn = PQfnumber(res, "aggfinalfn");
  1145. i_aggtranstype1 = PQfnumber(res, "aggtranstype1");
  1146. i_aggbasetype = PQfnumber(res, "aggbasetype");
  1147. i_aggtranstype2 = PQfnumber(res, "aggtranstype2");
  1148. i_agginitval1 = PQfnumber(res, "agginitval1");
  1149. i_agginitval2 = PQfnumber(res, "agginitval2");
  1150. i_usename = PQfnumber(res, "usename");
  1151. for (i = 0; i < ntups; i++)
  1152. {
  1153. agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
  1154. agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
  1155. agginfo[i].aggtransfn1 = strdup(PQgetvalue(res, i, i_aggtransfn1));
  1156. agginfo[i].aggtransfn2 = strdup(PQgetvalue(res, i, i_aggtransfn2));
  1157. agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
  1158. agginfo[i].aggtranstype1 = strdup(PQgetvalue(res, i, i_aggtranstype1));
  1159. agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
  1160. agginfo[i].aggtranstype2 = strdup(PQgetvalue(res, i, i_aggtranstype2));
  1161. agginfo[i].agginitval1 = strdup(PQgetvalue(res, i, i_agginitval1));
  1162. agginfo[i].agginitval2 = strdup(PQgetvalue(res, i, i_agginitval2));
  1163. agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
  1164. }
  1165. PQclear(res);
  1166. return agginfo;
  1167. }
  1168. /*
  1169.  * getFuncs:
  1170.  *   read all the user-defined functions in the system catalogs and
  1171.  * return them in the FuncInfo* structure
  1172.  *
  1173.  * numFuncs is set to the number of functions read in
  1174.  *
  1175.  *
  1176.  */
  1177. FuncInfo   *
  1178. getFuncs(int *numFuncs)
  1179. {
  1180. PGresult   *res;
  1181. int ntups;
  1182. int i;
  1183. char query[MAX_QUERY_SIZE];
  1184. FuncInfo   *finfo;
  1185. int i_oid;
  1186. int i_proname;
  1187. int i_prolang;
  1188. int i_pronargs;
  1189. int i_proargtypes;
  1190. int i_prorettype;
  1191. int i_proretset;
  1192. int i_prosrc;
  1193. int i_probin;
  1194. int i_usename;
  1195. /* find all user-defined funcs */
  1196. sprintf(query,
  1197. "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
  1198. "proretset, proargtypes, prosrc, probin, usename "
  1199. "from pg_proc, pg_user "
  1200. "where pg_proc.oid > '%u'::oid and proowner = usesysid",
  1201. g_last_builtin_oid);
  1202. res = PQexec(g_conn, query);
  1203. if (!res ||
  1204. PQresultStatus(res) != PGRES_TUPLES_OK)
  1205. {
  1206. fprintf(stderr, "getFuncs(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1207. exit_nicely(g_conn);
  1208. }
  1209. ntups = PQntuples(res);
  1210. *numFuncs = ntups;
  1211. finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));
  1212. i_oid = PQfnumber(res, "oid");
  1213. i_proname = PQfnumber(res, "proname");
  1214. i_prolang = PQfnumber(res, "prolang");
  1215. i_pronargs = PQfnumber(res, "pronargs");
  1216. i_proargtypes = PQfnumber(res, "proargtypes");
  1217. i_prorettype = PQfnumber(res, "prorettype");
  1218. i_proretset = PQfnumber(res, "proretset");
  1219. i_prosrc = PQfnumber(res, "prosrc");
  1220. i_probin = PQfnumber(res, "probin");
  1221. i_usename = PQfnumber(res, "usename");
  1222. for (i = 0; i < ntups; i++)
  1223. {
  1224. finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
  1225. finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
  1226. finfo[i].prosrc = checkForQuote(PQgetvalue(res, i, i_prosrc));
  1227. finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
  1228. finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
  1229. finfo[i].retset = (strcmp(PQgetvalue(res, i, i_proretset), "t") == 0);
  1230. finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
  1231. finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
  1232. finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
  1233. parseArgTypes(finfo[i].argtypes, PQgetvalue(res, i, i_proargtypes));
  1234. finfo[i].dumped = 0;
  1235. }
  1236. PQclear(res);
  1237. return finfo;
  1238. }
  1239. /*
  1240.  * getTables
  1241.  *   read all the user-defined tables (no indices, no catalogs)
  1242.  * in the system catalogs return them in the TableInfo* structure
  1243.  *
  1244.  * numTables is set to the number of tables read in
  1245.  *
  1246.  *
  1247.  */
  1248. TableInfo  *
  1249. getTables(int *numTables, FuncInfo *finfo, int numFuncs)
  1250. {
  1251. PGresult   *res;
  1252. int ntups;
  1253. int i;
  1254. char query[MAX_QUERY_SIZE];
  1255. TableInfo  *tblinfo;
  1256. int i_oid;
  1257. int i_relname;
  1258. int i_relkind;
  1259. int i_relacl;
  1260. int i_usename;
  1261. int i_relchecks;
  1262. int i_reltriggers;
  1263. /*
  1264.  * find all the user-defined tables (no indices and no catalogs),
  1265.  * ordering by oid is important so that we always process the parent
  1266.  * tables before the child tables when traversing the tblinfo*
  1267.  *
  1268.  * we ignore tables that are not type 'r' (ordinary relation)
  1269.  * or 'S' (sequence) --- in particular, Large Object relations
  1270.  * (type 'l') are ignored.
  1271.  */
  1272. sprintf(query,
  1273. "SELECT pg_class.oid, relname, relkind, relacl, usename, "
  1274. "relchecks, reltriggers "
  1275. "from pg_class, pg_user "
  1276. "where relowner = usesysid and "
  1277. "(relkind = 'r' or relkind = 'S') and relname !~ '^pg_' "
  1278. "order by oid");
  1279. res = PQexec(g_conn, query);
  1280. if (!res ||
  1281. PQresultStatus(res) != PGRES_TUPLES_OK)
  1282. {
  1283. fprintf(stderr, "getTables(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1284. exit_nicely(g_conn);
  1285. }
  1286. ntups = PQntuples(res);
  1287. *numTables = ntups;
  1288. tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));
  1289. i_oid = PQfnumber(res, "oid");
  1290. i_relname = PQfnumber(res, "relname");
  1291. i_relkind = PQfnumber(res, "relkind");
  1292. i_relacl = PQfnumber(res, "relacl");
  1293. i_usename = PQfnumber(res, "usename");
  1294. i_relchecks = PQfnumber(res, "relchecks");
  1295. i_reltriggers = PQfnumber(res, "reltriggers");
  1296. for (i = 0; i < ntups; i++)
  1297. {
  1298. tblinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
  1299. tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
  1300. tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
  1301. tblinfo[i].sequence = (strcmp(PQgetvalue(res, i, i_relkind), "S") == 0);
  1302. tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
  1303. tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
  1304. tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
  1305. /*
  1306.  * Exclude inherited CHECKs from CHECK constraints total. If a
  1307.  * constraint matches by name and condition with a constraint
  1308.  * belonging to a parent class, we assume it was inherited.
  1309.  */
  1310. if (tblinfo[i].ncheck > 0)
  1311. {
  1312. PGresult   *res2;
  1313. int ntups2;
  1314. if (g_verbose)
  1315. fprintf(stderr, "%s excluding inherited CHECK constraints "
  1316. "for relation: '%s' %sn",
  1317. g_comment_start,
  1318. tblinfo[i].relname,
  1319. g_comment_end);
  1320. sprintf(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
  1321. "where rcrelid = '%s'::oid "
  1322. " and rcrelid = i.inhrel"
  1323. " and exists "
  1324. "  (select * from pg_relcheck as c "
  1325. "    where c.rcname = pg_relcheck.rcname "
  1326. "      and c.rcsrc = pg_relcheck.rcsrc "
  1327. "      and c.rcrelid = i.inhparent) ",
  1328. tblinfo[i].oid);
  1329. res2 = PQexec(g_conn, query);
  1330. if (!res2 ||
  1331. PQresultStatus(res2) != PGRES_TUPLES_OK)
  1332. {
  1333. fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1334. exit_nicely(g_conn);
  1335. }
  1336. ntups2 = PQntuples(res2);
  1337. tblinfo[i].ncheck -= ntups2;
  1338. if (tblinfo[i].ncheck < 0)
  1339. {
  1340. fprintf(stderr, "getTables(): found more inherited CHECKs than total for "
  1341. "relation %sn",
  1342. tblinfo[i].relname);
  1343. exit_nicely(g_conn);
  1344. }
  1345. PQclear(res2);
  1346. }
  1347. /* Get non-inherited CHECK constraints, if any */
  1348. if (tblinfo[i].ncheck > 0)
  1349. {
  1350. PGresult   *res2;
  1351. int i_rcname,
  1352. i_rcsrc;
  1353. int ntups2;
  1354. int i2;
  1355. if (g_verbose)
  1356. fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %sn",
  1357. g_comment_start,
  1358. tblinfo[i].relname,
  1359. g_comment_end);
  1360. sprintf(query, "SELECT rcname, rcsrc from pg_relcheck "
  1361. "where rcrelid = '%s'::oid "
  1362. "   and not exists "
  1363. "  (select * from pg_relcheck as c, pg_inherits as i "
  1364. "   where i.inhrel = pg_relcheck.rcrelid "
  1365. "     and c.rcname = pg_relcheck.rcname "
  1366. "     and c.rcsrc = pg_relcheck.rcsrc "
  1367. "     and c.rcrelid = i.inhparent) ",
  1368. tblinfo[i].oid);
  1369. res2 = PQexec(g_conn, query);
  1370. if (!res2 ||
  1371. PQresultStatus(res2) != PGRES_TUPLES_OK)
  1372. {
  1373. fprintf(stderr, "getTables(): SELECT (for CHECK) failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1374. exit_nicely(g_conn);
  1375. }
  1376. ntups2 = PQntuples(res2);
  1377. if (ntups2 != tblinfo[i].ncheck)
  1378. {
  1379. fprintf(stderr, "getTables(): relation '%s': %d CHECKs were expected, but got %dn",
  1380. tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
  1381. exit_nicely(g_conn);
  1382. }
  1383. i_rcname = PQfnumber(res2, "rcname");
  1384. i_rcsrc = PQfnumber(res2, "rcsrc");
  1385. tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
  1386. for (i2 = 0; i2 < ntups2; i2++)
  1387. {
  1388. char    *name = PQgetvalue(res2, i2, i_rcname);
  1389. char    *expr = PQgetvalue(res2, i2, i_rcsrc);
  1390. query[0] = '';
  1391. if (name[0] != '$')
  1392. sprintf(query, "CONSTRAINT %s ", fmtId(name, force_quotes));
  1393. sprintf(query + strlen(query), "CHECK (%s)", expr);
  1394. tblinfo[i].check_expr[i2] = strdup(query);
  1395. }
  1396. PQclear(res2);
  1397. }
  1398. else
  1399. tblinfo[i].check_expr = NULL;
  1400. /* Get Triggers */
  1401. if (tblinfo[i].ntrig > 0)
  1402. {
  1403. PGresult   *res2;
  1404. int i_tgname,
  1405. i_tgfoid,
  1406. i_tgtype,
  1407. i_tgnargs,
  1408. i_tgargs;
  1409. int ntups2;
  1410. int i2;
  1411. if (g_verbose)
  1412. fprintf(stderr, "%s finding Triggers for relation: '%s' %sn",
  1413. g_comment_start,
  1414. tblinfo[i].relname,
  1415. g_comment_end);
  1416. sprintf(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs "
  1417. "from pg_trigger "
  1418. "where tgrelid = '%s'::oid ",
  1419. tblinfo[i].oid);
  1420. res2 = PQexec(g_conn, query);
  1421. if (!res2 ||
  1422. PQresultStatus(res2) != PGRES_TUPLES_OK)
  1423. {
  1424. fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1425. exit_nicely(g_conn);
  1426. }
  1427. ntups2 = PQntuples(res2);
  1428. if (ntups2 != tblinfo[i].ntrig)
  1429. {
  1430. fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %dn",
  1431. tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
  1432. exit_nicely(g_conn);
  1433. }
  1434. i_tgname = PQfnumber(res2, "tgname");
  1435. i_tgfoid = PQfnumber(res2, "tgfoid");
  1436. i_tgtype = PQfnumber(res2, "tgtype");
  1437. i_tgnargs = PQfnumber(res2, "tgnargs");
  1438. i_tgargs = PQfnumber(res2, "tgargs");
  1439. tblinfo[i].triggers = (char **) malloc(ntups2 * sizeof(char *));
  1440. for (i2 = 0, query[0] = 0; i2 < ntups2; i2++)
  1441. {
  1442. char    *tgfunc = PQgetvalue(res2, i2, i_tgfoid);
  1443. int2 tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
  1444. int tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
  1445. char    *tgargs = PQgetvalue(res2, i2, i_tgargs);
  1446. char    *p;
  1447. char farg[MAX_QUERY_SIZE];
  1448. int findx;
  1449. for (findx = 0; findx < numFuncs; findx++)
  1450. {
  1451. if (strcmp(finfo[findx].oid, tgfunc) == 0 &&
  1452. finfo[findx].nargs == 0 &&
  1453. strcmp(finfo[findx].prorettype, "0") == 0)
  1454. break;
  1455. }
  1456. if (findx == numFuncs)
  1457. {
  1458. fprintf(stderr, "getTables(): relation '%s': cannot find function with oid %s for trigger %sn",
  1459. tblinfo[i].relname, tgfunc, PQgetvalue(res2, i2, i_tgname));
  1460. exit_nicely(g_conn);
  1461. }
  1462. tgfunc = finfo[findx].proname;
  1463. #if 0
  1464. /* XXX - how to emit this DROP TRIGGER? */
  1465. if (dropSchema)
  1466. {
  1467. sprintf(query, "DROP TRIGGER %s ON %s;n",
  1468.  fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes),
  1469. fmtId(tblinfo[i].relname, force_quotes));
  1470. fputs(query, fout);
  1471. }
  1472. #endif
  1473. sprintf(query, "CREATE TRIGGER %s ", fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
  1474. /* Trigger type */
  1475. findx = 0;
  1476. if (TRIGGER_FOR_BEFORE(tgtype))
  1477. strcat(query, "BEFORE");
  1478. else
  1479. strcat(query, "AFTER");
  1480. if (TRIGGER_FOR_INSERT(tgtype))
  1481. {
  1482. strcat(query, " INSERT");
  1483. findx++;
  1484. }
  1485. if (TRIGGER_FOR_DELETE(tgtype))
  1486. {
  1487. if (findx > 0)
  1488. strcat(query, " OR DELETE");
  1489. else
  1490. strcat(query, " DELETE");
  1491. findx++;
  1492. }
  1493. if (TRIGGER_FOR_UPDATE(tgtype))
  1494. {
  1495. if (findx > 0)
  1496. strcat(query, " OR UPDATE");
  1497. else
  1498. strcat(query, " UPDATE");
  1499. }
  1500. sprintf(query, "%s ON %s FOR EACH ROW EXECUTE PROCEDURE %s (",
  1501.  query, fmtId(tblinfo[i].relname, force_quotes), tgfunc);
  1502. for (findx = 0; findx < tgnargs; findx++)
  1503. {
  1504. char    *s,
  1505.    *d;
  1506. for (p = tgargs;;)
  1507. {
  1508. p = strchr(p, '\');
  1509. if (p == NULL)
  1510. {
  1511. fprintf(stderr, "getTables(): relation '%s': bad argument string (%s) for trigger '%s'n",
  1512. tblinfo[i].relname,
  1513. PQgetvalue(res2, i2, i_tgargs),
  1514. PQgetvalue(res2, i2, i_tgname));
  1515. exit_nicely(g_conn);
  1516. }
  1517. p++;
  1518. if (*p == '\')
  1519. {
  1520. p++;
  1521. continue;
  1522. }
  1523. if (p[0] == '0' && p[1] == '0' && p[2] == '0')
  1524. break;
  1525. }
  1526. p--;
  1527. for (s = tgargs, d = &(farg[0]); s < p;)
  1528. {
  1529. if (*s == ''')
  1530. *d++ = '\';
  1531. *d++ = *s++;
  1532. }
  1533. *d = 0;
  1534. sprintf(query, "%s'%s'%s", query, farg,
  1535. (findx < tgnargs - 1) ? ", " : "");
  1536. tgargs = p + 4;
  1537. }
  1538. strcat(query, ");n");
  1539. tblinfo[i].triggers[i2] = strdup(query);
  1540. }
  1541. PQclear(res2);
  1542. }
  1543. else
  1544. tblinfo[i].triggers = NULL;
  1545. }
  1546. PQclear(res);
  1547. return tblinfo;
  1548. }
  1549. /*
  1550.  * getInherits
  1551.  *   read all the inheritance information
  1552.  * from the system catalogs return them in the InhInfo* structure
  1553.  *
  1554.  * numInherits is set to the number of tables read in
  1555.  *
  1556.  *
  1557.  */
  1558. InhInfo    *
  1559. getInherits(int *numInherits)
  1560. {
  1561. PGresult   *res;
  1562. int ntups;
  1563. int i;
  1564. char query[MAX_QUERY_SIZE];
  1565. InhInfo    *inhinfo;
  1566. int i_inhrel;
  1567. int i_inhparent;
  1568. /* find all the inheritance information */
  1569. sprintf(query, "SELECT inhrel, inhparent from pg_inherits");
  1570. res = PQexec(g_conn, query);
  1571. if (!res ||
  1572. PQresultStatus(res) != PGRES_TUPLES_OK)
  1573. {
  1574. fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1575. exit_nicely(g_conn);
  1576. }
  1577. ntups = PQntuples(res);
  1578. *numInherits = ntups;
  1579. inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
  1580. i_inhrel = PQfnumber(res, "inhrel");
  1581. i_inhparent = PQfnumber(res, "inhparent");
  1582. for (i = 0; i < ntups; i++)
  1583. {
  1584. inhinfo[i].inhrel = strdup(PQgetvalue(res, i, i_inhrel));
  1585. inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
  1586. }
  1587. PQclear(res);
  1588. return inhinfo;
  1589. }
  1590. /*
  1591.  * getTableAttrs -
  1592.  *   for each table in tblinfo, read its attributes types and names
  1593.  *
  1594.  * this is implemented in a very inefficient way right now, looping
  1595.  * through the tblinfo and doing a join per table to find the attrs and their
  1596.  * types
  1597.  *
  1598.  * modifies tblinfo
  1599.  */
  1600. void
  1601. getTableAttrs(TableInfo *tblinfo, int numTables)
  1602. {
  1603. int i,
  1604. j;
  1605. char q[MAX_QUERY_SIZE];
  1606. int i_attname;
  1607. int i_typname;
  1608. int i_atttypmod;
  1609. int i_attnotnull;
  1610. int i_atthasdef;
  1611. PGresult   *res;
  1612. int ntups;
  1613. for (i = 0; i < numTables; i++)
  1614. {
  1615. if (tblinfo[i].sequence)
  1616. continue;
  1617. /* find all the user attributes and their types */
  1618. /* we must read the attribute names in attribute number order! */
  1619. /*
  1620.  * because we will use the attnum to index into the attnames array
  1621.  * later
  1622.  */
  1623. if (g_verbose)
  1624. fprintf(stderr, "%s finding the attrs and types for table: '%s' %sn",
  1625. g_comment_start,
  1626. tblinfo[i].relname,
  1627. g_comment_end);
  1628. sprintf(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
  1629. "a.attnotnull, a.atthasdef "
  1630. "from pg_attribute a, pg_type t "
  1631. "where a.attrelid = '%s'::oid and a.atttypid = t.oid "
  1632. "and a.attnum > 0 order by attnum",
  1633. tblinfo[i].oid);
  1634. res = PQexec(g_conn, q);
  1635. if (!res ||
  1636. PQresultStatus(res) != PGRES_TUPLES_OK)
  1637. {
  1638. fprintf(stderr, "getTableAttrs(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1639. exit_nicely(g_conn);
  1640. }
  1641. ntups = PQntuples(res);
  1642. i_attname = PQfnumber(res, "attname");
  1643. i_typname = PQfnumber(res, "typname");
  1644. i_atttypmod = PQfnumber(res, "atttypmod");
  1645. i_attnotnull = PQfnumber(res, "attnotnull");
  1646. i_atthasdef = PQfnumber(res, "atthasdef");
  1647. tblinfo[i].numatts = ntups;
  1648. tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
  1649. tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
  1650. tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
  1651. tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
  1652. tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
  1653. tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
  1654. tblinfo[i].parentRels = NULL;
  1655. tblinfo[i].numParents = 0;
  1656. for (j = 0; j < ntups; j++)
  1657. {
  1658. tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
  1659. tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
  1660. tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
  1661. tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
  1662.  * flagInhAttrs() */
  1663. tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
  1664. if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
  1665. {
  1666. PGresult   *res2;
  1667. if (g_verbose)
  1668. fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %sn",
  1669. g_comment_start,
  1670. tblinfo[i].attnames[j],
  1671. g_comment_end);
  1672. sprintf(q, "SELECT adsrc from pg_attrdef "
  1673. "where adrelid = '%s'::oid and adnum = %d ",
  1674. tblinfo[i].oid, j + 1);
  1675. res2 = PQexec(g_conn, q);
  1676. if (!res2 ||
  1677. PQresultStatus(res2) != PGRES_TUPLES_OK)
  1678. {
  1679. fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1680. exit_nicely(g_conn);
  1681. }
  1682. tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
  1683. PQclear(res2);
  1684. }
  1685. else
  1686. tblinfo[i].adef_expr[j] = NULL;
  1687. }
  1688. PQclear(res);
  1689. }
  1690. }
  1691. /*
  1692.  * getIndices
  1693.  *   read all the user-defined indices information
  1694.  * from the system catalogs return them in the InhInfo* structure
  1695.  *
  1696.  * numIndices is set to the number of indices read in
  1697.  *
  1698.  *
  1699.  */
  1700. IndInfo    *
  1701. getIndices(int *numIndices)
  1702. {
  1703. int i;
  1704. char query[MAX_QUERY_SIZE];
  1705. PGresult   *res;
  1706. int ntups;
  1707. IndInfo    *indinfo;
  1708. int i_indexrelname;
  1709. int i_indrelname;
  1710. int i_indamname;
  1711. int i_indproc;
  1712. int i_indkey;
  1713. int i_indclass;
  1714. int i_indisunique;
  1715. /*
  1716.  * find all the user-defined indices. We do not handle partial
  1717.  * indices.
  1718.  *
  1719.  * Notice we skip indices on inversion objects (relkind 'l')
  1720.  *
  1721.  * this is a 4-way join !!
  1722.  */
  1723. sprintf(query,
  1724.   "SELECT t1.relname as indexrelname, t2.relname as indrelname, "
  1725. "i.indproc, i.indkey, i.indclass, "
  1726. "a.amname as indamname, i.indisunique "
  1727. "from pg_index i, pg_class t1, pg_class t2, pg_am a "
  1728. "where t1.oid = i.indexrelid and t2.oid = i.indrelid "
  1729. "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
  1730. "and t2.relname !~ '^pg_' and t2.relkind != 'l'",
  1731. g_last_builtin_oid);
  1732. res = PQexec(g_conn, query);
  1733. if (!res ||
  1734. PQresultStatus(res) != PGRES_TUPLES_OK)
  1735. {
  1736. fprintf(stderr, "getIndices(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1737. exit_nicely(g_conn);
  1738. }
  1739. ntups = PQntuples(res);
  1740. *numIndices = ntups;
  1741. indinfo = (IndInfo *) malloc(ntups * sizeof(IndInfo));
  1742. i_indexrelname = PQfnumber(res, "indexrelname");
  1743. i_indrelname = PQfnumber(res, "indrelname");
  1744. i_indamname = PQfnumber(res, "indamname");
  1745. i_indproc = PQfnumber(res, "indproc");
  1746. i_indkey = PQfnumber(res, "indkey");
  1747. i_indclass = PQfnumber(res, "indclass");
  1748. i_indisunique = PQfnumber(res, "indisunique");
  1749. for (i = 0; i < ntups; i++)
  1750. {
  1751. indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
  1752. indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
  1753. indinfo[i].indamname = strdup(PQgetvalue(res, i, i_indamname));
  1754. indinfo[i].indproc = strdup(PQgetvalue(res, i, i_indproc));
  1755. parseArgTypes((char **) indinfo[i].indkey,
  1756.   (const char *) PQgetvalue(res, i, i_indkey));
  1757. parseArgTypes((char **) indinfo[i].indclass,
  1758.   (const char *) PQgetvalue(res, i, i_indclass));
  1759. indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
  1760. }
  1761. PQclear(res);
  1762. return indinfo;
  1763. }
  1764. /*
  1765.  * dumpTypes
  1766.  *   writes out to fout the queries to recreate all the user-defined types
  1767.  *
  1768.  */
  1769. void
  1770. dumpTypes(FILE *fout, FuncInfo *finfo, int numFuncs,
  1771.   TypeInfo *tinfo, int numTypes)
  1772. {
  1773. int i;
  1774. char q[MAX_QUERY_SIZE];
  1775. int funcInd;
  1776. for (i = 0; i < numTypes; i++)
  1777. {
  1778. /* skip all the builtin types */
  1779. if (atoi(tinfo[i].oid) < g_last_builtin_oid)
  1780. continue;
  1781. /* skip relation types */
  1782. if (atoi(tinfo[i].typrelid) != 0)
  1783. continue;
  1784. /* skip all array types that start w/ underscore */
  1785. if ((tinfo[i].typname[0] == '_') &&
  1786. (strcmp(tinfo[i].typinput, "array_in") == 0))
  1787. continue;
  1788. /*
  1789.  * before we create a type, we need to create the input and output
  1790.  * functions for it, if they haven't been created already
  1791.  */
  1792. funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
  1793. if (funcInd != -1)
  1794. dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
  1795. funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
  1796. if (funcInd != -1)
  1797. dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
  1798. becomeUser(fout, tinfo[i].usename);
  1799. if (dropSchema)
  1800. {
  1801. sprintf(q, "DROP TYPE %s;n", fmtId(tinfo[i].typname, force_quotes));
  1802. fputs(q, fout);
  1803. }
  1804. sprintf(q,
  1805. "CREATE TYPE %s "
  1806. "( internallength = %s, externallength = %s, input = %s, "
  1807. "output = %s, send = %s, receive = %s, default = '%s'",
  1808. fmtId(tinfo[i].typname, force_quotes),
  1809. tinfo[i].typlen,
  1810. tinfo[i].typprtlen,
  1811. tinfo[i].typinput,
  1812. tinfo[i].typoutput,
  1813. tinfo[i].typsend,
  1814. tinfo[i].typreceive,
  1815. tinfo[i].typdefault);
  1816. if (tinfo[i].isArray)
  1817. {
  1818. char    *elemType;
  1819. elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem);
  1820. sprintf(q, "%s, element = %s, delimiter = '%s'",
  1821. q, elemType, tinfo[i].typdelim);
  1822. }
  1823. if (tinfo[i].passedbyvalue)
  1824. strcat(q, ",passedbyvalue);n");
  1825. else
  1826. strcat(q, ");n");
  1827. fputs(q, fout);
  1828. }
  1829. }
  1830. /*
  1831.  * dumpProcLangs
  1832.  *   writes out to fout the queries to recreate user-defined procedural languages
  1833.  *
  1834.  */
  1835. void
  1836. dumpProcLangs(FILE *fout, FuncInfo *finfo, int numFuncs,
  1837.   TypeInfo *tinfo, int numTypes)
  1838. {
  1839. PGresult   *res;
  1840. char query[MAX_QUERY_SIZE];
  1841. int ntups;
  1842. int i_lanname;
  1843. int i_lanpltrusted;
  1844. int i_lanplcallfoid;
  1845. int i_lancompiler;
  1846. char    *lanname;
  1847. char    *lancompiler;
  1848. char    *lanplcallfoid;
  1849. int i,
  1850. fidx;
  1851. sprintf(query, "SELECT * FROM pg_language "
  1852. "WHERE lanispl "
  1853. "ORDER BY oid");
  1854. res = PQexec(g_conn, query);
  1855. if (!res ||
  1856. PQresultStatus(res) != PGRES_TUPLES_OK)
  1857. {
  1858. fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1859. exit_nicely(g_conn);
  1860. }
  1861. ntups = PQntuples(res);
  1862. i_lanname = PQfnumber(res, "lanname");
  1863. i_lanpltrusted = PQfnumber(res, "lanpltrusted");
  1864. i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
  1865. i_lancompiler = PQfnumber(res, "lancompiler");
  1866. for (i = 0; i < ntups; i++)
  1867. {
  1868. lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
  1869. for (fidx = 0; fidx < numFuncs; fidx++)
  1870. {
  1871. if (!strcmp(finfo[fidx].oid, lanplcallfoid))
  1872. break;
  1873. }
  1874. if (fidx >= numFuncs)
  1875. {
  1876. fprintf(stderr, "dumpProcLangs(): handler procedure for language %s not foundn", PQgetvalue(res, i, i_lanname));
  1877. exit_nicely(g_conn);
  1878. }
  1879. dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
  1880. lanname = checkForQuote(PQgetvalue(res, i, i_lanname));
  1881. lancompiler = checkForQuote(PQgetvalue(res, i, i_lancompiler));
  1882. if (dropSchema)
  1883. fprintf(fout, "DROP PROCEDURAL LANGUAGE '%s';n", lanname);
  1884. fprintf(fout, "CREATE %sPROCEDURAL LANGUAGE '%s' "
  1885. "HANDLER %s LANCOMPILER '%s';n",
  1886. (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
  1887. lanname,
  1888. fmtId(finfo[fidx].proname, force_quotes),
  1889. lancompiler);
  1890. free(lanname);
  1891. free(lancompiler);
  1892. }
  1893. PQclear(res);
  1894. }
  1895. /*
  1896.  * dumpFuncs
  1897.  *   writes out to fout the queries to recreate all the user-defined functions
  1898.  *
  1899.  */
  1900. void
  1901. dumpFuncs(FILE *fout, FuncInfo *finfo, int numFuncs,
  1902.   TypeInfo *tinfo, int numTypes)
  1903. {
  1904. int i;
  1905. for (i = 0; i < numFuncs; i++)
  1906. dumpOneFunc(fout, finfo, i, tinfo, numTypes);
  1907. }
  1908. /*
  1909.  * dumpOneFunc:
  1910.  *   dump out only one function,  the index of which is given in the third
  1911.  * argument
  1912.  *
  1913.  */
  1914. static void
  1915. dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
  1916. TypeInfo *tinfo, int numTypes)
  1917. {
  1918. char q[MAX_QUERY_SIZE];
  1919. int j;
  1920. char    *func_def;
  1921. char func_lang[NAMEDATALEN + 1];
  1922. if (finfo[i].dumped)
  1923. return;
  1924. else
  1925. finfo[i].dumped = 1;
  1926. becomeUser(fout, finfo[i].usename);
  1927. if (finfo[i].lang == INTERNALlanguageId)
  1928. {
  1929. func_def = finfo[i].prosrc;
  1930. strcpy(func_lang, "INTERNAL");
  1931. }
  1932. else if (finfo[i].lang == ClanguageId)
  1933. {
  1934. func_def = finfo[i].probin;
  1935. strcpy(func_lang, "C");
  1936. }
  1937. else if (finfo[i].lang == SQLlanguageId)
  1938. {
  1939. func_def = finfo[i].prosrc;
  1940. strcpy(func_lang, "SQL");
  1941. }
  1942. else
  1943. {
  1944. PGresult   *res;
  1945. int nlangs;
  1946. int i_lanname;
  1947. char query[256];
  1948. sprintf(query, "SELECT lanname FROM pg_language "
  1949. "WHERE oid = %u",
  1950. finfo[i].lang);
  1951. res = PQexec(g_conn, query);
  1952. if (!res ||
  1953. PQresultStatus(res) != PGRES_TUPLES_OK)
  1954. {
  1955. fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  1956. exit_nicely(g_conn);
  1957. }
  1958. nlangs = PQntuples(res);
  1959. if (nlangs != 1)
  1960. {
  1961. fprintf(stderr, "dumpOneFunc(): procedural language for function %s not foundn", finfo[i].proname);
  1962. exit_nicely(g_conn);
  1963. }
  1964. i_lanname = PQfnumber(res, "lanname");
  1965. func_def = finfo[i].prosrc;
  1966. strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
  1967. PQclear(res);
  1968. }
  1969. if (dropSchema)
  1970. {
  1971. sprintf(q, "DROP FUNCTION %s (", fmtId(finfo[i].proname, force_quotes));
  1972. for (j = 0; j < finfo[i].nargs; j++)
  1973. {
  1974. char    *typname;
  1975. typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
  1976. sprintf(q, "%s%s%s",
  1977. q,
  1978. (j > 0) ? "," : "",
  1979. fmtId(typname, false));
  1980. }
  1981. sprintf(q, "%s);n", q);
  1982. fputs(q, fout);
  1983. }
  1984. sprintf(q, "CREATE FUNCTION %s (", fmtId(finfo[i].proname, force_quotes));
  1985. for (j = 0; j < finfo[i].nargs; j++)
  1986. {
  1987. char    *typname;
  1988. typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
  1989. sprintf(q, "%s%s%s",
  1990. q,
  1991. (j > 0) ? "," : "",
  1992. fmtId(typname, false));
  1993. }
  1994. sprintf(q, "%s ) RETURNS %s%s AS '%s' LANGUAGE '%s';n",
  1995. q,
  1996. (finfo[i].retset) ? " SETOF " : "",
  1997.    fmtId(findTypeByOid(tinfo, numTypes, finfo[i].prorettype), false),
  1998. func_def, func_lang);
  1999. fputs(q, fout);
  2000. }
  2001. /*
  2002.  * dumpOprs
  2003.  *   writes out to fout the queries to recreate all the user-defined operators
  2004.  *
  2005.  */
  2006. void
  2007. dumpOprs(FILE *fout, OprInfo *oprinfo, int numOperators,
  2008.  TypeInfo *tinfo, int numTypes)
  2009. {
  2010. int i;
  2011. char q[MAX_QUERY_SIZE];
  2012. char leftarg[MAX_QUERY_SIZE/8];
  2013. char rightarg[MAX_QUERY_SIZE/8];
  2014. char commutator[MAX_QUERY_SIZE/8];
  2015. char negator[MAX_QUERY_SIZE/8];
  2016. char restrictor[MAX_QUERY_SIZE/8];
  2017. char join[MAX_QUERY_SIZE/8];
  2018. char sort1[MAX_QUERY_SIZE/8];
  2019. char sort2[MAX_QUERY_SIZE/8];
  2020. for (i = 0; i < numOperators; i++)
  2021. {
  2022. /* skip all the builtin oids */
  2023. if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
  2024. continue;
  2025. /*
  2026.  * some operator are invalid because they were the result of user
  2027.  * defining operators before commutators exist
  2028.  */
  2029. if (strcmp(oprinfo[i].oprcode, "-") == 0)
  2030. continue;
  2031. leftarg[0] = '';
  2032. rightarg[0] = '';
  2033. /*
  2034.  * right unary means there's a left arg and left unary means
  2035.  * there's a right arg
  2036.  */
  2037. if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
  2038. strcmp(oprinfo[i].oprkind, "b") == 0)
  2039. {
  2040. sprintf(leftarg, ",ntLEFTARG = %s ",
  2041. fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false));
  2042. }
  2043. if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
  2044. strcmp(oprinfo[i].oprkind, "b") == 0)
  2045. {
  2046. sprintf(rightarg, ",ntRIGHTARG = %s ",
  2047. fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
  2048. }
  2049. if (strcmp(oprinfo[i].oprcom, "0") == 0)
  2050. commutator[0] = '';
  2051. else
  2052. sprintf(commutator, ",ntCOMMUTATOR = %s ",
  2053.  findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));
  2054. if (strcmp(oprinfo[i].oprnegate, "0") == 0)
  2055. negator[0] = '';
  2056. else
  2057. sprintf(negator, ",ntNEGATOR = %s ",
  2058.   findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate));
  2059. if (strcmp(oprinfo[i].oprrest, "-") == 0)
  2060. restrictor[0] = '';
  2061. else
  2062. sprintf(restrictor, ",ntRESTRICT = %s ", oprinfo[i].oprrest);
  2063. if (strcmp(oprinfo[i].oprjoin, "-") == 0)
  2064. join[0] = '';
  2065. else
  2066. sprintf(join, ",ntJOIN = %s ", oprinfo[i].oprjoin);
  2067. if (strcmp(oprinfo[i].oprlsortop, "0") == 0)
  2068. sort1[0] = '';
  2069. else
  2070. sprintf(sort1, ",ntSORT1 = %s ",
  2071.  findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop));
  2072. if (strcmp(oprinfo[i].oprrsortop, "0") == 0)
  2073. sort2[0] = '';
  2074. else
  2075. sprintf(sort2, ",ntSORT2 = %s ",
  2076.  findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop));
  2077. becomeUser(fout, oprinfo[i].usename);
  2078. if (dropSchema)
  2079. {
  2080. sprintf(q, "DROP OPERATOR %s (%s, %s);n", oprinfo[i].oprname,
  2081. fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false),
  2082. fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
  2083. fputs(q, fout);
  2084. }
  2085. sprintf(q,
  2086. "CREATE OPERATOR %s "
  2087. "(PROCEDURE = %s %s%s%s%s%s%s%s%s%s);n",
  2088. oprinfo[i].oprname,
  2089. oprinfo[i].oprcode,
  2090. leftarg,
  2091. rightarg,
  2092. commutator,
  2093. negator,
  2094. restrictor,
  2095.   (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",ntHASHES" : "",
  2096. join,
  2097. sort1,
  2098. sort2);
  2099. fputs(q, fout);
  2100. }
  2101. }
  2102. /*
  2103.  * dumpAggs
  2104.  *   writes out to fout the queries to create all the user-defined aggregates
  2105.  *
  2106.  */
  2107. void
  2108. dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
  2109.  TypeInfo *tinfo, int numTypes)
  2110. {
  2111. int i;
  2112. char q[MAX_QUERY_SIZE];
  2113. char sfunc1[MAX_QUERY_SIZE];
  2114. char sfunc2[MAX_QUERY_SIZE];
  2115. char basetype[MAX_QUERY_SIZE];
  2116. char finalfunc[MAX_QUERY_SIZE];
  2117. char comma1[2],
  2118. comma2[2];
  2119. for (i = 0; i < numAggs; i++)
  2120. {
  2121. /* skip all the builtin oids */
  2122. if (atoi(agginfo[i].oid) < g_last_builtin_oid)
  2123. continue;
  2124. sprintf(basetype,
  2125. "BASETYPE = %s, ",
  2126. fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
  2127. if (strcmp(agginfo[i].aggtransfn1, "-") == 0)
  2128. sfunc1[0] = '';
  2129. else
  2130. {
  2131. sprintf(sfunc1,
  2132. "SFUNC1 = %s, STYPE1 = %s",
  2133. agginfo[i].aggtransfn1,
  2134. fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype1), false));
  2135. if (agginfo[i].agginitval1)
  2136. sprintf(sfunc1, "%s, INITCOND1 = '%s'",
  2137. sfunc1, agginfo[i].agginitval1);
  2138. }
  2139. if (strcmp(agginfo[i].aggtransfn2, "-") == 0)
  2140. sfunc2[0] = '';
  2141. else
  2142. {
  2143. sprintf(sfunc2,
  2144. "SFUNC2 = %s, STYPE2 = %s",
  2145. agginfo[i].aggtransfn2,
  2146. fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype2), false));
  2147. if (agginfo[i].agginitval2)
  2148. sprintf(sfunc2, "%s, INITCOND2 = '%s'",
  2149. sfunc2, agginfo[i].agginitval2);
  2150. }
  2151. if (strcmp(agginfo[i].aggfinalfn, "-") == 0)
  2152. finalfunc[0] = '';
  2153. else
  2154. sprintf(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
  2155. if (sfunc1[0] != '' && sfunc2[0] != '')
  2156. {
  2157. comma1[0] = ',';
  2158. comma1[1] = '';
  2159. }
  2160. else
  2161. comma1[0] = '';
  2162. if (finalfunc[0] != '' && (sfunc1[0] != '' || sfunc2[0] != ''))
  2163. {
  2164. comma2[0] = ',';
  2165. comma2[1] = '';
  2166. }
  2167. else
  2168. comma2[0] = '';
  2169. becomeUser(fout, agginfo[i].usename);
  2170. if (dropSchema)
  2171. {
  2172. sprintf(q, "DROP AGGREGATE %s %s;n", agginfo[i].aggname,
  2173. fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
  2174. fputs(q, fout);
  2175. }
  2176. sprintf(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );n",
  2177. agginfo[i].aggname,
  2178. basetype,
  2179. sfunc1,
  2180. comma1,
  2181. sfunc2,
  2182. comma2,
  2183. finalfunc);
  2184. fputs(q, fout);
  2185. }
  2186. }
  2187. /*
  2188.  * These are some support functions to fix the acl problem of pg_dump
  2189.  *
  2190.  * Matthew C. Aycock 12/02/97
  2191.  */
  2192. /* Append a keyword to a keyword list, inserting comma if needed.
  2193.  * Caller must make aclbuf big enough for all possible keywords.
  2194.  */
  2195. static void
  2196. AddAcl(char *aclbuf, const char *keyword)
  2197. {
  2198. if (*aclbuf)
  2199. strcat(aclbuf, ",");
  2200. strcat(aclbuf, keyword);
  2201. }
  2202. /*
  2203.  * This will take a string of 'arwR' and return a malloced,
  2204.  * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
  2205.  */
  2206. static char *
  2207. GetPrivileges(const char *s)
  2208. {
  2209. char aclbuf[100];
  2210. aclbuf[0] = '';
  2211. if (strchr(s, 'a'))
  2212. AddAcl(aclbuf, "INSERT");
  2213. if (strchr(s, 'w'))
  2214. AddAcl(aclbuf, "UPDATE,DELETE");
  2215. if (strchr(s, 'r'))
  2216. AddAcl(aclbuf, "SELECT");
  2217. if (strchr(s, 'R'))
  2218. AddAcl(aclbuf, "RULE");
  2219. /* Special-case when they're all there */
  2220. if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
  2221. return strdup("ALL");
  2222. return strdup(aclbuf);
  2223. }
  2224. /*
  2225.  * dumpACL:
  2226.  *   Write out grant/revoke information
  2227.  *   Called for sequences and tables
  2228.  */
  2229. static void
  2230. dumpACL(FILE *fout, TableInfo tbinfo)
  2231. {
  2232. const char *acls = tbinfo.relacl;
  2233. char    *aclbuf,
  2234.    *tok,
  2235.    *eqpos,
  2236.    *priv;
  2237. if (strlen(acls) == 0)
  2238. return; /* table has default permissions */
  2239. /*
  2240.  * Revoke Default permissions for PUBLIC. Is this actually necessary,
  2241.  * or is it just a waste of time?
  2242.  */
  2243. fprintf(fout,
  2244. "REVOKE ALL on %s from PUBLIC;n",
  2245. fmtId(tbinfo.relname, force_quotes));
  2246. /* Make a working copy of acls so we can use strtok */
  2247. aclbuf = strdup(acls);
  2248. /* Scan comma-separated ACL items */
  2249. for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
  2250. {
  2251. /*
  2252.  * Token may start with '{' and/or '"'.  Actually only the start
  2253.  * of the string should have '{', but we don't verify that.
  2254.  */
  2255. if (*tok == '{')
  2256. tok++;
  2257. if (*tok == '"')
  2258. tok++;
  2259. /* User name is string up to = in tok */
  2260. eqpos = strchr(tok, '=');
  2261. if (!eqpos)
  2262. {
  2263. fprintf(stderr, "Could not parse ACL list for '%s'...Exiting!n",
  2264. tbinfo.relname);
  2265. exit_nicely(g_conn);
  2266. }
  2267. /*
  2268.  * Parse the privileges (right-hand side). Skip if there are
  2269.  * none.
  2270.  */
  2271. priv = GetPrivileges(eqpos + 1);
  2272. if (*priv)
  2273. {
  2274. fprintf(fout,
  2275. "GRANT %s on %s to ",
  2276. priv, fmtId(tbinfo.relname, force_quotes));
  2277. /*
  2278.  * Note: fmtId() can only be called once per printf, so don't
  2279.  * try to merge printing of username into the above printf.
  2280.  */
  2281. if (eqpos == tok)
  2282. {
  2283. /* Empty left-hand side means "PUBLIC" */
  2284. fprintf(fout, "PUBLIC;n");
  2285. }
  2286. else
  2287. {
  2288. *eqpos = ''; /* it's ok to clobber aclbuf */
  2289. if (strncmp(tok, "group ", strlen("group ")) == 0)
  2290. fprintf(fout, "GROUP %s;n",
  2291. fmtId(tok + strlen("group "), force_quotes));
  2292. else
  2293. fprintf(fout, "%s;n", fmtId(tok, force_quotes));
  2294. }
  2295. }
  2296. free(priv);
  2297. }
  2298. free(aclbuf);
  2299. }
  2300. /*
  2301.  * dumpTables:
  2302.  *   write out to fout all the user-define tables
  2303.  */
  2304. void
  2305. dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
  2306.    InhInfo *inhinfo, int numInherits,
  2307.    TypeInfo *tinfo, int numTypes, const char *tablename,
  2308.    const bool aclsSkip)
  2309. {
  2310. int i,
  2311. j,
  2312. k;
  2313. char q[MAX_QUERY_SIZE];
  2314. char    *serialSeq = NULL; /* implicit sequence name created
  2315.  * by SERIAL datatype */
  2316. const char *serialSeqSuffix = "_id_seq"; /* suffix for implicit
  2317.  * SERIAL sequences */
  2318. char   **parentRels; /* list of names of parent relations */
  2319. int numParents;
  2320. int actual_atts; /* number of attrs in this CREATE statment */
  2321. int32 tmp_typmod;
  2322. int precision;
  2323. int scale;
  2324. /* First - dump SEQUENCEs */
  2325. if (tablename)
  2326. {
  2327. serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
  2328. strcpy(serialSeq, tablename);
  2329. strcat(serialSeq, serialSeqSuffix);
  2330. }
  2331. for (i = 0; i < numTables; i++)
  2332. {
  2333. if (!(tblinfo[i].sequence))
  2334. continue;
  2335. if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
  2336. || (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
  2337. {
  2338. becomeUser(fout, tblinfo[i].usename);
  2339. dumpSequence(fout, tblinfo[i]);
  2340. if (!aclsSkip)
  2341. dumpACL(fout, tblinfo[i]);
  2342. }
  2343. }
  2344. if (tablename)
  2345. free(serialSeq);
  2346. for (i = 0; i < numTables; i++)
  2347. {
  2348. if (tblinfo[i].sequence)/* already dumped */
  2349. continue;
  2350. if (!tablename || (!strcmp(tblinfo[i].relname, tablename)))
  2351. {
  2352. /* Skip VIEW relations */
  2353. /*
  2354.  * if (isViewRule(tblinfo[i].relname)) continue;
  2355.  */
  2356. parentRels = tblinfo[i].parentRels;
  2357. numParents = tblinfo[i].numParents;
  2358. becomeUser(fout, tblinfo[i].usename);
  2359. if (dropSchema)
  2360. {
  2361. sprintf(q, "DROP TABLE %s;n", fmtId(tblinfo[i].relname, force_quotes));
  2362. fputs(q, fout);
  2363. }
  2364. sprintf(q, "CREATE TABLE %s (nt", fmtId(tblinfo[i].relname, force_quotes));
  2365. actual_atts = 0;
  2366. for (j = 0; j < tblinfo[i].numatts; j++)
  2367. {
  2368. if (tblinfo[i].inhAttrs[j] == 0)
  2369. {
  2370. if (actual_atts > 0)
  2371. strcat(q, ",nt");
  2372. sprintf(q + strlen(q), "%s ",
  2373. fmtId(tblinfo[i].attnames[j], force_quotes));
  2374. /* Show lengths on bpchar and varchar */
  2375. if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
  2376. {
  2377. int len = (tblinfo[i].atttypmod[j] - VARHDRSZ);
  2378. sprintf(q + strlen(q), "character");
  2379. if (len > 1)
  2380. sprintf(q + strlen(q), "(%d)",
  2381. tblinfo[i].atttypmod[j] - VARHDRSZ);
  2382. }
  2383. else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
  2384. {
  2385. sprintf(q + strlen(q), "character varying");
  2386. if (tblinfo[i].atttypmod[j] != -1)
  2387. {
  2388. sprintf(q + strlen(q), "(%d)",
  2389. tblinfo[i].atttypmod[j] - VARHDRSZ);
  2390. }
  2391. }
  2392. else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
  2393. {
  2394. sprintf(q + strlen(q), "numeric");
  2395. if (tblinfo[i].atttypmod[j] != -1)
  2396. {
  2397. tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
  2398. precision = (tmp_typmod >> 16) & 0xffff;
  2399. scale = tmp_typmod & 0xffff;
  2400. sprintf(q + strlen(q), "(%d,%d)",
  2401. precision, scale);
  2402. }
  2403. }
  2404. /*
  2405.  * char is an internal single-byte data type; Let's
  2406.  * make sure we force it through with quotes. - thomas
  2407.  * 1998-12-13
  2408.  */
  2409. else if (!strcmp(tblinfo[i].typnames[j], "char"))
  2410. {
  2411. sprintf(q + strlen(q), "%s",
  2412. fmtId(tblinfo[i].typnames[j], true));
  2413. }
  2414. else
  2415. {
  2416. sprintf(q + strlen(q), "%s",
  2417. fmtId(tblinfo[i].typnames[j], false));
  2418. }
  2419. if (tblinfo[i].adef_expr[j] != NULL)
  2420. sprintf(q + strlen(q), " DEFAULT %s",
  2421. tblinfo[i].adef_expr[j]);
  2422. if (tblinfo[i].notnull[j])
  2423. strcat(q, " NOT NULL");
  2424. actual_atts++;
  2425. }
  2426. }
  2427. /* put the CONSTRAINTS inside the table def */
  2428. for (k = 0; k < tblinfo[i].ncheck; k++)
  2429. {
  2430. if (actual_atts + k > 0)
  2431. strcat(q, ",nt");
  2432. sprintf(q + strlen(q), "%s",
  2433. tblinfo[i].check_expr[k]);
  2434. }
  2435. strcat(q, ")");
  2436. if (numParents > 0)
  2437. {
  2438. strcat(q, "ninherits (");
  2439. for (k = 0; k < numParents; k++)
  2440. {
  2441. sprintf(q + strlen(q), "%s%s",
  2442. (k > 0) ? ", " : "",
  2443. fmtId(parentRels[k], force_quotes));
  2444. }
  2445. strcat(q, ")");
  2446. }
  2447. strcat(q, ";n");
  2448. fputs(q, fout);
  2449. if (!aclsSkip)
  2450. dumpACL(fout, tblinfo[i]);
  2451. }
  2452. }
  2453. }
  2454. /*
  2455.  * dumpIndices:
  2456.  *   write out to fout all the user-define indices
  2457.  */
  2458. void
  2459. dumpIndices(FILE *fout, IndInfo *indinfo, int numIndices,
  2460. TableInfo *tblinfo, int numTables, const char *tablename)
  2461. {
  2462. int i,
  2463. k;
  2464. int tableInd;
  2465. char attlist[1000];
  2466. char    *classname[INDEX_MAX_KEYS];
  2467. char    *funcname; /* the name of the function to comput the
  2468.  * index key from */
  2469. int indkey,
  2470. indclass;
  2471. int nclass;
  2472. char q[MAX_QUERY_SIZE],
  2473. id1[MAX_QUERY_SIZE],
  2474. id2[MAX_QUERY_SIZE];
  2475. PGresult   *res;
  2476. for (i = 0; i < numIndices; i++)
  2477. {
  2478. tableInd = findTableByName(tblinfo, numTables,
  2479.    indinfo[i].indrelname);
  2480. if (tableInd < 0)
  2481. {
  2482. fprintf(stderr, "failed sanity check, table %s was not foundn",
  2483. indinfo[i].indrelname);
  2484. exit(2);
  2485. }
  2486. if (strcmp(indinfo[i].indproc, "0") == 0)
  2487. funcname = NULL;
  2488. else
  2489. {
  2490. /*
  2491.  * the funcname is an oid which we use to find the name of the
  2492.  * pg_proc.  We need to do this because getFuncs() only reads
  2493.  * in the user-defined funcs not all the funcs.  We might not
  2494.  * find what we want by looking in FuncInfo*
  2495.  */
  2496. sprintf(q,
  2497. "SELECT proname from pg_proc "
  2498. "where pg_proc.oid = '%s'::oid",
  2499. indinfo[i].indproc);
  2500. res = PQexec(g_conn, q);
  2501. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
  2502. {
  2503. fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  2504. exit_nicely(g_conn);
  2505. }
  2506. funcname = strdup(PQgetvalue(res, 0,
  2507.  PQfnumber(res, "proname")));
  2508. PQclear(res);
  2509. }
  2510. /* convert opclass oid(s) into names */
  2511. for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
  2512. {
  2513. indclass = atoi(indinfo[i].indclass[nclass]);
  2514. if (indclass == 0)
  2515. break;
  2516. sprintf(q,
  2517. "SELECT opcname from pg_opclass "
  2518. "where pg_opclass.oid = '%u'::oid",
  2519. indclass);
  2520. res = PQexec(g_conn, q);
  2521. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
  2522. {
  2523. fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  2524. exit_nicely(g_conn);
  2525. }
  2526. classname[nclass] = strdup(PQgetvalue(res, 0,
  2527.  PQfnumber(res, "opcname")));
  2528. PQclear(res);
  2529. }
  2530. if (funcname && nclass != 1)
  2531. {
  2532. fprintf(stderr, "dumpIndices(): Must be exactly one OpClass "
  2533. "for functional index %sn", indinfo[i].indexrelname);
  2534. exit_nicely(g_conn);
  2535. }
  2536. /* convert attribute numbers into attribute list */
  2537. for (k = 0, attlist[0] = 0; k < INDEX_MAX_KEYS; k++)
  2538. {
  2539. char    *attname;
  2540. indkey = atoi(indinfo[i].indkey[k]);
  2541. if (indkey == InvalidAttrNumber)
  2542. break;
  2543. indkey--;
  2544. if (indkey == ObjectIdAttributeNumber - 1)
  2545. attname = "oid";
  2546. else
  2547. attname = tblinfo[tableInd].attnames[indkey];
  2548. if (funcname)
  2549. sprintf(attlist + strlen(attlist), "%s%s",
  2550.  (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
  2551. else
  2552. {
  2553. if (k >= nclass)
  2554. {
  2555. fprintf(stderr, "dumpIndices(): OpClass not found for "
  2556. "attribute '%s' of index '%s'n",
  2557. attname, indinfo[i].indexrelname);
  2558. exit_nicely(g_conn);
  2559. }
  2560. strcpy(id1, fmtId(attname, force_quotes));
  2561. strcpy(id2, fmtId(classname[k], force_quotes));
  2562. sprintf(attlist + strlen(attlist), "%s%s %s",
  2563. (k == 0) ? "" : ", ", id1, id2);
  2564. free(classname[k]);
  2565. }
  2566. }
  2567. if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
  2568. {
  2569. /*
  2570.  * We make the index belong to the owner of its table, which
  2571.  * is not necessarily right but should answer 99% of the time.
  2572.  * Would have to add owner name to IndInfo to do it right.
  2573.  */
  2574. becomeUser(fout, tblinfo[tableInd].usename);
  2575. strcpy(id1, fmtId(indinfo[i].indexrelname, force_quotes));
  2576. strcpy(id2, fmtId(indinfo[i].indrelname, force_quotes));
  2577. if (dropSchema)
  2578. {
  2579. sprintf(q, "DROP INDEX %s;n", id1);
  2580. fputs(q, fout);
  2581. }
  2582. fprintf(fout, "CREATE %s INDEX %s on %s using %s (",
  2583.   (strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
  2584. id1,
  2585. id2,
  2586. indinfo[i].indamname);
  2587. if (funcname)
  2588. {
  2589. /* need 2 printf's here cuz fmtId has static return area */
  2590. fprintf(fout, " %s", fmtId(funcname, false));
  2591. fprintf(fout, " (%s) %s );n", attlist, fmtId(classname[0], force_quotes));
  2592. free(funcname);
  2593. free(classname[0]);
  2594. }
  2595. else
  2596. fprintf(fout, " %s );n", attlist);
  2597. }
  2598. }
  2599. }
  2600. /*
  2601.  * dumpTuples
  2602.  *   prints out the tuples in ASCII representation. The output is a valid
  2603.  *   input to COPY FROM stdin.
  2604.  *
  2605.  *   We only need to do this for POSTGRES 4.2 databases since the
  2606.  *   COPY TO statment doesn't escape newlines properly. It's been fixed
  2607.  *   in PostgreSQL.
  2608.  *
  2609.  * the attrmap passed in tells how to map the attributes copied in to the
  2610.  * attributes copied out
  2611.  */
  2612. #ifdef NOT_USED
  2613. void
  2614. dumpTuples(PGresult *res, FILE *fout, int *attrmap)
  2615. {
  2616. int j,
  2617. k;
  2618. int m,
  2619. n;
  2620. char   **outVals = NULL; /* values to copy out */
  2621. n = PQntuples(res);
  2622. m = PQnfields(res);
  2623. if (m > 0)
  2624. {
  2625. /*
  2626.  * Print out the tuples but only print tuples with at least 1
  2627.  * field.
  2628.  */
  2629. outVals = (char **) malloc(m * sizeof(char *));
  2630. for (j = 0; j < n; j++)
  2631. {
  2632. for (k = 0; k < m; k++)
  2633. outVals[attrmap[k]] = PQgetvalue(res, j, k);
  2634. for (k = 0; k < m; k++)
  2635. {
  2636. char    *pval = outVals[k];
  2637. if (k != 0)
  2638. fputc('t', fout); /* delimiter for attribute */
  2639. if (pval)
  2640. {
  2641. while (*pval != '')
  2642. {
  2643. /* escape tabs, newlines and backslashes */
  2644. if (*pval == 't' || *pval == 'n' || *pval == '\')
  2645. fputc('\', fout);
  2646. fputc(*pval, fout);
  2647. pval++;
  2648. }
  2649. }
  2650. }
  2651. fputc('n', fout); /* delimiter for a tuple */
  2652. }
  2653. free(outVals);
  2654. }
  2655. }
  2656. #endif
  2657. /*
  2658.  * setMaxOid -
  2659.  * find the maximum oid and generate a COPY statement to set it
  2660. */
  2661. static void
  2662. setMaxOid(FILE *fout)
  2663. {
  2664. PGresult   *res;
  2665. Oid max_oid;
  2666. res = PQexec(g_conn, "CREATE TABLE pgdump_oid (dummy int4)");
  2667. if (!res ||
  2668. PQresultStatus(res) != PGRES_COMMAND_OK)
  2669. {
  2670. fprintf(stderr, "Can not create pgdump_oid table.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  2671. exit_nicely(g_conn);
  2672. }
  2673. PQclear(res);
  2674. res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
  2675. if (!res ||
  2676. PQresultStatus(res) != PGRES_COMMAND_OK)
  2677. {
  2678. fprintf(stderr, "Can not insert into pgdump_oid table.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  2679. exit_nicely(g_conn);
  2680. }
  2681. max_oid = atol(PQoidStatus(res));
  2682. if (max_oid == 0)
  2683. {
  2684. fprintf(stderr, "Invalid max id in setMaxOidn");
  2685. exit_nicely(g_conn);
  2686. }
  2687. PQclear(res);
  2688. res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
  2689. if (!res ||
  2690. PQresultStatus(res) != PGRES_COMMAND_OK)
  2691. {
  2692. fprintf(stderr, "Can not drop pgdump_oid table.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  2693. exit_nicely(g_conn);
  2694. }
  2695. PQclear(res);
  2696. if (g_verbose)
  2697. fprintf(stderr, "%s maximum system oid is %u %sn",
  2698. g_comment_start, max_oid, g_comment_end);
  2699. fprintf(fout, "CREATE TABLE pgdump_oid (dummy int4);n");
  2700. fprintf(fout, "COPY pgdump_oid WITH OIDS FROM stdin;n");
  2701. fprintf(fout, "%-dt0n", max_oid);
  2702. fprintf(fout, "\.n");
  2703. fprintf(fout, "DROP TABLE pgdump_oid;n");
  2704. }
  2705. /*
  2706.  * findLastBuiltInOid -
  2707.  * find the last built in oid
  2708.  * we do this by looking up the oid of 'template1' in pg_database,
  2709.  * this is probably not foolproof but comes close
  2710. */
  2711. static int
  2712. findLastBuiltinOid(void)
  2713. {
  2714. PGresult   *res;
  2715. int ntups;
  2716. int last_oid;
  2717. res = PQexec(g_conn,
  2718.   "SELECT oid from pg_database where datname = 'template1'");
  2719. if (res == NULL ||
  2720. PQresultStatus(res) != PGRES_TUPLES_OK)
  2721. {
  2722. fprintf(stderr, "pg_dump error in finding the template1 database.  Explanation from backend: '%s'.n", PQerrorMessage(g_conn));
  2723. exit_nicely(g_conn);
  2724. }
  2725. ntups = PQntuples(res);
  2726. if (ntups != 1)
  2727. {
  2728. fprintf(stderr, "pg_dump: couldn't find the template1 database.  "
  2729. "You are really hosed.nGiving up.n");
  2730. exit_nicely(g_conn);
  2731. }
  2732. last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
  2733. PQclear(res);
  2734. return last_oid;
  2735. }
  2736. /*
  2737.  * checkForQuote:
  2738.  *   checks a string for quote characters and quotes them
  2739.  */
  2740. static char *
  2741. checkForQuote(const char *s)
  2742. {
  2743. char    *r;
  2744. char c;
  2745. char    *result;
  2746. int j = 0;
  2747. r = malloc(strlen(s) * 3 + 1); /* definitely long enough */
  2748. while ((c = *s) != '')
  2749. {
  2750. if (c == ''')
  2751. {
  2752. r[j++] = '''; /* quote the single quotes */
  2753. }
  2754. r[j++] = c;
  2755. s++;
  2756. }
  2757. r[j] = '';
  2758. result = strdup(r);
  2759. free(r);
  2760. return result;
  2761. }
  2762. static void
  2763. dumpSequence(FILE *fout, TableInfo tbinfo)
  2764. {
  2765. PGresult   *res;
  2766. int4 last,
  2767. incby,
  2768. maxv,
  2769. minv,
  2770. cache;
  2771. char cycled,
  2772. called,
  2773.    *t;
  2774. char query[MAX_QUERY_SIZE];
  2775. sprintf(query,
  2776. "SELECT sequence_name, last_value, increment_by, max_value, "
  2777. "min_value, cache_value, is_cycled, is_called from %s",
  2778. fmtId(tbinfo.relname, force_quotes));
  2779. res = PQexec(g_conn, query);
  2780. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
  2781. {
  2782. fprintf(stderr, "dumpSequence(%s): SELECT failed.  Explanation from backend: '%s'.n", tbinfo.relname, PQerrorMessage(g_conn));
  2783. exit_nicely(g_conn);
  2784. }
  2785. if (PQntuples(res) != 1)
  2786. {
  2787. fprintf(stderr, "dumpSequence(%s): %d (!= 1) tuples returned by SELECTn",
  2788. tbinfo.relname, PQntuples(res));
  2789. exit_nicely(g_conn);
  2790. }
  2791. if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
  2792. {
  2793. fprintf(stderr, "dumpSequence(%s): different sequence name "
  2794. "returned by SELECT: %sn",
  2795. tbinfo.relname, PQgetvalue(res, 0, 0));
  2796. exit_nicely(g_conn);
  2797. }
  2798. last = atoi(PQgetvalue(res, 0, 1));
  2799. incby = atoi(PQgetvalue(res, 0, 2));
  2800. maxv = atoi(PQgetvalue(res, 0, 3));
  2801. minv = atoi(PQgetvalue(res, 0, 4));
  2802. cache = atoi(PQgetvalue(res, 0, 5));
  2803. t = PQgetvalue(res, 0, 6);
  2804. cycled = *t;
  2805. t = PQgetvalue(res, 0, 7);
  2806. called = *t;
  2807. PQclear(res);
  2808. if (dropSchema)
  2809. {
  2810. sprintf(query, "DROP SEQUENCE %s;n", fmtId(tbinfo.relname, force_quotes));
  2811. fputs(query, fout);
  2812. }
  2813. sprintf(query,
  2814. "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
  2815. "minvalue %d  cache %d %s;n",
  2816.  fmtId(tbinfo.relname, force_quotes), last, incby, maxv, minv, cache,
  2817. (cycled == 't') ? "cycle" : "");
  2818. fputs(query, fout);
  2819. if (called == 'f')
  2820. return; /* nothing to do more */
  2821. sprintf(query, "SELECT nextval ('%s');n", tbinfo.relname);
  2822. fputs(query, fout);
  2823. }
  2824. static void
  2825. dumpTriggers(FILE *fout, const char *tablename,
  2826.  TableInfo *tblinfo, int numTables)
  2827. {
  2828. int i,
  2829. j;
  2830. if (g_verbose)
  2831. fprintf(stderr, "%s dumping out triggers %sn",
  2832. g_comment_start, g_comment_end);
  2833. for (i = 0; i < numTables; i++)
  2834. {
  2835. if (tablename && strcmp(tblinfo[i].relname, tablename))
  2836. continue;
  2837. for (j = 0; j < tblinfo[i].ntrig; j++)
  2838. {
  2839. becomeUser(fout, tblinfo[i].usename);
  2840. fputs(tblinfo[i].triggers[j], fout);
  2841. }
  2842. }
  2843. }
  2844. static void
  2845. dumpRules(FILE *fout, const char *tablename,
  2846.   TableInfo *tblinfo, int numTables)
  2847. {
  2848. PGresult   *res;
  2849. int nrules;
  2850. int i,
  2851. t;
  2852. char query[MAX_QUERY_SIZE];
  2853. int i_definition;
  2854. if (g_verbose)
  2855. fprintf(stderr, "%s dumping out rules %sn",
  2856. g_comment_start, g_comment_end);
  2857. /*
  2858.  * For each table we dump
  2859.  */
  2860. for (t = 0; t < numTables; t++)
  2861. {
  2862. if (tablename && strcmp(tblinfo[t].relname, tablename))
  2863. continue;
  2864. /*
  2865.  * Get all rules defined for this table
  2866.  */
  2867. sprintf(query, "SELECT pg_get_ruledef(pg_rewrite.rulename) "
  2868. "AS definition FROM pg_rewrite, pg_class "
  2869. "WHERE pg_class.relname = '%s' "
  2870. "AND pg_rewrite.ev_class = pg_class.oid "
  2871. "ORDER BY pg_rewrite.oid",
  2872. tblinfo[t].relname);
  2873. res = PQexec(g_conn, query);
  2874. if (!res ||
  2875. PQresultStatus(res) != PGRES_TUPLES_OK)
  2876. {
  2877. fprintf(stderr, "dumpRules(): SELECT failed for table %s.  Explanation from backend: '%s'.n",
  2878. tblinfo[t].relname, PQerrorMessage(g_conn));
  2879. exit_nicely(g_conn);
  2880. }
  2881. nrules = PQntuples(res);
  2882. i_definition = PQfnumber(res, "definition");
  2883. /*
  2884.  * Dump them out
  2885.  */
  2886. for (i = 0; i < nrules; i++)
  2887. fprintf(fout, "%sn", PQgetvalue(res, i, i_definition));
  2888. PQclear(res);
  2889. }
  2890. }
  2891. /* Issue a psql connect command to become the specified user.
  2892.  * We want to do this only if we are dumping ACLs,
  2893.  * and only if the new username is different from the last one
  2894.  * (to avoid the overhead of useless backend launches).
  2895.  */
  2896. static void
  2897. becomeUser(FILE *fout, const char *username)
  2898. {
  2899. static const char *lastusername = "";
  2900. if (aclsSkip)
  2901. return;
  2902. if (strcmp(lastusername, username) == 0)
  2903. return;
  2904. fprintf(fout, "\connect - %sn", username);
  2905. lastusername = username;
  2906. }