Skip to content
Open
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
66 changes: 63 additions & 3 deletions contrib/babelfishpg_tsql/runtime/functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@
#include "utils/float.h"
#include "utils/xid8.h"
#include "utils/xml.h"
#include "catalog/pg_class_d.h"
#include <math.h>

extern const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME;
extern char *get_value_by_name_from_array(ArrayType *array, const char *name);

static char *get_orig_temp_table_name(Oid relid);

#include "../src/babelfish_version.h"
#include "../src/datatype_info.h"
#include "../src/pltsql.h"
Expand Down Expand Up @@ -1319,7 +1325,19 @@ get_enr_list(PG_FUNCTION_ARGS)
MemSet(nulls, 0, sizeof(nulls));

values[0] = ((EphemeralNamedRelationMetadata) lfirst(lc))->reliddesc;
values[1] = CStringGetTextDatum(((EphemeralNamedRelationMetadata) lfirst(lc))->name);
{
EphemeralNamedRelationMetadata md = (EphemeralNamedRelationMetadata) lfirst(lc);
const char *name = md->name;

/* Use original untruncated name from reloptions if available */
if (md->enrtype == ENR_TSQL_TEMP)
{
char *orig = get_orig_temp_table_name(md->reliddesc);

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.

Nit: can we instead make the utility itself handle all of this - get_orig_temp_table_name(Enr) returns fullname or truncated name.

if (orig)
name = orig;
}
values[1] = CStringGetTextDatum(name);
}

tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
Expand Down Expand Up @@ -2798,6 +2816,33 @@ object_id(PG_FUNCTION_ARGS)
* if there is no such object in specified database, if database id is not provided it will lookup in current database
* if user don't have right permission
*/
/*
* get_orig_temp_table_name - Get original untruncated name from reloptions.
* Returns palloc'd string or NULL if not found.
*/
static char *
get_orig_temp_table_name(Oid relid)
{
HeapTuple tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
char *orig = NULL;

if (HeapTupleIsValid(tuple))
{
Datum datum;
bool isnull;

datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull);
if (!isnull)
{
ArrayType *reloptions = DatumGetArrayTypeP(datum);
orig = get_value_by_name_from_array(reloptions, ATTOPTION_BBF_ORIGINAL_TABLE_NAME);
}
ReleaseSysCache(tuple);
}
/* orig remains valid after ReleaseSysCache - get_value_by_name_from_array palloc's a copy */
return orig;
}

Datum
object_name(PG_FUNCTION_ARGS)
{
Expand Down Expand Up @@ -2844,7 +2889,12 @@ object_name(PG_FUNCTION_ARGS)
enr = GetENRTempTableWithOid(object_id, false);
if (enr != NULL && enr->md.enrtype == ENR_TSQL_TEMP)
{
PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(enr->md.name));
const char *name = enr->md.name;
char *orig = get_orig_temp_table_name(object_id);

if (orig)
name = orig;
PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(name));
}

/* search in pg_class by object_id */
Expand All @@ -2855,7 +2905,17 @@ object_name(PG_FUNCTION_ARGS)
if (pg_class_aclcheck(object_id, user_id, ACL_SELECT) == ACLCHECK_OK)
{
Form_pg_class pg_class = (Form_pg_class) GETSTRUCT(tuple);
result_text = cstring_to_text(NameStr(pg_class->relname)); // make a copy before releasing syscache

if (pg_class->relpersistence == RELPERSISTENCE_TEMP &&
NameStr(pg_class->relname)[0] == '#')
Comment on lines +2909 to +2910

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.

Nit: lets create a utility for this?

bool IsTsqlTempTable(Relation)...

{
Comment on lines +2909 to +2911

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.

wouldn't we be handling this for all identifiers? are we doing this for now for temp tables only?

char *orig = get_orig_temp_table_name(object_id);
if (orig)
result_text = cstring_to_text(orig);
}

if (!result_text)
result_text = cstring_to_text(NameStr(pg_class->relname));
schema_id = pg_class->relnamespace;
}
ReleaseSysCache(tuple);
Expand Down
5 changes: 5 additions & 0 deletions contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y
Original file line number Diff line number Diff line change
Expand Up @@ -3557,6 +3557,11 @@ tsql_IndexStmt:
n->transformed = false;
n->if_not_exists = false;

if (n->idxname)
n->options = lappend(n->options,
makeDefElem("name_location",
(Node *) makeInteger(@7), @7));

Comment on lines +3560 to +3564

@ayushdsh ayushdsh Jun 15, 2026

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.

this is unconditional - we are populating the name_location field no matter what? should we add a NAMEDATALEN check? and btw this will also happen for indexes on permanent tables as well .. this is expected right?

