Section 12a
Stored Procedures — Validation  ·  SQL Server  ·  2026-05-03

12a Stored Procedures — Validation

40 SPs that enforce data quality across all ABSD_ triggers and UI entry points. All share a common RETURN pattern and are called inline from trigger cursors.

Usage context: Every ABSD_ trigger that validates a field calls one of these SPs before writing. A non-zero return from any validator causes the trigger to RAISERROR and roll back. The same SPs are called directly by the Captiva/UI data-entry layer to provide instant field-level feedback before the row is saved.

Validation Architecture

The validation layer sits between raw user/feed input and the ABSD_ tables. There are two tiers:

Tier 1 — Generic Field Validators (val*)

Pattern-based checks applicable across many fields. Named by the LR field type number they enforce (Standard1 = 1-char classification code, Standard9 = YYYYMMDD date, etc.). Called from triggers and UI.

  • 22 SPs in the val* family
  • Inputs: the raw string value + OUTPUT message parameter
  • Return: 0 = valid, 1 = invalid

Tier 2 — Domain Validators (spValidate*)

Cross-table or regex-complex rules for specific fields: MMSI (9-digit + EDM range check), callsign (country range lookup), LBP/LOA/REG lengths (inter-field relationship), MANBOW_LEN (vs breadth), BBOW (breadth vs LOA), etc.

  • 18 SPs in the spValidate* family
  • More parameters — may accept LRNO or multiple field values
  • Same 0/1 return convention

Universal Return Pattern

Every validation SP follows this skeleton:

CREATE PROCEDURE valXxx
    @PASSEDDATA  varchar(N) = NULL,
    @RETMESSAGE  VARCHAR(254) = NULL OUTPUT
AS
    DECLARE @RETERR INT
    SELECT  @RETERR = 0

    IF NOT(@PASSEDDATA IS NULL)
    BEGIN
        -- check logic: set @RETERR=1 and @RETMESSAGE on failure
    END
    ELSE
        SELECT @RETERR = 0   -- NULL always passes

    RETURN @RETERR
NULL always passes. Every validator treats NULL as "no value supplied" and returns 0. This allows optional fields to be left blank without triggering validation errors. Only valStandard2NoNull enforces the non-null rule.

Caller pattern inside a trigger cursor:

DECLARE @VALERR INT, @VALMSG VARCHAR(254)
EXEC @VALERR = valStandard9new @newdate, @VALMSG OUTPUT
IF @VALERR <> 0
    BEGIN
        RAISERROR('Field X: %s', 16, 1, @VALMSG)
        ROLLBACK TRANSACTION
        RETURN
    END

spGetUserSettings / spSetUserSettings

Not a validator, but called at the top of every create/update SP to stamp the annotation trail.

spGetUserSettings @Initials OUTPUT, @Source OUTPUT, @SourceRef OUTPUT, @FilingRef OUTPUT
spSetUserSettings @WindowsUser, @Initials, @Source, @SourceRef, @FilingRef
ParameterDirectionDescription
@InitialsOUTPUT3-char user initials written to J06_AUTHOR on every ABSD_ row update
@SourceOUTPUTCurrent data source code (e.g. 'LR', 'AIS', 'BV') stamped in tblChanges
@SourceRefOUTPUTSource reference string for tblChanges
@FilingRefOUTPUTFiling reference for tblChanges

Behaviour: Reads tblUserSettings using SYSTEM_USER (Windows login). If no row exists, inserts a placeholder row with initials 'XXX' and returns. Companion SPs: spGetUserSettingsOwners (same pattern for the ownership data-entry context), spSetUserSettings / spSetUserSettingsOwners (write updated preferences back).

valStandard1 — 1-char Classification Code

valStandard1 @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT

Validates single-character LR classification confidence codes.

Valid valuesMeaning
CConfirmed (sourced from LR survey/document)
DDerived (computed from other confirmed fields)
EEstimated
GGiven (self-reported by owner/manager)
LLegacy (historical, source unknown)
XUnverified third-party data

Used on every confidence-code field in the ABSD_ schema (column suffix _VER or _C in most tables).

valStandard2 / valStandard2NoNull — 2-char Type Code

valStandard2 @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard2NoNull @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT

Validates 2-character alpha-only codes (used for flag state ISO2, hull construction code, etc.). valStandard2 allows NULL; valStandard2NoNull additionally rejects NULL and empty string.

Check: LEN(@PASSEDDATA) = 2 AND all chars are alphabetic (A-Z, a-z). Rejects digits, spaces, special chars.

