|
12 | 12 | *by PostgreSQL
|
13 | 13 | *
|
14 | 14 | * IDENTIFICATION
|
15 |
| - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.367 2004/03/03 21:28:54 tgl Exp $ |
| 15 | + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.368 2004/03/20 20:09:45 tgl Exp $ |
16 | 16 | *
|
17 | 17 | *-------------------------------------------------------------------------
|
18 | 18 | */
|
@@ -67,6 +67,15 @@ extern intoptind,
|
67 | 67 | opterr;
|
68 | 68 |
|
69 | 69 |
|
| 70 | +typedefstruct |
| 71 | +{ |
| 72 | +constchar*descr;/* comment for an object */ |
| 73 | +Oidclassoid;/* object class (catalog OID) */ |
| 74 | +Oidobjoid;/* object OID */ |
| 75 | +intobjsubid;/* subobject (table column #) */ |
| 76 | +}CommentItem; |
| 77 | + |
| 78 | + |
70 | 79 | /* global decls */
|
71 | 80 | boolg_verbose;/* User wants verbose narration of our
|
72 | 81 | * activities. */
|
@@ -105,6 +114,9 @@ static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
|
105 | 114 | staticvoiddumpComment(Archive*fout,constchar*target,
|
106 | 115 | constchar*namespace,constchar*owner,
|
107 | 116 | CatalogIdcatalogId,intsubid,DumpIddumpId);
|
| 117 | +staticintfindComments(Archive*fout,Oidclassoid,Oidobjoid, |
| 118 | +CommentItem**items); |
| 119 | +staticintcollectComments(Archive*fout,CommentItem**items); |
108 | 120 | staticvoiddumpDumpableObject(Archive*fout,DumpableObject*dobj);
|
109 | 121 | staticvoiddumpNamespace(Archive*fout,NamespaceInfo*nspinfo);
|
110 | 122 | staticvoiddumpType(Archive*fout,TypeInfo*tinfo);
|
@@ -3880,141 +3892,81 @@ dumpComment(Archive *fout, const char *target,
|
3880 | 3892 | constchar*namespace,constchar*owner,
|
3881 | 3893 | CatalogIdcatalogId,intsubid,DumpIddumpId)
|
3882 | 3894 | {
|
3883 |
| -PGresult*res; |
3884 |
| -PQExpBufferquery; |
3885 |
| -inti_description; |
| 3895 | +CommentItem*comments; |
| 3896 | +intncomments; |
3886 | 3897 |
|
3887 | 3898 | /* Comments are SCHEMA not data */
|
3888 | 3899 | if (dataOnly)
|
3889 | 3900 | return;
|
3890 | 3901 |
|
3891 |
| -/* |
3892 |
| - * Note we do NOT change source schema here; preserve the caller's |
3893 |
| - * setting, instead. |
3894 |
| - */ |
| 3902 | +/* Search for comments associated with catalogId, using table */ |
| 3903 | +ncomments=findComments(fout,catalogId.tableoid,catalogId.oid, |
| 3904 | +&comments); |
3895 | 3905 |
|
3896 |
| -/* Build query to find comment */ |
3897 |
| - |
3898 |
| -query=createPQExpBuffer(); |
3899 |
| - |
3900 |
| -if (fout->remoteVersion >=70300) |
3901 |
| -{ |
3902 |
| -appendPQExpBuffer(query, |
3903 |
| -"SELECT description FROM pg_catalog.pg_description " |
3904 |
| -"WHERE classoid = '%u'::pg_catalog.oid and " |
3905 |
| -"objoid = '%u'::pg_catalog.oid and objsubid = %d", |
3906 |
| -catalogId.tableoid,catalogId.oid,subid); |
3907 |
| -} |
3908 |
| -elseif (fout->remoteVersion >=70200) |
3909 |
| -{ |
3910 |
| -appendPQExpBuffer(query, |
3911 |
| -"SELECT description FROM pg_description " |
3912 |
| -"WHERE classoid = '%u'::oid and " |
3913 |
| -"objoid = '%u'::oid and objsubid = %d", |
3914 |
| -catalogId.tableoid,catalogId.oid,subid); |
3915 |
| -} |
3916 |
| -else |
| 3906 | +/* Is there one matching the subid? */ |
| 3907 | +while (ncomments>0) |
3917 | 3908 | {
|
3918 |
| -/* Note: this will fail to find attribute comments in pre-7.2... */ |
3919 |
| -appendPQExpBuffer(query,"SELECT description FROM pg_description WHERE objoid = '%u'::oid",catalogId.oid); |
| 3909 | +if (comments->objsubid==subid) |
| 3910 | +break; |
| 3911 | +comments++; |
| 3912 | +ncomments--; |
3920 | 3913 | }
|
3921 | 3914 |
|
3922 |
| -/* Execute query */ |
3923 |
| - |
3924 |
| -res=PQexec(g_conn,query->data); |
3925 |
| -check_sql_result(res,g_conn,query->data,PGRES_TUPLES_OK); |
3926 |
| - |
3927 | 3915 | /* If a comment exists, build COMMENT ON statement */
|
3928 |
| - |
3929 |
| -if (PQntuples(res)==1) |
| 3916 | +if (ncomments>0) |
3930 | 3917 | {
|
3931 |
| -i_description=PQfnumber(res,"description"); |
3932 |
| -resetPQExpBuffer(query); |
| 3918 | +PQExpBufferquery=createPQExpBuffer(); |
| 3919 | + |
3933 | 3920 | appendPQExpBuffer(query,"COMMENT ON %s IS ",target);
|
3934 |
| -appendStringLiteral(query,PQgetvalue(res,0,i_description), false); |
| 3921 | +appendStringLiteral(query,comments->descr, false); |
3935 | 3922 | appendPQExpBuffer(query,";\n");
|
3936 | 3923 |
|
3937 | 3924 | ArchiveEntry(fout,nilCatalogId,createDumpId(),
|
3938 | 3925 | target,namespace,owner,
|
3939 | 3926 | "COMMENT",query->data,"",NULL,
|
3940 | 3927 | &(dumpId),1,
|
3941 | 3928 | NULL,NULL);
|
3942 |
| -} |
3943 | 3929 |
|
3944 |
| -PQclear(res); |
3945 |
| -destroyPQExpBuffer(query); |
| 3930 | +destroyPQExpBuffer(query); |
| 3931 | +} |
3946 | 3932 | }
|
3947 | 3933 |
|
3948 | 3934 | /*
|
3949 | 3935 | * dumpTableComment --
|
3950 | 3936 | *
|
3951 | 3937 | * As above, but dump comments for both the specified table (or view)
|
3952 |
| - * and its columns. For speed, we want to do this with only one query. |
| 3938 | + * and its columns. |
3953 | 3939 | */
|
3954 | 3940 | staticvoid
|
3955 | 3941 | dumpTableComment(Archive*fout,TableInfo*tbinfo,
|
3956 | 3942 | constchar*reltypename)
|
3957 | 3943 | {
|
3958 |
| -PGresult*res; |
| 3944 | +CommentItem*comments; |
| 3945 | +intncomments; |
3959 | 3946 | PQExpBufferquery;
|
3960 | 3947 | PQExpBuffertarget;
|
3961 |
| -inti_description; |
3962 |
| -inti_objsubid; |
3963 |
| -intntups; |
3964 |
| -inti; |
3965 | 3948 |
|
3966 | 3949 | /* Comments are SCHEMA not data */
|
3967 | 3950 | if (dataOnly)
|
3968 | 3951 | return;
|
3969 | 3952 |
|
3970 |
| -/* |
3971 |
| - * Note we do NOT change source schema here; preserve the caller's |
3972 |
| - * setting, instead. |
3973 |
| - */ |
| 3953 | +/* Search for comments associated with relation, using table */ |
| 3954 | +ncomments=findComments(fout, |
| 3955 | +tbinfo->dobj.catId.tableoid, |
| 3956 | +tbinfo->dobj.catId.oid, |
| 3957 | +&comments); |
3974 | 3958 |
|
3975 |
| -/* Build query to find comments */ |
| 3959 | +/* If comments exist, build COMMENT ON statements */ |
| 3960 | +if (ncomments <=0) |
| 3961 | +return; |
3976 | 3962 |
|
3977 | 3963 | query=createPQExpBuffer();
|
3978 | 3964 | target=createPQExpBuffer();
|
3979 | 3965 |
|
3980 |
| -if (fout->remoteVersion >=70300) |
3981 |
| -{ |
3982 |
| -appendPQExpBuffer(query,"SELECT description, objsubid FROM pg_catalog.pg_description " |
3983 |
| -"WHERE classoid = '%u'::pg_catalog.oid and " |
3984 |
| -"objoid = '%u'::pg_catalog.oid " |
3985 |
| -"ORDER BY objoid, classoid, objsubid", |
3986 |
| -tbinfo->dobj.catId.tableoid,tbinfo->dobj.catId.oid); |
3987 |
| -} |
3988 |
| -elseif (fout->remoteVersion >=70200) |
3989 |
| -{ |
3990 |
| -appendPQExpBuffer(query,"SELECT description, objsubid FROM pg_description " |
3991 |
| -"WHERE classoid = '%u'::oid and " |
3992 |
| -"objoid = '%u'::oid " |
3993 |
| -"ORDER BY objoid, classoid, objsubid", |
3994 |
| -tbinfo->dobj.catId.tableoid,tbinfo->dobj.catId.oid); |
3995 |
| -} |
3996 |
| -else |
3997 |
| -{ |
3998 |
| -/* Note: this will fail to find attribute comments in pre-7.2... */ |
3999 |
| -appendPQExpBuffer(query,"SELECT description, 0 as objsubid FROM pg_description WHERE objoid = '%u'::oid", |
4000 |
| -tbinfo->dobj.catId.oid); |
4001 |
| -} |
4002 |
| - |
4003 |
| -/* Execute query */ |
4004 |
| - |
4005 |
| -res=PQexec(g_conn,query->data); |
4006 |
| -check_sql_result(res,g_conn,query->data,PGRES_TUPLES_OK); |
4007 |
| - |
4008 |
| -i_description=PQfnumber(res,"description"); |
4009 |
| -i_objsubid=PQfnumber(res,"objsubid"); |
4010 |
| - |
4011 |
| -/* If comments exist, build COMMENT ON statements */ |
4012 |
| - |
4013 |
| -ntups=PQntuples(res); |
4014 |
| -for (i=0;i<ntups;i++) |
| 3966 | +while (ncomments>0) |
4015 | 3967 | {
|
4016 |
| -constchar*descr=PQgetvalue(res,i,i_description); |
4017 |
| -intobjsubid=atoi(PQgetvalue(res,i,i_objsubid)); |
| 3968 | +constchar*descr=comments->descr; |
| 3969 | +intobjsubid=comments->objsubid; |
4018 | 3970 |
|
4019 | 3971 | if (objsubid==0)
|
4020 | 3972 | {
|
@@ -4054,13 +4006,183 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
|
4054 | 4006 | &(tbinfo->dobj.dumpId),1,
|
4055 | 4007 | NULL,NULL);
|
4056 | 4008 | }
|
| 4009 | + |
| 4010 | +comments++; |
| 4011 | +ncomments--; |
4057 | 4012 | }
|
4058 | 4013 |
|
4059 |
| -PQclear(res); |
4060 | 4014 | destroyPQExpBuffer(query);
|
4061 | 4015 | destroyPQExpBuffer(target);
|
4062 | 4016 | }
|
4063 | 4017 |
|
| 4018 | +/* |
| 4019 | + * findComments -- |
| 4020 | + * |
| 4021 | + * Find the comment(s), if any, associated with the given object. All the |
| 4022 | + * objsubid values associated with the given classoid/objoid are found with |
| 4023 | + * one search. |
| 4024 | + */ |
| 4025 | +staticint |
| 4026 | +findComments(Archive*fout,Oidclassoid,Oidobjoid, |
| 4027 | +CommentItem**items) |
| 4028 | +{ |
| 4029 | +/* static storage for table of comments */ |
| 4030 | +staticCommentItem*comments=NULL; |
| 4031 | +staticintncomments=-1; |
| 4032 | + |
| 4033 | +CommentItem*middle=NULL; |
| 4034 | +CommentItem*low; |
| 4035 | +CommentItem*high; |
| 4036 | +intnmatch; |
| 4037 | + |
| 4038 | +/* Get comments if we didn't already */ |
| 4039 | +if (ncomments<0) |
| 4040 | +ncomments=collectComments(fout,&comments); |
| 4041 | + |
| 4042 | +/* |
| 4043 | + * Pre-7.2, pg_description does not contain classoid, so collectComments |
| 4044 | + * just stores a zero. If there's a collision on object OID, well, you |
| 4045 | + * get duplicate comments. |
| 4046 | + */ |
| 4047 | +if (fout->remoteVersion<70200) |
| 4048 | +classoid=0; |
| 4049 | + |
| 4050 | +/* |
| 4051 | + * Do binary search to find some item matching the object. |
| 4052 | + */ |
| 4053 | +low=&comments[0]; |
| 4054 | +high=&comments[ncomments-1]; |
| 4055 | +while (low <=high) |
| 4056 | +{ |
| 4057 | +middle=low+ (high-low) /2; |
| 4058 | + |
| 4059 | +if (classoid<middle->classoid) |
| 4060 | +high=middle-1; |
| 4061 | +elseif (classoid>middle->classoid) |
| 4062 | +low=middle+1; |
| 4063 | +elseif (objoid<middle->objoid) |
| 4064 | +high=middle-1; |
| 4065 | +elseif (objoid>middle->objoid) |
| 4066 | +low=middle+1; |
| 4067 | +else |
| 4068 | +break;/* found a match */ |
| 4069 | +} |
| 4070 | + |
| 4071 | +if (low>high)/* no matches */ |
| 4072 | +{ |
| 4073 | +*items=NULL; |
| 4074 | +return0; |
| 4075 | +} |
| 4076 | + |
| 4077 | +/* |
| 4078 | + * Now determine how many items match the object. The search loop |
| 4079 | + * invariant still holds: only items between low and high inclusive |
| 4080 | + * could match. |
| 4081 | + */ |
| 4082 | +nmatch=1; |
| 4083 | +while (middle>low) |
| 4084 | +{ |
| 4085 | +if (classoid!=middle[-1].classoid|| |
| 4086 | +objoid!=middle[-1].objoid) |
| 4087 | +break; |
| 4088 | +middle--; |
| 4089 | +nmatch++; |
| 4090 | +} |
| 4091 | + |
| 4092 | +*items=middle; |
| 4093 | + |
| 4094 | +middle+=nmatch; |
| 4095 | +while (middle <=high) |
| 4096 | +{ |
| 4097 | +if (classoid!=middle->classoid|| |
| 4098 | +objoid!=middle->objoid) |
| 4099 | +break; |
| 4100 | +middle++; |
| 4101 | +nmatch++; |
| 4102 | +} |
| 4103 | + |
| 4104 | +returnnmatch; |
| 4105 | +} |
| 4106 | + |
| 4107 | +/* |
| 4108 | + * collectComments -- |
| 4109 | + * |
| 4110 | + * Construct a table of all comments available for database objects. |
| 4111 | + * We used to do per-object queries for the comments, but it's much faster |
| 4112 | + * to pull them all over at once, and on most databases the memory cost |
| 4113 | + * isn't high. |
| 4114 | + * |
| 4115 | + * The table is sorted by classoid/objid/objsubid for speed in lookup. |
| 4116 | + */ |
| 4117 | +staticint |
| 4118 | +collectComments(Archive*fout,CommentItem**items) |
| 4119 | +{ |
| 4120 | +PGresult*res; |
| 4121 | +PQExpBufferquery; |
| 4122 | +inti_description; |
| 4123 | +inti_classoid; |
| 4124 | +inti_objoid; |
| 4125 | +inti_objsubid; |
| 4126 | +intntups; |
| 4127 | +inti; |
| 4128 | +CommentItem*comments; |
| 4129 | + |
| 4130 | +/* |
| 4131 | + * Note we do NOT change source schema here; preserve the caller's |
| 4132 | + * setting, instead. |
| 4133 | + */ |
| 4134 | + |
| 4135 | +query=createPQExpBuffer(); |
| 4136 | + |
| 4137 | +if (fout->remoteVersion >=70300) |
| 4138 | +{ |
| 4139 | +appendPQExpBuffer(query,"SELECT description, classoid, objoid, objsubid " |
| 4140 | +"FROM pg_catalog.pg_description " |
| 4141 | +"ORDER BY classoid, objoid, objsubid"); |
| 4142 | +} |
| 4143 | +elseif (fout->remoteVersion >=70200) |
| 4144 | +{ |
| 4145 | +appendPQExpBuffer(query,"SELECT description, classoid, objoid, objsubid " |
| 4146 | +"FROM pg_description " |
| 4147 | +"ORDER BY classoid, objoid, objsubid"); |
| 4148 | +} |
| 4149 | +else |
| 4150 | +{ |
| 4151 | +/* Note: this will fail to find attribute comments in pre-7.2... */ |
| 4152 | +appendPQExpBuffer(query,"SELECT description, 0 as classoid, objoid, 0 as objsubid " |
| 4153 | +"FROM pg_description " |
| 4154 | +"ORDER BY objoid"); |
| 4155 | +} |
| 4156 | + |
| 4157 | +res=PQexec(g_conn,query->data); |
| 4158 | +check_sql_result(res,g_conn,query->data,PGRES_TUPLES_OK); |
| 4159 | + |
| 4160 | +/* Construct lookup table containing OIDs in numeric form */ |
| 4161 | + |
| 4162 | +i_description=PQfnumber(res,"description"); |
| 4163 | +i_classoid=PQfnumber(res,"classoid"); |
| 4164 | +i_objoid=PQfnumber(res,"objoid"); |
| 4165 | +i_objsubid=PQfnumber(res,"objsubid"); |
| 4166 | + |
| 4167 | +ntups=PQntuples(res); |
| 4168 | + |
| 4169 | +comments= (CommentItem*)malloc(ntups*sizeof(CommentItem)); |
| 4170 | + |
| 4171 | +for (i=0;i<ntups;i++) |
| 4172 | +{ |
| 4173 | +comments[i].descr=PQgetvalue(res,i,i_description); |
| 4174 | +comments[i].classoid=atooid(PQgetvalue(res,i,i_classoid)); |
| 4175 | +comments[i].objoid=atooid(PQgetvalue(res,i,i_objoid)); |
| 4176 | +comments[i].objsubid=atoi(PQgetvalue(res,i,i_objsubid)); |
| 4177 | +} |
| 4178 | + |
| 4179 | +/* Do NOT free the PGresult since we are keeping pointers into it */ |
| 4180 | +destroyPQExpBuffer(query); |
| 4181 | + |
| 4182 | +*items=comments; |
| 4183 | +returnntups; |
| 4184 | +} |
| 4185 | + |
4064 | 4186 | /*
|
4065 | 4187 | * dumpDumpableObject
|
4066 | 4188 | *
|
|