Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/backend/oracle_parser/ora_scan.l
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/ora_compatible.h"
#include "executor/spi.h"
#include "executor/spi.h"
#include "parser/parse_param.h"
}

Expand Down Expand Up @@ -951,7 +951,7 @@ other .
&& !identifier_case_from_pg_dump)
{
if (identifier_case_switch == LOWERCASE
&& is_all_upper(ident, strlen(ident)))
&& identifier_is_all_upper(ident, strlen(ident)))
{
char *lowerident = ident;

Expand Down Expand Up @@ -1671,4 +1671,3 @@ ora_core_yyfree(void *ptr, ora_core_yyscan_t yyscanner)
if (ptr)
pfree(ptr);
}

85 changes: 84 additions & 1 deletion src/backend/parser/scansup.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "postgres.h"

#include <ctype.h>
#include <stdbool.h>

#include "mb/pg_wchar.h"
#include "parser/scansup.h"
Expand Down Expand Up @@ -49,22 +50,34 @@ downcase_identifier(const char *ident, int len, bool warn, bool truncate)
char *result;
int i;
bool enc_is_single_byte;
Assert(ident != NULL);
Assert(len >= 0);

result = palloc(len + 1);
enc_is_single_byte = pg_database_encoding_max_length() == 1;

/*
* SQL99 specifies Unicode-aware case normalization, which we don't yet
* have the infrastructure for. Instead we use tolower() to provide a
* locale-aware translation. However, in some locales (for example,
* locale-aware translation. However, in some locales (for example,
* Turkish with 'i' and 'I') this still is not correct. Our compromise is
* to use tolower() for characters with the high bit set, as long as they
* aren't part of a multi-byte character, and use an ASCII-only approach
* for 7-bit characters.
*/
memcpy(result, ident, len);
for (i = 0; i < len; i++)
{
unsigned char ch = (unsigned char) ident[i];
if (!enc_is_single_byte)
{
int mblen = pg_mblen(ident + i);
if (mblen > 1)
{
i += (mblen - 1);
continue;
}
}

if (ch >= 'A' && ch <= 'Z')
ch += 'a' - 'A';
Expand All @@ -86,6 +99,8 @@ upcase_identifier(const char *ident, int len, bool warn, bool truncate)
char *result;
int i;
bool enc_is_single_byte;
Assert(ident != NULL);
Assert(len >= 0);

result = palloc(len + 1);
enc_is_single_byte = pg_database_encoding_max_length() == 1;
Expand All @@ -100,9 +115,19 @@ upcase_identifier(const char *ident, int len, bool warn, bool truncate)
* the high bit set, as long as they aren't part of a multi-byte
* character, and use an ASCII-only downcasing for 7-bit characters.
*/
memcpy(result, ident, len);
for (i = 0; i < len; i++)
{
unsigned char ch = (unsigned char) ident[i];
if (!enc_is_single_byte)
{
int mblen = pg_mblen(ident + i);
if (mblen > 1)
{
i += (mblen - 1);
continue;
}
}

if (ch >= 'a' && ch <= 'z')
ch -= 'a' - 'A';
Expand Down Expand Up @@ -193,3 +218,61 @@ scanner_isspace(char ch)
return true;
return false;
}

/*
* Detemine whether the letters in the string are all lowercase letters
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in comments.

"Detemine" should be "Determine" in both function comments.

📝 Proposed fix
 /*
- *  Detemine whether the letters in the string are all lowercase letters
+ *  Determine whether the letters in the string are all lowercase letters
  */

Apply the same fix to the comment at line 263 for identifier_is_all_upper.

Also applies to: 263-263

🤖 Prompt for AI Agents
In @src/backend/parser/scansup.c at line 234, Fix the spelling mistake in the
comment for the function identifier_is_all_lower by changing "Detemine" to
"Determine"; make the identical correction in the comment for
identifier_is_all_upper as well so both function comments read "Determine
whether the letters in the string are all lowercase/uppercase letters"
respectively, leaving code and punctuation unchanged.

*/
bool
identifier_is_all_lower(const char *ident, int len)
{
int i;
const char* s;

s = ident;

for (i = 0; i < len; i++)
{
int mblen = pg_mblen(s);

if (mblen > 1)
{
s += mblen;
i += (mblen - 1);
continue;
}

if (isalpha(*s) && isupper(*s))
return false;
s++;
}
return true;
}
Comment on lines +225 to +249
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Undefined behavior: pass unsigned char to ctype functions.

isalpha() and isupper() have undefined behavior when passed a negative value (which occurs for high-bit-set chars when char is signed). Cast to unsigned char as done in downcase_identifier.

Also:

  • Line 234: Typo "Detemine" → "Determine"
  • Line 236: Remove leading space before bool
  • Line 240: Use PostgreSQL pointer style const char *s
  • Add Assert(ident != NULL); Assert(len >= 0); for consistency
Suggested fix
 /*
- *  Detemine whether the letters in the string are all lowercase letters
+ *  Determine whether the letters in the string are all lowercase letters
  */
- bool
- identifier_is_all_lower(const char *ident, int len)
+bool
+identifier_is_all_lower(const char *ident, int len)
 {
-	int i;
-	const char* s;
-
-	s = ident;
+	int			i;
+	const char *s = ident;
+
+	Assert(ident != NULL);
+	Assert(len >= 0);
 
 	for (i = 0; i < len; i++)
 	{
+		unsigned char ch;
 		int mblen = pg_mblen(s);
 
 		if (mblen > 1)
 		{
 			s += mblen;
 			i += (mblen - 1);
 			continue;
 		}
 
-		if (isalpha(*s) && isupper(*s))
+		ch = (unsigned char) *s;
+		if (isalpha(ch) && isupper(ch))
 			return false;
 		s++;
 	}
 	return true;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool
identifier_is_all_lower(const char *ident, int len)
{
int i;
const char* s;
s = ident;
for (i = 0; i < len; i++)
{
int mblen = pg_mblen(s);
if (mblen > 1)
{
s += mblen;
i += (mblen - 1);
continue;
}
if (isalpha(*s) && isupper(*s))
return false;
s++;
}
return true;
}
/*
* Determine whether the letters in the string are all lowercase letters
*/
bool
identifier_is_all_lower(const char *ident, int len)
{
int i;
const char *s = ident;
Assert(ident != NULL);
Assert(len >= 0);
for (i = 0; i < len; i++)
{
unsigned char ch;
int mblen = pg_mblen(s);
if (mblen > 1)
{
s += mblen;
i += (mblen - 1);
continue;
}
ch = (unsigned char) *s;
if (isalpha(ch) && isupper(ch))
return false;
s++;
}
return true;
}
🤖 Prompt for AI Agents
In @src/backend/parser/scansup.c around lines 236 - 260, The function
identifier_is_all_lower has undefined behavior because isalpha() and isupper()
are called with plain char; cast the character to (unsigned char) before passing
to isalpha/isupper (as done in downcase_identifier), add Assert(ident != NULL);
Assert(len >= 0); at the start for consistency, change the signature spacing to
"bool identifier_is_all_lower(const char *ident, int len)" and use PostgreSQL
pointer style "const char *s", and fix the comment typo "Detemine" →
"Determine"; keep the existing multi-byte handling via pg_mblen() and advance s
and i as currently implemented.

Comment on lines +222 to +249
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo in comment and missing input validation.

  1. Line 223: "Detemine" should be "Determine".
  2. Lines 225-226: Formatting issue - there's a leading space before bool on the function definition.
  3. Unlike downcase_identifier and upcase_identifier (which have Assert checks at lines 53-54 and 102-103), this function lacks validation for NULL ident or negative len. For consistency and safety, consider adding similar assertions.
Suggested fix
 /*
- *  Detemine whether the letters in the string are all lowercase letters
+ *  Determine whether the letters in the string are all lowercase letters
  */
- bool
- identifier_is_all_lower(const char *ident, int len)
+bool
+identifier_is_all_lower(const char *ident, int len)
 {
 	int i;
 	const char* s;
+	Assert(ident != NULL);
+	Assert(len >= 0);
 
 	s = ident;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/*
* Detemine whether the letters in the string are all lowercase letters
*/
bool
identifier_is_all_lower(const char *ident, int len)
{
int i;
const char* s;
s = ident;
for (i = 0; i < len; i++)
{
int mblen = pg_mblen(s);
if (mblen > 1)
{
s += mblen;
i += (mblen - 1);
continue;
}
if (isalpha(*s) && isupper(*s))
return false;
s++;
}
return true;
}
/*
* Determine whether the letters in the string are all lowercase letters
*/
bool
identifier_is_all_lower(const char *ident, int len)
{
int i;
const char* s;
Assert(ident != NULL);
Assert(len >= 0);
s = ident;
for (i = 0; i < len; i++)
{
int mblen = pg_mblen(s);
if (mblen > 1)
{
s += mblen;
i += (mblen - 1);
continue;
}
if (isalpha(*s) && isupper(*s))
return false;
s++;
}
return true;
}
🤖 Prompt for AI Agents
In @src/backend/parser/scansup.c around lines 222 - 249, Fix the typo in the
function comment ("Detemine" → "Determine") and remove the stray leading space
before the function return type; then add the same defensive assertions used in
downcase_identifier and upcase_identifier to validate inputs (e.g., Assert(ident
!= NULL) and Assert(len >= 0)) at the start of identifier_is_all_lower so it
rejects NULL ident and negative len values consistently with those other
functions.


/*
* Detemine whether the letters in the string are all uppercase letters
*/
bool
identifier_is_all_upper(const char *ident, int len)
{
int i;
const char* s;

s = ident;

for (i = 0; i < len; i++)
{
int mblen = pg_mblen(s);

if (mblen > 1)
{
s += mblen;
i += (mblen - 1);
continue;
}

if (isalpha(*s) && islower(*s))
return false;
s++;
}
return true;
}
Comment on lines +254 to +278
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Same issues as identifier_is_all_lower.

Apply identical fixes:

  • Cast to unsigned char before calling isalpha()/islower()
  • Fix typo "Detemine" → "Determine"
  • Fix formatting (leading space, pointer style)
  • Add assertions
Suggested fix
 /*
- *  Detemine whether the letters in the string are all uppercase letters
+ *  Determine whether the letters in the string are all uppercase letters
  */
- bool
- identifier_is_all_upper(const char *ident, int len)
+bool
+identifier_is_all_upper(const char *ident, int len)
 {
-	int i;
-	const char* s;
-
-	s = ident;
+	int			i;
+	const char *s = ident;
+
+	Assert(ident != NULL);
+	Assert(len >= 0);
 
 	for (i = 0; i < len; i++)
 	{
+		unsigned char ch;
 		int mblen = pg_mblen(s);
 
 		if (mblen > 1)
 		{
 			s += mblen;
 			i += (mblen - 1);
 			continue;
 		}
 
-		if (isalpha(*s) && islower(*s))
+		ch = (unsigned char) *s;
+		if (isalpha(ch) && islower(ch))
 			return false;
 		s++;
 	}
 	return true;
 }
🤖 Prompt for AI Agents
In @src/backend/parser/scansup.c around lines 265 - 289, In
identifier_is_all_upper, cast characters to unsigned char before calling
isalpha() and islower() (e.g., use (unsigned char)*s) to avoid undefined
behavior; add assertions (Assert(ident != NULL && len >= 0)) at function start;
fix the typo in any comment or message from "Detemine" to "Determine"; normalize
formatting to match project style (no leading space before function return type,
use consistent pointer style like const char *ident) and keep multibyte-handling
logic as-is while ensuring spacing/brace style matches identifier_is_all_lower.

Comment on lines +251 to +278
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo in comment and missing input validation (same issues as identifier_is_all_lower).

  1. Line 252: "Detemine" should be "Determine".
  2. Lines 254-255: Formatting issue with leading space before bool.
  3. Missing Assert checks for NULL pointer and non-negative length.
Suggested fix
 /*
- *  Detemine whether the letters in the string are all uppercase letters
+ *  Determine whether the letters in the string are all uppercase letters
  */
- bool
- identifier_is_all_upper(const char * ident, int len)
+bool
+identifier_is_all_upper(const char *ident, int len)
 {
 	int i;
 	const char* s;
+	Assert(ident != NULL);
+	Assert(len >= 0);
 
 	s = ident;
🤖 Prompt for AI Agents
In @src/backend/parser/scansup.c around lines 251 - 278, Fix the typo in the
function comment ("Detemine" -> "Determine") and remove the stray leading space
before the return type so the function declaration reads "bool
identifier_is_all_upper(...)" consistently; then add the same input validation
used in identifier_is_all_lower by asserting the pointer and length at the top
of identifier_is_all_upper (e.g., Assert(ident != NULL); Assert(len >= 0);)
before using ident and len. Maintain the existing multibyte handling and loop
logic otherwise.

17 changes: 9 additions & 8 deletions src/backend/tcop/backend_startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "utils/ps_status.h"
#include "utils/timeout.h"
#include "utils/varlena.h"
#include "parser/scansup.h"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove duplicate include directive.

Line 47 duplicates the include from line 30. This causes redundant preprocessing and should be removed.

🔧 Proposed fix
 #include "utils/varlena.h"
-#include "parser/scansup.h"
 
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include "parser/scansup.h"
#include "utils/varlena.h"
🤖 Prompt for AI Agents
In @src/backend/tcop/backend_startup.c at line 47, Remove the duplicate include
directive for "parser/scansup.h": find the second occurrence of #include
"parser/scansup.h" (the one duplicated at line 47) and delete it so only the
original include remains; ensure no other references rely on a second inclusion
and run a quick build to confirm preprocessing is unaffected.


/* GUCs */
bool Trace_connection_negotiation = false;
Expand Down Expand Up @@ -803,9 +804,9 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
if (ORA_PARSER == compatible_db && database_name != NULL)
{
if (identifier_case_switch == LOWERCASE &&
is_all_upper(database_name, strlen(database_name)))
identifier_is_all_upper(database_name, strlen(database_name)))
{
port->database_name = down_character(database_name, strlen(database_name));
port->database_name = downcase_identifier(database_name, strlen(database_name), false, false);
pfree(database_name);
}
else if (identifier_case_switch == INTERCHANGE)
Expand Down Expand Up @@ -834,9 +835,9 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
pfree(database_name);
pfree(casename);
}
else if (is_all_upper(database_name, strlen(database_name)))
else if (identifier_is_all_upper(database_name, strlen(database_name)))
{
port->database_name = down_character(database_name, strlen(database_name));
port->database_name = downcase_identifier(database_name, strlen(database_name), false, false);
pfree(database_name);
}
else
Expand All @@ -856,9 +857,9 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
if (ORA_PARSER == compatible_db && user_name != NULL)
{
if (identifier_case_switch == LOWERCASE &&
is_all_upper(user_name, strlen(user_name)))
identifier_is_all_upper(user_name, strlen(user_name)))
{
port->user_name = down_character(user_name, strlen(user_name));
port->user_name = downcase_identifier(user_name, strlen(user_name), false, false);
pfree(user_name);
}
else if (identifier_case_switch == INTERCHANGE)
Expand Down Expand Up @@ -887,9 +888,9 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
pfree(user_name);
pfree(casename);
}
else if (is_all_upper(user_name, strlen(user_name)))
else if (identifier_is_all_upper(user_name, strlen(user_name)))
{
port->user_name = down_character(user_name, strlen(user_name));
port->user_name = downcase_identifier(user_name, strlen(user_name), false, false);
pfree(user_name);
}
else
Expand Down
25 changes: 13 additions & 12 deletions src/bin/initdb/initdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include "getopt_long.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "oracle_fe_utils/ora_string_utils.h"
#include "utils/ora_compatible.h"


Expand Down Expand Up @@ -1699,7 +1700,7 @@ bootstrap_template1(void)

initPQExpBuffer(&cmd);

printfPQExpBuffer(&cmd, "\"%s\" --boot -C ivorysql.identifier_case_switch=%d %s %s %s",
printfPQExpBuffer(&cmd, "\"%s\" --boot -C ivorysql.identifier_case_switch=%d %s %s %s",
backend_exec, caseswitchmode, boot_options, extra_options, pg_strcasecmp(dbmode, "pg") ? "-y oracle" : "-y pg");
appendPQExpBuffer(&cmd, " -X %d", wal_segment_size_mb * (1024 * 1024));
if (data_checksums)
Expand Down Expand Up @@ -3694,27 +3695,27 @@ main(int argc, char *argv[])
if (strncmp(username, "pg_", 3) == 0)
pg_fatal("superuser name \"%s\" is disallowed; role names cannot begin with \"pg_\"", username);

set_info_version();

setup_data_file_paths();

setup_locale_encoding();

setup_text_search();

/* Oracle compatibility: transform uppercase usernames to lowercase. */
if (database_mode == DB_ORACLE && username != NULL
&& is_all_upper(username, strlen(username)))
&& caseswitchmode != NORMAL
&& is_all_upper(username, strlen(username), encodingid))
{
char *lowerusername = username;
username = down_character(username, strlen(username));
free(lowerusername);
username = down_character(username, strlen(username), encodingid);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

printf(_("The files belonging to this database system will be owned "
"by user \"%s\".\n"
"This user must also own the server process.\n\n"),
effective_user);

set_info_version();

setup_data_file_paths();

setup_locale_encoding();

setup_text_search();

printf("\n");

Expand Down
1 change: 0 additions & 1 deletion src/include/fe_utils/string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,4 @@ extern void patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf,
PQExpBuffer schemabuf, PQExpBuffer namebuf,
const char *pattern, bool force_escape,
bool want_literal_dbname, int *dotcnt);

#endif /* STRING_UTILS_H */
8 changes: 6 additions & 2 deletions src/include/oracle_fe_utils/ora_string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down Expand Up @@ -42,4 +42,8 @@ extern void getDbCompatibleMode(PGconn *conn);
/* Functions */
extern const char *ora_fmtId(const char *identifier);

extern char * down_character(const char * src,int len, int encoding);
extern char * upper_character(const char *src, int len, int encoding);
extern bool is_all_lower(const char *src, int len, int encoding);
extern bool is_all_upper(const char *src, int len, int encoding);
#endif /* ORA_STRING_UTILS_H */
3 changes: 3 additions & 0 deletions src/include/parser/scansup.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ extern void truncate_identifier(char *ident, int len, bool warn);

extern bool scanner_isspace(char ch);

extern bool identifier_is_all_lower(const char *ident, int len);
extern bool identifier_is_all_upper(const char *ident, int len);

#endif /* SCANSUP_H */
4 changes: 0 additions & 4 deletions src/include/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ extern void get_html_path(const char *my_exec_path, char *ret_path);
extern void get_man_path(const char *my_exec_path, char *ret_path);
extern bool get_home_path(char *ret_path);
extern void get_parent_directory(char *path);
extern char * down_character(const char * src,int len);
extern char * upper_character(const char *src, int len);
extern bool is_all_lower(const char *src, int len);
extern bool is_all_upper(const char *src, int len);


/* common/pgfnames.c */
Expand Down
Loading