valStandard3 / valStandard3Num / valStandard3NumRev — 3-char Codes

valStandard3 @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard3Num @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard3NumRev @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT

valStandard3 — 3-char alpha code (flag state ISO3, port, etc.). LEN=3, alpha chars.

valStandard3Num — 3-char code where the value is a number plus a confidence code appended (e.g. draft stored as numeric string + 'C'). Checks numeric range and confidence code validity.

valStandard3NumRev — same as 3Num but confidence code is the first character (legacy field layout variant).

valStandard4 / valStandard4_new — YYMMDD Date

valStandard4 @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard4_new @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT

Validates LR 6-character YYMMDD date format.

RuleDetail
LengthMust be exactly 6 characters
All numericISNUMERIC check
Month01–12 or 00 (unknown month) or 99 (sentinel)
Day01–31 or 00 (unknown day) or 99 (sentinel)
Sentinel '000000'PASSES — means "date unknown"
Sentinel '999999'PASSES — means "open-ended / still current"

_new variant: Added stricter checks — rejects impossible month/day combinations (e.g. month 13, day 32). The original valStandard4 only checks format, not calendar validity.

valStandard8 — Numeric String

valStandard8 @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT

Validates that the value is a pure numeric string (used for tonnage, measurement, and dimension fields stored as varchar). Uses ISNUMERIC() plus checks that no letters or special chars are present. Does not validate range (range checks are field-specific and done in the trigger itself).

valStandard9 Family — YYYYMMDD Date

valStandard9 @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard9new @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard9_old @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard9Non99 @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard9Owner @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard9Owner_new @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard9Owner_NODATE @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT

The most-used date validator. All variants check 8-char YYYYMMDD format with year range 1850–2050.

VariantKey Difference
valStandard9Strict — rejects 00 day/month, requires real calendar date
valStandard9newMost-used. Allows 00 in day/month fields (meaning unknown). Allows '19809999' and '00000000' as pass-through sentinels. Full leap-year and 30/31-day month checks.
valStandard9_oldLegacy version without 00-month/day support — kept for backward compat
valStandard9Non99Rejects '9999' year — used where sentinel '99' end date is not allowed
valStandard9OwnerOwner-record date variant: allows '00000000' but applies stricter future-date ceiling
valStandard9Owner_newAs Owner but with 00 day/month support
valStandard9Owner_NODATEAccepts empty/null date field specifically for ownership records with no known date

valStandard9new calendar logic (from source):

-- Leap year: Feb <= 29
IF YEAR % 4 = 0 AND MONTH = '02' AND DAY > 29 → error
-- Non-leap: Feb <= 28
IF YEAR % 4 <> 0 AND MONTH = '02' AND DAY > 28 → error
-- 30-day months (04,06,09,11)
IF MONTH IN ('04','06','09','11') AND DAY > 30 → error

valStandard10 / valStandard10_new — Flexible Date

valStandard10 @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT
valStandard10_new @PASSEDDATE varchar(20), @RETMESSAGE varchar(254) OUTPUT

Accepts either 6-char YYMMDD or 8-char YYYYMMDD format. Used for fields where legacy data may be in the short format and newer data uses the long format. Internally checks the length first, then delegates to the appropriate Standard4 or Standard9 validator logic.

valStandardYN — Y/N Boolean

valStandardYN @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT

Accepts only 'Y' or 'N' (case-sensitive). Used on boolean flag fields throughout ABSD_ (e.g. ABSD_OVGE.B14_NAVAIDS, ABSD_HIST.A02_CONV). Returns error for any other value including 'y', 'n', '1', '0', or empty string.

valStandardAlpha / valStandardNormal — String Quality

valStandardAlpha @PASSEDDATA varchar(255), @RETMESSAGE varchar(254) OUTPUT
valStandardNormal @PASSEDDATA varchar(255), @RETMESSAGE varchar(254) OUTPUT

valStandardAlpha — Checks that the string contains only alphabetic characters (A-Z, a-z) and spaces. Rejects digits and special characters. Used for name fields where numeric contamination indicates a data error.

valStandardNormal — Looser check: rejects control characters (ASCII < 32) and known problematic characters that break downstream XML/APS output. Allows alphanumeric plus common punctuation.

valStandardYMD / valStandardYMD_OLD — Year-Month-Day Components

valStandardYMD @YEAR varchar(4), @MONTH varchar(2), @DAY varchar(2), @RETMESSAGE varchar(254) OUTPUT

