PostgreSQL Source Code git master
Loading...
Searching...
No Matches
psqlscan.l File Reference
#include "postgres_fe.h"
#include "common/logging.h"
#include "fe_utils/psqlscan.h"
#include "libpq-fe.h"
#include "fe_utils/psqlscan_int.h"

Go to the source code of this file.

Macros

#define LEXRES_EOL   0 /* end of input */
 
#define LEXRES_SEMI   1 /* command-terminating semicolon found */
 
#define LEXRES_BACKSLASH   2 /* backslash command start */
 
#define ECHO   psqlscan_emit(cur_state, yytext, yyleng)
 

Typedefs

typedef int YYSTYPE
 

Functions

static void psqlscan_track_identifier (PsqlScanState state, const char *identifier)
 
int yylex (YYSTYPE *yylval_param, yyscan_t yyscanner)
 
static void psqlscan_record_initial_keyword (const char *identifier, char *idents, int idents_size, int *idents_count)
 
static bool psqlscan_is_create_routine (const char *idents)
 
PsqlScanState psql_scan_create (const PsqlScanCallbacks *callbacks)
 
void psql_scan_destroy (PsqlScanState state)
 
void psql_scan_set_passthrough (PsqlScanState state, void *passthrough)
 
void psql_scan_setup (PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
 
PsqlScanResult psql_scan (PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
 
void psql_scan_finish (PsqlScanState state)
 
void psql_scan_reset (PsqlScanState state)
 
void psql_scan_reselect_sql_lexer (PsqlScanState state)
 
bool psql_scan_in_quote (PsqlScanState state)
 
void psql_scan_get_location (PsqlScanState state, int *lineno, int *offset)
 
void psqlscan_push_new_buffer (PsqlScanState state, const char *newstr, const char *varname)
 
void psqlscan_pop_buffer_stack (PsqlScanState state)
 
void psqlscan_select_top_buffer (PsqlScanState state)
 
bool psqlscan_var_is_current_source (PsqlScanState state, const char *varname)
 
YY_BUFFER_STATE psqlscan_prepare_buffer (PsqlScanState state, const char *txt, int len, char **txtcopy)
 
void psqlscan_emit (PsqlScanState state, const char *txt, int len)
 
charpsqlscan_extract_substring (PsqlScanState state, const char *txt, int len)
 
void psqlscan_escape_variable (PsqlScanState state, const char *txt, int len, PsqlScanQuoteType quote)
 
void psqlscan_test_variable (PsqlScanState state, const char *txt, int len)
 

Macro Definition Documentation

◆ ECHO

Definition at line 62 of file psqlscan.l.

◆ LEXRES_BACKSLASH

#define LEXRES_BACKSLASH   2 /* backslash command start */

Definition at line 59 of file psqlscan.l.

◆ LEXRES_EOL

#define LEXRES_EOL   0 /* end of input */

Definition at line 57 of file psqlscan.l.

◆ LEXRES_SEMI

#define LEXRES_SEMI   1 /* command-terminating semicolon found */

Definition at line 58 of file psqlscan.l.

Typedef Documentation

◆ YYSTYPE

Definition at line 53 of file psqlscan.l.

Function Documentation

◆ psql_scan()

PsqlScanResult psql_scan ( PsqlScanState  state,
PQExpBuffer  query_buf,
promptStatus_t prompt 
)

Definition at line 1215 of file psqlscan.l.

1218{
1220 int lexresult;
uint32 result
static int fb(int x)
PsqlScanResult
Definition psqlscan.h:31
1221
1222 /* Must be scanning already */
1223 Assert(state->scanbufhandle != NULL);
#define Assert(condition)
Definition c.h:999
1224
1225 /* Set current output target */
1226 state->output_buf = query_buf;
1227
1228 /* Set input source */
1229 if (state->buffer_stack != NULL)
1230 yy_switch_to_buffer(state->buffer_stack->buf, state->scanner);
1231 else
1232 yy_switch_to_buffer(state->scanbufhandle, state->scanner);
1233
1234 /* And lex. */
1235 lexresult = yylex(NULL, state->scanner);
int yylex(void)
Definition pgc.l:465
1236
1237 /* Notify psql_scan_get_location() that a yylex call has been made. */
1238 if (state->cur_line_no == 0)
1239 state->cur_line_no = 1;
1240
1241 /*
1242 * Check termination state and return appropriate result info.
1243 */
1244 switch (lexresult)
1245 {
1246 case LEXRES_EOL: /* end of input */
1247 switch (state->start_state)
1248 {
1249 case INITIAL:
1250 case xqs: /* we treat this like INITIAL */
1251 if (state->paren_depth > 0)
1252 {
1255 }
1256 else if (state->begin_depth > 0)
1257 {
1260 }
1261 else if (query_buf->len > 0)
1262 {
1263 result = PSCAN_EOL;
1265 }
1266 else
1267 {
1268 /* never bother to send an empty buffer */
1271 }
1272 break;
1273 case xb:
1276 break;
1277 case xc:
1280 break;
1281 case xd:
1284 break;
1285 case xh:
1288 break;
1289 case xe:
1292 break;
1293 case xq:
1296 break;
1297 case xdolq:
1300 break;
1301 case xui:
1304 break;
1305 case xus:
1308 break;
1309 default:
1310 /* can't get here */
1311 fprintf(stderr, "invalid YY_START\n");
1312 exit(1);
1313 }
1314 break;
1315 case LEXRES_SEMI: /* semicolon */
1318 break;
1319 case LEXRES_BACKSLASH: /* backslash */
1322 break;
1323 default:
1324 /* can't get here */
1325 fprintf(stderr, "invalid yylex result\n");
1326 exit(1);
1327 }
#define fprintf(file, fmt, msg)
Definition cubescan.l:21
@ PSCAN_BACKSLASH
Definition psqlscan.h:33
@ PSCAN_EOL
Definition psqlscan.h:35
@ PSCAN_INCOMPLETE
Definition psqlscan.h:34
@ PSCAN_SEMICOLON
Definition psqlscan.h:32
@ PROMPT_READY
Definition psqlscan.h:41
@ PROMPT_PAREN
Definition psqlscan.h:47
@ PROMPT_COMMENT
Definition psqlscan.h:43
@ PROMPT_CONTINUE
Definition psqlscan.h:42
@ PROMPT_SINGLEQUOTE
Definition psqlscan.h:44
@ PROMPT_DOLLARQUOTE
Definition psqlscan.h:46
@ PROMPT_DOUBLEQUOTE
Definition psqlscan.h:45
#define LEXRES_BACKSLASH
Definition psqlscan.l:59
#define LEXRES_SEMI
Definition psqlscan.l:58
#define LEXRES_EOL
Definition psqlscan.l:57
1328
1329 return result;
1330}

References Assert, fb(), fprintf, LEXRES_BACKSLASH, LEXRES_EOL, LEXRES_SEMI, PROMPT_COMMENT, PROMPT_CONTINUE, PROMPT_DOLLARQUOTE, PROMPT_DOUBLEQUOTE, PROMPT_PAREN, PROMPT_READY, PROMPT_SINGLEQUOTE, PSCAN_BACKSLASH, PSCAN_EOL, PSCAN_INCOMPLETE, PSCAN_SEMICOLON, result, and yylex().

Referenced by MainLoop(), ParseScript(), and test_psql_parse().

◆ psql_scan_create()

PsqlScanState psql_scan_create ( const PsqlScanCallbacks callbacks)

Definition at line 1095 of file psqlscan.l.

1096{
1098
#define pg_malloc0_object(type)
Definition fe_memutils.h:61
1100
1101 state->callbacks = callbacks;
1102
1103 yylex_init(&state->scanner);
1104
1105 yyset_extra(state, state->scanner);
1106
void psql_scan_reset(PsqlScanState state)
Definition psqlscan.l:1369
1108
1109 return state;
1110}

References fb(), pg_malloc0_object, and psql_scan_reset().

Referenced by main(), MainLoop(), ParseScript(), and test_psql_parse().

◆ psql_scan_destroy()

void psql_scan_destroy ( PsqlScanState  state)

Definition at line 1116 of file psqlscan.l.

1117{
void psql_scan_finish(PsqlScanState state)
Definition psqlscan.l:1342
1119
1121
1122 yylex_destroy(state->scanner);
1123
1124 free(state);
#define free(a)
1125}

References fb(), free, psql_scan_finish(), and psql_scan_reset().

Referenced by main(), MainLoop(), ParseScript(), and test_psql_parse().

◆ psql_scan_finish()

void psql_scan_finish ( PsqlScanState  state)

Definition at line 1342 of file psqlscan.l.

1343{
1344 /* Drop any incomplete variable expansions. */
1345 while (state->buffer_stack != NULL)
void psqlscan_pop_buffer_stack(PsqlScanState state)
Definition psqlscan.l:1507
1347
1348 /* Done with the outer scan buffer, too */
1349 if (state->scanbufhandle)
1350 yy_delete_buffer(state->scanbufhandle, state->scanner);
1351 state->scanbufhandle = NULL;
1352 if (state->scanbuf)
1353 free(state->scanbuf);
1354 state->scanbuf = NULL;
1355}

References fb(), free, and psqlscan_pop_buffer_stack().

Referenced by MainLoop(), ParseScript(), and psql_scan_destroy().

◆ psql_scan_get_location()

void psql_scan_get_location ( PsqlScanState  state,
int lineno,
int offset 
)

Definition at line 1429 of file psqlscan.l.

1431{
1432 const char *line_end;
1433
1434 /*
1435 * We rely on flex's having stored a NUL after the current token in
1436 * scanbuf. Therefore we must specially handle the state before yylex()
1437 * has been called, when obviously that won't have happened yet.
1438 */
1439 if (state->cur_line_no == 0)
1440 {
1441 *lineno = 1;
1442 *offset = 0;
1443 return;
1444 }
1445
1446 /*
1447 * Advance cur_line_no/cur_line_ptr past whatever has been lexed so far.
1448 * Doing this prevents repeated calls from being O(N^2) for long inputs.
1449 */
1450 while ((line_end = strchr(state->cur_line_ptr, '\n')) != NULL)
1451 {
1452 state->cur_line_no++;
1453 state->cur_line_ptr = line_end + 1;
1454 }
1455 state->cur_line_ptr += strlen(state->cur_line_ptr);
1456
1457 /* Report current location. */
1458 *lineno = state->cur_line_no;
1459 *offset = state->cur_line_ptr - state->scanbuf;
1460}

References fb().

Referenced by expr_lex_one_word(), expr_yyerror_more(), and ParseScript().

◆ psql_scan_in_quote()

bool psql_scan_in_quote ( PsqlScanState  state)

Definition at line 1410 of file psqlscan.l.

1411{
1412 return state->start_state != INITIAL &&
1413 state->start_state != xqs;
1414}

References fb().

Referenced by MainLoop().

◆ psql_scan_reselect_sql_lexer()

void psql_scan_reselect_sql_lexer ( PsqlScanState  state)

Definition at line 1397 of file psqlscan.l.

1398{
1399 state->start_state = INITIAL;
1400}

References fb().

Referenced by expr_lex_one_word(), expr_scanner_finish(), psql_scan_slash_command(), psql_scan_slash_command_end(), and psql_scan_slash_option().

◆ psql_scan_reset()

void psql_scan_reset ( PsqlScanState  state)

Definition at line 1369 of file psqlscan.l.

1370{
1371 state->start_state = INITIAL;
1372 state->paren_depth = 0;
1373 state->xcdepth = 0; /* not really necessary */
1374 if (state->dolqstart)
1375 free(state->dolqstart);
1376 state->dolqstart = NULL;
1377 state->begin_depth = 0;
1378 state->init_idents_count = 0;
1379}

References fb(), and free.

Referenced by exec_command_reset(), exec_command_watch(), MainLoop(), psql_scan_create(), and psql_scan_destroy().

◆ psql_scan_set_passthrough()

void psql_scan_set_passthrough ( PsqlScanState  state,
void passthrough 
)

Definition at line 1135 of file psqlscan.l.

1136{
1137 state->cb_passthrough = passthrough;
1138}

References fb().

Referenced by main(), and MainLoop().

◆ psql_scan_setup()

void psql_scan_setup ( PsqlScanState  state,
const char line,
int  line_len,
int  encoding,
bool  std_strings 
)

Definition at line 1153 of file psqlscan.l.

1156{
1157 /* Mustn't be scanning already */
1158 Assert(state->scanbufhandle == NULL);
1159 Assert(state->buffer_stack == NULL);
1160
1161 /* Do we need to hack the character set encoding? */
1162 state->encoding = encoding;
1163 state->safe_encoding = pg_valid_server_encoding_id(encoding);
static char * encoding
Definition initdb.c:139
#define pg_valid_server_encoding_id
Definition pg_wchar.h:485
1164
1165 /* Save standard-strings flag as well */
1166 state->std_strings = std_strings;
1167
1168 /* Set up flex input buffer with appropriate translation and padding */
1169 state->scanbufhandle = psqlscan_prepare_buffer(state, line, line_len,
1170 &state->scanbuf);
1171 state->scanline = line;
YY_BUFFER_STATE psqlscan_prepare_buffer(PsqlScanState state, const char *txt, int len, char **txtcopy)
Definition psqlscan.l:1570
1172
1173 /* Set lookaside data in case we have to map unsafe encoding */
1174 state->curline = state->scanbuf;
1175 state->refline = state->scanline;
1176
1177 /* Initialize state for psql_scan_get_location() */
1178 state->cur_line_no = 0; /* yylex not called yet */
1179 state->cur_line_ptr = state->scanbuf;
1180}

References Assert, encoding, fb(), pg_valid_server_encoding_id, and psqlscan_prepare_buffer().

Referenced by main(), MainLoop(), ParseScript(), and test_psql_parse().

◆ psqlscan_emit()

void psqlscan_emit ( PsqlScanState  state,
const char txt,
int  len 
)

Definition at line 1611 of file psqlscan.l.

1612{
1613 PQExpBuffer output_buf = state->output_buf;
1614
1615 if (state->safe_encoding)
1616 appendBinaryPQExpBuffer(output_buf, txt, len);
1617 else
1618 {
1619 /* Gotta do it the hard way */
1620 const char *reference = state->refline;
1621 int i;
int i
Definition isn.c:77
const void size_t len
void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
1622
1623 reference += (txt - state->curline);
1624
1625 for (i = 0; i < len; i++)
1626 {
1627 char ch = txt[i];
1628
1629 if (ch == (char) 0xFF)
1630 ch = reference[i];
1631 appendPQExpBufferChar(output_buf, ch);
1632 }
1633 }
void appendPQExpBufferChar(PQExpBuffer str, char ch)
1634}

References appendBinaryPQExpBuffer(), appendPQExpBufferChar(), fb(), i, and len.

Referenced by psqlscan_escape_variable().

◆ psqlscan_escape_variable()

void psqlscan_escape_variable ( PsqlScanState  state,
const char txt,
int  len,
PsqlScanQuoteType  quote 
)

Definition at line 1679 of file psqlscan.l.

1681{
1682 char *varname;
1683 char *value;
static struct @175 value
1684
1685 /* Variable lookup. */
1686 varname = psqlscan_extract_substring(state, txt + 2, len - 3);
1687 if (state->callbacks->get_variable)
1688 value = state->callbacks->get_variable(varname, quote,
1689 state->cb_passthrough);
1690 else
1691 value = NULL;
1692 free(varname);
char * psqlscan_extract_substring(PsqlScanState state, const char *txt, int len)
Definition psqlscan.l:1643
1693
1694 if (value)
1695 {
1696 /* Emit the suitably-escaped value */
1697 appendPQExpBufferStr(state->output_buf, value);
1698 free(value);
1699 }
1700 else
1701 {
1702 /* Emit original token as-is */
1704 }
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
void psqlscan_emit(PsqlScanState state, const char *txt, int len)
Definition psqlscan.l:1611
1705}

References appendPQExpBufferStr(), fb(), free, len, psqlscan_emit(), psqlscan_extract_substring(), and value.

◆ psqlscan_extract_substring()

char * psqlscan_extract_substring ( PsqlScanState  state,
const char txt,
int  len 
)

Definition at line 1643 of file psqlscan.l.

1644{
1645 char *result = pg_malloc_array(char, (len + 1));
#define pg_malloc_array(type, count)
Definition fe_memutils.h:66
1646
1647 if (state->safe_encoding)
1648 memcpy(result, txt, len);
1649 else
1650 {
1651 /* Gotta do it the hard way */
1652 const char *reference = state->refline;
1653 int i;
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
1654
1655 reference += (txt - state->curline);
1656
1657 for (i = 0; i < len; i++)
1658 {
1659 char ch = txt[i];
1660
1661 if (ch == (char) 0xFF)
1662 ch = reference[i];
1663 result[i] = ch;
1664 }
1665 }
1666 result[len] = '\0';
1667 return result;
1668}

References fb(), i, len, memcpy(), pg_malloc_array, and result.

Referenced by psqlscan_escape_variable(), and psqlscan_test_variable().

◆ psqlscan_is_create_routine()

static bool psqlscan_is_create_routine ( const char idents)
static

Definition at line 996 of file psqlscan.l.

997{
998 return idents[0] == 'c' &&
999 (idents[1] == 'f' || idents[1] == 'p' ||
1000 (idents[1] == 'o' && idents[2] == 'r' &&
1001 (idents[3] == 'f' || idents[3] == 'p')));
1002}

Referenced by psqlscan_track_identifier().

◆ psqlscan_pop_buffer_stack()

void psqlscan_pop_buffer_stack ( PsqlScanState  state)

Definition at line 1507 of file psqlscan.l.

1508{
1509 StackElem *stackelem = state->buffer_stack;
1510
1511 state->buffer_stack = stackelem->next;
1512 yy_delete_buffer(stackelem->buf, state->scanner);
1513 free(stackelem->bufstring);
1514 if (stackelem->origstring)
1515 free(stackelem->origstring);
1516 if (stackelem->varname)
1517 free(stackelem->varname);
1518 free(stackelem);
struct state * next
Definition regguts.h:340
1519}

References fb(), free, and state::next.

Referenced by psql_scan_finish().

◆ psqlscan_prepare_buffer()

YY_BUFFER_STATE psqlscan_prepare_buffer ( PsqlScanState  state,
const char txt,
int  len,
char **  txtcopy 
)

Definition at line 1570 of file psqlscan.l.

1572{
1573 char *newtxt;
1574
1575 /* Flex wants two \0 characters after the actual data */
1576 newtxt = pg_malloc_array(char, (len + 2));
1577 *txtcopy = newtxt;
1579
1580 if (state->safe_encoding)
1581 memcpy(newtxt, txt, len);
1582 else
1583 {
1584 /* Gotta do it the hard way */
1585 int i = 0;
1586
1587 while (i < len)
1588 {
1589 int thislen = PQmblen(txt + i, state->encoding);
int PQmblen(const char *s, int encoding)
Definition fe-misc.c:1255
1590
1591 /* first byte should always be okay... */
1592 newtxt[i] = txt[i];
1593 i++;
1594 while (--thislen > 0 && i < len)
1595 newtxt[i++] = (char) 0xFF;
1596 }
1597 }
1598
1599 return yy_scan_buffer(newtxt, len + 2, state->scanner);
1600}

References fb(), i, len, memcpy(), pg_malloc_array, and PQmblen().

Referenced by psql_scan_setup(), and psqlscan_push_new_buffer().

◆ psqlscan_push_new_buffer()

void psqlscan_push_new_buffer ( PsqlScanState  state,
const char newstr,
const char varname 
)

Definition at line 1468 of file psqlscan.l.

1470{
1472
#define pg_malloc_object(type)
Definition fe_memutils.h:60
1474
1475 /*
1476 * In current usage, the passed varname points at the current flex input
1477 * buffer; we must copy it before calling psqlscan_prepare_buffer()
1478 * because that will change the buffer state.
1479 */
1480 stackelem->varname = varname ? pg_strdup(varname) : NULL;
char * pg_strdup(const char *in)
Definition fe_memutils.c:91
1481
1483 &stackelem->bufstring);
1484 state->curline = stackelem->bufstring;
1485 if (state->safe_encoding)
1486 {
1487 stackelem->origstring = NULL;
1488 state->refline = stackelem->bufstring;
1489 }
1490 else
1491 {
1492 stackelem->origstring = pg_strdup(newstr);
1493 state->refline = stackelem->origstring;
1494 }
1495 stackelem->next = state->buffer_stack;
1496 state->buffer_stack = stackelem;
1497}

References fb(), state::next, pg_malloc_object, pg_strdup(), and psqlscan_prepare_buffer().

◆ psqlscan_record_initial_keyword()

static void psqlscan_record_initial_keyword ( const char identifier,
char idents,
int  idents_size,
int idents_count 
)
static

Definition at line 968 of file psqlscan.l.

972{
974 {
975 /*
976 * What we need to recognize is CREATE [OR REPLACE] FUNCTION/PROCEDURE
977 * and CREATE SCHEMA. Checking for SCHEMA is useless but not harmful
978 * in the CREATE SCHEMA sub-statement case.
979 */
980 if (pg_strcasecmp(identifier, "create") == 0 ||
981 pg_strcasecmp(identifier, "function") == 0 ||
982 pg_strcasecmp(identifier, "procedure") == 0 ||
983 pg_strcasecmp(identifier, "or") == 0 ||
984 pg_strcasecmp(identifier, "replace") == 0 ||
985 pg_strcasecmp(identifier, "schema") == 0)
986 idents[*idents_count] = pg_tolower((unsigned char) identifier[0]);
987 /* For other keywords or identifiers, leave '\0' in the array entry */
988 (*idents_count)++;
989 }
int pg_strcasecmp(const char *s1, const char *s2)
unsigned char pg_tolower(unsigned char ch)
990}

References fb(), pg_strcasecmp(), and pg_tolower().

Referenced by psqlscan_track_identifier().

◆ psqlscan_select_top_buffer()

void psqlscan_select_top_buffer ( PsqlScanState  state)

Definition at line 1525 of file psqlscan.l.

1526{
1527 StackElem *stackelem = state->buffer_stack;
1528
1529 if (stackelem != NULL)
1530 {
1531 yy_switch_to_buffer(stackelem->buf, state->scanner);
1532 state->curline = stackelem->bufstring;
1533 state->refline = stackelem->origstring ? stackelem->origstring : stackelem->bufstring;
1534 }
1535 else
1536 {
1537 yy_switch_to_buffer(state->scanbufhandle, state->scanner);
1538 state->curline = state->scanbuf;
1539 state->refline = state->scanline;
1540 }
1541}

References fb().

◆ psqlscan_test_variable()

void psqlscan_test_variable ( PsqlScanState  state,
const char txt,
int  len 
)

Definition at line 1708 of file psqlscan.l.

1709{
1710 char *varname;
1711 char *value;
1712
1713 varname = psqlscan_extract_substring(state, txt + 3, len - 4);
1714 if (state->callbacks->get_variable)
1715 value = state->callbacks->get_variable(varname, PQUOTE_PLAIN,
1716 state->cb_passthrough);
1717 else
1718 value = NULL;
1719 free(varname);
@ PQUOTE_PLAIN
Definition psqlscan.h:54
1720
1721 if (value != NULL)
1722 {
1723 appendPQExpBufferStr(state->output_buf, "TRUE");
1724 free(value);
1725 }
1726 else
1727 {
1728 appendPQExpBufferStr(state->output_buf, "FALSE");
1729 }
1730}

References appendPQExpBufferStr(), fb(), free, len, PQUOTE_PLAIN, psqlscan_extract_substring(), and value.

◆ psqlscan_track_identifier()

static void psqlscan_track_identifier ( PsqlScanState  state,
const char identifier 
)
static

Definition at line 1016 of file psqlscan.l.

1017{
1018 bool is_create_schema;
1019
1020 /* None of this needs to happen when we're inside parentheses */
1021 if (state->paren_depth != 0)
1022 return;
1023
1024 /* Reset all my state at the start of each new statement */
1025 if (state->init_idents_count == 0)
1026 {
1027 memset(state->init_idents, 0, sizeof(state->init_idents));
1028 state->sub_idents_count = 0;
1029 memset(state->sub_idents, 0, sizeof(state->sub_idents));
1030 }
1031
1032 /* Record initial keywords if init_idents_count is small enough */
1034 state->init_idents,
1035 lengthof(state->init_idents),
1036 &state->init_idents_count);
#define lengthof(array)
Definition c.h:929
static void psqlscan_record_initial_keyword(const char *identifier, char *idents, int idents_size, int *idents_count)
Definition psqlscan.l:968
1037
1038 /*
1039 * In CREATE SCHEMA, track identifiers from each top-level CREATE schema
1040 * element separately, so that BEGIN/END tracking is enabled only within
1041 * CREATE [OR REPLACE] {FUNCTION|PROCEDURE} clauses.
1042 */
1043 is_create_schema = (state->init_idents[0] == 'c' &&
1044 state->init_idents[1] == 's');
1045 if (is_create_schema &&
1046 state->begin_depth == 0)
1047 {
1048 /* Reset sub-clause state at each top-level CREATE keyword */
1049 if (pg_strcasecmp(identifier, "create") == 0)
1050 {
1051 state->sub_idents_count = 0;
1052 memset(state->sub_idents, 0, sizeof(state->sub_idents));
1053 }
1054 /* ... and record the first few keywords following that */
1056 state->sub_idents,
1057 lengthof(state->sub_idents),
1058 &state->sub_idents_count);
1059 }
1060
1061 /*
1062 * Track BEGIN/CASE/END only when within an appropriate (sub) statement.
1063 */
1064 if (psqlscan_is_create_routine(state->init_idents) ||
1066 psqlscan_is_create_routine(state->sub_idents)))
1067 {
1068 if (pg_strcasecmp(identifier, "begin") == 0)
1069 state->begin_depth++;
1070 else if (pg_strcasecmp(identifier, "case") == 0)
1071 {
1072 /*
1073 * CASE also ends with END. We only need to track this if we are
1074 * already inside a BEGIN.
1075 */
1076 if (state->begin_depth >= 1)
1077 state->begin_depth++;
1078 }
1079 else if (pg_strcasecmp(identifier, "end") == 0)
1080 {
1081 if (state->begin_depth > 0)
1082 state->begin_depth--;
1083 }
1084 }
static bool psqlscan_is_create_routine(const char *idents)
Definition psqlscan.l:996
1085}

