MYSQL Error 1414 - Error doesnt make sense - mysql

This is my stored procedure, which works fine on my local machine, but on PRODUCTION, it gives me the above error: Its complaining about the OUT parameter, the last one:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `insert_projects`(
IN userName varchar(20),
IN projectName text,
IN projectDescription text,
IN projectCurrency text,
IN projectBudget1 double,
IN projectBudget2 double,
IN projectEndDate DATETIME,
IN expectedDelivDate DATETIME,
IN projectMessageForBidder text,
OUT projectCode bigint)
BEGIN
DECLARE
l_project_code bigint;
insert into projects
(PROJECT_CODE,
SR_USER_NAME ,
PROJECT_NAME,
PROJECT_DESCRIPTION,
PROJECT_CURRENCY,
PROJECT_BUDGET1 ,
PROJECT_BUDGET2 ,
PROJECT_STATUS,
PROJECT_END_DATE,
PROJECT_PAID,
EXPECTED_DELIV_DATE,
PROJECT_MESSAGE_FOR_BIDDER,
PROJECT_CREATION_DATE,
PROJECT_UPDATE_DATE)
values
(
0,
userName,
projectName,
projectDescription,
projectCurrency,
projectBudget1,
projectBudget2,
'Active',
projectEndDate,
null,
expectedDelivDate,
projectMessageForBidder,
NOW(),
NOW());
SELECT LAST_INSERT_ID() into l_project_code;
SET projectCode = l_project_code;
END
Below is my C# code, that sets up the parameters :
MySqlCommand command = new MySqlCommand("insert_projects", dbcontroller.conn);
command.CommandType = System.Data.CommandType.StoredProcedure;
// Add parameters for the insert_projects STORED PROC
command.Parameters.Add(new MySqlParameter("userName", SessionBag.Current.UserName));
command.Parameters["#userName"].Direction = System.Data.ParameterDirection.Input;
command.Parameters.Add(new MySqlParameter("projectCode", MySqlDbType.Int64));
command.Parameters["#projectCode"].Direction = System.Data.ParameterDirection.Output;
command.Parameters.Add(new MySqlParameter("projectName", model.projectName));
command.Parameters.Add(new MySqlParameter("projectDescription", model.projectDescription));
command.Parameters.Add(new MySqlParameter("projectCurrency", model.projectCurrency));
command.Parameters.Add(new MySqlParameter("projectBudget1", model.projectBudget1));
command.Parameters.Add(new MySqlParameter("projectBudget2", model.projectBudget2));
command.Parameters.Add(new MySqlParameter("projectEndDate", model.projectEndDate));
command.Parameters.Add(new MySqlParameter("expectedDelivDate", model.expectedDelivDate));
command.Parameters.Add(new MySqlParameter("projectMessageForBidder", model.projectMessageForBidder));
try
{
command.ExecuteNonQuery();
TempData["projectCode"] = (Int64)command.Parameters["?projectCode"].Value;
TempData["frompage"] = "AddProject";
dbcontroller.conn.Close();
return RedirectToAction("MyProjectsHeaderSR", "Projects");
}
Why is is complaining about this? My local machine works fine. The table "projects" contains a field called project_code which is set to BIGINT auto-increment... The rest of the fields are normal datatypes.
Ok, I have created a variable .. and passed it in .. same error
if (dbcontroller.DBConnection())
{
Int64 projectCode = 0;
MySqlCommand command = new MySqlCommand("insert_projects", dbcontroller.conn);
command.CommandType = System.Data.CommandType.StoredProcedure;
// Add parameters for the insert_projects STORED PROC
command.Parameters.Add(new MySqlParameter("userName", SessionBag.Current.UserName));
command.Parameters["#userName"].Direction = System.Data.ParameterDirection.Input;
command.Parameters.Add(new MySqlParameter("projectCode", projectCode));
command.Parameters["#projectCode"].Direction = System.Data.ParameterDirection.Output;
It still doesnt work

The error you describe is the result of a bug in older versions of MySQL, resolved in MySQL 5.5.3. It's probable that your local machine is running a version of MySQL where the bug has been fixed, and the production server is running an older version.
Although the best solution may be to upgrade the server, as a workaround until then, you could change the procedure to simply select the LAST_INSERT_ID() (not into a variable, but into a result set), and process that result into your variable.
Incidentally, a similar situation may arise when using INOUT parameters. Although you are using an OUT parameter (and so the following does not apply in your case), the situation would arise when an INOUT parameter but not providing a variable to populate, the following would similarly apply.
The line:
command.Parameters.Add(new MySqlParameter("projectCode", MySqlDbType.Int64));
...is providing a named parameter to the command object, and a type, but not giving it anything to populate. If you were using an INOUT parameter, you would need to provide a empty variable and pass it in; it'll give the SP something to output to.

Related

MySql Function not found error in asp.net application when calling ExecuteScalar() on a Stored Procedure command

I've inherited a rather old ASP.NET application that runs on our company intranet. The server it is on is extremely old and I am trying to get it working on a slightly newer server but I am having an issue with some MySQL Stored Procedures.
The error I am catching is "FUNCTION mann_production.spGetDraftID does not exist"
Here is the way I am creating the command object and calling ExecuteScalar()
Using connection As New MySqlConnection(ConfigurationManager.ConnectionStrings("MYSQL5_Products").ConnectionString)
Using command As New MySqlCommand("spGetDraftID", connection)
command.CommandType = Data.CommandType.StoredProcedure
command.Parameters.Add(New MySqlParameter("?parModuleID", ModuleID))
command.Parameters.Add(New MySqlParameter("?retNewModuleID", "0"))
command.Parameters("?retNewModuleID").Direction = Data.ParameterDirection.ReturnValue
connection.Open()
Try
command.ExecuteScalar()
Catch e As Exception
Return Nothing
End Try
Return command.Parameters("?retNewModuleID").Value
End Using
End Using
I have the ConnectionString defined in Web.config.
<connectionStrings>
<add name="MySQL5_Products" connectionString="Server=localhost; User ID=mannsql; Pwd=XXXXXX; pooling=true; Max Pool Size=300; Persist Security Info=true; Database=mann_production" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
The Stored Procedure in my MySQL database definitely exists.
This is it.
DELIMITER $$
USE `mann_production`$$
DROP PROCEDURE IF EXISTS `spGetDraftID`$$
CREATE DEFINER=`mannsql`#`` PROCEDURE `spGetDraftID`(
IN parModuleID INT(11),
OUT retNewModuleID INT(11))
COMMENT 'Either makes a draft of the given Module ID or returns the ID of'
BEGIN
/* Find draft if exists */
SET retNewModuleID = (SELECT Module.ModuleID
FROM Module INNER JOIN Module AS Module_1 ON Module.ModuleName = Module_1.ModuleName
WHERE ((Module.Rev = 'Draft') AND (Module_1.ModuleID = parModuleID))
LIMIT 1);
IF (IFNULL(retNewModuleID, 0) = 0) THEN
/*Create a new Module Draft*/
INSERT INTO Module ( Module.ModuleName, Module.Rev, Module.MinorRevision, Module.Current, Module.Description, Module.Notes) SELECT Module.ModuleName, 'Draft' AS Rev, 1 AS MinorRevision, 0 AS CURRENT, Module.Description, Module.Notes FROM(Module) WHERE (((Module.ModuleID)=parModuleID)) LIMIT 1;
/* Get the ID*/
SET retNewModuleID = (SELECT LAST_INSERT_ID());
/*Copy Operations*/
INSERT INTO ModuleOperations ( ModuleOperations.OP, ModuleOperations.Description, ModuleOperations.ModuleID ) SELECT ModuleOperations.OP, ModuleOperations.Description, retNewModuleID AS Expr1 FROM(ModuleOperations) WHERE (((ModuleOperations.ModuleID)= parModuleID));
/* Copy Parts */
INSERT INTO ModuleBOM ( ModuleBOM.OP, ModuleBOM.Seq, ModuleBOM.ItemID, ModuleBOM.Qty, ModuleBOM.Um, ModuleBOM.Ref, ModuleBOM.Notes, ModuleBOM.ModuleID ) SELECT ModuleBOM.OP, ModuleBOM.Seq, ModuleBOM.ItemID, ModuleBOM.Qty, ModuleBOM.Um, ModuleBOM.Ref, ModuleBOM.Notes, retNewModuleID AS Expr1 FROM(ModuleBOM) WHERE (((ModuleBOM.ModuleID)=parModuleID));
/* Add New Revision Record */
INSERT INTO ModuleReleaseNotes (ModuleReleaseNotes.OldModuleID, ModuleReleaseNotes.NewModuleID, ModuleReleaseNotes.Revision) VALUES (parModuleID, retNewModuleID, 'Draft');
END IF;
END$$
DELIMITER ;
Any ideas would be greatly appreciated.
Cheers.

