2222 *
2323 *
2424 * IDENTIFICATION
25- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.183 2000/12/03 20:45:37 tgl Exp $
25+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.184 2001/01/04 01:23:47 tgl Exp $
2626 *
2727 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
2828 *
@@ -138,7 +138,7 @@ static void dumpTriggers(Archive *fout, const char *tablename,
138138TableInfo * tblinfo ,int numTables );
139139static void dumpRules (Archive * fout ,const char * tablename ,
140140TableInfo * tblinfo ,int numTables );
141- static char * checkForQuote ( const char * s );
141+ static void formatStringLiteral ( PQExpBuffer buf , const char * str );
142142static void clearTableInfo (TableInfo * ,int );
143143static void dumpOneFunc (Archive * fout ,FuncInfo * finfo ,int i ,
144144TypeInfo * tinfo ,int numTypes );
@@ -434,7 +434,6 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
434434PQExpBuffer q = createPQExpBuffer ();
435435int tuple ;
436436int field ;
437- const char * expsrc ;
438437
439438appendPQExpBuffer (q ,"SELECT * FROM %s" ,fmtId (classname ,force_quotes ));
440439res = PQexec (g_conn ,q -> data );
@@ -492,32 +491,10 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
492491/*
493492 * All other types are printed as string literals,
494493 * with appropriate escaping of special characters.
495- * Quote mark ' goes to '' per SQL standard, other
496- * stuff goes to \ sequences.
497494 */
498- archputc ('\'' ,fout );
499- expsrc = PQgetvalue (res ,tuple ,field );
500- while (* expsrc )
501- {
502- char ch = * expsrc ++ ;
503-
504- if (ch == '\\' || ch == '\'' )
505- {
506- archputc (ch ,fout );/* double these */
507- archputc (ch ,fout );
508- }
509- else if (ch < '\040' )
510- {
511- /* generate octal escape for control chars */
512- archputc ('\\' ,fout );
513- archputc (((ch >>6 )& 3 )+ '0' ,fout );
514- archputc (((ch >>3 )& 7 )+ '0' ,fout );
515- archputc ((ch & 7 )+ '0' ,fout );
516- }
517- else
518- archputc (ch ,fout );
519- }
520- archputc ('\'' ,fout );
495+ resetPQExpBuffer (q );
496+ formatStringLiteral (q ,PQgetvalue (res ,tuple ,field ));
497+ archprintf (fout ,"%s" ,q -> data );
521498break ;
522499}
523500}
@@ -527,6 +504,41 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
527504return 1 ;
528505}
529506
507+ /*
508+ * Convert a string value to an SQL string literal,
509+ * with appropriate escaping of special characters.
510+ * Quote mark ' goes to '' per SQL standard, other
511+ * stuff goes to \ sequences.
512+ * The literal is appended to the given PQExpBuffer.
513+ */
514+ static void
515+ formatStringLiteral (PQExpBuffer buf ,const char * str )
516+ {
517+ appendPQExpBufferChar (buf ,'\'' );
518+ while (* str )
519+ {
520+ char ch = * str ++ ;
521+
522+ if (ch == '\\' || ch == '\'' )
523+ {
524+ appendPQExpBufferChar (buf ,ch );/* double these */
525+ appendPQExpBufferChar (buf ,ch );
526+ }
527+ else if ((unsignedchar )ch < (unsignedchar )' ' &&
528+ ch != '\n' && ch != '\t' )
529+ {
530+ /* generate octal escape for control chars other than whitespace */
531+ appendPQExpBufferChar (buf ,'\\' );
532+ appendPQExpBufferChar (buf , ((ch >>6 )& 3 )+ '0' );
533+ appendPQExpBufferChar (buf , ((ch >>3 )& 7 )+ '0' );
534+ appendPQExpBufferChar (buf , (ch & 7 )+ '0' );
535+ }
536+ else
537+ appendPQExpBufferChar (buf ,ch );
538+ }
539+ appendPQExpBufferChar (buf ,'\'' );
540+ }
541+
530542/*
531543 * DumpClasses -
532544 * dump the contents of all the classes.
@@ -1067,7 +1079,8 @@ dumpDatabase(Archive *AH)
10671079
10681080/* Get the dba */
10691081appendPQExpBuffer (dbQry ,"select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
1070- " where datname = '%s'" ,PQdb (g_conn ));
1082+ " where datname = " );
1083+ formatStringLiteral (dbQry ,PQdb (g_conn ));
10711084
10721085res = PQexec (g_conn ,dbQry -> data );
10731086if (!res ||
@@ -1826,7 +1839,7 @@ getFuncs(int *numFuncs)
18261839finfo [i ].oid = strdup (PQgetvalue (res ,i ,i_oid ));
18271840finfo [i ].proname = strdup (PQgetvalue (res ,i ,i_proname ));
18281841
1829- finfo [i ].prosrc = checkForQuote (PQgetvalue (res ,i ,i_prosrc ));
1842+ finfo [i ].prosrc = strdup (PQgetvalue (res ,i ,i_prosrc ));
18301843finfo [i ].probin = strdup (PQgetvalue (res ,i ,i_probin ));
18311844
18321845finfo [i ].prorettype = strdup (PQgetvalue (res ,i ,i_prorettype ));
@@ -1955,7 +1968,9 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
19551968PGresult * res2 ;
19561969
19571970resetPQExpBuffer (query );
1958- appendPQExpBuffer (query ,"SELECT pg_get_viewdef('%s') as viewdef " ,tblinfo [i ].relname );
1971+ appendPQExpBuffer (query ,"SELECT pg_get_viewdef(" );
1972+ formatStringLiteral (query ,tblinfo [i ].relname );
1973+ appendPQExpBuffer (query ,") as viewdef" );
19591974res2 = PQexec (g_conn ,query -> data );
19601975if (!res2 || PQresultStatus (res2 )!= PGRES_TUPLES_OK )
19611976{
@@ -2753,8 +2768,9 @@ dumpComment(Archive *fout, const char *target, const char *oid)
27532768{
27542769i_description = PQfnumber (res ,"description" );
27552770resetPQExpBuffer (query );
2756- appendPQExpBuffer (query ,"COMMENT ON %s IS '%s';\n" ,
2757- target ,checkForQuote (PQgetvalue (res ,0 ,i_description )));
2771+ appendPQExpBuffer (query ,"COMMENT ON %s IS " ,target );
2772+ formatStringLiteral (query ,PQgetvalue (res ,0 ,i_description ));
2773+ appendPQExpBuffer (query ,";\n" );
27582774
27592775ArchiveEntry (fout ,oid ,target ,"COMMENT" ,NULL ,query -> data ,"" /*Del*/ ,
27602776"" /* Copy */ ,"" /*Owner*/ ,NULL ,NULL );
@@ -2788,8 +2804,8 @@ dumpDBComment(Archive *fout)
27882804/*** Build query to find comment ***/
27892805
27902806query = createPQExpBuffer ();
2791- appendPQExpBuffer (query ,"SELECT oid FROM pg_database WHERE datname ='%s'" ,
2792- PQdb (g_conn ));
2807+ appendPQExpBuffer (query ,"SELECT oid FROM pg_database WHERE datname =" );
2808+ formatStringLiteral ( query , PQdb (g_conn ));
27932809
27942810/*** Execute query ***/
27952811
@@ -2864,25 +2880,28 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
28642880resetPQExpBuffer (q );
28652881appendPQExpBuffer (q ,
28662882"CREATE TYPE %s "
2867- "( internallength = %s, externallength = %s, input = %s, "
2868- "output = %s, send = %s, receive = %s, default = '%s'" ,
2883+ "( internallength = %s, externallength = %s," ,
28692884fmtId (tinfo [i ].typname ,force_quotes ),
28702885tinfo [i ].typlen ,
2871- tinfo [i ].typprtlen ,
2872- tinfo [i ].typinput ,
2873- tinfo [i ].typoutput ,
2874- tinfo [i ].typsend ,
2875- tinfo [i ].typreceive ,
2876- tinfo [i ].typdefault );
2886+ tinfo [i ].typprtlen );
2887+ /* cannot combine these because fmtId uses static result area */
2888+ appendPQExpBuffer (q ," input = %s," ,
2889+ fmtId (tinfo [i ].typinput ,force_quotes ));
2890+ appendPQExpBuffer (q ," output = %s," ,
2891+ fmtId (tinfo [i ].typoutput ,force_quotes ));
2892+ appendPQExpBuffer (q ," send = %s," ,
2893+ fmtId (tinfo [i ].typsend ,force_quotes ));
2894+ appendPQExpBuffer (q ," receive = %s, default = " ,
2895+ fmtId (tinfo [i ].typreceive ,force_quotes ));
2896+ formatStringLiteral (q ,tinfo [i ].typdefault );
28772897
28782898if (tinfo [i ].isArray )
28792899{
28802900char * elemType ;
28812901
28822902elemType = findTypeByOid (tinfo ,numTypes ,tinfo [i ].typelem ,zeroAsOpaque );
2883-
2884- appendPQExpBuffer (q ,", element = %s, delimiter = '%s'" ,
2885- elemType ,tinfo [i ].typdelim );
2903+ appendPQExpBuffer (q ,", element = %s, delimiter = " ,elemType );
2904+ formatStringLiteral (q ,tinfo [i ].typdelim );
28862905}
28872906if (tinfo [i ].passedbyvalue )
28882907appendPQExpBuffer (q ,",passedbyvalue);\n" );
@@ -2971,24 +2990,25 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
29712990
29722991dumpOneFunc (fout ,finfo ,fidx ,tinfo ,numTypes );
29732992
2974- lanname = checkForQuote ( PQgetvalue (res ,i ,i_lanname ) );
2975- lancompiler = checkForQuote ( PQgetvalue (res ,i ,i_lancompiler ) );
2993+ lanname = PQgetvalue (res ,i ,i_lanname );
2994+ lancompiler = PQgetvalue (res ,i ,i_lancompiler );
29762995
2977- appendPQExpBuffer (delqry ,"DROP PROCEDURAL LANGUAGE '%s';\n" ,lanname );
2996+ appendPQExpBuffer (delqry ,"DROP PROCEDURAL LANGUAGE " );
2997+ formatStringLiteral (delqry ,lanname );
2998+ appendPQExpBuffer (delqry ,";\n" );
29782999
2979- appendPQExpBuffer (defqry ,"CREATE %sPROCEDURAL LANGUAGE '%s' "
2980- "HANDLER %s LANCOMPILER '%s';\n" ,
2981- (PQgetvalue (res ,i ,i_lanpltrusted )[0 ]== 't' ) ?"TRUSTED " :"" ,
2982- lanname ,
2983- fmtId (finfo [fidx ].proname ,force_quotes ),
2984- lancompiler );
3000+ appendPQExpBuffer (defqry ,"CREATE %sPROCEDURAL LANGUAGE " ,
3001+ (PQgetvalue (res ,i ,i_lanpltrusted )[0 ]== 't' ) ?
3002+ "TRUSTED " :"" );
3003+ formatStringLiteral (defqry ,lanname );
3004+ appendPQExpBuffer (defqry ," HANDLER %s LANCOMPILER " ,
3005+ fmtId (finfo [fidx ].proname ,force_quotes ));
3006+ formatStringLiteral (defqry ,lancompiler );
3007+ appendPQExpBuffer (defqry ,";\n" );
29853008
29863009ArchiveEntry (fout ,PQgetvalue (res ,i ,i_oid ),lanname ,"PROCEDURAL LANGUAGE" ,
29873010NULL ,defqry -> data ,delqry -> data ,"" ,"" ,NULL ,NULL );
29883011
2989- free (lanname );
2990- free (lancompiler );
2991-
29923012resetPQExpBuffer (defqry );
29933013resetPQExpBuffer (delqry );
29943014}
@@ -3071,15 +3091,21 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
30713091 */
30723092if (strcmp (finfo [i ].probin ,"-" )!= 0 )
30733093{
3094+ appendPQExpBuffer (asPart ,"AS " );
3095+ formatStringLiteral (asPart ,finfo [i ].probin );
30743096if (strcmp (finfo [i ].prosrc ,"-" )!= 0 )
3075- appendPQExpBuffer (asPart ,"AS '%s', '%s'" ,finfo [i ].probin ,finfo [i ].prosrc );
3076- else
3077- appendPQExpBuffer (asPart ,"AS '%s'" ,finfo [i ].probin );
3097+ {
3098+ appendPQExpBuffer (asPart ,", " );
3099+ formatStringLiteral (asPart ,finfo [i ].prosrc );
3100+ }
30783101}
30793102else
30803103{
30813104if (strcmp (finfo [i ].prosrc ,"-" )!= 0 )
3082- appendPQExpBuffer (asPart ,"AS '%s'" ,finfo [i ].prosrc );
3105+ {
3106+ appendPQExpBuffer (asPart ,"AS " );
3107+ formatStringLiteral (asPart ,finfo [i ].prosrc );
3108+ }
30833109}
30843110
30853111strcpy (func_lang ,PQgetvalue (res ,0 ,i_lanname ));
@@ -3107,10 +3133,11 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
31073133
31083134resetPQExpBuffer (q );
31093135appendPQExpBuffer (q ,"CREATE FUNCTION %s " ,fn -> data );
3110- appendPQExpBuffer (q ,"RETURNS %s%s %s LANGUAGE'%s' " ,
3111- (finfo [i ].retset ) ?" SETOF " :"" ,
3136+ appendPQExpBuffer (q ,"RETURNS %s%s %s LANGUAGE " ,
3137+ (finfo [i ].retset ) ?"SETOF " :"" ,
31123138findTypeByOid (tinfo ,numTypes ,finfo [i ].prorettype ,zeroAsOpaque ),
3113- asPart -> data ,func_lang );
3139+ asPart -> data );
3140+ formatStringLiteral (q ,func_lang );
31143141
31153142if (finfo [i ].iscachable || finfo [i ].isstrict )/* OR in new attrs here */
31163143{
@@ -3286,8 +3313,10 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
32863313findTypeByOid (tinfo ,numTypes ,agginfo [i ].aggtranstype ,zeroAsOpaque + useBaseTypeName ));
32873314
32883315if (agginfo [i ].agginitval )
3289- appendPQExpBuffer (details ,", INITCOND = '%s'" ,
3290- agginfo [i ].agginitval );
3316+ {
3317+ appendPQExpBuffer (details ,", INITCOND = " );
3318+ formatStringLiteral (details ,agginfo [i ].agginitval );
3319+ }
32913320
32923321if (!(strcmp (agginfo [i ].aggfinalfn ,"-" )== 0 ))
32933322appendPQExpBuffer (details ,", FINALFUNC = %s" ,
@@ -3970,7 +3999,8 @@ findLastBuiltinOid(const char* dbname)
39703999PQExpBuffer query = createPQExpBuffer ();
39714000
39724001resetPQExpBuffer (query );
3973- appendPQExpBuffer (query ,"SELECT datlastsysoid from pg_database where datname = '%s'" ,dbname );
4002+ appendPQExpBuffer (query ,"SELECT datlastsysoid from pg_database where datname = " );
4003+ formatStringLiteral (query ,dbname );
39744004
39754005res = PQexec (g_conn ,query -> data );
39764006if (res == NULL ||
@@ -3999,41 +4029,6 @@ findLastBuiltinOid(const char* dbname)
39994029}
40004030
40014031
4002- /*
4003- * checkForQuote:
4004- * checks a string for quote characters and quotes them
4005- */
4006- static char *
4007- checkForQuote (const char * s )
4008- {
4009- char * r ;
4010- char c ;
4011- char * result ;
4012-
4013- int j = 0 ;
4014-
4015- r = malloc (strlen (s )* 3 + 1 );/* definitely long enough */
4016-
4017- while ((c = * s )!= '\0' )
4018- {
4019-
4020- if (c == '\'' )
4021- {
4022- r [j ++ ]= '\'' ;/* quote the single quotes */
4023- }
4024- r [j ++ ]= c ;
4025- s ++ ;
4026- }
4027- r [j ]= '\0' ;
4028-
4029- result = strdup (r );
4030- free (r );
4031-
4032- return result ;
4033-
4034- }
4035-
4036-
40374032static void
40384033dumpSequence (Archive * fout ,TableInfo tbinfo )
40394034{
@@ -4113,8 +4108,9 @@ dumpSequence(Archive *fout, TableInfo tbinfo)
41134108
41144109
41154110resetPQExpBuffer (query );
4116- appendPQExpBuffer (query ,"SELECT setval ('%s', %d, '%c');\n" ,
4117- fmtId (tbinfo .relname ,force_quotes ),last ,called );
4111+ appendPQExpBuffer (query ,"SELECT setval (" );
4112+ formatStringLiteral (query ,fmtId (tbinfo .relname ,force_quotes ));
4113+ appendPQExpBuffer (query ,", %d, '%c');\n" ,last ,called );
41184114
41194115ArchiveEntry (fout ,tbinfo .oid ,fmtId (tbinfo .relname ,force_quotes ),"SEQUENCE SET" ,NULL ,
41204116query -> data ,"" /* Del */ ,"" ,"" ,NULL ,NULL );
@@ -4191,12 +4187,13 @@ dumpRules(Archive *fout, const char *tablename,
41914187" (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
41924188" pg_rewrite.oid, pg_rewrite.rulename "
41934189"FROM pg_rewrite, pg_class, pg_rules "
4194- "WHERE pg_class.relname = '%s' "
4190+ "WHERE pg_class.relname = " );
4191+ formatStringLiteral (query ,tblinfo [t ].relname );
4192+ appendPQExpBuffer (query ,
41954193" AND pg_rewrite.ev_class = pg_class.oid "
41964194" AND pg_rules.tablename = pg_class.relname "
41974195" AND pg_rules.rulename = pg_rewrite.rulename "
4198- "ORDER BY pg_rewrite.oid" ,
4199- tblinfo [t ].relname );
4196+ "ORDER BY pg_rewrite.oid" );
42004197res = PQexec (g_conn ,query -> data );
42014198if (!res ||
42024199PQresultStatus (res )!= PGRES_TUPLES_OK )