Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

My fork is ready #376

Merged
merged 15 commits into from Sep 14, 2011
Merged

My fork is ready #376

merged 15 commits into from Sep 14, 2011

Conversation

roylez
Copy link
Contributor

@roylez roylez commented Aug 27, 2011

Please review my code and make any change if you want to. I can pull back and do spec testing here. Thanks.

@jeremyevans
Copy link
Owner

Looks pretty good, here are my notes:

  • You generally shouldn't monkey patch a driver's connection class. Instead, create a subclass of it and modify that. So the connection class should be something like "class Sequel::IBMDB::Connection < IBM_DB::Connection".

  • I don't think Connection should have a :stmt accessor, unless it is impossible for a connection to create more than one simultaneously. I can see why you are doing it, but it should be refactored to not require it. You should be returning a stmt object if necessary and passing the stmt object to the the appropriate accessors (or adding methods to the appropriate stmt class, such as #rows_affected, #field_type, #num_fields, #field_name). Yielding the stmt object (or both the connection object and stmt objects) to the execute block that is called in fetch_rows is fine from an API perspective.

  • You should probably have the connection's @prepared_statements hash store a two element array of [sql, stmt], instead of using two separate hashes.

  • Connection#bind doesn't appear to be called, unless it get's called internally, in which case I'm not sure how it works.

  • You shouldn't need to override Database#test_connection.

  • You may want to DRY up some duplicate code in execute_dui and execute by refactoring _execute.

  • Database#tables and #views don't appear to respect the identifier_output_method.

  • Defining set_columns inside every call to fetch_rows is a bad idea. You should just move it to inside the execute block, as it should be executed every time. You should use a local variable for @column_info.

  • You set supports_prepared_transactions to true. That's probably a mistake as I don't see code supporting it. prepared_transactions is unrelated to prepared_statements, it's a way to implement two-phase commit.

  • You can use Sequel::SQLTime for the :time part in Dataset#convert_type.

  • The adapter specs you added mostly just repeat other tests in the integration tests. In general, adapter tests should only be for adapter/database specific behavior. Generic database behavior such as updating/deleting/inserting correctly should be handled by the integration tests. I would delete your current adapter spec and just run the integration tests:

    SEQUEL_INTEGRATION_URL=$IBMDB_URL rake spec_integration

    Any errors in the integration tests should be fixed if possible, or have guards added if not possible using cspecify.

I know this seems like a lot, but please don't get discouraged. You've done a great job so far, most of the above suggestions are just intended to polish it up. Hopefully we can get it committed early next week, so it can ship in 3.27.0 on Thursday.

Jeremy

@roylez
Copy link
Contributor Author

roylez commented Aug 27, 2011

Thanks a lot for your careful review of my code.

I am trying to refactor Connection and possible a new Statement class. Because IBM_DB does not provide initialize functions for the Connection and Statement so I cannot simply subclass them.

I tried the integration test, the number of "F" almost scared me. I will catch up and update as soon as I can.

@roylez
Copy link
Contributor Author

roylez commented Sep 10, 2011

association_test.rb

Causes of failure:

  1. DB2 does not support "WHERE 1"

  2. DB2 does not support array sql "(A,B) in (C,D)"

    Pending:
    Sequel::Model Simple Associations it should behave like regular and composite key associations should work correctly when filtering by multiple associations
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Simple Associations it should behave like regular and composite key associations should work correctly when excluding by multiple associations
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Simple Associations it should behave like regular and composite key associations should work correctly when excluding by associations in regards to NULL values
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Simple Associations it should behave like regular and composite key associations should eager load via eager correctly
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Simple Associations it should behave like regular and composite key associations should work with a many_through_many association
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Composite Key Associations it should behave like regular and composite key associations should work correctly when filtering by multiple associations
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Composite Key Associations it should behave like regular and composite key associations should work correctly when excluding by multiple associations
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Composite Key Associations it should behave like regular and composite key associations should work correctly when excluding by associations in regards to NULL values
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Composite Key Associations it should behave like regular and composite key associations should eager load via eager correctly
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Model Composite Key Associations it should behave like regular and composite key associations should work with a many_through_many association
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76

    Finished in 14.38 seconds
    43 examples, 0 failures, 10 pending

database_test.rb

