부록
오류 코드
AgensGraph 서버가 생성하는 모든 메시지에는 “SQLSTATE” 코드에 대한 SQL 표준 규칙을 준수하는 5자리 오류 코드가 할당됩니다.
표준에 따라 오류 코드의 처음 두 자리는 오류 클래스를 나타내고, 마지막 세 자리는 해당 클래스 내의 특정 조건을 나타냅니다. 이로 인해 특정 오류 코드를 인식하지 못하는 애플리케이션이라 하더라도 오류 클래스 수준에서는 여전히 오류를 파악하고 동작할 수 있을 것으로 기대할 수 있습니다.
다음 표는 AgensGraph에 정의된 모든 오류 코드를 나열합니다. (이 중 일부는 현재 실제로 사용되지는 않지만, SQL 표준에 정의가 여전히 포함되어 있습니다.) 오류 클래스도 함께 표시됩니다. 각 오류 클래스에는 마지막 세 자리가 000인 “표준” 오류 코드가 있습니다. 이 코드는 해당 클래스에 속하지만 특정 코드가 할당되지 않은 오류 조건에만 사용됩니다. “Condition Name” 열의 기호는 PL/pgSQL에서 사용하는 조건 이름입니다. 조건 이름은 대문자 또는 소문자로 작성할 수 있습니다. (오류와 달리 PL/pgSQL은 클래스 00, 01, 02의 조건 이름에 대한 경고를 인식하지 않습니다.)
일부 유형의 오류에 대해 서버는 해당 오류와 관련된 데이터베이스 객체(테이블, 테이블 칼럼, 데이터 타입 또는 제약조건)의 이름을 보고합니다. 예를 들어 unique_isolation은 오류를 유발한 고유 제약조건의 이름입니다. 이러한 이름은 오류 보고 메시지의 별도 필드로 제공되므로, 애플리케이션이 사람이 읽을 수 있는 메시지 텍스트에서 이름을 추출할 필요가 없습니다.
오류 코드 |
조건 이름 |
|---|---|
Class 00 - 정상 완료 |
|
00000 |
successful_completion |
***Class 01 - 경고 *** |
|
01000 |
warning |
0100C |
dynamic_result_sets_returned |
01008 |
implicit_zero_bit_padding |
01003 |
null_value_eliminated_in_set_function |
01007 |
privilege_not_granted |
01006 |
privilege_not_revoked |
01004 |
string_data_right_truncation |
01P01 |
deprecated_feature |
Class 02 - 데이터 없음 |
|
02000 |
no_data |
02001 |
no_additional_dynamic_result_sets_returned |
Class 03 - SQL 구문이 아직 완료되지 않음 |
|
03000 |
sql_statement_not_yet_complete |
Class 08 - 연결 예외 |
|
08000 |
connection_exception |
08003 |
connection_does_not_exist |
08006 |
connection_failure |
08001 |
sqlclient_unable_to_establish_sqlconnection |
08004 |
sqlserver_rejected_establishment_of_sqlconnection |
08007 |
transaction_resolution_unknown |
08P01 |
protocol_violation |
Class 09 - 트리거된 동작 예외 |
|
09000 |
triggered_action_exception |
Class 0A - 지원되지 않는 기능 |
|
0A000 |
feature_not_supported |
Class 0B - 잘못된 트랜잭션 시작 |
|
0B000 |
invalid_transaction_initiation |
Class 0F - 로케이터 예외 |
|
0F000 |
locator_exception |
0F001 |
invalid_locator_specification |
Class 0L - 잘못된 권한 부여자 |
|
0L000 |
invalid_grantor |
0LP01 |
invalid_grant_operation |
Class 0P - 잘못된 롤 지정 |
|
0P000 |
invalid_role_specification |
Class 0Z - 진단 예외 |
|
0Z000 |
diagnostics_exception |
0Z002 |
stacked_diagnostics_accessed_without_active_handler |
Class 20 - CASE를 찾을 수 없음 |
|
20000 |
case_not_found |
Class 21 - 카디널리티 위반 |
|
21000 |
cardinality_violation |
Class 22 - 데이터 예외 |
|
22000 |
data_exception |
2202E |
array_subscript_error |
22021 |
character_not_in_repertoire |
22008 |
datetime_field_overflow |
22012 |
division_by_zero |
22005 |
error_in_assignment |
2200B |
escape_character_conflict |
22022 |
indicator_overflow |
22015 |
interval_field_overflow |
2201E |
invalid_argument_for_logarithm |
22014 |
invalid_argument_for_ntile_function |
22016 |
invalid_argument_for_nth_value_function |
2201F |
invalid_argument_for_power_function |
2201G |
invalid_argument_for_width_bucket_function |
22018 |
invalid_character_value_for_cast |
22007 |
invalid_datetime_format |
22019 |
invalid_escape_character |
2200D |
invalid_escape_octet |
22025 |
invalid_escape_sequence |
22P06 |
nonstandard_use_of_escape_character |
22010 |
invalid_indicator_parameter_value |
22023 |
invalid_parameter_value |
2201B |
invalid_regular_expression |
2201W |
invalid_row_count_in_limit_clause |
2201X |
invalid_row_count_in_result_offset_clause |
2202H |
invalid_tablesample_argument |
2202G |
invalid_tablesample_repeat |
22009 |
invalid_time_zone_displacement_value |
2200C |
invalid_use_of_escape_character |
2200G |
most_specific_type_mismatch |
22004 |
null_value_not_allowed |
22002 |
null_value_no_indicator_parameter |
22003 |
numeric_value_out_of_range |
22026 |
string_data_length_mismatch |
22001 |
string_data_right_truncation |
22011 |
substring_error |
22027 |
trim_error |
22024 |
unterminated_c_string |
2200F |
zero_length_character_string |
22P01 |
floating_point_exception |
22P02 |
invalid_text_representation |
22P03 |
invalid_binary_representation |
22P04 |
bad_copy_file_format |
22P05 |
untranslatable_character |
2200L |
not_an_xml_document |
2200M |
invalid_xml_document |
2200N |
invalid_xml_content |
2200S |
invalid_xml_comment |
2200T |
invalid_xml_processing_instruction |
Class 23 - 무결성 제약조건 위반 |
|
23000 |
integrity_constraint_violation |
23001 |
restrict_violation |
23502 |
not_null_violation |
23503 |
foreign_key_violation |
23505 |
unique_violation |
23514 |
check_violation |
23P01 |
exclusion_violation |
Class 24 - 잘못된 커서 상태 |
|
24000 |
invalid_cursor_state |
Class 25 - 잘못된 트랜잭션 상태 |
|
25000 |
invalid_transaction_state |
25001 |
active_sql_transaction |
25002 |
branch_transaction_already_active |
25008 |
held_cursor_requires_same_isolation_level |
25003 |
inappropriate_access_mode_for_branch_transaction |
25004 |
inappropriate_isolation_level_for_branch_transaction |
25005 |
no_active_sql_transaction_for_branch_transaction |
25006 |
read_only_sql_transaction |
25007 |
schema_and_data_statement_mixing_not_supported |
25P01 |
no_active_sql_transaction |
25P02 |
in_failed_sql_transaction |
25P03 |
idle_in_transaction_session_timeout |
Class 26 - 잘못된 SQL 구문 이름 |
|
26000 |
invalid_sql_statement_name |
***Class 27 - 트리거된 데이터 변경 위반 *** |
|
27000 |
triggered_data_change_violation |
Class 28 - 잘못된 권한 부여 지정 |
|
28000 |
invalid_authorization_specification |
28P01 |
invalid_password |
Class 2B - 종속 권한 디스크립터가 여전히 존재함 |
|
2B000 |
dependent_privilege_descriptors_still_exist |
2BP01 |
dependent_objects_still_exist |
***Class 2D - 잘못된 트랜잭션 종료 *** |
|
2D000 |
invalid_transaction_termination |
Class 2F - SQL 루틴 예외 |
|
2F000 |
sql_routine_exception |
2F005 |
function_executed_no_return_statement |
2F002 |
modifying_sql_data_not_permitted |
2F003 |
prohibited_sql_statement_attempted |
2F004 |
reading_sql_data_not_permitted |
Class 34 - 잘못된 커서 이름 |
|
34000 |
invalid_cursor_name |
Class 38 - 외부 루틴 예외 |
|
38000 |
external_routine_exception |
38001 |
containing_sql_not_permitted |
38002 |
modifying_sql_data_not_permitted |
38003 |
prohibited_sql_statement_attempted |
38004 |
reading_sql_data_not_permitted |
Class 39 - 외부 루틴 호출 예외 |
|
39000 |
external_routine_invocation_exception |
39001 |
invalid_sqlstate_returned |
39004 |
null_value_not_allowed |
39P01 |
trigger_protocol_violated |
39P02 |
srf_protocol_violated |
39P03 |
event_trigger_protocol_violated |
Class 3B - 세이브포인트 예외 |
|
3B000 |
savepoint_exception |
3B001 |
invalid_savepoint_specification |
Class 3D - 잘못된 카탈로그 이름 |
|
3D000 |
invalid_catalog_name |
Class 3F - 잘못된 스키마 이름 |
|
3F000 |
invalid_schema_name |
Class 40 - 트랜잭션 롤백 |
|
40000 |
transaction_rollback |
40002 |
transaction_integrity_constraint_violation |
40001 |
serialization_failure |
40003 |
statement_completion_unknown |
40P01 |
deadlock_detected |
Class 42 - 구문 오류 또는 접근 규칙 위반 |
|
42000 |
syntax_error_or_access_rule_violation |
42601 |
syntax_error |
42501 |
insufficient_privilege |
42846 |
cannot_coerce |
42803 |
grouping_error |
42P20 |
windowing_error |
42P19 |
invalid_recursion |
42830 |
invalid_foreign_key |
42602 |
invalid_name |
42622 |
name_too_long |
42939 |
reserved_name |
42804 |
datatype_mismatch |
42P18 |
indeterminate_datatype |
42P21 |
collation_mismatch |
42P22 |
indeterminate_collation |
42809 |
wrong_object_type |
42703 |
undefined_column |
42883 |
undefined_function |
42P01 |
undefined_table |
42P02 |
undefined_parameter |
42704 |
undefined_object |
42701 |
duplicate_column |
42P03 |
duplicate_cursor |
42P04 |
duplicate_database |
42723 |
duplicate_function |
42P05 |
duplicate_prepared_statement |
42P06 |
duplicate_schema |
42P07 |
duplicate_table |
42712 |
duplicate_alias |
42710 |
duplicate_object |
42702 |
ambiguous_column |
42725 |
ambiguous_function |
42P08 |
ambiguous_parameter |
42P09 |
ambiguous_alias |
42P10 |
invalid_column_reference |
42611 |
invalid_column_definition |
42P11 |
invalid_cursor_definition |
42P12 |
invalid_database_definition |
42P13 |
invalid_function_definition |
42P14 |
invalid_prepared_statement_definition |
42P15 |
invalid_schema_definition |
42P16 |
invalid_table_definition |
42P17 |
invalid_object_definition |
Class 44 - WITH CHECK OPTION 위반 |
|
44000 |
with_check_option_violation |
Class 53 - 리소스 부족 |
|
53000 |
insufficient_resources |
53100 |
disk_full |
53200 |
out_of_memory |
53300 |
too_many_connections |
53400 |
configuration_limit_exceeded |
Class 54 - 프로그램 제한 초과 |
|
54000 |
program_limit_exceeded |
54001 |
statement_too_complex |
54011 |
too_many_columns |
54023 |
too_many_arguments |
Class 55 - 객체가 사전 요구 상태가 아님 |
|
55000 |
object_not_in_prerequisite_state |
55006 |
object_in_use |
55P02 |
cant_change_runtime_param |
55P03 |
lock_not_available |
Class 57 - 운영자 개입 |
|
57000 |
operator_intervention |
57014 |
query_canceled |
57P01 |
admin_shutdown |
57P02 |
crash_shutdown |
57P03 |
cannot_connect_now |
57P04 |
database_dropped |
Class 58 - 시스템 오류 |
|
58000 |
system_error |
58030 |
io_error |
58P01 |
undefined_file |
58P02 |
duplicate_file |
Class 72 - 스냅샷 실패 |
|
72000 |
snapshot_too_old |
Class F0 - 설정 파일 오류 |
|
F0000 |
config_file_error |
F0001 |
lock_file_exists |
Class HV - Foreign Data Wrapper 오류 |
|
HV000 |
fdw_error |
HV005 |
fdw_column_name_not_found |
HV002 |
fdw_dynamic_parameter_value_needed |
HV010 |
fdw_function_sequence_error |
HV021 |
fdw_inconsistent_descriptor_information |
HV024 |
fdw_invalid_attribute_value |
HV007 |
fdw_invalid_column_name |
HV008 |
fdw_invalid_column_number |
HV004 |
fdw_invalid_data_type |
HV006 |
fdw_invalid_data_type_descriptors |
HV091 |
fdw_invalid_descriptor_field_identifier |
HV00B |
fdw_invalid_handle |
HV00C |
fdw_invalid_option_index |
HV00D |
fdw_invalid_option_name |
HV090 |
fdw_invalid_string_length_or_buffer_length |
HV00A |
fdw_invalid_string_format |
HV009 |
fdw_invalid_use_of_null_pointer |
HV014 |
fdw_too_many_handles |
HV001 |
fdw_out_of_memory |
HV00P |
fdw_no_schemas |
HV00J |
fdw_option_name_not_found |
HV00K |
fdw_reply_handle |
HV00Q |
fdw_schema_not_found |
HV00R |
fdw_table_not_found |
HV00L |
fdw_unable_to_create_execution |
HV00M |
fdw_unable_to_create_reply |
HV00N |
fdw_unable_to_establish_connection |
Class P0 - PL/pgSQL 오류 |
|
P0000 |
plpgsql_error |
P0001 |
raise_exception |
P0002 |
no_data_found |
P0003 |
too_many_rows |
P0004 |
assert_failure |
Class XX - 내부 오류 |
|
XX000 |
internal_error |
XX001 |
data_corrupted |
XX002 |
index_corrupted |
용어
데이터베이스 클러스터
Server (또는 Node)
AgensGraph가 설치된 하드웨어(실제 또는 가상)를 의미합니다.Cluster (또는 ‘Database Cluster’)
파일 시스템 내의 저장 공간(디렉터리, 하위 디렉터리, 파일)을 의미합니다. 데이터베이스 클러스터는 “사용자 및 권한”과 같은 전역 객체 정의도 가지고 있습니다. 이러한 항목은 전체 데이터베이스에 영향을 미칩니다. 데이터베이스 클러스터에는 최소 세 개의 데이터베이스(‘template0’, ‘template1’, ‘postgres’)가 있습니다. 각 데이터베이스의 역할은 다음과 같습니다.
template0’: CREATE DATABASE 명령으로 사용할 수 있는 템플릿 데이터베이스(template0은 절대 수정해서는 안 됩니다)
template1’: CREATE DATABASE 명령으로 사용할 수 있는 템플릿 데이터베이스(template1은 DBA가 수정할 수 있습니다)
postgres’: 주로 유지 관리 목적으로 사용되는 빈 데이터베이스Instance (또는 ‘Database Server Instance’ 또는 ‘Database Server’ 또는 ‘Backend’)
인스턴스는 UNIX 서버에서 하나의 프로세스 그룹입니다. Windows 서버에서는 서비스와 클러스터를 제어하고 관리하는 공유 메모리입니다. IP 관점에서 보면 인스턴스는 IP/포트 조합(예: http://localhost:5432)을 점유한다고 볼 수 있습니다. 즉, 동일한 서버에서 서로 다른 포트로 서로 다른 인스턴스를 실행할 수 있습니다. 또한 서버에 여러 클러스터가 있는 경우 클러스터마다 단일 시스템에서 여러 인스턴스를 실행하는 것도 가능합니다.Database
데이터베이스는 객체 컬렉션이 파일로 저장되는 파일 시스템 내의 저장 영역입니다. 객체는 데이터, 메타데이터(테이블 정의, 데이터 타입, 제약조건, 뷰 등) 및 인덱스와 같은 기타 데이터로 구성되며, 이들은 모두 기본 데이터베이스 ‘postgres’ 또는 새로 생성된 데이터베이스에 저장됩니다. 하나의 데이터베이스에 대한 저장 영역은 데이터베이스 클러스터 저장 영역 내의 단일 하위 디렉터리 트리로 구성됩니다. 즉, 하나의 데이터베이스 클러스터에는 여러 데이터베이스가 포함될 수 있습니다.Schema
데이터베이스 내의 네임스페이스입니다. 스키마는 데이터베이스의 다른 스키마에 있는 객체 이름과 동일한 이름을 가질 수 있는, 이름이 지정된 객체(테이블, 데이터 타입, 함수, 연산자)로 구성됩니다. 모든 데이터베이스는 기본 스키마 ‘public’을 포함하며 추가 스키마를 포함할 수 있습니다. 스키마 내의 모든 객체는 동일한 데이터베이스에 있어야 하며, 동일한 데이터베이스 내의 다른 스키마에 있는 객체는 동일한 이름을 가질 수 있습니다. 각 데이터베이스에는 특수 스키마인 ‘pg_catalog’가 있으며, ‘pg_catalog’는 모든 시스템 테이블, 내장 데이터 타입, 함수 및 연산자를 포함합니다.Search Path (또는 ‘Schema Search Path’)
스키마 이름의 목록입니다. 애플리케이션이 한정되지 않은 객체 이름(예: 테이블 이름 ‘employee_table’)을 사용하는 경우, 검색 경로를 사용하여 지정된 스키마 순서로 이 객체를 찾습니다. ‘pg_catalog’ 스키마는 검색 경로에 명시되어 있지 않지만 항상 검색 경로의 첫 번째 부분입니다. 이 동작 덕분에 AgensGraph는 시스템 객체를 찾을 수 있습니다.initdb (OS 명령)
initdb는 새 클러스터(‘template0’, ‘template1’, ‘postgres’ 포함)를 생성합니다.
일관된 쓰기
Checkpoint
체크포인트는 데이터베이스 파일이 일관된 상태임이 보장되는 시점입니다. 체크포인트 시점에는 모든 변경 사항이 WAL 파일에 기록되고, 공유 버퍼의 모든 더티 데이터 페이지가 디스크로 플러시되며, 마지막으로 체크포인트 레코드가 WAL 파일에 기록됩니다. 인스턴스의 체크포인트 프로세스는 정기적인 일정에 따라 트리거됩니다. 또한 클라이언트 프로그램에서 CHECKPOINT 명령을 통해 강제로 실행할 수도 있습니다. 데이터베이스 시스템의 경우 체크포인트 명령은 물리적으로 디스크에 기록되므로 실행하는 데 많은 시간이 소요됩니다.WAL File
WAL 파일은 INSERT, UPDATE, DELETE 또는 CREATE TABLE과 같은 명령을 통해 데이터에 적용되는 변경 사항으로 구성됩니다. 이는 (더 나은 성능을 위해) 데이터 파일에도 기록되므로 중복된 정보입니다. 인스턴스의 설정에 따라 더 많은 정보가 WAL 파일에 기록될 수 있습니다. WAL 파일은 pg_wal 디렉터리(버전 10 이하에서는 pg_xlog)에 16MB 고정 크기의 바이너리 형식으로 존재합니다. WAL 파일 내의 단일 정보 단위를 로그 레코드라고 합니다.Logfile
인스턴스는 특수한 상황에 대한 경고 및 오류 메시지를 사람이 읽을 수 있는 텍스트 파일에 기록하고 보고합니다. 여기에 기록되는 로그 파일은 클러스터를 제외한 서버의 어느 위치에나 저장할 수 있습니다.Log Record
로그 레코드는 WAL 파일 내의 단일 정보 단위입니다.
FAQ
어떤 디버깅 기능이 있습니까?
컴파일 시점
먼저 새로운 C 코드를 사용하여 개발하는 경우에는 항상 --enable-cassert 및 --enable-debug options로 구성된 빌드 환경에서 작업해야 합니다. 디버그 심볼을 활성화하면 디버거(예: gdb)를 사용하여 오작동하는 코드를 추적할 수 있습니다.
gcc로 컴파일할 때 -ggdb -Og -g3 -fno-omit-frame-pointer라는 추가 옵션은 많은 디버깅 정보를 삽입하므로 유용합니다. 다음과 같이 configure에 전달할 수 있습니다.
./configure --enable-cassert --enable-debug CFLAGS="-ggdb -Og -g3 -fno-omit-frame-pointer"
-Og 대신 -O0을 사용하면 인라이닝을 포함한 대부분의 컴파일러 최적화가 비활성화됩니다. 그러나 -Og는 -O2나 -Os와 같은 일반적인 최적화 플래그와 거의 비슷하게 동작하면서도 더 많은 디버그 정보를 제공합니다. -Og는 <value optimized out> 변수가 훨씬 적고, 실행 순서 변경에서 발생하는 혼란이나 어려움이 적으면서도 상당히 유용한 성능을 제공합니다. -ggdb -g3은 gcc가 매크로 정의와 같은 항목을 포함하여 생성된 바이너리에 최대한 많은 디버그 정보를 포함하도록 지시합니다. -fno-omit-frame-pointer는 프레임 포인터를 사용하는 추적 및 프로파일링 도구(예: perf)를 사용할 때 유용한데, 프레임 포인터를 통해 이러한 도구가 스택 최상위 함수뿐만 아니라 호출 스택까지 캡처할 수 있기 때문입니다.
실행 시점
postgres 서버에는 상세 정보(elog 또는 ereport DEBUGn 출력)를 기록하는 -d 옵션이 있습니다. -d 옵션은 디버그 레벨을 지정하는 숫자를 받습니다. 디버그 레벨 값이 높으면 큰 로그 파일이 생성된다는 점에 유의하십시오. 이 옵션은 ag_ctl을 통해 서버를 시작할 때는 사용할 수 없지만, -o log_min_messages = debug4 또는 이와 유사한 방법을 사용할 수 있습니다.
gdb
postmaster가 실행 중이라면, 한 창에서 agens를 시작하고 SELECT pg_backend_pid()를 사용하여 agens가 사용하는 postgres 프로세스의 PID를 찾습니다.
디버거를 사용하여 postgres PID에 연결하려면 -gdb -p 1234를 사용하거나, 실행 중인 gdb 내에서 attach 1234를 사용합니다. gdblive 스크립트도 유용할 수 있습니다. 디버거에서 브레이크포인트를 설정한 다음 agens 세션에서 쿼리를 실행할 수 있습니다.
오류나 로그 메시지를 생성하는 위치를 찾으려면 errfinish에 브레이크포인트를 설정하십시오. 이렇게 하면 사용 가능한 로그 레벨에서 모든 elog 및 ereport 호출을 트랩하게 되므로 많은 트리거가 발생할 수 있습니다. ERROR/FATAL/PANIC에만 관심이 있다면, errordata[errordata_stack_depth].elevel >= 20에 대한 gdb 조건부 브레이크포인트를 사용하거나, errfinish의 PANIC, FATAL, ERROR에 소스 라인 브레이크포인트를 설정하십시오. 모든 오류가 errfinish를 거치는 것은 아닙니다. 특히 권한 검사는 별도로 수행됩니다. 브레이크포인트가 트리거되지 않으면 오류 텍스트에 대해 git grep을 실행하여 어디에서 발생했는지 확인하십시오.
세션을 시작할 때 발생한 문제를 디버깅하는 경우에는 PGOPTIONS="-W n"을 설정한 후 agens를 시작할 수 있습니다. 그러면 시작을 n초 동안 지연시킨 다음, 디버거를 사용하여 프로세스에 연결하고 적절한 브레이크포인트를 설정한 후 시작 시퀀스를 계속 진행할 수 있습니다.
디버깅을 위해 pg_stat_activity, 로그,
pg_locks, pg_stat_replication 등을 살펴보며 대상 프로세스를 식별할 수도 있습니다.
initdb가 깨졌습니다. 어떻게 디버깅합니까?
때때로 패치가 initdb 실패를 유발할 수 있습니다. 이러한 실패는 initdb 자체에서는 드뭅니다. 실패는 initdb에 의해 더 자주 시작되는 postgres 백엔드에서 일부 설정 작업을 수행하는 과정에서 발생합니다.
그중 하나가 충돌하더라도 initdb에 gdb를 붙이는 것 자체는 괜찮으며, initdb 자체는 충돌하지 않으므로 gdb는 중단되지 않습니다.
해야 할 일은 gdb에서 initdb를 실행하고, fork에 브레이크포인트를 설정한 다음 실행을 계속하는 것뿐입니다. 브레이크포인트가 트리거되면 함수가 종료됩니다. gdb는 자식 프로세스가 생성되었다고 보고합니다. 그러나 실제 postgres 인스턴스를 시작한 것은 셸이므로 이것은 원하는 결과가 아닙니다.
initdb가 일시 중지된 동안 ps를 사용하여 시작된 postgres 인스턴스를 찾습니다. 이를 위해 pstree -p가 유용할 수 있습니다. 찾았다면 gdb -p $ the_postgres_pid로 별도의 gdb 세션을 연결합니다. 이 시점에서 initdb에서 gdb를 안전하게 분리하고 실패한 postgres 인스턴스를 디버깅할 수 있습니다.
파싱 쿼리를 변경해야 합니다. 파서 파일을 간략히 설명해 주시겠습니까?
파서 파일은 src/backend/parser 디렉터리에 있습니다.
scan.l은 문자열(SQL 구문 포함)을 토큰 스트림으로 분할하는 알고리즘인 렉서를 정의합니다. 토큰은 보통 단일 단어이며 공백을 포함하지 않습니다. 토큰은 공백으로 구분됩니다. 예를 들어 큰따옴표 또는 작은따옴표로 묶인 문자열일 수 있습니다. 렉서는 기본적으로 다양한 토큰 유형을 설명하는 정규 표현식으로 정의됩니다.
gram.y는 렉서가 생성한 토큰을 기본 구성 요소로 사용하여 SQL 구문의 문법(구문 구조)을 정의합니다. 문법은 BNF 표기법으로 정의됩니다. BNF는 정규 표현식과 유사하지만 문자 단위가 아닌 토큰 단위에서 동작합니다. 패턴(BNF에서는 규칙 또는 생성 규칙이라고도 함)에는 이름이 지정되며 재귀적일 수 있습니다. 즉, 자기 자신을 하위 패턴으로 사용할 수 있습니다.
실제 렉서는 flex라는 도구를 사용하여 scan.l에서 생성됩니다. 해당 매뉴얼은 http://flex.sourceforge.net/manual/에서 찾을 수 있습니다.
실제 파서는 bison이라는 도구를 사용하여 gram.y에서 생성됩니다. 관련 가이드는 http://www.gnu.org/s/bison/에서 찾을 수 있습니다.
다만, 이전에 flex나 bison을 사용해 본 적이 없다면 학습하기가 다소 어려울 수 있습니다.
백엔드 코드에서 시스템 카탈로그의 정보에 효율적으로 접근하려면 어떻게 합니까?
먼저 관심 있는 튜플(로우)을 찾아야 합니다. 두 가지 방법이 있습니다. 첫째, SearchSysCache() 및 관련 함수를 사용하면 카탈로그의 사전 정의된 인덱스를 통해 시스템 카탈로그를 조회할 수 있습니다. 이는 시스템 테이블에 접근하는 기본적인 방법인데, 캐시에 대한 첫 호출이 필요한 로우를 로드한 후에는 이후 요청에서 기본 테이블에 접근하지 않고도 결과를 반환할 수 있기 때문입니다. 사용 가능한 캐시 목록은 src/backend/utils/cache/syscache.c에 있습니다. 많은 칼럼별 캐시 조회는 src/backend/utils/cache/lsyscache.c에 포함되어 있습니다.
반환되는 로우는 캐시가 소유한 버전의 힙 로우입니다. 따라서 SearchSysCache()가 반환한 튜플을 수정하거나 삭제해서는 안 됩니다. 사용을 마쳤으면 ReleaseSysCache()로 해제해야 합니다. 이는 필요한 경우 튜플을 삭제할 수 있다는 것을 캐시에 알립니다. ReleaseSysCache()를 호출하지 않으면 캐시 항목은 트랜잭션이 끝날 때까지 캐시에 잠긴 상태로 유지됩니다. 이는 개발 단계에서만 허용될 수 있습니다(릴리스할 만한 코드에서는 허용되지 않습니다).
시스템 캐시를 사용할 수 없는 경우에는 모든 백엔드가 공유하는 버퍼 캐시를 사용하여 힙 테이블에서 직접 데이터를 가져와야 합니다. 백엔드는 자동으로 로우를 버퍼 캐시에 로드합니다. 이를 위해 heap_open()을 사용하여 테이블을 엽니다. 그런 다음 heap_beginscan()을 사용하여 테이블 스캔을 시작하고, heap_getnext()를 사용하고 HeapTupleIsValid()가 true를 반환하는 동안 계속 진행합니다.
이제 heap_endscan()을 실행합니다. 스캔에 키를 할당할 수 있습니다. 인덱스를 사용하지 않으므로 모든 로우가 키와 비교되고 유효한 로우만 반환됩니다.
heap_fetch()를 사용하여 블록 번호/오프셋으로 로우를 가져올 수도 있습니다. 검사기가 버퍼 캐시의 로우를 자동으로 잠그고 해제하지만, heap_fetch()에는 버퍼 포인터를 전달해야 합니다. 완료되면 releaseBuffer()를 전달해야 합니다.
로우가 확보되면 HeapTuple 구조체 항목에 접근하여 t_self 및 t_oid와 같이 모든 튜플에 공통된 데이터를 가져올 수 있습니다. 테이블 관련 칼럼이 필요하다면 HeapTuple 포인터를 가져온 다음 GETSTRUCT() 매크로를 사용하여 테이블 관련 시작 튜플에 접근해야 합니다. 그런 다음 포인터를 캐스팅합니다(예: pg_proc 테이블에 접근하는 경우 Form_pg_proc, pg_type에 접근하는 경우 Form_pg_type). 그러면 구조체 포인터를 사용하여 튜플의 필드에 접근할 수 있습니다: ((Form_pg_class) GETSTRUCT (tuple))->relnatts
그러나 이는 해당 칼럼이 고정 폭이고 non-null이며, 이전의 모든 칼럼이 고정 폭이고 반드시 null이 아닌 경우에만 동작합니다. 그렇지 않으면 칼럼의 위치가 가변적이므로 heap_getattr() 또는 관련 함수를 사용하여 튜플에서 추출해야 합니다.
라이브 튜플을 변경하여 구조체 필드에 직접 저장하지 마십시오. 가장 좋은 방법은 heap_modifytuple()을 사용하여 원본 튜플과 변경하려는 값을 전달하는 것입니다. 이는 palloc으로 묶인 튜플을 반환하며, 이를 heap_update()에 전달합니다. 튜플의 t_self를 heap_delete()에 전달하여 튜플을 삭제할 수 있습니다. heap_update()에도 t_self를 사용합니다. 튜플은 ReleaseSysCache() 호출 후 사라질 수 있는 시스템 캐시의 복사본이거나, heap_fetch()의 경우 heap_getnext(), heap_endscan 또는 ReleaseBuffer()가 사라질 때 디스크 버퍼에서 직접 읽는 것일 수 있습니다(또는 palloc 튜플일 수도 있습니다). 완료되면 pfree()를 수행해야 합니다.
새 포트를 어떻게 추가합니까?
새 포트를 추가하려면 수정해야 할 곳이 많습니다. src/template 디렉터리부터 시작하십시오. 해당 OS에 적절한 항목을 추가합니다. src/config.guess를 사용하여 src/template/.similar에 OS를 추가합니다. OS 버전을 정확히 일치시킬 필요는 없습니다. configure 테스트는 올바른 OS 버전 번호를 찾으며, 찾지 못하면 버전 번호 없이 일치하는 것을 찾습니다. src/configure.in을 편집하여 새 OS를 추가합니다. 위의 설정 항목을 참조하십시오. autoconf를 실행하거나 src/configure를 패치해야 합니다.
그런 다음 src/include/port를 확인하고 적절한 값으로 새 OS 파일을 추가합니다. 다행히 src/include/storage/s_lock.h에 CPU용 잠금 코드가 있습니다. 또한 포트별 Makefile 처리를 위한 src/makefiles 디렉터리도 있습니다. OS에 특수 파일이 필요한 경우를 위한 backend/port 디렉터리도 있습니다.