sequel_postgresql_triggers 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +71 -3
- data/lib/sequel/extensions/pg_triggers.rb +66 -18
- data/spec/sequel_postgresql_triggers_spec.rb +666 -544
- metadata +36 -9
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2a985c677d8d3b87630378feee9b80dda40ef2ba95147ec525f2df8feff18b38
         | 
| 4 | 
            +
              data.tar.gz: 8c6b9526bbedb13a72fd3edc44c2da56041fc985c0e41187613914bae9163230
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 39bd5f9c742aeed9331e59b521d571e5631c1b3dcd0804dd959e010a2a6c2bcd110ad8752eac92b1f9d0a768d0a9925f67cf59cdc5a34b718bc4e15e07ba996e
         | 
| 7 | 
            +
              data.tar.gz: e5304e315766b8059adc6d29e48b6eb60af4ead1662a70d0eb5d7a87daa541a3b5068385a0b3a302bddaf23fd35f88637c6c3cf762b8308d5f2b5c27f9db682e
         | 
    
        data/MIT-LICENSE
    CHANGED
    
    
    
        data/README.rdoc
    CHANGED
    
    | @@ -95,7 +95,7 @@ opts :: options hash | |
| 95 95 |  | 
| 96 96 | 
             
            === Counter Cache - pgt_counter_cache
         | 
| 97 97 |  | 
| 98 | 
            -
            This takes  | 
| 98 | 
            +
            This takes many arguments and sets up a
         | 
| 99 99 | 
             
            counter cache so that when the counted table is inserted to
         | 
| 100 100 | 
             
            or deleted from, records in the main table are updated with the
         | 
| 101 101 | 
             
            count of the corresponding records in the counted table.  The counter
         | 
| @@ -126,7 +126,7 @@ sum cache that sums the length of a string column. | |
| 126 126 |  | 
| 127 127 | 
             
            Arguments:
         | 
| 128 128 | 
             
            main_table :: name of table holding counter cache column
         | 
| 129 | 
            -
            main_table_id_column :: column in main table matching  | 
| 129 | 
            +
            main_table_id_column :: column in main table matching summed_table_id_column in summed_table
         | 
| 130 130 | 
             
            sum_column :: column in main table containing the sum cache
         | 
| 131 131 | 
             
            summed_table :: name of table being summed
         | 
| 132 132 | 
             
            summed_table_id_column :: column in summed_table matching main_table_id_column in main_table
         | 
| @@ -167,7 +167,7 @@ table :: name of table | |
| 167 167 |  | 
| 168 168 | 
             
            === Touch Propagation - pgt_touch
         | 
| 169 169 |  | 
| 170 | 
            -
            This takes several arguments  | 
| 170 | 
            +
            This takes several arguments and sets up a
         | 
| 171 171 | 
             
            trigger that watches one table for changes, and touches timestamps
         | 
| 172 172 | 
             
            of related rows in a separate table.
         | 
| 173 173 |  | 
| @@ -198,6 +198,74 @@ Options: | |
| 198 198 | 
             
            :referenced_function_name :: function name for trigger function on referenced table
         | 
| 199 199 | 
             
            :referenced_trigger_name :: trigger name for referenced table
         | 
| 200 200 |  | 
| 201 | 
            +
            === Force Defaults - pgt_force_defaults
         | 
| 202 | 
            +
             | 
| 203 | 
            +
            This takes 2 arguments, a table and a hash of column default values, and sets
         | 
| 204 | 
            +
            up an insert trigger that will override user submitted or database
         | 
| 205 | 
            +
            default values and use the values given when setting up the trigger.
         | 
| 206 | 
            +
            This is mostly useful in situations where multiple database accounts
         | 
| 207 | 
            +
            are used where one account has insert permissions but not update
         | 
| 208 | 
            +
            permissions, and you want to ensure that inserted rows have specific
         | 
| 209 | 
            +
            column values to enforce security requirements.
         | 
| 210 | 
            +
             | 
| 211 | 
            +
            Arguments:
         | 
| 212 | 
            +
            table :: The name of the table
         | 
| 213 | 
            +
            defaults :: A hash of default values to enforce, where keys are column names
         | 
| 214 | 
            +
                        and values are the default values to enforce
         | 
| 215 | 
            +
             | 