tsql_index_nulls_order(n->indexParams, n->accessMethod);
$$ = (Node *)n;
}
Expand Down
2 changes: 2 additions & 0 deletions contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-rule.l
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@
SET_YYLLOC();
CHECK_LOCAL_TEMP_TABLE_LENGTH(yytext);
yylval->str = pstrdup(yytext);
if (yyleng >= NAMEDATALEN)
truncate_identifier(yylval->str, yyleng, true);
return IDENT;
}

Expand Down
14 changes: 6 additions & 8 deletions contrib/babelfishpg_tsql/src/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -2497,20 +2497,18 @@ pltsql_post_transform_table_definition(ParseState *pstate, RangeVar *relation, c
stmt->objtype = OBJECT_TABLE;

/*
* Only store original_name if there's a difference, and if the difference
* is only in capitalization
* Store original_name in reloptions when:
* 1. There is a case-only difference between relname and original_name, OR
* 2. The identifier is a temp table name that was truncated (>= NAMEDATALEN)
*/
if (strncmp(relname, original_name, strlen(relname)) != 0 && strncasecmp(relname, original_name, strlen(relname)) == 0)
if ((strncmp(relname, original_name, strlen(relname)) != 0 && strncasecmp(relname, original_name, strlen(relname)) == 0) ||
(relation->relpersistence == RELPERSISTENCE_TEMP && original_name[0] == '#' && strlen(original_name) >= NAMEDATALEN))
{
/*
* add "ALTER TABLE SET (bbf_original_table_name=<original_name>)" to
* alist so that original_name will be stored in pg_class.reloptions
*/
cmd_orig_name = makeNode(AlterTableCmd);
cmd_orig_name->subtype = AT_SetRelOptions;
cmd_orig_name->def = (Node *) list_make1(makeDefElem(pstrdup(ATTOPTION_BBF_ORIGINAL_TABLE_NAME), (Node *) makeString(pstrdup(original_name)), -1));
cmd_orig_name->behavior = DROP_RESTRICT;
cmd_orig_name->missing_ok = false;
cmd_orig_name = make_original_rel_name_cmd(original_name);
stmt->cmds = lappend(stmt->cmds, cmd_orig_name);
}

Expand Down
61 changes: 58 additions & 3 deletions contrib/babelfishpg_tsql/src/pl_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ extern PLtsql_function *find_cached_batch(int handle);
extern void apply_post_compile_actions(PLtsql_function *func, InlineCodeBlockArgs *args);
Datum sp_prepare(PG_FUNCTION_ARGS);
Datum sp_unprepare(PG_FUNCTION_ARGS);
static List *transformSelectIntoStmt(CreateTableAsStmt *stmt);
static List *transformSelectIntoStmt(CreateTableAsStmt *stmt, const char *queryString);
static char *get_oid_type_string(int type_oid);
static int64 get_identity_into_args(Node *node);
extern char *construct_unique_index_name(char *index_name, char *relation_name);
Expand Down Expand Up @@ -239,6 +239,7 @@ static TargetEntry* buildJsonEntry(int nestLevel, char* tableAlias, TargetEntry*
static char *string_to_fixed_hash(const char *input);
static void processAutoColumns(Query *wrapperQuery, Query *origQuery, Alias *wrapperRteAlias, ForAutoContext *ctx, ForAutoMode mode);
extern const char *ATTOPTION_BBF_ORIGINAL_NAME;
extern const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME;
extern bool pltsql_ansi_defaults;
extern bool pltsql_quoted_identifier;
extern bool pltsql_concat_null_yields_null;
Expand Down Expand Up @@ -5386,6 +5387,34 @@ bbf_ProcessUtility(PlannedStmt *pstmt,
List *partition_schemes = stmt->excludeOpNames;

stmt->excludeOpNames = NIL;

/*
* For indexes on temp tables, extract the full original

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.

why just temp tables? why aren't we doing this for all indexes

* name from the query string using name_location stored
* by the parser. Remove name_location from options as
* it is for internal use only.
*/
{
ListCell *lc;
foreach(lc, stmt->options)
{
DefElem *opt = (DefElem *) lfirst(lc);
if (strcmp(opt->defname, "name_location") == 0)
{
if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP &&
stmt->relation->relname[0] == '#' && original_name)
{
int loc = intVal(opt->arg);
char *full_name = extract_identifier(queryString + loc, NULL);
if (full_name)
original_name = full_name;
}
stmt->options = foreach_delete_current(stmt->options, lc);
break;
}
}
}

if (stmt->idxname && !stmt->isconstraint)
stmt->idxname = construct_unique_index_name(stmt->idxname, stmt->relation->relname);
/*
Expand Down Expand Up @@ -8017,7 +8046,8 @@ get_identity_into_args(Node *node)
}

static List *
transformSelectIntoStmt(CreateTableAsStmt *stmt)
transformSelectIntoStmt
(CreateTableAsStmt *stmt, const char *queryString)

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.

are we doing the same for other SELECT INTOs as well? passing the queryString here and will use it to extract the actual name? why can't we do the same we do for CREATE TABLE ... storing the orig_name in reloptions?

{
List *result;
ListCell *elements;
Expand Down Expand Up @@ -8258,6 +8288,31 @@ transformSelectIntoStmt(CreateTableAsStmt *stmt)
}

result = lappend(result, stmt);

/* Store original name in reloption for SELECT INTO #temp with long names */
if (into && into->rel &&
into->rel->relpersistence == RELPERSISTENCE_TEMP &&
into->rel->relname[0] == '#' &&
into->rel->location >= 0 && queryString != NULL)
{
char *original_name = extract_identifier(queryString + into->rel->location, NULL);

if (original_name && strlen(original_name) >= NAMEDATALEN)
{
if (!altstmt)
{
altstmt = makeNode(AlterTableStmt);
altstmt->relation = into->rel;
altstmt->objtype = OBJECT_TABLE;
altstmt->cmds = NIL;
}
altstmt->cmds = lappend(altstmt->cmds, make_original_rel_name_cmd(original_name));
pfree(original_name);
}
else if (original_name)
pfree(original_name);
Comment on lines +8310 to +8313

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.

Nit: unnecessary. pfree handles NULLs

}

if (altstmt && list_length(altstmt->cmds) > 0)
result = lappend(result, altstmt);

Expand All @@ -8270,7 +8325,7 @@ void pltsql_bbfSelectIntoUtility(ParseState *pstate, PlannedStmt *pstmt, const c

Node *parsetree = pstmt->utilityStmt;
List *stmts;
stmts = transformSelectIntoStmt((CreateTableAsStmt *)parsetree);
stmts = transformSelectIntoStmt((CreateTableAsStmt *)parsetree, queryString);
while (stmts != NIL)
{
Node *stmt = (Node *)linitial(stmts);
Expand Down
1 change: 1 addition & 0 deletions contrib/babelfishpg_tsql/src/pltsql.h
Original file line number Diff line number Diff line change
Expand Up @@ -2331,6 +2331,7 @@ extern List *get_columns(char *index_stmt);
extern char *replace_special_chars_fts_impl(char *input_str);
extern bool is_unique_index(Oid relid, const char *index_name);
extern void exec_grantschema_subcmds(const char *schema, const char *rolname, bool is_grant, bool with_grant_option, AclMode privilege);
extern AlterTableCmd *make_original_rel_name_cmd(const char *original_name);
extern void exec_add_original_index_name(char *idxname, char *schemaname, char *original_name);
extern int TsqlUTF8LengthInUTF16(const void *vin, int len);
extern void TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit);
Expand Down
17 changes: 17 additions & 0 deletions contrib/babelfishpg_tsql/src/pltsql_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,23 @@ exec_utility_cmd_helper(char *query_str)
}

extern const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME;
/*
* make_original_rel_name_cmd - Create an AlterTableCmd that stores the
* original untruncated name in bbf_original_rel_name reloption.
*/
AlterTableCmd *
make_original_rel_name_cmd(const char *original_name)
{
AlterTableCmd *cmd = makeNode(AlterTableCmd);

cmd->subtype = AT_SetRelOptions;
cmd->def = (Node *) list_make1(makeDefElem(pstrdup(ATTOPTION_BBF_ORIGINAL_TABLE_NAME),
(Node *) makeString(pstrdup(original_name)), -1));
cmd->behavior = DROP_RESTRICT;
cmd->missing_ok = false;
return cmd;
}

void
exec_add_original_index_name(char *idxname, char *schemaname, char *original_name)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ long_bracket_login_test_user_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy
-- terminate-tsql-conn user=long_bracket_login_test_user_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu password=1234 database=long_bracket_database_test_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw

-- tsql
use master
GO
DROP DATABASE [long_bracket_database_test_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw];
GO

Expand Down
6 changes: 1 addition & 5 deletions test/JDBC/expected/TestErrorsWithLongIdentifiers.out
Original file line number Diff line number Diff line change
Expand Up @@ -565,13 +565,9 @@ GO
~~ERROR (Message: The identifier that starts with 'babel6434_ううううううううううううううううううううううううううううううううううううううう' is too long. Maximum length is 128.)~~


-- Temp table with multibyte name (116 chars - should pass, to be fixed with BABEL-6433 )
-- Temp table with multibyte name (116 chars - should pass)
CREATE TABLE #babel6434_さささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささ (a int);
GO
~~ERROR (Code: 33557097)~~

~~ERROR (Message: relation "#babel6434_さささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささ" does not exist)~~

DROP TABLE IF EXISTS #babel6434_さささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささささ;
GO

Expand Down
Loading
Loading