question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Facil generator fails when stored procedure contains merge statement (odd issue)

See original GitHub issue

Hi,

I spent at least 2 hours on this one.

What do I want to do? I want to generate the code that calls a stored procedure that processes data that is shoved in a sql server temp table.

Here are the files that can help you reproduce the issue:

TempTable1.sql:

CREATE TABLE #TempTable1
(
    Id int NOT NULL PRIMARY KEY
  , Name varchar(30) NOT NULL
);

This file goes under some directory containing sql (I put it under a folder called CreateTable).

in the yaml I have under procedures:

      - include: (?i)^dbo\.spTestFacil$
        tempTables:
          - definition: CreateTable/TempTable1.sql

Here is the stored procedure code:

-- File Name: dbo.spTestFacil.sql
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE OR ALTER PROCEDURE dbo.spTestFacil @psParam nvarchar(50)
as
begin


  DROP TABLE IF EXISTS #TmpJtsSnapshot;

  CREATE TABLE #TmpJtsSnapshot
  (
    Id int NOT NULL PRIMARY KEY
  , Name  varchar(30) NOT NULL

  );


  INSERT INTO #TmpJtsSnapshot ( Id, Name )
  values (1, 'Item 1')

  MERGE INTO #TmpJtsSnapshot AS Target
  USING
  (
    SELECT Id
         , Name
      FROM #TempTable1
  ) AS Source
     ON ( Target.Id = Source.Id )
   WHEN MATCHED THEN
    UPDATE SET Target.Name = Source.Name

   WHEN NOT MATCHED BY TARGET THEN
    INSERT ( Id, Name)
    VALUES
      ( Source.Id, Source.Name );

end
go

When I build the project I get these errors:

   1>Facil : error : System.Exception: Error getting output columns for stored procedure dbo.spTestFacil
          ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name '#TempTable1'.
            at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
            at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
            at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
            at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
            at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
            at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()
            at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
            at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
            at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)
            at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
            at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
            at Facil.Db.getColumnsFromQuery(RuleSet cfg, FSharpChoice`3 executable, SqlConnection conn) in C:\projects\facil\src\Facil.Generator\Db.fs:line 336
            at Facil.Db.getColumns(SqlConnection conn, RuleSet cfg, FSharpMap`2 sysTypeIdLookup, FSharpChoice`3 executable) in C:\projects\facil\src\Facil.Generator\Db.fs:line 403

I was curious and I used the sql server profiler to check what facil executes and it looks like facil executes exec dbo.spTestFacil @psParam=N'1' twice for whatever reason, but before it runs the second time it creates a new connection and it does not create the temp tables.

It’s very odd. Any idea?

For now, to move on, I am going to comment out the bodies of the stored procedures, run the generator, and them add them back. It is a pain but it works.

Thanks

Update: I forgot to include the usual info: .net 6.0, latest version of facil as of today (2.5.4), windows 2016 server. I use rider.net 2022.1.2, sql server 2017.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
cmeerencommented, Jul 12, 2022

Fix published in v2.5.5.

I was curious and I used the sql server profiler to check what facil executes and it looks like facil executes exec dbo.spTestFacil @psParam=N'1' twice for whatever reason, but before it runs the second time it creates a new connection and it does not create the temp tables.

It’s very odd. Any idea?

The bug was that it did not create the temp table the second time (on the second connection).

Opening two connections and executing the sproc twice is as designed. In order to get the result set metadata, Facil tries the following in succession (stopping at whatever works):

  1. sp_describe_first_result_set
  2. Execute sproc/script with SET FMTONLY ON
  3. Execute sproc/script normally

If step 3 is needed, it is performed on a separate connection/transaction (which is rolled back) to ensure there are no changes to the database. The bug was that the creation of the temp tables was not performed in step 3, so if a stored procedure (or script) needed this approach and used temp tables, they would fail with the error you encountered.

0reactions
cmeerencommented, Jul 12, 2022

Feel free, but I am unlikely to add it (was writing a response here, will wait for the separate issue instead), so don’t spend too much time on it.

Read more comments on GitHub >

github_iconTop Results From Across the Web

T-SQL Merge statement in stored procedure throws error
An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look...
Read more >
Merge in stored procedure
I working with oracle through sqlDeveloper software. The error I get is "sql statement ignored". I searched for this and I found that...
Read more >
What To Avoid If You Want To Use MERGE
It's a pretty thorough compilation of all the problems and defects associated with the MERGE statement that folks have reported in the past....
Read more >
CAST throwing error when run in stored procedure but not ...
Something very odd is happening here. I have a query that looks like this. SELECT CAST(FT.DOP AS SMALLINT) ...
Read more >
Updating a distribution key column in a MERGE statement ...
We have an ETL pipeline where one of the steps is failing and this is the error message we are getting. It was...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found