mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Skip using count estimate function for retrieving row counts if in read only context (#47761)
## Context Currently when retrieving row counts of a table in the Table Editor, we're using a `COUNT_ESTIMATE` pg function ([ref](https://github.com/supabase/supabase/blob/master/packages/pg-meta/src/sql/studio/database/get-count-estimate.ts#L5)) to retrieve an estimate (instead of checking `pg_class` -> `reltuples`) as that would theoretically provide a more accurate representation. However, in a read only context, that function can't be used - users will run into `cannot execute CREATE FUNCTION in a read-only transaction`, so we need to fallback to just checking `pg_class` in this scenario. The logic's already set up as we were previously looking into allowing users to use a read replica to power the dashboard, but we also need to consider members with read-only roles within the organization, so this PR updates the logic a little to factor that in. ## To test - [ ] With a read-only role, open the table editor and verify that we're not using the count estimate function to retrieve the table row counts <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Updated the invite member dialog to open in a larger size for better usability. * **Bug Fixes** * Improved table row count behavior so it now respects read-only access and permission limits more reliably. * Count estimates should now be shown more consistently across different database contexts. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
644fe0821b
commit
f34fdd6c8f
3 files changed
+15
-8
No files matched your search
@@ -280,7 +280,7 @@ export const InviteMemberButton = () => {
|
||||
</ButtonTooltip>
|
||||
</Shortcut>
|
||||
</SheetTrigger>
|
||||
<SheetContent className="flex flex-col gap-0">
|
||||
<SheetContent size="lg" className="flex flex-col gap-0">
|
||||
<SheetHeader>
|
||||
<SheetTitle>Invite team members</SheetTitle>
|
||||
<SheetDescription>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getTableRowsCountSql } from '@supabase/pg-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { QueryClient, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { IS_PLATFORM } from 'common'
|
||||
|
||||
@@ -9,6 +10,7 @@ import type { Filter, SupaTable } from '@/components/grid/types'
|
||||
import { useConnectionStringForReadOps } from '@/data/read-replicas/replicas-query'
|
||||
import { executeSql } from '@/data/sql/execute-sql-mutation'
|
||||
import { prefetchTableEditor } from '@/data/table-editor/table-editor-query'
|
||||
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
|
||||
import { RoleImpersonationState, wrapWithRoleImpersonation } from '@/lib/role-impersonation'
|
||||
import { isRoleImpersonationEnabled } from '@/state/role-impersonation-state'
|
||||
import { ResponseError, UseCustomQueryOptions } from '@/types'
|
||||
@@ -44,8 +46,8 @@ export async function getTableRowsCount(
|
||||
filters,
|
||||
roleImpersonationState,
|
||||
enforceExactCount,
|
||||
isUsingReadReplica = false,
|
||||
}: TableRowsCountVariables & { isUsingReadReplica?: boolean },
|
||||
isReadOnlyContext = false,
|
||||
}: TableRowsCountVariables & { isReadOnlyContext?: boolean },
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
const entity = await prefetchTableEditor(queryClient, {
|
||||
@@ -65,7 +67,7 @@ export async function getTableRowsCount(
|
||||
table,
|
||||
filters: formattedFilters,
|
||||
enforceExactCount,
|
||||
isUsingReadReplica,
|
||||
isReadOnlyContext,
|
||||
}),
|
||||
roleImpersonationState
|
||||
)
|
||||
@@ -103,6 +105,10 @@ export const useTableRowsCountQuery = <TData = TableRowsCountData>(
|
||||
identifier: readReplicaIdentifier,
|
||||
type,
|
||||
} = useConnectionStringForReadOps()
|
||||
const { can: canSQLAdminWrite } = useAsyncCheckPermissions(
|
||||
PermissionAction.TENANT_SQL_ADMIN_WRITE,
|
||||
'tables'
|
||||
)
|
||||
|
||||
return useQuery<TableRowsCountData, TableRowsCountError, TData>({
|
||||
queryKey: tableRowKeys.tableRowsCount(projectRef, {
|
||||
@@ -117,7 +123,7 @@ export const useTableRowsCountQuery = <TData = TableRowsCountData>(
|
||||
projectRef,
|
||||
connectionString,
|
||||
tableId,
|
||||
isUsingReadReplica: type === 'replica',
|
||||
isReadOnlyContext: type === 'replica' || !canSQLAdminWrite,
|
||||
...args,
|
||||
},
|
||||
signal
|
||||
|
||||
@@ -12,12 +12,13 @@ export const getTableRowsCountSql = ({
|
||||
table,
|
||||
filters = [],
|
||||
enforceExactCount = false,
|
||||
isUsingReadReplica = false,
|
||||
isReadOnlyContext = false,
|
||||
}: {
|
||||
table: any
|
||||
filters?: Filter[]
|
||||
enforceExactCount?: boolean
|
||||
isUsingReadReplica?: boolean
|
||||
/** Skips using the count estimate function if true and fallsback to checking reltuples from pg_class */
|
||||
isReadOnlyContext?: boolean
|
||||
}): SafeSqlFragment => {
|
||||
if (!table) return safeSql``
|
||||
|
||||
@@ -59,7 +60,7 @@ export const getTableRowsCountSql = ({
|
||||
? (countBaseSql.slice(0, -1) as SafeSqlFragment)
|
||||
: countBaseSql
|
||||
|
||||
if (isUsingReadReplica) {
|
||||
if (isReadOnlyContext) {
|
||||
const sql = safeSql`
|
||||
with approximation as (
|
||||
select reltuples as estimate
|
||||
|
||||
Reference in new issue
Block a user