Cause of Failure: Raw SQL "SELECT 1" is not valid for DB2.
Modified test added as adapter test case.

Pending:
  Sequel::Database should provide disconnect functionality after preparing a connection
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76

Finished in 0.06443 seconds
5 examples, 0 failures, 1 pending

dataset_test.rb

Causes of Failure:

  1. Mannually specifying AUTOINCREMENT primary key(GENERATED ALWAYS AS IDENTITY) is not allowed. Modifed version added as adapter test.

  2. DB2 does not allow "OFFSET". At least for versions lower than 9.7, or not setup with MySQL compatibility.

  3. DB2 does not support "WHERE 1".

  4. DB2's CTE implemention limits usage of recursive WITH or other features.

  5. DB2 does not support array sql "(A,B) in (C,D)"

  6. DB2 uses a different format for extracting parts year/month/day parts from a time stamp.

  7. Bitwise operations undefined for DB2 lower than 9.5 . These cases should work for DB2 9.5 and above.

    Pending:
    Simple Dataset operations should insert with a primary key specified
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76
    Simple Dataset operations should fetch correctly with a limit and offset
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Simple Dataset operations should fetch correctly with a limit and offset without an order
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Simple Dataset operations should handle true/false properly
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Simple Dataset operations in transactions should insert correctly with a primary key specified inside a transaction
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76
    Common Table Expressions should give correct results for recursive WITH
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76
    Common Table Expressions should support joining a dataset with a CTE
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76
    Window Functions should give correct results for aggregate window functions with frames
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Sequel::Dataset DSL support should work with multiple value arrays
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76
    SQL Extract Function should return the part of the datetime asked for
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76

    Failures:

    1. Sequel::Dataset DSL support should work with bitwise AND and OR operators
      Failure/Error: @ds.get{a.sql_number | b}.to_i.should == 7
      Sequel::DatabaseError:
      RuntimeError: [IBM][CLI Driver][DB2/LINUX] SQL0440N No authorized routine named "BITOR" of type "FUNCTION" having compatible arguments was found. SQLSTATE=42884 SQLCODE=-440

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:253:in `_execute'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in`execute'

      ./spec/integration/../../lib/sequel/connection_pool/threaded.rb:84:in `hold'

      ./spec/integration/../../lib/sequel/database/connecting.rb:226:in`synchronize'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in `execute'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:544:in`execute'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:310:in `fetch_rows'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:123:in`each'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:452:in `single_record'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:460:in`single_value'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:202:in `get'

      ./spec/integration/../../lib/sequel/adapters/shared/db2.rb:152:in`get'

      ./spec/integration/dataset_test.rb:702

    2. Sequel::Dataset DSL support should work with the bitwise compliment operator
      Failure/Error: Unable to find matching line from backtrace
      Sequel::DatabaseError:
      RuntimeError: [IBM][CLI Driver][DB2/LINUX] SQL0007N The character "~" following "SELECT " is not valid. SQLSTATE=42601 SQLCODE=-7

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:253:in `_execute'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in`execute'

      ./spec/integration/../../lib/sequel/connection_pool/threaded.rb:84:in `hold'

      ./spec/integration/../../lib/sequel/database/connecting.rb:226:in`synchronize'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in `execute'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:544:in`execute'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:310:in `fetch_rows'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:123:in`each'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:452:in `single_record'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:460:in`single_value'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:202:in `get'

      ./spec/integration/../../lib/sequel/adapters/shared/db2.rb:152:in`get'

      ./spec/integration/dataset_test.rb:708

    3. Sequel::Dataset DSL support should work with the bitwise xor operator
      Failure/Error: Unable to find matching line from backtrace
      Sequel::DatabaseError:
      RuntimeError: [IBM][CLI Driver][DB2/LINUX] SQL0440N No authorized routine named "BITXOR" of type "FUNCTION" having compatible arguments was found. SQLSTATE=42884 SQLCODE=-440

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:253:in `_execute'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in`execute'

      ./spec/integration/../../lib/sequel/connection_pool/threaded.rb:84:in `hold'

      ./spec/integration/../../lib/sequel/database/connecting.rb:226:in`synchronize'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in `execute'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:544:in`execute'

      ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:310:in `fetch_rows'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:123:in`each'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:452:in `single_record'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:460:in`single_value'

      ./spec/integration/../../lib/sequel/dataset/actions.rb:202:in `get'

      ./spec/integration/../../lib/sequel/adapters/shared/db2.rb:152:in`get'

      ./spec/integration/dataset_test.rb:714

    Finished in 5.43 seconds
    94 examples, 3 failures, 10 pending

    Failed examples:

    rspec ./spec/integration/dataset_test.rb:700 # Sequel::Dataset DSL support should work with bitwise AND and OR operators
    rspec ./spec/integration/spec_helper.rb:78 # Sequel::Dataset DSL support should work with the bitwise compliment operator
    rspec ./spec/integration/spec_helper.rb:78 # Sequel::Dataset DSL support should work with the bitwise xor operator