References fb(), lengthof, pg_strcasecmp(), psqlscan_is_create_routine(), and psqlscan_record_initial_keyword().

◆ psqlscan_var_is_current_source()

bool psqlscan_var_is_current_source ( PsqlScanState  state,
const char varname 
)

Definition at line 1548 of file psqlscan.l.

1549{
1551
1552 for (stackelem = state->buffer_stack;
1553 stackelem != NULL;
1554 stackelem = stackelem->next)
1555 {
1556 if (stackelem->varname && strcmp(stackelem->varname, varname) == 0)
1557 return true;
1558 }
1559 return false;
1560}

References fb().

◆ yylex()

int yylex ( YYSTYPE yylval_param,
yyscan_t  yyscanner 
)

Definition at line 390 of file psqlscan.l.

392 {
393 /* Declare some local variables inside yylex(), for convenience */
395 PQExpBuffer output_buf = cur_state->output_buf;
#define yyextra
Definition scan.l:1102
396
397 /*
398 * Force flex into the state indicated by start_state. This has a
399 * couple of purposes: it lets some of the functions below set a new
400 * starting state without ugly direct access to flex variables, and it
401 * allows us to transition from one flex lexer to another so that we
402 * can lex different parts of the source string using separate lexers.
403 */
404 BEGIN(cur_state->start_state);
405%}
406
407{whitespace} {
408 /*
409 * Note that the whitespace rule includes both true
410 * whitespace and single-line ("--" style) comments.
411 * We suppress whitespace until we have collected some
412 * non-whitespace data. (This interacts with some
413 * decisions in MainLoop(); see there for details.)
414 */
415 if (output_buf->len > 0)
416 ECHO;
417 }
#define ECHO
Definition psqlscan.l:62
418
419{xcstart} {
420 cur_state->xcdepth = 0;
421 BEGIN(xc);
422 /* Put back any characters past slash-star; see above */
423 yyless(2);
424 ECHO;
425 }
426
427<xc>{
428{xcstart} {
429 cur_state->xcdepth++;
430 /* Put back any characters past slash-star; see above */
431 yyless(2);
432 ECHO;
433 }
434
435{xcstop} {
436 if (cur_state->xcdepth <= 0)
437 BEGIN(INITIAL);
438 else
439 cur_state->xcdepth--;
440 ECHO;
441 }
442
443{xcinside} {
444 ECHO;
445 }
446
447{op_chars} {
448 ECHO;
449 }
450
451\*+ {
452 ECHO;
453 }
454} /* <xc> */
455
456{xbstart} {
457 BEGIN(xb);
458 ECHO;
459 }
460<xh>{xhinside} |
461<xb>{xbinside} {
462 ECHO;
463 }
464
465{xhstart} {
466 /* Hexadecimal bit type.
467 * At some point we should simply pass the string
468 * forward to the parser and label it there.
469 * In the meantime, place a leading "x" on the string
470 * to mark it for the input routine as a hex string.
471 */
472 BEGIN(xh);
473 ECHO;
474 }
475
476{xnstart} {
477 yyless(1); /* eat only 'n' this time */
478 ECHO;
479 }
480
481{xqstart} {
482 if (cur_state->std_strings)
483 BEGIN(xq);
484 else
485 BEGIN(xe);
486 ECHO;
487 }
488{xestart} {
489 BEGIN(xe);
490 ECHO;
491 }
492{xusstart} {
493 BEGIN(xus);
494 ECHO;
495 }
496
497<xb,xh,xq,xe,xus>{quote} {
498 /*
499 * When we are scanning a quoted string and see an end
500 * quote, we must look ahead for a possible continuation.
501 * If we don't see one, we know the end quote was in fact
502 * the end of the string. To reduce the lexer table size,
503 * we use a single "xqs" state to do the lookahead for all
504 * types of strings.
505 */
506 cur_state->state_before_str_stop = YYSTATE;
507 BEGIN(xqs);
508 ECHO;
509 }
510<xqs>{quotecontinue} {
511 /*
512 * Found a quote continuation, so return to the in-quote
513 * state and continue scanning the literal. Nothing is
514 * added to the literal's contents.
515 */
516 BEGIN(cur_state->state_before_str_stop);
517 ECHO;
518 }
519<xqs>{quotecontinuefail} |
520<xqs>{other} {
521 /*
522 * Failed to see a quote continuation. Throw back
523 * everything after the end quote, and handle the string
524 * according to the state we were in previously.
525 */
526 yyless(0);
527 BEGIN(INITIAL);
528 /* There's nothing to echo ... */
529 }
530
531<xq,xe,xus>{xqdouble} {
532 ECHO;
533 }
534<xq,xus>{xqinside} {
535 ECHO;
536 }
537<xe>{xeinside} {
538 ECHO;
539 }
540<xe>{xeunicode} {
541 ECHO;
542 }
543<xe>{xeunicodefail} {
544 ECHO;
545 }
546<xe>{xeescape} {
547 ECHO;
548 }
549<xe>{xeoctesc} {
550 ECHO;
551 }
552<xe>{xehexesc} {
553 ECHO;
554 }
555<xe>. {
556 /* This is only needed for \ just before EOF */
557 ECHO;
558 }
559
560{dolqdelim} {
561 cur_state->dolqstart = pg_strdup(yytext);
562 BEGIN(xdolq);
563 ECHO;
564 }
565{dolqfailed} {
566 /* throw back all but the initial "$" */
567 yyless(1);
568 ECHO;
569 }
570<xdolq>{dolqdelim} {
571 if (strcmp(yytext, cur_state->dolqstart) == 0)
572 {
573 free(cur_state->dolqstart);
574 cur_state->dolqstart = NULL;
575 BEGIN(INITIAL);
576 }
577 else
578 {
579 /*
580 * When we fail to match $...$ to dolqstart, transfer
581 * the $... part to the output, but put back the final
582 * $ for rescanning. Consider $delim$...$junk$delim$
583 */
584 yyless(yyleng - 1);
585 }
586 ECHO;
587 }
#define yyleng
Definition scan.l:1108
588<xdolq>{dolqinside} {
589 ECHO;
590 }
591<xdolq>{dolqfailed} {
592 ECHO;
593 }
594<xdolq>. {
595 /* This is only needed for $ inside the quoted text */
596 ECHO;
597 }
598
599{xdstart} {
600 BEGIN(xd);
601 ECHO;
602 }
603{xuistart} {
604 BEGIN(xui);
605 ECHO;
606 }
607<xd>{xdstop} {
608 BEGIN(INITIAL);
609 ECHO;
610 }
611<xui>{dquote} {
612 BEGIN(INITIAL);
613 ECHO;
614 }
615<xd,xui>{xddouble} {
616 ECHO;
617 }
618<xd,xui>{xdinside} {
619 ECHO;
620 }
621
622{xufailed} {
623 /* throw back all but the initial u/U */
624 yyless(1);
625 ECHO;
626 }
627
628{typecast} {
629 ECHO;
630 }
631
632{dot_dot} {
633 ECHO;
634 }
635
636{colon_equals} {
637 ECHO;
638 }
639
640{equals_greater} {
641 ECHO;
642 }
643
644{less_equals} {
645 ECHO;
646 }
647
648{greater_equals} {
649 ECHO;
650 }
651
652{less_greater} {
653 ECHO;
654 }
655
656{not_equals} {
657 ECHO;
658 }
659
660{right_arrow} {
661 ECHO;
662 }
663
664 /*
665 * These rules are specific to psql --- they implement parenthesis
666 * counting and detection of command-ending semicolon. These must
667 * appear before the {self} rule so that they take precedence over it.
668 */
669
670"(" {
671 cur_state->paren_depth++;
672 ECHO;
673 }
674
675")" {
676 if (cur_state->paren_depth > 0)
677 cur_state->paren_depth--;
678 ECHO;
679 }
680
681";" {
682 ECHO;
683 if (cur_state->paren_depth == 0 &&
684 cur_state->begin_depth == 0)
685 {
686 /* Terminate lexing temporarily */
687 cur_state->start_state = YY_START;
688 cur_state->init_idents_count = 0;
689 return LEXRES_SEMI;
690 }
691 }
692
693 /*
694 * psql-specific rules to handle backslash commands and variable
695 * substitution. We want these before {self}, also.
696 */
697
698"\\"[;:] {
699 /* Force a semi-colon or colon into the query buffer */
701 /* Reset BEGIN/END tracking if semi at outer level */
702 if (yytext[1] == ';' &&
703 cur_state->paren_depth == 0 &&
704 cur_state->begin_depth == 0)
705 cur_state->init_idents_count = 0;
706 }
707
708"\\" {
709 /* Terminate lexing temporarily */
710 cur_state->start_state = YY_START;
711 return LEXRES_BACKSLASH;
712 }
713
714:{variable_char}+ {
715 /* Possible psql variable substitution */
716 char *varname;
717 char *value;
718
720 yytext + 1,
721 yyleng - 1);
722 if (cur_state->callbacks->get_variable)
723 value = cur_state->callbacks->get_variable(varname,
725 cur_state->cb_passthrough);
726 else
727 value = NULL;
728
729 if (value)
730 {
731 /* It is a variable, check for recursion */
733 {
734 /* Recursive expansion --- don't go there */
735 pg_log_warning("skipping recursive expansion of variable \"%s\"",
736 varname);
737 /* Instead copy the string as is */
738 ECHO;
739 }
740 else
741 {
742 /* OK, perform substitution */
744 /* yy_scan_string already made buffer active */
745 }
746 free(value);
747 }
748 else
749 {
750 /*
751 * if the variable doesn't exist we'll copy the string
752 * as is
753 */
754 ECHO;
755 }
#define pg_log_warning(...)
Definition pgfnames.c:24
void psqlscan_push_new_buffer(PsqlScanState state, const char *newstr, const char *varname)
Definition psqlscan.l:1468
bool psqlscan_var_is_current_source(PsqlScanState state, const char *varname)
Definition psqlscan.l:1548
756
757 free(varname);
758 }
759
760:'{variable_char}+' {
763 }
@ PQUOTE_SQL_LITERAL
Definition psqlscan.h:55
void psqlscan_escape_variable(PsqlScanState state, const char *txt, int len, PsqlScanQuoteType quote)
Definition psqlscan.l:1679
764
765:\"{variable_char}+\" {
768 }
@ PQUOTE_SQL_IDENT
Definition psqlscan.h:56
769
770:\{\?{variable_char}+\} {
772 }
void psqlscan_test_variable(PsqlScanState state, const char *txt, int len)
Definition psqlscan.l:1708
773
774 /*
775 * These rules just avoid the need for scanner backup if one of the
776 * three rules above fails to match completely.
777 */
778
779:'{variable_char}* {
780 /* Throw back everything but the colon */
781 yyless(1);
782 ECHO;
783 }
784
785:\"{variable_char}* {
786 /* Throw back everything but the colon */
787 yyless(1);
788 ECHO;
789 }
790
791:\{\?{variable_char}* {
792 /* Throw back everything but the colon */
793 yyless(1);
794 ECHO;
795 }
796:\{ {
797 /* Throw back everything but the colon */
798 yyless(1);
799 ECHO;
800 }
801
802 /*
803 * Back to backend-compatible rules.
804 */
805
806{self} {
807 ECHO;
808 }
809
810{operator} {
811 /*
812 * Check for embedded slash-star or dash-dash; those
813 * are comment starts, so operator must stop there.
814 * Note that slash-star or dash-dash at the first
815 * character will match a prior rule, not this one.
816 */
817 int nchars = yyleng;
818 char *slashstar = strstr(yytext, "/*");
819 char *dashdash = strstr(yytext, "--");
820
821 if (slashstar && dashdash)
822 {
823 /* if both appear, take the first one */
824 if (slashstar > dashdash)
826 }
827 else if (!slashstar)
829 if (slashstar)
830 nchars = slashstar - yytext;
831
832 /*
833 * For SQL compatibility, '+' and '-' cannot be the
834 * last char of a multi-char operator unless the operator
835 * contains chars that are not in SQL operators.
836 * The idea is to lex '=-' as two operators, but not
837 * to forbid operator names like '?-' that could not be
838 * sequences of SQL operators.
839 */
840 if (nchars > 1 &&
841 (yytext[nchars - 1] == '+' ||
842 yytext[nchars - 1] == '-'))
843 {
844 int ic;
845
846 for (ic = nchars - 2; ic >= 0; ic--)
847 {
848 char c = yytext[ic];
849 if (c == '~' || c == '!' || c == '@' ||
850 c == '#' || c == '^' || c == '&' ||
851 c == '|' || c == '`' || c == '?' ||
852 c == '%')
853 break;
854 }
855 if (ic < 0)
856 {
857 /*
858 * didn't find a qualifying character, so remove
859 * all trailing [+-]
860 */
861 do {
862 nchars--;
863 } while (nchars > 1 &&
864 (yytext[nchars - 1] == '+' ||
865 yytext[nchars - 1] == '-'));
866 }
867 }
char * c
868
869 if (nchars < yyleng)
870 {
871 /* Strip the unwanted chars from the token */
872 yyless(nchars);
873 }
874 ECHO;
875 }
876
877{param} {
878 ECHO;
879 }
880{param_junk} {
881 ECHO;
882 }
883
884{decinteger} {
885 ECHO;
886 }
887{hexinteger} {
888 ECHO;
889 }
890{octinteger} {
891 ECHO;
892 }
893{bininteger} {
894 ECHO;
895 }
896{hexfail} {
897 ECHO;
898 }
899{octfail} {
900 ECHO;
901 }
902{binfail} {
903 ECHO;
904 }
905{numeric} {
906 ECHO;
907 }
908{numericfail} {
909 /* throw back the .., and treat as integer */
910 yyless(yyleng - 2);
911 ECHO;
912 }
913{real} {
914 ECHO;
915 }
916{realfail} {
917 ECHO;
918 }
919{integer_junk} {
920 ECHO;
921 }
922{numeric_junk} {
923 ECHO;
924 }
925{real_junk} {
926 ECHO;
927 }
928
929
930{identifier} {
932 ECHO;
933 }
static void psqlscan_track_identifier(PsqlScanState state, const char *identifier)
Definition psqlscan.l:1016
934
935{other} {
936 ECHO;
937 }
938
939<<EOF>> {
940 if (cur_state->buffer_stack == NULL)
941 {
942 cur_state->start_state = YY_START;
943 return LEXRES_EOL; /* end of input reached */
944 }
945
946 /*
947 * We were expanding a variable, so pop the inclusion
948 * stack and keep lexing
949 */
952 }
void psqlscan_select_top_buffer(PsqlScanState state)
Definition psqlscan.l:1525
953
954%%