revoke delete on table "storage"."buckets" from "anon"; revoke insert on table "storage"."buckets" from "anon"; revoke references on table "storage"."buckets" from "anon"; revoke select on table "storage"."buckets" from "anon"; revoke trigger on table "storage"."buckets" from "anon"; revoke truncate on table "storage"."buckets" from "anon"; revoke update on table "storage"."buckets" from "anon"; revoke delete on table "storage"."buckets" from "authenticated"; revoke insert on table "storage"."buckets" from "authenticated"; revoke references on table "storage"."buckets" from "authenticated"; revoke select on table "storage"."buckets" from "authenticated"; revoke trigger on table "storage"."buckets" from "authenticated"; revoke truncate on table "storage"."buckets" from "authenticated"; revoke update on table "storage"."buckets" from "authenticated"; revoke delete on table "storage"."buckets" from "postgres"; revoke insert on table "storage"."buckets" from "postgres"; revoke references on table "storage"."buckets" from "postgres"; revoke select on table "storage"."buckets" from "postgres"; revoke trigger on table "storage"."buckets" from "postgres"; revoke truncate on table "storage"."buckets" from "postgres"; revoke update on table "storage"."buckets" from "postgres"; revoke delete on table "storage"."buckets" from "service_role"; revoke insert on table "storage"."buckets" from "service_role"; revoke references on table "storage"."buckets" from "service_role"; revoke select on table "storage"."buckets" from "service_role"; revoke trigger on table "storage"."buckets" from "service_role"; revoke truncate on table "storage"."buckets" from "service_role"; revoke update on table "storage"."buckets" from "service_role"; revoke delete on table "storage"."buckets_analytics" from "anon"; revoke insert on table "storage"."buckets_analytics" from "anon"; revoke references on table "storage"."buckets_analytics" from "anon"; revoke select on table "storage"."buckets_analytics" from "anon"; revoke trigger on table "storage"."buckets_analytics" from "anon"; revoke truncate on table "storage"."buckets_analytics" from "anon"; revoke update on table "storage"."buckets_analytics" from "anon"; revoke delete on table "storage"."buckets_analytics" from "authenticated"; revoke insert on table "storage"."buckets_analytics" from "authenticated"; revoke references on table "storage"."buckets_analytics" from "authenticated"; revoke select on table "storage"."buckets_analytics" from "authenticated"; revoke trigger on table "storage"."buckets_analytics" from "authenticated"; revoke truncate on table "storage"."buckets_analytics" from "authenticated"; revoke update on table "storage"."buckets_analytics" from "authenticated"; revoke delete on table "storage"."buckets_analytics" from "service_role"; revoke insert on table "storage"."buckets_analytics" from "service_role"; revoke references on table "storage"."buckets_analytics" from "service_role"; revoke select on table "storage"."buckets_analytics" from "service_role"; revoke trigger on table "storage"."buckets_analytics" from "service_role"; revoke truncate on table "storage"."buckets_analytics" from "service_role"; revoke update on table "storage"."buckets_analytics" from "service_role"; revoke select on table "storage"."iceberg_namespaces" from "anon"; revoke select on table "storage"."iceberg_namespaces" from "authenticated"; revoke delete on table "storage"."iceberg_namespaces" from "service_role"; revoke insert on table "storage"."iceberg_namespaces" from "service_role"; revoke references on table "storage"."iceberg_namespaces" from "service_role"; revoke select on table "storage"."iceberg_namespaces" from "service_role"; revoke trigger on table "storage"."iceberg_namespaces" from "service_role"; revoke truncate on table "storage"."iceberg_namespaces" from "service_role"; revoke update on table "storage"."iceberg_namespaces" from "service_role"; revoke select on table "storage"."iceberg_tables" from "anon"; revoke select on table "storage"."iceberg_tables" from "authenticated"; revoke delete on table "storage"."iceberg_tables" from "service_role"; revoke insert on table "storage"."iceberg_tables" from "service_role"; revoke references on table "storage"."iceberg_tables" from "service_role"; revoke select on table "storage"."iceberg_tables" from "service_role"; revoke trigger on table "storage"."iceberg_tables" from "service_role"; revoke truncate on table "storage"."iceberg_tables" from "service_role"; revoke update on table "storage"."iceberg_tables" from "service_role"; revoke delete on table "storage"."migrations" from "anon"; revoke insert on table "storage"."migrations" from "anon"; revoke references on table "storage"."migrations" from "anon"; revoke select on table "storage"."migrations" from "anon"; revoke trigger on table "storage"."migrations" from "anon"; revoke truncate on table "storage"."migrations" from "anon"; revoke update on table "storage"."migrations" from "anon"; revoke delete on table "storage"."migrations" from "authenticated"; revoke insert on table "storage"."migrations" from "authenticated"; revoke references on table "storage"."migrations" from "authenticated"; revoke select on table "storage"."migrations" from "authenticated"; revoke trigger on table "storage"."migrations" from "authenticated"; revoke truncate on table "storage"."migrations" from "authenticated"; revoke update on table "storage"."migrations" from "authenticated"; revoke delete on table "storage"."migrations" from "postgres"; revoke insert on table "storage"."migrations" from "postgres"; revoke references on table "storage"."migrations" from "postgres"; revoke select on table "storage"."migrations" from "postgres"; revoke trigger on table "storage"."migrations" from "postgres"; revoke truncate on table "storage"."migrations" from "postgres"; revoke update on table "storage"."migrations" from "postgres"; revoke delete on table "storage"."migrations" from "service_role"; revoke insert on table "storage"."migrations" from "service_role"; revoke references on table "storage"."migrations" from "service_role"; revoke select on table "storage"."migrations" from "service_role"; revoke trigger on table "storage"."migrations" from "service_role"; revoke truncate on table "storage"."migrations" from "service_role"; revoke update on table "storage"."migrations" from "service_role"; revoke delete on table "storage"."objects" from "anon"; revoke insert on table "storage"."objects" from "anon"; revoke references on table "storage"."objects" from "anon"; revoke select on table "storage"."objects" from "anon"; revoke trigger on table "storage"."objects" from "anon"; revoke truncate on table "storage"."objects" from "anon"; revoke update on table "storage"."objects" from "anon"; revoke delete on table "storage"."objects" from "authenticated"; revoke insert on table "storage"."objects" from "authenticated"; revoke references on table "storage"."objects" from "authenticated"; revoke select on table "storage"."objects" from "authenticated"; revoke trigger on table "storage"."objects" from "authenticated"; revoke truncate on table "storage"."objects" from "authenticated"; revoke update on table "storage"."objects" from "authenticated"; revoke delete on table "storage"."objects" from "postgres"; revoke insert on table "storage"."objects" from "postgres"; revoke references on table "storage"."objects" from "postgres"; revoke select on table "storage"."objects" from "postgres"; revoke trigger on table "storage"."objects" from "postgres"; revoke truncate on table "storage"."objects" from "postgres"; revoke update on table "storage"."objects" from "postgres"; revoke delete on table "storage"."objects" from "service_role"; revoke insert on table "storage"."objects" from "service_role"; revoke references on table "storage"."objects" from "service_role"; revoke select on table "storage"."objects" from "service_role"; revoke trigger on table "storage"."objects" from "service_role"; revoke truncate on table "storage"."objects" from "service_role"; revoke update on table "storage"."objects" from "service_role"; revoke delete on table "storage"."prefixes" from "anon"; revoke insert on table "storage"."prefixes" from "anon"; revoke references on table "storage"."prefixes" from "anon"; revoke select on table "storage"."prefixes" from "anon"; revoke trigger on table "storage"."prefixes" from "anon"; revoke truncate on table "storage"."prefixes" from "anon"; revoke update on table "storage"."prefixes" from "anon"; revoke delete on table "storage"."prefixes" from "authenticated"; revoke insert on table "storage"."prefixes" from "authenticated"; revoke references on table "storage"."prefixes" from "authenticated"; revoke select on table "storage"."prefixes" from "authenticated"; revoke trigger on table "storage"."prefixes" from "authenticated"; revoke truncate on table "storage"."prefixes" from "authenticated"; revoke update on table "storage"."prefixes" from "authenticated"; revoke delete on table "storage"."prefixes" from "service_role"; revoke insert on table "storage"."prefixes" from "service_role"; revoke references on table "storage"."prefixes" from "service_role"; revoke select on table "storage"."prefixes" from "service_role"; revoke trigger on table "storage"."prefixes" from "service_role"; revoke truncate on table "storage"."prefixes" from "service_role"; revoke update on table "storage"."prefixes" from "service_role"; revoke select on table "storage"."s3_multipart_uploads" from "anon"; revoke select on table "storage"."s3_multipart_uploads" from "authenticated"; revoke delete on table "storage"."s3_multipart_uploads" from "service_role"; revoke insert on table "storage"."s3_multipart_uploads" from "service_role"; revoke references on table "storage"."s3_multipart_uploads" from "service_role"; revoke select on table "storage"."s3_multipart_uploads" from "service_role"; revoke trigger on table "storage"."s3_multipart_uploads" from "service_role"; revoke truncate on table "storage"."s3_multipart_uploads" from "service_role"; revoke update on table "storage"."s3_multipart_uploads" from "service_role"; revoke select on table "storage"."s3_multipart_uploads_parts" from "anon"; revoke select on table "storage"."s3_multipart_uploads_parts" from "authenticated"; revoke delete on table "storage"."s3_multipart_uploads_parts" from "service_role"; revoke insert on table "storage"."s3_multipart_uploads_parts" from "service_role"; revoke references on table "storage"."s3_multipart_uploads_parts" from "service_role"; revoke select on table "storage"."s3_multipart_uploads_parts" from "service_role"; revoke trigger on table "storage"."s3_multipart_uploads_parts" from "service_role"; revoke truncate on table "storage"."s3_multipart_uploads_parts" from "service_role"; revoke update on table "storage"."s3_multipart_uploads_parts" from "service_role"; alter table "storage"."iceberg_namespaces" drop constraint "iceberg_namespaces_bucket_id_fkey"; alter table "storage"."iceberg_tables" drop constraint "iceberg_tables_bucket_id_fkey"; alter table "storage"."iceberg_tables" drop constraint "iceberg_tables_namespace_id_fkey"; alter table "storage"."iceberg_namespaces" drop constraint "iceberg_namespaces_pkey"; alter table "storage"."iceberg_tables" drop constraint "iceberg_tables_pkey"; drop index if exists "storage"."iceberg_namespaces_pkey"; drop index if exists "storage"."iceberg_tables_pkey"; drop index if exists "storage"."idx_iceberg_namespaces_bucket_id"; drop index if exists "storage"."idx_iceberg_tables_namespace_id"; drop table "storage"."iceberg_namespaces"; drop table "storage"."iceberg_tables"; set check_function_bodies = off; CREATE OR REPLACE FUNCTION storage.add_prefixes(_bucket_id text, _name text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $function$ DECLARE prefixes text[]; BEGIN prefixes := "storage"."get_prefixes"("_name"); IF array_length(prefixes, 1) > 0 THEN INSERT INTO storage.prefixes (name, bucket_id) SELECT UNNEST(prefixes) as name, "_bucket_id" ON CONFLICT DO NOTHING; END IF; END; $function$ ; CREATE OR REPLACE FUNCTION storage.can_insert_object(bucketid text, name text, owner uuid, metadata jsonb) RETURNS void LANGUAGE plpgsql AS $function$ BEGIN INSERT INTO "storage"."objects" ("bucket_id", "name", "owner", "metadata") VALUES (bucketid, name, owner, metadata); -- hack to rollback the successful insert RAISE sqlstate 'PT200' using message = 'ROLLBACK', detail = 'rollback successful insert'; END $function$ ; CREATE OR REPLACE FUNCTION storage.delete_prefix(_bucket_id text, _name text) RETURNS boolean LANGUAGE plpgsql SECURITY DEFINER AS $function$ BEGIN -- Check if we can delete the prefix IF EXISTS( SELECT FROM "storage"."prefixes" WHERE "prefixes"."bucket_id" = "_bucket_id" AND level = "storage"."get_level"("_name") + 1 AND "prefixes"."name" COLLATE "C" LIKE "_name" || '/%' LIMIT 1 ) OR EXISTS( SELECT FROM "storage"."objects" WHERE "objects"."bucket_id" = "_bucket_id" AND "storage"."get_level"("objects"."name") = "storage"."get_level"("_name") + 1 AND "objects"."name" COLLATE "C" LIKE "_name" || '/%' LIMIT 1 ) THEN -- There are sub-objects, skip deletion RETURN false; ELSE DELETE FROM "storage"."prefixes" WHERE "prefixes"."bucket_id" = "_bucket_id" AND level = "storage"."get_level"("_name") AND "prefixes"."name" = "_name"; RETURN true; END IF; END; $function$ ; CREATE OR REPLACE FUNCTION storage.delete_prefix_hierarchy_trigger() RETURNS trigger LANGUAGE plpgsql AS $function$ DECLARE prefix text; BEGIN prefix := "storage"."get_prefix"(OLD."name"); IF coalesce(prefix, '') != '' THEN PERFORM "storage"."delete_prefix"(OLD."bucket_id", prefix); END IF; RETURN OLD; END; $function$ ; CREATE OR REPLACE FUNCTION storage.enforce_bucket_name_length() RETURNS trigger LANGUAGE plpgsql AS $function$ begin if length(new.name) > 100 then raise exception 'bucket name "%" is too long (% characters). Max is 100.', new.name, length(new.name); end if; return new; end; $function$ ; CREATE OR REPLACE FUNCTION storage.extension(name text) RETURNS text LANGUAGE plpgsql IMMUTABLE AS $function$ DECLARE _parts text[]; _filename text; BEGIN SELECT string_to_array(name, '/') INTO _parts; SELECT _parts[array_length(_parts,1)] INTO _filename; RETURN reverse(split_part(reverse(_filename), '.', 1)); END $function$ ; CREATE OR REPLACE FUNCTION storage.filename(name text) RETURNS text LANGUAGE plpgsql AS $function$ DECLARE _parts text[]; BEGIN select string_to_array(name, '/') into _parts; return _parts[array_length(_parts,1)]; END $function$ ; CREATE OR REPLACE FUNCTION storage.foldername(name text) RETURNS text[] LANGUAGE plpgsql IMMUTABLE AS $function$ DECLARE _parts text[]; BEGIN -- Split on "/" to get path segments SELECT string_to_array(name, '/') INTO _parts; -- Return everything except the last segment RETURN _parts[1 : array_length(_parts,1) - 1]; END $function$ ; CREATE OR REPLACE FUNCTION storage.get_level(name text) RETURNS integer LANGUAGE sql IMMUTABLE STRICT AS $function$ SELECT array_length(string_to_array("name", '/'), 1); $function$ ; CREATE OR REPLACE FUNCTION storage.get_prefix(name text) RETURNS text LANGUAGE sql IMMUTABLE STRICT AS $function$ SELECT CASE WHEN strpos("name", '/') > 0 THEN regexp_replace("name", '[\/]{1}[^\/]+\/?$', '') ELSE '' END; $function$ ; CREATE OR REPLACE FUNCTION storage.get_prefixes(name text) RETURNS text[] LANGUAGE plpgsql IMMUTABLE STRICT AS $function$ DECLARE parts text[]; prefixes text[]; prefix text; BEGIN -- Split the name into parts by '/' parts := string_to_array("name", '/'); prefixes := '{}'; -- Construct the prefixes, stopping one level below the last part FOR i IN 1..array_length(parts, 1) - 1 LOOP prefix := array_to_string(parts[1:i], '/'); prefixes := array_append(prefixes, prefix); END LOOP; RETURN prefixes; END; $function$ ; CREATE OR REPLACE FUNCTION storage.get_size_by_bucket() RETURNS TABLE(size bigint, bucket_id text) LANGUAGE plpgsql STABLE AS $function$ BEGIN return query select sum((metadata->>'size')::bigint) as size, obj.bucket_id from "storage".objects as obj group by obj.bucket_id; END $function$ ; CREATE OR REPLACE FUNCTION storage.list_multipart_uploads_with_delimiter(bucket_id text, prefix_param text, delimiter_param text, max_keys integer DEFAULT 100, next_key_token text DEFAULT ''::text, next_upload_token text DEFAULT ''::text) RETURNS TABLE(key text, id text, created_at timestamp with time zone) LANGUAGE plpgsql AS $function$ BEGIN RETURN QUERY EXECUTE 'SELECT DISTINCT ON(key COLLATE "C") * from ( SELECT CASE WHEN position($2 IN substring(key from length($1) + 1)) > 0 THEN substring(key from 1 for length($1) + position($2 IN substring(key from length($1) + 1))) ELSE key END AS key, id, created_at FROM storage.s3_multipart_uploads WHERE bucket_id = $5 AND key ILIKE $1 || ''%'' AND CASE WHEN $4 != '''' AND $6 = '''' THEN CASE WHEN position($2 IN substring(key from length($1) + 1)) > 0 THEN substring(key from 1 for length($1) + position($2 IN substring(key from length($1) + 1))) COLLATE "C" > $4 ELSE key COLLATE "C" > $4 END ELSE true END AND CASE WHEN $6 != '''' THEN id COLLATE "C" > $6 ELSE true END ORDER BY key COLLATE "C" ASC, created_at ASC) as e order by key COLLATE "C" LIMIT $3' USING prefix_param, delimiter_param, max_keys, next_key_token, bucket_id, next_upload_token; END; $function$ ; CREATE OR REPLACE FUNCTION storage.list_objects_with_delimiter(bucket_id text, prefix_param text, delimiter_param text, max_keys integer DEFAULT 100, start_after text DEFAULT ''::text, next_token text DEFAULT ''::text) RETURNS TABLE(name text, id uuid, metadata jsonb, updated_at timestamp with time zone) LANGUAGE plpgsql AS $function$ BEGIN RETURN QUERY EXECUTE 'SELECT DISTINCT ON(name COLLATE "C") * from ( SELECT CASE WHEN position($2 IN substring(name from length($1) + 1)) > 0 THEN substring(name from 1 for length($1) + position($2 IN substring(name from length($1) + 1))) ELSE name END AS name, id, metadata, updated_at FROM storage.objects WHERE bucket_id = $5 AND name ILIKE $1 || ''%'' AND CASE WHEN $6 != '''' THEN name COLLATE "C" > $6 ELSE true END AND CASE WHEN $4 != '''' THEN CASE WHEN position($2 IN substring(name from length($1) + 1)) > 0 THEN substring(name from 1 for length($1) + position($2 IN substring(name from length($1) + 1))) COLLATE "C" > $4 ELSE name COLLATE "C" > $4 END ELSE true END ORDER BY name COLLATE "C" ASC) as e order by name COLLATE "C" LIMIT $3' USING prefix_param, delimiter_param, max_keys, next_token, bucket_id, start_after; END; $function$ ; CREATE OR REPLACE FUNCTION storage.objects_insert_prefix_trigger() RETURNS trigger LANGUAGE plpgsql AS $function$ BEGIN PERFORM "storage"."add_prefixes"(NEW."bucket_id", NEW."name"); NEW.level := "storage"."get_level"(NEW."name"); RETURN NEW; END; $function$ ; CREATE OR REPLACE FUNCTION storage.objects_update_prefix_trigger() RETURNS trigger LANGUAGE plpgsql AS $function$ DECLARE old_prefixes TEXT[]; BEGIN -- Ensure this is an update operation and the name has changed IF TG_OP = 'UPDATE' AND (NEW."name" <> OLD."name" OR NEW."bucket_id" <> OLD."bucket_id") THEN -- Retrieve old prefixes old_prefixes := "storage"."get_prefixes"(OLD."name"); -- Remove old prefixes that are only used by this object WITH all_prefixes as ( SELECT unnest(old_prefixes) as prefix ), can_delete_prefixes as ( SELECT prefix FROM all_prefixes WHERE NOT EXISTS ( SELECT 1 FROM "storage"."objects" WHERE "bucket_id" = OLD."bucket_id" AND "name" <> OLD."name" AND "name" LIKE (prefix || '%') ) ) DELETE FROM "storage"."prefixes" WHERE name IN (SELECT prefix FROM can_delete_prefixes); -- Add new prefixes PERFORM "storage"."add_prefixes"(NEW."bucket_id", NEW."name"); END IF; -- Set the new level NEW."level" := "storage"."get_level"(NEW."name"); RETURN NEW; END; $function$ ; CREATE OR REPLACE FUNCTION storage.operation() RETURNS text LANGUAGE plpgsql STABLE AS $function$ BEGIN RETURN current_setting('storage.operation', true); END; $function$ ; CREATE OR REPLACE FUNCTION storage.prefixes_insert_trigger() RETURNS trigger LANGUAGE plpgsql AS $function$ BEGIN PERFORM "storage"."add_prefixes"(NEW."bucket_id", NEW."name"); RETURN NEW; END; $function$ ; CREATE OR REPLACE FUNCTION storage.search(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0, search text DEFAULT ''::text, sortcolumn text DEFAULT 'name'::text, sortorder text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql AS $function$ declare can_bypass_rls BOOLEAN; begin SELECT rolbypassrls INTO can_bypass_rls FROM pg_roles WHERE rolname = coalesce(nullif(current_setting('role', true), 'none'), current_user); IF can_bypass_rls THEN RETURN QUERY SELECT * FROM storage.search_v1_optimised(prefix, bucketname, limits, levels, offsets, search, sortcolumn, sortorder); ELSE RETURN QUERY SELECT * FROM storage.search_legacy_v1(prefix, bucketname, limits, levels, offsets, search, sortcolumn, sortorder); END IF; end; $function$ ; CREATE OR REPLACE FUNCTION storage.search_legacy_v1(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0, search text DEFAULT ''::text, sortcolumn text DEFAULT 'name'::text, sortorder text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql STABLE AS $function$ declare v_order_by text; v_sort_order text; begin case when sortcolumn = 'name' then v_order_by = 'name'; when sortcolumn = 'updated_at' then v_order_by = 'updated_at'; when sortcolumn = 'created_at' then v_order_by = 'created_at'; when sortcolumn = 'last_accessed_at' then v_order_by = 'last_accessed_at'; else v_order_by = 'name'; end case; case when sortorder = 'asc' then v_sort_order = 'asc'; when sortorder = 'desc' then v_sort_order = 'desc'; else v_sort_order = 'asc'; end case; v_order_by = v_order_by || ' ' || v_sort_order; return query execute 'with folders as ( select path_tokens[$1] as folder from storage.objects where objects.name ilike $2 || $3 || ''%'' and bucket_id = $4 and array_length(objects.path_tokens, 1) <> $1 group by folder order by folder ' || v_sort_order || ' ) (select folder as "name", null as id, null as updated_at, null as created_at, null as last_accessed_at, null as metadata from folders) union all (select path_tokens[$1] as "name", id, updated_at, created_at, last_accessed_at, metadata from storage.objects where objects.name ilike $2 || $3 || ''%'' and bucket_id = $4 and array_length(objects.path_tokens, 1) = $1 order by ' || v_order_by || ') limit $5 offset $6' using levels, prefix, search, bucketname, limits, offsets; end; $function$ ; CREATE OR REPLACE FUNCTION storage.search_v1_optimised(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0, search text DEFAULT ''::text, sortcolumn text DEFAULT 'name'::text, sortorder text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql STABLE AS $function$ declare v_order_by text; v_sort_order text; begin case when sortcolumn = 'name' then v_order_by = 'name'; when sortcolumn = 'updated_at' then v_order_by = 'updated_at'; when sortcolumn = 'created_at' then v_order_by = 'created_at'; when sortcolumn = 'last_accessed_at' then v_order_by = 'last_accessed_at'; else v_order_by = 'name'; end case; case when sortorder = 'asc' then v_sort_order = 'asc'; when sortorder = 'desc' then v_sort_order = 'desc'; else v_sort_order = 'asc'; end case; v_order_by = v_order_by || ' ' || v_sort_order; return query execute 'with folders as ( select (string_to_array(name, ''/''))[level] as name from storage.prefixes where lower(prefixes.name) like lower($2 || $3) || ''%'' and bucket_id = $4 and level = $1 order by name ' || v_sort_order || ' ) (select name, null as id, null as updated_at, null as created_at, null as last_accessed_at, null as metadata from folders) union all (select path_tokens[level] as "name", id, updated_at, created_at, last_accessed_at, metadata from storage.objects where lower(objects.name) like lower($2 || $3) || ''%'' and bucket_id = $4 and level = $1 order by ' || v_order_by || ') limit $5 offset $6' using levels, prefix, search, bucketname, limits, offsets; end; $function$ ; CREATE OR REPLACE FUNCTION storage.search_v2(prefix text, bucket_name text, limits integer DEFAULT 100, levels integer DEFAULT 1, start_after text DEFAULT ''::text) RETURNS TABLE(key text, name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql STABLE AS $function$ BEGIN RETURN query EXECUTE $sql$ SELECT * FROM ( ( SELECT split_part(name, '/', $4) AS key, name || '/' AS name, NULL::uuid AS id, NULL::timestamptz AS updated_at, NULL::timestamptz AS created_at, NULL::jsonb AS metadata FROM storage.prefixes WHERE name COLLATE "C" LIKE $1 || '%' AND bucket_id = $2 AND level = $4 AND name COLLATE "C" > $5 ORDER BY prefixes.name COLLATE "C" LIMIT $3 ) UNION ALL (SELECT split_part(name, '/', $4) AS key, name, id, updated_at, created_at, metadata FROM storage.objects WHERE name COLLATE "C" LIKE $1 || '%' AND bucket_id = $2 AND level = $4 AND name COLLATE "C" > $5 ORDER BY name COLLATE "C" LIMIT $3) ) obj ORDER BY name COLLATE "C" LIMIT $3; $sql$ USING prefix, bucket_name, limits, levels, start_after; END; $function$ ; CREATE OR REPLACE FUNCTION storage.update_updated_at_column() RETURNS trigger LANGUAGE plpgsql AS $function$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $function$ ; create policy "Authenticated can upload an avatar." on "storage"."objects" as permissive for insert to authenticated with check ((bucket_id = 'avatars'::text)); create policy "Authenticated users can upload objects 1ezt35i_0" on "storage"."objects" as permissive for insert to authenticated with check ((bucket_id = 'horses'::text)); create policy "Avatar images are publicly accessible." on "storage"."objects" as permissive for select to public using ((bucket_id = 'avatars'::text)); create policy "Enable insert for authenticated users only" on "storage"."objects" as permissive for delete to authenticated using (true); create policy "Horses images are publicly accessible 1ezt35i_0" on "storage"."objects" as permissive for select to public using ((bucket_id = 'horses'::text));