eager_loader_test.rb

Full Coverage

Finished in 5.94 seconds
26 examples, 0 failures

migrator_test.rb

Cause of Failure: Renaming of columns are for newer versions, probably 9.7 and above. Renaming columns may work with db2 9.7 or newer.

Finished in 3.29 seconds
15 examples, 1 failure

Failed examples:

rspec ./spec/integration/migrator_test.rb:189 # Sequel::Migrator should handle reversible migrations

model_test.rb

Full Coverage

Finished in 1.28 seconds
12 examples, 0 failures

plugin_test.rb

class_table_inheritance.rb and rcte_tree.rb are not supported.

Finished in 10.83 seconds
65 examples, 0 failures

prepared_statements_test.rb

Causes of Failure:

  1. DB2 cannot do OFFSET

  2. BLOB cannot be used in where clause (needs further investigation)

    Pending:
    Prepared Statements and Bound Arguments should support using a bound variable for a limit and offset
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76
    Prepared Statements and Bound Arguments should support using a prepared_statement for a limit and offset
    # Not yet working on db2
    # ./spec/integration/spec_helper.rb:76

    Finished in 3.23 seconds
    40 examples, 1 failure, 2 pending

    Failed examples:

    rspec ./spec/integration/spec_helper.rb:78 # Bound Argument Types should handle blob type

schema_test.rb

Causes of Failure:

  1. Newer version of DB2 is needed to do column renaming.

  2. Setting column type needs DB2 9.7 and newer.

  3. Adding primary key column (add_primary_key_column) involves two steps: add primary column, and then set the column to be auto incremental.

  4. Adding foreign key constraints needs the column to be not null first.

    Pending:
    Database schema modifiers should add primary key columns to tables correctly
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76
    Database schema modifiers should add unique constraints and foreign key table constraints correctly
    # Not yet working on ibmdb
    # ./spec/integration/spec_helper.rb:76

    Finished in 2.95 seconds
    31 examples, 4 failures, 2 pending

    Failed examples:

    rspec ./spec/integration/schema_test.rb:269 # Database schema modifiers should rename columns correctly
    rspec ./spec/integration/schema_test.rb:278 # Database schema modifiers should rename columns with defaults correctly
    rspec ./spec/integration/schema_test.rb:288 # Database schema modifiers should rename columns with not null constraints
    rspec ./spec/integration/schema_test.rb:321 # Database schema modifiers should set column types correctly

timezone_test.rb

DB2 only supports using UTC for database.

Finished in 0.36683 seconds
4 examples, 0 failures

transaction_test.rb

Full Coverage

Finished in 0.36103 seconds
7 examples, 0 failures

type_test.rb

Full Coverage. However, ibm_db has some problem dropping tables after some blob related operations, even after disconnecting and reconnect. If dropping the table manually in db2cli, then boolean type test can be passed by running rspec specifying only this test case.

Failures:

  1) Supported types should support generic boolean type
     Failure/Error: Unable to find matching line from backtrace
     Sequel::DatabaseError:
       RuntimeError: [IBM][CLI Driver][DB2/LINUX] SQL0950N  The table or index cannot be dropped because it is currently in use.  SQLSTATE=55006 SQLCODE=-950
     # ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:253:in `_execute'
     # ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in `execute'
     # ./spec/integration/../../lib/sequel/connection_pool/threaded.rb:84:in `hold'
     # ./spec/integration/../../lib/sequel/database/connecting.rb:226:in `synchronize'
     # ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:155:in `execute'
     # ./spec/integration/../../lib/sequel/adapters/ibmdb.rb:162:in `execute_dui'
     # ./spec/integration/../../lib/sequel/database/query.rb:64:in `execute_ddl'
     # ./spec/integration/../../lib/sequel/database/schema_methods.rb:173:in `drop_table'
     # ./spec/integration/../../lib/sequel/database/schema_methods.rb:172:in `each'
     # ./spec/integration/../../lib/sequel/database/schema_methods.rb:172:in `drop_table'
     # ./spec/integration/../../lib/sequel/database/schema_methods.rb:109:in `create_table!'
     # ./spec/integration/type_test.rb:5:in `create_items_table_with_column'
     # ./spec/integration/type_test.rb:104

