开发者

Oracle reflection of tuple on system level trigger to dynamically replace characters of interest

I am attempting to write a generic trigger that can inspect each tuple that is to be inserted into the database. In this inspection I want to replace characters that are of interest to me, such as the curly quotation mark (MS word) with the regular quotation mark ("). Since I do not want to have to write two replace calls for each column that stores data that the user supplies, nor do I want to do this in the application for a myriad of reasons. pseudocode as follows:

create or replace trigger changeChars
before insert  
on @tableName  
reference new as var
for开发者_StackOverflow each row  
Begin 
loop  
:var.@column  := replace(:var.@column,'”', '"');   
end 


Why do you want to replace these characters? A lot of folks have problems with characters like the Microsoft curly quotes because those characters are not supported by their database character set which, by default, causes character set conversion to replace those characters with replacement characters like '?'. If that is the problem that you're trying to solve, database code can't help because the character set conversion happens at the network layer before the data even gets to the database. Potentially, you could use Oracle Locale Builder to build a custom locale for your client machines that would allow you to specify different replacement characters (i.e. double-quotes rather than Microsoft curly quotes).

If your problem is not character set related, there is no way to create this sort of dynamic trigger. You could write a bit of dynamic SQL that created a trigger for every table that called REPLACE on every VARCHAR2 column in the table. Of course, you'd need to maintain the trigger every time an additional VARCHAR2 column was added (either by changing the trigger or re-running the PL/SQL block).

Untested, and I'm sure the DDL generated isn't correct, but you'd want something like

DECLARE
  l_sql_stmt VARCHAR2(4000);
BEGIN
  FOR tbl IN (SELECT * FROM user_tables)
  LOOP
    l_sql_stmt := 'CREATE OR REPLACE TRIGGER ' || tbl.table_name || '_changeChars ' ||
                  '  BEFORE INSERT ON ' || tbl.table_name ||
                  '  FOR EACH ROW ' ||
                  'BEGIN ';
    FOR col IN (SELECT * FROM user_tab_cols WHERE table_name = tbl.table_name)
    LOOP
      l_sql_stmt := l_sql_stmt ||
                    ' :new.' || col.column_name || 
                        ' := replace( :new.' || col.column_name || ',''"'', ''"''');';
    END LOOP;
    l_sql_stmt := l_sql_stmt || 
                    'END; ';
    dbms_output.put_line( 'SQL statement = ' || l_sql_stmt );
    EXECUTE IMMEDIATE l_sql_stmt;
  END LOOP;
END;


Okay, so the easy bit is to build a function to do the replacement.

create or replace function strip_quotes
    (p_str in varchar2)
    return varchar2
is
begin
    return translate(p_str, chr(145)||chr(146)||chr(147)||chr(148), chr(39)||chr(39)||chr(34)||chr(34));
end;
/

145 to 148 being the extended ASCII values for MS Smart Quotes, single and double. We can use it like this:

SQL> select strip_quotes('ôHiö said Jon.') from dual
  2  /

STRIP_QUOTES('ôHIöSAIDJON.')
-------------------------------------------------------------------------------
"Hi" said Jon.

SQL>

The harder bit is the reflection. I agree with Justin, that generating a trigger for each table is the best solution.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