I have here a card that fits in an PCIe slot, with some SMBus controllable chips on it. The card is self layouted and works fine in some older mainboard. In a newer mainboard (ASUS PRIME Z370-A) it is not working.
The card is not using the PCIe Interface only the PCIe Slot. There is no connection between PRSNT1 and 2 and moreover no connection to the differential data lines. The PCIe Slot is only used for power supply (Pins A9, A19, B8 (+3.3V) - A4, A12, A15, A18, B4, B7, B13, B26, B18(GND)) and SMBus interface (B5 (SMCLK), B6 (SMDAT)).
With not working I mean that I can not talk to it via SMBus. I'm trying this with the i2c-dev kernel module. The output of i2cdetect -l is: (shortened, I removed the i2c devs of the nvidia card)
i2c-3 i2c i915 gmbus dpd I2C adapter
i2c-1 i2c i915 gmbus dpc I2C adapteradapter
i2c-4 i2c DPDDC-B I2C adapter
i2c-2 i2c i915 gmbus dpb I2C adapter
i2c-0 smbus SMBus I801 adapter at f040 SMBus adapter
In my opinion the i2c-0 device is the right one. When I run i2cdetect on Interface 0 some chips are detected, but not the right one (they have addr 0x70 and 0x72). To sum up I'm trying to talk via the SMBus master in the Intel 200 PCH with my SMBus slave chips.
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- 08 -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: 30 31 -- -- 34 35 -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- --
50: -- 51 -- 53 -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
I tried also bus 1-4 but the same result. On the other mainboard the detection is working, as you see below.
Furthermore I measured with my oscilloscope on pin B5 and B6 of the PCIe connector. There is no clock or data signal on one of these pins on the new mainboard.
I think I have to configure somehow the kernel module that it also tries to communicate to SMBus devices on the PCIe Slots. Maybe somebody can give me a hint.
Although no warnings about overlapping memory regions have occurred, I set the kernel option acpi_enforce_resources=lax to ensure that no ACPI memory binding conflicts with the SMBus Controller.
Some outputs
dmesg modprobe i2c-i801 (Output of kernel module, that abstracts the Intel SMBus Controller)
[ 81.667581] i801_smbus 0000:00:1f.4: SPD Write Disable is set
[ 81.667639] i801_smbus 0000:00:1f.4: SMBus using PCI interrupt
i2cdetect 0 (Working mainboard, SMBus Controller on i2c-0)
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- 72 -- -- -- -- --
uname -a
Linux XY 4.16.0-1-amd64 #1 SMP Debian 4.16.5-1
I've got an answer from Asus. The ASUS PRIME Z370-A has no SMBus connection on the PCIe Slots.
According to PCIe Card Electromechanical Specification, chapter 2 "Auxiliary Signals", the SMBus interface pins are collectively optional for both the add-in card and the system board. On the other hand PCIe M.2 specification mentiones (this ECN is incorporated in the standard) SMBus wires on boards to be helpful for sensors located on SSD devices.
So, in your case obviously old motherboard is more advanced than the newer one, it has those wirings done.
Related
I am trying to fetch the columns from a previously returned into a table of records. However, when i run the code in the package body I get the following error:
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
However, when i try to do this in a PL/SQL anonymous block window, I can successfully fetch the records using Bulk Collect instruction.
Here is my successful try as I stated:
DECLARE
--
O_ref SYS_REFCURSOR;
-- Variable and types declaration.
TYPE REC_TYP is record (
column_1 number(8),
column_2 varchar2(13)
);
TYPE TAB_TYP is table of REC_TYP;
L_tab_typ TAB_TYP;
--
BEGIN
--
open O_ref for
select sku,
upc
from upc_ean
where sku = 2004030;
--
LOOP
--
FETCH O_ref BULK COLLECT into L_tab_typ;
EXIT WHEN L_tab_typ.COUNT = 0;
--
FOR indx IN 1 .. L_tab_typ.COUNT
LOOP
--
dbms_output.put_line('SKU: ' || L_tab_typ(indx).column_1);
dbms_output.put_line('UPC: ' || L_tab_typ(indx).column_2);
--
END LOOP;
--
END LOOP;
--
CLOSE O_ref;
--
END;
When I run this code I get the following output:
SKU: 2004030
UPC: 5601126003439
SKU: 2004030
UPC: 5601126039056
In the package body I have the following:
Why doesn't this work in a regular package?
FUNCTION GET_STORE_ITEMS(I_store IN number
----------- output ------------
O_item_data OUT NB_TAB_ITEM_DETAIL, -- i want to return a table type after I get the info from the sys_ref
----------- error -------------
O_error_message OUT VARCHAR2)
RETURN BOOLEAN IS
--
L_tab_type NB_TAB_ITEM_DETAIL;
L_sys_ref SYS_REFCURSOR;
L_test_sku number(8);
--
CURSOR C_GET_ITEMS IS
--
SELECT a.sku
FROM win_store a
WHERE a.store = I_store;
--
BEGIN
--
-- Loop over the fashion skus.
FOR R_items IN C_GET_ITEMS LOOP
--
BEGIN
--
IF GET_ITEM_DETAIL(I_store => I_store,
I_sku => R_items.sku,
O_item_data => L_sys_ref, -- returns a sys_refcursor with the same structure as the type
O_error_message => L_error_message) = FALSE THEN
--
O_error_message := NB_MESSGE40_SQL.EMESSAGE(L_error_message);
RETURN FALSE;
--
END IF;
--
LOOP
--
FETCH L_sys_ref BULK COLLECT into L_tab_type; -- It jumps to when others exception
EXIT WHEN L_tab_type.COUNT = 0;
--
FOR indx IN 1 .. L_tab_type.COUNT
LOOP
--
L_test_sku := L_tab_type(indx).sku;
--
END LOOP;
--
END LOOP;
--
END;
--
END LOOP;
--
RETURN TRUE;
--
EXCEPTION
--
WHEN OTHERS THEN
--
-- ...
RETURN FALSE;
--
END GET_STORE_ITEMS;
Thank you!
I actually happened to solve the problem. It was necessary to declare a package-spec level type before fetching the sys_refcursor, just like it was done in the anonymous block.
At first, the record and table types were created in the database:
CREATE OR REPLACE TYPE NB_REC_ITEM_DETAIL AS OBJECT
(
column_1 number(8),
column_2 varchar2(13)
);
CREATE OR REPLACE TYPE NB_TAB_ITEM_DETAIL AS TABLE OF NB_REC_ITEM_DETAIL;
However, this structure is unknown for the PL/SQL engine and so it is necessary to create these data structures in the package spec as follows:
TYPE REC_TYP is record (
column_1 number(8),
column_2 varchar2(13)
);
TYPE TAB_TYP is table of REC_TYP;
Now it is possible to fetch the data from the sys_refcursor.
FUNCTION GET_STORE_ITEMS(I_store IN NUMBER,
----------- output ------------
O_item_data OUT NB_TAB_ITEM_DETAIL,
----------- error -------------
O_error_message OUT VARCHAR2)
RETURN BOOLEAN IS
--
L_error_message VARCHAR2(255);
L_item_data_rec REC_TYP;
L_item_detail_ref SYS_REFCURSOR;
--
CURSOR C_GET_STORE_ITEMS IS
--
SELECT a.sku
FROM win_store a
WHERE a.store = I_store;
--
BEGIN
--
-- Instantiate output structure object.
--
O_item_data := NB_TAB_ITEM_DETAIL();
--
-- Loop over the items in the store range.
--
FOR R_items IN C_GET_STORE_ITEMS LOOP
--
BEGIN
--
IF NB_ITEM_INFO_SQL.GET_ITEM_DETAIL(I_store => I_store,
I_sku => R_items.sku,
I_ean => NULL,
O_item_data => L_item_detail_ref,
O_error_message => L_error_message) = FALSE THEN
--
O_error_message := NB_MESSGE40_SQL.EMESSAGE(L_error_message);
RETURN FALSE;
--
END IF;
--
-- Fetch info from item_data sys_refcursor to record type.
--
FETCH L_item_detail_ref INTO L_item_data_rec;
EXIT WHEN L_item_detail_ref%NOTFOUND;
--
CLOSE L_item_detail_ref;
--
O_item_data.extend();
O_item_data(O_item_data.last) := nb_rec_item_detail(column_1 => L_item_data_rec.column_1 ,
column_2 => L_item_data_rec.column_2);
--
END;
--
END LOOP;
--
RETURN TRUE;
--
EXCEPTION
--
WHEN OTHERS THEN
-- ...
RETURN FALSE;
--
--
END GET_STORE_ITEMS;
I've found a few other people ask about this, but all of them are coding in Arduino, and I'm struggling to translate it into my project.
I'm on a research team developing a Cube Satellite for launch, and my role is to communicate with the peripherals, including the IMU (MPU-9250). I'm cross compiling with uClinux, coding in C.
So far, I can successfully read the accelerometer, gyroscope, and temperature, but cannot get the readings from the magnetometer. The magnetometer (AK8963) has its own address (0x0C), and I've been trying to communicate with it by writing to I2C_SLV0_ADDR(0x25), I2C_SLV0_REG(0x26), and I2C_SLV0_CTRL(0x27). Once I didn't appear to get any results, I tried to resolve it by writing to FIFO Enable(0x23) and I2C Master Control(0x24)
The datasheet and register map imply that the values taken from the magnetometer are stored in registers External Sensor Data(0x49-0x60), but I'm not getting anything in those registers when I try this.
Here's some code that shows the data I'm writing to the registers:
write_register(0x23, 0x04);
write_register(0x24, 0b11110000);
write_register(0x25,0x8c);
write_register(0x26,0x00);
write_register(0x27,0b11110001);
So my questions are:
1. Am I going about this process the right way, or am I completely off?
If I am on the right track, am I reading from the correct registers?
Thanks for your help everyone! Let me know if there's anything I need to clarify!
Alright! I figured out my own question :)
1) I was indeed going about the process the wrong way. There is a much easier way to do that and I will show how in detail.
2) I was not reading from the correct registers. I'll show what to do below.
So, connecting to the Magnetometer is super easy, but not intuitive at all. It does act like its own slave with its own slave address, but that address is inaccessible initially.
Since I'm cross compiling with uClinux, I can use the bash command i2cdetect 0 (when screening into my SmartFusion2) to check all the slaves on my i2C 0 bus. When I execute this command after resetting my board, I get the following address map printed out:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
So you can see that only the address for the IMU(0x68) is showing. To get the magnetometer showing up properly, you have to enable a bypass bit on INT_PIN_CFG(0x37). I've attached my code below in case anyone needs to replicate this.
#include <stdio.h>
//#include <linux/i2c-dev.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define IMU_ADDR 0x68
#define IMU_WHO_AM_I 0x75
int file;
void i2c_init();
void write_register(uint8_t register_address, uint8_t value);
uint8_t read_register(uint8_t register_address);
void i2c_init(address){
int adapter_nr = 0;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if(file < 0)
printf("Error: Failed to open file %s\n", filename);
int success= (ioctl(file, I2C_SLAVE, address));
if(file < 0) {
printf("Error: IMU I2C Failed to Open\n");
//return -1;
}
}
void write_register(uint8_t register_address, uint8_t value){
uint8_t data[]={register_address,value};
write(file, data,ARRAY_SIZE(data));
}
uint8_t read_register(uint8_t register_address){
uint8_t value;
if(write(file, ®ister_address, sizeof(register_address)) !=1)
{
printf("%d\n",write(file, ®ister_address, sizeof(register_address)));
printf("Failed to send data\n");
}
read(file, &value, sizeof(value));
return value;
}
int main(){
i2c_init(IMU_ADDR);
printf("\nNow testing the 'Who am I?' IMU register. Output should be 0x71\n");
printf("Register 0x75: 0x%02X \n", read_register(IMU_WHO_AM_I));
write_register(0x37, 0x22);
i2c_init(0x0C);
printf("\nNow testing the 'Who am I?' Magnetometer register. Output should be 0x48\n");
printf("Register 0x00: 0x%02x\n", read_register(0x00));
return 0;
}
Once the code is compiled and run, the command i2cdetect 0 returns the following datamap.
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- 0c -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
The program also returns 0x48, the correct value when reading from the magnetometer's 'who am I?' register. The magnetometer can now be read just like any other register. Hope this helps!!
Background:
This is a multi-tenant application, so that a normal identity column will not work. All tables have a unique client identifier Clients.id. So each client can have many customers. This column is not included below for simplicity.
We want to generate a unique customer number starting at 1000.
We store the current (last) generated number in a table called Master. Let's say Master.CustomerNumber. So numbers will go 1001, 1002 etc. and the last one is stored there.
So each time we add a customer, we have a query that looks up the current value, increment it, and insert it in Customer.Number.
NOTE: we are using SQL Server 2008. We have multiple servers in a cluster.
What is the best approach to insure that if two customers are added at the same time that each gets a unique customer number? Stored procedure, locking, CFLOCKING?
How do I insure that this process is 'single-threaded' and that the same number is not issued twice?
I do have a unique index on Customer.Number+Clients.id. I am interested in the implementation of how to guarantee uniqueness when generated.
I have not reviewed the existing solutions because they are quite long and elaborate. Wouldn't the following be all you need?
CREATE TABLE MasterDB.dbo.Sequences (ClientId INT NOT NULL PRIMARY KEY, LastGeneratedNumber INT NOT NULL)
DECLARE #nextId INT; //Holds the newly allocated ID
UPDATE MasterDB.dbo.Sequences
SET LastGeneratedNumber = LastGeneratedNumber + 1, #nextId = LastGeneratedNumber + 1
WHERE ClientId = 1234
This is correct under any isolation level and any index structure. The row holding the ID information will be U or X locked by the engine.
In case there never has been an ID generated this update statement will not do anything. You can solve that by using MERGE or by using control flow. I recommend MERGE.
Or, you insert a row whenever you create a new client. Set LastGeneratedNumber = 1000 - 1.
There is no need to use stored procedures but you certainly can. There is almost no performance difference to executing this T-SQL as a batch from the application. Do what's more convenient to you.
If you make this T-SQL part of your main transaction the ID assignment will be transactional. It will potentially roll back and it will serialize customer creation. If you don't like that use a separate transaction. That way IDs might be lost, though. This is unavoidable in any solution.
A variation the UPDATE given above is:
UPDATE MasterDB.dbo.Sequences
SET LastGeneratedNumber = LastGeneratedNumber + 1
OUTPUT INSERTED.LastGeneratedNumber
WHERE ClientId = 1234
You could use one sequence per client. This requires that your application executes DDL. This can be awkward. Also, you cannot make ID generation transactional. There is less control. I would not recommend that but it's possible.
You could use following solution:
CREATE TABLE dbo.[Master] (
-- Foreign key to dbo.Tenant table ?
-- Only one row for every tenant is allowed => PK on tenant identifier
TenantNum INT NOT NULL
CONSTRAINT PK_Master PRIMARY KEY CLUSTERED (TenantNum),
-- LastCustomerNum = last generated value for CustomerNum
-- NULL means no value was generated
LastCustomerNum INT NULL,
-- It will create one clustered unique index on these two columns
InitialValue INT NOT NULL
CONSTRAINT DF_Master_InitialValue DEFAULT (1),
Step INT NOT NULL
CONSTRAINT DF_Master_Step DEFAULT (1)
);
GO
CREATE PROCEDURE dbo.p_GetNewCustomerNum
#TenantNum INT,
#NewCustomerNum INT OUTPUT,
#HowManyCustomerNum INT = 1 -- Ussualy, we want to generate only one CustomerNum
AS
BEGIN
BEGIN TRY
IF #TenantNum IS NULL
RAISERROR('Invalid value for #TenantNum: %d', 16, 1, #TenantNum);
IF #HowManyCustomerNum IS NULL OR #HowManyCustomerNum < 1
RAISERROR('Invalid value for #HowManyCustomerNum: %d', 16, 1, #HowManyCustomerNum)
-- It updated the LastCustomerNum column and it assign the new value to #NewCustomerNum output parameter
UPDATE m
SET #NewCustomerNum
= LastCustomerNum
= CASE WHEN LastCustomerNum IS NULL THEN InitialValue - Step ELSE LastCustomerNum END
+ Step * #HowManyCustomerNum
FROM dbo.[Master] AS m
WHERE m.TenantNum = #TenantNum
IF ##ROWCOUNT = 0
RAISERROR('#TenantNum: %d doesn''t exist', 16, 1, #TenantNum);
END TRY
BEGIN CATCH
-- ReThrow intercepted exception/error
DECLARE #ExMessage NVARCHAR(2048) = ERROR_MESSAGE()
RAISERROR(#ExMessage, 16, 1)
-- Use THROW for SQL2012+
END CATCH
END
GO
Usage (no gaps):
BEGIN TRAN
...
DECLARE #cn INT
EXEC dbo.p_GetNewCustomerNum
#TenantNum = ...,
#NewCustomerNum = #cn OUTPUT,
[#HowManyCustomerNum = ...]
...
INSERT INTO dbo.Customer(..., CustomerNum, ...)
VALUES (..., #cs, ...)
COMMIT
Note: if you don't use transactions to generate the new customer number and then to insert this values into Customer table then they could get gaps.
How it works ?
{Primary key | Unique index} defined on TenantNum and CustomerNum will prevent any duplicates
Under default isolation level (READ COMMITTED) but also under READ UNCOMMITTED, REPETABLE READ and SERIALIZABLE, the UPDATE statement require and X lock. If we have two concurent SQL Server sessions (and transactions) which try to generate a new CustomerNum then first session will successfully get the X lock on tenant row and the second session will have to wait till first session (and transaction) will end (COMMIT or ROLLBACK). Note: I assumed that every session has one active transaction.
Regarding X lock behavior: this is possible because two [concurent] X locks are incompatibles. See table bellow with "Requested mode" and [Granted mode]:
For above reasons, only one connection/TX can update within dbo.[Master] a tenant row with a new customer number.
-- Tests #1
-- It insert few new and "old" tenants
INSERT dbo.[Master] (TenantNum) VALUES (101)
INSERT dbo.[Master] (TenantNum, LastCustomerNum) VALUES (102, 1111)
SELECT * FROM dbo.[Master]
/*
TenantNum LastCustomerNum InitialValue Step
----------- --------------- ------------ -----------
101 NULL 1 1
102 1111 1 1
*/
GO
-- It generate one CustomerNum for tenant 101
DECLARE #cn INT
EXEC p_GetNewCustomerNum 101, #cn OUTPUT
SELECT #cn AS [cn]
/*
cn
-----------
1
*/
GO
-- It generate second CustomerNums for tenant 101
DECLARE #cn INT
EXEC p_GetNewCustomerNum 101, #cn OUTPUT
SELECT #cn AS [cn]
/*
cn
-----------
2
*/
GO
-- It generate three CustomerNums for tenant 101
DECLARE #cn INT
EXEC p_GetNewCustomerNum 101, #cn OUTPUT, 3
SELECT #cn AS [cn]
/*
cn
-----------
5 <-- This ID means that following range was reserved [(5-3)+1, 5] = [3, 5] = {3, 4, 5}; Note: 1 = Step
*/
GO
-- It generate one CustomerNums for tenant 102
DECLARE #cn INT
EXEC p_GetNewCustomerNum 102, #cn OUTPUT
SELECT #cn AS [cn]
/*
cn
-----------
1112
*/
GO
-- End status of Master table
SELECT * FROM dbo.Master
/*
TenantNum LastCustomerNum InitialValue Step
----------- --------------- ------------ -----------
101 5 1 1
102 1112 1 1
*/
GO
.
-- Tests #2: To test concurent sesssions / TX you could use bellow script
-- Step 1: Session 1
BEGIN TRAN
-- It generate three CustomerNums for tenant 101
DECLARE #cn INT
EXEC p_GetNewCustomerNum 101, #cn OUTPUT
SELECT #cn AS [cn] -- > It generates #cn 6
-- Step 2: Session 2
BEGIN TRAN
-- It generate three CustomerNums for tenant 101
DECLARE #cn INT
EXEC p_GetNewCustomerNum 101, #cn OUTPUT -- Update waits for Session 1 to finish
SELECT #cn AS [cn]
COMMIT
-- Step 3: Session 1
COMMIT -- End of first TX. Check Session 2: it'll output 7.
First end note: to manage transactions and exceptions I would use SET XACT_ABORT ON and/or BEGIN TRAN ... END CATCH. Discussion about this topic is beyond the the purpose of this answer.
Second end note: see updated section "How it works ?" (bullet 3 and 4).
I know this is little bit late, but still hope it helps you :)
We do have same situation over here...
And we solved it by having a common table in a separate database, which contains only three columns (i.e. tablename, columnname and LastIndex).
Now, we use a separate SP to always getting new number from this table with separate transaction (as it should always commit, regardless your main Insert function true/false).
So, this will always return with new ID to any request, and that new Index will be used for inserting a record.
Let me know if you need any sample on this.
You want to use a Sequence, for example:
CREATE SEQUENCE Customer_Number_Seq
AS INTEGER
START WITH 1
INCREMENT BY 1
MINVALUE 1000
MAXVALUE 100
CYCLE;
and then possibly something like :
CREATE TABLE Customers
(customer_nbr INTEGER DEFAULT NEXT VALUE FOR Customer_Number_Seq,
.... other columns ....
The documentation has more details.
using select statement we can call functions inside the stored procedure, is there another ways to call functions inside the stored procedure.
getdate() you can call inside a proc
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE Proc1
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
declare #date datetime
set #date= getdate()
END
GO
try
SET #yourvariable = yourfunctionname('your params');
Function
create function fn_FunctionSum(#Number1 int , #Number2 int)
returns int
as
begin
declare #result int
select #result = #Number1 + #Number2;
return #result
end
Store Procedure
create proc sp_Sum(#first int, #second int )
as
begin
-------Call Function in store procedure ------
select [dbo].[fn_FunctionSum](#first, #second)
end
execute sp_Sum 2,5
Once again.. i have the trigger below which has the function to keep/set the value in column esb for maximum 1 row to value 0 (in each row the value cycles from Q->0->R->1)
When i insert more than 1 row the trigger fails with an "Subquery returned more than 1 value. This is not permitted when the subquery follows" error on row 38, the "IF ((SELECT esb FROM INSERTED) in ('1','Q'))" statment.
I understand that 'SELECT esb FROM INSERTED' will return all rows of the insert, but do not know how to process one row at a time. I also tried it by creating a temporary table and iterating through the resultset, but subsequently found out that temporary tables based on the INSERTED table are not allowed.
any suggestions are welcome (again)
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER TRIGGER [TR_PHOTO_AIU]
ON [SOA].[dbo].[photos_TEST]
AFTER INSERT,UPDATE
AS
DECLARE #MAXCONC INT -- Maximum concurrent processes
DECLARE #CONC INT -- Actual concurrent processes
SET #MAXCONC = 1 -- 1 concurrent process
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
-- If column esb is involved in the update, does not necessarily mean
-- that the column itself is updated
If ( Update(ESB) )
BEGIN
-- If column esb has been changed to 1 or Q
IF ((SELECT esb FROM INSERTED) in ('1','Q'))
BEGIN
-- count the number of (imminent) active processes
SET #CONC = (SELECT COUNT(*)
FROM SOA.dbo.photos_TEST pc
WHERE pc.esb in ('0','R'))
-- if maximum has not been reached
IF NOT ( #CONC >= #MAXCONC )
BEGIN
-- set additional rows esb to '0' to match #MAXCONC
UPDATE TOP(#MAXCONC-#CONC) p2
SET p2.esb = '0'
FROM ( SELECT TOP(#MAXCONC-#CONC) p1.esb
FROM SOA.dbo.photos_TEST p1
INNER JOIN INSERTED i ON i.Value = p1.Value
AND i.ArrivalDateTime > p1.ArrivalDateTime
WHERE p1.esb = 'Q'
ORDER BY p1.arrivaldatetime ASC
) p2
END
END
END
Try to rewrite your IF as:
IF EXISTS(SELECT 1 FROM INSERTED WHERE esb IN ('1','Q'))
...