|
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 int optind, |
67 | 67 | opterr; |
68 | 68 |
|
69 | 69 |
|
| 70 | +typedef struct |
| 71 | +{ |
| 72 | + const char *descr; /* comment for an object */ |
| 73 | + Oid classoid; /* object class (catalog OID) */ |
| 74 | + Oid objoid; /* object OID */ |
| 75 | + int objsubid; /* subobject (table column #) */ |
| 76 | +} CommentItem; |
| 77 | + |
| 78 | + |
70 | 79 | /* global decls */ |
71 | 80 | bool g_verbose; /* User wants verbose narration of our |
72 | 81 | * activities. */ |
@@ -105,6 +114,9 @@ static void dumpTableData(Archive *fout, TableDataInfo *tdinfo); |
105 | 114 | static void dumpComment(Archive *fout, const char *target, |
106 | 115 | const char *namespace, const char *owner, |
107 | 116 | CatalogId catalogId, int subid, DumpId dumpId); |
| 117 | +static int findComments(Archive *fout, Oid classoid, Oid objoid, |
| 118 | + CommentItem **items); |
| 119 | +static int collectComments(Archive *fout, CommentItem **items); |
108 | 120 | static void dumpDumpableObject(Archive *fout, DumpableObject *dobj); |
109 | 121 | static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo); |
110 | 122 | static void dumpType(Archive *fout, TypeInfo *tinfo); |
@@ -3880,141 +3892,81 @@ dumpComment(Archive *fout, const char *target, |
3880 | 3892 | const char *namespace, const char *owner, |
3881 | 3893 | CatalogId catalogId, int subid, DumpId dumpId) |
3882 | 3894 | { |
3883 | | - PGresult *res; |
3884 | | - PQExpBuffer query; |
3885 | | - int i_description; |
| 3895 | + CommentItem *comments; |
| 3896 | + int ncomments; |
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 | | - else if (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 | + PQExpBuffer query = 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 | static void |
3955 | 3941 | dumpTableComment(Archive *fout, TableInfo *tbinfo, |
3956 | 3942 | const char *reltypename) |
3957 | 3943 | { |
3958 | | - PGresult *res; |
| 3944 | + CommentItem *comments; |
| 3945 | + int ncomments; |
3959 | 3946 | PQExpBuffer query; |
3960 | 3947 | PQExpBuffer target; |
3961 | | - int i_description; |
3962 | | - int i_objsubid; |
3963 | | - int ntups; |
3964 | | - int i; |
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 | | - else if (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 | | - const char *descr = PQgetvalue(res, i, i_description); |
4017 | | - int objsubid = atoi(PQgetvalue(res, i, i_objsubid)); |
| 3968 | + const char *descr = comments->descr; |
| 3969 | + int objsubid = 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 | +static int |
| 4026 | +findComments(Archive *fout, Oid classoid, Oid objoid, |
| 4027 | + CommentItem **items) |
| 4028 | +{ |
| 4029 | + /* static storage for table of comments */ |
| 4030 | + static CommentItem *comments = NULL; |
| 4031 | + static int ncomments = -1; |
| 4032 | + |
| 4033 | + CommentItem *middle = NULL; |
| 4034 | + CommentItem *low; |
| 4035 | + CommentItem *high; |
| 4036 | + int nmatch; |
| 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 | + else if (classoid > middle->classoid) |
| 4062 | + low = middle + 1; |
| 4063 | + else if (objoid < middle->objoid) |
| 4064 | + high = middle - 1; |
| 4065 | + else if (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 | + return 0; |
| 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 | + return nmatch; |
| 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 | +static int |
| 4118 | +collectComments(Archive *fout, CommentItem **items) |
| 4119 | +{ |
| 4120 | + PGresult *res; |
| 4121 | + PQExpBuffer query; |
| 4122 | + int i_description; |
| 4123 | + int i_classoid; |
| 4124 | + int i_objoid; |
| 4125 | + int i_objsubid; |
| 4126 | + int ntups; |
| 4127 | + int i; |
| 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 | + else if (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 | + return ntups; |
| 4184 | +} |
| 4185 | + |
4064 | 4186 | /* |
4065 | 4187 | * dumpDumpableObject |
4066 | 4188 | * |
|
0 commit comments