Skip to content
Draft
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
36 changes: 34 additions & 2 deletions contrib/babelfishpg_tds/src/backend/tds/err_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "utils/elog.h"
#include "utils/hsearch.h"
#include "utils/palloc.h" /* Needed for pstrdup() */
#include "utils/memutils.h"
#include <dlfcn.h>

#include "src/include/tds_int.h"
#include "src/include/tds_response.h"
Expand Down Expand Up @@ -344,8 +346,38 @@ emit_tds_log(ErrorData *edata)
tsql_error_state = 1;
}

TdsSendError(tsql_error_code, tsql_error_state, tsql_error_sev,
edata->message, error_lineno);
{
/* Rewrite truncated identifiers in error message */
char *msg = edata->message;

{
/*
* Rewrite truncated identifiers in error message.
* Truncated names are always [a-z0-9_] with 32-char hex MD5 suffix.
* Search for patterns matching NAMEDATALEN-1 chars that look like
* truncated identifiers and replace with full original from cache.
*/
typedef char *(*rewrite_fn_t)(const char *);
static rewrite_fn_t rewrite_fn = NULL;
static bool rewrite_resolved = false;

if (!rewrite_resolved)
{
rewrite_fn = (rewrite_fn_t) dlsym(RTLD_DEFAULT, "bbf_rewrite_truncated_identifiers");
rewrite_resolved = true;
}

if (rewrite_fn)
{
char *newmsg = rewrite_fn(msg);
if (newmsg)
msg = newmsg;
}
}

TdsSendError(tsql_error_code, tsql_error_state, tsql_error_sev,
msg, error_lineno);
}

/*
* If we've not reached the main query loop yet, flush the error
Expand Down
27 changes: 26 additions & 1 deletion contrib/babelfishpg_tsql/runtime/functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -2872,7 +2872,32 @@ 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
char *relname = NameStr(pg_class->relname);

/* Try to get original name from reloptions */
if (strlen(relname) >= NAMEDATALEN - 1)
{
bool isnull;
Datum opts = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull);
if (!isnull)
{
ArrayType *arr = DatumGetArrayTypeP(opts);
Datum *elems;
int n;
deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, &elems, NULL, &n);
for (int i = 0; i < n; i++)
{
char *s = text_to_cstring(DatumGetTextP(elems[i]));
if (strncmp(s, "bbf_original_rel_name=", 22) == 0)
{
result_text = cstring_to_text(s + 22);
break;
}
}
}
}
if (result_text == NULL)
result_text = cstring_to_text(relname);
schema_id = pg_class->relnamespace;
}
ReleaseSysCache(tuple);
Expand Down
87 changes: 41 additions & 46 deletions contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions contrib/babelfishpg_tsql/sql/information_schema_tsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.columns_internal AS
ELSE NULL
END, ',')
FROM unnest(a.attoptions) AS option),
sys.bbf_get_view_column_name(a.attrelid, a.attnum::smallint),
a.attname)
AS sys.nvarchar(128)) AS "COLUMN_NAME",

