void QgsGrassVectorMapLayer::load() { clear(); if ( !mMap ) { return; } // Attributes are not loaded for topo layers in which case field == 0 if ( mField == 0 ) { return; } QgsDebugMsg( QString( "cidxFieldIndex() = %1 cidxFieldNumCats() = %2" ).arg( cidxFieldIndex() ).arg( cidxFieldNumCats() ) ); mFieldInfo = Vect_get_field( mMap->map(), mField ); // should work also with field = 0 if ( !mFieldInfo ) { QgsDebugMsg( "No field info -> no attribute table" ); } else { QgsDebugMsg( "Field info found -> open database" ); QFileInfo di( mMap->grassObject().mapsetPath() + "/vector/" + mMap->grassObject().name() + "/dbln" ); mLastLoaded = di.lastModified(); QString error; dbDriver *databaseDriver = openDriver( error ); if ( !databaseDriver || !error.isEmpty() ) { QgsDebugMsg( error ); } else { QgsDebugMsg( "Database opened -> open select cursor" ); QgsGrass::lock(); // not sure if lock is necessary dbString dbstr; db_init_string( &dbstr ); db_set_string( &dbstr, ( char * )"select * from " ); db_append_string( &dbstr, mFieldInfo->table ); QgsDebugMsg( QString( "SQL: %1" ).arg( db_get_string( &dbstr ) ) ); dbCursor databaseCursor; if ( db_open_select_cursor( databaseDriver, &dbstr, &databaseCursor, DB_SCROLL ) != DB_OK ) { db_close_database_shutdown_driver( databaseDriver ); QgsGrass::warning( "Cannot select attributes from table '" + QString( mFieldInfo->table ) + "'" ); } else { #ifdef QGISDEBUG int nRecords = db_get_num_rows( &databaseCursor ); QgsDebugMsg( QString( "Number of records: %1" ).arg( nRecords ) ); #endif dbTable *databaseTable = db_get_cursor_table( &databaseCursor ); int nColumns = db_get_table_number_of_columns( databaseTable ); // Read columns' description for ( int i = 0; i < nColumns; i++ ) { QPair<double, double> minMax( DBL_MAX, -DBL_MAX ); dbColumn *column = db_get_table_column( databaseTable, i ); int ctype = db_sqltype_to_Ctype( db_get_column_sqltype( column ) ); QVariant::Type qtype = QVariant::String; //default to string QgsDebugMsg( QString( "column = %1 ctype = %2" ).arg( db_get_column_name( column ) ).arg( ctype ) ); QString ctypeStr; switch ( ctype ) { case DB_C_TYPE_INT: ctypeStr = QStringLiteral( "integer" ); qtype = QVariant::Int; break; case DB_C_TYPE_DOUBLE: ctypeStr = QStringLiteral( "double" ); qtype = QVariant::Double; break; case DB_C_TYPE_STRING: ctypeStr = QStringLiteral( "string" ); qtype = QVariant::String; break; case DB_C_TYPE_DATETIME: ctypeStr = QStringLiteral( "datetime" ); qtype = QVariant::String; break; } mTableFields.append( QgsField( db_get_column_name( column ), qtype, ctypeStr, db_get_column_length( column ), db_get_column_precision( column ) ) ); mMinMax << minMax; if ( G_strcasecmp( db_get_column_name( column ), mFieldInfo->key ) == 0 ) { mKeyColumn = i; } } if ( mKeyColumn < 0 ) { mTableFields.clear(); QgsGrass::warning( QObject::tr( "Key column '%1' not found in the table '%2'" ).arg( mFieldInfo->key, mFieldInfo->table ) ); } else { mHasTable = true; // Read attributes to the memory for ( ;; ) { int more; if ( db_fetch( &databaseCursor, DB_NEXT, &more ) != DB_OK ) { QgsDebugMsg( "Cannot fetch DB record" ); break; } if ( !more ) { break; // no more records } // Check cat value dbColumn *column = db_get_table_column( databaseTable, mKeyColumn ); dbValue *value = db_get_column_value( column ); if ( db_test_value_isnull( value ) ) { continue; } int cat = db_get_value_int( value ); if ( cat < 0 ) { continue; } QList<QVariant> values; for ( int i = 0; i < nColumns; i++ ) { column = db_get_table_column( databaseTable, i ); int sqltype = db_get_column_sqltype( column ); int ctype = db_sqltype_to_Ctype( sqltype ); value = db_get_column_value( column ); db_convert_value_to_string( value, sqltype, &dbstr ); QgsDebugMsgLevel( QString( "column = %1 value = %2" ).arg( db_get_column_name( column ), db_get_string( &dbstr ) ), 3 ); QVariant variant; if ( !db_test_value_isnull( value ) ) { int iv; double dv; //layer.mAttributes[layer.nAttributes].values[i] = strdup( db_get_string( &dbstr ) ); switch ( ctype ) { case DB_C_TYPE_INT: iv = db_get_value_int( value ); variant = QVariant( iv ); mMinMax[i].first = std::min( mMinMax[i].first, ( double )iv ); mMinMax[i].second = std::min( mMinMax[i].second, ( double )iv ); break; case DB_C_TYPE_DOUBLE: dv = db_get_value_double( value ); variant = QVariant( dv ); mMinMax[i].first = std::min( mMinMax[i].first, dv ); mMinMax[i].second = std::min( mMinMax[i].second, dv ); break; case DB_C_TYPE_STRING: // Store as byte array so that codec may be used later variant = QVariant( QByteArray( db_get_value_string( value ) ) ); break; case DB_C_TYPE_DATETIME: variant = QVariant( QByteArray( db_get_string( &dbstr ) ) ); break; default: variant = QVariant( QByteArray( db_get_string( &dbstr ) ) ); } } QgsDebugMsgLevel( QString( "column = %1 variant = %2" ).arg( db_get_column_name( column ), variant.toString() ), 3 ); values << variant; } mAttributes.insert( cat, values ); } } mValid = true; db_close_cursor( &databaseCursor ); db_close_database_shutdown_driver( databaseDriver ); db_free_string( &dbstr ); QgsDebugMsg( QString( "mTableFields.size = %1" ).arg( mTableFields.size() ) ); QgsDebugMsg( QString( "number of attributes = %1" ).arg( mAttributes.size() ) ); } QgsGrass::unlock(); } } // Add cat if no attribute fields exist (otherwise qgis crashes) if ( mTableFields.size() == 0 ) { mKeyColumn = 0; mTableFields.append( QgsField( QStringLiteral( "cat" ), QVariant::Int, QStringLiteral( "integer" ) ) ); QPair<double, double> minMax( 0, 0 ); if ( cidxFieldIndex() >= 0 ) { int ncats, cat, type, id; ncats = Vect_cidx_get_num_cats_by_index( mMap->map(), cidxFieldIndex() ); if ( ncats > 0 ) { Vect_cidx_get_cat_by_index( mMap->map(), cidxFieldIndex(), 0, &cat, &type, &id ); minMax.first = cat; Vect_cidx_get_cat_by_index( mMap->map(), cidxFieldIndex(), ncats - 1, &cat, &type, &id ); minMax.second = cat; } } mMinMax << minMax; } mFields = mTableFields; mAttributeFields = mTableFields; QgsDebugMsg( QString( "layer loaded mTableFields.size() = %1 mAttributes.size() = %2" ).arg( mTableFields.size() ).arg( mAttributes.size() ) ); mValid = true; }
int db__copy_table(const char *from_drvname, const char *from_dbname, const char *from_tblname, const char *to_drvname, const char *to_dbname, const char *to_tblname, const char *where, const char *select, const char *selcol, int *ivals, int nvals) { int col, ncols, sqltype, ctype, more, selcol_found; char buf[1000]; int *ivalues; dbHandle from_handle, to_handle; dbString tblname, sql; dbString value_string; dbString *tblnames; dbTable *table, *out_table; dbCursor cursor; dbColumn *column; dbValue *value; const char *colname; dbDriver *from_driver, *to_driver; int count, i; G_debug(3, "db_copy_table():\n from driver = %s, db = %s, table = %s\n" " to driver = %s, db = %s, table = %s, where = %s, select = %s", from_drvname, from_dbname, from_tblname, to_drvname, to_dbname, to_tblname, where, select); db_init_handle(&from_handle); db_init_handle(&to_handle); db_init_string(&tblname); db_init_string(&sql); db_init_string(&value_string); /* Make a copy of input values and sort it */ if (ivals) { ivalues = (int *)G_malloc(nvals * sizeof(int)); memcpy(ivalues, ivals, nvals * sizeof(int)); qsort((void *)ivalues, nvals, sizeof(int), cmp); } /* Open input driver and database */ from_driver = db_start_driver(from_drvname); if (from_driver == NULL) { G_warning(_("Unable to start driver <%s>"), from_drvname); return DB_FAILED; } db_set_handle(&from_handle, from_dbname, NULL); if (db_open_database(from_driver, &from_handle) != DB_OK) { G_warning(_("Unable to open database <%s> by driver <%s>"), from_dbname, from_drvname); db_close_database_shutdown_driver(from_driver); return DB_FAILED; } /* Open output driver and database */ if (strcmp(from_drvname, to_drvname) == 0 && strcmp(from_dbname, to_dbname) == 0) { G_debug(3, "Use the same driver"); to_driver = from_driver; } else { to_driver = db_start_driver(to_drvname); if (to_driver == NULL) { G_warning(_("Unable to start driver <%s>"), to_drvname); db_close_database_shutdown_driver(from_driver); return DB_FAILED; } db_set_handle(&to_handle, to_dbname, NULL); if (db_open_database(to_driver, &to_handle) != DB_OK) { G_warning(_("Unable to open database <%s> by driver <%s>"), to_dbname, to_drvname); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } } db_begin_transaction(to_driver); /* Because in SQLite3 an opened cursor is no more valid if 'schema' is modified (create table), we have to open cursor twice */ /* test if the table exists */ if (db_list_tables(to_driver, &tblnames, &count, 0) != DB_OK) { G_warning(_("Unable to get list tables in database <%s>"), to_dbname); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) db_close_database_shutdown_driver(from_driver); return DB_FAILED; } for (i = 0; i < count; i++) { const char *tblname = db_get_string(&tblnames[i]); if (strcmp(to_tblname, tblname) == 0) { G_warning(_("Table <%s> already exists in database <%s>"), to_tblname, to_dbname); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) db_close_database_shutdown_driver(from_driver); return DB_FAILED; } } /* Create new table */ /* Open cursor for data structure */ if (select) { db_set_string(&sql, select); /* TODO!: cannot use this because it will not work if a query * ends with 'group by' for example */ /* tmp = strdup ( select ); G_tolcase ( tmp ); if ( !strstr( tmp,"where") ) { db_append_string ( &sql, " where 0 = 1"); } else { db_append_string ( &sql, " and 0 = 1"); } free (tmp); */ } else { db_set_string(&sql, "select * from "); db_append_string(&sql, from_tblname); db_append_string(&sql, " where 0 = 1"); /* to get no data */ } G_debug(3, db_get_string(&sql)); if (db_open_select_cursor(from_driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) { G_warning(_("Unable to open select cursor: '%s'"), db_get_string(&sql)); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } G_debug(3, "Select cursor opened"); table = db_get_cursor_table(&cursor); ncols = db_get_table_number_of_columns(table); G_debug(3, "ncols = %d", ncols); out_table = db_alloc_table(ncols); db_set_table_name(out_table, to_tblname); selcol_found = 0; for (col = 0; col < ncols; col++) { dbColumn *out_column; column = db_get_table_column(table, col); colname = db_get_column_name(column); sqltype = db_get_column_sqltype(column); ctype = db_sqltype_to_Ctype(sqltype); G_debug(3, "%s (%s)", colname, db_sqltype_name(sqltype)); out_column = db_get_table_column(out_table, col); if (selcol && G_strcasecmp(colname, selcol) == 0) { if (ctype != DB_C_TYPE_INT) G_fatal_error(_("Column <%s> is not integer"), colname); selcol_found = 1; } db_set_column_name(out_column, db_get_column_name(column)); db_set_column_description(out_column, db_get_column_description(column)); db_set_column_sqltype(out_column, db_get_column_sqltype(column)); db_set_column_length(out_column, db_get_column_length(column)); db_set_column_precision(out_column, db_get_column_precision(column)); db_set_column_scale(out_column, db_get_column_scale(column)); } db_close_cursor(&cursor); if (selcol && !selcol_found) G_fatal_error(_("Column <%s> not found"), selcol); if (db_create_table(to_driver, out_table) != DB_OK) { G_warning(_("Unable to create table <%s>"), to_tblname); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } /* Open cursor with data */ if (select) { db_set_string(&sql, select); } else { db_set_string(&sql, "select * from "); db_append_string(&sql, from_tblname); if (where) { db_append_string(&sql, " where "); db_append_string(&sql, where); } } G_debug(3, db_get_string(&sql)); if (db_open_select_cursor(from_driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) { G_warning(_("Unable to open select cursor: '%s'"), db_get_string(&sql)); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } G_debug(3, "Select cursor opened"); table = db_get_cursor_table(&cursor); ncols = db_get_table_number_of_columns(table); G_debug(3, "ncols = %d", ncols); /* Copy all rows */ while (1) { int select; if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) { G_warning(_("Unable to fetch data from table <%s>"), from_tblname); db_close_cursor(&cursor); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } if (!more) break; sprintf(buf, "insert into %s values ( ", to_tblname); db_set_string(&sql, buf); select = 1; for (col = 0; col < ncols; col++) { column = db_get_table_column(table, col); colname = db_get_column_name(column); sqltype = db_get_column_sqltype(column); ctype = db_sqltype_to_Ctype(sqltype); value = db_get_column_value(column); if (selcol && G_strcasecmp(colname, selcol) == 0) { if (db_test_value_isnull(value)) continue; if (!bsearch(&(value->i), ivalues, nvals, sizeof(int), cmp)) { select = 0; break; } } if (col > 0) db_append_string(&sql, ", "); db_convert_value_to_string(value, sqltype, &value_string); switch (ctype) { case DB_C_TYPE_STRING: case DB_C_TYPE_DATETIME: if (db_test_value_isnull(value)) { db_append_string(&sql, "null"); } else { db_double_quote_string(&value_string); db_append_string(&sql, "'"); db_append_string(&sql, db_get_string(&value_string)); db_append_string(&sql, "'"); } break; case DB_C_TYPE_INT: case DB_C_TYPE_DOUBLE: if (db_test_value_isnull(value)) { db_append_string(&sql, "null"); } else { db_append_string(&sql, db_get_string(&value_string)); } break; default: G_warning(_("Unknown column type (column <%s>)"), colname); db_close_cursor(&cursor); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } } if (!select) continue; db_append_string(&sql, ")"); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(to_driver, &sql) != DB_OK) { G_warning("Unable to insert new record: '%s'", db_get_string(&sql)); db_close_cursor(&cursor); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_FAILED; } } if (selcol) G_free(ivalues); G_debug(3, "Table copy OK"); db_close_cursor(&cursor); db_commit_transaction(to_driver); db_close_database_shutdown_driver(to_driver); if (from_driver != to_driver) { db_close_database_shutdown_driver(from_driver); } return DB_OK; }