Line data Source code
1 : /*-------------------------------------------------------------------------
2 : * A stack of automaton states to handle nested conditionals.
3 : *
4 : * Copyright (c) 2000-2026, PostgreSQL Global Development Group
5 : *
6 : * src/fe_utils/conditional.c
7 : *
8 : *-------------------------------------------------------------------------
9 : */
10 : #include "postgres_fe.h"
11 :
12 : #include "fe_utils/conditional.h"
13 :
14 : /*
15 : * create stack
16 : */
17 : ConditionalStack
18 9756 : conditional_stack_create(void)
19 : {
20 9756 : ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
21 :
22 9756 : cstack->head = NULL;
23 9756 : return cstack;
24 : }
25 :
26 : /*
27 : * Destroy all the elements from the stack. The stack itself is not freed.
28 : */
29 : void
30 9615 : conditional_stack_reset(ConditionalStack cstack)
31 10 : {
32 9615 : if (!cstack)
33 0 : return; /* nothing to do here */
34 :
35 9625 : while (conditional_stack_pop(cstack))
36 10 : continue;
37 : }
38 :
39 : /*
40 : * destroy stack
41 : */
42 : void
43 9604 : conditional_stack_destroy(ConditionalStack cstack)
44 : {
45 9604 : conditional_stack_reset(cstack);
46 9604 : free(cstack);
47 9604 : }
48 :
49 : /*
50 : * Create a new conditional branch.
51 : */
52 : void
53 28332 : conditional_stack_push(ConditionalStack cstack, ifState new_state)
54 : {
55 28332 : IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
56 :
57 28332 : p->if_state = new_state;
58 28332 : p->query_len = -1;
59 28332 : p->paren_depth = -1;
60 28332 : p->next = cstack->head;
61 28332 : cstack->head = p;
62 28332 : }
63 :
64 : /*
65 : * Destroy the topmost conditional branch.
66 : * Returns false if there was no branch to end.
67 : */
68 : bool
69 37944 : conditional_stack_pop(ConditionalStack cstack)
70 : {
71 37944 : IfStackElem *p = cstack->head;
72 :
73 37944 : if (!p)
74 9616 : return false;
75 28328 : cstack->head = cstack->head->next;
76 28328 : free(p);
77 28328 : return true;
78 : }
79 :
80 : /*
81 : * Returns current stack depth, for debugging purposes.
82 : */
83 : int
84 0 : conditional_stack_depth(ConditionalStack cstack)
85 : {
86 0 : if (cstack == NULL)
87 0 : return -1;
88 : else
89 : {
90 0 : IfStackElem *p = cstack->head;
91 0 : int depth = 0;
92 :
93 0 : while (p != NULL)
94 : {
95 0 : depth++;
96 0 : p = p->next;
97 : }
98 0 : return depth;
99 : }
100 : }
101 :
102 : /*
103 : * Fetch the current state of the top of the stack.
104 : */
105 : ifState
106 260769 : conditional_stack_peek(ConditionalStack cstack)
107 : {
108 260769 : if (conditional_stack_empty(cstack))
109 258144 : return IFSTATE_NONE;
110 2625 : return cstack->head->if_state;
111 : }
112 :
113 : /*
114 : * Change the state of the topmost branch.
115 : * Returns false if there was no branch state to set.
116 : */
117 : bool
118 171 : conditional_stack_poke(ConditionalStack cstack, ifState new_state)
119 : {
120 171 : if (conditional_stack_empty(cstack))
121 0 : return false;
122 171 : cstack->head->if_state = new_state;
123 171 : return true;
124 : }
125 :
126 : /*
127 : * True if there are no active \if-blocks.
128 : */
129 : bool
130 270512 : conditional_stack_empty(ConditionalStack cstack)
131 : {
132 270512 : return cstack->head == NULL;
133 : }
134 :
135 : /*
136 : * True if we should execute commands normally; that is, the current
137 : * conditional branch is active, or there is no open \if block.
138 : */
139 : bool
140 260054 : conditional_active(ConditionalStack cstack)
141 : {
142 260054 : ifState s = conditional_stack_peek(cstack);
143 :
144 260054 : return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
145 : }
146 :
147 : /*
148 : * Save current query buffer length in topmost stack entry.
149 : */
150 : void
151 140 : conditional_stack_set_query_len(ConditionalStack cstack, int len)
152 : {
153 : Assert(!conditional_stack_empty(cstack));
154 140 : cstack->head->query_len = len;
155 140 : }
156 :
157 : /*
158 : * Fetch last-recorded query buffer length from topmost stack entry.
159 : * Will return -1 if no stack or it was never saved.
160 : */
161 : int
162 118 : conditional_stack_get_query_len(ConditionalStack cstack)
163 : {
164 118 : if (conditional_stack_empty(cstack))
165 0 : return -1;
166 118 : return cstack->head->query_len;
167 : }
168 :
169 : /*
170 : * Save current parenthesis nesting depth in topmost stack entry.
171 : */
172 : void
173 140 : conditional_stack_set_paren_depth(ConditionalStack cstack, int depth)
174 : {
175 : Assert(!conditional_stack_empty(cstack));
176 140 : cstack->head->paren_depth = depth;
177 140 : }
178 :
179 : /*
180 : * Fetch last-recorded parenthesis nesting depth from topmost stack entry.
181 : * Will return -1 if no stack or it was never saved.
182 : */
183 : int
184 118 : conditional_stack_get_paren_depth(ConditionalStack cstack)
185 : {
186 118 : if (conditional_stack_empty(cstack))
187 0 : return -1;
188 118 : return cstack->head->paren_depth;
189 : }
|