Finished in 0.68248 seconds
13 examples, 1 failure

Failed examples:

rspec ./spec/integration/spec_helper.rb:78 # Supported types should support generic boolean type

@jeremyevans
Copy link
Owner

This is looking really good. Thanks for all of the work you are putting into it. I haven't looked at the code you, but from your notes, here are some comments:

  1. For WHERE 1: You should probably override boolean_constant_sql to handle true/false differently (use 1 = 1 or 1 = 0). Also override filter_expr to handle true/false specially. MSSQL and SQLite require similar changes, so I should refactor things so that core Sequel handles this and you just have to set a flag in the adapter (def supports_where_true? false end).

  2. For (A,B) in (C,D): Enable emulation by setting: def supports_multiple_column_in?; false; end

  3. For OFFSET: Can you emulate it using window functions (what the MSSQL adapter does)?

  4. For extract: I need to refactor the current implementation so that it doesn't use custom SQL.

  5. What are the issues with the class table inheritance plugin? Does DB2 not support JOIN USING?

  6. You can split the add primary/foreign key operation into multiple queries. Check the SQLite adapter since it emulates support for a bunch of unsupported schema stuff.

I'll try to review the code later today when I have more time.

Thanks,
Jeremy

@roylez
Copy link
Contributor Author

roylez commented Sep 10, 2011

Thanks for all the suggestions. I will try fixing them tomorrow.

For 5), you are right. It is about JOIN USING syntax. I have seen JOIN USING being used here, but nowhere else. The version of db2 in the link is old (5.4 for iSeries), and I do not know if this is just a dialect of db2 SQL.

Cheers,
Roy

@jeremyevans
Copy link
Owner

I reviewed the code and have the following comments:

You can't set @database_timezone = :utc and @application_timezone = :local in the adapter (you can do so in the DB2 adapter spec if you want). Sequel supports using multiple databases and adapters at once, and this could break the settings in other adapters. Especially the application_timezone setting to local doesn't make sense, because the user might want to use :utc as the application timezone as well.

Don't raise strings as errors (Connection#prepare, Connection#execute_prepared_statement, Database#_execute). You should probably raise them as Sequel::DatabaseErrors.

Connection#reorg looks vulnerable to SQL injection if table contains a '. You need to escape the table name.

You should avoid using explicit return if possible:

  • Statement#fail? should probably just be !@stmt.
  • Statement#fetch_assoc should probably just be IBM_DB.fetch_assoc(@stmt) if @stmt

If you override Database#alter_table, you should return whatever value is returned by super.

I don't think you need to override Database#execute_dui, as the default implementation does the same thing.

Database#execute probably should not rescue Exception. You should only rescue the specific exception class(es) raised by the underlying adapter.

Database#execute_insert looks broken in multithreaded use, as there's no guarantee the connection used by execute_dui is the same one as the one used by metadata_dataset.get. And using a symbol inside metadata_dataset.get looks wrong. You probably want to use a literal string.

Database#execute_prepared_statement should probably rescue the specific errors that can be raised and use raise_error. It also should not use eval, as that could probably be used for code injection. args should generally be ruby objects anyway, so I don't see the need for eval(literal(v)).

Database#execute_prepared_statement seems to think that conn.prepared_statements[ps_name] returns a string, when you are storing a two element array of string and statement.

Database#table_exists appears to be able to go into an infinite loop if the database still raises an exception. Again, you should only be rescuing the specific exception class, as currently you'll retry if an unrelated exception such as an interrupt is raised.

You can probably just alias type_literal_generic_falseclass to type_literal_generic_trueclass instead of using a separate method.

You should not override type_literal_specific to check for :text.

