fb 0.9.2 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85959395ea35e03609898e959a9a6d72a12e67668b2b438684c65d197ee9a77d
4
- data.tar.gz: 61d51c626978212ba2857911b4a041468b1b1cea5409d0fb87349a7a3e93cb06
3
+ metadata.gz: 1415cff2f9f2c6be0873c14498b0371608c71e43656539aa671b1ba980771748
4
+ data.tar.gz: f556b1a03eb33b21b12fe8ab28ffd677d6738c5848ff1d2da1aed3a3ed0df684
5
5
  SHA512:
6
- metadata.gz: 8ec388455ba9b8efcca12c767a5fa4560df0b1ede1c3b6b9fddaf271f6c5c9c39e9a2fcd264521b5cdb3079ec8d6114f2efeabafcaae00299226e13ed236bed8
7
- data.tar.gz: f1949849953a5539b0094359446440cb1426425b827431fce7400b93da57cfee58b98c742d5efdf47681dbf10553a7f261840a366ac5adf97de5890769880b6e
6
+ metadata.gz: 83d5395e6951329567df2da7b4b98e87cc933c40a1b6afa53385da86a3bd632dd4be082b4e04190c3ad25a36284afc83183f4ecd8c13cf620dbeaca8265f5d8b
7
+ data.tar.gz: 79f5db3854e727db141e6aee96284703bbfbc181ae18de57f7ef45f780c09ab329e19f01aa337414e2532fca6d6bf965cc19b4702105edd744b31f4d2de5759c
data/extconf.rb CHANGED
@@ -13,6 +13,7 @@
13
13
  # * Unit tests take about 10 times as long to complete using Firebird Classic. Default xinetd.conf settings may not allow the tests to complete due to the frequency with which new attachments are made.
14
14
  # = Mac OS X (Intel)
15
15
  # * Works
16
+ WINDOWS_PLATFORMS = /(mingw32|mswin32|x64-mingw-ucrt)/
16
17
 
17
18
  def unquote(string)
