Sybase read row with WriteNoPK using iSQL - sybase

i'm using Sybase SQL Anywhere 12. Let me say I have a Table user with the following connections to it:
conn_name conn_id user_id table_type creator table_name index_id lock_class lock_duration lock_type row_identifier
SQL_DBC_a2a1060 3193 DBA BASE DBA user (NULL) Row Transaction WriteNoPK 37431476262
SQL_DBC_a2a1060 3193 DBA BASE DBA user (NULL) Row Transaction Intent 45309427737
SQL_DBC_a2a1060 3193 DBA BASE DBA user (NULL) Row Transaction WriteNoPK 45309427737
SQL_DBC_a2a1060 3193 DBA BASE DBA user (NULL) Row Transaction Intent 37399035938
SQL_DBC_a2a1060 3193 DBA BASE DBA user (NULL) Row Transaction WriteNoPK 37399035938
SQL_DBC_a2a1060 3193 DBA BASE DBA user (NULL) Row Transaction Intent 37399035939
If I'm now going to SELECT * FROM user from within Sybase SQL Anywhere I'll get all rows and data as expected.
But if i'm going to fire the same SQL-Statement using the DBA-User in iSQL on OpenSuse 11.4, the Statement runs and I receive results till the row which is going to be selected has the WriteNoPK-Lockflag set.
The Statement than states the follwoing error:
Server message number=8405 severity=21 state=0 line=0 text=SQL Anywhere Error -210: User 'XYZ' has the row in 'user' locked , SQL: 'SELECT * FROM user'
Is there a possibility to read/select even if the row is WriteNoPK-Locked?
Many thanks,
Max

This is a result of the isolation level of your connection. The row is update locked, which prevents other processes from getting a possible 'dirty read' (e.g. reading an updated value that has not been committed, and could be rolled back)
To view your current isolation level:
SELECT CONNECTION_PROPERTY('isolation_level');
This section in the SQLAnywhere docs talks about the different isolation level settings, and how to change them. Isolation level 0, or 1 would probably allow your read to continue, but with some risk. You may also want to check out the snapshot isolation setting to see if it might suit your needs.
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.sqlanywhere.12.0.1/dbusage/udtisol.html

Related

Failed assembly deploy due to non-matching SIDs

