parser.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #include <yql/essentials/parser/pg_wrapper/interface/raw_parser.h>
  2. #include "arena_ctx.h"
  3. #include <util/generic/scope.h>
  4. #include <fcntl.h>
  5. #include <stdint.h>
  6. #ifndef WIN32
  7. #include <pthread.h>
  8. #endif
  9. #include <signal.h>
  10. #define TypeName PG_TypeName
  11. #define SortBy PG_SortBy
  12. #define Sort PG_Sort
  13. #define Unique PG_Unique
  14. #undef SIZEOF_SIZE_T
  15. extern "C" {
  16. #include "postgres.h"
  17. #include "access/session.h"
  18. #include "access/xact.h"
  19. #include "catalog/namespace.h"
  20. #include "mb/pg_wchar.h"
  21. #include "nodes/pg_list.h"
  22. #include "nodes/parsenodes.h"
  23. #include "nodes/value.h"
  24. #include "parser/parser.h"
  25. #include "utils/guc.h"
  26. #include "utils/palloc.h"
  27. #include "utils/memutils.h"
  28. #include "utils/memdebug.h"
  29. #include "utils/resowner.h"
  30. #include "utils/timestamp.h"
  31. #include "utils/guc_hooks.h"
  32. #include "port/pg_bitutils.h"
  33. #include "port/pg_crc32c.h"
  34. #include "postmaster/postmaster.h"
  35. #include "storage/latch.h"
  36. #include "storage/proc.h"
  37. #include "miscadmin.h"
  38. #include "tcop/tcopprot.h"
  39. #include "tcop/utility.h"
  40. #include "thread_inits.h"
  41. #undef Abs
  42. #undef Min
  43. #undef Max
  44. #undef TypeName
  45. #undef SortBy
  46. #undef LOG
  47. #undef INFO
  48. #undef NOTICE
  49. #undef WARNING
  50. #undef ERROR
  51. #undef FATAL
  52. #undef PANIC
  53. #undef open
  54. #undef fopen
  55. #undef bind
  56. #undef locale_t
  57. }
  58. #include "utils.h"
  59. extern "C" {
  60. extern __thread Latch LocalLatchData;
  61. extern void destroy_timezone_hashtable();
  62. extern void destroy_typecache_hashtable();
  63. extern void free_current_locale_conv();
  64. extern void RE_cleanup_cache();
  65. const char *progname;
  66. #define STDERR_BUFFER_LEN 4096
  67. #define DEBUG
  68. typedef struct {
  69. char* message; // exception message
  70. char* funcname; // source function of exception (e.g. SearchSysCache)
  71. char* filename; // source of exception (e.g. parse.l)
  72. int lineno; // source of exception (e.g. 104)
  73. int cursorpos; // char in query at which exception occurred
  74. char* context; // additional context (optional, can be NULL)
  75. } PgQueryError;
  76. typedef struct {
  77. List *tree;
  78. char* stderr_buffer;
  79. PgQueryError* error;
  80. } PgQueryInternalParsetreeAndError;
  81. PgQueryInternalParsetreeAndError pg_query_raw_parse(const char* input) {
  82. PgQueryInternalParsetreeAndError result = { 0 };
  83. char stderr_buffer[STDERR_BUFFER_LEN + 1] = { 0 };
  84. #ifndef DEBUG
  85. int stderr_global;
  86. int stderr_pipe[2];
  87. #endif
  88. #ifndef DEBUG
  89. // Setup pipe for stderr redirection
  90. if (pipe(stderr_pipe) != 0) {
  91. PgQueryError* error = (PgQueryError*)malloc(sizeof(PgQueryError));
  92. error->message = strdup("Failed to open pipe, too many open file descriptors");
  93. result.error = error;
  94. return result;
  95. }
  96. fcntl(stderr_pipe[0], F_SETFL, fcntl(stderr_pipe[0], F_GETFL) | O_NONBLOCK);
  97. // Redirect stderr to the pipe
  98. stderr_global = dup(STDERR_FILENO);
  99. dup2(stderr_pipe[1], STDERR_FILENO);
  100. close(stderr_pipe[1]);
  101. #endif
  102. PG_TRY();
  103. {
  104. result.tree = raw_parser(input, RAW_PARSE_DEFAULT);
  105. #ifndef DEBUG
  106. // Save stderr for result
  107. read(stderr_pipe[0], stderr_buffer, STDERR_BUFFER_LEN);
  108. #endif
  109. result.stderr_buffer = strdup(stderr_buffer);
  110. }
  111. PG_CATCH();
  112. {
  113. ErrorData* error_data;
  114. PgQueryError* error;
  115. error_data = CopyErrorData();
  116. // Note: This is intentionally malloc so exiting the memory context doesn't free this
  117. error = (PgQueryError*)malloc(sizeof(PgQueryError));
  118. error->message = strdup(error_data->message);
  119. error->filename = strdup(error_data->filename);
  120. error->funcname = strdup(error_data->funcname);
  121. error->context = NULL;
  122. error->lineno = error_data->lineno;
  123. error->cursorpos = error_data->cursorpos;
  124. result.error = error;
  125. FlushErrorState();
  126. }
  127. PG_END_TRY();
  128. #ifndef DEBUG
  129. // Restore stderr, close pipe
  130. dup2(stderr_global, STDERR_FILENO);
  131. close(stderr_pipe[0]);
  132. close(stderr_global);
  133. #endif
  134. return result;
  135. }
  136. void pg_query_free_error(PgQueryError *error) {
  137. free(error->message);
  138. free(error->funcname);
  139. free(error->filename);
  140. if (error->context) {
  141. free(error->context);
  142. }
  143. free(error);
  144. }
  145. }
  146. namespace NYql {
  147. static struct TGlobalInit {
  148. TGlobalInit() {
  149. pg_crc32c crc = 0;
  150. pg_popcount32(0);
  151. pg_popcount64(0);
  152. COMP_CRC32C(crc,"",0);
  153. }
  154. } GlobalInit;
  155. void PGParse(const TString& input, IPGParseEvents& events) {
  156. pg_thread_init();
  157. PgQueryInternalParsetreeAndError parsetree_and_error;
  158. TArenaMemoryContext arena;
  159. auto prevErrorContext = ErrorContext;
  160. ErrorContext = CurrentMemoryContext;
  161. Y_DEFER {
  162. ErrorContext = prevErrorContext;
  163. };
  164. parsetree_and_error = pg_query_raw_parse(input.c_str());
  165. Y_DEFER {
  166. if (parsetree_and_error.error) {
  167. pg_query_free_error(parsetree_and_error.error);
  168. }
  169. free(parsetree_and_error.stderr_buffer);
  170. };
  171. if (parsetree_and_error.error) {
  172. TPosition position(0, 1);
  173. // cursorpos is about codepoints, not bytes
  174. TTextWalker walker(position, true);
  175. auto cursorpos = parsetree_and_error.error->cursorpos;
  176. size_t codepoints = 0;
  177. if (cursorpos >= 0) {
  178. for (size_t i = 0; i < input.size(); ++i) {
  179. if (codepoints == cursorpos) {
  180. break;
  181. }
  182. if (!TTextWalker::IsUtf8Intermediate(input[i])) {
  183. ++codepoints;
  184. }
  185. walker.Advance(input[i]);
  186. }
  187. }
  188. events.OnError(TIssue(position, "ERROR: " + TString(parsetree_and_error.error->message) + "\n"));
  189. } else {
  190. events.OnResult(parsetree_and_error.tree);
  191. }
  192. }
  193. TString PrintPGTree(const List* raw) {
  194. auto str = nodeToString(raw);
  195. Y_DEFER {
  196. pfree(str);
  197. };
  198. return TString(str);
  199. }
  200. TString GetCommandName(Node* node) {
  201. return CreateCommandName(node);
  202. }
  203. }
  204. extern "C" void setup_pg_thread_cleanup() {
  205. struct TThreadCleanup {
  206. ~TThreadCleanup() {
  207. NYql::TExtensionsRegistry::Instance().CleanupThread();
  208. destroy_timezone_hashtable();
  209. destroy_typecache_hashtable();
  210. RE_cleanup_cache();
  211. free_current_locale_conv();
  212. ResourceOwnerDelete(CurrentResourceOwner);
  213. MemoryContextDelete(TopMemoryContext);
  214. free(MyProc);
  215. }
  216. };
  217. static thread_local TThreadCleanup ThreadCleanup;
  218. Log_error_verbosity = PGERROR_DEFAULT;
  219. SetDatabaseEncoding(PG_UTF8);
  220. SetClientEncoding(PG_UTF8);
  221. InitializeClientEncoding();
  222. MemoryContextInit();
  223. auto owner = ResourceOwnerCreate(NULL, "TopTransaction");
  224. TopTransactionResourceOwner = owner;
  225. CurTransactionResourceOwner = owner;
  226. CurrentResourceOwner = owner;
  227. MyProcPid = getpid();
  228. MyStartTimestamp = GetCurrentTimestamp();
  229. MyStartTime = timestamptz_to_time_t(MyStartTimestamp);
  230. InitializeLatchSupport();
  231. MyLatch = &LocalLatchData;
  232. InitLatch(MyLatch);
  233. InitializeLatchWaitSet();
  234. MyProc = (PGPROC*)malloc(sizeof(PGPROC));
  235. Zero(*MyProc);
  236. StartTransactionCommand();
  237. InitializeSession();
  238. work_mem = MAX_KILOBYTES; // a way to postpone spilling for tuple stores
  239. assign_max_stack_depth(1024, nullptr);
  240. MyDatabaseId = 3; // from catalog.pg_database
  241. namespace_search_path = pstrdup("public");
  242. InitializeSessionUserId(nullptr, 1);
  243. };