summaryrefslogtreecommitdiffstats
path: root/src/fe_utils/conditional.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe_utils/conditional.c')
-rw-r--r--src/fe_utils/conditional.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/fe_utils/conditional.c b/src/fe_utils/conditional.c
new file mode 100644
index 0000000..4df72d4
--- /dev/null
+++ b/src/fe_utils/conditional.c
@@ -0,0 +1,177 @@
+/*-------------------------------------------------------------------------
+ * A stack of automaton states to handle nested conditionals.
+ *
+ * Copyright (c) 2000-2020, PostgreSQL Global Development Group
+ *
+ * src/fe_utils/conditional.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include "fe_utils/conditional.h"
+
+/*
+ * create stack
+ */
+ConditionalStack
+conditional_stack_create(void)
+{
+ ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
+
+ cstack->head = NULL;
+ return cstack;
+}
+
+/*
+ * destroy stack
+ */
+void
+conditional_stack_destroy(ConditionalStack cstack)
+{
+ while (conditional_stack_pop(cstack))
+ continue;
+ free(cstack);
+}
+
+/*
+ * Create a new conditional branch.
+ */
+void
+conditional_stack_push(ConditionalStack cstack, ifState new_state)
+{
+ IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
+
+ p->if_state = new_state;
+ p->query_len = -1;
+ p->paren_depth = -1;
+ p->next = cstack->head;
+ cstack->head = p;
+}
+
+/*
+ * Destroy the topmost conditional branch.
+ * Returns false if there was no branch to end.
+ */
+bool
+conditional_stack_pop(ConditionalStack cstack)
+{
+ IfStackElem *p = cstack->head;
+
+ if (!p)
+ return false;
+ cstack->head = cstack->head->next;
+ free(p);
+ return true;
+}
+
+/*
+ * Returns current stack depth, for debugging purposes.
+ */
+int
+conditional_stack_depth(ConditionalStack cstack)
+{
+ if (cstack == NULL)
+ return -1;
+ else
+ {
+ IfStackElem *p = cstack->head;
+ int depth = 0;
+
+ while (p != NULL)
+ {
+ depth++;
+ p = p->next;
+ }
+ return depth;
+ }
+}
+
+/*
+ * Fetch the current state of the top of the stack.
+ */
+ifState
+conditional_stack_peek(ConditionalStack cstack)
+{
+ if (conditional_stack_empty(cstack))
+ return IFSTATE_NONE;
+ return cstack->head->if_state;
+}
+
+/*
+ * Change the state of the topmost branch.
+ * Returns false if there was no branch state to set.
+ */
+bool
+conditional_stack_poke(ConditionalStack cstack, ifState new_state)
+{
+ if (conditional_stack_empty(cstack))
+ return false;
+ cstack->head->if_state = new_state;
+ return true;
+}
+
+/*
+ * True if there are no active \if-blocks.
+ */
+bool
+conditional_stack_empty(ConditionalStack cstack)
+{
+ return cstack->head == NULL;
+}
+
+/*
+ * True if we should execute commands normally; that is, the current
+ * conditional branch is active, or there is no open \if block.
+ */
+bool
+conditional_active(ConditionalStack cstack)
+{
+ ifState s = conditional_stack_peek(cstack);
+
+ return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
+}
+
+/*
+ * Save current query buffer length in topmost stack entry.
+ */
+void
+conditional_stack_set_query_len(ConditionalStack cstack, int len)
+{
+ Assert(!conditional_stack_empty(cstack));
+ cstack->head->query_len = len;
+}
+
+/*
+ * Fetch last-recorded query buffer length from topmost stack entry.
+ * Will return -1 if no stack or it was never saved.
+ */
+int
+conditional_stack_get_query_len(ConditionalStack cstack)
+{
+ if (conditional_stack_empty(cstack))
+ return -1;
+ return cstack->head->query_len;
+}
+
+/*
+ * Save current parenthesis nesting depth in topmost stack entry.
+ */
+void
+conditional_stack_set_paren_depth(ConditionalStack cstack, int depth)
+{
+ Assert(!conditional_stack_empty(cstack));
+ cstack->head->paren_depth = depth;
+}
+
+/*
+ * Fetch last-recorded parenthesis nesting depth from topmost stack entry.
+ * Will return -1 if no stack or it was never saved.
+ */
+int
+conditional_stack_get_paren_depth(ConditionalStack cstack)
+{
+ if (conditional_stack_empty(cstack))
+ return -1;
+ return cstack->head->paren_depth;
+}