Database names and logins are anonymized in what follows. There are some answers
on SO that are similar to this situation, but not exactly the same, hence my question.
Attempting to deploy an assembly to production database FOO_PROD fails with message:
Msg 33009, Level 16, State 2, Line 17
The database owner SID recorded in the master database differs from the
database owner SID recorded in database 'FOO_PROD'. You should correct
this situation by resetting the owner of database 'FOO_PROD' using the
ALTER AUTHORIZATION statement.
Indeed, the following two queries demonstrate the difference in SID.
First, we look at the SID of FOO_PROD:
SELECT SD.[SID],
SL.Name as [LoginName]
FROM master..sysdatabases SD INNER JOIN master..syslogins SL
on SD.SID = SL.SID
WHERE SD.Name = 'FOO_PROD'
which shows the result of:
SID, LoginName
0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000, BATZ\boink
Second, we look at the SID of FOO_PROD in the master database:
SELECT SD.[SID],
SL.Name as [LoginName]
FROM master..sysdatabases SD INNER JOIN master..syslogins SL
on SD.SID = SL.SID
WHERE SD.Name = 'master'
which shows the result of:
SID, LoginName
0x01, [sa]
We notice that indeed, just as Visual Studio complained, the SIDs do not
match. They must be made to match in order to proceed (apparently).
Constraints: The SID on FOO_PROD cannot be changed because several other systems
that use the database expect it to have the SID and LoginName it currently has.
Question 1: Is the solution then to change the SID, LoginName on the master database? Would
it hurt anything or be a bad idea to do so?
Say you respond that it is ok to change the SID, LoginName on master, then,
how does one make the change to the 'master' database? Well, I've
not done it before, but candidate solutions and commentary can be found here:
The database owner SID recorded in the master database differs from the database owner SID
However, this situation is different from those presented in the link above, I
think, in that the change must happen to/on the master database ala:
exec sp_changedbowner [BATZ\boink]
Question 2: Is that the correct way to do it?
Naturally I'll check with stakeholders if such a change to master database will
cause undesired outcomes, but I hope to get some guidance here before I even
check on that.
Update based on #srutzky's updated answer:
-- Step 1
SELECT sd.[name], sd.[owner_sid], sp.[name]
FROM sys.databases sd
INNER JOIN sys.server_principals sp
ON sp.[sid] = sd.[owner_sid]
WHERE sd.[name] = N'FOO_PROD';
returns:
name, owner_sid, name
FOO_PROD, 0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000, BATZ\boink
Then
-- Step 2
USE [FOO_PROD];
SELECT dp.[sid], sp.[name]
FROM sys.database_principals dp
INNER JOIN sys.server_principals sp
ON sp.[sid] = dp.[sid]
WHERE dp.[name] = N'dbo';
returns:
sid, name
0x01, sa
Yes, the SIDs really do need to match as a mismatch is an indication of a potentially harmful DB being restored to the instance; this is a safe-guard.
BUT, first we need to know exactly what we are looking at. While there is definitely a mismatch in the owner SIDs between the record in FOO_PROD and the record in master (hence the error message), your queries are not looking at the value in FOO_PROD. Your two queries are looking at the value in master for the owner of FOO_PROD, and in master (again) for the owner of master (entirely irrelevant here), respectively.
Step 1
Do not use sys* objects for anything as those are compatibility Views so that older stuff written for SQL Server 2000 and prior still work (well, dbo.sys* tables in msdb are still valid). Starting with SQL Server 2005, only sys.* objects (no need to specify master.) should be used. Meaning, use:
SELECT sd.[name], sd.[owner_sid], sp.[name]
FROM sys.databases sd
INNER JOIN sys.server_principals sp
ON sp.[sid] = sd.[owner_sid]
WHERE sd.[name] = N'FOO_PROD';
Step 2
You need to check the value IN the database itself for the owner's SID as it has it recorded, which is not in sys.databases (or even in master..sysdatabases). When checking the Database's value for it's owner, you need to look in sys.database_principals for the dbo User as follows:
USE [FOO_PROD];
SELECT dp.[sid], sp.[name]
FROM sys.database_principals dp
INNER JOIN sys.server_principals sp
ON sp.[sid] = dp.[sid]
WHERE dp.[name] = N'dbo';
Step 3
Using sp_changedbowner is required if you are on SQL Server 2005, but starting with SQL Server 2008 that stored procedure is deprecated in favor of the newer ALTER AUTHORIZATION (though it still works). But yes, this is the way to make them the same as it will sync both locations to whichever Login you specify.
However, you need to make sure that BATZ\boink is a valid Windows Login for the domain that the SQL Server instance belongs to, AND that this particular Windows Login has an SID of 0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000. If the Login does not exist, hopefully you will be able to create it via CREATE LOGIN.
Since the owner in the database is SA, and you want to change the owner recorded in Master to SA, just run
alter authorization on database::[foo_prod] to sa

How to overcome "Failure getting record lock on a record from table"?