hsqldb procedure with date Input parameter

I need to write a test for some download operation. This operation call procedure from MSSQL database, take result set and java make some stuf. For test I use hsqldb.
My procedure:
CREATE PROCEDURE map.Get1(IN packageName varchar(100),
IN downloadDate DATE)
READS SQL DATA DYNAMIC RESULT SETS 1 BEGIN ATOMIC
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM map.tvschedule FOR READ ONLY;
OPEN result;
END
This procedure wan't work, i have an exception
call map.GET1('Genre','2018-03-10');
[42561][-5561] incompatible data type in conversion
java.lang.RuntimeException: org.hsqldb.HsqlException: incompatible data type
in conversion
But this(without date parameter) work well:
CREATE PROCEDURE map.Get1(IN packageName varchar(100))
READS SQL DATA DYNAMIC RESULT SETS 1 BEGIN ATOMIC
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM map.tvschedule FOR READ ONLY;
OPEN result;
END
call map.GET1('Genre');
first needed row
second needed row
I am not going to use input parameter, but i need this procedure to be looking i am going to.
My question is How to use date input parameter with hsqldb procedures?
UPDATE1:
I used TO_DATE and now it works well, but i have no data in my result set, my java code is:
try (CallableStatement callableStatement = connection.prepareCall("{ call
map.GetGenreProtocol( ?, ? ) }")) {
callableStatement.setString(1, packageName);
callableStatement.setDate(2, date);
callableStatement.execute();
ResultSet resultSet = callableStatement.getResultSet();
while (resultSet.next()) {
Interval Interval = new Interval();
Interval.setDuration(resultSet.getInt("duration"));
Interval.setMappingTargetId(resultSet.getInt("mappingTargetId"));
Interval.setGenreId(resultSet.getInt("genreId"));
Interval.setStart(resultSet.getLong("start"));
Interval.setCategoryId(resultSet.getInt("categoryId"));
Interval.setCategoryName(resultSet.getString("categoryName"));
Interval.setGenreName(resultSet.getString("genreName"));
Interval.setDescription(resultSet.getString("description"));
Intervals.add(Interval);
}
}
Use the TO_DATE function.
For example:
call map.GET1('Genre', TO_DATE('2018-03-10', 'YYYY-MM-DD'));
I guess you need to create a function that returns a table instead of a procedure:
CREATE FUNCTION map.Get1(IN packageName VARCHAR(100),
IN downloadDate DATE)
RETURNS TABLE(.....)
READS SQL DATA
BEGIN ATOMIC
....
END;

