72 lines
3.1 KiB
Python
Executable file
72 lines
3.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (C) 2024-2026 Whiterun LLC,
|
|
# This software is licensed under the GNU Affero General Public License (AGPL), version 3.0 or later.,
|
|
# A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/agpl-3.0.html
|
|
|
|
import os
|
|
import sys
|
|
import re
|
|
|
|
"""
|
|
Disallow COALESCE with first_seen_timestamp and mtp_timestamp on the same line in SQL queries.
|
|
These combinations should use effective_timestamp instead.
|
|
Note: Database schema definitions using GENERATED ALWAYS AS are allowed.
|
|
Note: COALESCE aliased as effective_timestamp is allowed (this is the correct pattern).
|
|
"""
|
|
|
|
OUR_PATH = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
def check_file_for_timestamp_coalesce(file_path):
|
|
"""Check if the file contains disallowed timestamp combinations."""
|
|
with open(file_path, 'r', encoding='utf-8') as file:
|
|
for line_num, line in enumerate(file, 1):
|
|
# Check if line contains COALESCE and both timestamp fields
|
|
if (re.search(r'\bCOALESCE\b', line, re.IGNORECASE) and
|
|
re.search(r'\bfirst_seen_timestamp\b', line) and
|
|
re.search(r'\bmtp_timestamp\b', line)):
|
|
|
|
# Skip database schema definitions (GENERATED ALWAYS AS)
|
|
if re.search(r'GENERATED\s+ALWAYS\s+AS', line, re.IGNORECASE):
|
|
continue
|
|
|
|
# Skip comments that are just documenting the pattern
|
|
if line.strip().startswith('//') and 'COALESCE' in line:
|
|
continue
|
|
|
|
# Allow COALESCE aliased as effective_timestamp (this is the correct pattern)
|
|
if re.search(r'AS\s+effective_timestamp', line, re.IGNORECASE):
|
|
continue
|
|
|
|
print(f"{file_path}:{line_num}: Disallowed COALESCE with first_seen_timestamp and mtp_timestamp")
|
|
print(f" Line: {line.strip()}")
|
|
print(f" Suggestion: Use effective_timestamp instead")
|
|
return False
|
|
|
|
return True
|
|
|
|
def check_files(directories):
|
|
"""
|
|
Traverse the specified directories and check each .rs file.
|
|
"""
|
|
found_forbidden_combinations = False
|
|
|
|
for directory in directories:
|
|
for root, dirs, files in os.walk(os.path.join(OUR_PATH, "..", directory)):
|
|
for file in files:
|
|
if file.endswith('.rs'):
|
|
file_path = os.path.join(root, file)
|
|
if not check_file_for_timestamp_coalesce(file_path):
|
|
found_forbidden_combinations = True
|
|
|
|
if found_forbidden_combinations:
|
|
print("\nForbidden timestamp combinations found.")
|
|
print("Please use effective_timestamp instead of COALESCE with first_seen_timestamp and mtp_timestamp.")
|
|
print("Note: Database schema definitions using GENERATED ALWAYS AS are allowed.")
|
|
print("Note: COALESCE aliased as effective_timestamp is allowed (this is the correct pattern).")
|
|
sys.exit(1)
|
|
else:
|
|
print("OK")
|
|
sys.exit(0)
|
|
|
|
if __name__ == "__main__":
|
|
check_files(['src', 'contrib'])
|