IvorySQL:Optimize the VARIABLE and PRINT command codes#846
IvorySQL:Optimize the VARIABLE and PRINT command codes#846gaoxueyu merged 1 commit intoIvorySQL:masterfrom
Conversation
WalkthroughThis change refactors and clarifies Oracle-compatible client command handling in the psql interactive terminal and related headers. It improves comments, reorganizes declarations, and enhances documentation for maintainability. Minor code changes include using Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PSQL Mainloop
participant Oracle Scanner/Parser
User->>PSQL Mainloop: Enter Oracle-compatible command
PSQL Mainloop->>Oracle Scanner/Parser: Initialize scan state and scanner
Oracle Scanner/Parser-->>PSQL Mainloop: Parse result (VARIABLE/PRINT/other)
PSQL Mainloop->>PSQL Mainloop: Dispatch command based on parse result
PSQL Mainloop->>Oracle Scanner/Parser: Cleanup scanner and state
PSQL Mainloop-->>User: Output or error message
Estimated code review effort🎯 2 (Simple) | ⏱️ ~7 minutes Possibly related PRs
Poem
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (7)
src/bin/psql/variables.c (1)
979-983: First-character check now locale-dependent – consider pg_isalpha for consistency
isalpha()is invoked on ASCII bytes to decide if the first char is a letter.
Although you guard with!IS_HIGHBIT_SET, behaviour ofisalpha()still depends on the current locale, whereas the rest of the function uses an explicit ASCII whitelist for subsequent characters.
For complete locale-independence and consistency with the rest of the scan rules, preferpg_isalpha()(or revert to the explicit ASCII table) instead of<ctype.h>’sisalpha().src/bin/psql/mainloop.c (1)
485-514: Off-by-one risk when duplicating quotes
pg_malloc0(strlen(bind_var->init_value) * 2)can leave no room for
the terminating'\0'in the worst-case (input of length 1 produces
output length 1 plus NUL → need+1).
Allocate*2 + 1to be safe:- char *str_double_quote = pg_malloc0(strlen(bind_var->init_value) * 2); + char *str_double_quote = pg_malloc0(strlen(bind_var->init_value) * 2 + 1);src/bin/psql/psqlplus.h (5)
23-27: Good rationale on keyword categories; consider preventing drift with grammarThese comments help future readers. To avoid divergence from psqlplusparse.y over time, consider generating the keyword tables from a single source (e.g., an X-macro .def file included by both the scanner and parser).
42-44: Prefer designated initializers for robustnessThis avoids ordering mistakes if the struct changes later and improves readability.
Apply:
-/* Macro for defining keywords */ -#define PSQL_KEYWORD(name,value,category) {name,value,category}, +/* Macro for defining keywords (designated initializers for clarity) */ +#define PSQL_KEYWORD(name_, value_, category_) \ + { .name = (name_), .value = (value_), .category = (category_) },
49-53: OID docs — good; consider an explicit “FE-only” guardNice explanation. Optional: add a brief note that these defines must never be seen when including backend headers to avoid macro redefinition if someone accidentally includes pg_type_d.h in FE code.
63-66: Clarify units (bytes vs characters) for max lengthsOracle’s limits depend on CHAR vs BYTE semantics. Consider noting whether these maxima are in characters, bytes, or dependent on NLS length semantics to prevent misinterpretation downstream.
83-86: Don’t define objects in headers; move callbacks to a .c/.l moduleDefining a (file-scope) static in a header creates one copy per TU and can go stale. Prefer an extern declaration in the header and a single definition in the scanner module. Also consider zero-initialization instead of a “placeholder” element to avoid assumptions about struct shape.
Apply in header:
-/* Callback functions for the flex lexer */ -static const Ora_psqlScanCallbacks psqlplus_callbacks = { - NULL, /* placeholder for future callback functions */ -}; +/* Callback functions for the flex lexer (defined in psqlplus.l/.c) */ +extern const Ora_psqlScanCallbacks psqlplus_callbacks;And define once (e.g., in psqlplus.l or a new psqlplus_callbacks.c):
const Ora_psqlScanCallbacks psqlplus_callbacks = { 0 };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/bin/psql/Makefile(0 hunks)src/bin/psql/mainloop.c(1 hunks)src/bin/psql/psqlplus.h(3 hunks)src/bin/psql/psqlplusparse.y(1 hunks)src/bin/psql/variables.c(2 hunks)src/bin/psql/variables.h(2 hunks)src/include/fe_utils/psqlscan_int.h(3 hunks)
💤 Files with no reviewable changes (1)
- src/bin/psql/Makefile
🔇 Additional comments (7)
src/bin/psql/psqlplusparse.y (1)
90-91: No functional change – comment wording looks goodOnly wording updated; nothing to fix.
src/include/fe_utils/psqlscan_int.h (1)
88-95: Enum & struct comments improved – OKDocumentation-only edits; no action required.
src/bin/psql/variables.h (1)
85-95: Header refactor is comment-only – LGTMStructural and naming comments add clarity without affecting ABI.
src/bin/psql/psqlplus.h (4)
6-6: Abstract clarification — LGTMClear and precise about Oracle compatibility. No issues.
32-40: Keyword struct docs — LGTMField docs are clear. Using int16 for token and category is fine given typical token ranges.
68-72: Scanner/parser interface grouping — LGTMForward-declaring YYSTYPE and grouping interfaces improves readability.
75-82: Confirm flex/bison entrypoint signatures
psqlplus_scanner_init,psqlplus_scanner_finishandpsqlplus_yyerrorin src/bin/psql/psqlplusscan.l match the declarations in src/bin/psql/psqlplus.h.psqlplus_yyparsein mainloop.c lines 464–466 aligns with its header prototype.- The lexer function
psqlplus_yylexis generated by flex—please ensure your%option prefix="psqlplus_yy"andbison-bridge(or equivalent) settings produce a definition matching
extern int psqlplus_yylex(union YYSTYPE *lvalp, yyscan_t yyscanner);
| PsqlScanState pstate; | ||
| yyscan_t yyscanner; | ||
| char *psqlplus_line = pg_strdup(line); // Copy current input line for Oracle command processing | ||
|
|
||
| // Create and initialize Oracle compatibility mode scanning state | ||
| pstate = ora_psql_scan_create(&psqlplus_callbacks); | ||
| ora_psql_scan_setup(pstate, psqlplus_line, | ||
| strlen(psqlplus_line), |
There was a problem hiding this comment.
Undefined symbol psqlplus_callbacks – compilation will fail
pstate = ora_psql_scan_create(&psqlplus_callbacks);
psqlplus_callbacks is not declared anywhere in this TU (only Ora_psqlscan_callbacks exists above).
The build will break at link-time or compile-time depending on headers.
- pstate = ora_psql_scan_create(&psqlplus_callbacks);
+ pstate = ora_psql_scan_create(&Ora_psqlscan_callbacks);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PsqlScanState pstate; | |
| yyscan_t yyscanner; | |
| char *psqlplus_line = pg_strdup(line); // Copy current input line for Oracle command processing | |
| // Create and initialize Oracle compatibility mode scanning state | |
| pstate = ora_psql_scan_create(&psqlplus_callbacks); | |
| ora_psql_scan_setup(pstate, psqlplus_line, | |
| strlen(psqlplus_line), | |
| PsqlScanState pstate; | |
| yyscan_t yyscanner; | |
| char *psqlplus_line = pg_strdup(line); // Copy current input line for Oracle command processing | |
| // Create and initialize Oracle compatibility mode scanning state | |
| - pstate = ora_psql_scan_create(&psqlplus_callbacks); | |
| + pstate = ora_psql_scan_create(&Ora_psqlscan_callbacks); | |
| ora_psql_scan_setup(pstate, psqlplus_line, | |
| strlen(psqlplus_line), |
🤖 Prompt for AI Agents
In src/bin/psql/mainloop.c around lines 449 to 456, the symbol
psqlplus_callbacks is used but not declared, causing compilation errors. Replace
psqlplus_callbacks with the correctly declared symbol Ora_psqlscan_callbacks to
fix the undefined symbol issue and ensure successful compilation.
| /* Macro to get extra data from yyscanner */ | ||
| #define psql_yyget_extra(yyscanner) (*((PsqlScanStateData **) (yyscanner))) |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify yyscanner/extra layout; simplify macro to avoid aliasing surprises
This macro assumes yyscanner is actually a PsqlScanState* (i.e., a pointer to a PsqlScanState value), which is common in our psql scanner shim. If that assumption holds, the cast can be clearer and avoids referring to the concrete Data type.
Proposed change:
-/* Macro to get extra data from yyscanner */
-#define psql_yyget_extra(yyscanner) (*((PsqlScanStateData **) (yyscanner)))
+/* Macro to get extra data from yyscanner.
+ * Assumes yyscanner is a PsqlScanState* (see psqlplus_scanner_init). */
+#define psql_yyget_extra(yyscanner) (*(PsqlScanState *)(yyscanner))If instead the scanner is a real Flex reentrant scanner, prefer using the generated accessor (e.g., psqlplus_yyget_extra(yyscanner)) rather than hard-coding layout.
To double-check current usage and definitions, you can run:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -A2 -e 'typedef .* PsqlScanState;' fe_utils/psqlscan_int.h
rg -n -A3 -e 'psqlplus_scanner_init\\('
rg -n -A2 -e 'psqlplus_yyget_extra\\(|yyget_extra\\('Length of output: 150
I couldn’t locate the typedef or initialization functions with the prior commands—let’s broaden the search across the repo:
This will confirm the actual types and usages so we can validate (or update) the macro safely.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the header defining PsqlScanState / PsqlScanStateData
fd -t f psqlscan_int.h
# Search for typedefs
rg -n -A2 'typedef.*PsqlScanState'
rg -n -A2 'typedef.*PsqlScanStateData'
# Find where the scanner is initialized
rg -n -A2 'psqlplus_scanner_init'
# Find any generated accessors
rg -n -A2 'psqlplus_yyget_extra'Length of output: 2545
Let’s confirm what yyscan_t really is and how the scanner struct lays out its “extra” pointer:
This will tell us whether casting yyscan_t to a PsqlScanState * (vs. PsqlScanStateData **) is safe and compliant with strict-aliasing.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find how yyscan_t is defined
rg -n -A2 'typedef.*yyscan_t' -g '*.h'
# See any forward declarations of the guts struct
rg -n -A2 'struct.*yyguts_t' -g '*.h'
# Glimpse usage in psqlplus.h
rg -n -A2 'yyscan_t' src/bin/psql/psqlplus.hLength of output: 1343
Simplify psql_yyget_extra macro to use the PsqlScanState alias
We’ve confirmed in src/include/fe_utils/psqlscan.h (and its Oracle mirror) that
typedef struct PsqlScanStateData *PsqlScanState;and in src/include/fe_utils/psqlscan_int.h that
typedef void *yyscan_t;No generated psqlplus_yyget_extra accessor exists, and the Flex reentrant scanner stores the user‐state pointer (PsqlScanStateData*) as its first field. We can therefore simplify the cast to avoid naming the Data type directly.
File: src/bin/psql/psqlplus.h
Lines: 45–46
-/* Macro to get extra data from yyscanner */
-#define psql_yyget_extra(yyscanner) (*((PsqlScanStateData **) (yyscanner)))
+/* Macro to get extra data from yyscanner.
+ * Assumes yyscanner is a PsqlScanState* (see psqlplus_scanner_init). */
+#define psql_yyget_extra(yyscanner) (*(PsqlScanState *)(yyscanner))If in the future you switch to a “pure” Flex scanner, you can replace this with the generated psqlplus_yyget_extra(yyscanner) accessor instead.
🤖 Prompt for AI Agents
In src/bin/psql/psqlplus.h at lines 45-46, simplify the psql_yyget_extra macro
by casting yyscanner directly to the PsqlScanState type alias instead of
dereferencing to PsqlScanStateData*. Replace the current macro definition with
one that casts yyscanner to (PsqlScanState) to avoid referencing the Data struct
explicitly, aligning with the typedefs in psqlscan.h and psqlscan_int.h.
Summary by CodeRabbit
Refactor
Style