Validates year, month, and day passed as separate components rather than a concatenated date string. Used in UI contexts where the three parts are entered in separate fields. Applies the same calendar logic as valStandard9new (leap year, 30/31-day months). The _OLD variant is kept for backward compatibility without the calendar refinements.

valOwner* Family — Ownership Role Codes

valOwnerCode @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valOwnerRelationship @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valOwnerRelationshipAny @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valOwnerRelationshipFXCODE @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
valOwnerRelationshipOWCODE @PASSEDDATA varchar(20), @RETMESSAGE varchar(254) OUTPUT
SPValidates
valOwnerCode7-char OWCODE format (numeric + alpha suffix). Checks against ABSD_OWGE existence.
valOwnerRelationshipRelationship code IN ('RC','RP','RM','IRP') — primary ownership categories
valOwnerRelationshipAnyBroader set including secondary relationships (agent, manager, operator, P&I)
valOwnerRelationshipFXCODEValidates FXCODE field (fleet/group relationship code)
valOwnerRelationshipOWCODEValidates that the given OWCODE is a live company (not deleted) in ABSD_OWGE

spValidateMMSI — Maritime Mobile Service Identity

spValidateMMSI @PASSEDDATA varchar(9), @RETMESSAGE varchar(254) OUTPUT

Two-stage validation:

  1. Format: Exactly 9 numeric digits; first digit in 2–7 (valid MID range); not all zeros.
  2. EDM duplicate check: Queries EDM.DBO.T_REF_COUNTRY_CALL_SIGN_RANGES to verify the MMSI falls within the country's assigned EDM range. Returns warning (not error) if the MMSI is outside the known allocation for the vessel's flag state.

Called from the SuppOVGEUpdate trigger on SUPPLEMENTAL_ABSD_OVGE and from the UI MMSI entry field.

spValidateLengths — LOA / LBP / REG Cross-check

spValidateLengths @LRNO varchar(7), @LOA numeric, @LBP numeric, @REG numeric, @RETMESSAGE varchar(254) OUTPUT

Validates the three length fields of a vessel record against each other:

Called from the ABSD_HIDR_Update trigger and the dimensions entry screen.

spValidateCallsign — Radio Callsign

spValidateCallsign @Callsign varchar(20), @Flag varchar(3), @RETMESSAGE varchar(254) OUTPUT

Validates a callsign against the country's allocated ITU callsign prefix ranges. Queries Callsign_range (local table of ITU allocations). The trigger-level validation in ABSD_OVGE_Update (added March 2026) supersedes this with a live EDM lookup, but the SP remains available for batch validation jobs. Returns 0 (valid), 1 (invalid format), or 2 (valid format but outside country's allocation — treated as warning).

spValidateManbow_Len / spTIPValidateD22_MANBOW_LEN

spValidateManbow_Len @LRNO varchar(7), @D22_MANBOW_LEN numeric, @RETMESSAGE varchar(254) OUTPUT
spTIPValidateD22_MANBOW_LEN @D22_MANBOW_LEN numeric, @D01_LOA numeric, @RETMESSAGE varchar(254) OUTPUT

Validates moulded breadth (D22_MANBOW_LEN) against LOA: breadth must not exceed LOA (implausible hull). The TIP variant receives both values directly (no LRNO lookup needed for external data feeds).

spValidateC02_BBOW — Breadth at Bow

spValidateC02_BBOW @LRNO varchar(7), @C02_BBOW numeric, @RETMESSAGE varchar(254) OUTPUT

Validates breadth at bow against the vessel's moulded breadth (D22_MANBOW_LEN from ABSD_MABU). Rule: C02_BBOW must be ≤ D22_MANBOW_LEN. Returns error with specific message identifying the current moulded breadth value for context.

spValidateHIMO* — Main Engine Numeric Fields

spValidateHIMOsmallint @PASSEDDATA varchar(20), @FieldName varchar(50), @RETMESSAGE varchar(254) OUTPUT
spValidateHIMOVarchars @PASSEDDATA varchar(255), @FieldName varchar(50), @RETMESSAGE varchar(254) OUTPUT

Validates ABSD_HIMO (main engine) field values. The smallint variant checks that numeric engine fields (kW, RPM, cylinders) are within physically plausible ranges. The varchar variant checks that coded fields (engine type, stroke type) are in the valid codebook values. @FieldName is passed so the error message can identify which specific engine field failed.

spValidateMAAU* — Auxiliary Engine Numeric Fields

spValidateMAAUsmallint @PASSEDDATA varchar(20), @FieldName varchar(50), @RETMESSAGE varchar(254) OUTPUT

