--- sql/pgtap.sql.saf 2012-09-10 17:04:49.000000000 -0700 +++ sql/pgtap.sql 2012-09-10 17:05:13.000000000 -0700 @@ -5,6 +5,59 @@ -- -- http://pgtap.org/ +-- Cast booleans to text like 8.3 does. +CREATE OR REPLACE FUNCTION booltext(boolean) +RETURNS text AS 'SELECT CASE WHEN $1 then ''true'' ELSE ''false'' END;' +LANGUAGE sql IMMUTABLE STRICT; + +CREATE CAST (boolean AS text) WITH FUNCTION booltext(boolean) AS ASSIGNMENT; + +-- Cast text[]s to text like 8.3 does. +CREATE OR REPLACE FUNCTION textarray_text(text[]) +RETURNS TEXT AS 'SELECT textin(array_out($1));' +LANGUAGE sql IMMUTABLE STRICT; + +CREATE CAST (text[] AS text) WITH FUNCTION textarray_text(text[]) AS ASSIGNMENT; + +-- Cast name[]s to text like 8.3 does. +CREATE OR REPLACE FUNCTION namearray_text(name[]) +RETURNS TEXT AS 'SELECT textin(array_out($1));' +LANGUAGE sql IMMUTABLE STRICT; + +CREATE CAST (name[] AS text) WITH FUNCTION namearray_text(name[]) AS ASSIGNMENT; + +-- Compare name[]s more or less like 8.3 does. +CREATE OR REPLACE FUNCTION namearray_eq( name[], name[] ) +RETURNS bool +AS 'SELECT $1::text = $2::text;' +LANGUAGE sql IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = name[], + RIGHTARG = name[], + NEGATOR = <>, + PROCEDURE = namearray_eq +); + +CREATE OR REPLACE FUNCTION namearray_ne( name[], name[] ) +RETURNS bool +AS 'SELECT $1::text <> $2::text;' +LANGUAGE sql IMMUTABLE STRICT; + +CREATE OPERATOR <> ( + LEFTARG = name[], + RIGHTARG = name[], + NEGATOR = =, + PROCEDURE = namearray_ne +); + +-- Cast regtypes to text like 8.3 does. +CREATE OR REPLACE FUNCTION regtypetext(regtype) +RETURNS text AS 'SELECT textin(regtypeout($1))' +LANGUAGE sql IMMUTABLE STRICT; + +CREATE CAST (regtype AS text) WITH FUNCTION regtypetext(regtype) AS ASSIGNMENT; + CREATE OR REPLACE FUNCTION pg_version() RETURNS text AS 'SELECT current_setting(''server_version'')' LANGUAGE SQL IMMUTABLE; @@ -188,11 +241,11 @@ RETURNS integer AS $$ BEGIN EXECUTE 'INSERT INTO __tresults__ ( ok, aok, descr, type, reason ) - VALUES( ' || $1 || ', ' - || $2 || ', ' - || quote_literal(COALESCE($3, '')) || ', ' - || quote_literal($4) || ', ' - || quote_literal($5) || ' )'; + VALUES( ' || $1::text || ', ' + || $2::text || ', ' + || quote_literal(COALESCE($3, '')::text) || ', ' + || quote_literal($4::text) || ', ' + || quote_literal($5::text) || ' )'; RETURN currval('__tresults___numb_seq'); END; $$ LANGUAGE plpgsql; @@ -267,21 +320,6 @@ ); $$ LANGUAGE sql strict; -CREATE OR REPLACE FUNCTION diag ( msg anyelement ) -RETURNS TEXT AS $$ - SELECT diag($1::text); -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION diag( VARIADIC text[] ) -RETURNS TEXT AS $$ - SELECT diag(array_to_string($1, '')); -$$ LANGUAGE sql; - -CREATE OR REPLACE FUNCTION diag( VARIADIC anyarray ) -RETURNS TEXT AS $$ - SELECT diag(array_to_string($1, '')); -$$ LANGUAGE sql; - CREATE OR REPLACE FUNCTION ok ( boolean, text ) RETURNS TEXT AS $$ DECLARE @@ -494,9 +532,9 @@ output TEXT; BEGIN EXECUTE 'SELECT ' || - COALESCE(quote_literal( have ), 'NULL') || '::' || pg_typeof(have) || ' ' + COALESCE(quote_literal( have ), 'NULL') || '::' || pg_typeof(have)::text || ' ' || op || ' ' || - COALESCE(quote_literal( want ), 'NULL') || '::' || pg_typeof(want) + COALESCE(quote_literal( want ), 'NULL') || '::' || pg_typeof(want)::text INTO result; output := ok( COALESCE(result, FALSE), descr ); RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag( @@ -1100,7 +1138,7 @@ SELECT COALESCE(substring( pg_catalog.format_type($1, $2), '(("(?!")([^"]|"")+"|[^.]+)([(][^)]+[)])?)$' - ), '') + ) || CASE WHEN $2 IS NULL OR $2 < 0 OR pg_catalog.format_type($1, $2) LIKE '%)' THEN '' ELSE '(' || $2 || ')' END, '') $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION display_type ( NAME, OID, INTEGER ) @@ -2191,7 +2229,7 @@ p.proname AS name, array_to_string(p.proargtypes::regtype[], ',') AS args, CASE p.proretset WHEN TRUE THEN 'setof ' ELSE '' END - || p.prorettype::regtype AS returns, + || p.prorettype::regtype::text AS returns, p.prolang AS langoid, p.proisstrict AS is_strict, p.proisagg AS is_agg, @@ -3409,63 +3447,6 @@ SELECT ok( NOT _has_type( $1, ARRAY['e'] ), ('Enum ' || quote_ident($1) || ' should not exist')::text ); $$ LANGUAGE sql; --- enum_has_labels( schema, enum, labels, description ) -CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT is( - ARRAY( - SELECT e.enumlabel - FROM pg_catalog.pg_type t - JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid - JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid - WHERE t.typisdefined - AND n.nspname = $1 - AND t.typname = $2 - AND t.typtype = 'e' - ORDER BY e.oid - ), - $3, - $4 - ); -$$ LANGUAGE sql; - --- enum_has_labels( schema, enum, labels ) -CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT enum_has_labels( - $1, $2, $3, - 'Enum ' || quote_ident($1) || '.' || quote_ident($2) || ' should have labels (' || array_to_string( $3, ', ' ) || ')' - ); -$$ LANGUAGE sql; - --- enum_has_labels( enum, labels, description ) -CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT is( - ARRAY( - SELECT e.enumlabel - FROM pg_catalog.pg_type t - JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid - WHERE t.typisdefined - AND pg_catalog.pg_type_is_visible(t.oid) - AND t.typname = $1 - AND t.typtype = 'e' - ORDER BY e.oid - ), - $2, - $3 - ); -$$ LANGUAGE sql; - --- enum_has_labels( enum, labels ) -CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT enum_has_labels( - $1, $2, - 'Enum ' || quote_ident($1) || ' should have labels (' || array_to_string( $2, ', ' ) || ')' - ); -$$ LANGUAGE sql; - CREATE OR REPLACE FUNCTION _has_role( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( @@ -5934,13 +5915,13 @@ -- Find extra records. FOR rec in EXECUTE 'SELECT * FROM ' || have || ' EXCEPT ' || $4 || 'SELECT * FROM ' || want LOOP - extras := extras || rec::text; + extras := array_append(extras, textin(record_out(rec))); END LOOP; -- Find missing records. FOR rec in EXECUTE 'SELECT * FROM ' || want || ' EXCEPT ' || $4 || 'SELECT * FROM ' || have LOOP - missing := missing || rec::text; + missing := array_append(missing, textin(record_out(rec))); END LOOP; -- Drop the temporary tables. @@ -6164,7 +6145,7 @@ -- Find relevant records. FOR rec in EXECUTE 'SELECT * FROM ' || want || ' ' || $4 || ' SELECT * FROM ' || have LOOP - results := results || rec::text; + results := array_append(results, textin(record_out(rec))); END LOOP; -- Drop the temporary tables. @@ -6259,11 +6240,11 @@ FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP - IF have_rec::text IS DISTINCT FROM want_rec::text OR have_found <> want_found THEN + IF textin(record_out(have_rec)) IS DISTINCT FROM textin(record_out(want_rec)) OR have_found <> want_found THEN RETURN ok( false, $3 ) || E'\n' || diag( ' Results differ beginning at row ' || rownum || E':\n' || - ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || - ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END + ' have: ' || CASE WHEN have_found THEN textin(record_out(have_rec)) ELSE 'NULL' END || E'\n' || + ' want: ' || CASE WHEN want_found THEN textin(record_out(want_rec)) ELSE 'NULL' END ); END IF; rownum = rownum + 1; @@ -6278,8 +6259,8 @@ WHEN datatype_mismatch THEN RETURN ok( false, $3 ) || E'\n' || diag( E' Columns differ between queries:\n' || - ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || - ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END + ' have: ' || CASE WHEN have_found THEN textin(record_out(have_rec)) ELSE 'NULL' END || E'\n' || + ' want: ' || CASE WHEN want_found THEN textin(record_out(want_rec)) ELSE 'NULL' END ); END; $$ LANGUAGE plpgsql; @@ -6414,7 +6395,7 @@ FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP - IF have_rec::text IS DISTINCT FROM want_rec::text OR have_found <> want_found THEN + IF textin(record_out(have_rec)) IS DISTINCT FROM textin(record_out(want_rec)) OR have_found <> want_found THEN RETURN ok( true, $3 ); ELSE FETCH have INTO have_rec; @@ -6428,8 +6409,8 @@ WHEN datatype_mismatch THEN RETURN ok( false, $3 ) || E'\n' || diag( E' Columns differ between queries:\n' || - ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || - ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END + ' have: ' || CASE WHEN have_found THEN textin(record_out(have_rec)) ELSE 'NULL' END || E'\n' || + ' want: ' || CASE WHEN want_found THEN textin(record_out(want_rec)) ELSE 'NULL' END ); END; $$ LANGUAGE plpgsql; @@ -6554,9 +6535,9 @@ DECLARE typeof regtype := pg_typeof($1); BEGIN - IF typeof = $2 THEN RETURN ok(true, $3 || ' isa ' || $2 ); END IF; - RETURN ok(false, $3 || ' isa ' || $2 ) || E'\n' || - diag(' ' || $3 || ' isn''t a "' || $2 || '" it''s a "' || typeof || '"'); + IF typeof = $2 THEN RETURN ok(true, $3 || ' isa ' || $2::text ); END IF; + RETURN ok(false, $3 || ' isa ' || $2::text ) || E'\n' || + diag(' ' || $3 || ' isn''t a "' || $2::text || '" it''s a "' || typeof::text || '"'); END; $$ LANGUAGE plpgsql; @@ -6577,7 +6558,7 @@ BEGIN -- Find extra records. FOR rec in EXECUTE _query($1) LOOP - extras := extras || rec::text; + extras := extras || textin(record_out(rec)); END LOOP; -- What extra records do we have? @@ -6722,7 +6703,7 @@ t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) - AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) + AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem) AND n.nspname = $1 AND t.typtype = ANY( COALESCE($4, ARRAY['b', 'c', 'd', 'p', 'e']) ) EXCEPT @@ -6740,7 +6721,7 @@ t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) - AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) + AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem) AND n.nspname = $1 AND t.typtype = ANY( COALESCE($4, ARRAY['b', 'c', 'd', 'p', 'e']) ) ), @@ -6773,7 +6754,7 @@ t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) - AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) + AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) @@ -6792,7 +6773,7 @@ t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) - AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) + AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) @@ -7072,10 +7053,12 @@ rec RECORD; BEGIN EXECUTE _query($1) INTO rec; - IF NOT rec::text IS DISTINCT FROM $2::text THEN RETURN ok(true, $3); END IF; + IF NOT textin(record_out(rec)) IS DISTINCT FROM textin(record_out($2)) + THEN RETURN ok(true, $3); + END IF; RETURN ok(false, $3 ) || E'\n' || diag( - ' have: ' || CASE WHEN rec IS NULL THEN 'NULL' ELSE rec::text END || - E'\n want: ' || CASE WHEN $2 IS NULL THEN 'NULL' ELSE $2::text END + ' have: ' || CASE WHEN rec IS NULL THEN 'NULL' ELSE textin(record_out(rec)) END || + E'\n want: ' || CASE WHEN $2 IS NULL THEN 'NULL' ELSE textin(record_out($2)) END ); END; $$ LANGUAGE plpgsql; @@ -7220,7 +7203,7 @@ CREATE OR REPLACE FUNCTION display_oper ( NAME, OID ) RETURNS TEXT AS $$ - SELECT $1 || substring($2::regoperator::text, '[(][^)]+[)]$') + SELECT $1 || substring(textin(regoperatorout($2::regoperator)), '[(][^)]+[)]$') $$ LANGUAGE SQL; -- operators_are( schema, operators[], description ) @@ -7229,7 +7212,7 @@ SELECT _areni( 'operators', ARRAY( - SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype + SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype::text FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE n.nspname = $1 @@ -7241,7 +7224,7 @@ SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT - SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype + SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype::text FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE n.nspname = $1 @@ -7262,7 +7245,7 @@ SELECT _areni( 'operators', ARRAY( - SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype + SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype::text FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE pg_catalog.pg_operator_is_visible(o.oid) @@ -7275,7 +7258,7 @@ SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT - SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype + SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype::text FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE pg_catalog.pg_operator_is_visible(o.oid)