{"id":347643,"date":"2023-05-19T09:03:38","date_gmt":"2023-05-19T09:03:38","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=347643"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=347643","title":{"rendered":"<span>PostgreSQL \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c. \u0427\u0430\u0441\u0442\u044c 5. \u041f\u0440\u043e\u0441\u0442\u043e\u0439 SELECT \u0437\u0430\u043f\u0440\u043e\u0441<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e!<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0443\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e SELECT \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u044b\u043b\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e \u0432 <a href=\"https:\/\/habr.com\/ru\/articles\/723668\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>. \u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"sql\">SELECT u.name  FROM users AS u WHERE u.age &gt; 24 GROUP BY u.name HAVING COUNT(*) = 1 ORDER BY u.name LIMIT 50<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u0438\u044f, \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441 <a href=\"https:\/\/habr.com\/ru\/articles\/723668\/\" rel=\"noopener noreferrer nofollow\">\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/a>, \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432 3 \u043c\u0435\u0441\u0442\u0430\u0445: \u043f\u0430\u0440\u0441\u0438\u043d\u0433, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u0438 \u0441\u043b\u0443\u0447\u0430\u0438.<\/p>\n<h2>\u041f\u0430\u0440\u0441\u0438\u043d\u0433<\/h2>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f.&nbsp;<\/p>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 &#8212; <code>transformStmt<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/analyze.c#L313\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/analyze.c<\/a>). \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u0414\u043b\u044f SELECT \u044d\u0442\u043e \u0441\u043d\u043e\u0432\u0430 <code>transformSelectStmt<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/analyze.c#L1282\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/analyze.c<\/a>). <\/p>\n<h4>FROM users AS u<\/h4>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f <code>FROM<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>transformFromClause<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L113\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>). \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0441\u0442\u0438\u0441\u044c \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435.<\/p>\n<h4>SELECT u.name<\/h4>\n<p>\u0412 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0432\u0441\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0430\u0441\u0442\u0435\u0440\u0438\u0441\u043a<em> <\/em>(*)<em>. <\/em>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f  <code>ExpandColumnRefStar<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L1116\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>).<\/p>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u0433\u0434\u0430 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0435\u0442 \u0430\u0441\u0442\u0435\u0440\u0438\u0441\u043a\u0430, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>transformTargetEntry<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L77\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>)  &#8212; \u043d\u0435 \u0432\u0430\u0436\u043d\u043e \u0441\u0442\u043e\u043b\u0431\u0435\u0446, \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043b\u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430.<\/p>\n<pre><code class=\"cpp\">\/*  * transformTargetEntry()  *Transform any ordinary \"expression-type\" node into a targetlist entry.  *This is exported so that parse_clause.c can generate targetlist entries  *for ORDER\/GROUP BY items that are not already in the targetlist.  *  * nodethe (untransformed) parse tree for the value expression.  * exprthe transformed expression, or NULL if caller didn't do it yet.  * exprKind expression kind (EXPR_KIND_SELECT_TARGET, etc)  * colnamethe column name to be assigned, or NULL if none yet set.  * resjunktrue if the target should be marked resjunk, ie, it is not  *wanted in the final projected tuple.  *\/ TargetEntry * transformTargetEntry(ParseState *pstate, Node *node, Node *expr, ParseExprKind exprKind, char *colname, bool resjunk)<\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043e\u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 2 \u0447\u0430\u0441\u0442\u0435\u0439 (\u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0439):<\/p>\n<ul>\n<li>\n<p><code>transformExpr<\/code> &#8212; \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_expr.c#L94\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_expr.c<\/a>)<\/p>\n<\/li>\n<li>\n<p><code>FigureColname<\/code> &#8212; \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u0430 (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L1690\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>)<\/p>\n<\/li>\n<\/ul>\n<p><code>transformExpr<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>ParseState<\/code> \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0435 <code>transformExprRecurse<\/code> &#8212; \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443 \u043f\u0430\u0440\u0441\u0435\u0440\u0443.<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043e\u043d \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u044d\u0433\u0430 \u0443\u0437\u043b\u0430. \u0414\u043b\u044f <em>u.name<\/em> \u0442\u044d\u0433 &#8212; <code>T_ColumnRef<\/code> (\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446). \u0414\u043b\u044f \u043d\u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>transformColumnRef<\/code><\/p>\n<p>\u041d\u0430 \u0432\u0445\u043e\u0434 \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 <code>ParseState<\/code> \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 <code>ColumnRef<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * ColumnRef - specifies a reference to a column, or possibly a whole tuple  *  * The \"fields\" list must be nonempty.  It can contain String nodes  * (representing names) and A_Star nodes (representing occurrence of a '*').  * Currently, A_Star must appear only as the last list element --- the grammar  * is responsible for enforcing this!  *  * Note: any container subscripting or selection of fields from composite columns  * is represented by an A_Indirection node above the ColumnRef.  However,  * for simplicity in the normal case, initial field selection from a table  * name is represented within ColumnRef and not by adding A_Indirection.  *\/ typedef struct ColumnRef { NodeTagtype; List   *fields;\/* field names (String nodes) or A_Star *\/ intlocation;\/* token location, or -1 if unknown *\/ } ColumnRef;<\/code><\/pre>\n<pre><code class=\"cpp\">\/*  * State information used during parse analysis  *  * parentParseState: NULL in a top-level ParseState.  When parsing a subquery,  * links to current parse state of outer query.  *  * p_sourcetext: source string that generated the raw parsetree being  * analyzed, or NULL if not available.  (The string is used only to  * generate cursor positions in error messages: we need it to convert  * byte-wise locations in parse structures to character-wise cursor  * positions.)  *  * p_rtable: list of RTEs that will become the rangetable of the query.  * Note that neither relname nor refname of these entries are necessarily  * unique; searching the rtable by name is a bad idea.  *  * p_joinexprs: list of JoinExpr nodes associated with p_rtable entries.  * This is one-for-one with p_rtable, but contains NULLs for non-join  * RTEs, and may be shorter than p_rtable if the last RTE(s) aren't joins.  *  * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that  * will become the fromlist of the query's top-level FromExpr node.  *  * p_namespace: list of ParseNamespaceItems that represents the current  * namespace for table and column lookup.  (The RTEs listed here may be just  * a subset of the whole rtable.  See ParseNamespaceItem comments below.)  *  * p_lateral_active: true if we are currently parsing a LATERAL subexpression  * of this parse level.  This makes p_lateral_only namespace items visible,  * whereas they are not visible when p_lateral_active is FALSE.  *  * p_ctenamespace: list of CommonTableExprs (WITH items) that are visible  * at the moment.  This is entirely different from p_namespace because a CTE  * is not an RTE, rather \"visibility\" means you could make an RTE from it.  *  * p_future_ctes: list of CommonTableExprs (WITH items) that are not yet  * visible due to scope rules.  This is used to help improve error messages.  *  * p_parent_cte: CommonTableExpr that immediately contains the current query,  * if any.  *  * p_target_relation: target relation, if query is INSERT\/UPDATE\/DELETE\/MERGE  *  * p_target_nsitem: target relation's ParseNamespaceItem.  *  * p_is_insert: true to process assignment expressions like INSERT, false  * to process them like UPDATE.  (Note this can change intra-statement, for  * cases like INSERT ON CONFLICT UPDATE.)  *  * p_windowdefs: list of WindowDefs representing WINDOW and OVER clauses.  * We collect these while transforming expressions and then transform them  * afterwards (so that any resjunk tlist items needed for the sort\/group  * clauses end up at the end of the query tlist).  A WindowDef's location in  * this list, counting from 1, is the winref number to use to reference it.  *  * p_expr_kind: kind of expression we're currently parsing, as per enum above;  * EXPR_KIND_NONE when not in an expression.  *  * p_next_resno: next TargetEntry.resno to assign, starting from 1.  *  * p_multiassign_exprs: partially-processed MultiAssignRef source expressions.  *  * p_locking_clause: query's FOR UPDATE\/FOR SHARE clause, if any.  *  * p_locked_from_parent: true if parent query level applies FOR UPDATE\/SHARE  * to this subquery as a whole.  *  * p_resolve_unknowns: resolve unknown-type SELECT output columns as type TEXT  * (this is true by default).  *  * p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated  * constructs in the query.  *  * p_last_srf: the set-returning FuncExpr or OpExpr most recently found in  * the query, or NULL if none.  *  * p_pre_columnref_hook, etc: optional parser hook functions for modifying the  * interpretation of ColumnRefs and ParamRefs.  *  * p_ref_hook_state: passthrough state for the parser hook functions.  *\/ struct ParseState { ParseState *parentParseState;\/* stack link *\/ const char *p_sourcetext;\/* source text, or NULL if not available *\/ List   *p_rtable;\/* range table so far *\/ List   *p_joinexprs;\/* JoinExprs for RTE_JOIN p_rtable entries *\/ List   *p_joinlist;\/* join items so far (will become FromExpr  * node's fromlist) *\/ List   *p_namespace;\/* currently-referenceable RTEs (List of  * ParseNamespaceItem) *\/ boolp_lateral_active;\/* p_lateral_only items visible? *\/ List   *p_ctenamespace; \/* current namespace for common table exprs *\/ List   *p_future_ctes;\/* common table exprs not yet in namespace *\/ CommonTableExpr *p_parent_cte;\/* this query's containing CTE *\/ Relationp_target_relation;\/* INSERT\/UPDATE\/DELETE\/MERGE target rel *\/ ParseNamespaceItem *p_target_nsitem;\/* target rel's NSItem, or NULL *\/ boolp_is_insert;\/* process assignment like INSERT not UPDATE *\/ List   *p_windowdefs;\/* raw representations of window clauses *\/ ParseExprKind p_expr_kind;\/* what kind of expression we're parsing *\/ intp_next_resno;\/* next targetlist resno to assign *\/ List   *p_multiassign_exprs;\/* junk tlist entries for multiassign *\/ List   *p_locking_clause;\/* raw FOR UPDATE\/FOR SHARE info *\/ boolp_locked_from_parent;\/* parent has marked this subquery  * with FOR UPDATE\/FOR SHARE *\/ boolp_resolve_unknowns; \/* resolve unknown-type SELECT outputs as  * type text *\/  QueryEnvironment *p_queryEnv;\/* curr env, incl refs to enclosing env *\/  \/* Flags telling about things found in the query: *\/ boolp_hasAggs; boolp_hasWindowFuncs; boolp_hasTargetSRFs; boolp_hasSubLinks; boolp_hasModifyingCTE;  Node   *p_last_srf;\/* most recent set-returning func\/op found *\/  \/*  * Optional hook functions for parser callbacks.  These are null unless  * set up by the caller of make_parsestate.  *\/ PreParseColumnRefHook p_pre_columnref_hook; PostParseColumnRefHook p_post_columnref_hook; ParseParamRefHook p_paramref_hook; CoerceParamHook p_coerce_param_hook; void   *p_ref_hook_state;\/* common passthrough link for above *\/ };<\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0443\u0437\u043b\u0430. \u0422\u0438\u043f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>ParseExprKind<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/parser\/parse_node.h#L38\" rel=\"noopener noreferrer nofollow\">src\/include\/parser\/parse_node.h<\/a>)<\/p>\n<pre><code class=\"cpp\">\/*  * Expression kinds distinguished by transformExpr().  Many of these are not  * semantically distinct so far as expression transformation goes; rather,  * we distinguish them so that context-specific error messages can be printed.  *  * Note: EXPR_KIND_OTHER is not used in the core code, but is left for use  * by extension code that might need to call transformExpr().  The core code  * will not enforce any context-driven restrictions on EXPR_KIND_OTHER  * expressions, so the caller would have to check for sub-selects, aggregates,  * window functions, SRFs, etc if those need to be disallowed.  *\/ typedef enum ParseExprKind { EXPR_KIND_NONE = 0,\/* \"not in an expression\" *\/ EXPR_KIND_OTHER,\/* reserved for extensions *\/ EXPR_KIND_JOIN_ON,\/* JOIN ON *\/ EXPR_KIND_JOIN_USING,\/* JOIN USING *\/ EXPR_KIND_FROM_SUBSELECT,\/* sub-SELECT in FROM clause *\/ EXPR_KIND_FROM_FUNCTION,\/* function in FROM clause *\/ EXPR_KIND_WHERE,\/* WHERE *\/ EXPR_KIND_HAVING,\/* HAVING *\/ EXPR_KIND_FILTER,\/* FILTER *\/ EXPR_KIND_WINDOW_PARTITION, \/* window definition PARTITION BY *\/ EXPR_KIND_WINDOW_ORDER,\/* window definition ORDER BY *\/ EXPR_KIND_WINDOW_FRAME_RANGE,\/* window frame clause with RANGE *\/ EXPR_KIND_WINDOW_FRAME_ROWS,\/* window frame clause with ROWS *\/ EXPR_KIND_WINDOW_FRAME_GROUPS,\/* window frame clause with GROUPS *\/ EXPR_KIND_SELECT_TARGET,\/* SELECT target list item *\/ EXPR_KIND_INSERT_TARGET,\/* INSERT target list item *\/ EXPR_KIND_UPDATE_SOURCE,\/* UPDATE assignment source item *\/ EXPR_KIND_UPDATE_TARGET,\/* UPDATE assignment target item *\/ EXPR_KIND_MERGE_WHEN,\/* MERGE WHEN [NOT] MATCHED condition *\/ EXPR_KIND_GROUP_BY,\/* GROUP BY *\/ EXPR_KIND_ORDER_BY,\/* ORDER BY *\/ EXPR_KIND_DISTINCT_ON,\/* DISTINCT ON *\/ EXPR_KIND_LIMIT,\/* LIMIT *\/ EXPR_KIND_OFFSET,\/* OFFSET *\/ EXPR_KIND_RETURNING,\/* RETURNING *\/ EXPR_KIND_VALUES,\/* VALUES *\/ EXPR_KIND_VALUES_SINGLE,\/* single-row VALUES (in INSERT only) *\/ EXPR_KIND_CHECK_CONSTRAINT, \/* CHECK constraint for a table *\/ EXPR_KIND_DOMAIN_CHECK,\/* CHECK constraint for a domain *\/ EXPR_KIND_COLUMN_DEFAULT,\/* default value for a table column *\/ EXPR_KIND_FUNCTION_DEFAULT, \/* default parameter value for function *\/ EXPR_KIND_INDEX_EXPRESSION, \/* index expression *\/ EXPR_KIND_INDEX_PREDICATE,\/* index predicate *\/ EXPR_KIND_STATS_EXPRESSION, \/* extended statistics expression *\/ EXPR_KIND_ALTER_COL_TRANSFORM,\/* transform expr in ALTER COLUMN TYPE *\/ EXPR_KIND_EXECUTE_PARAMETER,\/* parameter value in EXECUTE *\/ EXPR_KIND_TRIGGER_WHEN,\/* WHEN condition in CREATE TRIGGER *\/ EXPR_KIND_POLICY,\/* USING or WITH CHECK expr in policy *\/ EXPR_KIND_PARTITION_BOUND,\/* partition bound expression *\/ EXPR_KIND_PARTITION_EXPRESSION, \/* PARTITION BY expression *\/ EXPR_KIND_CALL_ARGUMENT,\/* procedure argument in CALL *\/ EXPR_KIND_COPY_WHERE,\/* WHERE condition in COPY FROM *\/ EXPR_KIND_GENERATED_COLUMN, \/* generation expression for a column *\/ EXPR_KIND_CYCLE_MARK,\/* cycle mark value *\/ } ParseExprKind;<\/code><\/pre>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f &#8212; <code>EXPR_KIND_COLUMN_DEFAULT<\/code> \u0438 <code>EXPR_KIND_PARTITION_BOUND<\/code>.<\/p>\n<pre><code class=\"cpp\">switch (pstate-&gt;p_expr_kind) {     \/\/ ...     case EXPR_KIND_COLUMN_DEFAULT:         err = _(\"cannot use column reference in DEFAULT expression\");         break;     case EXPR_KIND_PARTITION_BOUND:         err = _(\"cannot use column reference in partition bound expression\");         break;     \/\/ ... }<\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0446\u044b.<\/p>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c \u0442\u0430\u0431\u043b\u0438\u0446 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <em>A.B.C<\/em> \u0438\u043b\u0438 <em>A.*<\/em>&nbsp;<\/p>\n<p>\u0412\u0441\u0435\u0433\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c 7 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u041a\u0430\u0436\u0434\u044b\u0439 \u043e\u043f\u0438\u0441\u0430\u043d \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<pre><code class=\"cpp\">\/*----------  * The allowed syntaxes are:  *  * AFirst try to resolve as unqualified column name;  *if no luck, try to resolve as unqualified table name (A.*).  * A.BA is an unqualified table name; B is either a  *column or function name (trying column name first).  * A.B.Cschema A, table B, col or func name C.  * A.B.C.Dcatalog A, schema B, table C, col or func D.  * A.*A is an unqualified table name; means whole-row value.  * A.B.*whole-row value of table B in schema A.  * A.B.C.*whole-row value of table C in schema B in catalog A.  *  * We do not need to cope with bare \"*\"; that will only be accepted by  * the grammar at the top level of a SELECT list, and transformTargetList  * will take care of it before it ever gets here.  Also, \"A.*\" etc will  * be expanded by transformTargetList if they appear at SELECT top level,  * so here we are only going to see them as function or operator inputs.  *  * Currently, if a catalog name is given then it must equal the current  * database name; we check it here and then discard it.  *----------  *\/<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435 <code>fields<\/code> \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b <code>ColumnRef<\/code>. \u042d\u0442\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f A, B, C, D (\u0438\u0437 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f).&nbsp;<\/p>\n<p>\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u043b\u0438\u043d\u044b \u0441\u043f\u0438\u0441\u043a\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0434\u043b\u0438\u043d\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 2, \u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442\u0441\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b <em>A.B<\/em> \u0438 <em>A.*<\/em><\/p>\n<pre><code class=\"cpp\">switch (list_length(cref-&gt;fields)) {   \/\/ ...   case 2:   {       Node   *field1 = (Node *) linitial(cref-&gt;fields);       Node   *field2 = (Node *) lsecond(cref-&gt;fields);        Assert(IsA(field1, String));       relname = strVal(field1);        \/* Locate the referenced nsitem *\/       nsitem = refnameNamespaceItem(pstate, nspname, relname,                                     cref-&gt;location,                                     &amp;levels_up);       if (nsitem == NULL)       {           crerr = CRERR_NO_RTE;           break;       }        \/* Whole-row reference? *\/       if (IsA(field2, A_Star))       {           node = transformWholeRowRef(pstate, nsitem, levels_up,                                       cref-&gt;location);           break;       }        Assert(IsA(field2, String));       colname = strVal(field2);        \/* Try to identify as a column of the nsitem *\/       node = scanNSItemForColumn(pstate, nsitem, levels_up, colname,                                  cref-&gt;location);       if (node == NULL)       {           \/* Try it as a function call on the whole row *\/           node = transformWholeRowRef(pstate, nsitem, levels_up,                                       cref-&gt;location);           node = ParseFuncOrColumn(pstate,                                    list_make1(makeString(colname)),                                    list_make1(node),                                    pstate-&gt;p_last_srf,                                    NULL,                                    false,                                    cref-&gt;location);       }       break;   }   \/\/ ... }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a. \u0422\u0430\u043a \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u043c \u0432\u044b\u0448\u0435 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430, \u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>crerr<\/code> \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>CRERR_NO_RTE<\/code><\/p>\n<pre><code class=\"cpp\">enum {     CRERR_NO_COLUMN,     CRERR_NO_RTE,     CRERR_WRONG_DB,     CRERR_TOO_MANY } crerr = CRERR_NO_COLUMN;  \/\/ ...  if (nsitem == NULL) {     crerr = CRERR_NO_RTE;     break; }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0435\u0433\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435. \u0415\u0441\u043b\u0438 \u043c\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043f\u0441\u0435\u0432\u0434\u043e\u043d\u0438\u043c ( \u201c<code>AS \u2026<\/code>\u201d), \u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u0437\u0430\u0434\u0430\u043d\u043e, \u0438\u043d\u0430\u0447\u0435 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0432\u044b\u0432\u0435\u0441\u0442\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>FigureColname<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L1729\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>)<\/p>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0438\u043f\u0430 \u0443\u0437\u043b\u0430. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u043e\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 (\u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c <code>*<\/code>)<\/p>\n<pre><code class=\"cpp\">switch (nodeTag(node)) {     case T_ColumnRef:         {             char   *fname = NULL;             ListCell   *l;                \/* find last field name, if any, ignoring \"*\" *\/             foreach(l, ((ColumnRef *) node)-&gt;fields)             {                 Node   *i = lfirst(l);                    if (IsA(i, String))                     fname = strVal(i);             }             if (fname)             {                 *name = fname;                 return 2;             }         }         break;     \/\/ ... }<\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432, \u043d\u043e \u043a\u0443\u0434\u0430 \u043e\u043d\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0442\u0430\u0434\u0438\u044f &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 OID \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>markTargetListOrigin<\/code>  (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L345\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>)<\/p>\n<h4>WHERE u.age &gt; 24<\/h4>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f <code>WHERE<\/code>. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>transformWhereClause<\/code><\/p>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0441\u0430\u043c\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0412 \u0443\u0441\u043b\u043e\u0432\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>transformExpr<\/code> (\u043e\u0431\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439)<\/p>\n<p>\u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0443\u0437\u0435\u043b \u0438 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0441\u0432\u043e\u0438 \u0442\u044d\u0433\u0438. \u0414\u043b\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0441 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u043c\u0438\/\u0443\u043d\u0430\u0440\u043d\u044b\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438\u043b\u0438 SQL \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 (<em>LIKE<\/em>, <em>BETWEEN<\/em>) \u0442\u0435\u0433 \u0443\u0437\u043b\u0430 \u0440\u0430\u0432\u0435\u043d <code>T_A_Expr<\/code>. \u0410 \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u044f\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0442\u0438\u043f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 <code>kind<\/code> \u0442\u0438\u043f\u0430 <code>A_Expr_Kind<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/nodes\/parsenodes.h#L270\" rel=\"noopener noreferrer nofollow\">src\/include\/nodes\/parsenodes.h<\/a>)<\/p>\n<pre><code class=\"cpp\">\/*  * A_Expr - infix, prefix, and postfix expressions  *\/ typedef enum A_Expr_Kind { AEXPR_OP,\/* normal operator *\/ AEXPR_OP_ANY,\/* scalar op ANY (array) *\/ AEXPR_OP_ALL,\/* scalar op ALL (array) *\/ AEXPR_DISTINCT,\/* IS DISTINCT FROM - name must be \"=\" *\/ AEXPR_NOT_DISTINCT,\/* IS NOT DISTINCT FROM - name must be \"=\" *\/ AEXPR_NULLIF,\/* NULLIF - name must be \"=\" *\/ AEXPR_IN,\/* [NOT] IN - name must be \"=\" or \"&lt;&gt;\" *\/ AEXPR_LIKE,\/* [NOT] LIKE - name must be \"~~\" or \"!~~\" *\/ AEXPR_ILIKE,\/* [NOT] ILIKE - name must be \"~~*\" or \"!~~*\" *\/ AEXPR_SIMILAR,\/* [NOT] SIMILAR - name must be \"~\" or \"!~\" *\/ AEXPR_BETWEEN,\/* name must be \"BETWEEN\" *\/ AEXPR_NOT_BETWEEN,\/* name must be \"NOT BETWEEN\" *\/ AEXPR_BETWEEN_SYM,\/* name must be \"BETWEEN SYMMETRIC\" *\/ AEXPR_NOT_BETWEEN_SYM\/* name must be \"NOT BETWEEN SYMMETRIC\" *\/ } A_Expr_Kind;<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (\u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435) \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u0440\u0430\u0432\u043d\u043e <code>AEXPR_OP<\/code>. \u0417\u0430 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>transformAExprOp<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_expr.c#L861\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_expr.c<\/a>). \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a<\/p>\n<pre><code class=\"cpp\">switch (nodeTag(expr)) {     case T_A_Expr: { A_Expr   *a = (A_Expr *) expr; switch (a-&gt;kind) {             case AEXPR_OP: result = transformAExprOp(pstate, a);     break;             \/\/ ..         }         break;     \/\/ ...     } } <\/code><\/pre>\n<p>\u0421\u0430\u043c<em> <\/em><code>transformAExprOp<\/code> \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u0440\u0430\u0435\u0432\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432:<\/p>\n<ol>\n<li>\n<p>&#171;<code>= NULL<\/code>&#171;<\/p>\n<\/li>\n<\/ol>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 &#8212; \u044d\u0442\u043e \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u201c<code>= NULL<\/code>\u201d \u0432 \u201c<code>IS NULL<\/code>\u201d. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u043f\u043e\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u044f\u0437\u044b\u043a\u0430\u043c\u0438, \u043d\u0430\u0440\u0443\u0448\u0430\u044e\u0449\u0438\u043c\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u044b SQL&nbsp;<\/p>\n<pre><code class=\"cpp\">\/*  * Special-case \"foo = NULL\" and \"NULL = foo\" for compatibility with  * standards-broken products (like Microsoft's).  Turn these into IS NULL  * exprs. (If either side is a CaseTestExpr, then the expression was  * generated internally from a CASE-WHEN expression, and  * transform_null_equals does not apply.)  *\/ if (Transform_null_equals &amp;&amp;     list_length(a-&gt;name) == 1 &amp;&amp;     strcmp(strVal(linitial(a-&gt;name)), \"=\") == 0 &amp;&amp;     (exprIsNullConstant(lexpr) || exprIsNullConstant(rexpr)) &amp;&amp;     (!IsA(lexpr, CaseTestExpr) &amp;&amp; !IsA(rexpr, CaseTestExpr))) {    \/\/ ... }<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p><code>ROW op SUBSELECT<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u0440\u0443\u0433\u043e\u0439 \u043e\u0441\u043e\u0431\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 &#8212; \u043a\u043e\u0433\u0434\u0430 \u043e\u0434\u0438\u043d \u0438\u0437 \u043e\u043f\u0435\u0440\u0430\u043d\u0434\u043e\u0432 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441. \u042d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0438\u043f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441 <code>EXPR_SUBLINK<\/code> \u043d\u0430 <code>ROWCOMPARE_SUBLINK<\/code>. \u0421\u0430\u043c \u0442\u0438\u043f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>SubLinkType<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * SubLink  *  * A SubLink represents a subselect appearing in an expression, and in some  * cases also the combining operator(s) just above it.  The subLinkType  * indicates the form of the expression represented:  *EXISTS_SUBLINKEXISTS(SELECT ...)  *ALL_SUBLINK(lefthand) op ALL (SELECT ...)  *ANY_SUBLINK(lefthand) op ANY (SELECT ...)  *ROWCOMPARE_SUBLINK(lefthand) op (SELECT ...)  *EXPR_SUBLINK(SELECT with single targetlist item ...)  *MULTIEXPR_SUBLINK(SELECT with multiple targetlist items ...)  *ARRAY_SUBLINKARRAY(SELECT with single targetlist item ...)  *CTE_SUBLINKWITH query (never actually part of an expression)  * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the  * same length as the subselect's targetlist.  ROWCOMPARE will *always* have  * a list with more than one entry; if the subselect has just one target  * then the parser will create an EXPR_SUBLINK instead (and any operator  * above the subselect will be represented separately).  * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most  * one row (if it returns no rows, the result is NULL).  * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean  * results.  ALL and ANY combine the per-row results using AND and OR  * semantics respectively.  * ARRAY requires just one target column, and creates an array of the target  * column's type using any number of rows resulting from the subselect.  *  * SubLink is classed as an Expr node, but it is not actually executable;  * it must be replaced in the expression tree by a SubPlan node during  * planning.  *  * NOTE: in the raw output of gram.y, testexpr contains just the raw form  * of the lefthand expression (if any), and operName is the String name of  * the combining operator.  Also, subselect is a raw parsetree.  During parse  * analysis, the parser transforms testexpr into a complete boolean expression  * that compares the lefthand value(s) to PARAM_SUBLINK nodes representing the  * output columns of the subselect.  And subselect is transformed to a Query.  * This is the representation seen in saved rules and in the rewriter.  *  * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName  * are unused and are always null.  *  * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in  * other SubLinks.  This number identifies different multiple-assignment  * subqueries within an UPDATE statement's SET list.  It is unique only  * within a particular targetlist.  The output column(s) of the MULTIEXPR  * are referenced by PARAM_MULTIEXPR Params appearing elsewhere in the tlist.  *  * The CTE_SUBLINK case never occurs in actual SubLink nodes, but it is used  * in SubPlans generated for WITH subqueries.  *\/ typedef enum SubLinkType { EXISTS_SUBLINK, ALL_SUBLINK, ANY_SUBLINK, ROWCOMPARE_SUBLINK, EXPR_SUBLINK, MULTIEXPR_SUBLINK, ARRAY_SUBLINK, CTE_SUBLINK\/* for SubPlans only *\/ } SubLinkType;<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043e\u0431\u0435 \u0447\u0430\u0441\u0442\u0438 &#8212; \u044d\u0442\u043e <code>ROW<\/code>  \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u043e\u0436\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 (<code>ROW op ROW<\/code>).<\/p>\n<ol start=\"3\">\n<li>\n<p>\u041e\u0431\u044b\u0447\u043d\u044b\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u043e\u0447\u043d\u0435\u0435 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u044d\u0442\u043e \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043b\u0443\u0447\u0430\u0438. \u0421\u044e\u0434\u0430 \u043c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c, \u0435\u0441\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438.<\/p>\n<p>\u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0432\u0435\u0442\u043a\u0443. \u0412\u043d\u0443\u0442\u0440\u0438 \u043a\u0430\u0436\u0434\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f (\u0432\u044b\u0437\u043e\u0432 <code>transformExprRecurse<\/code>):<\/p>\n<ul>\n<li>\n<p>\u041b\u0435\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c <code>u.name<\/code> \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043f\u043e\u0434 \u0441\u043b\u0443\u0447\u0430\u0439 <code>ColumnRef<\/code> &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446. \u041e\u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432\u044b\u0448\u0435 (\u0432 <code>SELECT<\/code>)<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0430\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c <em>24<\/em> \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043f\u043e\u0434 \u0441\u043b\u0443\u0447\u0430\u0439 <code>T_Const<\/code> : \u0443\u0437\u0435\u043b &#8212; \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430. \u0414\u043b\u044f \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442 \u0443\u0437\u043b\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>make_const<\/em>. \u0420\u0430\u0437\u0431\u043e\u0440 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b &#8212; \u0442\u043e\u0442 \u0436\u0435 \u0441\u0430\u043c\u044b\u0439 switch\/case. \u041f\u0440\u0438\u0447\u0435\u043c \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0447\u0438\u0441\u043b\u0430 &#8212; \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 (\u0432\u0441\u0435\u0433\u043e 4 \u0441\u0442\u0440\u043e\u043a\u0438)<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cpp\">\/*  * make_const  *  *Convert an A_Const node (as returned by the grammar) to a Const node  *of the \"natural\" type for the constant.  Note that this routine is  *only used when there is no explicit cast for the constant, so we  *have to guess what type is wanted.  *  *For string literals we produce a constant of type UNKNOWN ---- whose  *representation is the same as cstring, but it indicates to later type  *resolution that we're not sure yet what type it should be considered.  *Explicit \"NULL\" constants are also typed as UNKNOWN.  *  *For integers and floats we produce int4, int8, or numeric depending  *on the value of the number.  XXX We should produce int2 as well,  *but additional cleanup is needed before we can do that; there are  *too many examples that fail if we try.  *\/ Const * make_const(ParseState *pstate, A_Const *aconst) {   \/\/ ...   switch (nodeTag(&amp;aconst-&gt;val))   {       case T_Integer:           val = Int32GetDatum(intVal(&amp;aconst-&gt;val));           typeid = INT4OID;           typelen = sizeof(int32);           typebyval = true;           break;       \/\/ ...   }   \/\/ .. }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>make_op<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_oper.c#L672\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_oper.c<\/a>) \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n<h4>HAVING COUNT(*) = 1<\/h4>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u0430\u043f &#8212; \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f <code>HAVING<\/code>. \u0414\u043b\u044f \u0440\u0430\u0437\u0431\u043e\u0440\u0430 <code>HAVING<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u0430 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0447\u0442\u043e \u0438 \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435&nbsp; WHERE &#8212; <code>transformWhereClause<\/code><\/p>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u0438\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>transformExprRecurse<\/code>: \u043b\u0435\u0432\u044b\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446, \u0430 \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u044d\u0433 \u043d\u0435 <code>T_ColumnRef<\/code>, \u0430 <code>T_FuncCall<\/code> &#8212; \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0417\u0430 \u0435\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>transformFuncCall<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_expr.c#L1351\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_expr.c<\/a>)<\/p>\n<p>\u0421\u0430\u043c\u0430 \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>ParseFuncOrColumn<\/code><\/p>\n<details class=\"spoiler\">\n<summary>tab.col = col(tab)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 Postgres \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0441\u0442\u043e\u043b\u0431\u0446\u0443 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043e 2 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438: \u0447\u0435\u0440\u0435\u0437 \u0442\u043e\u0447\u043a\u0443 (<code>table.column<\/code>) \u0438 \u043a\u0430\u043a \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 (<code>column(table)<\/code>). \u042d\u0442\u043e \u043b\u0435\u0433\u0430\u0441\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043d\u0443\u0436\u043d\u043e \u043c\u0438\u0440\u0438\u0442\u044c\u0441\u044f.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043c\u0435\u0435\u0442 \u0442\u0430\u043a\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435.<\/p>\n<p>\u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0434\u0430\u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/p>\n<pre><code class=\"cpp\">\/*  *Parse a function call  *  *For historical reasons, Postgres tries to treat the notations tab.col  *and col(tab) as equivalent: if a single-argument function call has an  *argument of complex type and the (unqualified) function name matches  *any attribute of the type, we can interpret it as a column projection.  *Conversely a function of a single complex-type argument can be written  *like a column reference, allowing functions to act like computed columns.  *  *If both interpretations are possible, we prefer the one matching the  *syntactic form, but otherwise the form does not matter.  *  *Hence, both cases come through here.  If fn is null, we're dealing with  *column syntax not function syntax.  In the function-syntax case,  *the FuncCall struct is needed to carry various decoration that applies  *to aggregate and window functions.  *  *Also, when fn is null, we return NULL on failure rather than  *reporting a no-such-function error.  * ...  *\/<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0438\u0441\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445 (\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 . \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>func_get_detail<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_func.c#L1393\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_func.c<\/a>).<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u044b. \u041f\u043e\u0438\u0441\u043a \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e (\u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441 \u0438 \u0438\u043c\u044f) \u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c (\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u0438 \u0438\u043c\u0435\u043d\u0430\u043c).<\/p>\n<p>\u041f\u043e\u0438\u0441\u043a \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0432 <code>FuncnameGetCandidates<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/catalog\/namespace.c#L951\" rel=\"noopener noreferrer nofollow\">src\/backend\/catalog\/namespace.c<\/a>). \u0412\u043d\u0430\u0447\u0430\u043b\u0435 \u0438\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u044d\u0448\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (\u0441\u043f\u0438\u0441\u043e\u043a) \u0441 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0442\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e \u0432\u0441\u0435\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c \u044d\u0442\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043f\u043e\u0438\u0441\u043a\u0435 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u0432. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u0442\u044c \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438:<\/p>\n<ol>\n<li>\n<p>\u041d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 (\u043f\u043e\u0438\u0441\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e)<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043f\u043e <code>OUT<\/code> \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c<\/p>\n<\/li>\n<li>\n<p>\u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0441\u043e\u0432\u043f\u0430\u043b\u0438<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u043f\u043e \u0442\u0438\u043f\u0430\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432<\/p>\n<\/li>\n<\/ol>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u0432 \u0433\u043e\u0442\u043e\u0432, \u043e\u043d \u043f\u043e\u0434\u0432\u0435\u0440\u0433\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u044f\u043c.&nbsp;<\/p>\n<p>\u041f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0438\u0441\u043a \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0430: \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u0438\u043f\u044b \u0432\u0441\u0435\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u0432\u0441\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442, \u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0430\u0439\u0434\u0435\u043d\u0430<\/p>\n<pre><code class=\"cpp\">\/*  * Quickly check if there is an exact match to the input datatypes (there  * can be only one)  *\/ for (best_candidate = raw_candidates;      best_candidate != NULL;      best_candidate = best_candidate-&gt;next) {     \/* if nargs==0, argtypes can be null; don't pass that to memcmp *\/     if (nargs == 0 ||         memcmp(argtypes, best_candidate-&gt;args, nargs * sizeof(Oid)) == 0)         break; }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u043d\u0430\u0448\u043b\u043e\u0441\u044c \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u043e\u043b\u044c\u043a\u043e 1 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 &#8212; \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f &#8212; \u043a\u0430\u0441\u0442 \u043a \u0442\u0438\u043f\u0443. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043c\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u0430 \u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u043a \u043a\u0430\u0441\u0442\u0443 (<code>coercion<\/code>).<\/p>\n<pre><code class=\"cpp\">if (best_candidate == NULL) {     if (nargs == 1 &amp;&amp; fargs != NIL &amp;&amp; fargnames == NIL)     {         OidtargetType = FuncNameAsType(funcname);          if (OidIsValid(targetType))         {            \/\/ ...         }    } }<\/code><\/pre>\n<p>\u041f\u043e\u0442\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0442\u0438\u043f\u043e\u0432 &#8212; <code>func_match_argtypes<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_func.c#L921\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_func.c<\/a>).<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0430\u0448\u043b\u0430\u0441\u044c \u043e\u0434\u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u043d\u0430. <\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0434 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u043e \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 <s>\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u044b\u0432\u043e\u043a<\/s> \u0432\u044b\u0437\u043e\u0432 <code>func_select_candidate<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_func.c#L1006\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_func.c<\/a>),  \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0448\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0434\u043e\u0448\u043b\u0438 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 &#8212; \u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043a\u044d\u0448, syscache<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445 \u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b, \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u201c\u0433\u043e\u0440\u044f\u0447\u0438\u0435\u201d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. \u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0438\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043a\u044d\u0448.<\/p>\n<p>\u0417\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043d\u0438\u043c \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043c\u043e\u0434\u0443\u043b\u044c <code>syscache<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/utils\/syscache.h\" rel=\"noopener noreferrer nofollow\">src\/include\/utils\/syscache.h<\/a>).<\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 <code>SysCacheIdentifier<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/utils\/syscache.h#L32\" rel=\"noopener noreferrer nofollow\">src\/include\/utils\/syscache.h<\/a>), \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043a\u044d\u0448\u0443 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 <code>SysCacheIdentifier<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0438\u0449\u0435\u043c.<\/p>\n<pre><code class=\"cpp\">\/*  *SysCache identifiers.  *  *The order of these identifiers must match the order  *of the entries in the array cacheinfo[] in syscache.c.  *Keep them in alphabetical order (renumbering only costs a  *backend rebuild).  *\/  enum SysCacheIdentifier { AGGFNOID = 0, AMNAME, AMOID, AMOPOPID, AMOPSTRATEGY, AMPROCNUM, ATTNAME, ATTNUM, AUTHMEMMEMROLE, AUTHMEMROLEMEM, AUTHNAME, AUTHOID, CASTSOURCETARGET, CLAAMNAMENSP, CLAOID, COLLNAMEENCNSP, COLLOID, CONDEFAULT, CONNAMENSP, CONSTROID, CONVOID, DATABASEOID, DEFACLROLENSPOBJ, ENUMOID, ENUMTYPOIDNAME, EVENTTRIGGERNAME, EVENTTRIGGEROID, FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPEROID, FOREIGNSERVERNAME, FOREIGNSERVEROID, FOREIGNTABLEREL, INDEXRELID, LANGNAME, LANGOID, NAMESPACENAME, NAMESPACEOID, OPERNAMENSP, OPEROID, OPFAMILYAMNAMENSP, OPFAMILYOID, PARAMETERACLNAME, PARAMETERACLOID, PARTRELID, PROCNAMEARGSNSP, PROCOID, PUBLICATIONNAME, PUBLICATIONNAMESPACE, PUBLICATIONNAMESPACEMAP, PUBLICATIONOID, PUBLICATIONREL, PUBLICATIONRELMAP, RANGEMULTIRANGE, RANGETYPE, RELNAMENSP, RELOID, REPLORIGIDENT, REPLORIGNAME, RULERELNAME, SEQRELID, STATEXTDATASTXOID, STATEXTNAMENSP, STATEXTOID, STATRELATTINH, SUBSCRIPTIONNAME, SUBSCRIPTIONOID, SUBSCRIPTIONRELMAP, TABLESPACEOID, TRFOID, TRFTYPELANG, TSCONFIGMAP, TSCONFIGNAMENSP, TSCONFIGOID, TSDICTNAMENSP, TSDICTOID, TSPARSERNAMENSP, TSPARSEROID, TSTEMPLATENAMENSP, TSTEMPLATEOID, TYPENAMENSP, TYPEOID, USERMAPPINGOID, USERMAPPINGUSERSERVER  #define SysCacheSize (USERMAPPINGUSERSERVER + 1) };<\/code><\/pre>\n<p>\u041a\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0438\u0437 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u044b, \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>InitCatalogCache<\/code> \u0438 <code>InitCatalogCachePhase2<\/code> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442 \u043a\u044d\u0448. \u041e\u0431\u0435 \u044d\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 <code>InitPostgres<\/code> \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0435 \u0441\u0442\u0430\u0440\u0442\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f 2 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 2 \u0444\u0430\u0437\u044b: \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u043e\u0431\u0449\u0430\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f (\u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u044d\u0448\u0430), \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.&nbsp;<\/p>\n<p>\u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u044d\u0448\u0435\u043c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ol>\n<li>\n<p>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0430\u043a\u0440\u043e\u0441 <code>SearchSysCacheList*<\/code> \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u043a\u043b\u044e\u0447\u0443. \u041f\u043e\u0434 <code>*<\/code> \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u0432\u0438\u0434\u0443 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043b\u044e\u0447\u0435\u0439 \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0438\u0434\u0435\u0442 \u043f\u043e\u0438\u0441\u043a. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 1<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">\/* Search syscache by name only *\/ catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(funcname));<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>\u041d\u0430\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>CatCList<\/code>. \u041e\u043d\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u044d\u0448\u0430. \u042d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u044d\u0442\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f <code>CatCTup<\/code><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">\/*  * A CatCList describes the result of a partial search, ie, a search using  * only the first K key columns of an N-key cache.  We store the keys used  * into the keys attribute to represent the stored key set.  The CatCList  * object contains links to cache entries for all the table rows satisfying  * the partial key.  (Note: none of these will be negative cache entries.)  *  * A CatCList is only a member of a per-cache list; we do not currently  * divide them into hash buckets.  *  * A list marked \"dead\" must not be returned by subsequent searches.  * However, it won't be physically deleted from the cache until its  * refcount goes to zero.  (A list should be marked dead if any of its  * member entries are dead.)  *  * If \"ordered\" is true then the member tuples appear in the order of the  * cache's underlying index.  This will be true in normal operation, but  * might not be true during bootstrap or recovery operations. (namespace.c  * is able to save some cycles when it is true.)  *\/ typedef struct catclist { intcl_magic;\/* for identifying CatCList entries *\/ #define CL_MAGIC   0x52765103  uint32hash_value;\/* hash value for lookup keys *\/  dlist_nodecache_elem;\/* list member of per-catcache list *\/  \/*  * Lookup keys for the entry, with the first nkeys elements being valid.  * All by-reference are separately allocated.  *\/ Datumkeys[CATCACHE_MAXKEYS];  intrefcount;\/* number of active references *\/ booldead;\/* dead but not yet removed? *\/ boolordered;\/* members listed in index order? *\/ shortnkeys;\/* number of lookup keys specified *\/ intn_members;\/* number of member tuples *\/ CatCache   *my_cache;\/* link to owning catcache *\/ CatCTup    *members[FLEXIBLE_ARRAY_MEMBER]; \/* members *\/ } CatCList;<\/code><\/pre>\n<pre><code class=\"cpp\">typedef struct catctup { intct_magic;\/* for identifying CatCTup entries *\/ #define CT_MAGIC   0x57261502  uint32hash_value;\/* hash value for this tuple's keys *\/  \/*  * Lookup keys for the entry. By-reference datums point into the tuple for  * positive cache entries, and are separately allocated for negative ones.  *\/ Datumkeys[CATCACHE_MAXKEYS];  \/*  * Each tuple in a cache is a member of a dlist that stores the elements  * of its hash bucket.  We keep each dlist in LRU order to speed repeated  * lookups.  *\/ dlist_nodecache_elem;\/* list member of per-bucket list *\/  \/*  * A tuple marked \"dead\" must not be returned by subsequent searches.  * However, it won't be physically deleted from the cache until its  * refcount goes to zero.  (If it's a member of a CatCList, the list's  * refcount must go to zero, too; also, remember to mark the list dead at  * the same time the tuple is marked.)  *  * A negative cache entry is an assertion that there is no tuple matching  * a particular key.  This is just as useful as a normal entry so far as  * avoiding catalog searches is concerned.  Management of positive and  * negative entries is identical.  *\/ intrefcount;\/* number of active references *\/ booldead;\/* dead but not yet removed? *\/ boolnegative;\/* negative cache entry? *\/ HeapTupleData tuple;\/* tuple management header *\/  \/*  * The tuple may also be a member of at most one CatCList.  (If a single  * catcache is list-searched with varying numbers of keys, we may have to  * make multiple entries for the same tuple because of this restriction.  * Currently, that's not expected to be common, so we accept the potential  * inefficiency.)  *\/ struct catclist *c_list;\/* containing CatCList, or NULL if none *\/  CatCache   *my_cache;\/* link to owning catcache *\/ \/* properly aligned tuple data follows, unless a negative entry *\/ } CatCTup;<\/code><\/pre>\n<ol start=\"3\">\n<li>\n<p>\u0418\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u043f\u043e \u0432\u0441\u0435\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c <code>members<\/code>, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u043c\u044b\u0435 \u0432 \u043d\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u043d\u0438\u043c\u0438<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">for (i = 0; i &lt; catlist-&gt;n_members; i++) { HeapTupleproctup = &amp;catlist-&gt;members[i]-&gt;tuple;     \/\/ ... }<\/code><\/pre>\n<ol start=\"4\">\n<li>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u043a\u044d\u0448 &#8212; <em>ReleaseSysCacheList<\/em><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">ReleaseSysCacheList(catlist);<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c \u043a\u0430\u043a \u044d\u0442\u043e\u0442 \u043a\u044d\u0448 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f.<\/p>\n<h4>\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/h4>\n<p>\u0421\u0430\u043c \u043a\u044d\u0448 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>SysCache<\/code>. \u042d\u0442\u043e \u043c\u0430\u0441\u0441\u0438\u0432 \u0442\u0438\u043f\u0430 <code>CatCache<\/code>&nbsp;<\/p>\n<pre><code class=\"cpp\">typedef struct catcache { intid;\/* cache identifier --- see syscache.h *\/ intcc_nbuckets;\/* # of hash buckets in this cache *\/ TupleDesccc_tupdesc;\/* tuple descriptor (copied from reldesc) *\/ dlist_head *cc_bucket;\/* hash buckets *\/ CCHashFNcc_hashfunc[CATCACHE_MAXKEYS];\/* hash function for each key *\/ CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS];\/* fast equal function for  * each key *\/ intcc_keyno[CATCACHE_MAXKEYS]; \/* AttrNumber of each key *\/ dlist_headcc_lists;\/* list of CatCList structs *\/ intcc_ntup;\/* # of tuples currently in this cache *\/ intcc_nkeys;\/* # of keys (1..CATCACHE_MAXKEYS) *\/ const char *cc_relname;\/* name of relation the tuples come from *\/ Oidcc_reloid;\/* OID of relation the tuples come from *\/ Oidcc_indexoid;\/* OID of index matching cache keys *\/ boolcc_relisshared; \/* is relation shared across databases? *\/ slist_nodecc_next;\/* list link *\/ ScanKeyData cc_skey[CATCACHE_MAXKEYS];\/* precomputed key info for heap  * scans *\/  \/*  * Keep these at the end, so that compiling catcache.c with CATCACHE_STATS  * doesn't break ABI for other modules  *\/ #ifdef CATCACHE_STATS longcc_searches;\/* total # searches against this cache *\/ longcc_hits;\/* # of matches against existing entry *\/ longcc_neg_hits;\/* # of matches against negative entry *\/ longcc_newloads;\/* # of successful loads of new entry *\/  \/*  * cc_searches - (cc_hits + cc_neg_hits + cc_newloads) is number of failed  * searches, each of which will result in loading a negative entry  *\/ longcc_invals;\/* # of entries invalidated from cache *\/ longcc_lsearches;\/* total # list-searches *\/ longcc_lhits;\/* # of matches against existing lists *\/ #endif } CatCache;   static CatCache *SysCache[SysCacheSize];<\/code><\/pre>\n<h4>\u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435<\/h4>\n<p>\u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 &#8212; \u043b\u0435\u043d\u0438\u0432\u043e:&nbsp; \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u0437\u043e\u0432\u0430 <code>SearchCatCacheList<\/code> \u043c\u044b \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u043f\u043e \u0438\u043c\u0435\u044e\u0449\u0438\u043c\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u043c, \u043d\u043e \u0435\u0441\u043b\u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043d\u0430\u0448\u043b\u0438, \u0442\u043e \u0432\u0445\u043e\u0434\u0438\u043c \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u044d\u0448\u0430. \u042d\u0442\u0430 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043e\u043a\u0430\u0439\u043c\u043b\u0435\u043d\u0430 <code>PG_TRY\/PG_CATCH<\/code> \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0442\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 \u0445\u044d\u0448 \u0442\u0430\u0431\u043b\u0438\u0446\u0443.<\/p>\n<pre><code class=\"cpp\">CatCList * SearchCatCacheList(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3) {     dlist_foreach(iter, &amp;cache-&gt;cc_lists)     {         \/\/ \u041f\u043e\u0438\u0441\u043a \u0432 \u043f\u0430\u043c\u044f\u0442\u0438     }          PG_TRY();     {         \/\/ \u0421\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445     }     PG_CATCH(); { \/\/ \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043a\u044d\u0448\u0430  PG_RE_THROW(); } PG_END_TRY();        foreach(ctlist_item, ctlist)     {         \/\/ \u041f\u043e\u0438\u0441\u043a \u0432 \u043d\u043e\u0432\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u044b     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h4>ORDER BY u.name<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0438\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 <code>ORDER BY u.name<\/code>.&nbsp; \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>transformSortClause<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L2606\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>)<\/p>\n<p>\u041f\u0430\u0440\u0441\u0438\u043d\u0433 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 (\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438) \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u0438\u0445 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a. \u0417\u0430 \u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0442 2 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<ul>\n<li>\n<p><code>findTargetlistEntrySQL99<\/code> &#8212; \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 SQL 99 (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L2046\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>)<\/p>\n<\/li>\n<li>\n<p><code>findTargetlistEntrySQL92<\/code> &#8212; \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 SQL 92 (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L1880\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>)<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0430\u043c \u0440\u0430\u0437\u0431\u043e\u0440 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438\u0442\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e \u0441\u043f\u0438\u0441\u043a\u0443 \u0438 \u0432\u044b\u0437\u043e\u0432\u0430 <code>transformTargetEntry<\/code> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430<\/p>\n<pre><code class=\"cpp\">foreach(olitem, orderlist) {     SortBy   *sortby = (SortBy *) lfirst(olitem);     TargetEntry *tle;      if (useSQL99)         tle = findTargetlistEntrySQL99(pstate, sortby-&gt;node,                                        targetlist, exprKind);     else         tle = findTargetlistEntrySQL92(pstate, sortby-&gt;node,                                        targetlist, exprKind);      sortlist = addTargetToSortList(pstate, tle,                                    sortlist, *targetlist, sortby); }<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 SQL 92 \u0438 SQL 99<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041e\u0434\u043d\u043e \u0438\u0437 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0439 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430\u0445 <em>SQL92<\/em> \u0438 <em>SQL99<\/em> \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043b\u043e\u0433\u0438\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0432 <code>ORDER BY<\/code> \u0438 <code>GROUP BY.<\/code><\/p>\n<p>\u0412 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0435 <em>SQL92<\/em> \u044d\u0442\u043e\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0438\u043b\u0438 \u043d\u043e\u043c\u0435\u0440\u0430 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 (\u0447\u0438\u0441\u043b\u0430). \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>SELECT name, age FROM users ORDER BY 2<\/code> &#8212; \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0443 (age)<\/p>\n<p>\u0412 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0435 <code>SQL99<\/code> \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 &#8212; \u044d\u0442\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0435\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b \u0442\u0430\u0431\u043b\u0438\u0446. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <\/p>\n<p><code>SELECT length(name), name from users ORDER BY age * 2<\/code> <\/p>\n<p>\u0432 <code>ORDER BY<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0430 \u043d\u0435 \u0441\u044b\u0440\u043e\u0439 \u0441\u0442\u043e\u043b\u0431\u0435\u0446.<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 \u043b\u043e\u0433\u0438\u043a\u0435 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f: \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c <em>SQL92<\/em>, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0438\u0437 <code>SELECT<\/code> \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0442\u043e \u0437\u0430\u043f\u0430\u0441\u043d\u044b\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433 <em>SQL99<\/em> \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c.<\/p>\n<pre><code class=\"cpp\">static TargetEntry * findTargetlistEntrySQL92(ParseState *pstate, Node *node, List **tlist,  ParseExprKind exprKind) {     \/\/ ... \u041f\u0430\u0440\u0441\u0438\u043d\u0433 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c SQL92 ...    \/*  * Otherwise, we have an expression, so process it per SQL99 rules.  *\/ return findTargetlistEntrySQL99(pstate, node, tlist, exprKind); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u043a\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0438\u0447\u0430-\u0444\u043b\u0430\u0433 <code>useSQL99<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0432 <code>transformSortClause<\/code>. <\/p>\n<pre><code class=\"cpp\">List * transformSortClause(ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool useSQL99) {     \/\/ ...     if (useSQL99)         tle = findTargetlistEntrySQL99(pstate, sortby-&gt;node,                                        targetlist, exprKind);     else         tle = findTargetlistEntrySQL92(pstate, sortby-&gt;node,                                        targetlist, exprKind);     \/\/ ... }<\/code><\/pre>\n<p><strong>GROUP BY u.name<\/strong><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0438\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 <code>GROUP BY<\/code>. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>transformGroupClause<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L2506\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>).<\/p>\n<p>\u0412 \u0441\u043f\u0438\u0441\u043a\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c 2 \u201c\u0433\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0445\u201d \u0441\u043b\u0443\u0447\u0430\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0440\u0430\u0437\u043d\u043e\u043c\u0443:&nbsp;<\/p>\n<ul>\n<li>\n<p>\u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 (\u0441\u0442\u043e\u043b\u0431\u0435\u0446, \u0444\u0443\u043d\u043a\u0446\u0438\u044f)<\/p>\n<\/li>\n<li>\n<p><code>GROUPING SET<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0441\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0435 <code>flat_grouplist<\/code>. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u044d\u0442\u043e\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f.<\/p>\n<p>\u0417\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>transformGroupClauseExpr<\/code>. \u0420\u0430\u0437\u0431\u043e\u0440 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0435\u0434\u0435\u0442\u0441\u044f \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 &#8212; <code>findTargetlistEntrySQL99<\/code> \u0438 <code>findTargetlistEntrySQL92<\/code>. \u041d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f: \u0443\u0447\u0435\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438.&nbsp;<\/p>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>SortGroupClause<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/nodes\/parsenodes.h#L1296\" rel=\"noopener noreferrer nofollow\">src\/include\/nodes\/parsenodes.h<\/a>).<\/p>\n<pre><code class=\"cpp\">\/*  * SortGroupClause -  *representation of ORDER BY, GROUP BY, PARTITION BY,  *DISTINCT, DISTINCT ON items  * ...  *\/ typedef struct SortGroupClause { NodeTagtype; IndextleSortGroupRef;\/* reference into targetlist *\/ Oideqop;\/* the equality operator ('=' op) *\/ Oidsortop;\/* the ordering operator ('&lt;' op), or 0 *\/ boolnulls_first;\/* do NULLs come before normal values? *\/ boolhashable;\/* can eqop be implemented by hashing? *\/ } SortGroupClause; <\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u043e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 (\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u0444\u043b\u0430\u0433 \u0445\u044d\u0448\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438), \u0430 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u043c\u044f\u0442\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f &#8212; \u0438\u043d\u0434\u0435\u043a\u0441 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 <code>SELECT<\/code>.<\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430 <code>transformGroupClauseExpr<\/code> \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u0438\u043f\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 <code>GROUPING SET<\/code> \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u043f\u043e\u0434\u0442\u0438\u043f\u0430. \u041f\u043e\u0434\u0442\u0438\u043f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>GroupingSetKind<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/nodes\/parsenodes.h#L1356\" rel=\"noopener noreferrer nofollow\">src\/include\/nodes\/parsenodes.h<\/a>)<\/p>\n<pre><code class=\"cpp\">typedef enum GroupingSetKind { GROUPING_SET_EMPTY, GROUPING_SET_SIMPLE, GROUPING_SET_ROLLUP, GROUPING_SET_CUBE, GROUPING_SET_SETS } GroupingSetKind;<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043b\u0443\u0447\u0430\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442  <code>transformGroupClauseExpr<\/code>, \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a <code>SortGroupClause<\/code> &#8212; \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438\u0437 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.<\/p>\n<h4>LIMIT 50<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 LIMIT. \u0417\u0430 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>transformLimitClause<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L1755\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>)<\/p>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 <code>transformExpr<\/code>. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>checkExprIsVarFree<\/code>. \u041e\u043d\u0430 \u043e\u0431\u0445\u043e\u0434\u0438\u0442 \u0434\u0435\u0440\u0435\u0432\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432 \u043b\u044e\u0431\u043e\u043c \u0438\u0437 \u0443\u0437\u043b\u043e\u0432.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <code>query_tree_walker<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/nodes\/nodeFuncs.c#L2393\" rel=\"noopener noreferrer nofollow\">src\/backend\/nodes\/nodeFuncs.c<\/a>)<\/p>\n<pre><code class=\"cpp\">bool query_tree_walker(Query *query,   bool (*walker) (),   void *context,   int flags)<\/code><\/pre>\n<p>\u0421\u0430\u043c \u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u044c &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c. <code>query_tree_walker<\/code> \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u0432\u0441\u0435\u043c \u0443\u0437\u043b\u0430\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u0435\u0435 \u043a \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0443\u0437\u043b\u0443.<\/p>\n<p>\u041f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u044c, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0438\u0439 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, &#8212; <code>contain_vars_of_level_walker<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/var.c#L449\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/util\/var.c<\/a>).<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e <code>transformLimitClause<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u043a\u0430\u043a \u0438 <code>LIMIT<\/code> \u0442\u0430\u043a \u0438 <code>OFFSET<\/code>. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0434\u043b\u044f <code>LIMIT<\/code>: \u0432 <code>FETCH FIRST \u2026 WITH TIES<\/code> \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>NULL<\/code><\/p>\n<pre><code class=\"cpp\">\/* * Don't allow NULLs in FETCH FIRST .. WITH TIES.  This test is ugly and * extremely simplistic, in that you can pass a NULL anyway by hiding it * inside an expression -- but this protects ruleutils against emitting an * unadorned NULL that's not accepted back by the grammar. *\/ if (exprKind == EXPR_KIND_LIMIT &amp;&amp; limitOption == LIMIT_OPTION_WITH_TIES &amp;&amp;     IsA(clause, A_Const) &amp;&amp; castNode(A_Const, clause)-&gt;isnull)   ereport(ERROR,           (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),            errmsg(\"row count cannot be null in FETCH FIRST ... WITH TIES clause\")));<\/code><\/pre>\n<h2>\u041f\u0440\u0435\u0434\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/h2>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0430\u0436\u043d\u044b\u0439 \u044d\u0442\u0430\u043f &#8212; \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041d\u043e \u043f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0435\u0434\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.<\/p>\n<h4>LIMIT<\/h4>\n<p>&nbsp;\u041f\u0435\u0440\u0432\u044b\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 <code>LIMIT\/OFFSET<\/code> \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>preprocess_limit<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/plan\/planner.c#L2367\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>). \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0430\u0440\u0441\u0438\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u0437\u043b\u0430 <code>LIMIT<\/code>, \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0446\u0435\u043d\u043a\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 &#8212; <code>tuple_fraction<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>tuple_fraction<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041e\u0434\u043d\u043e \u0438\u0437 \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432 PostgreSQL &#8212; \u0443\u043c\u043d\u044b\u0439 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a. \u041e\u0434\u0438\u043d \u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0442\u0430\u043a\u043e\u0439 \u0440\u0435\u043f\u0443\u0442\u0430\u0446\u0438\u0438 &#8212; \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435. \u0412 GUC \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 <a href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/13\/runtime-config-query#GUC-CURSOR-TUPLE-FRACTION\" rel=\"noopener noreferrer nofollow\">\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440<\/a> <code>cursor_tuple_fraction<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0446\u0435\u043d\u043a\u0443 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043e\u043d \u0440\u0430\u0432\u0435\u043d <code>0,1<\/code> (10%)<\/p>\n<p>\u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043f\u043b\u0430\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f: \u0435\u0441\u043b\u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043c\u0430\u043b\u043e \u0441\u0442\u0440\u043e\u043a, \u0442\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u043d \u0441 \u0441\u0430\u043c\u044b\u043c \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0441\u0442\u0430\u0440\u0442\u043e\u043c.<\/p>\n<p>\u041d\u043e <code>cursor_tuple_fraction<\/code> &#8212; \u043d\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f &#8212; <code>preprocess_limit<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>tuple_fraction<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043b\u0430\u043d\u0430.<\/p>\n<p>\u041a\u043e\u0434 \u0435\u0433\u043e \u0440\u0430\u0441\u0447\u0435\u0442\u0430 &#8212; \u0434\u0435\u0440\u0435\u0432\u043e \u0432\u044b\u0431\u043e\u0440\u0430<\/p>\n<pre><code class=\"cpp\">static double preprocess_limit(PlannerInfo *root, double tuple_fraction,  int64 *offset_est, int64 *count_est) {     \/\/ ...      if (*count_est != 0) { \/*  * A LIMIT clause limits the absolute number of tuples returned.  * However, if it's not a constant LIMIT then we have to guess; for  * lack of a better idea, assume 10% of the plan's result is wanted.  *\/ if (*count_est &lt; 0 || *offset_est &lt; 0) { \/* LIMIT or OFFSET is an expression ... punt ... *\/ limit_fraction = 0.10; } else { \/* LIMIT (plus OFFSET, if any) is max number of tuples needed *\/ limit_fraction = (double) *count_est + (double) *offset_est; }  \/*  * If we have absolute limits from both caller and LIMIT, use the  * smaller value; likewise if they are both fractional.  If one is  * fractional and the other absolute, we can't easily determine which  * is smaller, but we use the heuristic that the absolute will usually  * be smaller.  *\/ if (tuple_fraction &gt;= 1.0) { if (limit_fraction &gt;= 1.0) { \/* both absolute *\/ tuple_fraction = Min(tuple_fraction, limit_fraction); } else { \/* caller absolute, limit fractional; use caller's value *\/ } } else if (tuple_fraction &gt; 0.0) { if (limit_fraction &gt;= 1.0) { \/* caller fractional, limit absolute; use limit *\/ tuple_fraction = limit_fraction; } else { \/* both fractional *\/ tuple_fraction = Min(tuple_fraction, limit_fraction); } } else { \/* no info from caller, just use limit *\/ tuple_fraction = limit_fraction; } } else if (*offset_est != 0 &amp;&amp; tuple_fraction &gt; 0.0) { \/*  * We have an OFFSET but no LIMIT.  This acts entirely differently  * from the LIMIT case: here, we need to increase rather than decrease  * the caller's tuple_fraction, because the OFFSET acts to cause more  * tuples to be fetched instead of fewer.  This only matters if we got  * a tuple_fraction &gt; 0, however.  *  * As above, use 10% if OFFSET is present but unestimatable.  *\/ if (*offset_est &lt; 0) limit_fraction = 0.10; else limit_fraction = (double) *offset_est;  \/*  * If we have absolute counts from both caller and OFFSET, add them  * together; likewise if they are both fractional.  If one is  * fractional and the other absolute, we want to take the larger, and  * we heuristically assume that's the fractional one.  *\/ if (tuple_fraction &gt;= 1.0) { if (limit_fraction &gt;= 1.0) { \/* both absolute, so add them together *\/ tuple_fraction += limit_fraction; } else { \/* caller absolute, limit fractional; use limit *\/ tuple_fraction = limit_fraction; } } else { if (limit_fraction &gt;= 1.0) { \/* caller fractional, limit absolute; use caller's value *\/ } else { \/* both fractional, so add them together *\/ tuple_fraction += limit_fraction; if (tuple_fraction &gt;= 1.0) tuple_fraction = 0.0;\/* assume fetch all *\/ } } }  return tuple_fraction;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h4>GROUP BY<\/h4>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f <code>GROUP BY<\/code> &#8212; \u0432\u044b\u0437\u043e\u0432 <code>preprocess_groupclause<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/plan\/planner.c#L2772\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>).<\/p>\n<p>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#8212; \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>GROUP BY<\/code> \u0438 <code>ORDER BY<\/code> \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0442\u043e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0438 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043e\u0434\u043d\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0435\u0439.<\/p>\n<h4>SELECT \u2026<\/h4>\n<p>\u0417\u0430 \u043f\u0440\u0435\u0434\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>preprocess_targetlist<\/code><em> <\/em>(src\/backend\/<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/prep\/preptlist.c#L62\" rel=\"noopener noreferrer nofollow\">optimizer\/prep\/preptlist.c<\/a>). \u0412\u043a\u0440\u0430\u0442\u0446\u0435, \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u044b \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 FOR UPDATE\/SHARE<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0431\u044b\u043b\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043e <code>FOR UPDATE\/SHARE<\/code>, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0438 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0434\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a \u043d\u0438\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c. <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 &#8212; \u0435\u0441\u043b\u0438 \u0432 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u0435\u0441\u0442\u044c \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438, \u0442\u043e \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435 (\u043c\u0443\u0441\u043e\u0440\u043d\u044b\u0435, junk) \u0441\u0442\u043e\u043b\u0431\u0446\u044b, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 &#8212; \u043f\u043e\u043c\u0435\u0447\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<pre><code class=\"cpp\">foreach(lc, root-&gt;rowMarks) {     PlanRowMark *rc = (PlanRowMark *) lfirst(lc);      \/\/ ...        if (rc-&gt;allMarkTypes &amp; ~(1 &lt;&lt; ROW_MARK_COPY))     {         \/* Need to fetch TID *\/         var = makeVar(rc-&gt;rti,                       SelfItemPointerAttributeNumber,                       TIDOID,                       -1,                       InvalidOid,                       0);         snprintf(resname, sizeof(resname), \"ctid%u\", rc-&gt;rowmarkId);         tle = makeTargetEntry((Expr *) var,                               list_length(tlist) + 1,                               pstrdup(resname),                               true);         tlist = lappend(tlist, tle);     }     if (rc-&gt;allMarkTypes &amp; (1 &lt;&lt; ROW_MARK_COPY))     {         \/* Need the whole row as a junk var *\/         var = makeWholeRowVar(rt_fetch(rc-&gt;rti, range_table),                               rc-&gt;rti,                               0,                               false);         snprintf(resname, sizeof(resname), \"wholerow%u\", rc-&gt;rowmarkId);         tle = makeTargetEntry((Expr *) var,                               list_length(tlist) + 1,                               pstrdup(resname),                               true);         tlist = lappend(tlist, tle);     }     \/\/ ... }<\/code><\/pre>\n<p>\u0418\u043c\u0435\u043d\u0430 \u044d\u0442\u0438\u0445 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0438\u043c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u0421\u0430\u043c\u0438 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 <code>PlanRowMark<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * PlanRowMark -  *   plan-time representation of FOR [KEY] UPDATE\/SHARE clauses  * ...  *\/ typedef struct PlanRowMark { NodeTagtype; Indexrti;\/* range table index of markable relation *\/ Indexprti;\/* range table index of parent relation *\/ IndexrowmarkId;\/* unique identifier for resjunk columns *\/ RowMarkType markType;\/* see enum above *\/ intallMarkTypes;\/* OR of (1&lt;&lt;markType) for all children *\/ LockClauseStrength strength;\/* LockingClause's strength, or LCS_NONE *\/ LockWaitPolicy waitPolicy;\/* NOWAIT and SKIP LOCKED options *\/ boolisParent;\/* true if this is a \"dummy\" parent entry *\/ } PlanRowMark;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0443\u0442\u0435\u0439<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u0440\u0435\u0434\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430, \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0443\u0442\u0435\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. <\/p>\n<p>\u041f\u0443\u0442\u044c &#8212; \u044d\u0442\u043e \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043b\u0430\u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0443\u0442\u044c &#8212; \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 &#8212; \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 <code>Path<\/code>. \u041e\u043d \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u043c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0434\u0440\u0443\u0433\u0438\u0445.<\/p>\n<pre><code class=\"cpp\">\/*  * Type \"Path\" is used as-is for sequential-scan paths, as well as some other  * simple plan types that we don't need any extra information in the path for.  * For other path types it is the first component of a larger struct.  *  * \"pathtype\" is the NodeTag of the Plan node we could build from this Path.  * It is partially redundant with the Path's NodeTag, but allows us to use  * the same Path type for multiple Plan types when there is no need to  * distinguish the Plan type during path processing.  *  * \"parent\" identifies the relation this Path scans, and \"pathtarget\"  * describes the precise set of output columns the Path would compute.  * In simple cases all Paths for a given rel share the same targetlist,  * which we represent by having path-&gt;pathtarget equal to parent-&gt;reltarget.  *  * \"param_info\", if not NULL, links to a ParamPathInfo that identifies outer  * relation(s) that provide parameter values to each scan of this path.  * That means this path can only be joined to those rels by means of nestloop  * joins with this path on the inside.  Also note that a parameterized path  * is responsible for testing all \"movable\" joinclauses involving this rel  * and the specified outer rel(s).  *  * \"rows\" is the same as parent-&gt;rows in simple paths, but in parameterized  * paths and UniquePaths it can be less than parent-&gt;rows, reflecting the  * fact that we've filtered by extra join conditions or removed duplicates.  *  * \"pathkeys\" is a List of PathKey nodes (see above), describing the sort  * ordering of the path's output rows.  *\/ typedef struct Path { NodeTagtype;  NodeTagpathtype;\/* tag identifying scan\/join method *\/  RelOptInfo *parent;\/* the relation this path can build *\/ PathTarget *pathtarget;\/* list of Vars\/Exprs, cost, width *\/  ParamPathInfo *param_info;\/* parameterization info, or NULL if none *\/  boolparallel_aware; \/* engage parallel-aware logic? *\/ boolparallel_safe;\/* OK to use as part of parallel plan? *\/ intparallel_workers;\/* desired # of workers; 0 = not parallel *\/  \/* estimated size\/costs for path (see costsize.c for more info) *\/ Cardinality rows;\/* estimated number of result tuples *\/ Coststartup_cost;\/* cost expended before fetching any tuples *\/ Costtotal_cost;\/* total cost (assuming all tuples fetched) *\/  List   *pathkeys;\/* sort ordering of path's output *\/ \/* pathkeys is a List of PathKey nodes; see above *\/ } Path;<\/code><\/pre>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0437\u043e\u0432\u043e\u043c <code>query_planner<\/code><em>. <\/em>\u0417\u0430\u0442\u0435\u043c, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 (<code>GROUP BY<\/code>, <code>ORDER BY<\/code>) \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u0432\u043e\u0438 \u043f\u0443\u0442\u0438.<\/p>\n<h4>\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430<\/h4>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0443\u0442\u0435\u0439, \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>make_sort_input_target<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/plan\/planner.c#L5553\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>).<\/p>\n<p>\u0412\u043d\u0430\u0447\u0430\u043b\u0435, \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0432 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0435\u0433\u043e \u0442\u0438\u043f\u0430\/\u0441\u0432\u043e\u0439\u0441\u0442\u0432, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430.&nbsp;<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0432 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f <code>volatile<\/code> \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u0442\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u043b\u0430\u0433 <code>have_volatile<\/code><\/p>\n<pre><code class=\"cpp\">foreach(lc, final_target-&gt;exprs) {     \/\/ ...     if (contain_volatile_functions((Node *) expr))     {         \/* Unconditionally postpone *\/         postpone_col[i] = true;         have_volatile = true;     }     \/\/ ... }<\/code><\/pre>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u044b, \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043e. \u0414\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u0438\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0430\u0441\u0441\u0438\u0432 \u0444\u043b\u0430\u0433\u043e\u0432.&nbsp;\u042d\u0442\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435: <code>postpone_col[i] = true<\/code>.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 <code>PathTarget<\/code> \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 PathTarget<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043f\u0443\u0442\u0438, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u044b \u043d\u0435 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u044b \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u0443\u0442\u0438 \u0438\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 <code>PathTarget<\/code><\/p>\n<pre><code class=\"cpp\">typedef struct PathTarget { NodeTagtype; List   *exprs;\/* list of expressions to be computed *\/ Index   *sortgrouprefs;\/* corresponding sort\/group refnos, or 0 *\/ QualCostcost;\/* cost of evaluating the expressions *\/ intwidth;\/* estimated avg width of result tuples *\/ VolatileFunctionStatus has_volatile_expr;\/* indicates if exprs contain  * any volatile functions. *\/ } PathTarget;<\/code><\/pre>\n<p>\u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0438. \u0421\u0430\u043c\u0438 \u043f\u043b\u0430\u043d\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u043f\u043e\u0441\u043b\u0435, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u0438\u0445 \u043f\u0443\u0442\u0435\u0439 <\/p>\n<\/div>\n<\/details>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c &#8212; \u0441\u043f\u0435\u0440\u0432\u0430 \u0438\u0434\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0442\u0435, \u0447\u0442\u043e \u043c\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043a\u0430\u043a \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435.<\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>set_pathtarget_cost_width<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/path\/costsize.c#L5991\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/path\/costsize.c<\/a>) \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0443\u0442\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>set_pathtarget_cost_width<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0435 \u043d\u043e\u0432\u044b\u0435 \u043f\u0443\u0442\u0438, \u043f\u043e\u0434\u0447\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u043c\u0443 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0443:&nbsp;<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0443\u0442\u0438 (<code>PathTarget<\/code>)<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0435\u0433\u043e \u0434\u0430\u043d\u043d\u044b\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0437\u043e\u0432 <code>set_pathtarget_cost_width<\/code>&nbsp;<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438&nbsp;<\/p>\n<\/li>\n<\/ol>\n<p>P.S. 3 \u0438 4 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u0432 <code>return set_pathtarget_cost_width<\/code><\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#8212; \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u0443\u0442\u0438.&nbsp;<\/p>\n<p>\u0421\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 <code>QualCost<\/code><\/p>\n<pre><code class=\"cpp\">typedef double Cost;\/* execution cost (in page-access units) *\/  \/*  * The cost estimate produced by cost_qual_eval() includes both a one-time  * (startup) cost, and a per-tuple cost.  *\/ typedef struct QualCost { Coststartup;\/* one-time cost *\/ Costper_tuple;\/* per-evaluation cost *\/ } QualCost;<\/code><\/pre>\n<p>\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u0432\u0441\u0435\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u0432 \u043f\u0443\u0442\u0438, \u0438, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0435\u0433\u043e \u0442\u0438\u043f\u0430, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c.<\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0435 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e 2 \u0442\u0438\u043f\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439: \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u041f\u0440\u0438\u0447\u0435\u043c \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u0443\u0442\u0438 \u043c\u043e\u0433\u0443\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f &#8212; \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0432\u043d\u0430 0<\/p>\n<pre><code class=\"cpp\">foreach(lc, target-&gt;exprs) {     Node   *node = (Node *) lfirst(lc);      if (IsA(node, Var))     {         Var   *var = (Var *) node;         int32item_width;          \/\/ ...                  tuple_width += item_width;     }     else     {         \/*          * Handle general expressions using type info.          *\/         int32item_width;         QualCostcost;          \/\/ ...                target-&gt;cost.startup += cost.startup;         target-&gt;cost.per_tuple += cost.per_tuple;     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d Visitor &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>cost_qual_eval_node<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/path\/costsize.c#L4376\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/path\/costsize.c<\/a>) \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u044c <code>cost_qual_eval_walker<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0445\u043e\u0434\u0438\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0443\u0437\u0435\u043b \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f.&nbsp;<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 &#8212; \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>add_function_cost<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/plancat.c#L2006\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/util\/plancat.c<\/a>), \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438 \u043f\u043e\u0434\u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<pre><code class=\"cpp\">static bool cost_qual_eval_walker(Node *node, cost_qual_eval_context *context) { if (node == NULL) return false;  if (IsA(node, RestrictInfo)) { \/\/ ... }  if (IsA(node, FuncExpr)) { add_function_cost(context-&gt;root, ((FuncExpr *) node)-&gt;funcid, node,   &amp;context-&gt;total); } else if (IsA(node, OpExpr) ||  IsA(node, DistinctExpr) ||  IsA(node, NullIfExpr)) { \/\/ ... } else if (IsA(node, ScalarArrayOpExpr)) { \/\/ ... } else if (IsA(node, Aggref) ||  IsA(node, WindowFunc)) { \/\/ ... } else if (IsA(node, GroupingFunc)) { \/\/ ... } else if (IsA(node, CoerceViaIO)) { \/\/ ... } else if (IsA(node, ArrayCoerceExpr)) { \/\/ ... } else if (IsA(node, RowCompareExpr)) { \/\/ ... } else if (IsA(node, MinMaxExpr) ||  IsA(node, SQLValueFunction) ||  IsA(node, XmlExpr) ||  IsA(node, CoerceToDomain) ||  IsA(node, NextValueExpr)) { \/\/ ... } else if (IsA(node, CurrentOfExpr)) { \/\/ ... } else if (IsA(node, SubLink)) { \/\/ ... } else if (IsA(node, SubPlan)) { \/\/ ... } else if (IsA(node, AlternativeSubPlan)) { \/\/ ... } else if (IsA(node, PlaceHolderVar)) { \/\/ ... }  \/* recurse into children *\/ return expression_tree_walker(node, cost_qual_eval_walker,   (void *) context); } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h4>\u041f\u0443\u0442\u0438 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438<\/h4>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u0443\u0442\u0435\u0439 \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>make_group_input_target<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/plancat.c#L2006\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>).<\/p>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u0432\u0441\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b \u0434\u0435\u043b\u044f\u0442\u0441\u044f \u043d\u0430 2 \u0433\u0440\u0443\u043f\u043f\u044b: \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0438 \u043d\u0435\u0442 \u0432 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0435.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043f\u0443\u0442\u044c \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b, \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0432 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0435, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>set_pathtarget_cost_width<\/code> \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u043e\u0432<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u0443\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b, \u043e\u043d\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u0435 <code>upper_targets<\/code>. \u042d\u0442\u043e \u043c\u0430\u0441\u0441\u0438\u0432 \u0445\u0440\u0430\u043d\u044f\u0449\u0438\u0439 \u0432 \u0441\u0435\u0431\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438. \u0414\u043b\u044f \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u0438 \u043f\u043e \u043d\u0435\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 <code>UpperRelationKind<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * This enum identifies the different types of \"upper\" (post-scan\/join)  * relations that we might deal with during planning.  *\/ typedef enum UpperRelationKind { UPPERREL_SETOP,\/* result of UNION\/INTERSECT\/EXCEPT, if any *\/ UPPERREL_PARTIAL_GROUP_AGG, \/* result of partial grouping\/aggregation, if  * any *\/ UPPERREL_GROUP_AGG,\/* result of grouping\/aggregation, if any *\/ UPPERREL_WINDOW,\/* result of window functions, if any *\/ UPPERREL_PARTIAL_DISTINCT,\/* result of partial \"SELECT DISTINCT\", if any *\/ UPPERREL_DISTINCT,\/* result of \"SELECT DISTINCT\", if any *\/ UPPERREL_ORDERED,\/* result of ORDER BY, if any *\/ UPPERREL_FINAL\/* result of any remaining top-level actions *\/ \/* NB: UPPERREL_FINAL must be last enum entry; it's used to size arrays *\/ } UpperRelationKind;<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u0435\u0434\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043b\u0430\u043d\u044b<\/p>\n<pre><code class=\"cpp\">\/*  * Save the various upper-rel PathTargets we just computed into  * root-&gt;upper_targets[].  The core code doesn't use this, but it  * provides a convenient place for extensions to get at the info.  For  * consistency, we save all the intermediate targets, even though some  * of the corresponding upperrels might not be needed for this query.  *\/ root-&gt;upper_targets[UPPERREL_FINAL] = final_target; root-&gt;upper_targets[UPPERREL_ORDERED] = final_target; root-&gt;upper_targets[UPPERREL_PARTIAL_DISTINCT] = sort_input_target; root-&gt;upper_targets[UPPERREL_DISTINCT] = sort_input_target; root-&gt;upper_targets[UPPERREL_WINDOW] = sort_input_target; root-&gt;upper_targets[UPPERREL_GROUP_AGG] = grouping_target;<\/code><\/pre>\n<h4>\u041f\u043b\u0430\u043d\u044b \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438<\/h4>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u0430\u043d\u043e\u0432.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u043d, \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0443. \u042d\u0442\u043e <code>create_grouping_paths<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>degenerate_grouping_paths<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 Postgres \u0435\u0441\u0442\u044c \u043f\u043e\u043d\u044f\u0442\u0438\u0435 <code>degenerate grouping<\/code>. \u042d\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 <code>GROUP BY<\/code>, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0435\u0441\u0442\u044c <code>HAVING<\/code> \u0438\u043b\u0438 <code>GROUPING SET<\/code>.&nbsp;<\/p>\n<p>\u0414\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.&nbsp;<\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0441\u043b\u0443\u0447\u0430\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432 <code>is_degenerate_grouping<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/plan\/planner.c#L3511\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>)<\/p>\n<pre><code class=\"cpp\">\/*  * is_degenerate_grouping  *  * A degenerate grouping is one in which the query has a HAVING qual and\/or  * grouping sets, but no aggregates and no GROUP BY (which implies that the  * grouping sets are all empty).  *\/ static bool is_degenerate_grouping(PlannerInfo *root) { Query   *parse = root-&gt;parse;  return (root-&gt;hasHavingQual || parse-&gt;groupingSets) &amp;&amp; !parse-&gt;hasAggs &amp;&amp; parse-&gt;groupClause == NIL; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0438\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0443\u0437\u0435\u043b &#8212; <code>GroupResultPath<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * GroupResultPath represents use of a Result plan node to compute the  * output of a degenerate GROUP BY case, wherein we know we should produce  * exactly one row, which might then be filtered by a HAVING qual.  *  * Note that quals is a list of bare clauses, not RestrictInfos.  *\/ typedef struct GroupResultPath { Pathpath; List   *quals; } GroupResultPath;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u043f\u043b\u0430\u043d\u043e\u0432 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0432\u0430\u0436\u043d\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b \u043b\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0438\u043b\u0438 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<p>\u042d\u0442\u0438 \u0444\u043b\u0430\u0433\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043c\u0430\u043a\u0440\u043e\u0441\u0430\u043c\u0438&nbsp;<\/p>\n<pre><code class=\"cpp\">\/*  * Various flags indicating what kinds of grouping are possible.  *  * GROUPING_CAN_USE_SORT should be set if it's possible to perform  * sort-based implementations of grouping.  When grouping sets are in use,  * this will be true if sorting is potentially usable for any of the grouping  * sets, even if it's not usable for all of them.  *  * GROUPING_CAN_USE_HASH should be set if it's possible to perform  * hash-based implementations of grouping.  *  * GROUPING_CAN_PARTIAL_AGG should be set if the aggregation is of a type  * for which we support partial aggregation (not, for example, grouping sets).  * It says nothing about parallel-safety or the availability of suitable paths.  *\/ #define GROUPING_CAN_USE_SORT       0x0001 #define GROUPING_CAN_USE_HASH       0x0002 #define GROUPING_CAN_PARTIAL_AGG0x0004<\/code><\/pre>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c<\/p>\n<pre><code class=\"cpp\">if ((parse-&gt;groupClause != NIL &amp;&amp;      root-&gt;numOrderedAggs == 0 &amp;&amp;      (gd ? gd-&gt;any_hashable : grouping_is_hashable(parse-&gt;groupClause))))     flags |= GROUPING_CAN_USE_HASH;<\/code><\/pre>\n<p>\u0421\u0430\u043c\u0430 \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0443\u0442\u0435\u0439 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432 <code>add_paths_to_grouping_rel<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/plan\/planner.c#L6214\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>). \u0417\u0434\u0435\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0443\u0442\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0441 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u043e\u0439.<\/p>\n<pre><code class=\"cpp\">static void add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,   RelOptInfo *grouped_rel,   RelOptInfo *partially_grouped_rel,   const AggClauseCosts *agg_costs,   grouping_sets_data *gd, double dNumGroups,   GroupPathExtraData *extra) { Query   *parse = root-&gt;parse; Path   *cheapest_path = input_rel-&gt;cheapest_total_path; ListCell   *lc; boolcan_hash = (extra-&gt;flags &amp; GROUPING_CAN_USE_HASH) != 0; boolcan_sort = (extra-&gt;flags &amp; GROUPING_CAN_USE_SORT) != 0; List   *havingQual = (List *) extra-&gt;havingQual; AggClauseCosts *agg_final_costs = &amp;extra-&gt;agg_final_costs;  if (can_sort) { \/*  * Use any available suitably-sorted path as input, and also consider  * sorting the cheapest-total path.  *\/ foreach(lc, input_rel-&gt;pathlist) {             \/\/ ...         }     }      if (can_hash) { if (parse-&gt;groupingSets) { \/*  * Try for a hash-only groupingsets path over unsorted input.  *\/ consider_groupingsets_paths(root, grouped_rel, cheapest_path, false, true, gd, agg_costs, dNumGroups); } else { \/*  * Generate a HashAgg Path.  We just need an Agg over the  * cheapest-total input path, since input order won't matter.  *\/ add_path(grouped_rel, (Path *)  create_agg_path(root, grouped_rel,  cheapest_path,  grouped_rel-&gt;reltarget,  AGG_HASHED,  AGGSPLIT_SIMPLE,  parse-&gt;groupClause,  havingQual,  agg_costs,  dNumGroups)); }          \/\/ ...     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u043b\u0443\u0447\u0430\u044f <code>GROUP BY u.name<\/code> \u0440\u0430\u0431\u043e\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439.&nbsp;<\/p>\n<p>\u0424\u043b\u0430\u0433 <code>can_hash<\/code> \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u0430 \u0432\u0435\u0442\u043a\u0430.<\/p>\n<ol>\n<li>\n<p>\u0411\u0435\u0440\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u0443\u0442\u044c (\u043c\u0430\u0441\u0441\u0438\u0432 <code>pathlist<\/code>)<\/p>\n<\/li>\n<li>\n<p>GROUPING SET \u0443 \u043d\u0430\u0441 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043e\u0437\u0434\u0430\u0435\u043c <code>HashAgg<\/code> \u0443\u0437\u0435\u043b (<code>create_agg_path<\/code>)<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>set_cheapest<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/pathnode.c#L244\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/util\/pathnode.c<\/a>), \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043b\u0443\u0447\u0448\u0438\u0435 \u043f\u0443\u0442\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>set_cheapest<\/summary>\n<div class=\"spoiler__content\">\n<p><code>set_cheapest<\/code> &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043b\u0443\u0447\u0448\u0438\u0445 \u043f\u0443\u0442\u044f\u0445<\/p>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u043b\u0430\u043d\u043e\u0432, \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>RelOptInfo<\/code>. \u0412 \u043d\u0435\u0439 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u043f\u043e\u043b\u044f, \u0445\u0440\u0430\u043d\u044f\u0449\u0438\u0435 <em>\u0442\u0435\u043a\u0443\u0449\u0438\u0435<\/em> \u043b\u0443\u0447\u0448\u0438\u0435 \u043f\u0443\u0442\u0438<\/p>\n<pre><code class=\"cpp\">typedef struct RelOptInfo {     \/\/ ...     struct Path *cheapest_startup_path; struct Path *cheapest_total_path; struct Path *cheapest_unique_path; List   *cheapest_parameterized_paths;     \/\/ ... }<\/code><\/pre>\n<p>\u041d\u043e \u044d\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0435\u043f\u043e\u043a &#8212; \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0433\u043e\u0434\u043d\u044b\u0435 \u043f\u0443\u0442\u0438. \u0414\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>set_cheapest<\/code>.<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438  \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0445\u043e\u0434 \u043f\u043e \u0432\u0441\u0435\u043c \u043f\u0443\u0442\u044f\u043c \u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0441 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u043b\u0443\u0447\u0448\u0438\u043c<\/p>\n<pre><code class=\"cpp\">void set_cheapest(RelOptInfo *parent_rel) {     Path *cheapest_startup_path; Path *cheapest_total_path; Path *best_param_path;      cheapest_startup_path = cheapest_total_path = best_param_path = NULL;    foreach(p, parent_rel-&gt;pathlist) { Path   *path = (Path *) lfirst(p); intcmp;              if (path-&gt;param_info) {             \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f         } else { \/* Unparameterized path, so consider it for cheapest slots *\/ if (cheapest_total_path == NULL) { cheapest_startup_path = cheapest_total_path = path; continue; }  \/*  * If we find two paths of identical costs, try to keep the  * better-sorted one.  The paths might have unrelated sort  * orderings, in which case we can only guess which might be  * better to keep, but if one is superior then we definitely  * should keep that one.  *\/ cmp = compare_path_costs(cheapest_startup_path, path, STARTUP_COST); if (cmp &gt; 0 || (cmp == 0 &amp;&amp;  compare_pathkeys(cheapest_startup_path-&gt;pathkeys,   path-&gt;pathkeys) == PATHKEYS_BETTER2)) cheapest_startup_path = path;  cmp = compare_path_costs(cheapest_total_path, path, TOTAL_COST); if (cmp &gt; 0 || (cmp == 0 &amp;&amp;  compare_pathkeys(cheapest_total_path-&gt;pathkeys,   path-&gt;pathkeys) == PATHKEYS_BETTER2)) cheapest_total_path = path; }     }      \/\/ ...        parent_rel-&gt;cheapest_startup_path = cheapest_startup_path; parent_rel-&gt;cheapest_total_path = cheapest_total_path; parent_rel-&gt;cheapest_unique_path = NULL;\/* computed only if needed *\/ parent_rel-&gt;cheapest_parameterized_paths = parameterized_paths; }<\/code><\/pre>\n<p>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0443\u0442\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <code>compare_path_costs <\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/pathnode.c#L71\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/util\/pathnode.c<\/a>)<\/p>\n<pre><code class=\"cpp\">\/*  * compare_path_costs  *  Return -1, 0, or +1 according as path1 is cheaper, the same cost,  *  or more expensive than path2 for the specified criterion.  *\/ int compare_path_costs(Path *path1, Path *path2, CostSelector criterion) { if (criterion == STARTUP_COST) { if (path1-&gt;startup_cost &lt; path2-&gt;startup_cost) return -1; if (path1-&gt;startup_cost &gt; path2-&gt;startup_cost) return +1;  \/*  * If paths have the same startup cost (not at all unlikely), order  * them by total cost.  *\/ if (path1-&gt;total_cost &lt; path2-&gt;total_cost) return -1; if (path1-&gt;total_cost &gt; path2-&gt;total_cost) return +1; } else { if (path1-&gt;total_cost &lt; path2-&gt;total_cost) return -1; if (path1-&gt;total_cost &gt; path2-&gt;total_cost) return +1;  \/*  * If paths have the same total cost, order them by startup cost.  *\/ if (path1-&gt;startup_cost &lt; path2-&gt;startup_cost) return -1; if (path1-&gt;startup_cost &gt; path2-&gt;startup_cost) return +1; } return 0; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h4>\u041f\u043b\u0430\u043d\u044b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438<\/h4>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u043e\u0432, \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443. \u0417\u0430 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>create_ordered_paths<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/plan\/planner.c#L4663\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/plan\/planner.c<\/a>).<\/p>\n<p>\u0417\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u043b\u0430\u043d\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>create_sort_path<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/pathnode.c#L2942\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/util\/pathnode.c<\/a>), \u043b\u0438\u0431\u043e <code>create_incremental_sort_path<\/code>, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430.<\/p>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0443\u0442\u044c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u0437\u0435\u043b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 <\/p>\n<pre><code class=\"cpp\">foreach(lc, input_rel-&gt;pathlist) {     Path   *input_path = (Path *) lfirst(lc);     Path   *sorted_path = input_path;     boolis_sorted;     intpresorted_keys;      is_sorted = pathkeys_count_contained_in(root-&gt;sort_pathkeys,                                             input_path-&gt;pathkeys, &amp;presorted_keys);      if (is_sorted)     {         \/* Use the input path as is, but add a projection step if needed *\/         if (sorted_path-&gt;pathtarget != target)             sorted_path = apply_projection_to_path(root, ordered_rel,                                                    sorted_path, target);          add_path(ordered_rel, sorted_path);     }     else     {         \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u044f\u0432\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438        } }<\/code><\/pre>\n<h4>\u041f\u043b\u0430\u043d LIMIT\/OFFSET<\/h4>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u0433\u0434\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043f\u043b\u0430\u043d \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d, \u043a \u043d\u0435\u043c\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0443\u0437\u043b\u044b <code>LIMIT<\/code> \u0438\/\u0438\u043b\u0438 <code>OFFSET<\/code>. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 <code>create_limit_path<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/optimizer\/util\/pathnode.c#L3737\" rel=\"noopener noreferrer nofollow\">src\/backend\/optimizer\/util\/pathnode.c<\/a>).<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u043b\u0430\u043d\u0430<\/h4>\n<p>\u0421\u043f\u0443\u0441\u0442\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u0432 \u0432\u0432\u0435\u0440\u0445 \u043f\u043e \u0441\u0442\u0435\u043a\u0443 \u0432\u044b\u0437\u043e\u0432\u043e\u0432, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043f\u043b\u0430\u043d \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0432 <code>standard_planner<\/code><\/p>\n<pre><code class=\"cpp\">\/* Select best Path and turn it into a Plan *\/ final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL); best_path = get_cheapest_fractional_path(final_rel, tuple_fraction); top_plan = create_plan(root, best_path);<\/code><\/pre>\n<p>\u041f\u043b\u0430\u043d \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d, \u043f\u043e\u0440\u0430 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e.<\/p>\n<h2>\u042d\u0442\u0430\u043f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>ExecutePlan<\/code>.<\/p>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e:<\/p>\n<ol>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u043f\u043b\u0430\u043d, \u0430 \u043f\u043e\u0440\u0442\u0430\u043b. \u041e\u043d \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u043b\u0430\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0443\u0437\u0435\u043b \u201c\u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f\u201d \u043e\u0442 <code>PlanState<\/code>&nbsp;<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 <code>PlanState<\/code> \u201c\u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u201d <code>ExecProcNodeMtd<\/code> &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0443\u0437\u043b\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e <code>LIMIT<\/code>, \u0442\u043e \u0441\u043b\u0435\u0434\u0438\u0442 \u0437\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a)<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cpp\">\/* ----------------  *PlanState node  *  * We never actually instantiate any PlanState nodes; this is just the common  * abstract superclass for all PlanState-type nodes.  * ----------------  *\/ typedef struct PlanState { NodeTagtype;  Plan   *plan;\/* associated Plan node *\/  EState   *state;\/* at execution time, states of individual  * nodes point to one EState for the whole  * top-level plan *\/  ExecProcNodeMtd ExecProcNode;\/* function to return next tuple *\/ ExecProcNodeMtd ExecProcNodeReal;\/* actual function, if above is a  * wrapper *\/  Instrumentation *instrument;\/* Optional runtime stats for this node *\/ WorkerInstrumentation *worker_instrument;\/* per-worker instrumentation *\/  \/* Per-worker JIT instrumentation *\/ struct SharedJitInstrumentation *worker_jit_instrument;  \/*  * Common structural data for all Plan types.  These links to subsidiary  * state trees parallel links in the associated plan tree (except for the  * subPlan list, which does not exist in the plan tree).  *\/ ExprState  *qual;\/* boolean qual condition *\/ struct PlanState *lefttree; \/* input plan tree(s) *\/ struct PlanState *righttree;  List   *initPlan;\/* Init SubPlanState nodes (un-correlated expr  * subselects) *\/ List   *subPlan;\/* SubPlanState nodes in my expressions *\/  \/*  * State for management of parameter-change-driven rescanning  *\/ Bitmapset  *chgParam;\/* set of IDs of changed Params *\/  \/*  * Other run-time state needed by most if not all node types.  *\/ TupleDescps_ResultTupleDesc; \/* node's return type *\/ TupleTableSlot *ps_ResultTupleSlot; \/* slot for my result tuples *\/ ExprContext *ps_ExprContext;\/* node's expression-evaluation context *\/ ProjectionInfo *ps_ProjInfo;\/* info for doing tuple projection *\/  boolasync_capable;\/* true if node is async-capable *\/  \/*  * Scanslot's descriptor if known. This is a bit of a hack, but otherwise  * it's hard for expression compilation to optimize based on the  * descriptor, without encoding knowledge about all executor nodes.  *\/ TupleDescscandesc;  \/*  * Define the slot types for inner, outer and scanslots for expression  * contexts with this state as a parent.  If *opsset is set, then  * *opsfixed indicates whether *ops is guaranteed to be the type of slot  * used. That means that every slot in the corresponding  * ExprContext.ecxt_*tuple will point to a slot of that type, while  * evaluating the expression.  If *opsfixed is false, but *ops is set,  * that indicates the most likely type of slot.  *  * The scan* fields are set by ExecInitScanTupleSlot(). If that's not  * called, nodes can initialize the fields themselves.  *  * If outer\/inneropsset is false, the information is inferred on-demand  * using ExecGetResultSlotOps() on -&gt;righttree\/lefttree, using the  * corresponding node's resultops* fields.  *  * The result* fields are automatically set when ExecInitResultSlot is  * used (be it directly or when the slot is created by  * ExecAssignScanProjectionInfo() \/  * ExecConditionalAssignProjectionInfo()).  If no projection is necessary  * ExecConditionalAssignProjectionInfo() defaults those fields to the scan  * operations.  *\/ const TupleTableSlotOps *scanops; const TupleTableSlotOps *outerops; const TupleTableSlotOps *innerops; const TupleTableSlotOps *resultops; boolscanopsfixed; boolouteropsfixed; boolinneropsfixed; boolresultopsfixed; boolscanopsset; boolouteropsset; boolinneropsset; boolresultopsset; } PlanState;<\/code><\/pre>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441\u043e\u0437\u0434\u0430\u043b\u0441\u044f \u043f\u043b\u0430\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>LIMIT<\/p>\n<\/li>\n<li>\n<p>ORDER BY<\/p>\n<\/li>\n<li>\n<p>GROUP BY<\/p>\n<\/li>\n<li>\n<p>SEQ SCAN<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u0440\u0442\u0435\u0436\u0430 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0443\u0437\u043b\u044b (\u044d\u0442\u0430\u043f\u044b).<\/p>\n<h4>LIMIT<\/h4>\n<p>\u041a\u043e\u0440\u043d\u0435\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u0434\u0435\u0440\u0435\u0432\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u0443\u0434\u0435\u0442 <code>LIMIT<\/code>.<\/p>\n<p>\u0423\u0437\u0435\u043b, \u0435\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439, &#8212; <code>LimitState<\/code><\/p>\n<pre><code class=\"cpp\">typedef struct LimitState { PlanStateps;\/* its first field is NodeTag *\/ ExprState  *limitOffset;\/* OFFSET parameter, or NULL if none *\/ ExprState  *limitCount;\/* COUNT parameter, or NULL if none *\/ LimitOption limitOption;\/* limit specification type *\/ int64offset;\/* current OFFSET value *\/ int64count;\/* current COUNT, if any *\/ boolnoCount;\/* if true, ignore count *\/ LimitStateCond lstate;\/* state machine status, as above *\/ int64position;\/* 1-based index of last tuple returned *\/ TupleTableSlot *subSlot;\/* tuple last obtained from subplan *\/ ExprState  *eqfunction;\/* tuple equality qual in case of WITH TIES  * option *\/ TupleTableSlot *last_slot;\/* slot for evaluation of ties *\/ } LimitState;<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>ExecProcNodeMtd<\/code> &#8212; <code>ExecLimit<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/executor\/nodeLimit.c#L41\" rel=\"noopener noreferrer nofollow\">src\/backend\/executor\/nodeLimit.c<\/a>).<\/p>\n<p>\u0423\u0437\u0435\u043b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 \u043c\u0430\u0448\u0438\u043d\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>LimitStateCond<\/code><\/p>\n<pre><code class=\"cpp\">typedef enum { LIMIT_INITIAL,\/* initial state for LIMIT node *\/ LIMIT_RESCAN,\/* rescan after recomputing parameters *\/ LIMIT_EMPTY,\/* there are no returnable rows *\/ LIMIT_INWINDOW,\/* have returned a row in the window *\/ LIMIT_WINDOWEND_TIES,\/* have returned a tied row *\/ LIMIT_SUBPLANEOF,\/* at EOF of subplan (within window) *\/ LIMIT_WINDOWEND,\/* stepped off end of window *\/ LIMIT_WINDOWSTART\/* stepped off beginning of window *\/ } LimitStateCond;<\/code><\/pre>\n<p>\u0414\u043b\u044f <code>LIMIT 50<\/code> \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438:<\/p>\n<ol>\n<li>\n<p><code>LIMIT_INITIAL<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u042d\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0417\u0434\u0435\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>recompute_limits<\/code>, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f offset (\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c) \u0438 count (\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0437\u044f\u0442\u044c). \u0418\u0437 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u044b \u0441\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 <code>LIMIT_RESCAN<\/code>.<\/p>\n<ol start=\"2\">\n<li>\n<p><code>LIMIT_RESCAN<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u042d\u0442\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u0434\u043f\u043b\u0430\u043d (\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0442 \u043d\u0435\u0433\u043e \u043a\u043e\u0440\u0442\u0435\u0436\u0438) \u0434\u043e \u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439. \u0415\u0441\u043b\u0438 \u043f\u0440\u0435\u0434\u0435\u043b\u0430 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438, \u0442\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 <code>LIMIT_INWINDOW<\/code>.<\/p>\n<ol start=\"3\">\n<li>\n<p><code>LIMIT_INWINDOW<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u044d\u0442\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u0435\u0439 <code>WITH TIES<\/code>. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043c\u044b \u043f\u043e\u043f\u0430\u043b\u0438 \u0441\u044e\u0434\u0430, \u0442\u043e \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438 <code>50<\/code> \u0441\u0442\u0440\u043e\u043a \u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 (\u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435 \u0432\u0435\u0440\u043d\u0443\u043b\u0441\u044f <code>null<\/code>).&nbsp;<\/p>\n<p><code>WITH TIES<\/code> \u043c\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 &#8212; <code>LIMIT_WINDOWEND<\/code>.<\/p>\n<ol start=\"4\">\n<li>\n<p><code>LIMIT_WINDOWEND<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043b\u044f \u043d\u0430\u0441 \u044d\u0442\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043a\u0443\u0440\u0441\u043e\u0440 \u0434\u0432\u0438\u0436\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438).<\/p>\n<ol start=\"5\">\n<li>\n<p>* \u0415\u0441\u043b\u0438 \u0441\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u0430\u043a, \u0447\u0442\u043e \u0438\u0437 \u043f\u043e\u0434\u043f\u043b\u0430\u043d\u0430 \u0432\u0435\u0440\u043d\u0443\u043b\u043e\u0441\u044c \u043c\u0435\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0432 <code>LIMIT<\/code>, \u0442\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u043f\u043e\u0441\u043b\u0435 <code>LIMIT_RESCAN<\/code> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 &#8212; <code>LIMIT_EMPTY<\/code>. \u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u043e \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>LIMIT_WINDOWEND<\/code> &#8212; \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>NULL<\/code> (\u043d\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430\u0437\u0430\u0434)<\/p>\n<\/li>\n<\/ol>\n<h4>SORT<\/h4>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u043e\u0434\u0443\u0437\u0435\u043b &#8212; \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430. \u0415\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 <code>SortState<\/code><\/p>\n<pre><code class=\"cpp\">typedef struct SortState { ScanStatess;\/* its first field is NodeTag *\/ boolrandomAccess;\/* need random access to sort output? *\/ boolbounded;\/* is the result set bounded? *\/ int64bound;\/* if bounded, how many tuples are needed *\/ boolsort_Done;\/* sort completed yet? *\/ boolbounded_Done;\/* value of bounded we did the sort with *\/ int64bound_Done;\/* value of bound we did the sort with *\/ void   *tuplesortstate; \/* private state of tuplesort.c *\/ boolam_worker;\/* are we a worker? *\/ booldatumSort;\/* Datum sort instead of tuple sort? *\/ SharedSortInfo *shared_info;\/* one entry per worker *\/ } SortState;<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>ExecProcNodeMtd<\/code> &#8212; <code>ExecSort<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/executor\/nodeSort.c#L50\" rel=\"noopener noreferrer nofollow\">src\/backend\/executor\/nodeSort.c<\/a>).<\/p>\n<p>\u0424\u043b\u0430\u0433 <code>sort_Done<\/code> \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u043e \u0442\u043e\u043c, \u0431\u044b\u043b\u0430 \u043b\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0443\u0436\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0430 (\u043f\u0435\u0440\u0432\u044b\u0439 \u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a). \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438. <\/p>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>Tuplesortstate<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u0430\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0441\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0434\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0430 \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 (\u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f, \u0438\u043c\u0435\u0435\u0442 \u0442\u0438\u043f <code>void*<\/code>, \u0441\u043c. \u0432\u044b\u0448\u0435)<\/p>\n<pre><code class=\"cpp\">struct Tuplesortstate { TupSortStatus status;\/* enumerated value as shown above *\/ intnKeys;\/* number of columns in sort key *\/ intsortopt;\/* Bitmask of flags used to setup sort *\/ boolbounded;\/* did caller specify a maximum number of  * tuples to return? *\/ boolboundUsed;\/* true if we made use of a bounded heap *\/ intbound;\/* if bounded, the maximum number of tuples *\/ booltuples;\/* Can SortTuple.tuple ever be set? *\/ int64availMem;\/* remaining memory available, in bytes *\/ int64allowedMem;\/* total memory allowed, in bytes *\/ intmaxTapes;\/* max number of input tapes to merge in each  * pass *\/ int64maxSpace;\/* maximum amount of space occupied among sort  * of groups, either in-memory or on-disk *\/ boolisMaxSpaceDisk; \/* true when maxSpace is value for on-disk  * space, false when it's value for in-memory  * space *\/ TupSortStatus maxSpaceStatus;\/* sort status when maxSpace was reached *\/ MemoryContext maincontext;\/* memory context for tuple sort metadata that  * persists across multiple batches *\/ MemoryContext sortcontext;\/* memory context holding most sort data *\/ MemoryContext tuplecontext; \/* sub-context of sortcontext for tuple data *\/ LogicalTapeSet *tapeset;\/* logtape.c object for tapes in a temp file *\/  \/*  * These function pointers decouple the routines that must know what kind  * of tuple we are sorting from the routines that don't need to know it.  * They are set up by the tuplesort_begin_xxx routines.  *  * Function to compare two tuples; result is per qsort() convention, ie:  * &lt;0, 0, &gt;0 according as a&lt;b, a=b, a&gt;b.  The API must match  * qsort_arg_comparator.  *\/ SortTupleComparator comparetup;  \/*  * Function to copy a supplied input tuple into palloc'd space and set up  * its SortTuple representation (ie, set tuple\/datum1\/isnull1).  Also,  * state-&gt;availMem must be decreased by the amount of space used for the  * tuple copy (note the SortTuple struct itself is not counted).  *\/ void(*copytup) (Tuplesortstate *state, SortTuple *stup, void *tup);  \/*  * Function to write a stored tuple onto tape.  The representation of the  * tuple on tape need not be the same as it is in memory; requirements on  * the tape representation are given below.  Unless the slab allocator is  * used, after writing the tuple, pfree() the out-of-line data (not the  * SortTuple struct!), and increase state-&gt;availMem by the amount of  * memory space thereby released.  *\/ void(*writetup) (Tuplesortstate *state, LogicalTape *tape,  SortTuple *stup);  \/*  * Function to read a stored tuple from tape back into memory. 'len' is  * the already-read length of the stored tuple.  The tuple is allocated  * from the slab memory arena, or is palloc'd, see readtup_alloc().  *\/ void(*readtup) (Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int len);  \/*  * Whether SortTuple's datum1 and isnull1 members are maintained by the  * above routines.  If not, some sort specializations are disabled.  *\/ boolhaveDatum1;  \/*  * This array holds the tuples now in sort memory.  If we are in state  * INITIAL, the tuples are in no particular order; if we are in state  * SORTEDINMEM, the tuples are in final sorted order; in states BUILDRUNS  * and FINALMERGE, the tuples are organized in \"heap\" order per Algorithm  * H.  In state SORTEDONTAPE, the array is not used.  *\/ SortTuple  *memtuples;\/* array of SortTuple structs *\/ intmemtupcount;\/* number of tuples currently present *\/ intmemtupsize;\/* allocated length of memtuples array *\/ boolgrowmemtuples;\/* memtuples' growth still underway? *\/  \/*  * Memory for tuples is sometimes allocated using a simple slab allocator,  * rather than with palloc().  Currently, we switch to slab allocation  * when we start merging.  Merging only needs to keep a small, fixed  * number of tuples in memory at any time, so we can avoid the  * palloc\/pfree overhead by recycling a fixed number of fixed-size slots  * to hold the tuples.  *  * For the slab, we use one large allocation, divided into SLAB_SLOT_SIZE  * slots.  The allocation is sized to have one slot per tape, plus one  * additional slot.  We need that many slots to hold all the tuples kept  * in the heap during merge, plus the one we have last returned from the  * sort, with tuplesort_gettuple.  *  * Initially, all the slots are kept in a linked list of free slots.  When  * a tuple is read from a tape, it is put to the next available slot, if  * it fits.  If the tuple is larger than SLAB_SLOT_SIZE, it is palloc'd  * instead.  *  * When we're done processing a tuple, we return the slot back to the free  * list, or pfree() if it was palloc'd.  We know that a tuple was  * allocated from the slab, if its pointer value is between  * slabMemoryBegin and -End.  *  * When the slab allocator is used, the USEMEM\/LACKMEM mechanism of  * tracking memory usage is not used.  *\/ boolslabAllocatorUsed;  char   *slabMemoryBegin;\/* beginning of slab memory arena *\/ char   *slabMemoryEnd;\/* end of slab memory arena *\/ SlabSlot   *slabFreeHead;\/* head of free list *\/  \/* Memory used for input and output tape buffers. *\/ size_ttape_buffer_mem;  \/*  * When we return a tuple to the caller in tuplesort_gettuple_XXX, that  * came from a tape (that is, in TSS_SORTEDONTAPE or TSS_FINALMERGE  * modes), we remember the tuple in 'lastReturnedTuple', so that we can  * recycle the memory on next gettuple call.  *\/ void   *lastReturnedTuple;  \/*  * While building initial runs, this is the current output run number.  * Afterwards, it is the number of initial runs we made.  *\/ intcurrentRun;  \/*  * Logical tapes, for merging.  *  * The initial runs are written in the output tapes.  In each merge pass,  * the output tapes of the previous pass become the input tapes, and new  * output tapes are created as needed.  When nInputTapes equals  * nInputRuns, there is only one merge pass left.  *\/ LogicalTape **inputTapes; intnInputTapes; intnInputRuns;  LogicalTape **outputTapes; intnOutputTapes; intnOutputRuns;  LogicalTape *destTape;\/* current output tape *\/  \/*  * These variables are used after completion of sorting to keep track of  * the next tuple to return.  (In the tape case, the tape's current read  * position is also critical state.)  *\/ LogicalTape *result_tape;\/* actual tape of finished output *\/ intcurrent;\/* array index (only used if SORTEDINMEM) *\/ booleof_reached;\/* reached EOF (needed for cursors) *\/  \/* markpos_xxx holds marked position for mark and restore *\/ longmarkpos_block;\/* tape block# (only used if SORTEDONTAPE) *\/ intmarkpos_offset; \/* saved \"current\", or offset in tape block *\/ boolmarkpos_eof;\/* saved \"eof_reached\" *\/  \/*  * These variables are used during parallel sorting.  *  * worker is our worker identifier.  Follows the general convention that  * -1 value relates to a leader tuplesort, and values &gt;= 0 worker  * tuplesorts. (-1 can also be a serial tuplesort.)  *  * shared is mutable shared memory state, which is used to coordinate  * parallel sorts.  *  * nParticipants is the number of worker Tuplesortstates known by the  * leader to have actually been launched, which implies that they must  * finish a run that the leader needs to merge.  Typically includes a  * worker state held by the leader process itself.  Set in the leader  * Tuplesortstate only.  *\/ intworker; Sharedsort *shared; intnParticipants;  \/*  * The sortKeys variable is used by every case other than the hash index  * case; it is set by tuplesort_begin_xxx.  tupDesc is only used by the  * MinimalTuple and CLUSTER routines, though.  *\/ TupleDesctupDesc; SortSupport sortKeys;\/* array of length nKeys *\/  \/*  * This variable is shared by the single-key MinimalTuple case and the  * Datum case (which both use qsort_ssup()).  Otherwise, it's NULL.  The  * presence of a value in this field is also checked by various sort  * specialization functions as an optimization when comparing the leading  * key in a tiebreak situation to determine if there are any subsequent  * keys to sort on.  *\/ SortSupport onlyKey;  \/*  * Additional state for managing \"abbreviated key\" sortsupport routines  * (which currently may be used by all cases except the hash index case).  * Tracks the intervals at which the optimization's effectiveness is  * tested.  *\/ int64abbrevNext;\/* Tuple # at which to next check  * applicability *\/  \/*  * These variables are specific to the CLUSTER case; they are set by  * tuplesort_begin_cluster.  *\/ IndexInfo  *indexInfo;\/* info about index being used for reference *\/ EState   *estate;\/* for evaluating index expressions *\/  \/*  * These variables are specific to the IndexTuple case; they are set by  * tuplesort_begin_index_xxx and used only by the IndexTuple routines.  *\/ RelationheapRel;\/* table the index is being built on *\/ RelationindexRel;\/* index being built *\/  \/* These are specific to the index_btree subcase: *\/ boolenforceUnique;\/* complain if we find duplicate tuples *\/ booluniqueNullsNotDistinct; \/* unique constraint null treatment *\/  \/* These are specific to the index_hash subcase: *\/ uint32high_mask;\/* masks for sortable part of hash code *\/ uint32low_mask; uint32max_buckets;  \/*  * These variables are specific to the Datum case; they are set by  * tuplesort_begin_datum and used only by the DatumTuple routines.  *\/ OiddatumType; \/* we need typelen in order to know how to copy the Datums. *\/ intdatumTypeLen;  \/*  * Resource snapshot for time of sort start.  *\/ #ifdef TRACE_SORT PGRUsageru_start; #endif }; <\/code><\/pre>\n<p>\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043b\u0438\u0431\u043e \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u0435 (\u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0435) \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043b\u0438\u0431\u043e \u0446\u0435\u043b\u044b\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0438. \u0414\u043b\u044f \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0445 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u0431\u044b\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f <code>Tuplesortstate<\/code>. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u0441\u0432\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0448\u0430\u0433\u0438: \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043e\u0442 \u0442\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 <\/p>\n<pre><code class=\"cpp\">if (node-&gt;datumSort) {     ExecClearTuple(slot);     if (tuplesort_getdatum(tuplesortstate, ScanDirectionIsForward(dir),                            &amp;(slot-&gt;tts_values[0]), &amp;(slot-&gt;tts_isnull[0]), NULL))         ExecStoreVirtualTuple(slot); } else     (void) tuplesort_gettupleslot(tuplesortstate,                                   ScanDirectionIsForward(dir),                                   false, slot, NULL);<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Datum<\/summary>\n<div class=\"spoiler__content\">\n<p>Datum \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u043d\u0430\u0434 \u201c\u043b\u044e\u0431\u044b\u043c\u201d \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c. \u041e\u043d \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0441\u0435\u0432\u0434\u043e\u043d\u0438\u043c\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441 \u0441\u044b\u0440\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0438\u0447\u0435\u0433\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0433\u043e \u0441 \u043d\u0438\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f <\/p>\n<pre><code class=\"cpp\">\/*  * A Datum contains either a value of a pass-by-value type or a pointer to a  * value of a pass-by-reference type.  Therefore, we require:  *  * sizeof(Datum) == sizeof(void *) == 4 or 8  *  * The macros below and the analogous macros for other types should be used to  * convert between a Datum and the appropriate C type.  *\/  typedef uintptr_t Datum;<\/code><\/pre>\n<p>\u041d\u043e \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0438\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043a\u0443\u0447\u0430 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <code>int<\/code> \u0435\u0441\u0442\u044c 2 \u043c\u0430\u043a\u0440\u043e\u0441\u0430<\/p>\n<pre><code class=\"cpp\">\/*  * DatumGetInt32  *Returns 32-bit integer value of a datum.  *\/  #define DatumGetInt32(X) ((int32) (X))  \/*  * Int32GetDatum  *Returns datum representation for a 32-bit integer.  *\/  #define Int32GetDatum(X) ((Datum) (X))<\/code><\/pre>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435 \u043c\u0430\u043a\u0440\u043e\u0441\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 + \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0442\u0438\u043f\u044b Postgres, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>TransactionId<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * DatumGetTransactionId  *Returns transaction identifier value of a datum.  *\/  #define DatumGetTransactionId(X) ((TransactionId) (X))  \/*  * TransactionIdGetDatum  *Returns datum representation for a transaction identifier.  *\/  #define TransactionIdGetDatum(X) ((Datum) (X))<\/code><\/pre>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>NullableDatum<\/code>, \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u043c\u0438 <code>null<\/code>. \u041d\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u044f\u0432\u043d\u043e \u043e\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f &#8212; \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 jit \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f llvm.<\/p>\n<pre><code class=\"cpp\">typedef struct NullableDatum { #define FIELDNO_NULLABLE_DATUM_DATUM 0 Datumvalue; #define FIELDNO_NULLABLE_DATUM_ISNULL 1 boolisnull; \/* due to alignment padding this could be used for flags for free *\/ } NullableDatum;<\/code><\/pre>\n<p>\u0418\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u044b\u0448\u0435, \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 <code>Tuplesortstate<\/code> \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f <code>Datum<\/code> \u0438\u0437 \u043f\u043e\u0434\u0443\u0437\u043b\u0430. <\/p>\n<pre><code class=\"cpp\">if (node-&gt;datumSort) {     for (;;)     {         slot = ExecProcNode(outerNode);          if (TupIsNull(slot))             break;         slot_getsomeattrs(slot, 1);         tuplesort_putdatum(tuplesortstate,                            slot-&gt;tts_values[0],                            slot-&gt;tts_isnull[0]);     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>tuplesort_putdatum<\/code>. \u041a\u0430\u043a \u044f \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b, \u044f\u0432\u043d\u044b\u0439 <code>NullableDatum<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0435 \u0432\u0435\u0437\u0434\u0435. \u0417\u0434\u0435\u0441\u044c \u0444\u043b\u0430\u0433\u0438 <code>null<\/code> \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0432 \u0432\u0438\u0434\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430.<\/p>\n<p>\u0412\u043e\u0442 \u0442\u0430\u043a Datum \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 <code>Tuplesortstate<\/code> (\u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 <code>Datum<\/code> \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043a\u043e\u0440\u0442\u0435\u0436\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043e\u0447\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f)<\/p>\n<pre><code class=\"cpp\">void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull) {     \/\/ ...     if (isNull || !state-&gt;tuples) { \/*  * Set datum1 to zeroed representation for NULLs (to be consistent,  * and to support cheap inequality tests for NULL abbreviated keys).  *\/ stup.datum1 = !isNull ? val : (Datum) 0; stup.isnull1 = isNull; stup.tuple = NULL;\/* no separate storage *\/ MemoryContextSwitchTo(state-&gt;sortcontext); } else { Datumoriginal = datumCopy(val, false, state-&gt;datumTypeLen);  stup.isnull1 = false; stup.tuple = DatumGetPointer(original);         \/\/ ...     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u043e \u0432\u043e\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 &#8212; \u0435\u0434\u0438\u043d\u0430\u044f \u0434\u043b\u044f \u0432\u0441\u0435\u0445. \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u043e\u043d\u0430 \u0432 <code>tuplesort_performsort<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/utils\/sort\/tuplesort.c#L2197\" rel=\"noopener noreferrer nofollow\">src\/backend\/utils\/sort\/tuplesort.c<\/a>).<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u043c\u0435\u0436\u0434\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f\u043c\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c\u044b\u043c\u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>TupSortStatus<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u0430\u043c\u044f\u0442\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c quick sort<\/p>\n<pre><code class=\"cpp\">\/*  * All tuples have been provided; finish the sort.  *\/ void tuplesort_performsort(Tuplesortstate *state) {     switch (state-&gt;status) { case TSS_INITIAL:  \/*  * We were able to accumulate all the tuples within the allowed  * amount of memory, or leader to take over worker tapes  *\/ if (SERIAL(state)) { \/* Just qsort 'em and we're done *\/ tuplesort_sort_memtuples(state); state-&gt;status = TSS_SORTEDINMEM; }               \/\/ ...     } }<\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043e\u043a\u043e\u043d\u0447\u0435\u043d\u0430 \u0438 \u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u043e\u0441\u044c \u0432 <code>SortState<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0436\u0435 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0438.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 <code>Tuplesortstate<\/code> \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>tuplesort_gettupleslot<\/code><em> <\/em>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/utils\/sort\/tuplesort.c#L2562\" rel=\"noopener noreferrer nofollow\">src\/backend\/utils\/sort\/tuplesort.c<\/a>).<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0430 \u0438\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0435 &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430 (\u043d\u043e \u044d\u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u0430 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438)<\/p>\n<pre><code class=\"cpp\">switch (state-&gt;status) {     case TSS_SORTEDINMEM:         Assert(forward || state-&gt;sortopt &amp; TUPLESORT_RANDOMACCESS);         Assert(!state-&gt;slabAllocatorUsed);         if (forward)         {             if (state-&gt;current &lt; state-&gt;memtupcount)             {                 *stup = state-&gt;memtuples[state-&gt;current++];                 return true;             }             state-&gt;eof_reached = true;              \/*              * Complain if caller tries to retrieve more tuples than              * originally asked for in a bounded sort.  This is because              * returning EOF here might be the wrong thing.              *\/             if (state-&gt;bounded &amp;&amp; state-&gt;current &gt;= state-&gt;bound)                 elog(ERROR, \"retrieved too many tuples in a bounded sort\");              return false;         }     \/\/ ... }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0447\u0438\u0442\u0430\u0442\u044c \u043a\u043e\u0440\u0442\u0435\u0436\u0438 \u0438\u0437 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430.<\/p>\n<h4>GROUP<\/h4>\n<p>\u041d\u0438\u0436\u0435\u043b\u0435\u0436\u0430\u0449\u0438\u0439 \u0443\u0437\u0435\u043b &#8212; \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430. \u0421\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u043c\u043d\u043e\u0433\u043e. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0447\u0442\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0443 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f &#8212; <code>AggState<\/code><\/p>\n<pre><code class=\"cs\">typedef struct AggState { ScanStatess;\/* its first field is NodeTag *\/ List   *aggs;\/* all Aggref nodes in targetlist &amp; quals *\/ intnumaggs;\/* length of list (could be zero!) *\/ intnumtrans;\/* number of pertrans items *\/ AggStrategy aggstrategy;\/* strategy mode *\/ AggSplitaggsplit;\/* agg-splitting mode, see nodes.h *\/ AggStatePerPhase phase;\/* pointer to current phase data *\/ intnumphases;\/* number of phases (including phase 0) *\/ intcurrent_phase;\/* current phase number *\/ AggStatePerAgg peragg;\/* per-Aggref information *\/ AggStatePerTrans pertrans;\/* per-Trans state information *\/ ExprContext *hashcontext;\/* econtexts for long-lived data (hashtable) *\/ ExprContext **aggcontexts;\/* econtexts for long-lived data (per GS) *\/ ExprContext *tmpcontext;\/* econtext for input expressions *\/ #define FIELDNO_AGGSTATE_CURAGGCONTEXT 14 ExprContext *curaggcontext; \/* currently active aggcontext *\/ AggStatePerAgg curperagg;\/* currently active aggregate, if any *\/ #define FIELDNO_AGGSTATE_CURPERTRANS 16 AggStatePerTrans curpertrans;\/* currently active trans state, if any *\/ boolinput_done;\/* indicates end of input *\/ boolagg_done;\/* indicates completion of Agg scan *\/ intprojected_set;\/* The last projected grouping set *\/ #define FIELDNO_AGGSTATE_CURRENT_SET 20 intcurrent_set;\/* The current grouping set being evaluated *\/ Bitmapset  *grouped_cols;\/* grouped cols in current projection *\/ List   *all_grouped_cols;\/* list of all grouped cols in DESC order *\/ Bitmapset  *colnos_needed;\/* all columns needed from the outer plan *\/ intmax_colno_needed;\/* highest colno needed from outer plan *\/ boolall_cols_needed;\/* are all cols from outer plan needed? *\/ \/* These fields are for grouping set phase data *\/ intmaxsets;\/* The max number of sets in any phase *\/ AggStatePerPhase phases;\/* array of all phases *\/ Tuplesortstate *sort_in;\/* sorted input to phases &gt; 1 *\/ Tuplesortstate *sort_out;\/* input is copied here for next phase *\/ TupleTableSlot *sort_slot;\/* slot for sort results *\/ \/* these fields are used in AGG_PLAIN and AGG_SORTED modes: *\/ AggStatePerGroup *pergroups;\/* grouping set indexed array of per-group  * pointers *\/ HeapTuplegrp_firstTuple; \/* copy of first tuple of current group *\/ \/* these fields are used in AGG_HASHED and AGG_MIXED modes: *\/ booltable_filled;\/* hash table filled yet? *\/ intnum_hashes; MemoryContext hash_metacxt; \/* memory for hash table itself *\/ struct LogicalTapeSet *hash_tapeset;\/* tape set for hash spill tapes *\/ struct HashAggSpill *hash_spills;\/* HashAggSpill for each grouping set,  * exists only during first pass *\/ TupleTableSlot *hash_spill_rslot;\/* for reading spill files *\/ TupleTableSlot *hash_spill_wslot;\/* for writing spill files *\/ List   *hash_batches;\/* hash batches remaining to be processed *\/ boolhash_ever_spilled;\/* ever spilled during this execution? *\/ boolhash_spill_mode;\/* we hit a limit during the current batch  * and we must not create new groups *\/ Sizehash_mem_limit; \/* limit before spilling hash table *\/ uint64hash_ngroups_limit; \/* limit before spilling hash table *\/ inthash_planned_partitions;\/* number of partitions planned  * for first pass *\/ doublehashentrysize;\/* estimate revised during execution *\/ Sizehash_mem_peak;\/* peak hash table memory usage *\/ uint64hash_ngroups_current;\/* number of groups currently in  * memory in all hash tables *\/ uint64hash_disk_used; \/* kB of disk space used *\/ inthash_batches_used;\/* batches used during entire execution *\/  AggStatePerHash perhash;\/* array of per-hashtable data *\/ AggStatePerGroup *hash_pergroup;\/* grouping set indexed array of  * per-group pointers *\/  \/* support for evaluation of agg input expressions: *\/ #define FIELDNO_AGGSTATE_ALL_PERGROUPS 53 AggStatePerGroup *all_pergroups;\/* array of first -&gt;pergroups, than  * -&gt;hash_pergroup *\/ ProjectionInfo *combinedproj;\/* projection machinery *\/ SharedAggInfo *shared_info; \/* one entry per worker *\/ } AggState;<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>ExecProcNodeMtd<\/code> &#8212; <code>ExecAgg<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/executor\/nodeAgg.c#L2140\" rel=\"noopener noreferrer nofollow\">src\/backend\/executor\/nodeAgg.c<\/a>).<\/p>\n<p>\u0413\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0443\u0436\u0435 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0422\u0430\u043a\u0438\u0435 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>AggStrategy<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * AggStrategy -  *  overall execution strategies for Agg plan nodes  *  * This is needed in both pathnodes.h and plannodes.h, so put it here...  *\/ typedef enum AggStrategy { AGG_PLAIN,\/* simple agg across all input rows *\/ AGG_SORTED,\/* grouped agg, input must be sorted *\/ AGG_HASHED,\/* grouped agg, use internal hashtable *\/ AGG_MIXED\/* grouped agg, hash and sort both used *\/ } AggStrategy;<\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c &#8212; <code>AGG_HASHED<\/code>.<\/p>\n<p>\u041e\u0431\u0449\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u0440\u0442\u0435\u0436\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <code>agg_retrieve_hash_table_in_memory<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/executor\/nodeAgg.c#L2753\" rel=\"noopener noreferrer nofollow\">src\/backend\/executor\/nodeAgg.c<\/a>).<\/p>\n<p>\u0414\u043b\u044f \u0445\u044d\u0448\u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0432 \u0445\u044d\u0448 \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 &#8212; <code>TupleHashTable<\/code><\/p>\n<pre><code class=\"cpp\">typedef struct TupleHashTableData { tuplehash_hash *hashtab;\/* underlying hash table *\/ intnumCols;\/* number of columns in lookup key *\/ AttrNumber *keyColIdx;\/* attr numbers of key columns *\/ FmgrInfo   *tab_hash_funcs; \/* hash functions for table datatype(s) *\/ ExprState  *tab_eq_func;\/* comparator for table datatype(s) *\/ Oid   *tab_collations; \/* collations for hash and comparison *\/ MemoryContext tablecxt;\/* memory context containing table *\/ MemoryContext tempcxt;\/* context for function evaluations *\/ Sizeentrysize;\/* actual size to make each hash entry *\/ TupleTableSlot *tableslot;\/* slot for referencing table entries *\/ \/* The following fields are set transiently for each table search: *\/ TupleTableSlot *inputslot;\/* current input tuple's slot *\/ FmgrInfo   *in_hash_funcs;\/* hash functions for input datatype(s) *\/ ExprState  *cur_eq_func;\/* comparator for input vs. table *\/ uint32hash_iv;\/* hash-function IV *\/ ExprContext *exprcontext;\/* expression context *\/ }  TupleHashTableData;  typedef struct TupleHashTableData *TupleHashTable;<\/code><\/pre>\n<p>\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u044b <code>TupleHashTable<\/code> &#8212; <code>TupleHashEntryData<\/code><\/p>\n<pre><code class=\"cpp\">typedef struct TupleHashEntryData { MinimalTuple firstTuple;\/* copy of first tuple in this group *\/ void   *additional;\/* user data *\/ uint32status;\/* hash status *\/ uint32hash;\/* hash value (cached) *\/ } TupleHashEntryData;  typedef struct TupleHashEntryData *TupleHashEntry;<\/code><\/pre>\n<p> \u0414\u043b\u044f <code>AggState<\/code> \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0438\u043f\u043e\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439:<\/p>\n<ul>\n<li>\n<p><code>AggStatePerAgg<\/code> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u0440\u0442\u0435\u0436\u0430<\/p>\n<\/li>\n<li>\n<p><code>AggStatePerGroup<\/code> &#8212; \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0435\u0434\u0438\u043d\u044b\u0439 \u0431\u043b\u043e\u043a \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p><code>AggStatePerHash<\/code> &#8212; \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0435 \u043f\u0440\u0438 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 <code>AGG_HASH<\/code> (\u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440, \u043d\u043e \u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>GROUPING SET<\/code>, \u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u044b \u0441\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435)<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u043f\u043e \u0432\u0441\u0435\u043c \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f\u043c \u0432 \u0445\u044d\u0448 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0438 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043d\u0430\u0439\u0442\u0438 \u043f\u0435\u0440\u0432\u044b\u0439 <code>TupleHashEntryData<\/code>, \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0449\u0438\u0439 <code>HAVING<\/code>.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u0440\u0442\u0435\u0436\u0430 \u0438\u0437 \u0445\u044d\u0448 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0430\u043a\u0440\u043e\u0441 ScanTupleHashTable.&nbsp;<\/p>\n<blockquote>\n<p>\u0425\u044d\u0448-\u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0445\u044d\u0448-\u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041f\u0440\u0438\u0447\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u0414\u043b\u044f \u0445\u044d\u0448 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>tuplehash<\/code> \u0438 \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u044d\u0442\u043e\u0439 \u0445\u044d\u0448 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u0438 \u0438\u043c\u0435\u044e\u0442 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>tuplehash<\/code><\/p>\n<\/blockquote>\n<p>\u041a\u043e\u0433\u0434\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0439\u0434\u0435\u043d, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>project_aggregates<\/code>. \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0443\u0441\u043b\u043e\u0432\u0438\u044f <code>HAVING<\/code> \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0417\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 <code>HAVING<\/code> \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <code>ExecQual<\/code>. \u041f\u043e \u0444\u0430\u043a\u0442\u0443 \u043e\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0445\u0440\u0430\u043d\u044f\u0449\u0443\u044e\u0441\u044f \u0432 \u043f\u043e\u043b\u0435 <code>evalfunc<\/code><\/p>\n<pre><code class=\"cpp\">typedef Datum (*ExprStateEvalFunc) (struct ExprState *expression, struct ExprContext *econtext, bool *isNull);  typedef struct ExprState {     \/\/ ...   \/*  * Function that actually evaluates the expression.  This can be set to  * different values depending on the complexity of the expression.  *\/ ExprStateEvalFunc evalfunc;     \/\/ ... }  <\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u043e\u0441\u044c, \u0442\u043e \u0432\u044b\u0437\u043e\u0432\u043e\u043c <code>ExecProject<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0440\u0442\u0435\u0436, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f.<\/p>\n<h4>SeqScan<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0415\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u044b\u043b\u0430 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0430 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e:<\/p>\n<ol>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>ExecProcNodeMtd<\/code> &#8212; <code>ExecSeqScan<\/code>. \u041e\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>ExecScan<\/code><\/p>\n<\/li>\n<li>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0431\u0443\u0444\u0435\u0440\u043e\u0432, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442\u0441\u044f \u0431\u0443\u0444\u0435\u0440\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043f\u0430\u043c\u044f\u0442\u0438 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435<\/p>\n<\/li>\n<\/ol>\n<h2>\u041a\u043e\u043d\u0435\u0446<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u0430 \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043e \u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u044b \u0432\u0441\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0438.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/736154\/\"> https:\/\/habr.com\/ru\/articles\/736154\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e!<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0443\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e SELECT \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u044b\u043b\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e \u0432 <a href=\"https:\/\/habr.com\/ru\/articles\/723668\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>. \u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"sql\">SELECT u.name  FROM users AS u WHERE u.age &gt; 24 GROUP BY u.name HAVING COUNT(*) = 1 ORDER BY u.name LIMIT 50<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u0438\u044f, \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441 <a href=\"https:\/\/habr.com\/ru\/articles\/723668\/\" rel=\"noopener noreferrer nofollow\">\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/a>, \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0432 3 \u043c\u0435\u0441\u0442\u0430\u0445: \u043f\u0430\u0440\u0441\u0438\u043d\u0433, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u0438 \u0441\u043b\u0443\u0447\u0430\u0438.<\/p>\n<h2>\u041f\u0430\u0440\u0441\u0438\u043d\u0433<\/h2>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f.&nbsp;<\/p>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 &#8212; <code>transformStmt<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/analyze.c#L313\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/analyze.c<\/a>). \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u0414\u043b\u044f SELECT \u044d\u0442\u043e \u0441\u043d\u043e\u0432\u0430 <code>transformSelectStmt<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/analyze.c#L1282\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/analyze.c<\/a>). <\/p>\n<h4>FROM users AS u<\/h4>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f <code>FROM<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>transformFromClause<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_clause.c#L113\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_clause.c<\/a>). \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0441\u0442\u0438\u0441\u044c \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435.<\/p>\n<h4>SELECT u.name<\/h4>\n<p>\u0412 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0432\u0441\u0435 \u0441\u0442\u043e\u043b\u0431\u0446\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0430\u0441\u0442\u0435\u0440\u0438\u0441\u043a<em> <\/em>(*)<em>. <\/em>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f  <code>ExpandColumnRefStar<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L1116\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>).<\/p>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u0433\u0434\u0430 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0435\u0442 \u0430\u0441\u0442\u0435\u0440\u0438\u0441\u043a\u0430, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>transformTargetEntry<\/code> (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L77\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>)  &#8212; \u043d\u0435 \u0432\u0430\u0436\u043d\u043e \u0441\u0442\u043e\u043b\u0431\u0435\u0446, \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043b\u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430.<\/p>\n<pre><code class=\"cpp\">\/*  * transformTargetEntry()  *Transform any ordinary \"expression-type\" node into a targetlist entry.  *This is exported so that parse_clause.c can generate targetlist entries  *for ORDER\/GROUP BY items that are not already in the targetlist.  *  * nodethe (untransformed) parse tree for the value expression.  * exprthe transformed expression, or NULL if caller didn't do it yet.  * exprKind expression kind (EXPR_KIND_SELECT_TARGET, etc)  * colnamethe column name to be assigned, or NULL if none yet set.  * resjunktrue if the target should be marked resjunk, ie, it is not  *wanted in the final projected tuple.  *\/ TargetEntry * transformTargetEntry(ParseState *pstate, Node *node, Node *expr, ParseExprKind exprKind, char *colname, bool resjunk)<\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043e\u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 2 \u0447\u0430\u0441\u0442\u0435\u0439 (\u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0439):<\/p>\n<ul>\n<li>\n<p><code>transformExpr<\/code> &#8212; \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_expr.c#L94\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_expr.c<\/a>)<\/p>\n<\/li>\n<li>\n<p><code>FigureColname<\/code> &#8212; \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u0430 (<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/backend\/parser\/parse_target.c#L1690\" rel=\"noopener noreferrer nofollow\">src\/backend\/parser\/parse_target.c<\/a>)<\/p>\n<\/li>\n<\/ul>\n<p><code>transformExpr<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>ParseState<\/code> \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0435 <code>transformExprRecurse<\/code> &#8212; \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443 \u043f\u0430\u0440\u0441\u0435\u0440\u0443.<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043e\u043d \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u044d\u0433\u0430 \u0443\u0437\u043b\u0430. \u0414\u043b\u044f <em>u.name<\/em> \u0442\u044d\u0433 &#8212; <code>T_ColumnRef<\/code> (\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446). \u0414\u043b\u044f \u043d\u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>transformColumnRef<\/code><\/p>\n<p>\u041d\u0430 \u0432\u0445\u043e\u0434 \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 <code>ParseState<\/code> \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 <code>ColumnRef<\/code><\/p>\n<pre><code class=\"cpp\">\/*  * ColumnRef - specifies a reference to a column, or possibly a whole tuple  *  * The \"fields\" list must be nonempty.  It can contain String nodes  * (representing names) and A_Star nodes (representing occurrence of a '*').  * Currently, A_Star must appear only as the last list element --- the grammar  * is responsible for enforcing this!  *  * Note: any container subscripting or selection of fields from composite columns  * is represented by an A_Indirection node above the ColumnRef.  However,  * for simplicity in the normal case, initial field selection from a table  * name is represented within ColumnRef and not by adding A_Indirection.  *\/ typedef struct ColumnRef { NodeTagtype; List   *fields;\/* field names (String nodes) or A_Star *\/ intlocation;\/* token location, or -1 if unknown *\/ } ColumnRef;<\/code><\/pre>\n<pre><code class=\"cpp\">\/*  * State information used during parse analysis  *  * parentParseState: NULL in a top-level ParseState.  When parsing a subquery,  * links to current parse state of outer query.  *  * p_sourcetext: source string that generated the raw parsetree being  * analyzed, or NULL if not available.  (The string is used only to  * generate cursor positions in error messages: we need it to convert  * byte-wise locations in parse structures to character-wise cursor  * positions.)  *  * p_rtable: list of RTEs that will become the rangetable of the query.  * Note that neither relname nor refname of these entries are necessarily  * unique; searching the rtable by name is a bad idea.  *  * p_joinexprs: list of JoinExpr nodes associated with p_rtable entries.  * This is one-for-one with p_rtable, but contains NULLs for non-join  * RTEs, and may be shorter than p_rtable if the last RTE(s) aren't joins.  *  * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that  * will become the fromlist of the query's top-level FromExpr node.  *  * p_namespace: list of ParseNamespaceItems that represents the current  * namespace for table and column lookup.  (The RTEs listed here may be just  * a subset of the whole rtable.  See ParseNamespaceItem comments below.)  *  * p_lateral_active: true if we are currently parsing a LATERAL subexpression  * of this parse level.  This makes p_lateral_only namespace items visible,  * whereas they are not visible when p_lateral_active is FALSE.  *  * p_ctenamespace: list of CommonTableExprs (WITH items) that are visible  * at the moment.  This is entirely different from p_namespace because a CTE  * is not an RTE, rather \"visibility\" means you could make an RTE from it.  *  * p_future_ctes: list of CommonTableExprs (WITH items) that are not yet  * visible due to scope rules.  This is used to help improve error messages.  *  * p_parent_cte: CommonTableExpr that immediately contains the current query,  * if any.  *  * p_target_relation: target relation, if query is INSERT\/UPDATE\/DELETE\/MERGE  *  * p_target_nsitem: target relation's ParseNamespaceItem.  *  * p_is_insert: true to process assignment expressions like INSERT, false  * to process them like UPDATE.  (Note this can change intra-statement, for  * cases like INSERT ON CONFLICT UPDATE.)  *  * p_windowdefs: list of WindowDefs representing WINDOW and OVER clauses.  * We collect these while transforming expressions and then transform them  * afterwards (so that any resjunk tlist items needed for the sort\/group  * clauses end up at the end of the query tlist).  A WindowDef's location in  * this list, counting from 1, is the winref number to use to reference it.  *  * p_expr_kind: kind of expression we're currently parsing, as per enum above;  * EXPR_KIND_NONE when not in an expression.  *  * p_next_resno: next TargetEntry.resno to assign, starting from 1.  *  * p_multiassign_exprs: partially-processed MultiAssignRef source expressions.  *  * p_locking_clause: query's FOR UPDATE\/FOR SHARE clause, if any.  *  * p_locked_from_parent: true if parent query level applies FOR UPDATE\/SHARE  * to this subquery as a whole.  *  * p_resolve_unknowns: resolve unknown-type SELECT output columns as type TEXT  * (this is true by default).  *  * p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated  * constructs in the query.  *  * p_last_srf: the set-returning FuncExpr or OpExpr most recently found in  * the query, or NULL if none.  *  * p_pre_columnref_hook, etc: optional parser hook functions for modifying the  * interpretation of ColumnRefs and ParamRefs.  *  * p_ref_hook_state: passthrough state for the parser hook functions.  *\/ struct ParseState { ParseState *parentParseState;\/* stack link *\/ const char *p_sourcetext;\/* source text, or NULL if not available *\/ List   *p_rtable;\/* range table so far *\/ List   *p_joinexprs;\/* JoinExprs for RTE_JOIN p_rtable entries *\/ List   *p_joinlist;\/* join items so far (will become FromExpr  * node's fromlist) *\/ List   *p_namespace;\/* currently-referenceable RTEs (List of  * ParseNamespaceItem) *\/ boolp_lateral_active;\/* p_lateral_only items visible? *\/ List   *p_ctenamespace; \/* current namespace for common table exprs *\/ List   *p_future_ctes;\/* common table exprs not yet in namespace *\/ CommonTableExpr *p_parent_cte;\/* this query's containing CTE *\/ Relationp_target_relation;\/* INSERT\/UPDATE\/DELETE\/MERGE target rel *\/ ParseNamespaceItem *p_target_nsitem;\/* target rel's NSItem, or NULL *\/ boolp_is_insert;\/* process assignment like INSERT not UPDATE *\/ List   *p_windowdefs;\/* raw representations of window clauses *\/ ParseExprKind p_expr_kind;\/* what kind of expression we're parsing *\/ intp_next_resno;\/* next targetlist resno to assign *\/ List   *p_multiassign_exprs;\/* junk tlist entries for multiassign *\/ List   *p_locking_clause;\/* raw FOR UPDATE\/FOR SHARE info *\/ boolp_locked_from_parent;\/* parent has marked this subquery  * with FOR UPDATE\/FOR SHARE *\/ boolp_resolve_unknowns; \/* resolve unknown-type SELECT outputs as  * type text *\/  QueryEnvironment *p_queryEnv;\/* curr env, incl refs to enclosing env *\/  \/* Flags telling about things found in the query: *\/ boolp_hasAggs; boolp_hasWindowFuncs; boolp_hasTargetSRFs; boolp_hasSubLinks; boolp_hasModifyingCTE;  Node   *p_last_srf;\/* most recent set-returning func\/op found *\/  \/*  * Optional hook functions for parser callbacks.  These are null unless  * set up by the caller of make_parsestate.  *\/ PreParseColumnRefHook p_pre_columnref_hook; PostParseColumnRefHook p_post_columnref_hook; ParseParamRefHook p_paramref_hook; CoerceParamHook p_coerce_param_hook; void   *p_ref_hook_state;\/* common passthrough link for above *\/ };<\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0442\u043e\u043b\u0431\u0435\u0446. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0443\u0437\u043b\u0430. \u0422\u0438\u043f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c <code>ParseExprKind<\/code>(<a href=\"https:\/\/github.com\/postgres\/postgres\/blob\/REL_15_STABLE\/src\/include\/parser\/parse_node.h#L38\" rel=\"noopener noreferrer nofollow\">src\/include\/parser\/parse_node.h<\/a>)<\/p>\n<pre><code class=\"cpp\">\/*  * Expression kinds distinguished by transformExpr().  Many of these are not  * semantically distinct so far as expression transformation goes; rather,  * we distinguish them so that context-specific error messages can be printed.  *  * Note: EXPR_KIND_OTHER is not used in the core code, but is left for use  * by extension code that might need to call transformExpr().  The core code  * will not enforce any context-driven restrictions on EXPR_KIND_OTHER  * expressions, so the caller would have to check for sub-selects, aggregates,  * window functions, SRFs, etc if those need to be disallowed.  *\/ typedef enum ParseExprKind { EXPR_KIND_NONE = 0,\/* \"not in an expression\" <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-347643","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/347643","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=347643"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/347643\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=347643"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=347643"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=347643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}