/************************************************************************* * * Function: sql_fetch_row * * Purpose: database specific fetch_row. Returns a SQL_ROW struct * with all the data for the query in 'sqlsocket->row'. Returns * 0 on success, -1 on failure, SQL_DOWN if 'database is down' * *************************************************************************/ static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) { int c, i; SQLINTEGER len, slen; SQL_ROW retval; rlm_sql_db2_sock *sock; sock = sqlsocket->conn; c = sql_num_fields(sqlsocket, config); retval = (SQL_ROW)rad_malloc(c*sizeof(char*)+1); /* advance cursor */ if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND) { sqlsocket->row = NULL; return 0; } for(i = 0; i < c; i++) { /* get column length */ SQLColAttribute(sock->stmt, i+1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len); retval[i] = (char*)rad_malloc(len+1); /* get the actual column */ SQLGetData(sock->stmt, i+1, SQL_C_CHAR, retval[i], len+1, &slen); if(slen == SQL_NULL_DATA) retval[i][0] = '\0'; } sqlsocket->row = retval; return 0; }
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query) { rlm_sql_unixodbc_conn_t *conn = handle->conn; SQLINTEGER i; SQLLEN len; int colcount; int state; /* Only state = 0 means success */ if ((state = sql_query(handle, config, query))) { return state; } colcount = sql_num_fields(handle, config); if (colcount < 0) { return RLM_SQL_ERROR; } /* Reserving memory for result */ conn->row = talloc_zero_array(conn, char *, colcount + 1); /* Space for pointers */ for (i = 1; i <= colcount; i++) { SQLColAttributes(conn->statement, ((SQLUSMALLINT) i), SQL_COLUMN_LENGTH, NULL, 0, NULL, &len); conn->row[i - 1] = talloc_array(conn->row, char, ++len); SQLBindCol(conn->statement, i, SQL_C_CHAR, (SQLCHAR *)conn->row[i - 1], len, NULL); } return RLM_SQL_OK; }
/************************************************************************* * * Function: sql_select_query * * Purpose: Issue a select query to the database * *************************************************************************/ static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query) { rlm_sql_unixodbc_conn_t *conn = handle->conn; SQLINTEGER column; SQLLEN len; int numfields; int state; /* Only state = 0 means success */ if ((state = sql_query(handle, config, query))) { return state; } numfields=sql_num_fields(handle, config); if (numfields < 0) { return -1; } /* Reserving memory for result */ conn->row = (char **) rad_malloc((numfields+1)*sizeof(char *)); conn->row[numfields] = NULL; for(column = 1; column <= numfields; column++) { SQLColAttributes(conn->statement,((SQLUSMALLINT) column),SQL_COLUMN_LENGTH,NULL,0,NULL,&len); conn->row[column-1] = (char*)rad_malloc((int)++len); SQLBindCol(conn->statement, column, SQL_C_CHAR, (SQLCHAR *)conn->row[column-1], len, NULL); } return 0; }
/************************************************************************* * * Function: sql_query * * Purpose: Issue a query to the database * *************************************************************************/ static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr) { rlm_sql_postgres_sock *pg_sock = sqlsocket->conn; if (config->sqltrace) radlog(L_DBG,"rlm_sql_postgresql: query:\n%s", querystr); if (pg_sock->conn == NULL) { radlog(L_ERR, "rlm_sql_postgresql: Socket not connected"); return SQL_DOWN; } pg_sock->result = PQexec(pg_sock->conn, querystr); /* Returns a result pointer or possibly a NULL pointer. * A non-NULL pointer will generally be returned except in * out-of-memory conditions or serious errors such as inability * to send the command to the backend. If a NULL is returned, * it should be treated like a PGRES_FATAL_ERROR result. * Use PQerrorMessage to get more information about the error. */ if (!pg_sock->result) { radlog(L_ERR, "rlm_sql_postgresql: PostgreSQL Query failed Error: %s", PQerrorMessage(pg_sock->conn)); return SQL_DOWN; } else { ExecStatusType status = PQresultStatus(pg_sock->result); radlog(L_DBG, "rlm_sql_postgresql: Status: %s", PQresStatus(status)); radlog(L_DBG, "rlm_sql_postgresql: affected rows = %s", PQcmdTuples(pg_sock->result)); if (!status_is_ok(status)) return sql_check_error(status); if (strncasecmp("select", querystr, 6) != 0) { /* store the number of affected rows because the sql module * calls finish_query before it retrieves the number of affected * rows from the driver */ pg_sock->affected_rows = affected_rows(pg_sock->result); return 0; } else { if ((sql_store_result(sqlsocket, config) == 0) && (sql_num_fields(sqlsocket, config) >= 0)) return 0; else return -1; } } }
/************************************************************************* * * Function: sql_free_result * * Purpose: database specific free_result. Frees memory allocated * for a result set * *************************************************************************/ static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { int i=0; rlm_sql_iodbc_conn_t *conn = handle->conn; for(i=0; i<sql_num_fields(handle, config); i++) { free(conn->row[i]); } free(conn->row); conn->row=NULL; SQLFreeStmt( conn->stmt_handle, SQL_DROP ); return 0; }
/************************************************************************* * * Function: sql_num_fields * * Purpose: database specific num_fields function. Returns number * of columns from query * *************************************************************************/ static int sql_num_fields(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config) { int num = 0; rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn; #if MYSQL_VERSION_ID >= 32224 if (!(num = mysql_field_count(mysql_sock->sock))) { #else if (!(num = mysql_num_fields(mysql_sock->sock))) { #endif radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: No Fields"); radlog(L_ERR, "rlm_sql_mysql: MYSQL error: %s", mysql_error(mysql_sock->sock)); } return num; } /************************************************************************* * * Function: sql_select_query * * Purpose: Issue a select query to the database * *************************************************************************/ static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) { int ret; ret = sql_query(sqlsocket, config, querystr); if(ret) return ret; ret = sql_store_result(sqlsocket, config); if (ret) { return ret; } /* Why? Per http://www.mysql.com/doc/n/o/node_591.html, * this cannot return an error. Perhaps just to complain if no * fields are found? */ sql_num_fields(sqlsocket, config); return ret; }
/************************************************************************* * * Function: sql_free_result * * Purpose: database specific free_result. Frees memory allocated * for a result set * *************************************************************************/ static int sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_sock *unixodbc_sock = handle->conn; int column, numfileds=sql_num_fields(handle, config); /* Freeing reserved memory */ if(unixodbc_sock->row != NULL) { for(column=0; column<numfileds; column++) { if(unixodbc_sock->row[column] != NULL) { free(unixodbc_sock->row[column]); unixodbc_sock->row[column] = NULL; } } free(unixodbc_sock->row); unixodbc_sock->row = NULL; } return 0; }
/************************************************************************* * * Function: sql_num_fields * * Purpose: database specific num_fields function. Returns number * of columns from query * *************************************************************************/ static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config) { int num = 0; rlm_sql_mysql_conn_t *conn = handle->conn; #if MYSQL_VERSION_ID >= 32224 if (!(num = mysql_field_count(conn->sock))) { #else if (!(num = mysql_num_fields(conn->sock))) { #endif ERROR("rlm_sql_mysql: MYSQL Error: No Fields"); ERROR("rlm_sql_mysql: MYSQL error: %s", mysql_error(conn->sock)); } return num; } /************************************************************************* * * Function: sql_select_query * * Purpose: Issue a select query to the database * *************************************************************************/ static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query) { int ret; ret = sql_query(handle, config, query); if(ret) return ret; ret = sql_store_result(handle, config); if (ret) { return ret; } /* Why? Per http://www.mysql.com/doc/n/o/node_591.html, * this cannot return an error. Perhaps just to complain if no * fields are found? */ sql_num_fields(handle, config); return ret; }
/************************************************************************* * * Function: sql_fetch_row * * Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct * with all the data for the query in 'handle->row'. Returns * 0 on success, -1 on failure, RLM_SQL_RECONNECT if 'database is down' * *************************************************************************/ static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { int c, i; SQLINTEGER len, slen; rlm_sql_row_t retval; rlm_sql_db2_conn_t *conn; conn = handle->conn; c = sql_num_fields(handle, config); retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1); memset(retval, 0, c*sizeof(char*)+1); /* advance cursor */ if(SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) { handle->row = NULL; goto error; } for(i = 0; i < c; i++) { /* get column length */ SQLColAttribute(conn->stmt, i+1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len); retval[i] = rad_malloc(len+1); /* get the actual column */ SQLGetData(conn->stmt, i + 1, SQL_C_CHAR, retval[i], len+1, &slen); if(slen == SQL_NULL_DATA) { retval[i][0] = '\0'; } } handle->row = retval; return RLM_SQL_OK; error: for(i = 0; i < c; i++) { free(retval[i]); } free(retval); return RLM_SQL_ERROR; }
/************************************************************************* * * Function: sql_select_query * * Purpose: Issue a select query to the database * *************************************************************************/ static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query) { int numfields = 0; int i = 0; char **row = NULL; long len = 0; rlm_sql_iodbc_conn_t *conn = handle->conn; if(sql_query(handle, config, query) < 0) { return -1; } numfields = sql_num_fields(handle, config); row = (char **) rad_malloc(sizeof(char *) * (numfields+1)); memset(row, 0, (sizeof(char *) * (numfields))); row[numfields] = NULL; for(i=1; i<=numfields; i++) { SQLColAttributes(conn->stmt_handle, ((SQLUSMALLINT) i), SQL_COLUMN_LENGTH, NULL, 0, NULL, &len); len++; /* * Allocate space for each column */ row[i - 1] = rad_malloc((size_t) len); /* * This makes me feel dirty, but, according to Microsoft, it works. * Any ODBC datatype can be converted to a 'char *' according to * the following: * * http://msdn.microsoft.com/library/psdk/dasdk/odap4o4z.htm */ SQLBindCol(conn->stmt_handle, i, SQL_C_CHAR, (SQLCHAR *)row[i-1], len, 0); } conn->row = row; return 0; }
/* * List dashes as part of header for listing SQL results in a table */ static void list_dashes(B_DB *mdb, OUTPUT_FORMATTER *send) { SQL_FIELD *field; int i, j; int len; int num_fields; sql_field_seek(mdb, 0); send->decoration("+"); num_fields = sql_num_fields(mdb); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } len = max_length(field->max_length + 2); for (j = 0; j < len; j++) { send->decoration("-"); } send->decoration("+"); } send->decoration("\n"); }
/* * List dashes as part of header for listing SQL results in a table */ void list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx) { SQL_FIELD *field; int i, j; int len; int num_fields; sql_field_seek(mdb, 0); send(ctx, "+"); num_fields = sql_num_fields(mdb); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } len = max_length(field->max_length + 2); for (j = 0; j < len; j++) { send(ctx, "-"); } send(ctx, "+"); } send(ctx, "\n"); }
/* * If full_list is set, we list vertically, otherwise, we * list on one line horizontally. * Return number of rows */ int list_result(JCR *jcr, B_DB *mdb, OUTPUT_FORMATTER *send, e_list_type type) { SQL_FIELD *field; SQL_ROW row; int i, col_len, max_len = 0; int num_fields; char ewc[30]; POOL_MEM key; POOL_MEM value; Dmsg0(800, "list_result starts\n"); if (sql_num_rows(mdb) == 0) { send->decoration(_("No results to list.\n")); send->object_end("table"); return sql_num_rows(mdb); } num_fields = sql_num_fields(mdb); switch (type) { case NF_LIST: case RAW_LIST: /* * No need to calculate things like column widths for * unformated or raw output. */ break; case HORZ_LIST: case VERT_LIST: Dmsg1(800, "list_result starts looking at %d fields\n", num_fields); /* * Determine column display widths */ sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result processing field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } col_len = cstrlen(field->name); if (type == VERT_LIST) { if (col_len > max_len) { max_len = col_len; } } else { if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */ field->max_length += (field->max_length - 1) / 3; } if (col_len < (int)field->max_length) { col_len = field->max_length; } if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) { col_len = 4; /* 4 = length of the word "NULL" */ } field->max_length = col_len; /* reset column info */ } } break; } Dmsg0(800, "list_result finished first loop\n"); switch (type) { case NF_LIST: case RAW_LIST: Dmsg1(800, "list_result starts second loop looking at %d fields\n", num_fields); while ((row = sql_fetch_row(mdb)) != NULL) { send->object_start(row[0]); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { value.bsprintf(" %s", "NULL"); } else { value.bsprintf(" %s", row[i]); } send->object_key_value(field->name, value.c_str(), "%s"); } if (type != RAW_LIST) { send->decoration("\n"); } send->object_end(row[0]); } break; case HORZ_LIST: Dmsg1(800, "list_result starts second loop looking at %d fields\n", num_fields); list_dashes(mdb, send); send->decoration("|"); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result looking at field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); send->decoration(" %-*s |", max_len, field->name); } send->decoration("\n"); list_dashes(mdb, send); Dmsg1(800, "list_result starts third loop looking at %d fields\n", num_fields); while ((row = sql_fetch_row(mdb)) != NULL) { send->object_start(row[0]); sql_field_seek(mdb, 0); send->decoration("|"); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); if (row[i] == NULL) { value.bsprintf(" %-*s |", max_len, "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { value.bsprintf(" %*s |", max_len, add_commas(row[i], ewc)); } else { value.bsprintf(" %-*s |", max_len, row[i]); } if (i == num_fields-1) { value.strcat("\n"); } /* use value format string to send preformated value */ send->object_key_value(field->name, row[i], value.c_str()); } send->object_end(row[0]); } list_dashes(mdb, send); break; case VERT_LIST: Dmsg1(800, "list_result starts vertical list at %d fields\n", num_fields); while ((row = sql_fetch_row(mdb)) != NULL) { send->object_start(row[0]); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { key.bsprintf(" %*s: ", max_len, field->name); value.bsprintf("%s\n", "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { key.bsprintf(" %*s: ", max_len, field->name); value.bsprintf("%s\n", add_commas(row[i], ewc)); } else { key.bsprintf(" %*s: ", max_len, field->name); value.bsprintf("%s\n", row[i]); } /* use value format string to send preformated value */ send->object_key_value(field->name, key.c_str(), row[i], value.c_str()); } send->decoration("\n"); send->object_end(row[0]); } break; } return sql_num_rows(mdb); }
int list_result(void *vctx, int nb_col, char **row) { SQL_FIELD *field; int i, col_len, max_len = 0; int num_fields; char ewc[30]; POOL_MEM key; POOL_MEM value; LIST_CTX *pctx = (LIST_CTX *)vctx; OUTPUT_FORMATTER *send = pctx->send; e_list_type type = pctx->type; B_DB *mdb = pctx->mdb; JCR *jcr = pctx->jcr; send->object_start("row"); num_fields = sql_num_fields(mdb); switch (type) { case NF_LIST: case RAW_LIST: /* * No need to calculate things like maximum field lenght for * unformated or raw output. */ break; case HORZ_LIST: case VERT_LIST: if (!pctx->once) { pctx->once = true; Dmsg1(800, "list_result starts looking at %d fields\n", num_fields); /* * Determine column display widths */ sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result processing field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } col_len = cstrlen(field->name); if (type == VERT_LIST) { if (col_len > max_len) { max_len = col_len; } } else { if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */ field->max_length += (field->max_length - 1) / 3; } if (col_len < (int)field->max_length) { col_len = field->max_length; } if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) { col_len = 4; /* 4 = length of the word "NULL" */ } field->max_length = col_len; /* reset column info */ } } pctx->num_rows++; Dmsg0(800, "list_result finished first loop\n"); if (type == VERT_LIST) { break; } Dmsg1(800, "list_result starts second loop looking at %d fields\n", num_fields); /* * Keep the result to display the same line at the end of the table */ list_dashes(mdb, send); send->decoration("|"); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result looking at field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); send->decoration(" %-*s |", max_len, field->name); } send->decoration("\n"); list_dashes(mdb, send); } break; default: break; } switch (type) { case NF_LIST: case RAW_LIST: Dmsg1(800, "list_result starts third loop looking at %d fields\n", num_fields); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { value.bsprintf(" %s", "NULL"); } else { value.bsprintf(" %s", row[i]); } send->object_key_value(field->name, value.c_str(), "%s"); } if (type != RAW_LIST) { send->decoration("\n"); } break; case HORZ_LIST: Dmsg1(800, "list_result starts third loop looking at %d fields\n", num_fields); sql_field_seek(mdb, 0); send->decoration("|"); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); if (row[i] == NULL) { value.bsprintf(" %-*s |", max_len, "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { value.bsprintf(" %*s |", max_len, add_commas(row[i], ewc)); } else { value.bsprintf(" %-*s |", max_len, row[i]); } /* * Use value format string to send preformated value. */ send->object_key_value(field->name, row[i], value.c_str()); } send->decoration("\n"); break; case VERT_LIST: Dmsg1(800, "list_result starts vertical list at %d fields\n", num_fields); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { key.bsprintf(" %*s: ", max_len, field->name); value.bsprintf("%s\n", "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { key.bsprintf(" %*s: ", max_len, field->name); value.bsprintf("%s\n", add_commas(row[i], ewc)); } else { key.bsprintf(" %*s: ", max_len, field->name); value.bsprintf("%s\n", row[i]); } /* * Use value format string to send preformated value. */ send->object_key_value(field->name, key.c_str(), row[i], value.c_str()); } send->decoration("\n"); break; default: break; } send->object_end("row"); return 0; }
int list_result(void *vctx, int nb_col, char **row) { SQL_FIELD *field; int i, col_len, max_len = 0; int num_fields; char buf[2000], ewc[30]; LIST_CTX *pctx = (LIST_CTX *)vctx; DB_LIST_HANDLER *send = pctx->send; e_list_type type = pctx->type; B_DB *mdb = pctx->mdb; void *ctx = pctx->ctx; JCR *jcr = pctx->jcr; num_fields = sql_num_fields(mdb); switch (type) { case NF_LIST: case RAW_LIST: /* * No need to calculate things like maximum field lenght for * unformated or raw output. */ break; case HORZ_LIST: case VERT_LIST: if (!pctx->once) { pctx->once = true; Dmsg1(800, "list_result starts looking at %d fields\n", num_fields); /* * Determine column display widths */ sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result processing field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } col_len = cstrlen(field->name); if (type == VERT_LIST) { if (col_len > max_len) { max_len = col_len; } } else { if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */ field->max_length += (field->max_length - 1) / 3; } if (col_len < (int)field->max_length) { col_len = field->max_length; } if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) { col_len = 4; /* 4 = length of the word "NULL" */ } field->max_length = col_len; /* reset column info */ } } pctx->num_rows++; Dmsg0(800, "list_result finished first loop\n"); if (type == VERT_LIST) { break; } Dmsg1(800, "list_result starts second loop looking at %d fields\n", num_fields); /* * Keep the result to display the same line at the end of the table */ list_dashes(mdb, last_line_handler, pctx); send(ctx, pctx->line); send(ctx, "|"); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result looking at field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name); send(ctx, buf); } send(ctx, "\n"); list_dashes(mdb, send, ctx); } break; default: break; } switch (type) { case NF_LIST: case RAW_LIST: Dmsg1(800, "list_result starts third loop looking at %d fields\n", num_fields); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %s", "NULL"); } else { bsnprintf(buf, sizeof(buf), " %s", row[i]); } send(ctx, buf); } if (type != RAW_LIST) { send(ctx, "\n"); } break; case HORZ_LIST: Dmsg1(800, "list_result starts third loop looking at %d fields\n", num_fields); sql_field_seek(mdb, 0); send(ctx, "|"); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { bsnprintf(buf, sizeof(buf), " %*s |", max_len, add_commas(row[i], ewc)); } else { bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]); } send(ctx, buf); } send(ctx, "\n"); break; case VERT_LIST: Dmsg1(800, "list_result starts vertical list at %d fields\n", num_fields); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, add_commas(row[i], ewc)); } else { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]); } send(ctx, buf); } send(ctx, "\n"); break; default: break; } return 0; }
/************************************************************************* * * Function: sql_select_query * * Purpose: Issue a select query to the database * *************************************************************************/ static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) { int x; int y; int colcount; OCIParam *param; OCIDefine *define; ub2 dtype; ub2 dsize; char **rowdata=NULL; sb2 *indicators; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (config->sqltrace) DEBUG(querystr); if (oracle_sock->conn == NULL) { radlog(L_ERR, "rlm_sql_oracle: Socket not connected"); return SQL_DOWN; } if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle, querystr, strlen(querystr), OCI_NTV_SYNTAX, OCI_DEFAULT)) { radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_select_query: %s",sql_error(sqlsocket, config)); return -1; } /* Query only one row by default (for now) */ x = OCIStmtExecute(oracle_sock->conn, oracle_sock->queryHandle, oracle_sock->errHandle, (ub4) 0, (ub4) 0, (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT); if (x == OCI_NO_DATA) { /* Nothing to fetch */ return 0; } if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: query failed in sql_select_query: %s", sql_error(sqlsocket, config)); return sql_check_error(sqlsocket, config); } /* * Define where the output from fetch calls will go * * This is a gross hack, but it works - we convert * all data to strings for ease of use. Fortunately, most * of the data we deal with is already in string format. */ colcount = sql_num_fields(sqlsocket, config); /* DEBUG2("sql_select_query(): colcount=%d",colcount); */ /* * FIXME: These malloc's can probably go, as the schema * is fixed... */ rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1) ); memset(rowdata, 0, (sizeof(char *) * (colcount+1) )); indicators = (sb2 *) rad_malloc(sizeof(sb2) * (colcount+1) ); memset(indicators, 0, sizeof(sb2) * (colcount+1)); for (y=1; y <= colcount; y++) { x=OCIParamGet(oracle_sock->queryHandle, OCI_HTYPE_STMT, oracle_sock->errHandle, (dvoid **)¶m, (ub4) y); if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM, (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE, oracle_sock->errHandle); if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } dsize=MAX_DATASTR_LEN; /* * Use the retrieved length of dname to allocate an output * buffer, and then define the output variable (but only * for char/string type columns). */ switch(dtype) { #ifdef SQLT_AFC case SQLT_AFC: /* ansii fixed char */ #endif #ifdef SQLT_AFV case SQLT_AFV: /* ansii var char */ #endif case SQLT_VCS: /* var char */ case SQLT_CHR: /* char */ case SQLT_STR: /* string */ x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM, (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE, oracle_sock->errHandle); if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } rowdata[y-1]=rad_malloc(dsize+1); memset(rowdata[y-1], 0, dsize+1); break; case SQLT_DAT: case SQLT_INT: case SQLT_UIN: case SQLT_FLT: case SQLT_PDN: case SQLT_BIN: case SQLT_NUM: rowdata[y-1]=rad_malloc(dsize+1); memset(rowdata[y-1], 0, dsize+1); break; default: dsize=0; rowdata[y-1]=NULL; break; } indicators[y-1] = 0; x=OCIDefineByPos(oracle_sock->queryHandle, &define, oracle_sock->errHandle, y, (ub1 *) rowdata[y-1], dsize+1, SQLT_STR, &indicators[y-1], (dvoid *) 0, (dvoid *) 0, OCI_DEFAULT); /* * FIXME: memory leaks of indicators & rowdata? */ if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } } oracle_sock->results=rowdata; oracle_sock->indicators=indicators; return 0; }
/* * If full_list is set, we list vertically, otherwise, we * list on one line horizontally. * Return number of rows */ int list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) { SQL_FIELD *field; SQL_ROW row; int i, col_len, max_len = 0; int num_fields; char buf[2000], ewc[30]; Dmsg0(800, "list_result starts\n"); if (sql_num_rows(mdb) == 0) { send(ctx, _("No results to list.\n")); return sql_num_rows(mdb); } num_fields = sql_num_fields(mdb); switch (type) { case NF_LIST: case RAW_LIST: /* * No need to calculate things like column widths for * unformated or raw output. */ break; case HORZ_LIST: case VERT_LIST: Dmsg1(800, "list_result starts looking at %d fields\n", num_fields); /* * Determine column display widths */ sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result processing field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } col_len = cstrlen(field->name); if (type == VERT_LIST) { if (col_len > max_len) { max_len = col_len; } } else { if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */ field->max_length += (field->max_length - 1) / 3; } if (col_len < (int)field->max_length) { col_len = field->max_length; } if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) { col_len = 4; /* 4 = length of the word "NULL" */ } field->max_length = col_len; /* reset column info */ } } break; } Dmsg0(800, "list_result finished first loop\n"); switch (type) { case NF_LIST: case RAW_LIST: Dmsg1(800, "list_result starts second loop looking at %d fields\n", num_fields); while ((row = sql_fetch_row(mdb)) != NULL) { sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %s", "NULL"); } else { bsnprintf(buf, sizeof(buf), " %s", row[i]); } send(ctx, buf); } if (type != RAW_LIST) { send(ctx, "\n"); } } break; case HORZ_LIST: Dmsg1(800, "list_result starts second loop looking at %d fields\n", num_fields); list_dashes(mdb, send, ctx); send(ctx, "|"); sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { Dmsg1(800, "list_result looking at field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name); send(ctx, buf); } send(ctx, "\n"); list_dashes(mdb, send, ctx); Dmsg1(800, "list_result starts third loop looking at %d fields\n", num_fields); while ((row = sql_fetch_row(mdb)) != NULL) { sql_field_seek(mdb, 0); send(ctx, "|"); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { bsnprintf(buf, sizeof(buf), " %*s |", max_len, add_commas(row[i], ewc)); } else { bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]); } send(ctx, buf); } send(ctx, "\n"); } list_dashes(mdb, send, ctx); break; case VERT_LIST: Dmsg1(800, "list_result starts vertical list at %d fields\n", num_fields); while ((row = sql_fetch_row(mdb)) != NULL) { sql_field_seek(mdb, 0); for (i = 0; i < num_fields; i++) { field = sql_fetch_field(mdb); if (!field) { break; } if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL"); } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, add_commas(row[i], ewc)); } else { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]); } send(ctx, buf); } send(ctx, "\n"); } break; } return sql_num_rows(mdb); }
/************************************************************************* * * Function: sql_fetch_row * * Purpose: database specific fetch_row. Returns a SQL_ROW struct * with all the data for the query in 'sqlsocket->row'. Returns * 0 on success, -1 on failure, SQL_DOWN if database is down. * *************************************************************************/ static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) { int returnCode = -1; rlm_sql_sqlite_sock *sqlite_sock = sqlsocket->conn; const char *blob; int blobLen; int status; int colindex = 0; int colcount = 0; int coltype = 0; int colintvalue = 0; int ret_blob_size = 0; char **rowdata = NULL; const unsigned char *textStr; char intStr[256]; status = sqlite3_step(sqlite_sock->pStmt); radlog(L_DBG, "rlm_sql_sqlite: sqlite3_step = %d\n", status); if (status == SQLITE_DONE) { sql_free_rowdata(sqlsocket, sqlite_sock->columnCount); return 0; } else if (status == SQLITE_ROW) { if (sqlite_sock->columnCount == 0) { sqlite_sock->columnCount = sql_num_fields(sqlsocket, config); } colcount = sqlite_sock->columnCount; if (colcount == 0) return -1; sql_free_rowdata(sqlsocket, colcount); ret_blob_size = sizeof(char *) * (colcount+1); rowdata = (char **)rad_malloc(ret_blob_size); /* Space for pointers */ if (rowdata != NULL) { memset(rowdata, 0, ret_blob_size); /* NULL-pad the pointers */ sqlsocket->row = rowdata; } for (colindex = 0; colindex < colcount; colindex++) { coltype = sqlite3_column_type(sqlite_sock->pStmt, colindex); switch (coltype) { case SQLITE_INTEGER: colintvalue = sqlite3_column_int(sqlite_sock->pStmt, colindex); snprintf(intStr, sizeof(intStr), "%d", colintvalue); rowdata[colindex] = strdup(intStr); break; case SQLITE_TEXT: textStr = sqlite3_column_text(sqlite_sock->pStmt, colindex); if (textStr != NULL) rowdata[colindex] = strdup((const char *)textStr); break; case SQLITE_BLOB: blob = sqlite3_column_blob(sqlite_sock->pStmt, colindex); if (blob != NULL) { blobLen = sqlite3_column_bytes(sqlite_sock->pStmt, colindex); rowdata[colindex] = (char *)rad_malloc(blobLen + 1); if (rowdata[colindex] != NULL) { memcpy(rowdata[colindex], blob, blobLen); } } break; default: break; } } returnCode = 0; } return returnCode; }