Class: DbMeta::Oracle::Constraint

Inherits:
Base
  • Object
show all
Defined in:
lib/db_meta/oracle/types/constraint.rb

Constant Summary collapse

@@cache =
{}
@@cache_mutex =
Mutex.new

Constants inherited from Base

Base::TYPES

Instance Attribute Summary collapse

Attributes inherited from Base

#extract_type, #name, #status, #system_object, #type

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#ddl_drop, from_type, register_type, #system_object?

Methods included from Helper

#block, #create_folder, #pluralize, #remove_folder, #type_sequence, #write_buffer_to_file

Constructor Details

#initialize(args = {}) ⇒ Constraint

Returns a new instance of Constraint.



74
75
76
77
78
79
# File 'lib/db_meta/oracle/types/constraint.rb', line 74

def initialize(args = {})
  super

  @extract_type = :embedded
  @columns = []
end

Instance Attribute Details

#columnsObject (readonly)

Returns the value of attribute columns.



6
7
8
# File 'lib/db_meta/oracle/types/constraint.rb', line 6

def columns
  @columns
end

#constraint_typeObject (readonly)

Returns the value of attribute constraint_type.



6
7
8
# File 'lib/db_meta/oracle/types/constraint.rb', line 6

def constraint_type
  @constraint_type
end

#delete_ruleObject (readonly)

Returns the value of attribute delete_rule.



6
7
8
# File 'lib/db_meta/oracle/types/constraint.rb', line 6

def delete_rule
  @delete_rule
end

#referential_constraintObject (readonly)

Returns the value of attribute referential_constraint.



6
7
8
# File 'lib/db_meta/oracle/types/constraint.rb', line 6

def referential_constraint
  @referential_constraint
end

#search_conditionObject (readonly)

Returns the value of attribute search_condition.



6
7
8
# File 'lib/db_meta/oracle/types/constraint.rb', line 6

def search_condition
  @search_condition
end

#table_nameObject (readonly)

Returns the value of attribute table_name.



6
7
8
# File 'lib/db_meta/oracle/types/constraint.rb', line 6

def table_name
  @table_name
end

Class Method Details

.cacheObject



66
67
68
# File 'lib/db_meta/oracle/types/constraint.rb', line 66

def self.cache
  @@cache
end

.preload(args = {}) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/db_meta/oracle/types/constraint.rb', line 11

def self.preload(args = {})
  connection_class = args[:connection_class] || Connection
  connection = connection_class.instance.get

  meta = {}
  cursor = connection.exec(
    "select constraint_name, constraint_type, table_name, search_condition, r_constraint_name, delete_rule " \
    "from user_constraints"
  )
  cursor.fetch_hash do |row|
    name = row["CONSTRAINT_NAME"]
    type = translate_constraint_type(row["CONSTRAINT_TYPE"])
    search_condition = row["SEARCH_CONDITION"]

    # Skip Oracle-generated NOT NULL CHECK constraints. They are already
    # represented by the column's NOT NULL clause in the table DDL, so
    # emitting them again is redundant noise that breaks schema diffs.
    next if redundant_not_null?(name, type, search_condition)

    meta[name] = {
      constraint_type: type,
      table_name: row["TABLE_NAME"],
      search_condition: search_condition,
      r_constraint_name: row["R_CONSTRAINT_NAME"],
      delete_rule: row["DELETE_RULE"],
      columns: []
    }
  end
  cursor.close

  cursor = connection.exec(
    "select constraint_name, column_name, position " \
    "from user_cons_columns order by constraint_name, position"
  )
  cursor.fetch_hash do |row|
    entry = meta[row["CONSTRAINT_NAME"]]
    next unless entry
    entry[:columns] << row["COLUMN_NAME"]
  end
  cursor.close

  @@cache_mutex.synchronize { @@cache = meta }
end

.redundant_not_null?(name, type, search_condition) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
62
63
64
# File 'lib/db_meta/oracle/types/constraint.rb', line 59

def self.redundant_not_null?(name, type, search_condition)
  return false unless system_generated?(name) && type == "CHECK"
  return false if search_condition.nil?
  # Match patterns like: "COL_NAME" IS NOT NULL  or  COL_NAME IS NOT NULL
  !!search_condition.match?(/\A\s*"?[A-Z0-9_$#]+"?\s+IS\s+NOT\s+NULL\s*\z/i)
end

.reset_cacheObject



70
71
72
# File 'lib/db_meta/oracle/types/constraint.rb', line 70

def self.reset_cache
  @@cache_mutex.synchronize { @@cache = {} }
end

.sort_value(type) ⇒ Object



126
127
128
# File 'lib/db_meta/oracle/types/constraint.rb', line 126

def self.sort_value(type)
  ["PRIMARY KEY", "FOREIGN KEY", "UNIQUE", "CHECK"].index(type)
end

.system_generated?(name) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/db_meta/oracle/types/constraint.rb', line 55

def self.system_generated?(name)
  name.to_s.start_with?("SYS_")
end

.translate_constraint_type(type) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/db_meta/oracle/types/constraint.rb', line 130

def self.translate_constraint_type(type)
  case type
  when "P"
    "PRIMARY KEY"
  when "U"
    "UNIQUE"
  when "C"
    "CHECK"
  when "R"
    "FOREIGN KEY"
  end
end

Instance Method Details

#extract(args = {}) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/db_meta/oracle/types/constraint.rb', line 101

def extract(args = {})
  buffer = []
  buffer << "ALTER TABLE #{@table_name} ADD ("
  buffer << "  CONSTRAINT #{@name}" unless Constraint.system_generated?(@name)

  case @constraint_type
  when "CHECK"
    buffer << "  #{@constraint_type} (#{@search_condition})"
  when "FOREIGN KEY"
    buffer << "  #{@constraint_type} (#{@columns.join(", ")})"
    buffer << "  REFERENCES #{@referential_constraint.table_name} (#{@referential_constraint.columns.join(", ")})"
  else
    buffer << "  #{@constraint_type} (#{@columns.join(", ")})"
  end

  buffer << "  ON DELETE CASCADE" if @delete_rule == "CASCADE"
  buffer << "  ENABLE VALIDATE"
  buffer << ");"

  (0..buffer.size - 1).each { |n| buffer[n] = ("-- " + buffer[n]) } if args[:comment] == true

  buffer << nil
  buffer.join("\n")
end

#fetch(args = {}) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/db_meta/oracle/types/constraint.rb', line 81

def fetch(args = {})
  entry = @@cache[@name]
  return unless entry

  @constraint_type = entry[:constraint_type]
  @table_name = entry[:table_name]
  @search_condition = entry[:search_condition]
  @delete_rule = entry[:delete_rule]
  @columns = entry[:columns].dup
  @extract_type = :merged if @constraint_type == "FOREIGN KEY"

  if @constraint_type == "FOREIGN KEY" && entry[:r_constraint_name]
    @referential_constraint = Constraint.new(
      "OBJECT_TYPE" => "CONSTRAINT",
      "OBJECT_NAME" => entry[:r_constraint_name]
    )
    @referential_constraint.fetch
  end
end