mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
This reverts commitd516974840, along with parts of commit049b742daa("psql: Tighten heuristics for BEGIN/END within CREATE SCHEMA"). While there's nothing particularly wrong withd51697484in itself, it depends ona9c350d9e("Don't try to re-order the subcommands of CREATE SCHEMA"), and concerns have been raised that the compatibility impact of that outweighs the benefit of allowing more object types within CREATE SCHEMA. It's not possible to revert049b742daverbatim, because the CVE-2026-6464 patches3045a25ba("Teach psql to skip in-line COPY ... FROM STDIN data after a failure") andcf754f741("Save/restore more lexer state when skipping text due to \if") depend on infrastructure it added. Instead, rip out just the bits specifically needed to parse CREATE FUNCTION within CREATE SCHEMA. This results in lexer code that matches v18-and-earlier as modified by CVE-2026-6464. Author: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/20260904180712.cc.noahmisch@microsoft.com Backpatch-through: 19
176 lines
7.5 KiB
C
176 lines
7.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* psqlscan_int.h
|
|
* lexical scanner internal declarations
|
|
*
|
|
* This file declares the PsqlScanStateData structure used by psqlscan.l
|
|
* and shared by other lexers compatible with it, such as psqlscanslash.l.
|
|
*
|
|
* One difficult aspect of this code is that we need to work in multibyte
|
|
* encodings that are not ASCII-safe. A "safe" encoding is one in which each
|
|
* byte of a multibyte character has the high bit set (it's >= 0x80). Since
|
|
* all our lexing rules treat all high-bit-set characters alike, we don't
|
|
* really need to care whether such a byte is part of a sequence or not.
|
|
* In an "unsafe" encoding, we still expect the first byte of a multibyte
|
|
* sequence to be >= 0x80, but later bytes might not be. If we scan such
|
|
* a sequence as-is, the lexing rules could easily be fooled into matching
|
|
* such bytes to ordinary ASCII characters. Our solution for this is to
|
|
* substitute 0xFF for each non-first byte within the data presented to flex.
|
|
* The flex rules will then pass the FF's through unmolested. The
|
|
* psqlscan_emit() subroutine is responsible for looking back to the original
|
|
* string and replacing FF's with the corresponding original bytes.
|
|
*
|
|
* Another interesting thing we do here is scan different parts of the same
|
|
* input with physically separate flex lexers (ie, lexers written in separate
|
|
* .l files). We can get away with this because the only part of the
|
|
* persistent state of a flex lexer that depends on its parsing rule tables
|
|
* is the start state number, which is easy enough to manage --- usually,
|
|
* in fact, we just need to set it to INITIAL when changing lexers. But to
|
|
* make that work at all, we must use re-entrant lexers, so that all the
|
|
* relevant state is in the yyscan_t attached to the PsqlScanState;
|
|
* if we were using lexers with separate static state we would soon end up
|
|
* with dangling buffer pointers in one or the other. Also note that this
|
|
* is unlikely to work very nicely if the lexers aren't all built with the
|
|
* same flex version, or if they don't use the same flex options.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/fe_utils/psqlscan_int.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef PSQLSCAN_INT_H
|
|
#define PSQLSCAN_INT_H
|
|
|
|
#include "fe_utils/psqlscan.h"
|
|
|
|
/*
|
|
* These are just to allow this file to be compilable standalone for header
|
|
* validity checking; in actual use, this file should always be included
|
|
* from the body of a flex file, where these symbols are already defined.
|
|
*/
|
|
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
|
typedef void *yyscan_t;
|
|
|
|
/*
|
|
* We use a stack of flex buffers to handle substitution of psql variables.
|
|
* Each stacked buffer contains the as-yet-unread text from one psql variable.
|
|
* When we pop the stack all the way, we resume reading from the outer buffer
|
|
* identified by scanbufhandle.
|
|
*/
|
|
typedef struct StackElem
|
|
{
|
|
YY_BUFFER_STATE buf; /* flex input control structure */
|
|
char *bufstring; /* data actually being scanned by flex */
|
|
char *origstring; /* copy of original data, if needed */
|
|
char *varname; /* name of variable providing data, or NULL */
|
|
struct StackElem *next;
|
|
} StackElem;
|
|
|
|
/*
|
|
* All working state of the lexer must be stored in PsqlScanStateData
|
|
* between calls. This allows us to have multiple open lexer operations,
|
|
* which is needed for nested include files. The lexer itself is not
|
|
* recursive, but it must be re-entrant.
|
|
*/
|
|
typedef struct PsqlScanStateData
|
|
{
|
|
yyscan_t scanner; /* Flex's state for this PsqlScanState */
|
|
|
|
PQExpBuffer output_buf; /* current output buffer */
|
|
|
|
StackElem *buffer_stack; /* stack of variable expansion buffers */
|
|
|
|
/*
|
|
* These variables always refer to the outer buffer, never to any stacked
|
|
* variable-expansion buffer.
|
|
*/
|
|
YY_BUFFER_STATE scanbufhandle;
|
|
char *scanbuf; /* start of outer-level input buffer */
|
|
const char *scanline; /* current input line at outer level */
|
|
|
|
/* safe_encoding, curline, refline are used by emit() to replace FFs */
|
|
int encoding; /* encoding being used now */
|
|
bool safe_encoding; /* is current encoding "safe"? */
|
|
bool std_strings; /* are string literals standard? */
|
|
const char *curline; /* actual flex input string for cur buf */
|
|
const char *refline; /* original data for cur buffer */
|
|
|
|
/* status for psql_scan_get_location() */
|
|
int cur_line_no; /* current line#, or 0 if no yylex done */
|
|
const char *cur_line_ptr; /* points into cur_line_no'th line in scanbuf */
|
|
|
|
/*
|
|
* All this state lives across successive input lines, until explicitly
|
|
* reset by psql_scan_reset. start_state is adopted by yylex() on entry,
|
|
* and updated with its finishing state on exit.
|
|
*/
|
|
int start_state; /* yylex's starting/finishing state */
|
|
int state_before_str_stop; /* start cond. before end quote */
|
|
int paren_depth; /* depth of nesting in parentheses */
|
|
int xcdepth; /* depth of nesting in slash-star comments */
|
|
char *dolqstart; /* current $foo$ quote start string */
|
|
|
|
/*
|
|
* State used to track boundaries of BEGIN ... END blocks in function
|
|
* definitions, so that semicolons do not send query too early. We also
|
|
* use this state to detect and count COPY FROM STDIN commands.
|
|
*/
|
|
int begin_depth; /* depth of begin/end pairs */
|
|
int copy_stdin_count; /* number of COPY FROM STDIN commands */
|
|
int init_idents_count; /* # identifiers since start of statement */
|
|
char init_idents[8]; /* records the first few identifiers */
|
|
|
|
/*
|
|
* Callback functions provided by the program making use of the lexer,
|
|
* plus a void* callback passthrough argument.
|
|
*/
|
|
const PsqlScanCallbacks *callbacks;
|
|
void *cb_passthrough;
|
|
} PsqlScanStateData;
|
|
|
|
/*
|
|
* Conditional scanning (\if ... \endif) needs to be able to reset the
|
|
* lexer's state to what it was at the beginning of a chunk of text that
|
|
* we choose to ignore. PsqlScanStateSave holds the values that need
|
|
* to be saved and restored. We assume that saving/restoring happens only
|
|
* while processing a backslash command, so we needn't save state that is
|
|
* concerned with comment or SQL literal processing: we won't be inside
|
|
* one of those.
|
|
*/
|
|
typedef struct PsqlScanStateSave
|
|
{
|
|
int paren_depth; /* depth of nesting in parentheses */
|
|
int begin_depth; /* depth of begin/end pairs */
|
|
int copy_stdin_count; /* number of COPY FROM STDIN commands */
|
|
int init_idents_count; /* # identifiers since start of statement */
|
|
char init_idents[8]; /* records the first few identifiers */
|
|
} PsqlScanStateSave;
|
|
|
|
|
|
/*
|
|
* Functions exported by psqlscan.l, but only meant for use within
|
|
* compatible lexers.
|
|
*/
|
|
extern void psqlscan_push_new_buffer(PsqlScanState state,
|
|
const char *newstr, const char *varname);
|
|
extern void psqlscan_pop_buffer_stack(PsqlScanState state);
|
|
extern void psqlscan_select_top_buffer(PsqlScanState state);
|
|
extern bool psqlscan_var_is_current_source(PsqlScanState state,
|
|
const char *varname);
|
|
extern YY_BUFFER_STATE psqlscan_prepare_buffer(PsqlScanState state,
|
|
const char *txt, int len,
|
|
char **txtcopy);
|
|
extern void psqlscan_emit(PsqlScanState state, const char *txt, int len);
|
|
extern char *psqlscan_extract_substring(PsqlScanState state,
|
|
const char *txt, int len);
|
|
extern void psqlscan_escape_variable(PsqlScanState state,
|
|
const char *txt, int len,
|
|
PsqlScanQuoteType quote);
|
|
extern void psqlscan_test_variable(PsqlScanState state,
|
|
const char *txt, int len);
|
|
|
|
#endif /* PSQLSCAN_INT_H */
|