int main(void) { yy_extra_type yyextra; int res; int fd2; for (int i = 0; i < NTIMES; ++i) { yyscan_t scanner = scanner_init(stdin, &yyextra, ScanKeywords, NumScanKeywords); parser_init(); yyparse(scanner); res = scanner_finish(scanner); if (res < 0) { return(res); } if (fseek(stdin, 0, SEEK_SET) < 0) { return(0); } if (i == 0) { if ((fd2 = open("/dev/null", O_WRONLY)) < 0) { perror("open"); return(-1); } if (dup2(fd2,1) < 0) { perror("dup2"); return(-1); } close(fd2); } } return(0); }
/* * raw_parser * Given a query in string form, do lexical and grammatical analysis. * * Returns a list of raw (un-analyzed) parse trees. The immediate elements * of the list are always RawStmt nodes. */ List * raw_parser(const char *str) { core_yyscan_t yyscanner; base_yy_extra_type yyextra; int yyresult; /* initialize the flex scanner */ yyscanner = scanner_init(str, &yyextra.core_yy_extra, ScanKeywords, NumScanKeywords); /* base_yylex() only needs this much initialization */ yyextra.have_lookahead = false; /* initialize the bison parser */ parser_init(&yyextra); /* Parse! */ yyresult = base_yyparse(yyscanner); /* Clean up (release memory) */ scanner_finish(yyscanner); if (yyresult) /* error */ return NIL; return yyextra.parsetree; }
void lexer_destroy(yyscan_t scanner) { void* extra = base_yyget_extra(scanner); scanner_finish(scanner); base_yylex_destroy(scanner); free(extra); }
/* * Called after parsing is done to clean up after plpgsql_scanner_init() */ void plpgsql_scanner_finish(void) { /* release storage */ scanner_finish(yyscanner); /* avoid leaving any dangling pointers */ yyscanner = NULL; scanorig = NULL; }
/* * pg_parse_string_token - get the value represented by a string literal * * Given the textual form of a SQL string literal, produce the represented * value as a palloc'd string. It is caller's responsibility that the * passed string does represent one single string literal. * * We export this function to avoid having plpgsql depend on internal details * of the core grammar (such as the token code assigned to SCONST). Note * that since the scanner isn't presently re-entrant, this cannot be used * during use of the main parser/scanner. */ char * pg_parse_string_token(const char *token) { int ctoken; scanner_init(token); ctoken = base_yylex(); if (ctoken != SCONST) /* caller error */ elog(ERROR, "expected string constant, got token code %d", ctoken); scanner_finish(); return base_yylval.str; }
/* * raw_parser * Given a query in string form, do lexical and grammatical analysis. * * Returns a list of raw (un-analyzed) parse trees. */ List * raw_parser(const char *str) { int yyresult; parsetree = NIL; /* in case grammar forgets to set it */ have_lookahead = false; scanner_init(str); parser_init(); yyresult = base_yyparse(); scanner_finish(); if (yyresult) /* error */ return NIL; return parsetree; }
/* * raw_parser * Given a query in string form, do lexical and grammatical analysis. * * Returns a list of raw (un-analyzed) parse trees. */ List * raw_parser(const char *str) { char *sqlString; core_yyscan_t yyscanner; base_yy_extra_type yyextra; int yyresult; /* initialize the flex scanner */ yyscanner = scanner_init(str, &yyextra.core_yy_extra, ScanKeywords, NumScanKeywords); /* base_yylex() only needs this much initialization */ yyextra.have_lookahead = false; /* initialize the bison parser */ parser_init(&yyextra); /* Parse! */ yyresult = base_yyparse(yyscanner); /* Clean up (release memory) */ scanner_finish(yyscanner); if (yyresult) /* error */ return NIL; /* elog(WARNING, "Expression Tree: %s", nodeToString((const void *)yyextra.parsetree)); sqlString = toSQL((const void *)yyextra.parsetree); elog(WARNING, "SQL Conversion: %s", sqlString); */ return yyextra.parsetree; }
/* * Given a valid SQL string and an array of constant-location records, * fill in the textual lengths of those constants. * * The constants may use any allowed constant syntax, such as float literals, * bit-strings, single-quoted strings and dollar-quoted strings. This is * accomplished by using the public API for the core scanner. * * It is the caller's job to ensure that the string is a valid SQL statement * with constants at the indicated locations. Since in practice the string * has already been parsed, and the locations that the caller provides will * have originated from within the authoritative parser, this should not be * a problem. * * Duplicate constant pointers are possible, and will have their lengths * marked as '-1', so that they are later ignored. (Actually, we assume the * lengths were initialized as -1 to start with, and don't change them here.) * * N.B. There is an assumption that a '-' character at a Const location begins * a negative numeric constant. This precludes there ever being another * reason for a constant to start with a '-'. */ static void fill_in_constant_lengths(pgssConstLocations *jstate, const char *query) { pgssLocationLen *locs; core_yyscan_t yyscanner; core_yy_extra_type yyextra; core_YYSTYPE yylval; YYLTYPE yylloc; int last_loc = -1; int i; /* * Sort the records by location so that we can process them in order while * scanning the query text. */ if (jstate->clocations_count > 1) qsort(jstate->clocations, jstate->clocations_count, sizeof(pgssLocationLen), comp_location); locs = jstate->clocations; /* initialize the flex scanner --- should match raw_parser() */ yyscanner = scanner_init(query, &yyextra, ScanKeywords, NumScanKeywords); /* Search for each constant, in sequence */ for (i = 0; i < jstate->clocations_count; i++) { int loc = locs[i].location; int tok; Assert(loc >= 0); if (loc <= last_loc) continue; /* Duplicate constant, ignore */ /* Lex tokens until we find the desired constant */ for (;;) { tok = core_yylex(&yylval, &yylloc, yyscanner); /* We should not hit end-of-string, but if we do, behave sanely */ if (tok == 0) break; /* out of inner for-loop */ /* * We should find the token position exactly, but if we somehow * run past it, work with that. */ if (yylloc >= loc) { if (query[loc] == '-') { /* * It's a negative value - this is the one and only case * where we replace more than a single token. * * Do not compensate for the core system's special-case * adjustment of location to that of the leading '-' * operator in the event of a negative constant. It is * also useful for our purposes to start from the minus * symbol. In this way, queries like "select * from foo * where bar = 1" and "select * from foo where bar = -2" * will have identical normalized query strings. */ tok = core_yylex(&yylval, &yylloc, yyscanner); if (tok == 0) break; /* out of inner for-loop */ } /* * We now rely on the assumption that flex has placed a zero * byte after the text of the current token in scanbuf. */ locs[i].length = (int) strlen(yyextra.scanbuf + loc); /* Quoted string with Unicode escapes * * The lexer consumes trailing whitespace in order to find UESCAPE, but if there * is no UESCAPE it has still consumed it - don't include it in constant length. */ if (locs[i].length > 4 && /* U&'' */ (yyextra.scanbuf[loc] == 'u' || yyextra.scanbuf[loc] == 'U') && yyextra.scanbuf[loc + 1] == '&' && yyextra.scanbuf[loc + 2] == '\'') { int j = locs[i].length - 1; /* Skip the \0 */ for (; j >= 0 && scanner_isspace(yyextra.scanbuf[loc + j]); j--) {} locs[i].length = j + 1; /* Count the \0 */ } break; /* out of inner for-loop */ } } /* If we hit end-of-string, give up, leaving remaining lengths -1 */ if (tok == 0) break; last_loc = loc; } scanner_finish(yyscanner); }