错误" PL / SQL:数字或值错误:字符串缓冲区太小"在存储过程中使用可选参数时

时间:2014-04-03 10:02:12

标签: sql vb.net oracle stored-procedures enterprise-library

我使用以下存储过程返回特定关键字的递增键值。它采用Y或N的可选参数来确定结果是否应该以另一个值作为前缀。

create or replace
PROCEDURE                        "ASGETPRIMARYKEY" 
(
  p_ObjectName IN LASTPRIMARYKEY.OBJECTNAME%type ,
  p_PrimaryKey OUT LASTPRIMARYKEY.NEXTKEY%type,
  useSitePrefix IN NVARCHAR2 Default 'Y'
)
AS
   v_transcount NUMBER := 1;
   v_sys_error NUMBER := 0;
   v_SitePrefix NVARCHAR2(4000);
   v_LastPrimaryKey NUMBER(10,0);
   -- Error Handling Variables
   v_LocalTran NUMBER(1,0);
   v_Error NUMBER(10,0);
BEGIN
   NULL/*TODO:SET XACT_ABORT ON*/;
   NULL/*TODO:SET NOCOUNT ON*/;
   -- STEP 0: Start the transaction
   -- If procedure doesn't need to begin a transaction this can be set to 0
   IF v_transcount > 0 THEN
      v_LocalTran := 0;
   ELSE
      v_LocalTran := 1;
   END IF;

   IF v_LocalTran = 1 THEN
      SET TRANSACTION READ WRITE;
      v_transcount := v_transcount + 1;
   END IF;
   -- STEP 1: Get @SitePrefix
   SELECT settingtext
     INTO v_SitePrefix
     FROM systemsetting
     WHERE settingdescription = 'Site Id Prefix';
   -- Check if there were any errors
   v_Error := v_sys_error;
   IF v_Error != 0 THEN
   BEGIN
      raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(1a)' || cast(v_error as NVARCHAR2));
      GOTO ErrExit;
   END;
   END IF;
   -- STEP 1b: Check SitePrefix exists
   -- Rollback the transaction if SitePrefix doesn't exist in systemsetting
   IF v_SitePrefix IS NULL THEN
   BEGIN
      raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(1b)' || cast(v_error as NVARCHAR2));
      GOTO ErrExit;
   END;
   END IF;
   BEGIN
      -- STEP 2: Set NextKey for requested ObjectName
      UPDATE LastPrimaryKey
         SET NextKey = (NextKey + 1)
         WHERE objectname = p_ObjectName;
   EXCEPTION
      WHEN OTHERS THEN
         v_sys_error := SQLCODE;
   END;
   BEGIN
      -- Check if there were any errors
      v_Error := v_sys_error;
   EXCEPTION
      WHEN OTHERS THEN
         v_sys_error := SQLCODE;
   END;
   IF v_Error != 0 THEN
   BEGIN
      raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(2)' || cast(v_error as NVARCHAR2));
      GOTO ErrExit;
   END;
   END IF;
   -- STEP 3: Set NextKey for for requested ObjectName
   SELECT NextKey - 1
     INTO v_LastPrimaryKey
     FROM LastPrimaryKey
     WHERE objectname = p_ObjectName;
   BEGIN
      -- Check if there were any errors
      v_Error := v_sys_error;
   EXCEPTION
      WHEN OTHERS THEN
         v_sys_error := SQLCODE;
   END;
   IF v_Error != 0 THEN
   BEGIN
      raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(3)' || cast(v_error as NVARCHAR2));
      GOTO ErrExit;
   END;
   END IF;
   -- STEP 4: Check SitePrefix exists
   -- Rollback the transaction if SitePrefix doesn't exist in systemsetting
   IF v_LastPrimaryKey IS NULL THEN
   BEGIN
      raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(4)' || cast(v_error as NVARCHAR2));
      GOTO ErrExit;
   END;
   END IF;
   -- STEP 5: Set @p_PrimaryKey by adding prefix
   IF useSitePrefix = 'y' THEN
      p_PrimaryKey := (CAST(v_SitePrefix || CAST(v_LastPrimaryKey AS NVARCHAR2) AS NUMBER));
   ELSE
      p_PrimaryKey := v_lastprimarykey;
   END IF;
   -- Check if there were any errors
   v_Error := v_sys_error;
   IF v_Error != 0 THEN
   BEGIN
      raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(5)' || cast(v_error as NVARCHAR2));
      GOTO ErrExit;
   END;
   END IF;
   -- STEP 6: If we reach this point, the commands completed successfully
   --         Commit the transaction....
   -- Normal exit
   IF v_LocalTran = 1 THEN
      COMMIT;
      v_transcount := v_transcount - 1;
   END IF;
   -- Error Exit
   <<ErrExit>>
   IF v_LocalTran = 1 THEN
      ROLLBACK;
      v_transcount := v_transcount - 1;
   END IF;
END;

使用以下vb代码从企业库中调用存储过程:

        Dim sqlCommand As String = "asGetPrimaryKey"
        Dim _db As Database = EnterpriseLibraryContainer.Current.GetInstance(Of Database)(ASDBMSS.clsDBMSS.ConnectionStringName)
        Dim DbCommand As System.Data.Common.DbCommand = _db.GetStoredProcCommand(sqlCommand)
        ' Add primary keys to command wrapper.
        _db.AddInParameter(DbCommand, "p_objectName", DbType.String, ObjectName)

        If pbIgnoreSiteIndex Then
            _db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "Y")
        Else
            _db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "N")
        End If

        _db.AddOutParameter(DbCommand, "p_PrimaryKey", DbType.Int32, 8)
        _db.ExecuteNonQuery(DbCommand)

        Dim _result As String = _db.GetParameterValue(DbCommand, "p_PrimaryKey").ToString
        lcl_NextKey = CInt(_result)
        result = 1

当我传递可选参数时,问题就出现了。 如果我跳过带有可选参数的行,它可以正常工作。 如果我使用SQL服务器而不是Oracle,它可以正常工作。 如果我传递参数并使用Oracle,我会收到以下错误消息:

ORA-06502:PL / SQL:数字或值错误:字符串缓冲区太小 ORA-06512:第1行

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

将v_LastPrimaryKey从数字(10,0)更改为与p_PrimaryKey相同OUT LASTPRIMARYKEY.NEXTKEY%type,

其次,你传递的是Y或N,但在代码中比较y。因此,流量总是在“其他”中进行,您不使用强制转换。 希望有所帮助。 干杯 V

答案 1 :(得分:1)

我找到了问题!

只要名称匹配,SQL服务器就不关心参数的传递顺序。看起来似乎是Oracle。

我将调用它们的顺序改为:

        _db.AddInParameter(DbCommand, "p_objectName", DbType.String, ObjectName)
        _db.AddOutParameter(DbCommand, "p_PrimaryKey", DbType.Int32, 8)

        If pbIgnoreSiteIndex Then
            _db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "Y")
        Else
            _db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "N")
        End If

        _db.ExecuteNonQuery(DbCommand)

它现在可以正常运行