1 /*
2 * psql - the PostgreSQL interactive terminal
3 *
4 * Copyright (c) 2000-2017, PostgreSQL Global Development Group
5 *
6 * src/bin/psql/conditional.c
7 */
8 #include "postgres_fe.h"
9
10 #include "conditional.h"
11
12 /*
13 * create stack
14 */
15 ConditionalStack
conditional_stack_create(void)16 conditional_stack_create(void)
17 {
18 ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
19
20 cstack->head = NULL;
21 return cstack;
22 }
23
24 /*
25 * destroy stack
26 */
27 void
conditional_stack_destroy(ConditionalStack cstack)28 conditional_stack_destroy(ConditionalStack cstack)
29 {
30 while (conditional_stack_pop(cstack))
31 continue;
32 free(cstack);
33 }
34
35 /*
36 * Create a new conditional branch.
37 */
38 void
conditional_stack_push(ConditionalStack cstack,ifState new_state)39 conditional_stack_push(ConditionalStack cstack, ifState new_state)
40 {
41 IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
42
43 p->if_state = new_state;
44 p->query_len = -1;
45 p->paren_depth = -1;
46 p->next = cstack->head;
47 cstack->head = p;
48 }
49
50 /*
51 * Destroy the topmost conditional branch.
52 * Returns false if there was no branch to end.
53 */
54 bool
conditional_stack_pop(ConditionalStack cstack)55 conditional_stack_pop(ConditionalStack cstack)
56 {
57 IfStackElem *p = cstack->head;
58
59 if (!p)
60 return false;
61 cstack->head = cstack->head->next;
62 free(p);
63 return true;
64 }
65
66 /*
67 * Fetch the current state of the top of the stack.
68 */
69 ifState
conditional_stack_peek(ConditionalStack cstack)70 conditional_stack_peek(ConditionalStack cstack)
71 {
72 if (conditional_stack_empty(cstack))
73 return IFSTATE_NONE;
74 return cstack->head->if_state;
75 }
76
77 /*
78 * Change the state of the topmost branch.
79 * Returns false if there was no branch state to set.
80 */
81 bool
conditional_stack_poke(ConditionalStack cstack,ifState new_state)82 conditional_stack_poke(ConditionalStack cstack, ifState new_state)
83 {
84 if (conditional_stack_empty(cstack))
85 return false;
86 cstack->head->if_state = new_state;
87 return true;
88 }
89
90 /*
91 * True if there are no active \if-blocks.
92 */
93 bool
conditional_stack_empty(ConditionalStack cstack)94 conditional_stack_empty(ConditionalStack cstack)
95 {
96 return cstack->head == NULL;
97 }
98
99 /*
100 * True if we should execute commands normally; that is, the current
101 * conditional branch is active, or there is no open \if block.
102 */
103 bool
conditional_active(ConditionalStack cstack)104 conditional_active(ConditionalStack cstack)
105 {
106 ifState s = conditional_stack_peek(cstack);
107
108 return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
109 }
110
111 /*
112 * Save current query buffer length in topmost stack entry.
113 */
114 void
conditional_stack_set_query_len(ConditionalStack cstack,int len)115 conditional_stack_set_query_len(ConditionalStack cstack, int len)
116 {
117 Assert(!conditional_stack_empty(cstack));
118 cstack->head->query_len = len;
119 }
120
121 /*
122 * Fetch last-recorded query buffer length from topmost stack entry.
123 * Will return -1 if no stack or it was never saved.
124 */
125 int
conditional_stack_get_query_len(ConditionalStack cstack)126 conditional_stack_get_query_len(ConditionalStack cstack)
127 {
128 if (conditional_stack_empty(cstack))
129 return -1;
130 return cstack->head->query_len;
131 }
132
133 /*
134 * Save current parenthesis nesting depth in topmost stack entry.
135 */
136 void
conditional_stack_set_paren_depth(ConditionalStack cstack,int depth)137 conditional_stack_set_paren_depth(ConditionalStack cstack, int depth)
138 {
139 Assert(!conditional_stack_empty(cstack));
140 cstack->head->paren_depth = depth;
141 }
142
143 /*
144 * Fetch last-recorded parenthesis nesting depth from topmost stack entry.
145 * Will return -1 if no stack or it was never saved.
146 */
147 int
conditional_stack_get_paren_depth(ConditionalStack cstack)148 conditional_stack_get_paren_depth(ConditionalStack cstack)
149 {
150 if (conditional_stack_empty(cstack))
151 return -1;
152 return cstack->head->paren_depth;
153 }
154