I am running a query using OpenQuery and getting a peculiar error.
This is my query:
select * from OpenQuery("CAPITAOC",'SELECT per.*
FROM pub."re-tenancy" AS t
INNER JOIN pub."re-tncy-person" AS per
ON t."tncy-sys-ref" = per."tncy-sys-ref"
INNER JOIN pub."re-tncy-place" AS place
ON t."tncy-sys-ref" = place."tncy-sys-ref"
WHERE t."tncy-status" = ''CUR'' and place."place-ref"=''GALL01000009''')
This is the error message:
OLE DB provider "MSDASQL" for linked server "CAPITAOC" returned message "[DataDirect][ODBC Progress OpenEdge Wire Protocol driver][OPENEDGE]Failure getting record lock on a record from table PUB.RE-TNCY-PERSON.".
OLE DB provider "MSDASQL" for linked server "CAPITAOC" returned message "[DataDirect][ODBC Progress OpenEdge Wire Protocol driver]Error in row.".
Msg 7330, Level 16, State 2, Line 1
Cannot fetch a row from OLE DB provider "MSDASQL" for linked server "CAPITAOC".
How do I read this data?
The record lock error:
In a multi-user environment it is useful to lock records that are being updated to prevent an other user session from accessing that record. This prevents a "dirty read" of your data.
To overcome this issue, I suggest looking at this article :
http://knowledgebase.progress.com/articles/Article/20255
The Transaction Isolation Level must be set prior to any other
transactions within the session.
And this is how you find out WHO has locked your record :
http://knowledgebase.progress.com/articles/Article/19833
Also, I would like to suggest that if you are using something like SQL explorer which does not Auto-commit your updates unless you ask it to, then the database table might be locked until you commit your changes.
I ran across this issue as well and the other answer's links were not as helpful as I had hoped. I used the following link: https://knowledgebase.progress.com/articles/Article/P12158
Option #1 - applies from OpenEdge 10.1A02 and later.
Use the WITH (NOLOCK) hint in the SELECT query. This ensures that no record locks are acquired. For example,
SELECT * FROM pub.customer WITH (NOLOCK);
The WITH (NOLOCK) hint is similar to using the Read Uncommitted isolation level in that it will result in a dirty read.
Option #2 - applies to all OpenEdge (10.x/11.x) versions using the Read Committed isolation level.
Use the WITH (READPAST) hint in the SELECT query. This option causes a transaction to skip rows locked by other transactions that would ordinarily appear in the result set, rather than block the transaction waiting for the other transactions to release their locks on these rows. For example,
SELECT * FROM pub.customer WITH (READPAST NOWAIT);
SELECT * FROM pub.customer WITH (READPAST WAIT 5);
Please be aware that this can lead to fewer records being returned than expected since locked records are skipped/omitted from the result set.
Option #3 - applies to all Progress/OpenEdge versions.
Change the Isolation Level to Read Uncommitted to ensure that, when a record is read, no record locks are acquired. Using the Read Uncommitted isolation level will result in a dirty read.
This can be done at ODBC DSN level or via the SET TRANSACTION ISOLATION LEVEL <isolation_level_name> statement. For example,
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Option 1 worked for me.

Count number of rollbacks in SQL Sever 2008

I am experimenting with the SET-OPTION XACT_ABORT ON as I am seeing a lot of sleeping sessions holding an open transaction causing problems in the application.
Is there a way to measure if flipping the option has an effect or not? I am thinking about something like number of rollbacks per day. How could I collect these?
I am on SQL Server 2008 SP4.
Considering your database is in Full Recovery Model.You can combine all the transaction log backups taken per day and Query it...
SELECT
CASE
WHEN OPERATION='LOP_ABORT_XACT' THEN 'COMMITS'
ELSE 'ROLLBACKS' END AS 'OPERATIONS'
,COUNT(*) AS CNT
FROM FN_DBLOG(NULL,NULL) WHERE OPERATION IN ('LOP_COMMIT_XACT','LOP_ABORT_XACT')
GROUP BY OPERATION
I did some tests using some sample data..
Begin tran test1
insert into t1
select 3
rollback
Output:
Operations cnt
Commits 3
RollBacks 4
Update as per comments:
Reading Transaction log Backup can be expensive ,I recommend you do this on backups taken and not on Active log ..doing this on active Tlog can have below effects
1.since this does a Log Scan,Transaction log truncation will be prevented
2.Huge IO load on server depending on Your log backup Size,since the output of ::fn_dblog can easily go into millions of rows
References:
http://rusanu.com/2014/03/10/how-to-read-and-interpret-the-sql-server-log/
https://blogs.msdn.microsoft.com/dfurman/2009/11/05/reading-database-transaction-log-with-fn_dump_dblog/

Tracking User activity log for SQL Server database

I have a database with multiple tables and I want to log the users activity via my MVC 3 web application.
User X updated category HELLO. Name changed from 'HELLO' to 'Hi There' on 24/04/2011
User Y deleted vehicle Test on 24/04/2011.
User Z updated vehicle Bla. Name changed from 'Blu' to 'Bla' on 24/04/2011.
User Z updated vehicle Bla. Wheels changed from 'WheelsX' to 'WheelsY' on 24/04/2011.
User Z updated vehicle Bla. BuildProgress changed from '20' to '50' on 24/04/2011
My initial idea is to have on all of my actions that have database crud, to add a couple lines of code that would enter those strings in a table.
Is there a better way of checking which table and column has been modified than to check every column one by one with if statements (first I select the current values, then check each of them with the value of the textbox) I did that for another ASPX web app and it was painful.
Now that I'm using MVC and ADO.NET Entity Data Model I'm wondering if a faster way to find the columns that were changed and build a log like the one above.
You can also accomplish this by putting your database into full recovery mode and then reading the transaction log.
When database is in a full recovery mode then sql server logs all Update, insert and delete (and others such as create, alter, drop..) statements into it's transaction log.
So, using this approach you dont need to make any additinal changes to your application or your database structure.
But you will need 3rd party sql transaction log reader. Red gate has a free solution for sql server 2000 only. If your server is 2005 or higher you would probably want to go with ApexSQL Log
Also, this approach will not be able to audit select statements but it's definately the easiest to implement if you dont really need to audit select queries.
The way I see, you have two options:
Create triggers in the database side, mapping changes in a table by table basis and getting result into a Log table
OR
Having the code handle the changes. You would have a base class with data and with reflection you could iterate all object properties and see what has changed. And then save that into your Log table. Of course, that coding would be on your Data Access Layer.
By the way, if you have a good code structure/architecture, I would go with the second option.
You could have a trigger (AFTER insert/update/deelte) on each table you want to monitor. The beauty is columns_updated() which returns a barbinary value, indicating which columns have been updated.
Here is some snippet of code that I put in each trigger:
IF (##ROWCOUNT = 0) return
declare #AuditType_ID int ,
#AuditDate datetime ,
#AuditUserName varchar(128),
#AuditBitMask varbinary(10)
select #AuditDate = getdate() ,
#AuditUserNAme = system_user,
#AuditBitMask = columns_updated()
-- Determine modification type
IF (exists (select 1 from inserted) and exists (select 1 from deleted))
select #AuditType_ID = 2 -- UPDATE
ELSE IF (exists (select * from inserted))
select #AuditType_ID = 1 -- INSERT
ELSE
select #AuditType_ID = 3 -- DELETE
(record this data to your table of choice)
I have a special function that can decode the bitmask values, but for some reason it is not pasting well here. Message me and I'll email it to you.

SQL Server COMPILE locks?

SQL Server 2000 here.
I'm trying to be an interim DBA, but don't know much about the mechanics of a database server, so I'm getting a little stuck. There's a client process that hits three views simultaneously. These three views query a remote server to pull back data.
What it looks like is that one of these queries will work, but the other two fail (client process says it times out, so I'm guessing a lock can do that). The querying process has a lock that sticks around until the SQL process is restarted (I got gutsy and tried to kill the spid once, but it wouldn't let go). Any queries to this database after the lock hang, and blame the first process for blocking it.
The process reports these locks... (apologies for the formatting, the preview functionality shows it as fully lined up).
spid dbid ObjId IndId Type Resource Mode Status
53 17 0 0 DB S GRANT
53 17 1445580188 0 TAB Sch-S GRANT
53 17 1445580188 0 TAB [COMPILE] X GRANT
I can't analyze that too well. Object 1445580188 is sp_bindefault, a system stored procedure in master. What's it hanging on to an exclusive lock for?
View code, to protect the proprietary...I only changed the names (they stayed consistent with aliases and whatnot) and tried to keep everything else exactly the same.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER view [dbo].[theView]
as
select
a.[column1] column_1
,b.[column2] column_2
,[column3]
,[column4]
,[column5]
,[column6]
,[column7]
,[column8]
,[column9]
,[column10]
,p.[column11]
,p.[column12]
FROM
[remoteServer].db1.dbo.[tableP] p
join [remoteServer].db2.dbo.tableA a on p.id2 = a.id
join [remoteServer].db2.dbo.tableB b on p.id = b.p_id
WHERE
isnumeric(b.code) = 1
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
Take a look at this link. Are you sure it's views that are blocking and not stored procedures? To find out, run this query below with the ObjId from your table above. There are things that you can do to mitigate stored procedure re-compiles. The biggest thing is to avoid naming your stored procedures with an "sp_" prefix, see this article on page 10. Also avoid using if/else branches in the code, use where clauses with case statements instead. I hope this helps.
[Edit]:
I believe sp_binddefault/rule is used in conjunction with user defined types (UDT). Does your view make reference to any UDT's?
SELECT * FROM sys.Objects where object_id = 1445580188
Object 1445580188 is sp_bindefault in the master database, no? Also, it shows resource = "TAB" = table.
USE master
SELECT OBJECT_NAME(1445580188), OBJECT_ID('sp_bindefault')
USE mydb
SELECT OBJECT_NAME(1445580188)
If the 2nd query returns NULL, then the object is a work table.
I'm guessing it's a work table being generated to deal with the results locally.
The JOIN will happen locally and all data must be pulled across.
Now, I can't shed light on the compile lock: the view should be compiled already. This is complicated by the remote server access and my experience of compile locks is all related to stored procs.

Resources