| 216 | 
            +
            === JSON Audit Logging - pgt_json_audit_log_setup and pg_json_audit_log
         | 
| 217 | 
            +
             | 
| 218 | 
            +
            These methods setup an auditing function where updates and deletes log
         | 
| 219 | 
            +
            the previous values to a central auditing table in JSON format.
         | 
| 220 | 
            +
             | 
| 221 | 
            +
            ==== pgt_json_audit_log_setup
         | 
| 222 | 
            +
             | 
| 223 | 
            +
            This creates an audit table and a trigger function that will log
         | 
| 224 | 
            +
            previous values to the audit table. This returns the name of the
         | 
| 225 | 
            +
            trigger function created, which should be passed to
         | 
| 226 | 
            +
            +pgt_json_audit_log+.
         | 
| 227 | 
            +
             | 
| 228 | 
            +
            Arguments:
         | 
| 229 | 
            +
            table :: The name of the table storing the audit logs.
         | 
| 230 | 
            +
             | 
| 231 | 
            +
            Options:
         | 
| 232 | 
            +
            function_opts :: Options to pass to +create_function+ when creating
         | 
| 233 | 
            +
                             the trigger function.
         | 
| 234 | 
            +
             | 
| 235 | 
            +
            The audit log table will store the following columns:
         | 
| 236 | 
            +
             | 
| 237 | 
            +
            txid :: The 64-bit transaction ID for the transaction that made the modification (txid_current())
         | 
| 238 | 
            +
            at :: The timestamp of the transaction that made the modification (CURRENT_TIMESTAMP)
         | 
| 239 | 
            +
            user :: The database user name that made the modification (CURRENT_USER)
         | 
| 240 | 
            +
            schema :: The schema containing the table that was modified (TG_TABLE_SCHEMA)
         | 
| 241 | 
            +
            table :: The table that was modified (TG_TABLE_NAME)
         | 
| 242 | 
            +
            action :: The type of modification, either DELETE or UPDATE (TG_OP)
         | 
| 243 | 
            +
            prior :: A jsonb column with the contents of the row before the modification (to_jsonb(OLD))
         | 
| 244 | 
            +
             | 
| 245 | 
            +
            ==== pgt_json_audit_log
         | 
| 246 | 
            +
             | 
| 247 | 
            +
            This adds a trigger to the table that will log previous values to the
         | 
| 248 | 
            +
            audting table for updates and deletes.
         | 
| 249 | 
            +
             | 
| 250 | 
            +
            Arguments:
         | 
| 251 | 
            +
            table :: The name of the table to audit
         | 
| 252 | 
            +
            function :: The name of the trigger function to call to log changes
         | 
| 253 | 
            +
             | 
| 254 | 
            +
            Note that it is probably a bad idea to use the same table argument
         | 
| 255 | 
            +
            to both +pgt_json_audit_log_setup+ and +pgt_json_audit_log+.
         | 
| 256 | 
            +
             | 
| 257 | 
            +
            == Caveats
         | 
| 258 | 
            +
             | 
| 259 | 
            +
            If you have defined counter or sum cache triggers using this library
         | 
| 260 | 
            +
            before version 1.6.0, you should drop them and regenerate them if
         | 
| 261 | 
            +
            you want the triggers to work correctly with queries that use
         | 
| 262 | 
            +
            <tt>INSERT ... ON CONFLICT DO NOTHING</tt>.
         | 
| 263 | 
            +
             | 
| 264 | 
            +
            When restoring a data-only migration with +pg_dump+, you may need to
         | 
| 265 | 
            +
            use <tt>--disable-triggers</tt> for it to restore correctly, and you
         | 
| 266 | 
            +
            will need to manually enforce data integrity if you are doing
         | 
| 267 | 
            +
            partial restores and not full restores.
         | 
| 268 | 
            +
             | 
| 201 269 | 
             
            == License
         | 
| 202 270 |  | 
| 203 271 | 
             
            This library is released under the MIT License.  See the MIT-LICENSE
         | 
| @@ -6,15 +6,15 @@ module Sequel | |
| 6 6 | 
             
              module Postgres
         | 
| 7 7 | 
             
                PGT_DEFINE = proc do
         | 
| 8 8 | 
             
                  def pgt_counter_cache(main_table, main_table_id_column, counter_column, counted_table, counted_table_id_column, opts={})
         | 
