Fix mis-deparsing of ORDER BY lists when there is a name conflict.
[pgsql.git] / src / port / win32env.c
blobfdc5537fb4e9cae3914ea07ac9645b2b0634a72c
1 /*-------------------------------------------------------------------------
3 * win32env.c
4 * putenv(), setenv(), and unsetenv() for win32.
6 * These functions update both the process environment and caches in
7 * (potentially multiple) C run-time library (CRT) versions.
9 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
13 * IDENTIFICATION
14 * src/port/win32env.c
16 *-------------------------------------------------------------------------
19 #include "c.h"
23 * Note that unlike POSIX putenv(), this doesn't use the passed-in string
24 * as permanent storage.
26 int
27 pgwin32_putenv(const char *envval)
29 char *envcpy;
30 char *cp;
31 typedef int (_cdecl * PUTENVPROC) (const char *);
32 static const char *const modulenames[] = {
33 "msvcrt", /* Visual Studio 6.0 / MinGW */
34 "msvcrtd",
35 "msvcr70", /* Visual Studio 2002 */
36 "msvcr70d",
37 "msvcr71", /* Visual Studio 2003 */
38 "msvcr71d",
39 "msvcr80", /* Visual Studio 2005 */
40 "msvcr80d",
41 "msvcr90", /* Visual Studio 2008 */
42 "msvcr90d",
43 "msvcr100", /* Visual Studio 2010 */
44 "msvcr100d",
45 "msvcr110", /* Visual Studio 2012 */
46 "msvcr110d",
47 "msvcr120", /* Visual Studio 2013 */
48 "msvcr120d",
49 "ucrtbase", /* Visual Studio 2015 and later */
50 "ucrtbased",
51 NULL
53 int i;
56 * Update process environment, making this change visible to child
57 * processes and to CRTs initializing in the future. Do this before the
58 * _putenv() loop, for the benefit of any CRT that initializes during this
59 * pgwin32_putenv() execution, after the loop checks that CRT.
61 * Need a copy of the string so we can modify it.
63 envcpy = strdup(envval);
64 if (!envcpy)
65 return -1;
66 cp = strchr(envcpy, '=');
67 if (cp == NULL)
69 free(envcpy);
70 return -1;
72 *cp = '\0';
73 cp++;
74 if (*cp)
77 * Only call SetEnvironmentVariable() when we are adding a variable,
78 * not when removing it. Calling it on both crashes on at least
79 * certain versions of MinGW.
81 if (!SetEnvironmentVariable(envcpy, cp))
83 free(envcpy);
84 return -1;
87 free(envcpy);
90 * Each CRT has its own _putenv() symbol and copy of the environment.
91 * Update the environment in each CRT module currently loaded, so every
92 * third-party library sees this change regardless of the CRT it links
93 * against. Addresses within these modules may become invalid the moment
94 * we call FreeLibrary(), so don't cache them.
96 for (i = 0; modulenames[i]; i++)
98 HMODULE hmodule = NULL;
99 BOOL res = GetModuleHandleEx(0, modulenames[i], &hmodule);
101 if (res != 0 && hmodule != NULL)
103 PUTENVPROC putenvFunc;
105 putenvFunc = (PUTENVPROC) (pg_funcptr_t) GetProcAddress(hmodule, "_putenv");
106 if (putenvFunc)
107 putenvFunc(envval);
108 FreeLibrary(hmodule);
113 * Finally, update our "own" cache. This is redundant with the loop
114 * above, except when PostgreSQL itself links to a CRT not listed above.
115 * Ideally, the loop does visit all possible CRTs, making this redundant.
117 return _putenv(envval);
121 pgwin32_setenv(const char *name, const char *value, int overwrite)
123 int res;
124 char *envstr;
126 /* Error conditions, per POSIX */
127 if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL ||
128 value == NULL)
130 errno = EINVAL;
131 return -1;
134 /* No work if variable exists and we're not to replace it */
135 if (overwrite == 0 && getenv(name) != NULL)
136 return 0;
138 envstr = (char *) malloc(strlen(name) + strlen(value) + 2);
139 if (!envstr) /* not much we can do if no memory */
140 return -1;
142 sprintf(envstr, "%s=%s", name, value);
144 res = pgwin32_putenv(envstr);
145 free(envstr);
146 return res;
150 pgwin32_unsetenv(const char *name)
152 int res;
153 char *envbuf;
155 envbuf = (char *) malloc(strlen(name) + 2);
156 if (!envbuf)
157 return -1;
159 sprintf(envbuf, "%s=", name);
160 res = pgwin32_putenv(envbuf);
161 free(envbuf);
162 return res;