Member Junction
    Preparing search index...

    SECURITY — the field-level security gate for SQL text a caller authors: RunView filters, sorts and aggregate expressions, a saved view's stored clauses, dataset item filters, and the rendered SQL of a saved query.

    Output projection alone is not enough. A user denied Salary who can write ExtraFilter: "Salary > 200000", sort by it, or aggregate MIN(Salary) reconstructs its values from which rows come back. This gate refuses such text before it reaches the cache or the database, for every caller: client requests, agents and actions alike.

    The text is split into tokens with the database's own lexical rules (ScanSQLForScreening), so a name inside a string literal or a comment is not a reference, and a [bracketed] or "quoted" name is read as the bare name it is. Every unquoted word and quoted identifier is then compared with every denied field of every entity the SQL reads:

    • the entity the fragment filters (its columns can be named unqualified);
    • the entities whose base view or base table the text names, such as a subquery's FROM;
    • any entities the caller says the SQL reads.

    A name matches a denied field by the rule IdentifierMatches states, or when the two are equal after Unicode compatibility folding, accent stripping and case folding, the comparisons a database collation can make. So a look-alike spelling that the database would still resolve to the denied column is refused too. Each name is compared on its own, so one denied name inside another can never hide it.

    A reference qualified by an alias or view name that binds only to entities whose denied set does not hold that name is not a reference to a denied field. An unknown qualifier is checked against every restricted entity.

    For a user denied something on an entity the SQL reads, constructs that read a whole row without naming its columns are refused: SELECT * and alias.* (except directly inside EXISTS (…) whose body has no set operation or row-picking ORDER BY), FOR JSON, FOR XML, any function of * other than COUNT(*)/COUNT_BIG(*) (for example CHECKSUM(*)), NATURAL JOIN, a column alias list on such a relation, and a relation or its alias used as a value (PostgreSQL's whole-row reference, as in row_to_json(e) or TABLE vw). A user with no denials on the entities read is not affected; ordinary subqueries keep working.

    Text the scanner cannot read the way the database does is refused for any user who carries a denial on an entity the SQL could read. So is a name holding a control, format or default-ignorable character (a zero-width joiner, a direction mark), which a collation may give no weight to.

    A reference to a column that does not exist reaches the database, which rejects it. For a user carrying denials, FieldSecuritySQLGate.ErrorForInvalidColumn turns that rejection into the same FieldSecurityError a denied column gets, so the two cannot be told apart.

    Index

    Constructors

    Methods

    • True when user is denied at least one field on any entity of catalog.

      Memoized per (catalog, user): after the first call it costs a few comparisons. The memo is discarded when the catalog array changes length, when the field-security generation moves (an entity rebuilt, a flag assigned, a cache invalidated; see CurrentFieldSecurityGeneration) or when the user's roles change, which are everything the answer depends on. A catalog swapped for a new array starts a new memo.

      Parameters

      Returns boolean

    • For a user carrying field denials on entity, the FieldSecurityError a database's "no such column" rejection becomes, so a column that does not exist and a column that is denied produce the same error. Null when the user carries no denials there, or the error is not a "no such column" rejection.

      Reads SQL Server's Invalid column name 'x' and The multi-part identifier "a.x" could not be bound, and PostgreSQL's column "x" does not exist and column a.x does not exist.

      Parameters

      Returns FieldSecurityError

    • The entities whose base view or base table sql reads as a relation: a name after FROM, JOIN or APPLY, or in a FROM list, wherever it appears (subqueries and CTE bodies included), with schema qualifiers skipped. A name in a literal or a comment is not a relation. A bare name shared by entities in several schemas yields each of them, so the set never misses a read. A relation inside a parenthesized join and PostgreSQL's FROM ONLY x count too. Null when the text cannot be read the way the database reads it.

      Parameters

      Returns EntityInfo[]

    • The name a "no such column" error would give for name as sql writes it, so a denied column is reported exactly as an unknown one. On PostgreSQL, MJ quotes a capitalized or dot-qualified word before the database sees it (AutoQuoteLeavesWordBare), so the error names such a word as written; a word left bare is folded to lower case. A quoted name, and every name on SQL Server, is reported as written. The first token spelled name decides.

      Parameters

      • sql: string

        The caller's SQL

      • name: string

        The reference as the database reads it

      • dialect: SQLScreeningDialect

        The dialect the SQL runs under

      Returns string