Dataset#fetch_rows should remove the unless @columns and @column_info, you should not assume they will be the same as the previous call. Also, you should probably inline hash_row and use local variables. The inner part of fetch_rows is basically the inner loop when row fetching, so you should optimize it as much as possible. Take a look at some other adapters such as mysql, postgres, and sqlite to see how to optimize things.

literal_false and literal_true, and the BOOL_TRUE, BOOL_FALSE, BITWISE_METHOD_MAP, and CONSTANT_MAP should move to the shared adapter.

tables, views, indexes, and schema_parse_table in the shared adapter are all vulnerable to SQL injection. Use literal instead of trying to quote things yourself.

Turning identifier quoting off by default is generally not advised, so you should only do that as a last resort.

I know I previously advised adding a from inside get, but it's probably better to override select_from_sql and add the table there if there is no :from option set in the dataset.

convert_type should be moved from the shared adapter to the native adapter.

If you can't emulate OFFSET with window functions, you should probably have the dataset raise an Error instead of silently ignoring them.

select_limit_sql is defined twice in the shared adapter.

You should probably use #{literal(table)} inside _truncate_sql, even if identifiers are not quoted by default.

You should be able to define the IBMDB_URL via an environment variable in the spec. Only database specific stuff should be tested in an adapter spec. If the spec could apply to something other than DB2, it should added to the integration tests.

You should add the ibmdb adapter spec tasks to the Rakefile.

You should modify the opening_databases.rdoc to add information about the ibmdb adapter.

Also, modify ADAPTERS in lib/sequel/database/connecting.rb to add ibmdb.

I know this seems like a lot. You've done a great job so far. I'm going to look into setting up a DB2 instance myself to test things on a regular basis, so that I can be sure support for DB2 stays good.

@jeremyevans
Copy link
Owner

