diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index d61822e6c0c384bd557d6ee47121aacd2637adec..19ddc001899da3a5c0d29f5630602d72ebfa5ef8 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -105,8 +105,8 @@ static Oid AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, - char new_array_type, - Oid ownerid); + Oid ownerid, + Oid new_array_type); static void RelationRemoveInheritance(Oid relid); static Oid StoreRelCheck(Relation rel, char *ccname, char *ccbin, Oid conoid); static Node* cookConstraint (ParseState *pstate, @@ -533,18 +533,17 @@ CheckAttributeType(const char *attname, Oid atttypid) if (Gp_role != GP_ROLE_EXECUTE) { - /* - * Warn user, but don't fail, if column to be created has UNKNOWN type - * (usually as a result of a 'retrieve into' - jolly) - * - * Refuse any attempt to create a pseudo-type column. - */ - if (atttypid == UNKNOWNOID) + { + /* + * Warn user, but don't fail, if column to be created has UNKNOWN type + * (usually as a result of a 'retrieve into' - jolly) + */ ereport(WARNING, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" has type \"unknown\"", attname), errdetail("Proceeding with relation creation anyway."))); + } else if (att_typtype == TYPTYPE_PSEUDO) { /* @@ -580,6 +579,7 @@ CheckAttributeType(const char *attname, Oid atttypid) continue; CheckAttributeType(NameStr(attr->attname), attr->atttypid); } + relation_close(relation, AccessShareLock); } } @@ -1151,8 +1151,8 @@ AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, - char new_array_type, - Oid ownerid) + Oid ownerid, + Oid new_array_type) { return TypeCreate(typeName, /* type name */ @@ -1372,7 +1372,7 @@ heap_create_with_catalog(const char *relname, Relation gp_relation_node_desc; Relation new_rel_desc; Oid new_type_oid; - Oid new_array_oid = InvalidOid; + Oid new_array_oid = InvalidOid; bool appendOnlyRel; StdRdOptions *stdRdOptions; int safefswritesize = gp_safefswritesize; @@ -1381,7 +1381,7 @@ heap_create_with_catalog(const char *relname, { new_array_oid = *comptypeArrayOid; } - + pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); if (!IsBootstrapProcessingMode()) @@ -1506,7 +1506,7 @@ heap_create_with_catalog(const char *relname, } /* - * since defining a relation also defines a complex type, we add a new + * Since defining a relation also defines a complex type, we add a new * system type corresponding to the new relation. * * NOTE: we could get a unique-index failure here, in case the same name @@ -1527,8 +1527,8 @@ heap_create_with_catalog(const char *relname, relnamespace, relid, relkind, - new_array_oid, - ownerid); + ownerid, + new_array_oid); else { new_type_oid = TypeCreateWithOid( @@ -1573,37 +1573,39 @@ heap_create_with_catalog(const char *relname, if (OidIsValid(new_array_oid)) { char *relarrayname; + relarrayname = makeArrayTypeName(relname, relnamespace); + TypeCreateWithOid( relarrayname, /* type name */ relnamespace, /* type namespace */ - InvalidOid, /* relation oid */ - 0, /* relation kind */ - ownerid, - -1, /* internal size (varlena) */ - TYPTYPE_BASE, /* type-type (complex) */ - DEFAULT_TYPDELIM, /* default array delimiter */ - F_ARRAY_IN, /* input procedure */ - F_ARRAY_OUT, /* output procedure */ - F_ARRAY_RECV, /* receive procedure */ - F_ARRAY_SEND, /* send procedure */ - InvalidOid, /* typmodin procedure */ - InvalidOid, /* typmodout procedure */ - InvalidOid, /* analyze procedure - default */ - new_type_oid, /* array element type - irrelevant */ - true, /* this is not an array type */ - InvalidOid, /* array type if any */ - InvalidOid, /* domain base type - irrelevant */ - NULL, /* default value - none */ - NULL, /* default binary representation */ - false, /* passed by reference */ - 'd', /* alignment - must be the largest! */ - 'x', /* fully TOASTable */ - -1, /* typmod */ - 0, /* array dimensions for typBaseType */ - false, /* Type NOT NULL */ - new_array_oid, - 0); + InvalidOid, /* relation oid */ + 0, /* relation kind */ + ownerid, + -1, /* internal size (varlena) */ + TYPTYPE_BASE, /* type-type (complex) */ + DEFAULT_TYPDELIM, /* default array delimiter */ + F_ARRAY_IN, /* input procedure */ + F_ARRAY_OUT, /* output procedure */ + F_ARRAY_RECV, /* receive procedure */ + F_ARRAY_SEND, /* send procedure */ + InvalidOid, /* typmodin procedure */ + InvalidOid, /* typmodout procedure */ + InvalidOid, /* analyze procedure - default */ + new_type_oid, /* array element type - irrelevant */ + true, /* this is not an array type */ + InvalidOid, /* array type if any */ + InvalidOid, /* domain base type - irrelevant */ + NULL, /* default value - none */ + NULL, /* default binary representation */ + false, /* passed by reference */ + 'd', /* alignment - must be the largest! */ + 'x', /* fully TOASTable */ + -1, /* typmod */ + 0, /* array dimensions for typBaseType */ + false, /* Type NOT NULL */ + new_array_oid, + 0); if (PointerIsValid(comptypeArrayOid)) { diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index bbd9a8b95fda950355f89d12aa3259233630e643..0ed09197451f2e2f2e5d5eb3407d8be8118a6b92 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -297,9 +297,9 @@ TypeCreateWithOid(const char *typeName, values[i++] = CharGetDatum(typeType); /* typtype */ values[i++] = BoolGetDatum(true); /* typisdefined */ values[i++] = CharGetDatum(typDelim); /* typdelim */ - values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */ + values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */ values[i++] = ObjectIdGetDatum(elementType); /* typelem */ - values[i++] = ObjectIdGetDatum(arrayType); /* typarray */ + values[i++] = ObjectIdGetDatum(arrayType); /* typarray */ values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */ values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */ values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */ @@ -477,28 +477,28 @@ Oid TypeCreate(const char *typeName, ownerId, internalSize, typeType, - typDelim, - inputProcedure, - outputProcedure, - receiveProcedure, - sendProcedure, - typmodinProcedure, - typmodoutProcedure, - analyzeProcedure, - elementType, + typDelim, + inputProcedure, + outputProcedure, + receiveProcedure, + sendProcedure, + typmodinProcedure, + typmodoutProcedure, + analyzeProcedure, + elementType, isImplicitArray, arrayType, - baseType, - defaultTypeValue, - defaultTypeBin, - passedByValue, - alignment, - storage, - typeMod, - typNDims, - typeNotNull, - InvalidOid, - 0); + baseType, + defaultTypeValue, + defaultTypeBin, + passedByValue, + alignment, + storage, + typeMod, + typNDims, + typeNotNull, + InvalidOid, + 0); } /* @@ -540,8 +540,14 @@ GenerateTypeDependencies(Oid typeNamespace, myself.objectId = typeObjectId; myself.objectSubId = 0; - /* dependency on namespace */ - /* skip for relation rowtype, since we have indirect dependency */ + /* + * Make dependency on namespace and shared dependency on owner. + * + * For a relation rowtype (that's not a composite type), we should skip + * these because we'll depend on them indirectly through the pg_class + * entry. Likewise, skip for implicit arrays since we'll depend on them + * through the element type. + */ if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) && !isImplicitArray) { @@ -632,17 +638,17 @@ GenerateTypeDependencies(Oid typeNamespace, } /* - * If the type is an array type, mark it auto-dependent on the base type. - * (This is a compromise between the typical case where the array type is - * automatically generated and the case where it is manually created: we'd - * prefer INTERNAL for the former case and NORMAL for the latter.) + * If the type is an implicitly-created array type, mark it as internally + * dependent on the element type. Otherwise, if it has an element type, + * the dependency is a normal one. */ if (OidIsValid(elementType)) { referenced.classId = TypeRelationId; referenced.objectId = elementType; referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + recordDependencyOn(&myself, &referenced, + isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL); } /* Normal dependency from a domain to its base type. */ @@ -657,7 +663,6 @@ GenerateTypeDependencies(Oid typeNamespace, /* Normal dependency on the default expression. */ if (defaultExpr) recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL); - } /* @@ -732,10 +737,14 @@ makeArrayTypeName(const char *typeName, Oid typeNamespace) int i; Relation pg_type_desc; - if (!typeName) - return NULL; + /* + * The idea is to prepend underscores as needed until we make a name that + * doesn't collide with anything... + */ arr = (char*)palloc(NAMEDATALEN); + pg_type_desc = heap_open(TypeRelationId, AccessShareLock); + for (i = 1; i < NAMEDATALEN - 1; i++) { arr[i - 1] = '_'; @@ -747,7 +756,9 @@ makeArrayTypeName(const char *typeName, Oid typeNamespace) 0, 0)) break; } + heap_close(pg_type_desc, AccessShareLock); + if (i >= NAMEDATALEN-1) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 4b7c1e156a45beccc45e85bc126a03cbbd67c9e4..f8b71b58dadc86cbeaf40a47fac4a266f14e04fb 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -144,16 +144,6 @@ DefineType(List *names, List *parameters, Oid newOid, Oid shadowOid) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(typeNamespace)); - /* - * Type names must be one character shorter than other names, allowing - * room to create the corresponding array type name with prepended "_". - */ - if (strlen(typeName) > (NAMEDATALEN - 2)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("type names must be %d characters or less", - NAMEDATALEN - 2))); - /* * Look to see if type already exists (presumably as a shell; if not, * TypeCreate will complain). If it doesn't, create it as a shell, so @@ -442,6 +432,7 @@ DefineType(List *names, List *parameters, Oid newOid, Oid shadowOid) if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(analyzeName)); + /* Preassign array type OID so we can insert it in pg_type.typarray */ pg_type = heap_open(TypeRelationId, AccessShareLock); array_oid = shadowOid; @@ -504,7 +495,7 @@ DefineType(List *names, List *parameters, Oid newOid, Oid shadowOid) InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ - -1, /* internal size */ + -1, /* internal size (always varlena) */ TYPTYPE_BASE, /* type-type (base type) */ delimiter, /* array element delimiter */ F_ARRAY_IN, /* input procedure */ @@ -701,19 +692,6 @@ DefineDomain(CreateDomainStmt *stmt) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(domainNamespace)); - /* - * Domainnames, unlike typenames don't need to account for the '_' prefix. - * So they can be one character longer. (This test is presently useless - * since the parser will have truncated the name to fit. But leave it - * here since we may someday support arrays of domains, in which case - * we'll be back to needing to enforce NAMEDATALEN-2.) - */ - if (strlen(domainName) > (NAMEDATALEN - 1)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("domain names must be %d characters or less", - NAMEDATALEN - 1))); - /* * Look up the base type. */ @@ -1501,7 +1479,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) /* Rebuild dependencies */ GenerateTypeDependencies(typTup->typnamespace, domainoid, - typTup->typrelid, + InvalidOid, /* typrelid is n/a */ 0, /* relation kind is n/a */ typTup->typowner, typTup->typinput, @@ -1512,7 +1490,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) typTup->typmodout, typTup->typanalyze, typTup->typelem, - false, + false, /* a domain isn't an implicit array */ typTup->typbasetype, defaultExpr, true); /* Rebuild is true */ @@ -2372,7 +2350,7 @@ AlterTypeOwner(List *names, Oid newOwnerId) /* * If it's a composite type, we need to check that it really is a - * free-standing composite type, and not a table's underlying type. We + * free-standing composite type, and not a table's rowtype. We * want people to use ALTER TABLE not ALTER TYPE for that case. */ if (typTup->typtype == TYPTYPE_COMPOSITE && @@ -2382,6 +2360,16 @@ AlterTypeOwner(List *names, Oid newOwnerId) errmsg("\"%s\" is a table's row type", TypeNameToString(typename)))); + /* don't allow direct alteration of array types, either */ + if (OidIsValid(typTup->typelem) && + get_array_type(typTup->typelem) == typeOid) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot alter array type %s", + format_type_be(typeOid)), + errhint("You can alter type %s, which will alter the array type as well.", + format_type_be(typTup->typelem)))); + /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. @@ -2428,6 +2416,10 @@ AlterTypeOwner(List *names, Oid newOwnerId) /* Update owner dependency reference */ changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId); + + /* If it has an array type, update that too */ + if (OidIsValid(typTup->typarray)) + AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false); } } @@ -2482,6 +2474,10 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId, if (hasDependEntry) changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId); + /* If it has an array type, update that too */ + if (OidIsValid(typTup->typarray)) + AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false); + /* Clean up */ heap_close(rel, RowExclusiveLock); } @@ -2495,6 +2491,7 @@ AlterTypeNamespace(List *names, const char *newschema) TypeName *typename; Oid typeOid; Oid nspOid; + Oid elemOid; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); @@ -2508,6 +2505,16 @@ AlterTypeNamespace(List *names, const char *newschema) /* get schema OID and check its permissions */ nspOid = LookupCreationNamespace(newschema); + /* don't allow direct alteration of array types */ + elemOid = get_element_type(typeOid); + if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot alter array type %s", + format_type_be(typeOid)), + errhint("You can alter type %s, which will alter the array type as well.", + format_type_be(elemOid)))); + /* and do the work */ AlterTypeNamespaceInternal(typeOid, nspOid, false, true); } @@ -2517,6 +2524,10 @@ AlterTypeNamespace(List *names, const char *newschema) * * Caller must have already checked privileges. * + * The function automatically recurses to process the type's array type, + * if any. isImplicitArray should be TRUE only when doing this internal + * recursion (outside callers must never try to move an array type directly). + * * If errorOnTableType is TRUE, the function errors out if the type is * a table type. ALTER TABLE has to be used to move a table to a new * namespace. @@ -2661,6 +2672,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, heap_freetuple(tup); heap_close(rel, RowExclusiveLock); + /* Recursively alter the associated array type, if any */ if (OidIsValid(arrayOid)) AlterTypeNamespaceInternal(arrayOid, nspOid, true, true); diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 378ada1d248b338784a3a304561679e1d3b10b77..8a72239e9bdcb63a8d3d1aafd4f8c9b75394ef69 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -2927,7 +2927,7 @@ get_element_type(Oid typid) /* * get_array_type * - * Given the type OID, get the corresponding "true" array type. + * Given the type OID, get the corresponding "true" array type. * Returns InvalidOid if no array type can be found. * */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 8c2455bc5e42e7e3f6e544dd2bf083c570116af1..29f97c1ac1bb605be083a1e7f4613dcbeee2dca9 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -1181,9 +1181,8 @@ selectDumpableType(TypeInfo *tinfo) else if (!tinfo->isDefined) tinfo->dobj.dump = false; - /* skip all array types that start w/ underscore */ - else if ((tinfo->dobj.name[0] == '_') && - OidIsValid(tinfo->typelem)) + /* skip auto-generated array types */ + else if (tinfo->isArray) tinfo->dobj.dump = false; else @@ -2065,6 +2064,7 @@ getTypes(int *numTypes) int i_typrelkind; int i_typtype; int i_typisdefined; + int i_isarray; /* * we include even the built-in types because those may be used as array @@ -2072,7 +2072,14 @@ getTypes(int *numTypes) * * we filter out the built-in types when we dump out the types * - * same approach for undefined (shell) types + * same approach for undefined (shell) types and array types + * + * Note: as of 8.3 we can reliably detect whether a type is an + * auto-generated array type by checking the element type's typarray. + * (Before that the test is capable of generating false positives.) We + * still check for name beginning with '_', though, so as to avoid the + * cost of the subselect probe for all standard types. This would have to + * be revisited if the backend ever allows renaming of array types. */ /* Make sure we are in proper schema */ @@ -2085,7 +2092,9 @@ getTypes(int *numTypes) "typoutput::oid as typoutput, typelem, typrelid, " "CASE WHEN typrelid = 0 THEN ' '::\"char\" " "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, " - "typtype, typisdefined " + "typtype, typisdefined, " + "typname[0] = '_' AND typelem != 0 AND " + "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray " "FROM pg_type", username_subquery); @@ -2108,6 +2117,7 @@ getTypes(int *numTypes) i_typrelkind = PQfnumber(res, "typrelkind"); i_typtype = PQfnumber(res, "typtype"); i_typisdefined = PQfnumber(res, "typisdefined"); + i_isarray = PQfnumber(res, "isarray"); for (i = 0; i < ntups; i++) { @@ -2135,20 +2145,16 @@ getTypes(int *numTypes) tinfo[i].typrelkind != RELKIND_COMPOSITE_TYPE) tinfo[i].dobj.objType = DO_TABLE_TYPE; - /* - * check for user-defined array types, omit system generated ones - */ - if (OidIsValid(tinfo[i].typelem) && - tinfo[i].dobj.name[0] != '_') - tinfo[i].isArray = true; - else - tinfo[i].isArray = false; - if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0) tinfo[i].isDefined = true; else tinfo[i].isDefined = false; + if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0) + tinfo[i].isArray = true; + else + tinfo[i].isArray = false; + /* Decide whether we want to dump it */ selectDumpableType(&tinfo[i]); @@ -5074,7 +5080,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBufferStr(q, typdefault); } - if (tinfo->isArray) + if (OidIsValid(tinfo->typelem)) { char *elemType; diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 0fe50b5f7781c6b01f8e061d86c80df02f525b0a..39a05272a6248a69d47245fe279da334d7615525 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -156,7 +156,7 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP /* * If there is a "true" array type having this type as element type, * typarray links to it. Zero if no associated "true" array type. - */ + */ Oid typarray; /* @@ -788,7 +788,7 @@ extern Oid TypeCreateWithOid(const char *typeName, Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, - bool isImplicitArray, + bool isImplicitArray, Oid arrayType, Oid baseType, const char *defaultTypeValue, @@ -811,8 +811,8 @@ extern void GenerateTypeDependencies(Oid typeNamespace, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, - Oid typmodinProcedure, - Oid typmodoutProcedure, + Oid typmodinProcedure, + Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, bool isImplicitArray, diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index fdd7081df345ce3474114fb226fcde54a5c4c9de..f587ea30f07b0ef21747e7116bde45a6b41257cc 100644 --- a/src/include/commands/typecmds.h +++ b/src/include/commands/typecmds.h @@ -40,7 +40,7 @@ extern void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId, extern void AlterTypeNamespace(List *names, const char *newschema); extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, - bool errorOnTableType); + bool errorOnTableType); extern void AlterType(AlterTypeStmt *stmt); extern void AlterType(AlterTypeStmt *stmt); diff --git a/src/test/regress/expected/information_schema.out b/src/test/regress/expected/information_schema.out index f8feedca2361232689b96aca3ac096c107745112..e8b120189136abb7cbec7b424df5dacc731b4257 100644 --- a/src/test/regress/expected/information_schema.out +++ b/src/test/regress/expected/information_schema.out @@ -85,7 +85,7 @@ where ordinal_position = 20; pg_catalog | pg_statistic | stavalues3 | 20 pg_catalog | pg_partitions | parenttablespace | 20 information_schema | attributes | datetime_precision | 20 - pg_catalog | pg_type | typstorage | 20 + pg_catalog | pg_type | typstorage | 20 pg_catalog | pg_proc | proargnames | 20 pg_catalog | pg_class | reltriggers | 20 pg_catalog | pg_am | ambuild | 20 diff --git a/src/test/regress/expected/information_schema_optimizer.out b/src/test/regress/expected/information_schema_optimizer.out index 0073eb1d4f9acd83a1e3ddd769deb10e7586831f..d5a32ea71e27650cb04f5996c133bc840d992351 100644 --- a/src/test/regress/expected/information_schema_optimizer.out +++ b/src/test/regress/expected/information_schema_optimizer.out @@ -85,7 +85,7 @@ where ordinal_position = 20; pg_catalog | pg_statistic | stavalues3 | 20 pg_catalog | pg_partitions | parenttablespace | 20 information_schema | attributes | datetime_precision | 20 - pg_catalog | pg_type | typstorage | 20 + pg_catalog | pg_type | typstorage | 20 pg_catalog | pg_proc | proargnames | 20 pg_catalog | pg_class | reltriggers | 20 pg_catalog | pg_am | ambuild | 20 diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 2118a181ecfa5bf4698ad8fe2d5173680bd9da99..f77d89e96b8cb1442e12f9984e9ed9ab1c44608e 100755 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -721,6 +721,14 @@ WHERE typelem != 0 AND ------+--------- (0 rows) +SELECT ctid, typarray +FROM pg_catalog.pg_type fk +WHERE typarray != 0 AND + NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray); + ctid | typarray +------+---------- +(0 rows) + SELECT ctid, typinput FROM pg_catalog.pg_type fk WHERE typinput != 0 AND diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index e53bf08f420a0980238e10e892c5375f514af534..ba6440fc5f99f1b3b583213e1b871ffb0e89038e 100755 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -117,6 +117,16 @@ ORDER BY 1; 30 | oidvector | 54 | oidvectorin (2 rows) +-- Make sure typarray points to a varlena array type of our own base +SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype, + p2.typelem, p2.typlen +FROM pg_type p1 LEFT JOIN pg_type p2 ON (p1.typarray = p2.oid) +WHERE p1.typarray <> 0 AND + (p2.oid IS NULL OR p2.typelem <> p1.oid OR p2.typlen <> -1); + oid | basetype | arraytype | typelem | typlen +-----+----------+-----------+---------+-------- +(0 rows) + -- Check for bogus typoutput routines -- As of 8.0, this check finds refcursor, which is borrowing -- other types' I/O routines diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql index 5eb440f0f541bab854295d7524fc93bb1c25281f..0f875079c454b9c9cc977f93afb8a9be4046c4d8 100644 --- a/src/test/regress/sql/oidjoins.sql +++ b/src/test/regress/sql/oidjoins.sql @@ -361,6 +361,10 @@ SELECT ctid, typelem FROM pg_catalog.pg_type fk WHERE typelem != 0 AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem); +SELECT ctid, typarray +FROM pg_catalog.pg_type fk +WHERE typarray != 0 AND + NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray); SELECT ctid, typinput FROM pg_catalog.pg_type fk WHERE typinput != 0 AND diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 7cabe9dee37c36581a818b26563b0688bba71e8f..1b6eaab9ded74e42701414511f5bfc4d0baac767 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -94,6 +94,13 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND (p2.oid = 'array_in'::regproc) ORDER BY 1; +-- Make sure typarray points to a varlena array type of our own base +SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype, + p2.typelem, p2.typlen +FROM pg_type p1 LEFT JOIN pg_type p2 ON (p1.typarray = p2.oid) +WHERE p1.typarray <> 0 AND + (p2.oid IS NULL OR p2.typelem <> p1.oid OR p2.typlen <> -1); + -- Check for bogus typoutput routines -- As of 8.0, this check finds refcursor, which is borrowing