The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
25 RCSID("$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  */
203 sql_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:481
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition: cf_util.c:1578
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
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
#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 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
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
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
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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_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
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
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