代码之家  ›  专栏  ›  技术社区  ›  jeroenh

将时间戳类型的关联数组传递给oracle存储过程

  •  1
  • jeroenh  · 技术社区  · 16 年前

    我们在使用OracleODP.Net(连接到Oracle9)时遇到了一个奇怪的错误。下面的代码片段说明了这个问题。

    这是我们遇到的错误:

    ORA-00600:内部错误代码,参数:[15419],[在PL/SQL执行期间发生严重错误],[],[],[],[],[],[],[],[],[],[]

    ORA-06544:PL/SQL:内部错误,参数:[78502],[],[],[],[],[],[],[],[],[],[],[],[]

    ORA-06553:PLS-801:内部错误[78502]

    谷歌搜索使我们怀疑(尽管我们不能完全确定)Odp.Net不支持传递时间戳数组。

    • 可以传递一个数组吗 使用 odp.net?
    • 如果没有,是否有好的解决方法?

    说明问题的C#控制台程序:

    using System;
    using System.Collections;
    using System.Data;
    using Oracle.DataAccess.Client;
    
    class Program 
    {
    private const string _db = "<db>";
    private const string _username = "<user>";
    private const string _password = "<password>";
    private const string _storedProcedureName = "<sproc>";
    
    static void Main(string[] args)
    {
      var connectionString = string.Format(
                                  "data source={0};user id={1};password={2}", 
                                  _db, _username, _password);
    
      var connection = new OracleConnection(connectionString);
    
      try
      {
    
        connection.Open();
    
    
        var timeStamps = new[] { DateTime.Now, DateTime.Now };
    
        var parameter = new OracleParameter("inTimeStamps", OracleDbType.TimeStamp)
          {
            Direction = ParameterDirection.Input,
            CollectionType = OracleCollectionType.PLSQLAssociativeArray,
            Size = timeStamps.Length,
            Value = timeStamps
          };
    
        var command = connection.CreateCommand();
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = _storedProcedureName;
        command.Parameters.Add(parameter);
    
        command.ExecuteReader();
    
      }
      finally
      {
        connection.Close();
      }
    }
    }
    

      TYPE ArrayOfTimestamps is table of timestamp index by binary_integer;
    
      PROCEDURE TestOdpTimeStamp (inTimeStamps in ArrayOfTimestamps)
      IS
      test number;
      BEGIN
         select 1 into test from dual;
      END;
    
    3 回复  |  直到 15 年前
        1
  •  3
  •   tuinstoel    16 年前

    您可以将嵌套的时间戳表而不是关联数组传递给PL/SQL过程。

    如果需要odp.net 11.1.0.6.20或更高版本,可以使用odp.net 11.1.0.6.20连接到Oracle 9服务器。

    作为Oracle用户测试执行:

    create or replace type MyTimeStamp as object 
    (
      my timestamp
    )
    /
    
    create or replace type mytimestamp_table as table of MyTimeStamp 
    /
    
    create table testinserttimestamp 
    ( my timestamp);
    
    create or replace procedure test_timestamp_table (p_in in mytimestamp_table)
    is
    begin
      for i in p_in.first..p_in.last loop
        insert into testinserttimestamp values (p_in(i).my);
     end loop;
     commit;
    end;
    

    在C#中,使用名为button1的按钮创建一个表单,然后执行。。。

    using System;
    using System.Data;
    using System.Windows.Forms;
    using Oracle.DataAccess.Client;
    using Oracle.DataAccess.Types;
    
    namespace TestTimeStamp
    {
      public partial class Form1 : Form
      {
        public Form1()
        {
          InitializeComponent();
        }
    
    
        public class MyUdtTimeStamp : INullable, IOracleCustomType
        {
    
          [OracleObjectMappingAttribute("MY")]
          public OracleTimeStamp My { get; set; }
    
          public bool IsNull
          {
            get { return false;}
          }
    
          public void FromCustomObject(OracleConnection con, IntPtr pUdt)
          {
            OracleUdt.SetValue(con, pUdt, "MY", My);
          }
    
          public void ToCustomObject(OracleConnection con, IntPtr pUdt)
          {
            My = (OracleTimeStamp)OracleUdt.GetValue(con, pUdt, "MY");
          }
        }
    
        [OracleCustomTypeMappingAttribute("TESTTS.MYTIMESTAMP")]
        public class StudentFactory : IOracleCustomTypeFactory
        {
          public IOracleCustomType CreateObject()
          {
            return new MyUdtTimeStamp();
          }
        }
    
        [OracleCustomTypeMappingAttribute("TESTTS.MYTIMESTAMP_TABLE")]
        public class PersonArrayFactory : IOracleArrayTypeFactory
        {
          public Array CreateArray(int numElems)
          {
            return new MyUdtTimeStamp[numElems];
          }
    
          public Array CreateStatusArray(int numElems)
          {
            return null;
          }
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
          OracleConnectionStringBuilder b = new OracleConnectionStringBuilder();
          b.UserID = "testts";
          b.Password = "ts";
          b.DataSource = "ora11";
          using (OracleConnection conn = new OracleConnection(b.ToString())) {
            conn.Open();
            using (OracleCommand comm = conn.CreateCommand())
            {
              comm.CommandText = "begin test_timestamp_table(:1); end;";
              OracleParameter p = new OracleParameter();
              p.OracleDbType = OracleDbType.Array;
              p.Direction = ParameterDirection.Input;
    
              p.UdtTypeName = "TESTTS.MYTIMESTAMP_TABLE";
              MyUdtTimeStamp[] times = new MyUdtTimeStamp[2];
              MyUdtTimeStamp m1 = new MyUdtTimeStamp();
              m1.My = new OracleTimeStamp(DateTime.Now);
              MyUdtTimeStamp m2 = new MyUdtTimeStamp();
              m2.My = new OracleTimeStamp(DateTime.Now);
              times[0] = m1;
              times[1] = m2;
              p.Value = times;
    
              comm.Parameters.Add(p);
    
              comm.ExecuteNonQuery();
            }
    
            conn.Close();
          }
        }
      }
    }
    

    在甲骨文中做什么。。。

    SQL> select * from testinserttimestamp;
    
    MY
    -------------------------------------------------
    12-10-09 21:13:54,328125
    12-10-09 21:13:55,171875
    
        2
  •  2
  •   DCookie    16 年前

    有一个Metalink注释(788282.1)指出,传递不受支持的数据类型可能会导致此错误。不支持时间戳。您可以通过在C#代码中构造一个匿名PL/SQL块并从该块中调用有问题的存储过程来绕过它。

    编辑:

    我无法从Metalink发布代码,原因很明显。

    comm.CommandText = "declare "+
                       "theTS mytimestamp_table;"+
                       "begin"+
                       "  theTS(1):= :1;"+
                       "  theTS(2):= :2;"+
                       "  test_timestamp_table(theTS);"+
                       "  end;"; 
    

    然后必须构造参数列表,为每个绑定变量提供值。

        3
  •  2
  •   Tim    14 年前

    我最近也遇到了这个问题,但我通过使用字符串和to_timestamp以不同的方式克服了这个问题,我希望这能帮助任何进一步遇到这个问题的人: http://timscyclingblog.wordpress.com/2011/10/07/oracle-plsqlassociativearray-timestamp-workaround/