Same pattern as spValidateHIMOsmallint but applies to ABSD_MAAU (auxiliary/emergency engine) numeric fields. Range limits differ from main engine (lower kW/RPM ceilings for generator sets).

spValidateD05_PRTYP / spValidateD12_CARGO_SEG / spValidateD22_MANBOW_LEN

spValidateD05_PRTYP @PASSEDDATA varchar(10), @RETMESSAGE varchar(254) OUTPUT
spValidateD12_CARGO_SEG @PASSEDDATA varchar(10), @RETMESSAGE varchar(254) OUTPUT

Codebook validators for specific ABSD field codes:

SPFieldValidates
spValidateD05_PRTYPABSD_FURO1.D05_PRTYPPropeller type code is in ABSD_CBUB1 (FLDI='D05')
spValidateD12_CARGO_SEGABSD_FUCA2.D12_CARGO_SEGCargo segment code is valid for the vessel's type group
spValidateD22_MANBOW_LENABSD_MABU.D22_MANBOW_LENMoulded breadth numeric + range check (0–100m)

All Validation SPs — Quick Reference

SP NameCategoryInput FormatNull OK?Key Check
valStandard1Generic1 charYesIN (C,D,E,G,L,X)
valStandard2Generic2 char alphaYesLEN=2, alpha only
valStandard2NoNullGeneric2 char alphaNoLEN=2, alpha only, not null
valStandard3Generic3 char alphaYesLEN=3, alpha only
valStandard3NumGenericnumeric+confYesnumeric part + valid conf code
valStandard3NumRevGenericconf+numericYesconf first, then numeric part
valStandard4DateYYMMDD (6)Yesformat only
valStandard4_newDateYYMMDD (6)Yesformat + calendar validity
valStandard8Genericnumeric strYesISNUMERIC, no letters
valStandard9DateYYYYMMDD (8)Yesstrict calendar, no 00 parts
valStandard9newDateYYYYMMDD (8)Yescalendar + allows 00 parts, sentinels
valStandard9_oldDateYYYYMMDD (8)Yeslegacy format check only
valStandard9Non99DateYYYYMMDD (8)Yesas 9new but rejects 9999 year
valStandard9OwnerDateYYYYMMDD (8)Yesownership date: allows 00000000, strict future ceiling
valStandard9Owner_newDateYYYYMMDD (8)Yesas Owner + 00 day/month
valStandard9Owner_NODATEDateYYYYMMDD (8)Yesallows blank/null explicitly
valStandard10Date6 or 8 charYesauto-detect YYMMDD vs YYYYMMDD
valStandard10_newDate6 or 8 charYesas 10 + calendar validity
valStandardYNGeneric1 charYesIN ('Y','N') only
valStandardAlphaGenericvarcharYesA-Z, a-z, spaces only
valStandardNormalGenericvarcharYesno control chars, no XML-breaking chars
valStandardYMDDate3 paramsYesseparate YYYY, MM, DD components
valStandardYMD_OLDDate3 paramsYeslegacy, no calendar refinements
valOwnerCodeOwner7 charYesOWCODE format + ABSD_OWGE existence
valOwnerRelationshipOwner2 charYesIN (RC,RP,RM,IRP)
valOwnerRelationshipAnyOwner2 charYesbroader relationship code set
valOwnerRelationshipFXCODEOwner2 charYesFXCODE valid values
valOwnerRelationshipOWCODEOwner7 charYesOWCODE is a live company
spValidateMMSIDomain9 charYesformat + EDM range check
spValidateLengthsDomainLRNO + 3 numsNoLOA ≥ LBP ≥ REG
spValidateCallsignDomaincallsign + flagYesITU prefix range check
spValidateManbow_LenDomainLRNO + breadthYesbreadth ≤ LOA
spValidateC02_BBOWDomainLRNO + BBOWYesBBOW ≤ moulded breadth
spValidateHIMOsmallintDomainval + fieldnameYesengine numeric range by field
spValidateHIMOVarcharsDomainval + fieldnameYesengine code in codebook by field
spValidateMAAUsmallintDomainval + fieldnameYesaux engine numeric range by field
spValidateD05_PRTYPDomaincodeYesABSD_CBUB1 FLDI='D05'
spValidateD12_CARGO_SEGDomaincodeYescargo segment valid for vessel type
spValidateD22_MANBOW_LENDomainnumericYes0–100m range
Section 12a  ·  LR Maritime Database Documentation  ·  2026-05-03