Index: backend/postmaster/postmaster.c =================================================================== RCS file: /home/snaga/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 postmaster.c *** backend/postmaster/postmaster.c 10 Jun 2004 00:22:29 -0000 1.1.1.1 --- backend/postmaster/postmaster.c 18 Jun 2004 03:17:22 -0000 *************** *** 2418,2424 **** * after a time delay, so that a broken client can't hog a connection * indefinitely. PreAuthDelay doesn't count against the time limit. */ ! if (!enable_sig_alarm(AuthenticationTimeout * 1000, false)) elog(FATAL, "could not set timer for authorization timeout"); /* --- 2418,2424 ---- * after a time delay, so that a broken client can't hog a connection * indefinitely. PreAuthDelay doesn't count against the time limit. */ ! if (!enable_sig_alarm(AuthenticationTimeout * 1000, false, false)) elog(FATAL, "could not set timer for authorization timeout"); /* *************** *** 2447,2453 **** * Done with authentication. Disable timeout, and prevent * SIGTERM/SIGQUIT again until backend startup is complete. */ ! if (!disable_sig_alarm(false)) elog(FATAL, "could not disable timer for authorization timeout"); PG_SETMASK(&BlockSig); --- 2447,2453 ---- * Done with authentication. Disable timeout, and prevent * SIGTERM/SIGQUIT again until backend startup is complete. */ ! if (!disable_sig_alarm(false, false)) elog(FATAL, "could not disable timer for authorization timeout"); PG_SETMASK(&BlockSig); Index: backend/storage/lmgr/proc.c =================================================================== RCS file: /home/snaga/cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 proc.c *** backend/storage/lmgr/proc.c 10 Jun 2004 00:22:29 -0000 1.1.1.1 --- backend/storage/lmgr/proc.c 28 Jun 2004 03:20:10 -0000 *************** *** 52,60 **** --- 52,68 ---- #include "storage/sinval.h" #include "storage/spin.h" + #ifdef LOCKTIMEOUT_DEBUG + #define PRINT_TIME(MSG, X) \ + elog(NOTICE, "%s: %d.%03d", MSG, (X).tv_sec, ((X).tv_usec/1000)) + #else + #define PRINT_TIME(MSG, X) {} + #endif + /* GUC variables */ int DeadlockTimeout = 1000; int StatementTimeout = 0; + int LockTimeout = 0; /* Pointer to this process's PGPROC struct, if any */ PGPROC *MyProc = NULL; *************** *** 78,92 **** /* Mark these volatile because they can be changed by signal handler */ static volatile bool statement_timeout_active = false; static volatile bool deadlock_timeout_active = false; /* statement_fin_time is valid only if statement_timeout_active is true */ static struct timeval statement_fin_time; ! static void ProcKill(void); static void DummyProcKill(void); static bool CheckStatementTimeout(void); /* * Report number of semaphores needed by InitProcGlobal. --- 86,102 ---- /* Mark these volatile because they can be changed by signal handler */ static volatile bool statement_timeout_active = false; static volatile bool deadlock_timeout_active = false; + static volatile bool lock_timeout_active = false; /* statement_fin_time is valid only if statement_timeout_active is true */ static struct timeval statement_fin_time; ! static struct timeval lock_fin_time; static void ProcKill(void); static void DummyProcKill(void); static bool CheckStatementTimeout(void); + static LOCK *prevWaitLock = NULL; /* * Report number of semaphores needed by InitProcGlobal. *************** *** 244,249 **** --- 254,261 ---- MyProc->waitHolder = NULL; SHMQueueInit(&(MyProc->procHolders)); + prevWaitLock = NULL; + /* * Arrange to clean up at backend exit. */ *************** *** 307,312 **** --- 319,326 ---- MyProc->waitHolder = NULL; SHMQueueInit(&(MyProc->procHolders)); + prevWaitLock = NULL; + /* * Arrange to clean up at process exit. */ *************** *** 338,344 **** waitingForLock = false; /* Turn off the deadlock timer, if it's still running (see ProcSleep) */ ! disable_sig_alarm(false); /* Unlink myself from the wait queue, if on it (might not be anymore!) */ LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); --- 352,358 ---- waitingForLock = false; /* Turn off the deadlock timer, if it's still running (see ProcSleep) */ ! disable_sig_alarm(false, false); /* Unlink myself from the wait queue, if on it (might not be anymore!) */ LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); *************** *** 627,632 **** --- 641,648 ---- MyProc->errType = STATUS_OK; /* initialize result for success */ + prevWaitLock = MyProc->waitLock; + /* * If we detected deadlock, give up without waiting. This must agree * with CheckDeadLock's recovery code, except that we shouldn't *************** *** 661,667 **** * By delaying the check until we've waited for a bit, we can avoid * running the rather expensive deadlock-check code in most cases. */ ! if (!enable_sig_alarm(DeadlockTimeout, false)) elog(FATAL, "could not set timer for process wakeup"); /* --- 677,683 ---- * By delaying the check until we've waited for a bit, we can avoid * running the rather expensive deadlock-check code in most cases. */ ! if (!enable_sig_alarm(DeadlockTimeout, false, false)) elog(FATAL, "could not set timer for process wakeup"); /* *************** *** 683,689 **** /* * Disable the timer, if it's still running */ ! if (!disable_sig_alarm(false)) elog(FATAL, "could not disable timer for process wakeup"); /* --- 699,705 ---- /* * Disable the timer, if it's still running */ ! if (!disable_sig_alarm(false, false)) elog(FATAL, "could not disable timer for process wakeup"); /* *************** *** 738,743 **** --- 754,761 ---- proc->waitHolder = NULL; proc->errType = errType; + prevWaitLock = NULL; + /* And awaken it */ PGSemaphoreUnlock(&proc->sem); *************** *** 885,890 **** --- 903,911 ---- * RemoveFromWaitQueue took care of waking up any such processes. */ LWLockRelease(LockMgrLock); + + deadlock_timeout_active = false; + prevWaitLock = NULL; } *************** *** 930,936 **** PGSemaphoreUnlock(&proc->sem); } - /***************************************************************************** * SIGALRM interrupt support * --- 951,956 ---- *************** *** 949,955 **** * Returns TRUE if okay, FALSE on failure. */ bool ! enable_sig_alarm(int delayms, bool is_statement_timeout) { #ifdef WIN32 #warning add Win32 timer --- 969,975 ---- * Returns TRUE if okay, FALSE on failure. */ bool ! enable_sig_alarm(int delayms, bool is_statement_timeout, bool is_lock_timeout) { #ifdef WIN32 #warning add Win32 timer *************** *** 963,970 **** bigtime_t time_interval; #endif /* Compute target timeout time if we will need it */ ! if (is_statement_timeout || statement_timeout_active) { gettimeofday(&fin_time, NULL); fin_time.tv_sec += delayms / 1000; --- 983,999 ---- bigtime_t time_interval; #endif + #ifdef LOCKTIMEOUT_DEBUG + elog(NOTICE, "enable_sig_alarm: is_statement_timeout=%d, " + "is_lock_timeout=%d\n", + is_statement_timeout, + is_lock_timeout); + elog(NOTICE, "enable_sig_alarm: LockTimeout=%d", LockTimeout); + #endif + /* Compute target timeout time if we will need it */ ! if (is_statement_timeout || statement_timeout_active || ! is_lock_timeout || lock_timeout_active ) { gettimeofday(&fin_time, NULL); fin_time.tv_sec += delayms / 1000; *************** *** 974,979 **** --- 1003,1009 ---- fin_time.tv_sec++; fin_time.tv_usec -= 1000000; } + PRINT_TIME("enable_sig_alarm", fin_time); } if (is_statement_timeout) *************** *** 983,1012 **** statement_fin_time = fin_time; statement_timeout_active = true; } ! else if (statement_timeout_active) { ! /* ! * Begin deadlock timeout with statement-level timeout active ! * ! * Here, we want to interrupt at the closer of the two timeout times. ! * If fin_time >= statement_fin_time then we need not touch the ! * existing timer setting; else set up to interrupt at the ! * deadlock timeout time. ! * ! * NOTE: in this case it is possible that this routine will be ! * interrupted by the previously-set timer alarm. This is okay ! * because the signal handler will do only what it should do ! * according to the state variables. The deadlock checker may get ! * run earlier than normal, but that does no harm. ! */ ! deadlock_timeout_active = true; ! if (fin_time.tv_sec > statement_fin_time.tv_sec || ! (fin_time.tv_sec == statement_fin_time.tv_sec && ! fin_time.tv_usec >= statement_fin_time.tv_usec)) ! return true; } else { /* Begin deadlock timeout with no statement-level timeout */ deadlock_timeout_active = true; } --- 1013,1066 ---- statement_fin_time = fin_time; statement_timeout_active = true; } ! else if ( is_lock_timeout ) { ! Assert(!lock_timeout_active); ! lock_fin_time = fin_time; ! lock_timeout_active = true; ! prevWaitLock = MyProc->waitLock; } else { + /* + * If is_statement_timeout and is_lock_timeout are false, + * delayms means a timeout time to detect deadlock. + */ + if (statement_timeout_active) + { + /* + * Begin deadlock timeout with statement-level timeout active + * + * Here, we want to interrupt at the closer of the two timeout times. + * If fin_time >= statement_fin_time then we need not touch the + * existing timer setting; else set up to interrupt at the + * deadlock timeout time. + * + * NOTE: in this case it is possible that this routine will be + * interrupted by the previously-set timer alarm. This is okay + * because the signal handler will do only what it should do + * according to the state variables. The deadlock checker may get + * run earlier than normal, but that does no harm. + */ + deadlock_timeout_active = true; + if (fin_time.tv_sec > statement_fin_time.tv_sec || + (fin_time.tv_sec == statement_fin_time.tv_sec && + fin_time.tv_usec >= statement_fin_time.tv_usec)) + return true; + } + if (lock_timeout_active) + { + /* + * If the lock timeout has been already set, and it is shorter + * than me, there is no need to set another one. + * The shortest timer has to be set. + */ + deadlock_timeout_active = true; + if (fin_time.tv_sec > lock_fin_time.tv_sec || + (fin_time.tv_sec == lock_fin_time.tv_sec && + fin_time.tv_usec >= lock_fin_time.tv_usec)) + return true; + } /* Begin deadlock timeout with no statement-level timeout */ deadlock_timeout_active = true; } *************** *** 1016,1021 **** --- 1070,1086 ---- MemSet(&timeval, 0, sizeof(struct itimerval)); timeval.it_value.tv_sec = delayms / 1000; timeval.it_value.tv_usec = (delayms % 1000) * 1000; + { + PRINT_TIME("enable_sig_alarm", timeval.it_value); + #ifdef LOCKTIMEOUT_DEBUG + elog(NOTICE, "enable_sig_alarm: deadlock_timeout_active=%d, " + "statement_timeout_active=%d, " + "lock_timeout_active=%d\n", + deadlock_timeout_active, + statement_timeout_active, + lock_timeout_active); + #endif + } if (setitimer(ITIMER_REAL, &timeval, NULL)) return false; #else *************** *** 1025,1030 **** --- 1090,1098 ---- return false; #endif #endif + + PRINT_TIME("enable_sig_alarm: lock_fin_time", lock_fin_time); + return true; } *************** *** 1036,1042 **** * Returns TRUE if okay, FALSE on failure. */ bool ! disable_sig_alarm(bool is_statement_timeout) { #ifdef WIN32 #warning add Win32 timer --- 1104,1110 ---- * Returns TRUE if okay, FALSE on failure. */ bool ! disable_sig_alarm(bool is_statement_timeout, bool is_lock_timeout) { #ifdef WIN32 #warning add Win32 timer *************** *** 1049,1055 **** * * We will re-enable the interrupt if necessary in CheckStatementTimeout. */ ! if (statement_timeout_active || deadlock_timeout_active) { #ifndef __BEOS__ struct itimerval timeval; --- 1117,1124 ---- * * We will re-enable the interrupt if necessary in CheckStatementTimeout. */ ! if (statement_timeout_active || deadlock_timeout_active || ! lock_timeout_active ) { #ifndef __BEOS__ struct itimerval timeval; *************** *** 1057,1070 **** MemSet(&timeval, 0, sizeof(struct itimerval)); if (setitimer(ITIMER_REAL, &timeval, NULL)) { ! statement_timeout_active = deadlock_timeout_active = false; return false; } #else /* BeOS doesn't have setitimer, but has set_alarm */ if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0) { ! statement_timeout_active = deadlock_timeout_active = false; return false; } #endif --- 1126,1143 ---- MemSet(&timeval, 0, sizeof(struct itimerval)); if (setitimer(ITIMER_REAL, &timeval, NULL)) { ! statement_timeout_active = deadlock_timeout_active ! = lock_timeout_active = false; ! prevWaitLock = NULL; return false; } #else /* BeOS doesn't have setitimer, but has set_alarm */ if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0) { ! statement_timeout_active = deadlock_timeout_active ! = lock_timeout_active = false; ! prevWaitLock = NULL; return false; } #endif *************** *** 1076,1081 **** --- 1149,1159 ---- /* Cancel or reschedule statement timeout */ if (is_statement_timeout) statement_timeout_active = false; + else if (is_lock_timeout) + { + lock_timeout_active = false; + prevWaitLock = NULL; + } else if (statement_timeout_active) { if (!CheckStatementTimeout()) *************** *** 1086,1091 **** --- 1164,1196 ---- } + static struct timeval * + GetShorterTimer(struct timeval *r, struct timeval t1, struct timeval t2) + { + if ( t1.tv_sectv_sec = t1.tv_sec; + r->tv_usec = t1.tv_usec; + } + else if ( t1.tv_sec>t2.tv_sec ) + { + r->tv_sec = t2.tv_sec; + r->tv_usec = t2.tv_usec; + } + else if ( t1.tv_usectv_sec = t1.tv_sec; + r->tv_usec = t1.tv_usec; + } + else + { + r->tv_sec = t2.tv_sec; + r->tv_usec = t2.tv_usec; + } + return r; + } + + /* * Check for statement timeout. If the timeout time has come, * trigger a query-cancel interrupt; if not, reschedule the SIGALRM *************** *** 1121,1128 **** struct itimerval timeval; MemSet(&timeval, 0, sizeof(struct itimerval)); ! timeval.it_value.tv_sec = statement_fin_time.tv_sec - now.tv_sec; ! timeval.it_value.tv_usec = statement_fin_time.tv_usec - now.tv_usec; if (timeval.it_value.tv_usec < 0) { timeval.it_value.tv_sec--; --- 1226,1242 ---- struct itimerval timeval; MemSet(&timeval, 0, sizeof(struct itimerval)); ! ! if ( statement_timeout_active && lock_timeout_active ) ! GetShorterTimer(&(timeval.it_value), statement_fin_time,lock_fin_time); ! else if ( statement_timeout_active ) ! timeval.it_value = statement_fin_time; ! else if ( lock_timeout_active ) ! timeval.it_value = lock_fin_time; ! ! timeval.it_value.tv_sec -= now.tv_sec; ! timeval.it_value.tv_usec -= now.tv_usec; ! if (timeval.it_value.tv_usec < 0) { timeval.it_value.tv_sec--; *************** *** 1131,1136 **** --- 1245,1251 ---- if (setitimer(ITIMER_REAL, &timeval, NULL)) return false; #else + #warning *** LOCKTIMEOUT NOT IMPLEMENTED!!! *** /* BeOS doesn't have setitimer, but has set_alarm */ bigtime_t time_interval; *************** *** 1146,1151 **** --- 1261,1346 ---- return true; } + static bool + CheckLockTimeout(void) + { + struct timeval now; + + if (!lock_timeout_active) + return true; /* do nothing if not active */ + + gettimeofday(&now, NULL); + + PRINT_TIME("CheckLockTimeout: now", now); + PRINT_TIME("CheckLockTimeout: lock_fin_time", lock_fin_time); + + if (now.tv_sec > lock_fin_time.tv_sec || + (now.tv_sec == lock_fin_time.tv_sec && + now.tv_usec >= lock_fin_time.tv_usec)) + + elog(DEBUG1, "MyProc.lwWaiting=%d, MyProc.lwExclusive=%d", MyProc->lwWaiting, + MyProc->lwWaiting); + elog(DEBUG1, "MyProc.waitLock=%p", MyProc->waitLock); + + /* + * Still waiting a same lock. + */ + if ( MyProc->waitLock && MyProc->waitLock==prevWaitLock ) + { + /* Time to die */ + lock_timeout_active = false; + prevWaitLock = NULL; + + ereport(ERROR, (errcode(ERRCODE_T_R_LOCKTIMEOUT_DETECTED), + errmsg("the current transaction is going to be rolled-back because of lock timeout."))); + } + else + { + /* Not time yet, so (re)schedule the interrupt */ + #ifdef WIN32 + #warning add win32 timer + #else + #ifndef __BEOS__ + struct itimerval timeval; + + MemSet(&timeval, 0, sizeof(struct itimerval)); + + if ( statement_timeout_active && lock_timeout_active ) + GetShorterTimer(&(timeval.it_value), statement_fin_time,lock_fin_time); + else if ( statement_timeout_active ) + timeval.it_value = statement_fin_time; + else if ( lock_timeout_active ) + timeval.it_value = lock_fin_time; + + PRINT_TIME("CheckLockTimeout: timeval.it_value", timeval.it_value); + timeval.it_value.tv_sec -= now.tv_sec; + timeval.it_value.tv_usec -= now.tv_usec; + PRINT_TIME("CheckLockTimeout: timeval.it_value", timeval.it_value); + + if (timeval.it_value.tv_usec < 0) + { + timeval.it_value.tv_sec--; + timeval.it_value.tv_usec += 1000000; + } + if (setitimer(ITIMER_REAL, &timeval, NULL)) + return false; + #else + #warning *** NOT IMPLEMENTED!!! *** + /* BeOS doesn't have setitimer, but has set_alarm */ + bigtime_t time_interval; + + time_interval = + (lock_fin_time.tv_sec - now.tv_sec) * 1000000 + + (lock_fin_time.tv_usec - now.tv_usec); + if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0) + return false; + #endif + #endif + } + + return true; + } + /* * Signal handler for SIGALRM *************** *** 1160,1173 **** { int save_errno = errno; if (deadlock_timeout_active) { - deadlock_timeout_active = false; CheckDeadLock(); } if (statement_timeout_active) (void) CheckStatementTimeout(); errno = save_errno; } --- 1355,1382 ---- { int save_errno = errno; + // elog(NOTICE, "handle_sig_alarm: deadlock_timeout_active=%d, statement_timeout_active=%d, lock_timeout_active=%d", deadlock_timeout_active, statement_timeout_active, lock_timeout_active); + + PRINT_TIME("handle_sig_alarm: lock_fin_time", lock_fin_time); + if (deadlock_timeout_active) { CheckDeadLock(); } + PRINT_TIME("handle_sig_alarm: lock_fin_time", lock_fin_time); + if (statement_timeout_active) + { (void) CheckStatementTimeout(); + } + + PRINT_TIME("handle_sig_alarm: lock_fin_time", lock_fin_time); + + if (lock_timeout_active) + { + (void) CheckLockTimeout(); + } errno = save_errno; } Index: backend/tcop/postgres.c =================================================================== RCS file: /home/snaga/cvsroot/pgsql/src/backend/tcop/postgres.c,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 postgres.c *** backend/tcop/postgres.c 10 Jun 2004 00:22:29 -0000 1.1.1.1 --- backend/tcop/postgres.c 18 Jun 2004 03:16:32 -0000 *************** *** 1734,1740 **** /* Set statement timeout running, if any */ if (StatementTimeout > 0) ! enable_sig_alarm(StatementTimeout, true); xact_started = true; } --- 1734,1742 ---- /* Set statement timeout running, if any */ if (StatementTimeout > 0) ! enable_sig_alarm(StatementTimeout, true, false); ! if (LockTimeout > 0) ! enable_sig_alarm(LockTimeout, false, true); xact_started = true; } *************** *** 1749,1755 **** DeferredTriggerEndQuery(); /* Cancel any active statement timeout before committing */ ! disable_sig_alarm(true); /* Now commit the command */ ereport(DEBUG3, --- 1751,1757 ---- DeferredTriggerEndQuery(); /* Cancel any active statement timeout before committing */ ! disable_sig_alarm(true, true); /* Now commit the command */ ereport(DEBUG3, *************** *** 2704,2710 **** QueryCancelPending = false; InterruptHoldoffCount = 1; CritSectionCount = 0; /* should be unnecessary, but... */ ! disable_sig_alarm(true); QueryCancelPending = false; /* again in case timeout occurred */ DisableNotifyInterrupt(); debug_query_string = NULL; --- 2706,2712 ---- QueryCancelPending = false; InterruptHoldoffCount = 1; CritSectionCount = 0; /* should be unnecessary, but... */ ! disable_sig_alarm(true, true); QueryCancelPending = false; /* again in case timeout occurred */ DisableNotifyInterrupt(); debug_query_string = NULL; Index: backend/utils/misc/guc.c =================================================================== RCS file: /home/snaga/cvsroot/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 guc.c *** backend/utils/misc/guc.c 10 Jun 2004 00:22:33 -0000 1.1.1.1 --- backend/utils/misc/guc.c 28 Jun 2004 01:30:20 -0000 *************** *** 910,917 **** NULL }, &DeadlockTimeout, ! 1000, 0, INT_MAX, NULL, NULL }, #ifdef HAVE_SYSLOG { --- 910,927 ---- NULL }, &DeadlockTimeout, ! 5000, 0, INT_MAX, NULL, NULL }, + + { + {"lock_timeout", PGC_SIGHUP, LOCK_MANAGEMENT, + gettext_noop("The time in milliseconds to wait on lock before detecting timeout."), + NULL + }, + &LockTimeout, + 0, 0, INT_MAX, NULL, NULL + }, + #ifdef HAVE_SYSLOG { Index: include/storage/proc.h =================================================================== RCS file: /home/snaga/cvsroot/pgsql/src/include/storage/proc.h,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 proc.h *** include/storage/proc.h 10 Jun 2004 00:22:34 -0000 1.1.1.1 --- include/storage/proc.h 15 Jun 2004 08:20:34 -0000 *************** *** 88,93 **** --- 88,94 ---- /* configurable options */ extern int DeadlockTimeout; + extern int LockTimeout; extern int StatementTimeout; *************** *** 111,118 **** extern void ProcCancelWaitForSignal(void); extern void ProcSendSignal(BackendId procId); ! extern bool enable_sig_alarm(int delayms, bool is_statement_timeout); ! extern bool disable_sig_alarm(bool is_statement_timeout); extern void handle_sig_alarm(SIGNAL_ARGS); #endif /* PROC_H */ --- 112,120 ---- extern void ProcCancelWaitForSignal(void); extern void ProcSendSignal(BackendId procId); ! extern bool enable_sig_alarm(int delayms, bool is_statement_timeout, ! bool is_lock_timeout); ! extern bool disable_sig_alarm(bool is_statement_timeout, bool is_lock_timeout); extern void handle_sig_alarm(SIGNAL_ARGS); #endif /* PROC_H */ Index: include/utils/errcodes.h =================================================================== RCS file: /home/snaga/cvsroot/pgsql/src/include/utils/errcodes.h,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 errcodes.h *** include/utils/errcodes.h 10 Jun 2004 00:22:34 -0000 1.1.1.1 --- include/utils/errcodes.h 18 Jun 2004 06:29:09 -0000 *************** *** 203,208 **** --- 203,211 ---- #define ERRCODE_T_R_SERIALIZATION_FAILURE MAKE_SQLSTATE('4','0', '0','0','1') #define ERRCODE_T_R_STATEMENT_COMPLETION_UNKNOWN MAKE_SQLSTATE('4','0', '0','0','3') #define ERRCODE_T_R_DEADLOCK_DETECTED MAKE_SQLSTATE('4','0', 'P','0','1') + #ifdef LOCKTIMEOUT + #define ERRCODE_T_R_LOCKTIMEOUT_DETECTED MAKE_SQLSTATE('4','0', 'P','0','2') + #endif /* Class 42 - Syntax Error or Access Rule Violation */ #define ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION MAKE_SQLSTATE('4','2', '0','0','0')