| 9 | 
            -
                    trigger_name = opts[:trigger_name] || "pgt_cc_#{main_table}__#{main_table_id_column}__#{counter_column}__#{counted_table_id_column}"
         | 
| 10 | 
            -
                    function_name = opts[:function_name] || "pgt_cc_#{main_table}__#{main_table_id_column}__#{counter_column}__#{counted_table}__#{counted_table_id_column}"
         | 
| 9 | 
            +
                    trigger_name = opts[:trigger_name] || "pgt_cc_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{counter_column}__#{counted_table_id_column}"
         | 
| 10 | 
            +
                    function_name = opts[:function_name] || "pgt_cc_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{counter_column}__#{pgt_mangled_table_name(counted_table)}__#{counted_table_id_column}"
         | 
| 11 11 |  | 
| 12 12 | 
             
                    table = quote_schema_table(main_table)
         | 
| 13 13 | 
             
                    id_column = quote_identifier(counted_table_id_column)
         | 
| 14 14 | 
             
                    main_column = quote_identifier(main_table_id_column)
         | 
| 15 15 | 
             
                    count_column = quote_identifier(counter_column)
         | 
| 16 16 |  | 
| 17 | 
            -
                    pgt_trigger(counted_table, trigger_name, function_name, [:insert, :update, :delete], <<-SQL)
         | 
| 17 | 
            +
                    pgt_trigger(counted_table, trigger_name, function_name, [:insert, :update, :delete], <<-SQL, :after=>true)
         | 
| 18 18 | 
             
                    BEGIN
         | 
