获取OCIError:ORA-00932:来自Rails 3的不一致数据类型

这是场景。
我正在为Ruby On Rails编写我的geo-ruby oracle适配器,它支持开箱即用的SDO_GEOMETRY。
一切顺利。 我编写了用于从Oracle DB中成功选择SDO_GEOMETRY对象的代码。
当我想编写插入和更新部件时,一切都毁了。
以下就是我的想法。 我希望能够做到这一点:

g = GeoShape.new(name:"point1", shape: Point.from_x_y(-34,-43,4326)) g.save 

我从上面的语句中生成了以下sql查询:

 INSERT INTO "GEO_SHAPES" ("CREATED_AT", "ID", "NAME", "SHAPE", "UPDATED_AT") VALUES (:a1, :a2, :a3, :a4, :a5) [["created_at", Tue, 03 Jul 2012 08:42:01 UTC +00:00], ["id", 10112], ["name", "point1"], ["shape", "SDO_GEOMETRY(2001, NULL, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(-34,-43))"], ["updated_at", Tue, 03 Jul 2012 08:42:01 UTC +00:00]] 

但执行上面的查询给了我这个错误:

 ActiveRecord::StatementInvalid: OCIError: ORA-00932: inconsistent datatypes: expected MDSYS.SDO_GEOMETRY got CHAR 

我进入oracle_enhanced_adapter来追踪问题。 我试图修补它并手动初始化绑定[3] [1](这是我的数据库中sdo_geometry列的值),如下所示:

  def exec_insert(sql, name, binds) log(sql, name, binds) do returning_id_index = nil cursor = if @statements.key?(sql) @statements[sql] else @statements[sql] = @connection.prepare(sql) end binds[3][1] = "SDO_GEOMETRY(2001, NULL, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(-34,-43))" ### DAVE binds.each_with_index do |bind, i| col, val = bind if col == :returning_id returning_id_index = i + 1 cursor.bind_returning_param(returning_id_index, Integer) else if val == "SDO_GEOMETRY(2001, NULL, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(-34,-43))" ### DAVE cursor.bind_param(i + 1, val, OCI8::Object::Mdsys::SdoGeometry) ###DAVE else ### DAVE cursor.bind_param(i + 1, type_cast(val, col), col && col.type) end end end cursor.exec_update 

不幸的是,它没有帮助。 我仍然得到相同的错误ORA-00932。 有任何想法吗? 解决这个问题对我来说至关重要。

PS:### DAVE部分是oracle_enhanced_adapter.rb的猴子补丁
PS:这是我的配置。

  • Oracle 11.2
  • Ruby版本1.9.3(i386-darwin11.3.0)
  • Rails版本3.2.5
  • Active Record版本3.2.5

最后,我设法解决了这个问题。
增强型适配器使用bind_param方法将绑定变量执行到适当的oracle类型。 这是问题和错误。
我必须覆盖oracle_enhanced_adpter.rb中的一些代码。
我在此文件中添加了一个方法来手动构建SDO_GEOMETRY对象。
然后我将这个返回的对象绑定到OCI8 :: Object :: Mdsys :: SdoGeometry类型。

我的方法包含这些代码(现在,仅用于创建SDO_GEOMETRY点):

 #I needed a connection to my oracle database. Connection placeholder is conn. def create_sdo_geometry_object(conn, gtype, srid, point, x, y) local_cursor = conn.parse("BEGIN :geom := SDO_GEOMETRY(:sdo_gtype, :sdo_srid, :sdo_point, :sdo_elem_info_array, :sdo_ordinate_array); END;") local_cursor.bind_param(:sdo_gtype, OraNumber) local_cursor.bind_param(:sdo_srid, OraNumber) local_cursor.bind_param(:sdo_point, OCI8::Object::Mdsys::SdoPointType) local_cursor.bind_param(:sdo_elem_info_array, OCI8::Object::Mdsys::SdoElemInfoArray) local_cursor.bind_param(:sdo_ordinate_array, OCI8::Object::Mdsys::SdoOrdinateArray) local_cursor.bind_param(:geom, OCI8::Object::Mdsys::SdoGeometry) sdo_gtype = OraNumber.new(gtype) sdo_srid = OraNumber.new(srid) sdo_point = nil #Temporarily I set it to nil #sdo_elem_info_array must be [1,1,1] for creating points. sdo_elem_info_array = OCI8::Object::Mdsys::SdoElemInfoArray.new(conn,OraNumber.new(1),OraNumber.new(1),OraNumber.new(1)) #I want to create a point with x and y coordinates sdo_ordinate_array = OCI8::Object::Mdsys::SdoOrdinateArray.new(conn,OraNumber.new(x),OraNumber.new(y)) local_cursor[:sdo_gtype] = sdo_gtype local_cursor[:sdo_srid] = sdo_srid local_cursor[:sdo_point] = sdo_point local_cursor[:sdo_elem_info_array] = sdo_elem_info_array local_cursor[:sdo_ordinate_array] = sdo_ordinate_array local_cursor.exec local_cursor[:geom] end 

然后当我想绑定这个参数时,我使用了以下代码:

 cursor.bind_param(i + 1, create_sdo_geometry_object("PARAMS HERE"), OCI8::Object::Mdsys::SdoGeometry) 

它就像一个魅力!