db_meta 0.13.1 → 0.14.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8adeed469464ae77a3a9c1a4bf97232a5ac8dee25ec05099de171ffa198e97ef
4
- data.tar.gz: f9c80bd97da0777df4435de3ac662683e4962c493c227d75a0a8874bf2be4bf0
3
+ metadata.gz: 613dba8df67586f3a98b0282ea2eba0acee08368b7842c3740624a03700b6feb
4
+ data.tar.gz: 2c727117d8873dd58a7753eb1e80032082dd4c3da3cc744b597091c3cb18af3a
5
5
  SHA512:
6
- metadata.gz: 2c2216ce758aaa1788d34b02691c9fdbbe6406f23b4a261e4bebf0971def0b939878cea61d93852e78c3c81cf9291174ca171cb8455943f1c6c5d00385ed8b56
7
- data.tar.gz: 1c45fc8c844195b9aa099fc008bd8f10ad7f6d8da1f22261b724d9aaa14c92bf6d118974b9d1ce8da80dcd0a7bcffe5ffd83056632cb46be2d85193deaae40e3
6
+ metadata.gz: e4c8637ed18a53a34be8fc9b0ba2b06460301f0883f757f4f9b9f409936338f0e230e46a8c8cc7cd3e0665d2c8551f703a13957676eadb1c64095f6e9e8b84a4
7
+ data.tar.gz: 91f156e1f312922e81ad795fd56a906a548bb3da5d3737a2cd394a68118a0cf3e6655e61b0bb0d175861db34a9b47ec074a443cd4adeb5322dbf7a503e3eae52
@@ -28,11 +28,11 @@ jobs:
28
28
  strategy:
29
29
  fail-fast: false
30
30
  matrix:
31
- ruby: [ '3.4', '3.3', '3.2']
31
+ ruby: [ '4.0', '3.4', '3.3']
32
32
 
33
33
  name: Ruby ${{ matrix.ruby }}
34
34
  steps:
35
- - uses: actions/checkout@v5
35
+ - uses: actions/checkout@v6
36
36
 
37
37
  - name: Install Oracle instant client
38
38
  run: |
@@ -20,7 +20,7 @@ jobs:
20
20
 
21
21
  steps:
22
22
  - name: Checkout current code
23
- uses: actions/checkout@v5
23
+ uses: actions/checkout@v6
24
24
 
25
25
  - name: Install Oracle instant client
26
26
  run: |
@@ -45,7 +45,7 @@ jobs:
45
45
  - name: Set up Ruby
46
46
  uses: ruby/setup-ruby@v1
47
47
  with:
48
- ruby-version: '3.4'
48
+ ruby-version: '4.0'
49
49
  bundler: latest
50
50
  bundler-cache: true
51
51
  cache-version: 1
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.4.7
1
+ 4.0.3
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.4.7
1
+ ruby 4.0.3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## [0.14.1] - 2026-04-28
2
+
3
+ ### Changed
4
+ - Sequences now extract with `START WITH <MINVALUE>` by default (previously `START WITH <LAST_NUMBER>`), so extracts are reproducible and comparable across instances of the same schema. Pass `preserve_sequence_position: true` to `extract` to keep the original live-position behavior.
5
+ - `INCREMENT BY` is now emitted for sequences (previously fetched but never written, so non-default increments produced incorrect DDL).
6
+
7
+ ### Fixed
8
+ - `Column#extract` now emits an explicit `NOT NULL` for non-nullable columns. Without this, 0.14.0 produced table DDL without any NOT NULL clauses because the previously-relied-on `SYS_*` NOT NULL CHECK constraints are now filtered out as redundant noise.
9
+
10
+ ## [0.14.0] - 2026-04-28
11
+
12
+ ### Changed
13
+ - Reuse a single OCI8 logical connection per worker thread for the duration of the fetch instead of acquiring/logging off on every type fetch. Drastically reduces session attach/detach traffic against the connection pool, which avoids the per-attach overhead (and the 23c Instant Client byte-leak symptom) on long extracts.
14
+ - Batch-load constraint metadata via two bulk queries against `USER_CONSTRAINTS` and `USER_CONS_COLUMNS` once before the parallel object fetch, and have `Constraint#fetch` read from an in-memory cache. Removes 2-3 round-trips per constraint.
15
+ - Constraints with Oracle-generated `SYS_*` names are now emitted without an explicit `CONSTRAINT <name>` clause, so DDL diffs across instances aren't dominated by name churn. User-given names are preserved.
16
+ - Redundant `SYS_*` NOT NULL CHECK constraints (whose condition is just `"COL" IS NOT NULL`) are filtered out — the column-level NOT NULL in the table DDL already covers them.
17
+ - Fixed `View#fetch` to reuse the acquired connection (previously called `Connection.instance.get` twice, leaking a logical connection per view).
18
+ - Fixed `View#extract` crash when a view has columns without comments (`column.comment.size` on nil).
19
+ - Fixed `Table#fetch` ensure logic (was `rescue` instead of `ensure`).
20
+ - Fixed `Column.all` typo (`loggoff` → cleanup no longer needed).
21
+
22
+ ### Added
23
+ - README troubleshooting section for macOS / Apple Silicon: short tip covering both the 23c OID lookup hang and the `libclntsh` ↔ OpenLDAP symbol-clash, with the shared `tnsnames.ora` + `NAMES.DIRECTORY_PATH=(TNSNAMES, EZCONNECT)` fix and links to the relevant ruby-oci8 / Oracle docs.
24
+ - Significantly expanded test coverage (49 → 125 examples; line coverage 58.94% → ~86%).
25
+ - Added Ruby 4.0 to the supported/tested matrix.
26
+
27
+ ### Removed
28
+ - Dropped Ruby 3.2 from the actively tested matrix (EOL 31 Mar 2026).
29
+
1
30
  ## [0.13.1] - 2025-11-09
2
31
 
3
32
  ### Added