I pushed some commits today that make it possible for extract to work correctly (see the shared sqlite and mssql adapters), and should fix the where 1 issue (set Dataset#supports_where_true? to false).

@jeremyevans
Copy link
Owner

I got DB2 setup in a VM, and I'm currently working with your branch. With only a small patch to enable the specs and fix a small syntax error (http://pastie.org/2523170), I'm getting "363 examples, 7 failures, 25 pending", which is a good sign. I don't want to overlap with what your doing, but I'm happy to test patches now, and if you get stuck in any part, I can make modifications and test them.

@jeremyevans
Copy link
Owner

Here's a diff to your adapter with some small changes for better compatibility: http://pastie.org/2523585

@roylez
Copy link
Contributor Author

roylez commented Sep 13, 2011

Sorry for being not responsive during the last few days. I am just back from vacation and thanks a lot for your careful review and help.

I made some changes according to your comments, but it is still not complete. Below are the things that you may want to know.

  • The eval in Database#execute_prepared_statement. The thing is, IBM_DB.execute, when accepting arguments to be bound to prepared statements placeholders, does not accept normal ruby types. Instead it accepts string literals same as in SQL statements. I still needs to get rid of the eval anyway.
  • exact works directly on database returned timestamp, which is in :utc time zone, and the spec test fails when expecting returned hour to be in :local time zone.
  • I cannot completely get rid of @column in hash_row for some wired reason. For example, if removing "@columns = columns", I get more failed tests.
  • Quoting identifiers is somehow looks very necessary for DB2 and informix. Informix adapter has this set as well. If not set, db2 will look for USER.SYSCAT.COLUMNS table instead of SYSCAT.COLUMNS with this SQL 'SELECT * FROM "SYSCAT.COLUMNS" ' when current user is USER.

It is a great help that you can setup a db2 instance yourself, and looks like your db2 version is newer than mine (9.1) and produces less errors.

@jeremyevans
Copy link
Owner

Your changes look good. I'll merge your changes into my local branch and just keep working on things. After things are mostly working, I'll merge it into the main Sequel branch, and after that we can just make small fixes to the main branch to fix issues. I'll need your help in testing older versions of DB2, since I don't want to setup multiple versions to test on.

Thanks to your help with the shared DB2 adapter, I'm also working on changes to the main db2 adapter (which uses ruby-db2) that make it actually run. Additionally, I'm working on a JDBC subadapter for DB2, but not much luck on that yet.

@jeremyevans
Copy link
Owner

I've almost got something ready to commit. I'm going to review the full diff from master tonight, and should be committing things tomorrow.

@jeremyevans jeremyevans merged commit 3e939fe into jeremyevans:master Sep 14, 2011
@jeremyevans
Copy link
Owner

Thanks for all of your help, Roy. If you find any issues with the changes I made that break something in DB 9.1, please send a pull request that makes some things conditional on version (you'll probably want to turn db2_version into an integer so it's easy to compare (server_version < 9070401). These are the only currently 6 pending specs on 9.7, everything else passes:

Prepared Statements and Bound Arguments should support using a prepared_statement for a limit and offset (Not yet working on db2)
/home/jeremy/sequel/spec/integration/spec_helper.rb:77:in `cspecify'

The OFFSET emulation with ROW_NUMBER doesn't seem to like a prepared statement, though it works fine in a regular query.

Simple Dataset operations should insert with a primary key specified (Not yet working on db2)
/home/jeremy/sequel/spec/integration/spec_helper.rb:77:in `cspecify'

Simple Dataset operations should have insert work correctly when inserting a row with all NULL values (Not yet working on db2)
/home/jeremy/sequel/spec/integration/spec_helper.rb:77:in `cspecify'

Simple Dataset operations should fetch correctly with a limit and offset without an order (Not yet working on db2)
/home/jeremy/sequel/spec/integration/spec_helper.rb:77:in `cspecify'

Simple Dataset operations in transactions should insert correctly with a primary key specified inside a transaction (Not yet working on db2)
/home/jeremy/sequel/spec/integration/spec_helper.rb:77:in `cspecify'

Common Table Expressions should give correct results for recursive WITH (Not yet working on db2)
/home/jeremy/sequel/spec/integration/spec_helper.rb:77:in `cspecify'

The rest of these are just issues with DB2, and probably won't be fixed. FWIW, ibmdb is one of the best adapters in terms of passing specs. postgres is the best with 0, followed by mysql with 1, h2 with 3, and then mysql2 and ibmdb with 6.

@roylez
Copy link
Contributor Author

roylez commented Sep 15, 2011

That is really a huge commit, and the code looks a lot clearer. I have tried integration test here, and everything works fine. The failed ones here are all expected so there is no need to make anything conditional on version. Please make change to Database#db2_version to return integer if you like.

Freeing prepared stmt in Database#excute_prepared_statement worries me a little. I am not sure if a statement can be reused after being freed. Perhaps it will give out error when for the second time it is executed with new bind arguments.

Also, although all prepared statement tests pass, prepared statement function does not seem to work as expected here.

ruby-1.8.7-p299 :004 >   dbh.create_table!(:items){Integer :n; String :s; primary_key [:n, :s] }
 => nil
ruby-1.8.7-p299 :006 > t = dbh[:items]
 => #<Sequel::IBMDB::Dataset: "SELECT * FROM ITEMS">
ruby-1.8.7-p299 :007 > t << { :n => 1, :s => 's'}
 => 0
ruby-1.8.7-p299 :008 > d = t.filter(:n=>:$n, :s=>:$s)
 => #<Sequel::IBMDB::Dataset: "SELECT * FROM ITEMS WHERE ((S = $S) AND (N = $N))">
ruby-1.8.7-p299 :009 > ps = d.prepare(:insert, :insert_n)
 => Sequel::IBMDB::DatasetPreparedStatement "INSERT INTO ITEMS VALUES DEFAULT"

@jeremyevans
Copy link
Owner

That's not a bug, the :where option is ignored when inserting (what would it mean)?

I'm guessing you want:

ps = t.prepare(:insert, :insert_n, :n=>:$n, :s=>:$s)
ps.call(:n=>1, :s=>'a')

@jeremyevans
Copy link
Owner

About freeing the prepared statement, it calls IBM_DB.free_result(@stmt), which leads me to believe it only frees the memory related to the result set, not the prepared statement object. I could be wrong, though. The only spec I see that calls a prepared statement more than once is actually failing on db2, but I think it was failing before I added the freeing of the statement. Regardless, we should have a spec that specifically tests that. If you could test that (or even better add a spec for it, failing or not), that would be great.

@roylez
Copy link
Contributor Author

roylez commented Sep 15, 2011

Freeing the statement does no harm. I was wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants