/* * Return a freshly allocated List. Since empty non-NIL lists are * invalid, new_list() also allocates the head cell of the new list: * the caller should be sure to fill in that cell's data. */ static List * new_list(NodeTag type) { List *new_list; ListCell *new_head; new_head = pgut_new(ListCell); new_head->next = NULL; /* new_head->data is left undefined! */ new_list = pgut_new(List); new_list->type = type; new_list->length = 1; new_list->head = new_head; new_list->tail = new_head; return new_list; }
/* * Allocate a new cell and make it the head of the specified * list. Assumes the list it is passed is non-NIL. * * The data in the new head cell is undefined; the caller should be * sure to fill it in */ static void new_head_cell(List *list) { ListCell *new_head; new_head = pgut_new(ListCell); new_head->next = list->head; list->head = new_head; list->length++; }
/* * Allocate a new cell and make it the tail of the specified * list. Assumes the list it is passed is non-NIL. * * The data in the new tail cell is undefined; the caller should be * sure to fill it in */ static void new_tail_cell(List *list) { ListCell *new_tail; new_tail = pgut_new(ListCell); new_tail->next = NULL; list->tail->next = new_tail; list->tail = new_tail; list->length++; }
/* * Create new parray object. * Never returns NULL. */ parray * parray_new(void) { parray *a = pgut_new(parray); a->data = NULL; a->used = 0; a->alloced = 0; parray_expand(a, 1024); return a; }
void pgut_atexit_push(pgut_atexit_callback callback, void *userdata) { pgut_atexit_item *item; AssertArg(callback != NULL); item = pgut_new(pgut_atexit_item); item->callback = callback; item->userdata = userdata; item->next = pgut_atexit_stack; pgut_atexit_stack = item; }
/* * Return a shallow copy of the specified list, without the first N elements. */ List * list_copy_tail(List *oldlist, int nskip) { List *newlist; ListCell *newlist_prev; ListCell *oldlist_cur; if (nskip < 0) nskip = 0; /* would it be better to elog? */ if (oldlist == NIL || nskip >= oldlist->length) return NIL; newlist = new_list(oldlist->type); newlist->length = oldlist->length - nskip; /* * Skip over the unwanted elements. */ oldlist_cur = oldlist->head; while (nskip-- > 0) oldlist_cur = oldlist_cur->next; /* * Copy over the data in the first remaining cell; new_list() has already * allocated the head cell itself */ newlist->head->data = oldlist_cur->data; newlist_prev = newlist->head; oldlist_cur = oldlist_cur->next; while (oldlist_cur) { ListCell *newlist_cur; newlist_cur = pgut_new(ListCell); newlist_cur->data = oldlist_cur->data; newlist_prev->next = newlist_cur; newlist_prev = newlist_cur; oldlist_cur = oldlist_cur->next; } newlist_prev->next = NULL; newlist->tail = newlist_prev; return newlist; }
/* * Add a new cell to the list, in the position after 'prev_cell'. The * data in the cell is left undefined, and must be filled in by the * caller. 'list' is assumed to be non-NIL, and 'prev_cell' is assumed * to be non-NULL and a member of 'list'. */ static ListCell * add_new_cell(List *list, ListCell *prev_cell) { ListCell *new_cell; new_cell = pgut_new(ListCell); /* new_cell->data is left undefined! */ new_cell->next = prev_cell->next; prev_cell->next = new_cell; if (list->tail == prev_cell) list->tail = new_cell; list->length++; return new_cell; }
/* FIXME: support recursive error */ static pgutErrorData * getErrorData(void) { #ifdef PGUT_MULTI_THREADED pgutErrorData *edata = pthread_getspecific(pgut_edata_key); if (edata == NULL) { edata = pgut_new(pgutErrorData); memset(edata, 0, sizeof(pgutErrorData)); pthread_setspecific(pgut_edata_key, edata); } return edata; #else static pgutErrorData edata; return &edata; #endif }
/* * Return a shallow copy of the specified list. */ List * list_copy(List *oldlist) { List *newlist; ListCell *newlist_prev; ListCell *oldlist_cur; if (oldlist == NIL) return NIL; newlist = new_list(oldlist->type); newlist->length = oldlist->length; /* * Copy over the data in the first cell; new_list() has already allocated * the head cell itself */ newlist->head->data = oldlist->head->data; newlist_prev = newlist->head; oldlist_cur = oldlist->head->next; while (oldlist_cur) { ListCell *newlist_cur; newlist_cur = pgut_new(ListCell); newlist_cur->data = oldlist_cur->data; newlist_prev->next = newlist_cur; newlist_prev = newlist_cur; oldlist_cur = oldlist_cur->next; } newlist_prev->next = NULL; newlist->tail = newlist_prev; return newlist; }
/* * parse_checkpoint */ bool parse_checkpoint(const char *message, const char *timestamp) { static CheckpointLog *ckpt = NULL; List *params; if ((params = capture(message, msg_checkpoint_starting, NUM_CHECKPOINT_STARTING)) != NIL) { /* log for checkpoint starting */ const char *type = (char *) list_nth(params, 0); const char *flags = (char *) list_nth(params, 1); CheckpointType ckpt_type; if (strcmp(type, "checkpoint") == 0) ckpt_type = CKPT_TYPE_CHECKPOINT; else if (strcmp(type, "restartpoint") == 0) ckpt_type = CKPT_TYPE_RESTARTPOINT; else { /* not a checkpoint log */ list_free_deep(params); return false; } /* ignore shutdown checkpoint */ if (strstr(flags, "shutdown")) { free(ckpt); ckpt = NULL; list_free_deep(params); return true; /* handled, but forget */ } if (ckpt == NULL) ckpt = pgut_new(CheckpointLog); /* copy type, flags and start timestamp */ ckpt->type = ckpt_type; strlcpy(ckpt->flags, flags, sizeof(ckpt->flags)); strlcpy(ckpt->start, timestamp, sizeof(ckpt->start)); list_free_deep(params); return true; } if ((params = capture(message, msg_checkpoint_complete, NUM_CHECKPOINT_COMPLETE)) != NIL || (params = capture(message, msg_restartpoint_complete, NUM_RESTARTPOINT_COMPLETE)) != NIL) { /* log for checkpoint complete */ /* ignore if we have not seen any checkpoint start */ if (ckpt == NULL) { list_free_deep(params); return true; /* handled, but forget */ } /* send checkpoint log to writer */ ckpt->params = params; ckpt->base.type = QUEUE_CHECKPOINT; ckpt->base.free = (QueueItemFree) Checkpoint_free; ckpt->base.exec = (QueueItemExec) Checkpoint_exec; writer_send((QueueItem *) ckpt); ckpt = NULL; return true; } /* not a checkpoint log */ return false; }
PGconn * pgut_connect(const char *info, YesNo prompt, int elevel) { char *passwd; StringInfoData add_pass; if (prompt == YES) { passwd = prompt_for_password(); initStringInfo(&add_pass); appendStringInfoString(&add_pass, info); appendStringInfo(&add_pass, " password=%s ", passwd); } else { passwd = NULL; add_pass.data = NULL; } /* Start the connection. Loop until we have a password if requested by backend. */ for (;;) { PGconn *conn; CHECK_FOR_INTERRUPTS(); if (!passwd) conn = PQconnectdb(info); else conn = PQconnectdb(add_pass.data); if (PQstatus(conn) == CONNECTION_OK) { pgutConn *c; c = pgut_new(pgutConn); c->conn = conn; c->cancel = NULL; pgut_conn_lock(); c->next = pgut_connections; pgut_connections = c; pgut_conn_unlock(); if (add_pass.data != NULL) termStringInfo(&add_pass); free(passwd); return conn; } if (conn && PQconnectionNeedsPassword(conn) && prompt != NO) { PQfinish(conn); free(passwd); passwd = prompt_for_password(); if (add_pass.data != NULL) resetStringInfo(&add_pass); else initStringInfo(&add_pass); appendStringInfoString(&add_pass, info); appendStringInfo(&add_pass, " password=%s ", passwd); continue; } if (add_pass.data != NULL) termStringInfo(&add_pass); free(passwd); ereport(elevel, (errcode(E_PG_CONNECT), errmsg("could not connect to database with \"%s\": %s", info, PQerrorMessage(conn)))); PQfinish(conn); return NULL; } }