data/README.md CHANGED
@@ -2,12 +2,15 @@
2
2
  [![01 - Test](https://github.com/thomis/db_meta/actions/workflows/01_test.yml/badge.svg)](https://github.com/thomis/db_meta/actions/workflows/01_test.yml)
3
3
  [![02 - Release](https://github.com/thomis/db_meta/actions/workflows/02_release.yml/badge.svg)](https://github.com/thomis/db_meta/actions/workflows/02_release.yml)
4
4
 
5
- # Welcome to db_meta
6
- Database meta and core data extraction.
5
+ # db_meta
7
6
 
8
- ## Is it production ready?
7
+ Extract Oracle schema metadata and core data as SQL DDL files.
9
8
 
10
- Well, I would not say, but I am using it already for my database development work where the gem covers my needs. Be careful and check details. Please create an issue when you think that someting is wrong or missing.
9
+ `db_meta` connects to an Oracle schema and writes out DDL for every object (tables, views, indexes, constraints, packages, sequences, synonyms, grants, …), plus optional `INSERT` scripts for reference/lookup data. The output is a folder of `.sql` files organized by object type suitable for checking into version control, diffing across environments, or seeding a fresh schema.
10
+
11
+ ## Status
12
+
13
+ Used in day-to-day database development by the author. It covers the most common Oracle object types but is not exhaustive — exotic features (advanced storage clauses, partitioning details, etc.) may be missing or simplified. Spot-check the output before relying on it for a migration, and please open an issue if you hit something that's wrong or missing.
11
14
 
12
15
  ## Installation
13
16
  via Gemfile
@@ -30,6 +33,18 @@ meta.fetch
30
33
  meta.extract
31
34
  ```
32
35
 
36
+ ## Output conventions
37
+
38
+ A few decisions worth knowing about, especially if you compare extracts across instances:
39
+
40
+ - **Auto-generated `SYS_*` constraint names are stripped from the output.** Oracle invents names like `SYS_C0012345` for unnamed constraints, and those names differ between instances — making schema diffs noisy. Constraints with a `SYS_*` name are emitted without an explicit `CONSTRAINT <name>` clause; on import, Oracle just generates a fresh name. User-given constraint names are preserved as-is.
41
+ - **Redundant `NOT NULL` CHECK constraints are omitted.** Oracle exposes column-level `NOT NULL` both as a column attribute and as a `SYS_*` CHECK constraint with a body of `"COL" IS NOT NULL`. The column-level form is already in the table DDL, so the duplicate CHECK is filtered out.
42
+ - **Sequences start from their `MINVALUE`, not from the live `LAST_NUMBER`.** Oracle's `LAST_NUMBER` advances every time someone calls `NEXTVAL`, so emitting it would make extracts diverge between any two instances of the same schema. The default output therefore starts each sequence at its baseline (typically 1), so a fresh schema build is reproducible and diffs stay clean. If you're seeding a new schema alongside imported data and need sequences to continue past existing PK values, pass `preserve_sequence_position: true` to `extract`:
43
+
44
+ ```ruby
45
+ meta.extract(preserve_sequence_position: true)
46
+ ```
47
+
33
48
  ## Supported Databases
34
49
  - Oracle
35
50
 
@@ -49,12 +64,13 @@ meta.extract
49
64
 
50
65
  Currently supported and tested ruby versions are:
51
66
 
67
+ - 4.0 (EOL 31 Mar 2029)
52
68
  - 3.4 (EOL 31 Mar 2028)
53
69
  - 3.3 (EOL 31 Mar 2027)
54
- - 3.2 (EOL 31 Mar 2026)
55
70
 
56
71
  Ruby versions not tested anymore:
57
72
 
73
+ - 3.2 (EOL 31 Mar 2026)
58
74
  - 3.1 (EOL 31 Mar 2025)
59
75
  - 3.0 (EOL 31 Mar 2024)
60
76
  - 2.7 (EOL 31 Mar 2023)
@@ -63,6 +79,16 @@ Ruby versions not tested anymore:
63
79
  ## Planned Features
64
80
  - Storage and tablespace clause
65
81
 
82
+ ## Troubleshooting (macOS / Apple Silicon)
83
+
84
+ If `OCI8.new` hangs for ~10s, prints "byte leak" gibberish, or crashes with `ldap_first_entry: Assertion …`, the issue is almost always that the Instant Client is trying to use LDAP/OID for database name resolution. The fix is the same in both cases: tell Oracle to use a local `tnsnames.ora` instead of LDAP. Create `~/opt/oracle/admin/tnsnames.ora` with your DB alias and `~/opt/oracle/admin/sqlnet.ora` containing `NAMES.DIRECTORY_PATH=(TNSNAMES, EZCONNECT)`, then `export TNS_ADMIN=$HOME/opt/oracle/admin`.
85
+
86
+ For background and the `libclntsh` ↔ OpenLDAP symbol-clash variant (caused by Oracle's bundled LDAP client and Homebrew's OpenLDAP both loading into the same Ruby process), see:
87
+
88
+ - [ruby-oci8 #32 — OCI8 hangs when switching to LDAP](https://github.com/kubo/ruby-oci8/issues/32)
89
+ - [ruby-oci8 #41 — Assertion failure using LDAP](https://github.com/kubo/ruby-oci8/issues/41)
90
+ - [Oracle Instant Client FAQ](https://www.oracle.com/database/technologies/instant-client/faqs.html)
91
+
66
92
  ## Publishing
67
93
 
68
94
  This project uses [Trusted Publishing](https://guides.rubygems.org/trusted-publishing/) to securely publish gems to RubyGems.org. Trusted Publishing eliminates the need for long-lived API tokens by using OpenID Connect (OIDC) to establish a trusted relationship between GitHub Actions and RubyGems.org.
data/db_meta.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 2.3"
21
+ spec.add_development_dependency "bundler", ">= 2.3"
22
22
  spec.add_development_dependency "rake", "~> 13.1"
23
23
  spec.add_development_dependency "rspec", "~> 3.13"
24
24
  spec.add_development_dependency "standard", "~> 1.34"
@@ -5,6 +5,8 @@ module DbMeta
5
5
  class Connection
6
6
  include Singleton
7
7
 
8
+ THREAD_KEY = :db_meta_oracle_connection
9
+
8
10
  attr_accessor :username, :password, :database_instance
9
11
  attr_reader :pool
10
12
  attr_reader :worker
@@ -23,11 +25,22 @@ module DbMeta
23
25
  Log.info("Connected to #{@username}@#{@database_instance}")
24
26
  end
25
27
 
26
- # create and return logical connection. It creates physical connection as needed.
27
- ::OCI8.new(@username, @password, @pool)
28
+ # one logical connection per thread - reused across all fetches in that thread
29
+ Thread.current[THREAD_KEY] ||= ::OCI8.new(@username, @password, @pool)
30
+ end
31
+
32
+ def release_thread_connection
33
+ connection = Thread.current[THREAD_KEY]
34
+ return unless connection
35
+ connection.logoff
36
+ rescue
37
+ # connection may already be closed
38
+ ensure
39
+ Thread.current[THREAD_KEY] = nil
28
40
  end
29
41
 
30
42
  def disconnect
43
+ release_thread_connection
31
44
  return unless @pool
32
45
  @pool.destroy
33
46
  Log.info("Logged off from #{@username}@#{@database_instance}")
@@ -26,6 +26,9 @@ module DbMeta
26
26
  end
27
27
 
28
28
  def fetch(args = {})
29
+ # bulk-load metadata that would otherwise drive N round-trips per object
30
+ Constraint.preload
31
+
29
32
  # fetch details in parallel
30
33
  # number of threads = physical connections / 2 to prevent application locking
31
34
  worker = (1..Connection.instance.worker / 2).map {
@@ -35,6 +38,8 @@ module DbMeta
35
38
  object.fetch
36
39
  end
37
40
  rescue ThreadError
41
+ ensure
42
+ Connection.instance.release_thread_connection
38
43
  end
39
44
  }
40
45
  worker.map(&:join) # wait until all are done
@@ -215,8 +220,6 @@ module DbMeta
215
220
  Log.info("Objects: #{items.size}, Object Types: #{types.uniq.size}")
216
221
 
217
222
  objects
218
- ensure
219
- connection&.logoff # closes logical connection
220
223
  end
221
224
  end
222
225
  end
@@ -7,6 +7,7 @@ module DbMeta
7
7
  buffer = ("%-30s" % @name).to_s
8
8
  buffer << " #{convert_type}"
9
9
  buffer << " DEFAULT #{@data_default.strip}" if @data_default.size > 0
10
+ buffer << " NOT NULL" if @nullable == "N"
10
11
  buffer
11
12
  end
12
13
 
@@ -36,8 +37,6 @@ module DbMeta
36
37
  cursor.close
37
38
 
38
39
  columns
39
- rescue
40
- connection.loggoff
41
40
  end
42
41
 
43
42
  private
@@ -9,8 +9,6 @@ module DbMeta
9
9
  while (row = cursor.fetch)
10
10
  @text = row[0]
11
11
  end
12
- ensure
13
- connection.logoff
14
12
  end
15
13
  end
16
14
  end
@@ -5,6 +5,72 @@ module DbMeta
5
5
 
6
6
  attr_reader :constraint_type, :table_name, :search_condition, :referential_constraint, :delete_rule, :columns
7
7
 
8
+ @@cache = {}
9
+ @@cache_mutex = Mutex.new
10
+
11
+ def self.preload(args = {})
12
+ connection_class = args[:connection_class] || Connection
13
+ connection = connection_class.instance.get
14
+
15
+ meta = {}
16
+ cursor = connection.exec(
17
+ "select constraint_name, constraint_type, table_name, search_condition, r_constraint_name, delete_rule " \
18
+ "from user_constraints"
19
+ )
20
+ cursor.fetch_hash do |row|
21
+ name = row["CONSTRAINT_NAME"]
22
+ type = translate_constraint_type(row["CONSTRAINT_TYPE"])
23
+ search_condition = row["SEARCH_CONDITION"]
24
+
25
+ # Skip Oracle-generated NOT NULL CHECK constraints. They are already
26
+ # represented by the column's NOT NULL clause in the table DDL, so
27
+ # emitting them again is redundant noise that breaks schema diffs.
28
+ next if redundant_not_null?(name, type, search_condition)
29
+
30
+ meta[name] = {
31
+ constraint_type: type,
32
+ table_name: row["TABLE_NAME"],
33
+ search_condition: search_condition,
34
+ r_constraint_name: row["R_CONSTRAINT_NAME"],
35
+ delete_rule: row["DELETE_RULE"],
36
+ columns: []
37
+ }
38
+ end
39
+ cursor.close
40
+
41
+ cursor = connection.exec(
42
+ "select constraint_name, column_name, position " \
43
+ "from user_cons_columns order by constraint_name, position"
44
+ )
45
+ cursor.fetch_hash do |row|
46
+ entry = meta[row["CONSTRAINT_NAME"]]
47
+ next unless entry
48
+ entry[:columns] << row["COLUMN_NAME"]
49
+ end
50
+ cursor.close
51
+
52
+ @@cache_mutex.synchronize { @@cache = meta }
53
+ end
54
+
55
+ def self.system_generated?(name)
56
+ name.to_s.start_with?("SYS_")
57
+ end
58
+
59
+ def self.redundant_not_null?(name, type, search_condition)
60
+ return false unless system_generated?(name) && type == "CHECK"
61
+ return false if search_condition.nil?
62
+ # Match patterns like: "COL_NAME" IS NOT NULL or COL_NAME IS NOT NULL
63
+ !!search_condition.match?(/\A\s*"?[A-Z0-9_$#]+"?\s+IS\s+NOT\s+NULL\s*\z/i)
64
+ end
65
+
66
+ def self.cache
67
+ @@cache
68
+ end
69
+
70
+ def self.reset_cache
71
+ @@cache_mutex.synchronize { @@cache = {} }
72
+ end
73
+
8
74
  def initialize(args = {})
9
75
  super
10
76
 
@@ -13,37 +79,29 @@ module DbMeta
13
79
  end
14
80
 
15
81
  def fetch(args = {})
16
- connection = Connection.instance.get
17
- cursor = connection.exec("select * from user_constraints where constraint_name = '#{@name}'")
18
- cursor.fetch_hash do |item|
19
- @constraint_type = translate_constraint_type(item["CONSTRAINT_TYPE"])
20
- @extract_type = :merged if @constraint_type == "FOREIGN KEY"
21
- @table_name = item["TABLE_NAME"]
22
- @search_condition = item["SEARCH_CONDITION"]
23
- @delete_rule = item["DELETE_RULE"]
24
-
25
- if @constraint_type == "FOREIGN KEY"
26
- constraint = Constraint.new("OBJECT_TYPE" => "CONSTRAINT", "OBJECT_NAME" => item["R_CONSTRAINT_NAME"])
27
- constraint.fetch
28
- @referential_constraint = constraint
29
- end
30
- end
31
- cursor.close
82
+ entry = @@cache[@name]
83
+ return unless entry
32
84
 
33
- # get affected columns
34
- cursor = connection.exec("select * from user_cons_columns where constraint_name = '#{@name}' order by position")
35
- cursor.fetch_hash do |item|
36
- @columns << item["COLUMN_NAME"]
85
+ @constraint_type = entry[:constraint_type]
86
+ @table_name = entry[:table_name]
87
+ @search_condition = entry[:search_condition]
88
+ @delete_rule = entry[:delete_rule]
89
+ @columns = entry[:columns].dup
90
+ @extract_type = :merged if @constraint_type == "FOREIGN KEY"
91
+
92
+ if @constraint_type == "FOREIGN KEY" && entry[:r_constraint_name]
93
+ @referential_constraint = Constraint.new(
94
+ "OBJECT_TYPE" => "CONSTRAINT",
95
+ "OBJECT_NAME" => entry[:r_constraint_name]
96
+ )
97
+ @referential_constraint.fetch
37
98
  end
38
- cursor.close
39
- ensure
40
- connection.logoff
41
99
  end
42
100
 
43
101
  def extract(args = {})
44
102
  buffer = []
45
103
  buffer << "ALTER TABLE #{@table_name} ADD ("
46
- buffer << " CONSTRAINT #{@name}"
104
+ buffer << " CONSTRAINT #{@name}" unless Constraint.system_generated?(@name)
47
105
 
48
106
  case @constraint_type
49
107
  when "CHECK"
@@ -69,9 +127,7 @@ module DbMeta
69
127
  ["PRIMARY KEY", "FOREIGN KEY", "UNIQUE", "CHECK"].index(type)
70
128
  end
71
129
 
72
- private
73
-
74
- def translate_constraint_type(type)
130
+ def self.translate_constraint_type(type)
75
131
  case type
76
132
  when "P"
77
133
  "PRIMARY KEY"
@@ -15,8 +15,6 @@ module DbMeta
15
15
  @host = row[2].to_s
16
16
  end
17
17
  cursor.close
18
- ensure
19
- connection.logoff
20
18
  end
21
19
 
22
20
  def extract(args = {})
@@ -14,8 +14,6 @@ module DbMeta
14
14
  @source << row[0].to_s
15
15
  end
16
16
  cursor.close
17
- ensure
18
- connection.logoff
19
17
  end
20
18
 
21
19
  def extract(args = {})
@@ -38,8 +38,6 @@ module DbMeta
38
38
  @columns[idx] = row[0] # replace sys_... entry
39
39
  end
40
40
  cursor.close
41
- ensure
42
- connection.logoff
43
41
  end
44
42
 
45
43
  def extract(args = {})
@@ -33,8 +33,6 @@ module DbMeta
33
33
  @comment = item["COMMENTS"]
34
34
  end
35
35
  cursor.close
36
- ensure
37
- connection.logoff
38
36
  end
39
37
 
40
38
  def extract(args = {})
@@ -6,22 +6,21 @@ module DbMeta
6
6
  attr_reader :header, :body
7
7
 
8
8
  def fetch
9
+ connection = Connection.instance.get
10
+
9
11
  @header = ""
10
- cursor = Connection.instance.get.exec("select text from user_source where type = 'PACKAGE' and name = '#{@name}' order by line")
12
+ cursor = connection.exec("select text from user_source where type = 'PACKAGE' and name = '#{@name}' order by line")
11
13
  while (row = cursor.fetch)
12
14
  @header << row[0].to_s
13
15
  end
14
16
  cursor.close
15
17
 
16
18
  @body = ""
17
- connection = Connection.instance.get
18
19
  cursor = connection.exec("select text from user_source where type = 'PACKAGE BODY' and name = '#{@name}' order by line")
19
20
  while (row = cursor.fetch)
20
21
  @body << row[0].to_s
21
22
  end
22
23
  cursor.close
23
- ensure
24
- connection.logoff
25
24
  end
26
25
 
27
26
  def extract(args = {})
@@ -14,8 +14,6 @@ module DbMeta
14
14
  @source << row[0].to_s
15
15
  end
16
16
  cursor.close
17
- ensure
18
- connection.logoff
19
17
  end
20
18
 
21
19
  def extract(args = {})
@@ -23,8 +23,6 @@ module DbMeta
23
23
  @compatible = row["COMPATIBLE"]
24
24
  end
25
25
  cursor.close
26
- ensure
27
- connection.logoff
28
26
  end
29
27
 
30
28
  def extract(args = {})
@@ -19,14 +19,15 @@ module DbMeta
19
19
  @last_number = row[6].to_i
20
20
  end
21
21
  cursor.close
22
- ensure
23
- connection.logoff
24
22
  end
25
23
 
26
24
  def extract(args = {})
25
+ start_value = args[:preserve_sequence_position] ? @last_number : @min_value
26
+
27
27
  buffer = [block(@name)]
28
28
  buffer << "CREATE SEQUENCE #{@name}"
29
- buffer << " START WITH #{@last_number}"
29
+ buffer << " START WITH #{start_value}"
30
+ buffer << " INCREMENT BY #{@increment_by}"
30
31
  buffer << " MAXVALUE #{@max_value}"
31
32
  buffer << " MINVALUE #{@min_value}"
32
33
  buffer << ((@cycle_flag == "N") ? " NOCYCLE" : " CYCLE")
@@ -21,8 +21,6 @@ module DbMeta
21
21
  @db_link = row[2].to_s
22
22
  end
23
23
  cursor.close
24
- ensure
25
- connection.logoff
26
24
  end
27
25
 
28
26
  def extract(args = {})
@@ -36,8 +36,6 @@ module DbMeta
36
36
  @duration = row[3].to_s
37
37
  end
38
38
  cursor.close
39
- rescue
40
- connection.logoff
41
39
  end
42
40
 
43
41
  def extract(args = {})
@@ -54,7 +52,7 @@ module DbMeta
54
52
  if @iot_type == "IOT"
55
53
  constraint = @constraints.find { |c| c.constraint_type == "PRIMARY KEY" }
56
54
  buffer[-1] += ","
57
- buffer << " CONSTRAINT #{constraint.name}"
55
+ buffer << " CONSTRAINT #{constraint.name}" unless Constraint.system_generated?(constraint.name)
58
56
  buffer << " PRIMARY KEY (#{constraint.columns.join(", ")})"
59
57
  buffer << " ENABLE VALIDATE"
60
58
  end
@@ -44,8 +44,6 @@ module DbMeta
44
44
  buffer << nil
45
45
 
46
46
  buffer.join("\n")
47
- ensure
48
- connection.logoff
49
47
  end
50
48
 
51
49
  def ddl_drop
@@ -27,8 +27,6 @@ module DbMeta
27
27
  parse_trigger_type
28
28
 
29
29
  cursor.close
30
- ensure
31
- connection.logoff
32
30
  end
33
31
 
34
32
  def extract(args = {})
@@ -19,8 +19,6 @@ module DbMeta
19
19
  @body << row[0].to_s
20
20
  end
21
21
  cursor.close
22
- ensure
23
- connection.logoff
24
22
  end
25
23
 
26
24
  def extract(args = {})
@@ -15,13 +15,11 @@ module DbMeta
15
15
 
16
16
  @source = ""
17
17
  connection = Connection.instance.get
18
- cursor = Connection.instance.get.exec("select text from user_views where view_name = '#{@name}'")
18
+ cursor = connection.exec("select text from user_views where view_name = '#{@name}'")
19
19
  while (row = cursor.fetch)
20
20
  @source << row[0].to_s
21
21
  end
22
22
  cursor.close
23
- ensure
24
- connection.logoff
25
23
  end
26
24
 
27
25
  def extract(args = {})
@@ -47,7 +45,7 @@ module DbMeta
47
45
 
48
46
  # view column comments
49
47
  @columns.each do |column|
50
- next if column.comment.size == 0
48
+ next if column.comment.nil? || column.comment.size == 0
51
49
  buffer << "COMMENT ON COLUMN #{@name}.#{column.name} IS '#{column.comment.gsub("'", "''")}';"
52
50
  end
53
51
 
@@ -1,3 +1,3 @@
1
1
  module DbMeta
2
- VERSION = "0.13.1"
2
+ VERSION = "0.14.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db_meta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomi
@@ -13,14 +13,14 @@ dependencies:
13
13
  name: bundler
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '2.3'
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '2.3'
26
26
  - !ruby/object:Gem::Dependency
@@ -185,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
185
  - !ruby/object:Gem::Version
186
186
  version: '0'
187
187
  requirements: []
188
- rubygems_version: 3.6.9
188
+ rubygems_version: 4.0.6
189
189
  specification_version: 4
190
190
  summary: Database meta and core data extraction
191
191
  test_files: []