The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
sql_state.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: bd151fe16e6928449cddb6757077884537e7ee01 $
19 * @file sql_state.c
20 * @brief Implements sql_state matching and categorisation
21 *
22 * @copyright 2019 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2019 The FreeRADIUS server project
24 */
25RCSID("$Id: bd151fe16e6928449cddb6757077884537e7ee01 $")
26
27#include "rlm_sql.h"
28
29/** These are standard, universal, error classes which all SQL servers should produce
30 *
31 * @note Only vague descriptions of these errors were available when deciding return codes.
32 * If anyone wishes to change the classification of any of these errors, please send
33 * a pull request.
34 */
36 { "00", "Successful completion", RLM_SQL_OK },
37 { "01", "Warning", RLM_SQL_OK },
38 { "02", "No data", RLM_SQL_NO_MORE_ROWS },
39 { "07", "Dynamic SQL error", RLM_SQL_ERROR },
40 { "08", "Connection exception", RLM_SQL_RECONNECT },
41 { "09", "Triggered action exception", RLM_SQL_ERROR },
42 { "0A", "Feature not supported", RLM_SQL_ERROR },
43 { "0D", "Invalid target type specification", RLM_SQL_ERROR },
44 { "0E", "Invalid schema name list specification", RLM_SQL_ERROR },
45 { "0F", "Locator exception", RLM_SQL_ERROR },
46 { "0K", "Resignal when handler not active", RLM_SQL_ERROR },
47 { "0L", "Invalid grantor", RLM_SQL_ERROR },
48 { "0M", "Invalid sql-invoked procedure reference", RLM_SQL_ERROR },
49 { "0N", "SQL/XML mapping error", RLM_SQL_ERROR },
50 { "0P", "Invalid role specification", RLM_SQL_ERROR },
51 { "0S", "Invalid transform group name specification", RLM_SQL_ERROR },
52 { "0T", "Target table disagrees with cursor specification", RLM_SQL_ERROR },
53 { "0V", "Attempt to assign to ordering column", RLM_SQL_ERROR },
54 { "0W", "Prohibited statement encountered during trigger execution", RLM_SQL_ERROR },
55 { "0X", "Invalid foreign server specification", RLM_SQL_ERROR },
56 { "0Y", "Pass-through specific condition", RLM_SQL_ERROR },
57 { "0Z", "Diagnostics exception", RLM_SQL_ERROR },
58 { "20", "Case not found", RLM_SQL_ERROR },
59 { "21", "Cardinality violation", RLM_SQL_ERROR },
60 { "22", "Data exception", RLM_SQL_QUERY_INVALID },
61 { "23", "Integrity constraint violation", RLM_SQL_ALT_QUERY },
62 { "24", "Invalid cursor state", RLM_SQL_ERROR },
63 { "25", "Invalid transaction state", RLM_SQL_ERROR },
64 { "26", "Invalid sql statement name", RLM_SQL_QUERY_INVALID },
65 { "27", "Triggered data changed violation", RLM_SQL_ERROR },
66 { "28", "Invalid authorization specification", RLM_SQL_ERROR },
67 { "2B", "Dependent privilege descriptions still exist", RLM_SQL_ERROR },
68 { "2C", "Invalid character set name", RLM_SQL_ERROR },
69 { "2D", "Invalid transaction termination", RLM_SQL_ERROR },
70 { "2E", "Invalid connection name", RLM_SQL_ERROR },
71 { "2F", "SQL routine exception", RLM_SQL_ERROR },
72 { "2H", "Invalid collation name", RLM_SQL_ERROR },
73 { "30", "Invalid sql statement name", RLM_SQL_ERROR },
74 { "33", "Invalid sql descriptor name", RLM_SQL_ERROR },
75 { "34", "Invalid cursor name", RLM_SQL_QUERY_INVALID },
76 { "35", "Invalid condition number", RLM_SQL_ERROR },
77 { "36", "Cursor sensitivity exception", RLM_SQL_ERROR },
78 { "38", "External routine exception", RLM_SQL_ERROR },
79 { "39", "External routine invocation exception", RLM_SQL_ERROR },
80 { "3B", "Savepoint exception", RLM_SQL_ERROR },
81 { "3C", "Ambiguous cursor name", RLM_SQL_ERROR },
82 { "3D", "Invalid catalog name", RLM_SQL_ERROR },
83 { "3F", "Invalid schema name", RLM_SQL_ERROR },
84 { "40", "Transaction rollback", RLM_SQL_ERROR },
85 { "42", "Syntax error", RLM_SQL_QUERY_INVALID },
86 { "44", "With check option violation", RLM_SQL_ERROR },
87 { "45", "Unhandled user-defined exception", RLM_SQL_ERROR },
88 { "46", "Java DDL", RLM_SQL_ERROR },
89 { "HV", "FDW Error", RLM_SQL_ERROR },
90 { "HY", "CLI-Specific Condition", RLM_SQL_ERROR },
91 { "HZ", "RDA", RLM_SQL_ERROR },
92 { NULL, NULL, RLM_SQL_OK }
93};
94
95/** Allocate a sql_state trie, and insert the initial set of entries
96 *
97 * @param[in] ctx to allocate states in.
98 * @return
99 * - SQL state trie on success.
100 * - NULL on failure.
101 */
103{
104 fr_trie_t *states;
105
106 MEM(states = fr_trie_alloc(ctx, NULL, NULL));
107
109 talloc_free(states);
110 return NULL;
111 }
112
113 return states;
114}
115
116/** Insert the contents of a state table into the state trie
117 *
118 * @param[in] states Trie of states.
119 * @param[in] table to insert.
120 * @return
121 * - 0 on success.
122 * - -1 on failure.
123 */
125{
126 sql_state_entry_t const *entry;
127
128 for (entry = table; entry->sql_state; entry++) {
129 size_t len = strlen(entry->sql_state) * 8;
130 int ret;
131
132 fr_trie_remove_by_key(states, entry->sql_state, len); /* Remove any old entries */
133 ret = fr_trie_insert_by_key(states, entry->sql_state, len, entry);
134 if (ret < 0) {
135 PERROR("Failed inserting state");
136 }
137 if (!fr_cond_assert(ret == 0)) return -1;
138 }
139
140 return 0;
141}
142
143/** Insert the contents of a CONF_SECTION into the state trie
144 *
145 * The attribute side of the CONF_PAIR specifies the sqlclass and the value specifies the error code.
146 *
147 * @param[in] states Trie of states.
148 * @param[in] cs Containing overrides to define new sql state entries or change existing ones.
149 * @return
150 * - 0 on success.
151 * - -1 on failure.
152 */
154{
155 CONF_PAIR *cp = NULL;
156
157 while ((cp = cf_pair_find_next(cs, cp, NULL))) {
158 char const *state;
159 size_t len;
160 sql_rcode_t rcode;
161 sql_state_entry_t *entry;
162
163 state = cf_pair_attr(cp);
164 len = strlen(state) * 8;
165 if (len < 2) {
166 cf_log_err(cp, "Expected state to have a length between 2-5 chars, got %zu", len);
167 return -1;
168 }
169
170 /*
171 * Resolve value to sql_rcode_t
172 */
173 if (cf_pair_in_table((int32_t *)&rcode, sql_rcode_table, sql_rcode_table_len, cp) < 0) return -1;/* Logs own error */
174
175 /*
176 * No existing match, create a new entry
177 */
178 entry = fr_trie_match_by_key(states, state, len );
179 if (!entry) {
180 MEM(entry = talloc(states, sql_state_entry_t));
181 entry->sql_state = talloc_strdup(entry, state);
182 entry->meaning = "USER DEFINED";
183 entry->rcode = rcode;
184 (void) fr_trie_insert_by_key(states, state, len, entry);
185 } else {
186 entry->rcode = rcode; /* Override previous sql rcode */
187 }
188
189 cf_pair_mark_parsed(cp); /* Make sure it doesn't emit a warning later */
190 }
191
192 return 0;
193}
194
195/** Lookup an SQL state based on an error code returned from the SQL server or client library
196 *
197 * @param[in] states Trie of states.
198 * @param[in] sql_state to lookup.
199 * @return
200 * - An #sql_state_entry_t with the #sql_rcode_t associated with the sql state.
201 * - NULL if no entry exists.
202 */
203sql_state_entry_t const *sql_state_entry_find(fr_trie_t const *states, char const *sql_state)
204{
205 return fr_trie_lookup_by_key(states, sql_state, strlen(sql_state) * 8);
206}
#define RCSID(id)
Definition build.h:483
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition cf_util.c:1453
int cf_pair_in_table(int32_t *out, fr_table_num_sorted_t const *table, size_t table_len, CONF_PAIR *cp)
Check to see if the CONF_PAIR value is present in the specified table.
Definition cf_util.c:1966
void cf_pair_mark_parsed(CONF_PAIR *cp)
Mark a pair as parsed.
Definition cf_util.c:1376
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1578
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
#define PERROR(_fmt,...)
Definition log.h:228
talloc_free(reap)
sql_rcode_t rcode
What should happen if we receive this error.
Definition rlm_sql.h:70
size_t sql_rcode_table_len
Definition sql.c:63
char const * meaning
Verbose description.
Definition rlm_sql.h:69
fr_table_num_sorted_t const sql_rcode_table[]
Definition sql.c:55
sql_rcode_t
Action to take at end of an SQL query.
Definition rlm_sql.h:44
@ RLM_SQL_QUERY_INVALID
Query syntax error.
Definition rlm_sql.h:45
@ RLM_SQL_ALT_QUERY
Key constraint violation, use an alternative query.
Definition rlm_sql.h:49
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
Definition rlm_sql.h:48
@ RLM_SQL_ERROR
General connection/server error.
Definition rlm_sql.h:46
@ RLM_SQL_OK
Success.
Definition rlm_sql.h:47
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition rlm_sql.h:50
char const * sql_state
2-5 char error code.
Definition rlm_sql.h:68
Definition rlm_sql.h:67
int sql_state_entries_from_table(fr_trie_t *states, sql_state_entry_t const table[])
Insert the contents of a state table into the state trie.
Definition sql_state.c:124
fr_trie_t * sql_state_trie_alloc(TALLOC_CTX *ctx)
Allocate a sql_state trie, and insert the initial set of entries.
Definition sql_state.c:102
int sql_state_entries_from_cs(fr_trie_t *states, CONF_SECTION *cs)
Insert the contents of a CONF_SECTION into the state trie.
Definition sql_state.c:153
static sql_state_entry_t sql_2011_classes[]
These are standard, universal, error classes which all SQL servers should produce.
Definition sql_state.c:35
sql_state_entry_t const * sql_state_entry_find(fr_trie_t const *states, char const *sql_state)
Lookup an SQL state based on an error code returned from the SQL server or client library.
Definition sql_state.c:203
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
Definition trie.c:2154
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
Definition trie.c:741
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
Definition trie.c:1262
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
Definition trie.c:1286
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
Definition trie.c:1875