18
19
  string.sub(/\A(['"])?(.*?)\1?\z/m, '\2') unless string.nil?
@@ -44,8 +45,8 @@ def search_firebird_path
44
45
  result = Dir["#{program_files}/Firebird/Firebird_*"].sort.last || Dir["#{program_files_x86}/Firebird/Firebird_*"].sort.last
45
46
  end
46
47
 
47
- if RUBY_PLATFORM =~ /(mingw32|mswin32)/ and ARGV.grep(/^--with-opt-dir=/).empty?
48
- opt = unquote(ENV['FIREBIRD'])
48
+ if RUBY_PLATFORM =~ WINDOWS_PLATFORMS and ARGV.grep(/^--with-opt-dir=/).empty?
49
+ opt = unquote(ENV['FIREBIRD'])
49
50
  opt = opt || read_firebird_registry
50
51
  opt = opt || search_firebird_path
51
52
  if opt
@@ -53,7 +54,7 @@ if RUBY_PLATFORM =~ /(mingw32|mswin32)/ and ARGV.grep(/^--with-opt-dir=/).empty?
53
54
  else
54
55
  puts "No any Firebird instances found in system."
55
56
  exit
56
- end
57
+ end
57
58
  end
58
59
 
59
60
  require 'mkmf'
@@ -63,7 +64,7 @@ libs = %w/ fbclient gds /
63
64
  case RUBY_PLATFORM
64
65
  when /bccwin32/
65
66
  libs.push "fbclient_bor"
66
- when /mswin32/, /mingw32/
67
+ when WINDOWS_PLATFORMS
67
68
  $CFLAGS = $CFLAGS + " -DOS_WIN32"
68
69
  libs.push "fbclient_ms"
69
70
  when /darwin/
@@ -73,7 +74,8 @@ case RUBY_PLATFORM
73
74
  # $LDFLAGS.gsub!(/-arch (\w+)/) { |m| $1 == hosttype ? m : '' }
74
75
  # CONFIG['LDSHARED'].gsub!(/-arch (\w+)/) { |m| $1 == hosttype ? m : '' }
75
76
  $CPPFLAGS += " -I/Library/Frameworks/Firebird.framework/Headers"
76
- $LDFLAGS += " -framework Firebird"
77
+ # $LDFLAGS += " -framework Firebird"
78
+ $LDFLAGS += " -L/Library/Frameworks/Firebird.framework/Resources/lib -Wl,-rpath,/Library/Frameworks/Firebird.framework/Resources/lib"
77
79
  when /linux/
78
80
  $CFLAGS = $CFLAGS + " -DOS_UNIX"
79
81
  end
@@ -83,7 +85,7 @@ dir_config("firebird")
83
85
  test_func = "isc_attach_database"
84
86
 
85
87
  case RUBY_PLATFORM
86
- when /mswin32/, /mingw32/
88
+ when WINDOWS_PLATFORMS
87
89
  libs.find {|lib| have_library(lib) } and
88
90
  have_func(test_func, ["ibase.h"])
89
91
  else
data/fb.c CHANGED
@@ -430,6 +430,11 @@ static VALUE fb_sql_type_from_code(int code, int subtype)
430
430
  case 2: sql_type = "DECIMAL"; break;
431
431
  }
432
432
  break;
433
+ #if (FB_API_VER >= 40)
434
+ case SQL_INT128:
435
+ sql_type = "INT128";
436
+ break;
437
+ #endif
433
438
  default:
434
439
  printf("Unknown: %d, %d\n", code, subtype);
435
440
  sql_type = "UNKNOWN";
@@ -497,8 +502,43 @@ static VALUE cursor_drop _((VALUE));
497
502
  static VALUE cursor_execute _((int, VALUE*, VALUE));
498
503
  static VALUE cursor_fetchall _((int, VALUE*, VALUE));
499
504
 
500
- static void fb_cursor_mark();
501
- static void fb_cursor_free();
505
+ static void fb_cursor_mark(struct FbCursor *fb_cursor);
506
+ static void fb_cursor_free(struct FbCursor *fb_cursor);
507
+ static void fb_connection_mark(struct FbConnection *fb_connection);
508
+ static void fb_connection_free(struct FbConnection *fb_connection);
509
+
510
+ /* ruby data types */
511
+
512
+ static const rb_data_type_t fbdatabase_data_type = {
513
+ "FBDB",
514
+ {
515
+ NULL,
516
+ NULL,
517
+ NULL,
518
+ NULL,
519
+ },
520
+ 0, 0, 0
521
+ };
522
+
523
+ static const rb_data_type_t fbconnection_data_type = {
524
+ "fbdb/connection",
525
+ {
526
+ (void (*)(void *))fb_connection_mark,
527
+ (void (*)(void *))fb_connection_free,
528
+ NULL,
529
+ },
530
+ 0, 0, 0
531
+ };
532
+
533
+ static const rb_data_type_t fbcursor_data_type = {
534
+ "fbdb/cursor",
535
+ {
536
+ (void (*)(void *))fb_cursor_mark,
537
+ (void (*)(void *))fb_cursor_free,
538
+ NULL,
539
+ },
540
+ 0, 0, 0
541
+ };
502
542
 
503
543
  /* connection utilities */
504
544
  static void fb_connection_check(struct FbConnection *fb_connection)
@@ -970,7 +1010,7 @@ static VALUE connection_transaction(int argc, VALUE *argv, VALUE self)
970
1010
  VALUE opt = Qnil;
971
1011
 
972
1012
  rb_scan_args(argc, argv, "01", &opt);
973
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1013
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
974
1014
 
975
1015
  fb_connection_transaction_start(fb_connection, opt);
976
1016
 
@@ -997,7 +1037,7 @@ static VALUE connection_transaction(int argc, VALUE *argv, VALUE self)
997
1037
  static VALUE connection_transaction_started(VALUE self)
998
1038
  {
999
1039
  struct FbConnection *fb_connection;
1000
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1040
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1001
1041
 
1002
1042
  return fb_connection->transact ? Qtrue : Qfalse;
1003
1043
  }
@@ -1010,7 +1050,7 @@ static VALUE connection_transaction_started(VALUE self)
1010
1050
  static VALUE connection_commit(VALUE self)
1011
1051
  {
1012
1052
  struct FbConnection *fb_connection;
1013
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1053
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1014
1054
 
1015
1055
  fb_connection_commit(fb_connection);
1016
1056
  return Qnil;
@@ -1024,7 +1064,7 @@ static VALUE connection_commit(VALUE self)
1024
1064
  static VALUE connection_rollback(VALUE self)
1025
1065
  {
1026
1066
  struct FbConnection *fb_connection;
1027
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1067
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1028
1068
 
1029
1069
  fb_connection_rollback(fb_connection);
1030
1070
  return Qnil;
@@ -1041,7 +1081,7 @@ static VALUE connection_is_open(VALUE self)
1041
1081
  {
1042
1082
  struct FbConnection *fb_connection;
1043
1083
 
1044
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1084
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1045
1085
  return (fb_connection->db == 0) ? Qfalse : Qtrue;
1046
1086
  }
1047
1087
 
@@ -1071,10 +1111,10 @@ static VALUE connection_cursor(VALUE self)
1071
1111
  struct FbConnection *fb_connection;
1072
1112
  struct FbCursor *fb_cursor;
1073
1113
 
1074
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1114
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1075
1115
  fb_connection_check(fb_connection);
1076
1116
 
1077
- c = Data_Make_Struct(rb_cFbCursor, struct FbCursor, fb_cursor_mark, fb_cursor_free, fb_cursor);
1117
+ c = TypedData_Make_Struct(rb_cFbCursor, struct FbCursor, &fbcursor_data_type, fb_cursor);
1078
1118
  fb_cursor->connection = self;
1079
1119
  fb_cursor->fields_ary = Qnil;
1080
1120
  fb_cursor->fields_hash = Qnil;
@@ -1181,7 +1221,7 @@ static VALUE connection_close(VALUE self)
1181
1221
  {
1182
1222
  struct FbConnection *fb_connection;
1183
1223
 
1184
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1224
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1185
1225
 
1186
1226
  if (fb_connection->dropped) return Qnil;
1187
1227
 
@@ -1201,7 +1241,7 @@ static VALUE connection_drop(VALUE self)
1201
1241
  {
1202
1242
  struct FbConnection *fb_connection;
1203
1243
 
1204
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1244
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1205
1245
  fb_connection->dropped = 1;
1206
1246
  fb_connection_disconnect(fb_connection);
1207
1247
  fb_connection_drop_cursors(fb_connection);
@@ -1218,7 +1258,7 @@ static VALUE connection_dialect(VALUE self)
1218
1258
  {
1219
1259
  struct FbConnection *fb_connection;
1220
1260
 
1221
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1261
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1222
1262
  fb_connection_check(fb_connection);
1223
1263
 
1224
1264
  return INT2FIX(fb_connection->dialect);
@@ -1233,7 +1273,7 @@ static VALUE connection_db_dialect(VALUE self)
1233
1273
  {
1234
1274
  struct FbConnection *fb_connection;
1235
1275
 
1236
- Data_Get_Struct(self, struct FbConnection, fb_connection);
1276
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
1237
1277
  fb_connection_check(fb_connection);
1238
1278
 
1239
1279
  return INT2FIX(fb_connection->db_dialect);
@@ -1292,14 +1332,72 @@ static void fb_cursor_free(struct FbCursor *fb_cursor)
1292
1332
 
1293
1333
  static VALUE sql_decimal_to_bigdecimal(long long sql_data, int scale)
1294
1334
  {
1295
- unsigned long i;
1296
- char bigdecimal_buffer[23];
1297
- unsigned long bigdecimal_dot;
1298
- sprintf(bigdecimal_buffer, "%022lld", sql_data);
1299
- bigdecimal_dot = strlen(bigdecimal_buffer) + scale;
1300
- for (i = strlen(bigdecimal_buffer); i > bigdecimal_dot; i--)
1301
- bigdecimal_buffer[i] = bigdecimal_buffer[i-1];
1302
- bigdecimal_buffer[bigdecimal_dot] = '.';
1335
+ char bigdecimal_buffer[128]; /* Increased buffer size */
1336
+ int is_negative = 0;
1337
+ unsigned long long abs_data;
1338
+ int len, decimal_places, dot_pos;
1339
+
1340
+ /* Handle negative numbers */
1341
+ if (sql_data < 0) {
1342
+ is_negative = 1;
1343
+ /* Use unsigned arithmetic to avoid overflow with minimum integer value */
1344
+ abs_data = (unsigned long long)(-sql_data);
1345
+ } else {
1346
+ abs_data = (unsigned long long)sql_data;
1347
+ }
1348
+
1349
+ /* Convert to string */
1350
+ int wrote = snprintf(bigdecimal_buffer, sizeof(bigdecimal_buffer), "%llu", abs_data);
1351
+ if (wrote < 0 || wrote >= (int)sizeof(bigdecimal_buffer)) {
1352
+ rb_raise(rb_eRuntimeError, "Buffer overflow in decimal conversion");
1353
+ }
1354
+ len = wrote;
1355
+
1356
+ /* Add decimal point if scale != 0 */
1357
+ if (scale != 0) {
1358
+ decimal_places = (scale < 0) ? -scale : scale;
1359
+ dot_pos = len - decimal_places;
1360
+
1361
+ /* If we need leading zeros before the decimal point */
1362
+ if (dot_pos <= 0) {
1363
+ /* Need to add leading zeros to ensure at least one digit before decimal point */
1364
+ int leading_zeros = 1 - dot_pos;
1365
+
1366
+ /* Check buffer bounds */
1367
+ if (len + leading_zeros + 1 >= (int)sizeof(bigdecimal_buffer)) {
1368
+ rb_raise(rb_eRuntimeError, "Buffer overflow in decimal conversion");
1369
+ }
1370
+
1371
+ /* Shift the string to make room for leading zeros */
1372
+ memmove(bigdecimal_buffer + leading_zeros, bigdecimal_buffer, len + 1);
1373
+
1374
+ /* Add leading zeros */
1375
+ memset(bigdecimal_buffer, '0', leading_zeros);
1376
+
1377
+ len += leading_zeros;
1378
+ dot_pos = len - decimal_places;
1379
+ }
1380
+
1381
+ /* Check buffer bounds before inserting decimal point */
1382
+ if (len + 1 >= (int)sizeof(bigdecimal_buffer)) {
1383
+ rb_raise(rb_eRuntimeError, "Buffer overflow in decimal conversion");
1384
+ }
1385
+
1386
+ /* Insert decimal point */
1387
+ memmove(bigdecimal_buffer + dot_pos + 1, bigdecimal_buffer + dot_pos, len - dot_pos);
1388
+ bigdecimal_buffer[dot_pos] = '.';
1389
+ bigdecimal_buffer[len + 1] = '\0';
1390
+ }
1391
+
1392
+ /* Add minus sign if needed - do this AFTER decimal point placement */
1393
+ if (is_negative) {
1394
+ /* Shift string to make room for minus sign */
1395
+ len = (int)strlen(bigdecimal_buffer);
1396
+ memmove(bigdecimal_buffer + 1, bigdecimal_buffer, len + 1);
1397
+ bigdecimal_buffer[0] = '-';
1398
+ bigdecimal_buffer[len + 1] = '\0'; /* Ensure proper null termination */
1399
+ }
1400
+
1303
1401
  return rb_funcall(rb_cObject, rb_intern("BigDecimal"), 1, rb_str_new2(bigdecimal_buffer));
1304
1402
  }
1305
1403
 
@@ -1341,7 +1439,7 @@ static void fb_cursor_set_inputparams(struct FbCursor *fb_cursor, long argc, VAL
1341
1439
  /* struct time_object *tobj; */
1342
1440
  struct tm tms;
1343
1441
 
1344
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
1442
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
1345
1443
 
1346
1444
  /* Check the number of parameters */
1347
1445
  if (fb_cursor->i_sqlda->sqld != argc) {
@@ -1535,7 +1633,22 @@ static void fb_cursor_set_inputparams(struct FbCursor *fb_cursor, long argc, VAL
1535
1633
  offset += alignment;
1536
1634
  break;
1537
1635
  #endif
1538
- default :
1636
+
1637
+ #if (FB_API_VER >= 40)
1638
+ case SQL_INT128:
1639
+ offset = FB_ALIGN(offset, alignment);
1640
+ var->sqldata = (char *)(fb_cursor->i_buffer + offset);
1641
+ if (var->sqlscale < 0) {
1642
+ llvalue = NUM2LL(object_to_unscaled_bigdecimal(obj, var->sqlscale));
1643
+ } else {
1644
+ llvalue = NUM2LL(object_to_fixnum(obj));
1645
+ }
1646
+ *(ISC_INT64 *)var->sqldata = llvalue;
1647
+ offset += alignment;
1648
+ break;
1649
+ #endif
1650
+
1651
+ default:
1539
1652
  rb_raise(rb_eFbError, "Specified table includes unsupported datatype (%d)", dtp);
1540
1653
  }
1541
1654
 
@@ -1561,7 +1674,7 @@ static void fb_cursor_execute_withparams(struct FbCursor *fb_cursor, long argc,
1561
1674
  {
1562
1675
  struct FbConnection *fb_connection;
1563
1676
 
1564
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
1677
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
1565
1678
  /* Check the first object type of the parameters */
1566
1679
  if (argc >= 1 && TYPE(argv[0]) == T_ARRAY) {
1567
1680
  int i;
@@ -1672,25 +1785,25 @@ static VALUE fb_cursor_fields_ary(XSQLDA *sqlda, short downcase_names)
1672
1785
  dtp = var->sqltype & ~1;
1673
1786
 
1674
1787
  if (var->aliasname_length) { /* aliasname always present? */
1675
- name = rb_tainted_str_new(var->aliasname, var->aliasname_length);
1788
+ name = rb_str_new(var->aliasname, var->aliasname_length);
1676
1789
  } else {
1677
- name = rb_tainted_str_new(var->sqlname, var->sqlname_length);
1790
+ name = rb_str_new(var->sqlname, var->sqlname_length);
1678
1791
  }
1679
1792
  if (downcase_names && no_lowercase(name)) {
1680
1793
  rb_funcall(name, id_downcase_bang, 0);
1681
1794
  }
1682
1795
  rb_str_freeze(name);
1683
- type_code = INT2NUM((long)(var->sqltype & ~1));
1796
+ type_code = INT2NUM((int)(var->sqltype & ~1));
1684
1797
  sql_type = fb_sql_type_from_code(dtp, var->sqlsubtype);
1685
1798
  sql_subtype = INT2FIX(var->sqlsubtype);
1686
- display_size = INT2NUM((long)var->sqllen);
1799
+ display_size = INT2NUM((int)var->sqllen);
1687
1800
  if (dtp == SQL_VARYING) {
1688
- internal_size = INT2NUM((long)var->sqllen + sizeof(short));
1801
+ internal_size = INT2NUM((int)(var->sqllen + sizeof(short)));
1689
1802
  } else {
1690
- internal_size = INT2NUM((long)var->sqllen);
1803
+ internal_size = INT2NUM((int)var->sqllen);
1691
1804
  }
1692
1805
  precision = precision_from_sqlvar(var);
1693
- scale = INT2NUM((long)var->sqlscale);
1806
+ scale = INT2NUM((int)var->sqlscale);
1694
1807
  nullable = (var->sqltype & 1) ? Qtrue : Qfalse;
1695
1808
 
1696
1809
  field = rb_struct_new(rb_sFbField, name, sql_type, sql_subtype, display_size, internal_size, precision, scale, nullable, type_code);
@@ -1727,7 +1840,7 @@ static void fb_cursor_fetch_prep(struct FbCursor *fb_cursor)
1727
1840
 
1728
1841
  fb_cursor_check(fb_cursor);
1729
1842
 
1730
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
1843
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
1731
1844
  fb_connection_check(fb_connection);
1732
1845
 
1733
1846
  /* Check if open cursor */
@@ -1786,7 +1899,7 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor)
1786
1899
  ISC_LONG num_segments = 0;
1787
1900
  ISC_LONG total_length = 0;
1788
1901
 
1789
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
1902
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
1790
1903
  fb_connection_check(fb_connection);
1791
1904
 
1792
1905
  if (fb_cursor->eof) {
@@ -1816,7 +1929,7 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor)
1816
1929
 
1817
1930
  switch (dtp) {
1818
1931
  case SQL_TEXT:
1819
- val = rb_tainted_str_new(var->sqldata, var->sqllen);
1932
+ val = rb_str_new(var->sqldata, var->sqllen);
1820
1933
  #if HAVE_RUBY_ENCODING_H
1821
1934
  rb_funcall(val, id_force_encoding, 1, fb_connection->encoding);
1822
1935
  #endif
@@ -1824,7 +1937,7 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor)
1824
1937
 
1825
1938
  case SQL_VARYING:
1826
1939
  vary = (VARY*)var->sqldata;
1827
- val = rb_tainted_str_new(vary->vary_string, vary->vary_length);
1940
+ val = rb_str_new(vary->vary_string, vary->vary_length);
1828
1941
  #if HAVE_RUBY_ENCODING_H
1829
1942
  rb_funcall(val, id_force_encoding, 1, fb_connection->encoding);
1830
1943
  #endif
@@ -1834,7 +1947,7 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor)
1834
1947
  if (var->sqlscale < 0) {
1835
1948
  val = sql_decimal_to_bigdecimal((long long)*(ISC_SHORT*)var->sqldata, var->sqlscale);
1836
1949
  } else {
1837
- val = INT2NUM((long)*(short*)var->sqldata);
1950
+ val = INT2NUM((int)*(short*)var->sqldata);
1838
1951
  }
1839
1952
  break;
1840
1953
 
@@ -1906,7 +2019,7 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor)
1906
2019
  break;
1907
2020
  }
1908
2021
  }
1909
- val = rb_tainted_str_new(NULL,total_length);
2022
+ val = rb_str_new(NULL,total_length);
1910
2023
  for (p = RSTRING_PTR(val); num_segments > 0; num_segments--, p += actual_seg_len) {
1911
2024
  isc_get_segment(fb_connection->isc_status, &blob_handle, &actual_seg_len, max_segment, p);
1912
2025
  fb_error_check(fb_connection->isc_status);
@@ -1923,6 +2036,17 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor)
1923
2036
  val = Qnil;
1924
2037
  break;
1925
2038
 
2039
+ #if (FB_API_VER >= 40)
2040
+ case SQL_INT128:
2041
+ /* Treat as 64-bit integer for now */
2042
+ if (var->sqlscale < 0) {
2043
+ val = sql_decimal_to_bigdecimal(*(ISC_INT64*)var->sqldata, var->sqlscale);
2044
+ } else {
2045
+ val = LL2NUM(*(ISC_INT64*)var->sqldata);
2046
+ }
2047
+ break;
2048
+ #endif
2049
+
1926
2050
  #if (FB_API_VER >= 30)
1927
2051
  case SQL_BOOLEAN:
1928
2052
  val = (*(bool*)var->sqldata) ? Qtrue : Qfalse;
@@ -2002,8 +2126,8 @@ static VALUE cursor_execute2(VALUE args)
2002
2126
  char isc_info_stmt[] = { isc_info_sql_stmt_type };
2003
2127
 
2004
2128
  VALUE self = rb_ary_pop(args);
2005
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2006
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
2129
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2130
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
2007
2131
 
2008
2132
  rb_sql = rb_ary_shift(args);
2009
2133
  sql = StringValuePtr(rb_sql);
@@ -2046,6 +2170,7 @@ static VALUE cursor_execute2(VALUE args)
2046
2170
  length = calculate_buffsize(fb_cursor->i_sqlda);
2047
2171
  if (length > fb_cursor->i_buffer_size) {
2048
2172
  fb_cursor->i_buffer = xrealloc(fb_cursor->i_buffer, length);
2173
+ memset(fb_cursor->i_buffer, 0, length);
2049
2174
  fb_cursor->i_buffer_size = length;
2050
2175
  }
2051
2176
  }
@@ -2065,7 +2190,7 @@ static VALUE cursor_execute2(VALUE args)
2065
2190
  fb_error_check(fb_connection->isc_status);
2066
2191
  }
2067
2192
  rows_affected = cursor_rows_affected(fb_cursor, statement);
2068
- result = INT2NUM(rows_affected);
2193
+ result = INT2NUM((int)rows_affected);
2069
2194
  } else {
2070
2195
  /* Open cursor if the SQL statement is query */
2071
2196
  /* Get the number of columns and reallocate the SQLDA */
@@ -2119,8 +2244,8 @@ static VALUE cursor_execute(int argc, VALUE* argv, VALUE self)
2119
2244
  args = rb_ary_new4(argc, argv);
2120
2245
  rb_ary_push(args, self);
2121
2246
 
2122
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2123
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
2247
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2248
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
2124
2249
  fb_connection_check(fb_connection);
2125
2250
 
2126
2251
  if (fb_cursor->open) {
@@ -2192,7 +2317,7 @@ static VALUE cursor_fetch(int argc, VALUE* argv, VALUE self)
2192
2317
 
2193
2318
  int hash_row = hash_format(argc, argv);
2194
2319
 
2195
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2320
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2196
2321
  fb_cursor_fetch_prep(fb_cursor);
2197
2322
 
2198
2323
  ary = fb_cursor_fetch(fb_cursor);
@@ -2217,7 +2342,7 @@ static VALUE cursor_fetchall(int argc, VALUE* argv, VALUE self)
2217
2342
 
2218
2343
  int hash_rows = hash_format(argc, argv);
2219
2344
 
2220
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2345
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2221
2346
  fb_cursor_fetch_prep(fb_cursor);
2222
2347
 
2223
2348
  ary = rb_ary_new();
@@ -2251,7 +2376,7 @@ static VALUE cursor_each(int argc, VALUE* argv, VALUE self)
2251
2376
 
2252
2377
  int hash_rows = hash_format(argc, argv);
2253
2378
 
2254
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2379
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2255
2380
  fb_cursor_fetch_prep(fb_cursor);
2256
2381
 
2257
2382
  for (;;) {
@@ -2277,8 +2402,8 @@ static VALUE cursor_close(VALUE self)
2277
2402
  struct FbCursor *fb_cursor;
2278
2403
  struct FbConnection *fb_connection;
2279
2404
 
2280
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2281
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
2405
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2406
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
2282
2407
  fb_cursor_check(fb_cursor);
2283
2408
 
2284
2409
  /* Close the cursor */
@@ -2312,13 +2437,13 @@ static VALUE cursor_drop(VALUE self)
2312
2437
  struct FbConnection *fb_connection;
2313
2438
  int i;
2314
2439
 
2315
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2440
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2316
2441
  fb_cursor_drop(fb_cursor);
2317
2442
  fb_cursor->fields_ary = Qnil;
2318
2443
  fb_cursor->fields_hash = Qnil;
2319
2444
 
2320
2445
  /* reset the reference from connection */
2321
- Data_Get_Struct(fb_cursor->connection, struct FbConnection, fb_connection);
2446
+ TypedData_Get_Struct(fb_cursor->connection, struct FbConnection, &fbconnection_data_type, fb_connection);
2322
2447
  for (i = 0; i < RARRAY_LEN(fb_connection->cursor); i++) {
2323
2448
  if (RARRAY_PTR(fb_connection->cursor)[i] == self) {
2324
2449
  RARRAY_PTR(fb_connection->cursor)[i] = Qnil;
@@ -2341,7 +2466,7 @@ static VALUE cursor_fields(int argc, VALUE* argv, VALUE self)
2341
2466
  {
2342
2467
  struct FbCursor *fb_cursor;
2343
2468
 
2344
- Data_Get_Struct(self, struct FbCursor, fb_cursor);
2469
+ TypedData_Get_Struct(self, struct FbCursor, &fbcursor_data_type, fb_cursor);
2345
2470
  if (argc == 0 || argv[0] == ID2SYM(rb_intern("array"))) {
2346
2471
  return fb_cursor->fields_ary;
2347
2472
  } else if (argv[0] == ID2SYM(rb_intern("hash"))) {
@@ -2427,7 +2552,7 @@ static VALUE connection_create(isc_db_handle handle, VALUE db)
2427
2552
  const char *parm;
2428
2553
  int i;
2429
2554
  struct FbConnection *fb_connection;
2430
- VALUE connection = Data_Make_Struct(rb_cFbConnection, struct FbConnection, fb_connection_mark, fb_connection_free, fb_connection);
2555
+ VALUE connection = TypedData_Make_Struct(rb_cFbConnection, struct FbConnection, &fbconnection_data_type, fb_connection);
2431
2556
  fb_connection->db = handle;
2432
2557
  fb_connection->transact = 0;
2433
2558
  fb_connection->cursor = rb_ary_new();
@@ -2459,7 +2584,7 @@ static VALUE connection_names(VALUE self, const char *sql)
2459
2584
  VALUE cursor = connection_execute(1, &query, self);
2460
2585
  VALUE names = rb_ary_new();
2461
2586
  struct FbConnection *fb_connection;
2462
- Data_Get_Struct(self, struct FbConnection, fb_connection);
2587
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
2463
2588
 
2464
2589
  while ((row = cursor_fetch(0, NULL, cursor)) != Qnil) {
2465
2590
  VALUE name = rb_ary_entry(row, 0);
@@ -2574,7 +2699,7 @@ static VALUE connection_columns(VALUE self, VALUE table_name)
2574
2699
  VALUE upcase_table_name = rb_funcall(table_name, rb_intern("upcase"), 0);
2575
2700
  VALUE query_parms[] = { query, upcase_table_name };
2576
2701
  VALUE rs = connection_query(2, query_parms, self);
2577
- Data_Get_Struct(self, struct FbConnection, fb_connection);
2702
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
2578
2703
  for (i = 0; i < RARRAY_LEN(rs); i++) {
2579
2704
  VALUE row = rb_ary_entry(rs, i);
2580
2705
  VALUE name = rb_ary_entry(row, 0);
@@ -2634,7 +2759,7 @@ static VALUE connection_index_columns(VALUE self, VALUE index_name)
2634
2759
  VALUE columns = rb_ary_new();
2635
2760
  int i;
2636
2761
  struct FbConnection *fb_connection;
2637
- Data_Get_Struct(self, struct FbConnection, fb_connection);
2762
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
2638
2763
 
2639
2764
  for (i = 0; i < RARRAY_LEN(result); i++) {
2640
2765
  VALUE row = rb_ary_entry(result, i);
@@ -2664,7 +2789,7 @@ static VALUE connection_indexes(VALUE self)
2664
2789
  VALUE indexes = rb_hash_new();
2665
2790
  int i;
2666
2791
  struct FbConnection *fb_connection;
2667
- Data_Get_Struct(self, struct FbConnection, fb_connection);
2792
+ TypedData_Get_Struct(self, struct FbConnection, &fbconnection_data_type, fb_connection);
2668
2793
 
2669
2794
  for (i = 0; i < RARRAY_LEN(ary_indexes); i++) {
2670
2795
  VALUE index_struct;
@@ -2727,9 +2852,7 @@ static VALUE default_int(VALUE hash, const char *key, int def)
2727
2852
 
2728
2853
  static VALUE database_allocate_instance(VALUE klass)
2729
2854
  {
2730
- NEWOBJ(obj, struct RObject);
2731
- OBJSETUP((VALUE)obj, klass, T_OBJECT);
2732
- return (VALUE)obj;
2855
+ return TypedData_Wrap_Struct(klass, &fbdatabase_data_type, NULL);
2733
2856
  }
2734
2857
 
2735
2858
  static VALUE hash_from_connection_string(VALUE cs)
@@ -2916,7 +3039,7 @@ static VALUE database_drop(VALUE self)
2916
3039
  struct FbConnection *fb_connection;
2917
3040
 
2918
3041
  VALUE connection = database_connect(self);
2919
- Data_Get_Struct(connection, struct FbConnection, fb_connection);
3042
+ TypedData_Get_Struct(connection, struct FbConnection, &fbconnection_data_type, fb_connection);
2920
3043
  isc_drop_database(fb_connection->isc_status, &fb_connection->db);
2921
3044
  fb_error_check(fb_connection->isc_status);
2922
3045
  /* fb_connection_remove(fb_connection); */
@@ -2941,7 +3064,8 @@ void Init_fb()
2941
3064
 
2942
3065
  rb_mFb = rb_define_module("Fb");
2943
3066
 
2944
- rb_cFbDatabase = rb_define_class_under(rb_mFb, "Database", rb_cData);
3067
+ rb_cFbDatabase = rb_define_class_under(rb_mFb, "Database", rb_cObject);
3068
+ rb_undef_alloc_func(rb_cFbDatabase);
2945
3069
  rb_define_alloc_func(rb_cFbDatabase, database_allocate_instance);
2946
3070
  rb_define_method(rb_cFbDatabase, "initialize", database_initialize, -1);
2947
3071
  rb_define_attr(rb_cFbDatabase, "database", 1, 1);
@@ -2959,7 +3083,9 @@ void Init_fb()
2959
3083
  rb_define_method(rb_cFbDatabase, "drop", database_drop, 0);
2960
3084
  rb_define_singleton_method(rb_cFbDatabase, "drop", database_s_drop, -1);
2961
3085
 
2962
- rb_cFbConnection = rb_define_class_under(rb_mFb, "Connection", rb_cData);
3086
+ rb_cFbConnection = rb_define_class_under(rb_mFb, "Connection", rb_cObject);
3087
+ rb_undef_alloc_func(rb_cFbConnection);
3088
+ rb_undef_method(CLASS_OF(rb_cFbConnection), "new");
2963
3089
  rb_define_attr(rb_cFbConnection, "database", 1, 1);
2964
3090
  rb_define_attr(rb_cFbConnection, "username", 1, 1);
2965
3091
  rb_define_attr(rb_cFbConnection, "password", 1, 1);
@@ -2989,7 +3115,9 @@ void Init_fb()
2989
3115
  rb_define_method(rb_cFbConnection, "columns", connection_columns, 1);
2990
3116
  /* rb_define_method(rb_cFbConnection, "cursor", connection_cursor, 0); */
2991
3117
 
2992
- rb_cFbCursor = rb_define_class_under(rb_mFb, "Cursor", rb_cData);
3118
+ rb_cFbCursor = rb_define_class_under(rb_mFb, "Cursor", rb_cObject);
3119
+ rb_undef_alloc_func(rb_cFbCursor);
3120
+ rb_undef_method(CLASS_OF(rb_cFbCursor), "new");
2993
3121
  /* rb_define_method(rb_cFbCursor, "execute", cursor_execute, -1); */
2994
3122
  rb_define_method(rb_cFbCursor, "fields", cursor_fields, -1);
2995
3123
  rb_define_method(rb_cFbCursor, "fetch", cursor_fetch, -1);
@@ -2998,7 +3126,9 @@ void Init_fb()
2998
3126
  rb_define_method(rb_cFbCursor, "close", cursor_close, 0);
2999
3127
  rb_define_method(rb_cFbCursor, "drop", cursor_drop, 0);
3000
3128
 
3001
- rb_cFbSqlType = rb_define_class_under(rb_mFb, "SqlType", rb_cData);
3129
+ rb_cFbSqlType = rb_define_class_under(rb_mFb, "SqlType", rb_cObject);
3130
+ rb_undef_alloc_func(rb_cFbSqlType);
3131
+ rb_undef_method(CLASS_OF(rb_cFbSqlType), "new");
3002
3132
  rb_define_singleton_method(rb_cFbSqlType, "from_code", sql_type_from_code, 2);
3003
3133
 
3004
3134
  rb_eFbError = rb_define_class_under(rb_mFb, "Error", rb_eStandardError);
@@ -2,7 +2,7 @@ require 'test/FbTestCases'
2
2
 
3
3
  class ConnectionTestCases < FbTestCase
4
4
  include FbTestCases
5
-
5
+
6
6
  def test_execute
7
7
  sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
8
8
  sql_select = "SELECT * FROM RDB$DATABASE"
@@ -16,50 +16,38 @@ class ConnectionTestCases < FbTestCase
16
16
  connection.drop
17
17
  end
18
18
  end
19
-
19
+
20
20
  def test_query_select
21
21
  sql_select = "SELECT * FROM RDB$DATABASE"
22
22
  Database.create(@parms) do |connection|
23
-
24
23
  d = connection.query(sql_select)
25
24
  assert_instance_of Array, d
26
25
  assert_equal 1, d.size
27
26
  assert_instance_of Array, d.first
28
- if @fb_version == 3
29
- assert_equal 5, d.first.size
30
- else
31
- assert_equal 4, d.first.size
32
- end
33
-
27
+
28
+ assert_equal expected_columns, d.first.size
29
+
34
30
  a = connection.query(:array, sql_select)
35
31
  assert_instance_of Array, a
36
32
  assert_equal 1, a.size
37
33
  assert_instance_of Array, a.first
38
- if @fb_version == 3
39
- assert_equal 5, a.first.size
40
- else
41
- assert_equal 4, a.first.size
42
- end
34
+ assert_equal expected_columns, a.first.size
43
35
 
44
36
  h = connection.query(:hash, sql_select)
45
37
  assert_instance_of Array, h
46
38
  assert_equal 1, h.size
47
39
  assert_instance_of Hash, h.first
48
- if @fb_version == 3
49
- assert_equal 5, h.first.keys.size
50
- else
51
- assert_equal 4, h.first.keys.size
52
- end
40
+
41
+ assert_equal expected_columns, h.first.keys.size
42
+
53
43
  assert h.first.keys.include?("RDB$DESCRIPTION")
54
44
  assert h.first.keys.include?("RDB$RELATION_ID")
55
45
  assert h.first.keys.include?("RDB$SECURITY_CLASS")
56
46
  assert h.first.keys.include?("RDB$CHARACTER_SET_NAME")
57
- if @fb_version == 3
58
- assert h.first.keys.include?("RDB$LINGER")
59
- end
47
+ assert h.first.keys.include?("RDB$LINGER") if @fb_version >= 3
60
48
  end
61
49
  end
62
-
50
+
63
51
  def test_query_update
64
52
  sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))"
65
53
  sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)"
@@ -69,22 +57,22 @@ class ConnectionTestCases < FbTestCase
69
57
  Database.create(@parms) do |connection|
70
58
  su = connection.query(sql_schema)
71
59
  assert_equal -1, su
72
-
60
+
73
61
  i = connection.query(sql_insert, 1, "NAME")
74
62
  assert_equal 1, i
75
-
63
+
76
64
  u = connection.query(sql_update, 1, "NAME2", 1)
77
65
  assert_equal 1, u
78
-
66
+
79
67
  d = connection.query(sql_delete, 1)
80
68
  assert_equal 1, d
81
-
69
+
82
70
  q = connection.query(sql_select)
83
71
  assert_instance_of Array, q
84
72
  assert_equal 0, q.size
85
73
  end
86
74
  end
87
-
75
+
88
76
  def test_insert_blobs_text
89
77
  sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20), MEMO BLOB SUB_TYPE TEXT)"
90
78
  sql_insert = "INSERT INTO TEST (ID, NAME, MEMO) VALUES (?, ?, ?)"
@@ -193,7 +181,7 @@ class ConnectionTestCases < FbTestCase
193
181
  connection.drop
194
182
  end
195
183
  end
196
-
184
+
197
185
  def test_open?
198
186
  db = Database.create(@parms);
199
187
  connection = db.connect
@@ -202,7 +190,7 @@ class ConnectionTestCases < FbTestCase
202
190
  assert !connection.open?
203
191
  db.drop
204
192
  end
205
-
193
+
206
194
  def test_properties_instance
207
195
  db = Database.new(@parms)
208
196
  db.create
@@ -215,7 +203,7 @@ class ConnectionTestCases < FbTestCase
215
203
  connection.drop
216
204
  end
217
205
  end
218
-
206
+
219
207
  def test_properties_singleton
220
208
  Database.create(@parms) do |connection|
221
209
  assert_equal @parms[:database], connection.database
@@ -226,25 +214,25 @@ class ConnectionTestCases < FbTestCase
226
214
  connection.drop
227
215
  end
228
216
  end
229
-
217
+
230
218
  def test_drop_instance
231
219
  db = Database.create(@parms)
232
- assert File.exists?(@db_file)
220
+ assert File.exist?(@db_file)
233
221
  connection = db.connect
234
- assert connection.open?
222
+ assert connection.open?
235
223
  connection.drop
236
224
  assert !connection.open?
237
- assert !File.exists?(@db_file)
225
+ assert !File.exist?(@db_file)
238
226
  end
239
-
227
+
240
228
  def test_drop_singleton
241
229
  Database.create(@parms) do |connection|
242
- assert File.exists?(@db_file)
230
+ assert File.exist?(@db_file)
243
231
  connection.drop
244
- assert !File.exists?(@db_file)
232
+ assert !File.exist?(@db_file)
245
233
  end
246
234
  end
247
-
235
+
248
236
  def test_to_s
249
237
  db = Database.new(@parms)
250
238
  db.create
@@ -256,7 +244,7 @@ class ConnectionTestCases < FbTestCase
256
244
  assert_equal "#{@parms[:database]} (CLOSED)", connection.to_s
257
245
  end
258
246
  end
259
-
247
+
260
248
  def test_table_names
261
249
  sql_schema = <<-END
262
250
  CREATE TABLE TEST1 (ID INT);
@@ -351,7 +339,7 @@ class ConnectionTestCases < FbTestCase
351
339
  assert_equal 'WRITER', names[1]
352
340
  end
353
341
  end
354
-
342
+
355
343
  def test_role_names_downcased
356
344
  sql_schema = <<-END
357
345
  create role reader;
@@ -364,7 +352,7 @@ class ConnectionTestCases < FbTestCase
364
352
  assert_equal 'writer', names[1]
365
353
  end
366
354
  end
367
-
355
+
368
356
  def test_procedure_names
369
357
  sql_schema = <<-END_SQL
370
358
  CREATE PROCEDURE PLUSONE(NUM1 INTEGER) RETURNS (NUM2 INTEGER) AS
@@ -376,7 +364,7 @@ class ConnectionTestCases < FbTestCase
376
364
  Database.create(@parms) do |connection|
377
365
  connection.execute(sql_schema)
378
366
  names = connection.procedure_names
379
- assert_equal 'PLUSONE', names[0]
367
+ assert names.include?('PLUSONE'), "PLUSONE procedure not found in: #{names.inspect}"
380
368
  end
381
369
  end
382
370
 
@@ -391,10 +379,10 @@ class ConnectionTestCases < FbTestCase
391
379
  Database.create(@parms.merge(:downcase_names => true)) do |connection|
392
380
  connection.execute(sql_schema)
393
381
  names = connection.procedure_names
394
- assert_equal 'plusone', names[0]
382
+ assert names.include?('plusone'), "plusone procedure not found in: #{names.inspect}"
395
383
  end
396
384
  end
397
-
385
+
398
386
  def test_trigger_names
399
387
  table_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20)); CREATE GENERATOR TEST_SEQ;"
400
388
  trigger_schema = <<-END_SQL
@@ -448,16 +436,16 @@ class ConnectionTestCases < FbTestCase
448
436
  assert indexes.keys.include?('FK_DETAIL_MASTER_ID')
449
437
  assert indexes.keys.include?('IX_MASTER_NAME1')
450
438
  assert indexes.keys.include?('IX_DETAIL_ID_DESC')
451
-
439
+
452
440
  assert indexes['PK_MASTER'].columns.include?('ID')
453
441
  assert indexes['PK_DETAIL'].columns.include?('ID')
454
442
 
455
443
  master_indexes = indexes.values.select {|ix| ix.table_name == 'MASTER' }
456
444
  assert_equal 2, master_indexes.size
457
-
445
+
458
446
  detail_indexes = indexes.values.select {|ix| ix.table_name == 'DETAIL' }
459
447
  assert_equal 3, detail_indexes.size
460
-
448
+
461
449
  assert_equal 'MASTER', indexes['PK_MASTER'].table_name
462
450
  assert indexes['PK_MASTER'].unique
463
451
  assert !indexes['PK_MASTER'].descending
@@ -465,7 +453,7 @@ class ConnectionTestCases < FbTestCase
465
453
  assert_equal 'MASTER', indexes['IX_MASTER_NAME1'].table_name
466
454
  assert indexes['IX_MASTER_NAME1'].unique
467
455
  assert !indexes['IX_MASTER_NAME1'].descending
468
-
456
+
469
457
  assert_equal 'DETAIL', indexes['PK_DETAIL'].table_name
470
458
  assert indexes['PK_DETAIL'].unique
471
459
  assert !indexes['PK_DETAIL'].descending
@@ -476,8 +464,8 @@ class ConnectionTestCases < FbTestCase
476
464
 
477
465
  assert_equal 'DETAIL', indexes['IX_DETAIL_ID_DESC'].table_name
478
466
  assert !indexes['IX_DETAIL_ID_DESC'].unique
479
- assert indexes['IX_DETAIL_ID_DESC'].descending
480
-
467
+ assert indexes['IX_DETAIL_ID_DESC'].descending
468
+
481
469
  connection.drop
482
470
  end
483
471
  end
@@ -514,7 +502,7 @@ class ConnectionTestCases < FbTestCase
514
502
  I INTEGER,
515
503
  SI SMALLINT,
516
504
  BI BIGINT,
517
- F FLOAT,
505
+ F FLOAT,
518
506
  D DOUBLE PRECISION,
519
507
  C CHAR,
520
508
  C10 CHAR(10),
@@ -552,5 +540,5 @@ class ConnectionTestCases < FbTestCase
552
540
  assert_equal column, columns[i]
553
541
  end
554
542
  end
555
- end
543
+ end
556
544
  end
@@ -9,11 +9,7 @@ class CursorTestCases < FbTestCase
9
9
  assert_instance_of Cursor, cursor
10
10
  row = cursor.fetch :array
11
11
  assert_instance_of Array, row
12
- if @fb_version == 3
13
- assert_equal 5, row.size
14
- else
15
- assert_equal 4, row.size
16
- end
12
+ assert_equal expected_columns, row.size
17
13
  end
18
14
  connection.execute("select * from rdb$database where rdb$description = 'bogus'") do |cursor|
19
15
  assert_instance_of Cursor, cursor
@@ -31,11 +27,7 @@ class CursorTestCases < FbTestCase
31
27
  assert_instance_of Cursor, cursor
32
28
  row = cursor.fetch :hash
33
29
  assert_instance_of Hash, row
34
- if @fb_version == 3
35
- assert_equal 5, row.size
36
- else
37
- assert_equal 4, row.size
38
- end
30
+ assert_equal expected_columns, row.size
39
31
  end
40
32
  connection.execute("select * from rdb$database where rdb$description = 'bogus'") do |cursor|
41
33
  assert_instance_of Cursor, cursor
@@ -55,11 +47,7 @@ class CursorTestCases < FbTestCase
55
47
  assert_instance_of Array, rows
56
48
  assert_equal 1, rows.size
57
49
  assert_instance_of Array, rows[0]
58
- if @fb_version == 3
59
- assert_equal 5, rows[0].size
60
- else
61
- assert_equal 4, rows[0].size
62
- end
50
+ assert_equal expected_columns, rows[0].size
63
51
  end
64
52
  connection.drop
65
53
  end
@@ -73,11 +61,7 @@ class CursorTestCases < FbTestCase
73
61
  assert_instance_of Array, rows
74
62
  assert_equal 1, rows.size
75
63
  assert_instance_of Hash, rows[0]
76
- if @fb_version == 3
77
- assert_equal 5, rows[0].size
78
- else
79
- assert_equal 4, rows[0].size
80
- end
64
+ assert_equal expected_columns, rows[0].size
81
65
  end
82
66
  connection.drop
83
67
  end
@@ -89,18 +73,12 @@ class CursorTestCases < FbTestCase
89
73
  fields = cursor.fields
90
74
  fields_ary = cursor.fields :array
91
75
  assert_equal fields, fields_ary
92
- if @fb_version == 3
93
- assert_equal 5, fields.size
94
- else
95
- assert_equal 4, fields.size
96
- end
76
+ assert_equal expected_columns, fields.size
97
77
  assert_equal "RDB$DESCRIPTION", fields[0].name;
98
78
  assert_equal "RDB$RELATION_ID", fields[1].name;
99
79
  assert_equal "RDB$SECURITY_CLASS", fields[2].name;
100
80
  assert_equal "RDB$CHARACTER_SET_NAME", fields[3].name;
101
- if @fb_version == 3
102
- assert_equal "RDB$LINGER", fields[4].name;
103
- end
81
+ assert_equal "RDB$LINGER", fields[4].name if @fb_version >= 3
104
82
  end
105
83
  connection.drop
106
84
  end
@@ -112,18 +90,12 @@ class CursorTestCases < FbTestCase
112
90
  fields = cursor.fields
113
91
  fields_ary = cursor.fields :array
114
92
  assert_equal fields, fields_ary
115
- if @fb_version == 3
116
- assert_equal 5, fields.size
117
- else
118
- assert_equal 4, fields.size
119
- end
93
+ assert_equal expected_columns, fields.size
120
94
  assert_equal "rdb$description", fields[0].name;
121
95
  assert_equal "rdb$relation_id", fields[1].name;
122
96
  assert_equal "rdb$security_class", fields[2].name;
123
97
  assert_equal "rdb$character_set_name", fields[3].name;
124
- if @fb_version == 3
125
- assert_equal "rdb$linger", fields[4].name;
126
- end
98
+ assert_equal "rdb$linger", fields[4].name if @fb_version >= 3
127
99
  end
128
100
  connection.drop
129
101
  end
@@ -133,18 +105,12 @@ class CursorTestCases < FbTestCase
133
105
  Database.create(@parms) do |connection|
134
106
  connection.execute("select * from rdb$database") do |cursor|
135
107
  fields = cursor.fields :hash
136
- if @fb_version == 3
137
- assert_equal 5, fields.size
138
- else
139
- assert_equal 4, fields.size
140
- end
108
+ assert_equal expected_columns, fields.size
141
109
  assert_equal 520, fields["RDB$DESCRIPTION"].type_code
142
110
  assert_equal 500, fields["RDB$RELATION_ID"].type_code
143
111
  assert_equal 452, fields["RDB$SECURITY_CLASS"].type_code
144
112
  assert_equal 452, fields["RDB$CHARACTER_SET_NAME"].type_code
145
- if @fb_version == 3
146
- assert_equal 496, fields["RDB$LINGER"].type_code
147
- end
113
+ assert_equal 496, fields["RDB$LINGER"].type_code if @fb_version >= 3
148
114
  end
149
115
  connection.drop
150
116
  end
@@ -154,18 +120,12 @@ class CursorTestCases < FbTestCase
154
120
  Database.create(@parms.merge(:downcase_names => true)) do |connection| # xxx true
155
121
  connection.execute("select * from rdb$database") do |cursor|
156
122
  fields = cursor.fields :hash
157
- if @fb_version == 3
158
- assert_equal 5, fields.size
159
- else
160
- assert_equal 4, fields.size
161
- end
123
+ assert_equal expected_columns, fields.size
162
124
  assert_equal 520, fields["rdb$description"].type_code
163
125
  assert_equal 500, fields["rdb$relation_id"].type_code
164
126
  assert_equal 452, fields["rdb$security_class"].type_code
165
127
  assert_equal 452, fields["rdb$character_set_name"].type_code
166
- if @fb_version == 3
167
- assert_equal 496, fields["rdb$linger"].type_code
168
- end
128
+ assert_equal 496, fields["rdb$linger"].type_code if @fb_version >= 3
169
129
  end
170
130
  connection.drop
171
131
  end
@@ -178,11 +138,7 @@ class CursorTestCases < FbTestCase
178
138
  cursor.each :array do |row|
179
139
  count += 1
180
140
  assert_instance_of Array, row
181
- if @fb_version == 3
182
- assert_equal 5, row.size
183
- else
184
- assert_equal 4, row.size
185
- end
141
+ assert_equal expected_columns, row.size
186
142
  end
187
143
  assert_equal 1, count
188
144
  end
@@ -197,11 +153,7 @@ class CursorTestCases < FbTestCase
197
153
  cursor.each :hash do |row|
198
154
  count += 1
199
155
  assert_instance_of Hash, row
200
- if @fb_version == 3
201
- assert_equal 5, row.size
202
- else
203
- assert_equal 4, row.size
204
- end
156
+ assert_equal expected_columns, row.size
205
157
  end
206
158
  assert_equal 1, count
207
159
  end
@@ -98,7 +98,7 @@ class DataTypesTestCases < FbTestCase
98
98
  I INTEGER,
99
99
  SI SMALLINT,
100
100
  BI BIGINT,
101
- F FLOAT,
101
+ F FLOAT,
102
102
  D DOUBLE PRECISION,
103
103
  C CHAR,
104
104
  C10 CHAR(10),
@@ -337,11 +337,25 @@ class DataTypesTestCases < FbTestCase
337
337
  connection.execute(sql_insert, Time.now)
338
338
  end
339
339
  elsif cols[i] == 'DT'
340
- assert_raises ArgumentError do
341
- connection.execute(sql_insert, Date)
340
+ # Ruby 3.0.3+ raises Date::Error instead of ArgumentError for Date class
341
+ if RUBY_VERSION >= "3.0"
342
+ assert_raises Date::Error do
343
+ connection.execute(sql_insert, Date)
344
+ end
345
+ else
346
+ assert_raises ArgumentError do
347
+ connection.execute(sql_insert, Date)
348
+ end
342
349
  end
343
- assert_raises ArgumentError do
344
- connection.execute(sql_insert, 2006)
350
+ # Ruby 3.0.3+ raises Date::Error instead of ArgumentError for integer
351
+ if RUBY_VERSION >= "3.0"
352
+ assert_raises Date::Error do
353
+ connection.execute(sql_insert, 2006)
354
+ end
355
+ else
356
+ assert_raises ArgumentError do
357
+ connection.execute(sql_insert, 2006)
358
+ end
345
359
  end
346
360
  elsif cols[i] == 'TM'
347
361
  assert_raises TypeError do
@@ -502,7 +516,9 @@ class DataTypesTestCases < FbTestCase
502
516
  connection.execute(sql_insert, -91520.65)
503
517
  vals = connection.query(sql_select)
504
518
  assert vals[0][0].is_a?(BigDecimal), "Numeric(15,4) must return BigDecimal"
505
- assert Float(91520.65) != vals[0][0]
519
+ # In Ruby 3.2+, BigDecimal and Float comparisons may be equal due to improved precision
520
+ # So we check that the types are different instead of the values
521
+ assert vals[0][0].class != Float(91520.65).class, "BigDecimal and Float should be different types"
506
522
  assert_equal BigDecimal('91520.65'), vals[0][0]
507
523
  assert_equal BigDecimal('91520.65'), vals[1][0]
508
524
  assert_equal BigDecimal('-91520.65'), vals[2][0]
@@ -69,7 +69,7 @@ class DatabaseTestCases < FbTestCase
69
69
  def test_create_instance
70
70
  db = Database.new(@parms)
71
71
  db.create
72
- assert File.exists?(@db_file)
72
+ assert File.exist?(@db_file)
73
73
  end
74
74
 
75
75
  def test_create_instance_block
@@ -82,17 +82,17 @@ class DatabaseTestCases < FbTestCase
82
82
  assert_equal 3, connection.dialect
83
83
  assert_equal 3, connection.db_dialect
84
84
  end
85
- assert File.exists?(@db_file)
85
+ assert File.exist?(@db_file)
86
86
  end
87
87
 
88
88
  def test_create_singleton
89
89
  db = Database.create(@parms);
90
- assert File.exists?(@db_file)
90
+ assert File.exist?(@db_file)
91
91
  end
92
92
 
93
93
  def test_create_singleton_with_defaults
94
94
  db = Database.create(:database => "localhost:#{@db_file}");
95
- assert File.exists?(@db_file)
95
+ assert File.exist?(@db_file)
96
96
  end
97
97
 
98
98
  def test_create_singleton_block
@@ -103,7 +103,7 @@ class DatabaseTestCases < FbTestCase
103
103
  end
104
104
  end
105
105
  assert_instance_of Database, db
106
- assert File.exists?(@db_file)
106
+ assert File.exist?(@db_file)
107
107
  end
108
108
 
109
109
  def test_create_bad_param
@@ -133,19 +133,19 @@ class DatabaseTestCases < FbTestCase
133
133
  end
134
134
 
135
135
  def test_drop_instance
136
- assert !File.exists?(@db_file)
136
+ assert !File.exist?(@db_file)
137
137
  db = Database.create(@parms)
138
- assert File.exists?(@db_file)
138
+ assert File.exist?(@db_file)
139
139
  db.drop
140
- assert !File.exists?(@db_file)
140
+ assert !File.exist?(@db_file)
141
141
  end
142
142
 
143
143
  def test_drop_singleton
144
- assert !File.exists?(@db_file)
144
+ assert !File.exist?(@db_file)
145
145
  Database.create(@parms)
146
- assert File.exists?(@db_file)
146
+ assert File.exist?(@db_file)
147
147
  Database.drop(@parms)
148
- assert !File.exists?(@db_file)
148
+ assert !File.exist?(@db_file)
149
149
  end
150
150
 
151
151
  def test_role_support
data/test/FbTestCases.rb CHANGED
@@ -44,17 +44,24 @@ module FbTestCases
44
44
  rm_rf @db_file
45
45
 
46
46
  Database.create(@parms) do |connection|
47
-
48
47
  d = connection.query("SELECT substring(rdb$get_context('SYSTEM', 'ENGINE_VERSION') from 1 for 1) from rdb$database")
49
-
50
48
  @fb_version = Integer(d.first[0])
51
-
52
49
  connection.drop
53
50
  end
54
51
 
55
52
  rm_rf @db_file
56
53
  end
57
54
 
55
+ def expected_columns
56
+ case @fb_version
57
+ when 5, 4
58
+ 6
59
+ when 3
60
+ 5
61
+ else
62
+ 4
63
+ end
64
+ end
58
65
  end
59
66
 
60
67
  class Fb::Connection
data/test/FbTestSuite.rb CHANGED
@@ -10,3 +10,4 @@ require 'TransactionTestCases'
10
10
  if RUBY_VERSION =~ /^1.9/
11
11
  require 'EncodingTestCases'
12
12
  end
13
+ require 'bigdecimal'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brent Rowland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-08 00:00:00.000000000 Z
11
+ date: 2025-09-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby Firebird Extension Library
14
14
  email: rowland@rowlandresearch.com
@@ -57,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
57
  version: '0'
58
58
  requirements:
59
59
  - Firebird client library fbclient.dll, libfbclient.so or Firebird.framework.
60
- rubygems_version: 3.0.3
60
+ rubygems_version: 3.1.6
61
61
  signing_key:
62
62
  specification_version: 4
63
63
  summary: Firebird database driver