tina4ruby 3.13.53 → 3.13.54

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: 79a09ae5dffe2688af3e75a98dcf999929a1c560f3d8afbdc874590d6dfca275
4
- data.tar.gz: 92d0d0b44f0e103a3f8ac894c620b075446bab88040d865095e7b9c23ea421fe
3
+ metadata.gz: cd2180527148137de7bd985ed3951aefcae89d9fee30032de3c34434b3cc209e
4
+ data.tar.gz: 78e32b6e6021f24c455bb002339a59c54a8a134a1b219493c6dc994d66ebaff5
5
5
  SHA512:
6
- metadata.gz: 128df90a6f281fefb62fc1e49e3075c52474d2c9f70cddc992e1c68a083b8dff38e9c6d014ffec0019736719f49bc2f80cb93eb2f3dff2b3deb336845db1f0e2
7
- data.tar.gz: c579de40838336727fd25581e8d4db17bd3c449034e4805ba29a8215be60f5344c7608152c6c21cc7258396525e1bc5aee86b12ec4927de62f1745f39797601d
6
+ metadata.gz: 8f422139294a6d51b34507f116dd21621e5299829b02f7ec613083bd2bc9d051a4c832c01dab8120978708fa637302b35b6b05d2f463a188f91dfc9d89d2879b
7
+ data.tar.gz: 96ebc4a47de1674a828dc5913c4586fc82170f0c04159724d69a1cd6a99d15596bc5f217aa76ed4e119675559fc48d7b22cbd71eccd10e231de32d1ab2bc61da
@@ -229,19 +229,34 @@ module Tina4
229
229
  end
230
230
  end
231
231
 
232
+ # Return a result row keyed by lower-case symbols. Firebird returns rows keyed
233
+ # by UPPERCASE string column names while SQLite/others return lower-case symbol
234
+ # keys, so the tracking-table reads below are normalised to one shape. Without
235
+ # this, `row[:migration_name]` is nil on Firebird and every applied migration
236
+ # is treated as pending and re-run.
237
+ def normalize_row(row)
238
+ return {} if row.nil?
239
+
240
+ source = row.respond_to?(:to_h) ? row.to_h : row
241
+ source.each_with_object({}) { |(k, v), h| h[k.to_s.downcase.to_sym] = v }
242
+ end
243
+
232
244
  def completed_migrations
233
245
  result = @db.fetch("SELECT migration_name FROM #{TRACKING_TABLE} WHERE passed = 1 ORDER BY id")
234
- result.map { |r| r[:migration_name] }
246
+ result.map { |r| normalize_row(r)[:migration_name] }
235
247
  end
236
248
 
237
249
  def completed_migrations_with_batch
238
250
  result = @db.fetch("SELECT id, migration_name, batch FROM #{TRACKING_TABLE} WHERE passed = 1 ORDER BY id")
239
- result.map { |r| { id: r[:id], migration_name: r[:migration_name], batch: r[:batch] } }
251
+ result.map do |r|
252
+ row = normalize_row(r)
253
+ { id: row[:id], migration_name: row[:migration_name], batch: row[:batch] }
254
+ end
240
255
  end
241
256
 
242
257
  def next_batch_number
243
- result = @db.fetch_one("SELECT MAX(batch) as max_batch FROM #{TRACKING_TABLE} WHERE passed = 1")
244
- (result && result[:max_batch] ? result[:max_batch].to_i : 0) + 1
258
+ result = normalize_row(@db.fetch_one("SELECT MAX(batch) as max_batch FROM #{TRACKING_TABLE} WHERE passed = 1"))
259
+ (result[:max_batch] ? result[:max_batch].to_i : 0) + 1
245
260
  end
246
261
 
247
262
  def pending_migrations
@@ -479,12 +494,22 @@ module Tina4
479
494
  next
480
495
  end
481
496
 
482
- # Statement delimiter — only reached outside blocks/comments/strings.
497
+ # Statement delimiter — only reached outside blocks/comments/strings. A
498
+ # SET TERM directive switches the active terminator and is consumed
499
+ # (never emitted); any other completed statement is collected.
483
500
  if !delimiter.empty? && sql[i, dlen] == delimiter
501
+ i += dlen
484
502
  stmt = current.strip
485
- statements << stmt unless stmt.empty?
486
503
  current = +""
487
- i += dlen
504
+ unless stmt.empty?
505
+ new_term = parse_set_term(stmt)
506
+ if new_term
507
+ delimiter = new_term
508
+ dlen = delimiter.length
509
+ else
510
+ statements << stmt
511
+ end
512
+ end
488
513
  next
489
514
  end
490
515
 
@@ -492,11 +517,30 @@ module Tina4
492
517
  i += 1
493
518
  end
494
519
 
520
+ # Trailing statement (may not end with a delimiter). A trailing SET TERM
521
+ # directive is a no-op — consume it, don't emit it.
495
522
  stmt = current.strip
496
- statements << stmt unless stmt.empty?
523
+ statements << stmt unless stmt.empty? || parse_set_term(stmt)
497
524
  statements
498
525
  end
499
526
 
527
+ # Return the new terminator from a `SET TERM <new> <current>` directive, or
528
+ # nil when +statement+ is not a SET TERM directive.
529
+ #
530
+ # SET TERM is a script-level directive (recognised by isql and other
531
+ # InterBase/Firebird tooling, not run by the engine) that changes the
532
+ # terminator separating statements. Recognising it lets a statement whose own
533
+ # body contains the default ";" terminator — a trigger, stored procedure or
534
+ # EXECUTE BLOCK — be kept intact rather than split on those inner ";". The
535
+ # terminator may be more than one character (e.g. "!!").
536
+ #
537
+ # @param statement [String] a single, already-stripped statement
538
+ # @return [String, nil] the new terminator, or nil when not a SET TERM directive
539
+ def parse_set_term(statement)
540
+ m = statement.strip.match(/\ASET\s+TERM\s+(\S+)\z/i)
541
+ m && m[1]
542
+ end
543
+
500
544
  def execute_sql_file(file)
501
545
  sql = File.read(file)
502
546
  statements = split_sql_statements(sql)
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.13.53"
4
+ VERSION = "3.13.54"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.53
4
+ version: 3.13.54
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-06 00:00:00.000000000 Z
11
+ date: 2026-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack