postgresql/src/fe_utils/conditional.c

190 lines
3.7 KiB
C

/*-------------------------------------------------------------------------
* A stack of automaton states to handle nested conditionals.
*
* Copyright (c) 2000-2024, 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 all the elements from the stack. The stack itself is not freed.
*/
void
conditional_stack_reset(ConditionalStack cstack)
{
if (!cstack)
return; /* nothing to do here */
while (conditional_stack_pop(cstack))
continue;
}
/*
* destroy stack
*/
void
conditional_stack_destroy(ConditionalStack cstack)
{
conditional_stack_reset(cstack);
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;
}