| 19 19 | 
             
                      IF (TG_OP = 'UPDATE' AND (NEW.#{id_column} = OLD.#{id_column} OR (OLD.#{id_column} IS NULL AND NEW.#{id_column} IS NULL))) THEN
         | 
| 20 20 | 
             
                        RETURN NEW;
         | 
| @@ -37,7 +37,7 @@ module Sequel | |
| 37 37 |  | 
| 38 38 | 
             
                  def pgt_created_at(table, column, opts={})
         | 
| 39 39 | 
             
                    trigger_name = opts[:trigger_name] || "pgt_ca_#{column}"
         | 
| 40 | 
            -
                    function_name = opts[:function_name] || "pgt_ca_#{table}__#{column}"
         | 
| 40 | 
            +
                    function_name = opts[:function_name] || "pgt_ca_#{pgt_mangled_table_name(table)}__#{column}"
         | 
| 41 41 | 
             
                    col = quote_identifier(column)
         | 
| 42 42 | 
             
                    pgt_trigger(table, trigger_name, function_name, [:insert, :update], <<-SQL)
         | 
| 43 43 | 
             
                    BEGIN
         | 
| @@ -51,6 +51,21 @@ module Sequel | |
| 51 51 | 
             
                    SQL
         | 
| 52 52 | 
             
                  end
         | 
| 53 53 |  | 
| 54 | 
            +
                  def pgt_force_defaults(table, defaults, opts={})
         | 
| 55 | 
            +
                    cols = defaults.keys.sort.join('_')
         | 
| 56 | 
            +
                    trigger_name = opts[:trigger_name] || "pgt_fd_#{cols}"
         | 
| 57 | 
            +
                    function_name = opts[:function_name] || "pgt_fd_#{pgt_mangled_table_name(table)}__#{cols}"
         | 
| 58 | 
            +
                    lines = defaults.map do |column, v|
         | 
| 59 | 
            +
                      "NEW.#{quote_identifier(column)} = #{literal(v)};"
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                    pgt_trigger(table, trigger_name, function_name, [:insert], <<-SQL)
         | 
| 62 | 
            +
                    BEGIN
         | 
| 63 | 
            +
                      #{lines.join("\n")}
         | 
| 64 | 
            +
                      RETURN NEW;
         | 
| 65 | 
            +
                    END;
         | 
| 66 | 
            +
                    SQL
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 54 69 | 
             
                  def pgt_immutable(table, *columns)
         | 
| 55 70 | 
             
                    opts = columns.last.is_a?(Hash) ? columns.pop : {}
         | 
| 56 71 | 
             
                    trigger_name = opts[:trigger_name] || "pgt_im_#{columns.join('__')}"
         | 
| @@ -67,9 +82,37 @@ module Sequel | |
| 67 82 | 
             
                    pgt_trigger(table, trigger_name, function_name, :update, "BEGIN #{ifs} RETURN NEW; END;")
         | 
| 68 83 | 
             
                  end
         | 
| 69 84 |  | 
| 85 | 
            +
                  def pgt_json_audit_log_setup(table, opts={})
         | 
| 86 | 
            +
                    function_name = opts[:function_name] || "pgt_jal_#{pgt_mangled_table_name(table)}"
         | 
| 87 | 
            +
                    create_table(table) do
         | 
| 88 | 
            +
                      Bignum :txid, :null=>false, :index=>true
         | 
| 89 | 
            +
                      DateTime :at, :default=>Sequel::CURRENT_TIMESTAMP, :null=>false
         | 
| 90 | 
            +
                      String :user, :null=>false
         | 
| 91 | 
            +
                      String :schema, :null=>false
         | 
| 92 | 
            +
                      String :table, :null=>false
         | 
| 93 | 
            +
                      String :action, :null=>false
         | 
| 94 | 
            +
                      jsonb :prior, :null=>false
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                    create_function(function_name, (<<-SQL), {:language=>:plpgsql, :returns=>:trigger, :replace=>true}.merge(opts[:function_opts]||{}))
         | 
| 97 | 
            +
                    BEGIN
         | 
| 98 | 
            +
                      INSERT INTO #{quote_schema_table(table)} (txid, at, "user", "schema", "table", action, prior) VALUES
         | 
| 99 | 
            +
                      (txid_current(), CURRENT_TIMESTAMP, CURRENT_USER, TG_TABLE_SCHEMA, TG_TABLE_NAME, TG_OP, to_jsonb(OLD));
         | 
| 100 | 
            +
                      IF (TG_OP = 'DELETE') THEN
         | 
| 101 | 
            +
                        RETURN OLD;
         | 
| 102 | 
            +
                      END IF;
         | 
| 103 | 
            +
                      RETURN NEW;
         | 
| 104 | 
            +
                    END;
         | 
| 105 | 
            +
                    SQL
         | 
| 106 | 
            +
                    function_name
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  def pgt_json_audit_log(table, function, opts={})
         | 
| 110 | 
            +
                    create_trigger(table, (opts[:trigger_name] || "pgt_jal_#{pgt_mangled_table_name(table)}"), function, :events=>[:update, :delete], :each_row=>true, :after=>true)
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
             | 
| 70 113 | 
             
                  def pgt_sum_cache(main_table, main_table_id_column, sum_column, summed_table, summed_table_id_column, summed_column, opts={})
         | 
| 71 | 
            -
                    trigger_name = opts[:trigger_name] || "pgt_sc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}"
         | 
| 72 | 
            -
                    function_name = opts[:function_name] || "pgt_sc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}__#{summed_column}"
         | 
| 114 | 
            +
                    trigger_name = opts[:trigger_name] || "pgt_sc_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}"
         | 
| 115 | 
            +
                    function_name = opts[:function_name] || "pgt_sc_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{sum_column}__#{pgt_mangled_table_name(summed_table)}__#{summed_table_id_column}__#{summed_column}"
         | 
| 73 116 |  | 
| 74 117 | 
             
                    table = quote_schema_table(main_table)
         | 
| 75 118 | 
             
                    id_column = quote_identifier(summed_table_id_column)
         | 
| @@ -79,7 +122,7 @@ module Sequel | |
| 79 122 | 
             
                    main_column = quote_identifier(main_table_id_column)
         | 
| 80 123 | 
             
                    sum_column = quote_identifier(sum_column)
         | 
| 81 124 |  | 
| 82 | 
            -
                    pgt_trigger(summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
         | 
| 125 | 
            +
                    pgt_trigger(summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL, :after=>true)
         | 
| 83 126 | 
             
                    BEGIN
         | 
| 84 127 | 
             
                      IF (TG_OP = 'UPDATE' AND NEW.#{id_column} = OLD.#{id_column}) THEN
         | 
| 85 128 | 
             
                        UPDATE #{table} SET #{sum_column} = #{sum_column} + #{new_table_summed_column} - #{old_table_summed_column} WHERE #{main_column} = NEW.#{id_column};
         | 
| @@ -111,10 +154,10 @@ module Sequel | |
| 111 154 | 
             
                    summed_table_fk_column = opts.fetch(:summed_table_fk_column)
         | 
| 112 155 |  | 
| 113 156 | 
             
                    summed_column_slug = summed_column.is_a?(String) || summed_column.is_a?(Symbol) ? "__#{summed_column}" : ""
         | 
| 114 | 
            -
                    trigger_name = opts[:trigger_name] || "pgt_stmc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}#{summed_column_slug}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 115 | 
            -
                    function_name = opts[:function_name] || "pgt_stmc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}#{summed_column_slug}__#{join_table}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 116 | 
            -
                    join_trigger_name = opts[:join_trigger_name] || "pgt_stmc_join_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}#{summed_column_slug}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 117 | 
            -
                    join_function_name = opts[:join_function_name] || "pgt_stmc_join_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}#{summed_column_slug}__#{join_table}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 157 | 
            +
                    trigger_name = opts[:trigger_name] || "pgt_stmc_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}#{summed_column_slug}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 158 | 
            +
                    function_name = opts[:function_name] || "pgt_stmc_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{sum_column}__#{pgt_mangled_table_name(summed_table)}__#{summed_table_id_column}#{summed_column_slug}__#{pgt_mangled_table_name(join_table)}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 159 | 
            +
                    join_trigger_name = opts[:join_trigger_name] || "pgt_stmc_join_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}#{summed_column_slug}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 160 | 
            +
                    join_function_name = opts[:join_function_name] || "pgt_stmc_join_#{pgt_mangled_table_name(main_table)}__#{main_table_id_column}__#{sum_column}__#{pgt_mangled_table_name(summed_table)}__#{summed_table_id_column}#{summed_column_slug}__#{pgt_mangled_table_name(join_table)}__#{main_table_fk_column}__#{summed_table_fk_column}"
         | 
| 118 161 |  | 
| 119 162 | 
             
                    orig_summed_table = summed_table
         | 
| 120 163 | 
             
                    orig_join_table = join_table
         | 
| @@ -133,7 +176,7 @@ module Sequel | |
| 133 176 | 
             
                    main_table_fk_column = quote_schema_table(main_table_fk_column)
         | 
| 134 177 | 
             
                    summed_table_fk_column = quote_schema_table(summed_table_fk_column)
         | 
| 135 178 |  | 
| 136 | 
            -
                    pgt_trigger(orig_summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
         | 
| 179 | 
            +
                    pgt_trigger(orig_summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL, :after=>true)
         | 
| 137 180 | 
             
                    BEGIN
         | 
| 138 181 | 
             
                      IF (TG_OP = 'UPDATE' AND NEW.#{summed_table_id_column} = OLD.#{summed_table_id_column}) THEN
         | 
| 139 182 | 
             
                        UPDATE #{main_table} SET #{sum_column} = #{sum_column} + #{new_table_summed_column} - #{old_table_summed_column} WHERE #{main_table_id_column} IN (SELECT #{main_table_fk_column} FROM #{join_table} WHERE #{summed_table_fk_column} = NEW.#{summed_table_id_column});
         | 
| @@ -152,7 +195,7 @@ module Sequel | |
| 152 195 | 
             
                    END;
         | 
| 153 196 | 
             
                    SQL
         | 
| 154 197 |  | 
| 155 | 
            -
                    pgt_trigger(orig_join_table, join_trigger_name, join_function_name, [:insert, :delete, :update], <<-SQL)
         | 
| 198 | 
            +
                    pgt_trigger(orig_join_table, join_trigger_name, join_function_name, [:insert, :delete, :update], <<-SQL, :after=>true)
         | 
| 156 199 | 
             
                    BEGIN
         | 
| 157 200 | 
             
                      IF (NOT (TG_OP = 'UPDATE' AND NEW.#{main_table_fk_column} = OLD.#{main_table_fk_column} AND NEW.#{summed_table_fk_column} = OLD.#{summed_table_fk_column})) THEN
         | 
| 158 201 | 
             
                        IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
         | 
| @@ -171,8 +214,8 @@ module Sequel | |
| 171 214 | 
             
                  end
         | 
| 172 215 |  | 
| 173 216 | 
             
                  def pgt_touch(main_table, touch_table, column, expr, opts={})
         | 
| 174 | 
            -
                    trigger_name = opts[:trigger_name] || "pgt_t_#{main_table}__#{touch_table}"
         | 
| 175 | 
            -
                    function_name = opts[:function_name] || "pgt_t_#{main_table}__#{touch_table}"
         | 
| 217 | 
            +
                    trigger_name = opts[:trigger_name] || "pgt_t_#{pgt_mangled_table_name(main_table)}__#{pgt_mangled_table_name(touch_table)}"
         | 
| 218 | 
            +
                    function_name = opts[:function_name] || "pgt_t_#{pgt_mangled_table_name(main_table)}__#{pgt_mangled_table_name(touch_table)}"
         | 
| 176 219 | 
             
                    cond = lambda{|source| expr.map{|k,v| "#{quote_identifier(k)} = #{source}.#{quote_identifier(v)}"}.join(" AND ")}
         | 
| 177 220 | 
             
                    same_id = expr.map{|k,v| "NEW.#{quote_identifier(v)} = OLD.#{quote_identifier(v)}"}.join(" AND ")
         | 
| 178 221 |  | 
| @@ -204,7 +247,7 @@ module Sequel | |
| 204 247 |  | 
| 205 248 | 
             
                  def pgt_updated_at(table, column, opts={})
         | 
| 206 249 | 
             
                    trigger_name = opts[:trigger_name] || "pgt_ua_#{column}"
         | 
| 207 | 
            -
                    function_name = opts[:function_name] || "pgt_ua_#{table}__#{column}"
         | 
| 250 | 
            +
                    function_name = opts[:function_name] || "pgt_ua_#{pgt_mangled_table_name(table)}__#{column}"
         | 
| 208 251 | 
             
                    pgt_trigger(table, trigger_name, function_name, [:insert, :update], <<-SQL)
         | 
| 209 252 | 
             
                    BEGIN
         | 
| 210 253 | 
             
                      NEW.#{quote_identifier(column)} := CURRENT_TIMESTAMP;
         | 
| @@ -216,9 +259,9 @@ module Sequel | |
| 216 259 | 
             
                  def pgt_foreign_key_array(opts={})
         | 
| 217 260 | 
             
                    table, column, rtable, rcolumn = opts.values_at(:table, :column, :referenced_table, :referenced_column)
         | 
| 218 261 | 
             
                    trigger_name = opts[:trigger_name] || "pgt_fka_#{column}"
         | 
| 219 | 
            -
                    function_name = opts[:function_name] || "pgt_fka_#{table}__#{column}"
         | 
| 262 | 
            +
                    function_name = opts[:function_name] || "pgt_fka_#{pgt_mangled_table_name(table)}__#{column}"
         | 
| 220 263 | 
             
                    rtrigger_name = opts[:referenced_trigger_name] || "pgt_rfka_#{column}"
         | 
| 221 | 
            -
                    rfunction_name = opts[:referenced_function_name] || "pgt_rfka_#{table}__#{column}"
         | 
| 264 | 
            +
                    rfunction_name = opts[:referenced_function_name] || "pgt_rfka_#{pgt_mangled_table_name(table)}__#{column}"
         | 
| 222 265 | 
             
                    col = quote_identifier(column)
         | 
| 223 266 | 
             
                    tab = quote_identifier(table)
         | 
| 224 267 | 
             
                    rcol = quote_identifier(rcolumn)
         | 
| @@ -281,6 +324,11 @@ module Sequel | |
| 281 324 | 
             
                    create_function(function_name, definition, :language=>:plpgsql, :returns=>:trigger, :replace=>true)
         | 
| 282 325 | 
             
                    create_trigger(table, trigger_name, function_name, :events=>events, :each_row=>true, :after=>opts[:after])
         | 
| 283 326 | 
             
                  end
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                  # Mangle the schema name so it can be used in an unquoted_identifier
         | 
| 329 | 
            +
                  def pgt_mangled_table_name(table)
         | 
| 330 | 
            +
                    quote_schema_table(table).gsub('"', '').gsub(/[^A-Za-z0-9]/, '_').gsub(/_+/, '_')
         | 
| 331 | 
            +
                  end
         | 
| 284 332 | 
             
                end
         | 
| 285 333 |  | 
| 286 334 | 
             
                module PGTMethods
         |