summaryrefslogtreecommitdiffstats
path: root/src/interfaces/ecpg/ecpglib/memory.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:15:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:15:05 +0000
commit46651ce6fe013220ed397add242004d764fc0153 (patch)
tree6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/interfaces/ecpg/ecpglib/memory.c
parentInitial commit. (diff)
downloadpostgresql-14-upstream.tar.xz
postgresql-14-upstream.zip
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/memory.c')
-rw-r--r--src/interfaces/ecpg/ecpglib/memory.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/ecpglib/memory.c b/src/interfaces/ecpg/ecpglib/memory.c
new file mode 100644
index 0000000..bd81251
--- /dev/null
+++ b/src/interfaces/ecpg/ecpglib/memory.c
@@ -0,0 +1,174 @@
+/* src/interfaces/ecpg/ecpglib/memory.c */
+
+#define POSTGRES_ECPG_INTERNAL
+#include "postgres_fe.h"
+
+#include "ecpg-pthread-win32.h"
+#include "ecpgerrno.h"
+#include "ecpglib.h"
+#include "ecpglib_extern.h"
+#include "ecpgtype.h"
+
+void
+ecpg_free(void *ptr)
+{
+ free(ptr);
+}
+
+char *
+ecpg_alloc(long size, int lineno)
+{
+ char *new = (char *) calloc(1L, size);
+
+ if (!new)
+ {
+ ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
+ return NULL;
+ }
+
+ return new;
+}
+
+char *
+ecpg_realloc(void *ptr, long size, int lineno)
+{
+ char *new = (char *) realloc(ptr, size);
+
+ if (!new)
+ {
+ ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
+ return NULL;
+ }
+
+ return new;
+}
+
+char *
+ecpg_strdup(const char *string, int lineno)
+{
+ char *new;
+
+ if (string == NULL)
+ return NULL;
+
+ new = strdup(string);
+ if (!new)
+ {
+ ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
+ return NULL;
+ }
+
+ return new;
+}
+
+/* keep a list of memory we allocated for the user */
+struct auto_mem
+{
+ void *pointer;
+ struct auto_mem *next;
+};
+
+#ifdef ENABLE_THREAD_SAFETY
+static pthread_key_t auto_mem_key;
+static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT;
+
+static void
+auto_mem_destructor(void *arg)
+{
+ (void) arg; /* keep the compiler quiet */
+ ECPGfree_auto_mem();
+}
+
+static void
+auto_mem_key_init(void)
+{
+ pthread_key_create(&auto_mem_key, auto_mem_destructor);
+}
+
+static struct auto_mem *
+get_auto_allocs(void)
+{
+ pthread_once(&auto_mem_once, auto_mem_key_init);
+ return (struct auto_mem *) pthread_getspecific(auto_mem_key);
+}
+
+static void
+set_auto_allocs(struct auto_mem *am)
+{
+ pthread_setspecific(auto_mem_key, am);
+}
+#else
+static struct auto_mem *auto_allocs = NULL;
+
+#define get_auto_allocs() (auto_allocs)
+#define set_auto_allocs(am) do { auto_allocs = (am); } while(0)
+#endif
+
+char *
+ecpg_auto_alloc(long size, int lineno)
+{
+ void *ptr = (void *) ecpg_alloc(size, lineno);
+
+ if (!ptr)
+ return NULL;
+
+ if (!ecpg_add_mem(ptr, lineno))
+ {
+ ecpg_free(ptr);
+ return NULL;
+ }
+ return ptr;
+}
+
+bool
+ecpg_add_mem(void *ptr, int lineno)
+{
+ struct auto_mem *am = (struct auto_mem *) ecpg_alloc(sizeof(struct auto_mem), lineno);
+
+ if (!am)
+ return false;
+
+ am->pointer = ptr;
+ am->next = get_auto_allocs();
+ set_auto_allocs(am);
+ return true;
+}
+
+void
+ECPGfree_auto_mem(void)
+{
+ struct auto_mem *am = get_auto_allocs();
+
+ /* free all memory we have allocated for the user */
+ if (am)
+ {
+ do
+ {
+ struct auto_mem *act = am;
+
+ am = am->next;
+ ecpg_free(act->pointer);
+ ecpg_free(act);
+ } while (am);
+ set_auto_allocs(NULL);
+ }
+}
+
+void
+ecpg_clear_auto_mem(void)
+{
+ struct auto_mem *am = get_auto_allocs();
+
+ /* only free our own structure */
+ if (am)
+ {
+ do
+ {
+ struct auto_mem *act = am;
+
+ am = am->next;
+ ecpg_free(act);
+ } while (am);
+ set_auto_allocs(NULL);
+ }
+}