Branch data 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 : 269 : conditional_stack_create(void)
19 : : {
20 : 269 : ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
21 : :
22 : 269 : cstack->head = NULL;
23 : 538 : return cstack;
24 : 269 : }
25 : :
26 : : /*
27 : : * Destroy all the elements from the stack. The stack itself is not freed.
28 : : */
29 : : void
30 : 269 : conditional_stack_reset(ConditionalStack cstack)
31 : : {
32 [ + - ]: 269 : if (!cstack)
33 : 0 : return; /* nothing to do here */
34 : :
35 [ + + ]: 272 : while (conditional_stack_pop(cstack))
36 : 3 : continue;
37 : 269 : }
38 : :
39 : : /*
40 : : * destroy stack
41 : : */
42 : : void
43 : 269 : conditional_stack_destroy(ConditionalStack cstack)
44 : : {
45 : 269 : conditional_stack_reset(cstack);
46 : 269 : free(cstack);
47 : 269 : }
48 : :
49 : : /*
50 : : * Create a new conditional branch.
51 : : */
52 : : void
53 : 2500 : conditional_stack_push(ConditionalStack cstack, ifState new_state)
54 : : {
55 : 2500 : IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
56 : :
57 : 2500 : p->if_state = new_state;
58 : 2500 : p->query_len = -1;
59 : 2500 : p->paren_depth = -1;
60 : 2500 : p->next = cstack->head;
61 : 2500 : cstack->head = p;
62 : 2500 : }
63 : :
64 : : /*
65 : : * Destroy the topmost conditional branch.
66 : : * Returns false if there was no branch to end.
67 : : */
68 : : bool
69 : 2769 : conditional_stack_pop(ConditionalStack cstack)
70 : : {
71 : 2769 : IfStackElem *p = cstack->head;
72 : :
73 [ + + ]: 2769 : if (!p)
74 : 269 : return false;
75 : 2500 : cstack->head = cstack->head->next;
76 : 2500 : free(p);
77 : 2500 : return true;
78 : 2769 : }
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 : 0 : }
100 : 0 : }
101 : :
102 : : /*
103 : : * Fetch the current state of the top of the stack.
104 : : */
105 : : ifState
106 : 56800 : conditional_stack_peek(ConditionalStack cstack)
107 : : {
108 [ + + ]: 56800 : if (conditional_stack_empty(cstack))
109 : 56364 : return IFSTATE_NONE;
110 : 436 : return cstack->head->if_state;
111 : 56800 : }
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 : 45 : conditional_stack_poke(ConditionalStack cstack, ifState new_state)
119 : : {
120 [ - + ]: 45 : if (conditional_stack_empty(cstack))
121 : 0 : return false;
122 : 45 : cstack->head->if_state = new_state;
123 : 45 : return true;
124 : 45 : }
125 : :
126 : : /*
127 : : * True if there are no active \if-blocks.
128 : : */
129 : : bool
130 : 57265 : conditional_stack_empty(ConditionalStack cstack)
131 : : {
132 : 57265 : 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 : 56741 : conditional_active(ConditionalStack cstack)
141 : : {
142 : 56741 : ifState s = conditional_stack_peek(cstack);
143 : :
144 [ + + + + ]: 56741 : return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
145 : 56741 : }
146 : :
147 : : /*
148 : : * Save current query buffer length in topmost stack entry.
149 : : */
150 : : void
151 : 42 : conditional_stack_set_query_len(ConditionalStack cstack, int len)
152 : : {
153 [ + - ]: 42 : Assert(!conditional_stack_empty(cstack));
154 : 42 : cstack->head->query_len = len;
155 : 42 : }
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 : 35 : conditional_stack_get_query_len(ConditionalStack cstack)
163 : : {
164 [ - + ]: 35 : if (conditional_stack_empty(cstack))
165 : 0 : return -1;
166 : 35 : return cstack->head->query_len;
167 : 35 : }
168 : :
169 : : /*
170 : : * Save current parenthesis nesting depth in topmost stack entry.
171 : : */
172 : : void
173 : 42 : conditional_stack_set_paren_depth(ConditionalStack cstack, int depth)
174 : : {
175 [ + - ]: 42 : Assert(!conditional_stack_empty(cstack));
176 : 42 : cstack->head->paren_depth = depth;
177 : 42 : }
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 : 35 : conditional_stack_get_paren_depth(ConditionalStack cstack)
185 : : {
186 [ - + ]: 35 : if (conditional_stack_empty(cstack))
187 : 0 : return -1;
188 : 35 : return cstack->head->paren_depth;
189 : 35 : }
|