Calling Stored Procedure from VB.NET without errors, but nothing happens in Database

I am experiencing a small problem with calling a stored procedure from VB.NET using the ADODB Library (Microsoft ActiveX Data Objects 6.1 Library).
I have the following stored procedure (copy from MySQL):
USE [DAB_Eindopdracht_DAB-TH]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spAlterTypeVermogen]
#strModel as varchar(30),
#strType as varchar(30),
#intVermogen as int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #inttblTypeID int
DECLARE #inttblModelID int
DECLARE #inttblModelTypeID int
SET #inttblTypeID = (SELECT ID FROM tblType WHERE strNaam = #strType)
SET #inttblModelID = (SELECT ID FROM tblModel WHERE strNaam = #strModel)
SET #inttblModelTypeID = (SELECT ID FROM tblModelType WHERE typeID = #inttblTypeID AND modelID = #inttblModelID)
-- Update QUERY
UPDATE tblModelType
SET intVermogen = #intVermogen
WHERE ID = #inttblModelTypeID
END
Then in my VB code I call this stored procedure using the following code:
Public Sub changeTypeVermogen(ByVal intVermogen As Int16, ByVal strType As String, ByVal strModel As String)
Dim cmdData As New ADODB.Command
cmdData.CommandText = "spAlterTypeVermogen"
cmdData.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
cmdData.Parameters.Append(cmdData.CreateParameter("strModel", ADODB.DataTypeEnum.adVarChar, ADODB.ParameterDirectionEnum.adParamInput, 30))
cmdData.Parameters.Append(cmdData.CreateParameter("strType", ADODB.DataTypeEnum.adVarChar, ADODB.ParameterDirectionEnum.adParamInput, 30))
cmdData.Parameters.Append(cmdData.CreateParameter("intVermogen", ADODB.DataTypeEnum.adInteger, ADODB.ParameterDirectionEnum.adParamInput))
connOpen()
cmdData.ActiveConnection = cnnDatabase
cmdData.Parameters(0).Value = strModel
cmdData.Parameters(1).Value = strType
cmdData.Parameters(2).Value = intVermogen
cmdData.Execute()
connClose()
end sub
Now my problem is that when I run this stored procedure from MySQL, it works absolutely fine, it does exactly what I want it to do.
But when I call this procedure from my VB application nothing happens...
It runs through my method, not generating ANY errors at all, but it doesn't change any data in my database either.
I have checked my variables for their values and they are in the actual database.... meaning that it should be able to fully finish the Query.
Is there anyone that could explain me why nothing happens? (and no errors come up).
Am I doing something wrong? Am I missing something?
Thanks in advance!
You need the # in the parameter name
cmdData.CreateParameter("#strModel".....

Calling a stored procedure from within a CLR stored procedure with a table valued parameter

The situation:
One Clr stored procedure that builds a data table and then it tries to call an SQL Stored procedure with a TVP parameter.
The code:
public class tvp_test : System.Data.DataTable
{
public tvp_test()
{
this.Column.Add("field1",typeof(System.Int32));
this.Column.Add("field2",typeof(System.Int32));
}
}
.............................................................
{
var tvp = new tvp_test();
.............................................................
using(SqlConnection con = new SqlConnection("context connection=true"))
{
con.Open();
var command = con.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandTest = "prc_test";
command.Parameters.Add("#a",System.Data.SqlDbType.Structured);
command.Parameters["#a"].Value = tvp;
command.ExecuteNonQuery();
con.Close();
}
}
......................................................................
create procedure prc_test
#a tvp_test readonly
begin
insert into #tmp (field1,field2) /* #tmp is created before the call of the CLR SP */
select field1,field2 from #a
end
The problem:
The behavior is erratic. One time it works, after x (where x is random) calls it will give me y (where y is random) "severe error occurred" with no other details, and after that the cycle will start again. From what I see the problem is on the CLR SP side as when errors start to occur, the SQL SP can be changed and be faulty as the error remains the same.
Maybe there is no love between CLR SP and TVPs, but I didn't find any reference to that.
As a side note, when it works it may work for a long time, but if I delete the SPs plan then it will start faulting. (can't find the logic in that "trigger" also)
Any thoughts ?
Thank you in advance.
Looks like this line has an error.
command.CommandTest = "prc_test";
Change it to
command.CommandText = "prc_test";

How to determine if a parameter value was passed to a stored procedure

I want to create a stored procedure (in SQL Server 2008 R2) that will update a record in a table based on the table's PK.
The stored proc will have, for example, four parameters:
#ID int,
#Name nvarchar(50),
#Email nvarchar(80),
#Phone nvarchar(20)
How can I determine if the caller of the stored proc passes a NULL value for one (or more) of the parameters vs. if the caller didn't pass anything for one (or more) of the parameters?
C# caller example:
Caller specifies NULL for #Phone:
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "EditPerson";
cmd.Parameters.AddWithValue("#ID", id);
cmd.Parameters.AddWithValue("#Name", 'Frank');
cmd.Parameters.AddWithValue("#Email", 'frank#frank.com');
cmd.Parameters.AddWithValue("#Phone", DBNull.Value);
DatabaseManager.instance.ExecuteScalarQuery(cmd);
}
Caller ignores the #Phone parameter:
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "EditPerson";
cmd.Parameters.AddWithValue("#ID", id);
cmd.Parameters.AddWithValue("#Name", 'Frank');
cmd.Parameters.AddWithValue("#Email", 'frank#frank.com');
DatabaseManager.instance.ExecuteScalarQuery(cmd);
}
What I'm trying to accomplish here is, if the caller explicitly specifies a NULL value for a parameter, then I will update the record with a NULL value. However, if the user explicitly ignores passing a parameter, then the UPDATE query will retain the value of the field/column that is already set for the particular record (i.e. the query will NOT update that particular column).
I suppose that I could specify default values that can be safely assumed that a caller will never use - something like this:
#ID int,
#Name nvarchar(50) = 'NameIsUndefined',
#Email nvarchar(80) = 'EmailIsUndefined',
#Phone nvarchar(20) = 'PhoneIsUndefined'
Then, in the stored proc, I can check for the undefined values - if the parameter vars are still set to the NameIsUndefined, EmailIsUndefined, and/or PhoneIsUndefined values, then I can safely assume that the caller did not explicitly define values for those params. Is this the only way to accomplish my goal?
If you declare your parameters like this (without default value), the stored proc will require all four of them and will just fail if any of them will not be passed to the EXEC statement composed by the provider.
You may declare some of the parameters optional like this:
#Phone nvarchar(20) = NULL
however, there will be no way to tell inside the sproc if it was omitted or explicitly set to NULL.
There's no way to tell the difference between NULL and NULL in SQL Server, AFAIK.
In your C# code, I would A) Pass another value, like an empty string, to indicate an empty value was passed, then process that in SQL to write NULL to the DB if the value was passed, or retain the previous value if the variable is NULL, or B) Instead of passing DBNull.Value, pass the previous value that was read from the DB.