Expand Down Expand Up @@ -514,10 +515,10 @@ BEGIN
RETURN QUERY
SELECT CAST(db_name AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG",
CAST(ext.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA",
CAST(c.conname AS sys.sysname) AS "CONSTRAINT_NAME",
COALESCE(case when octet_length(c.conname) >= 60 then (select m.original_identifier_name from sys.babelfish_identifier_mapping m where m.truncated_identifier_name = c.conname and m.nspname = nsp.nspname and m.pg_catalog_type = 'pg_constraint'::regclass::oid) end, c.conname::text)::sys.sysname AS "CONSTRAINT_NAME",
CAST(db_name AS sys.nvarchar(128)) AS "TABLE_CATALOG",
CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA",
CAST(r.relname AS sys.sysname) AS "TABLE_NAME",
COALESCE(case when octet_length(r.relname) >= 60 then (select substring(opt, 23) from unnest(r.reloptions) opt where opt like 'bbf_original_rel_name=%' limit 1) end, r.relname::text)::sys.sysname AS "TABLE_NAME",
CAST(
CASE c.contype WHEN 'c' THEN 'CHECK'
WHEN 'f' THEN 'FOREIGN KEY'
Expand Down Expand Up @@ -606,7 +607,7 @@ GRANT SELECT ON information_schema_tsql.views TO PUBLIC;
CREATE VIEW information_schema_tsql.check_constraints AS
SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG",
CAST(extc.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA",
CAST(c.conname AS sys.sysname) AS "CONSTRAINT_NAME",
COALESCE(case when octet_length(c.conname) >= 60 then (select m.original_identifier_name from sys.babelfish_identifier_mapping m where m.truncated_identifier_name = c.conname and m.nspname = nc.nspname and m.pg_catalog_type = 'pg_constraint'::regclass::oid) end, c.conname::text)::sys.sysname AS "CONSTRAINT_NAME",
CAST(sys.tsql_get_constraintdef(c.oid) AS sys.nvarchar(4000)) AS "CHECK_CLAUSE"

FROM sys.pg_namespace_ext nc LEFT OUTER JOIN sys.babelfish_namespace_ext extc ON nc.nspname = extc.nspname,
Expand Down Expand Up @@ -856,11 +857,11 @@ CREATE OR REPLACE VIEW information_schema_tsql.key_column_usage AS
SELECT
CAST(db_name AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG",
CAST(ext.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA",
CAST(c.conname AS sys.nvarchar(128)) AS "CONSTRAINT_NAME",
COALESCE(case when octet_length(c.conname) >= 60 then (select m.original_identifier_name from sys.babelfish_identifier_mapping m where m.truncated_identifier_name = c.conname and m.nspname = nsp.nspname and m.pg_catalog_type = 'pg_constraint'::regclass::oid) end, c.conname::text)::sys.nvarchar(128) AS "CONSTRAINT_NAME",
CAST(db_name AS sys.nvarchar(128)) AS "TABLE_CATALOG",
CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA",
CAST(r.relname AS sys.nvarchar(128)) AS "TABLE_NAME",
CAST(a.attname AS sys.nvarchar(128)) AS "COLUMN_NAME",
COALESCE(case when octet_length(r.relname) >= 60 then (select substring(opt, 23) from unnest(r.reloptions) opt where opt like 'bbf_original_rel_name=%' limit 1) end, r.relname::text)::sys.nvarchar(128) AS "TABLE_NAME",
COALESCE(case when octet_length(a.attname) >= 60 then (select substring(opt, 19) from unnest(a.attoptions) opt where opt like 'bbf_original_name=%' limit 1) end, a.attname::text)::sys.nvarchar(128) AS "COLUMN_NAME",
CAST(ord AS int) AS "ORDINAL_POSITION"
FROM
pg_constraint c
Expand Down
29 changes: 21 additions & 8 deletions contrib/babelfishpg_tsql/sql/ownership.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CREATE TABLE sys.babelfish_sysdatabases (
name TEXT NOT NULL COLLATE "C",
crdate timestamptz NOT NULL,
properties TEXT NOT NULL COLLATE "C",
orig_name sys.NVARCHAR(128) COLLATE sys.database_default,
PRIMARY KEY (name)
);

Expand Down Expand Up @@ -61,10 +62,21 @@ CREATE TABLE sys.babelfish_namespace_ext (
);
GRANT SELECT ON sys.babelfish_namespace_ext TO PUBLIC;

-- BABELFISH_IDENTIFIER_MAPPING
CREATE TABLE sys.babelfish_identifier_mapping (
nspname NAME NOT NULL,
pg_catalog_type OID NOT NULL,
truncated_identifier_name NAME NOT NULL,
original_identifier_name sys.NVARCHAR(128) NOT NULL COLLATE sys.database_default,
parent_name NAME NOT NULL DEFAULT '',
PRIMARY KEY (truncated_identifier_name, nspname, pg_catalog_type, parent_name)
);
GRANT SELECT ON sys.babelfish_identifier_mapping TO PUBLIC;

-- SYSDATABASES
CREATE OR REPLACE VIEW sys.sysdatabases AS
SELECT
t.name,
t.orig_name AS name,
sys.db_id(t.name) AS dbid,
CAST(CAST(r.oid AS int) AS SYS.VARBINARY(85)) AS sid,
CAST(0 AS SMALLINT) AS mode,
Expand All @@ -83,7 +95,7 @@ GRANT SELECT ON sys.sysdatabases TO PUBLIC;

-- PG_NAMESPACE_EXT
CREATE VIEW sys.pg_namespace_ext AS
SELECT BASE.* , DB.name as dbname FROM
SELECT BASE.* , DB.orig_name as dbname FROM
pg_catalog.pg_namespace AS base
LEFT OUTER JOIN sys.babelfish_namespace_ext AS EXT on BASE.nspname = EXT.nspname
INNER JOIN sys.babelfish_sysdatabases AS DB ON EXT.dbid = DB.dbid;
Expand Down Expand Up @@ -400,6 +412,7 @@ SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_namespace_ext', '');
SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_login_ext', '');
SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_user_ext', '');
SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_schema_permissions', '');
SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_identifier_mapping', '');

CREATE OR REPLACE FUNCTION sys.bbf_is_role_member(member NAME, rolename NAME)
RETURNS BOOLEAN
Expand Down Expand Up @@ -464,7 +477,7 @@ LEFT OUTER JOIN sys.babelfish_sysdatabases AS Db
ON Ext.database_name COLLATE sys.database_default = Db.name
LEFT OUTER JOIN pg_catalog.pg_roles AS Base3
ON Db.owner = Base3.rolname
WHERE Ext.database_name = DB_NAME()
WHERE Ext.database_name = sys.bbf_cur_db() collate database_default
AND (Ext.orig_username IN ('dbo', 'db_owner', 'db_securityadmin', 'db_accessadmin', 'db_datareader', 'db_datawriter', 'db_ddladmin', 'guest') -- system users should always be visible
OR bbf_is_role_member(current_user, Ext.rolname)) -- Current user should be able to see users it has permission of
UNION ALL
Expand Down Expand Up @@ -569,7 +582,7 @@ LEFT OUTER JOIN sys.babelfish_sysdatabases AS Db
ON Ext.database_name COLLATE sys.database_default = Db.name
LEFT OUTER JOIN pg_catalog.pg_roles AS Base3
ON Db.owner = Base3.rolname
WHERE Ext.database_name = sys.DB_NAME()
WHERE Ext.database_name = sys.bbf_cur_db() collate database_default
AND ((Ext.rolname = CURRENT_USER AND Ext.type in ('S','U')) OR
((SELECT orig_username FROM sys.babelfish_authid_user_ext WHERE rolname = CURRENT_USER) != 'dbo' AND Ext.type = 'R' AND pg_has_role(current_user, Ext.rolname, 'MEMBER')))
UNION ALL
Expand Down Expand Up @@ -622,7 +635,7 @@ CASE WHEN Dbp.type_desc = 'DATABASE_ROLE' THEN 1 ELSE 0 END AS issqlrole,
CAST(0 AS INT) AS isapprole
FROM sys.database_principals AS Dbp LEFT JOIN
(SELECT orig_username, user_can_connect FROM sys.babelfish_authid_user_ext
WHERE database_name = DB_NAME()) AS Ext
WHERE database_name = sys.bbf_cur_db() collate database_default) AS Ext
ON Dbp.name = Ext.orig_username;

GRANT SELECT ON sys.sysusers TO PUBLIC;
Expand Down Expand Up @@ -655,8 +668,8 @@ INNER JOIN pg_catalog.pg_roles AS Auth1 ON Auth1.oid = Authmbr.roleid
INNER JOIN pg_catalog.pg_roles AS Auth2 ON Auth2.oid = Authmbr.member
INNER JOIN sys.babelfish_authid_user_ext AS Ext1 ON Auth1.rolname = Ext1.rolname
INNER JOIN sys.babelfish_authid_user_ext AS Ext2 ON Auth2.rolname = Ext2.rolname
WHERE Ext1.database_name = DB_NAME()
AND Ext2.database_name = DB_NAME()
WHERE Ext1.database_name = sys.bbf_cur_db() collate database_default
AND Ext2.database_name = sys.bbf_cur_db() collate database_default
AND Ext1.type = 'R'
AND Ext2.orig_username != 'db_owner';

Expand Down Expand Up @@ -702,7 +715,7 @@ RETURNS table (

create or replace view sys.databases as
select
CAST(d.name as SYS.SYSNAME) as name
CAST(d.orig_name as SYS.SYSNAME) as name
, CAST(sys.db_id(d.name) as INT) as database_id
, CAST(NULL as INT) as source_database_id
, cast(s.sid as SYS.VARBINARY(85)) as owner_sid
Expand Down
4 changes: 4 additions & 0 deletions contrib/babelfishpg_tsql/sql/sys_function_helpers.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11492,3 +11492,7 @@ LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION sys.babelfish_construct_unique_index_name(index_name TEXT, table_name TEXT)
RETURNS TEXT AS 'babelfishpg_tsql', 'bbf_construct_unique_index_name'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE OR REPLACE FUNCTION sys.bbf_get_view_column_name(view_oid OID, attnum SMALLINT)
RETURNS TEXT AS 'babelfishpg_tsql', 'bbf_get_view_column_name'
LANGUAGE C STABLE PARALLEL SAFE;
5 changes: 5 additions & 0 deletions contrib/babelfishpg_tsql/sql/sys_functions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,11 @@ CREATE OR REPLACE FUNCTION sys.db_name() RETURNS sys.nvarchar(128)
AS 'babelfishpg_tsql', 'babelfish_db_name'
LANGUAGE C PARALLEL SAFE STABLE;

-- Returns truncated internal database name (for internal comparisons with database_name column)
CREATE OR REPLACE FUNCTION sys.bbf_cur_db() RETURNS TEXT
AS 'babelfishpg_tsql', 'babelfish_db_name_internal'
LANGUAGE C PARALLEL SAFE STABLE;

CREATE OR REPLACE FUNCTION sys.exp(IN arg DOUBLE PRECISION)
RETURNS DOUBLE PRECISION
AS 'babelfishpg_tsql', 'tsql_exp'
Expand Down
Loading
Loading