/* *ControlstructurefortheAVLtree(binarysearchtreekept *balancedwiththeAVLalgorithm)
*/ typedefstruct _avl_tree
{ int count; /* Total number of nodes */
avl_node *root; /* root of the tree */
avl_node *end; /* Immutable dereferenceable empty tree */
} avl_tree;
/* *Mainentrypointtothismodule. * *Processthedatafrom*resaccordingtotheoptionsinpset(global), *togeneratethehorizontalandverticalheaderscontents, *thencallprintCrosstab()fortheactualoutput.
*/ bool
PrintResultInCrosstab(const PGresult *res)
{ bool retval = false;
avl_tree piv_columns;
avl_tree piv_rows;
pivot_field *array_columns = NULL;
pivot_field *array_rows = NULL; int num_columns = 0; int num_rows = 0; int field_for_rows; int field_for_columns; int field_for_data; int sort_field_for_columns; int rn;
avlInit(&piv_rows);
avlInit(&piv_columns);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("\\crosstabview: statement did not return a result set"); goto error_return;
}
if (PQnfields(res) < 3)
{
pg_log_error("\\crosstabview: query must return at least three columns"); goto error_return;
}
/* Process first optional arg (vertical header column) */ if (pset.ctv_args[0] == NULL)
field_for_rows = 0; else
{
field_for_rows = indexOfColumn(pset.ctv_args[0], res); if (field_for_rows < 0) goto error_return;
}
/* Process second optional arg (horizontal header column) */ if (pset.ctv_args[1] == NULL)
field_for_columns = 1; else
{
field_for_columns = indexOfColumn(pset.ctv_args[1], res); if (field_for_columns < 0) goto error_return;
}
/* Insist that header columns be distinct */ if (field_for_columns == field_for_rows)
{
pg_log_error("\\crosstabview: vertical and horizontal headers must be different columns"); goto error_return;
}
/* Process third optional arg (data column) */ if (pset.ctv_args[2] == NULL)
{ int i;
/* *Ifthedatacolumnwasnotspecified,wesearchfortheonenot *usedaseitherverticalorhorizontalheaders.Mustbeexactly *threecolumns,orthiswon'tbeunique.
*/ if (PQnfields(res) != 3)
{
pg_log_error("\\crosstabview: data column must be specified when query returns more than three columns"); goto error_return;
}
field_for_data = -1; for (i = 0; i < PQnfields(res); i++)
{ if (i != field_for_rows && i != field_for_columns)
{
field_for_data = i; break;
}
}
Assert(field_for_data >= 0);
} else
{
field_for_data = indexOfColumn(pset.ctv_args[2], res); if (field_for_data < 0) goto error_return;
}
/* Process fourth optional arg (horizontal header sort column) */ if (pset.ctv_args[3] == NULL)
sort_field_for_columns = -1; /* no sort column */ else
{
sort_field_for_columns = indexOfColumn(pset.ctv_args[3], res); if (sort_field_for_columns < 0) goto error_return;
}
if (piv_columns.count > CROSSTABVIEW_MAX_COLUMNS)
{
pg_log_error("\\crosstabview: maximum number of columns (%d) exceeded",
CROSSTABVIEW_MAX_COLUMNS); goto error_return;
}
/* *OutputthepivotedresultsetwiththeprintTable*functions.Returntrue *ifsuccessful,falseotherwise.
*/ staticbool
printCrosstab(const PGresult *result, int num_columns, pivot_field *piv_columns, int field_for_columns, int num_rows, pivot_field *piv_rows, int field_for_rows, int field_for_data)
{
printQueryOpt popt = pset.popt;
printTableContent cont; int i,
rn; char col_align; int *horiz_map; bool retval = false;
/* Step 1: set target column names (horizontal header) */
/* The name of the first column is kept unchanged by the pivoting */
printTableAddHeader(&cont,
PQfname(result, field_for_rows), false,
column_type_alignment(PQftype(result,
field_for_rows)));
/* *Toiterateoverpiv_columns[]bypiv_columns[].rank,createareverse *mapassociatingeachpiv_columns[].ranktoitsindexinpiv_columns. *ThisavoidsanO(N^2)looplater.
*/
horiz_map = (int *) pg_malloc(sizeof(int) * num_columns); for (i = 0; i < num_columns; i++)
horiz_map[piv_columns[i].rank] = i;
/* Deallocate recursively an AVL tree, starting from node */ staticvoid
avlFree(avl_tree *tree, avl_node *node)
{ if (node->children[0] != tree->end)
{
avlFree(tree, node->children[0]);
pg_free(node->children[0]);
} if (node->children[1] != tree->end)
{
avlFree(tree, node->children[1]);
pg_free(node->children[1]);
} if (node == tree->root)
{ /* free the root separately as it's not child of anything */ if (node != tree->end)
pg_free(node); /* free the tree->end struct only once and when all else is freed */
pg_free(tree->end);
}
}
/* Set the height to 1 plus the greatest of left and right heights */ staticvoid
avlUpdateHeight(avl_node *n)
{
n->height = 1 + (n->children[0]->height > n->children[1]->height ?
n->children[0]->height :
n->children[1]->height);
}
/* Rotate a subtree left (dir=0) or right (dir=1). Not recursive */ static avl_node *
avlRotate(avl_node **current, int dir)
{
avl_node *before = *current;
avl_node *after = (*current)->children[dir];
/* Insert the value into the AVL tree, if it does not preexist */ staticvoid
avlMergeValue(avl_tree *tree, char *name, char *sort_value)
{
pivot_field field;
if (arg[0] && strspn(arg, "0123456789") == strlen(arg))
{ /* if arg contains only digits, it's a column number */
idx = atoi(arg) - 1; if (idx < 0 || idx >= PQnfields(res))
{
pg_log_error("\\crosstabview: column number %d is out of range 1..%d",
idx + 1, PQnfields(res)); return -1;
}
} else
{ int i;
/* Now look for match(es) among res' column names */
idx = -1; for (i = 0; i < PQnfields(res); i++)
{ if (strcmp(arg, PQfname(res, i)) == 0)
{ if (idx >= 0)
{ /* another idx was already found for the same name */
pg_log_error("\\crosstabview: ambiguous column name: \"%s\"", arg); return -1;
}
idx = i;
}
} if (idx == -1)
{
pg_log_error("\\crosstabview: column name not found: \"%s\"", arg); return -1;
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.18Bemerkung:
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.