|
3 | 3 | * procedural language
|
4 | 4 | *
|
5 | 5 | * IDENTIFICATION
|
6 |
| - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.51 2002/09/04 20:31:47 momjian Exp $ |
| 6 | + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.52 2002/09/12 00:24:09 momjian Exp $ |
7 | 7 | *
|
8 | 8 | * This software is copyrighted by Jan Wieck - Hamburg.
|
9 | 9 | *
|
@@ -1092,6 +1092,126 @@ plpgsql_parse_dblwordtype(char *word)
|
1092 | 1092 | return T_DTYPE;
|
1093 | 1093 | }
|
1094 | 1094 |
|
| 1095 | +/* ---------- |
| 1096 | + * plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE |
| 1097 | + * ---------- |
| 1098 | + */ |
| 1099 | +#define TYPE_JUNK_LEN 5 |
| 1100 | + |
| 1101 | +int |
| 1102 | +plpgsql_parse_tripwordtype(char *word) |
| 1103 | +{ |
| 1104 | + Oid classOid; |
| 1105 | + HeapTuple classtup; |
| 1106 | + Form_pg_class classStruct; |
| 1107 | + HeapTuple attrtup; |
| 1108 | + Form_pg_attribute attrStruct; |
| 1109 | + HeapTuple typetup; |
| 1110 | + Form_pg_type typeStruct; |
| 1111 | + PLpgSQL_type *typ; |
| 1112 | + char *cp[2]; |
| 1113 | + int qualified_att_len; |
| 1114 | + int numdots = 0; |
| 1115 | + int i; |
| 1116 | + RangeVar *relvar; |
| 1117 | + |
| 1118 | + /* Do case conversion and word separation */ |
| 1119 | + qualified_att_len = strlen(word) - TYPE_JUNK_LEN; |
| 1120 | + Assert(word[qualified_att_len] == '%'); |
| 1121 | + |
| 1122 | + for (i = 0; i < qualified_att_len; i++) |
| 1123 | + { |
| 1124 | + if (word[i] == '.' && ++numdots == 2) |
| 1125 | + { |
| 1126 | + cp[0] = (char *) palloc((i + 1) * sizeof(char)); |
| 1127 | + memset(cp[0], 0, (i + 1) * sizeof(char)); |
| 1128 | + memcpy(cp[0], word, i * sizeof(char)); |
| 1129 | + |
| 1130 | + /* qualified_att_len - one based position + 1 (null terminator) */ |
| 1131 | + cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char)); |
| 1132 | + memset(cp[1], 0, (qualified_att_len - i) * sizeof(char)); |
| 1133 | + memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char)); |
| 1134 | + |
| 1135 | + break; |
| 1136 | + } |
| 1137 | + } |
| 1138 | + |
| 1139 | + relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], "plpgsql_parse_dblwordtype")); |
| 1140 | + classOid = RangeVarGetRelid(relvar, true); |
| 1141 | + if (!OidIsValid(classOid)) |
| 1142 | + { |
| 1143 | + pfree(cp[0]); |
| 1144 | + pfree(cp[1]); |
| 1145 | + return T_ERROR; |
| 1146 | + } |
| 1147 | + classtup = SearchSysCache(RELOID, |
| 1148 | + ObjectIdGetDatum(classOid), |
| 1149 | + 0, 0, 0); |
| 1150 | + if (!HeapTupleIsValid(classtup)) |
| 1151 | + { |
| 1152 | + pfree(cp[0]); |
| 1153 | + pfree(cp[1]); |
| 1154 | + return T_ERROR; |
| 1155 | + } |
| 1156 | + |
| 1157 | + /* |
| 1158 | + * It must be a relation, sequence, view, or type |
| 1159 | + */ |
| 1160 | + classStruct = (Form_pg_class) GETSTRUCT(classtup); |
| 1161 | + if (classStruct->relkind != RELKIND_RELATION && |
| 1162 | + classStruct->relkind != RELKIND_SEQUENCE && |
| 1163 | + classStruct->relkind != RELKIND_VIEW && |
| 1164 | + classStruct->relkind != RELKIND_COMPOSITE_TYPE) |
| 1165 | + { |
| 1166 | + ReleaseSysCache(classtup); |
| 1167 | + pfree(cp[0]); |
| 1168 | + pfree(cp[1]); |
| 1169 | + return T_ERROR; |
| 1170 | + } |
| 1171 | + |
| 1172 | + /* |
| 1173 | + * Fetch the named table field and it's type |
| 1174 | + */ |
| 1175 | + attrtup = SearchSysCacheAttName(classOid, cp[1]); |
| 1176 | + if (!HeapTupleIsValid(attrtup)) |
| 1177 | + { |
| 1178 | + ReleaseSysCache(classtup); |
| 1179 | + pfree(cp[0]); |
| 1180 | + pfree(cp[1]); |
| 1181 | + return T_ERROR; |
| 1182 | + } |
| 1183 | + attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); |
| 1184 | + |
| 1185 | + typetup = SearchSysCache(TYPEOID, |
| 1186 | + ObjectIdGetDatum(attrStruct->atttypid), |
| 1187 | + 0, 0, 0); |
| 1188 | + if (!HeapTupleIsValid(typetup)) |
| 1189 | + elog(ERROR, "cache lookup for type %u of %s.%s failed", |
| 1190 | + attrStruct->atttypid, cp[0], cp[1]); |
| 1191 | + typeStruct = (Form_pg_type) GETSTRUCT(typetup); |
| 1192 | + |
| 1193 | + /* |
| 1194 | + * Found that - build a compiler type struct and return it |
| 1195 | + */ |
| 1196 | + typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); |
| 1197 | + |
| 1198 | + typ->typname = strdup(NameStr(typeStruct->typname)); |
| 1199 | + typ->typoid = attrStruct->atttypid; |
| 1200 | + perm_fmgr_info(typeStruct->typinput, &(typ->typinput)); |
| 1201 | + typ->typelem = typeStruct->typelem; |
| 1202 | + typ->typbyval = typeStruct->typbyval; |
| 1203 | + typ->typlen = typeStruct->typlen; |
| 1204 | + typ->atttypmod = attrStruct->atttypmod; |
| 1205 | + |
| 1206 | + plpgsql_yylval.dtype = typ; |
| 1207 | + |
| 1208 | + ReleaseSysCache(classtup); |
| 1209 | + ReleaseSysCache(attrtup); |
| 1210 | + ReleaseSysCache(typetup); |
| 1211 | + pfree(cp[0]); |
| 1212 | + pfree(cp[1]); |
| 1213 | + return T_DTYPE; |
| 1214 | +} |
1095 | 1215 |
|
1096 | 1216 | /* ----------
|
1097 | 1217 | * plpgsql_parse_wordrowtype Scanner found word%ROWTYPE.
|
@@ -1129,6 +1249,46 @@ plpgsql_parse_wordrowtype(char *word)
|
1129 | 1249 | return T_ROW;
|
1130 | 1250 | }
|
1131 | 1251 |
|
| 1252 | +/* ---------- |
| 1253 | + * plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE. |
| 1254 | + * So word must be namespace qualified a table name. |
| 1255 | + * ---------- |
| 1256 | + */ |
| 1257 | +#define ROWTYPE_JUNK_LEN 8 |
| 1258 | + |
| 1259 | +int |
| 1260 | +plpgsql_parse_dblwordrowtype(char *word) |
| 1261 | +{ |
| 1262 | + Oid classOid; |
| 1263 | + char *cp; |
| 1264 | + int i; |
| 1265 | + RangeVar *relvar; |
| 1266 | + |
| 1267 | + /* Do case conversion and word separation */ |
| 1268 | + /* We convert %rowtype to .rowtype momentarily to keep converter happy */ |
| 1269 | + i = strlen(word) - ROWTYPE_JUNK_LEN; |
| 1270 | + Assert(word[i] == '%'); |
| 1271 | + |
| 1272 | + cp = (char *) palloc((i + 1) * sizeof(char)); |
| 1273 | + memset(cp, 0, (i + 1) * sizeof(char)); |
| 1274 | + memcpy(cp, word, i * sizeof(char)); |
| 1275 | + |
| 1276 | + /* Lookup the relation */ |
| 1277 | + relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, "plpgsql_parse_dblwordtype")); |
| 1278 | + classOid = RangeVarGetRelid(relvar, true); |
| 1279 | + if (!OidIsValid(classOid)) |
| 1280 | + elog(ERROR, "%s: no such class", cp); |
| 1281 | + |
| 1282 | + /* |
| 1283 | + * Build and return the complete row definition |
| 1284 | + */ |
| 1285 | + plpgsql_yylval.row = build_rowtype(classOid); |
| 1286 | + |
| 1287 | + pfree(cp); |
| 1288 | + |
| 1289 | + return T_ROW; |
| 1290 | +} |
| 1291 | + |
1132 | 1292 | /*
|
1133 | 1293 | * Build a rowtype data structure given the pg_class OID.
|
1134 | 1294 | */
|
|
0 commit comments